Skip to content

Commit 2c87e0f

Browse files
committed
fix: resolve TypeScript type error and improve CI coverage reporting
1 parent 02027a3 commit 2c87e0f

6 files changed

Lines changed: 64 additions & 39 deletions

File tree

.github/workflows/ci.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,18 @@ jobs:
6363
- name: Run Tests & Coverage
6464
run: pnpm run test:coverage
6565

66+
- name: List coverage files
67+
if: always()
68+
run: ls -la coverage/ || echo "Coverage directory not found"
69+
6670
- name: Upload coverage to Codecov
6771
uses: codecov/codecov-action@v5
6872
if: always()
6973
with:
7074
token: ${{ secrets.CODECOV_TOKEN }}
7175
slug: upskill-team/back-end-dsw
7276
files: ./coverage/lcov.info
73-
fail_ci_if_error: true
77+
fail_ci_if_error: false
7478
verbose: true
7579

7680
build:

codecov.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ codecov:
66
coverage:
77
precision: 2
88
round: down
9-
range: "70...100"
10-
9+
range: '70...100'
10+
1111
status:
1212
project:
1313
default:
@@ -20,13 +20,13 @@ coverage:
2020
threshold: 0%
2121

2222
comment:
23-
layout: "reach,diff,flags,tree"
23+
layout: 'reach,diff,flags,tree'
2424
behavior: default
2525
require_changes: no
2626

2727
ignore:
28-
- "src/**/*.spec.ts"
29-
- "src/**/*.integration.spec.ts"
30-
- "src/shared/testing/**"
31-
- "src/server.ts"
32-
- "**/*.d.ts"
28+
- 'src/**/*.spec.ts'
29+
- 'src/**/*.integration.spec.ts'
30+
- 'src/shared/testing/**'
31+
- 'src/server.ts'
32+
- '**/*.d.ts'

eslint.config.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ export default [
2525
},
2626
},
2727
{
28-
ignores: ['dist/', 'coverage/', 'eslint.config.js', './docs/','jest.config.ts'],
28+
ignores: [
29+
'dist/',
30+
'coverage/',
31+
'eslint.config.js',
32+
'./docs/',
33+
'jest.config.ts',
34+
],
2935
},
3036
];

jest.config.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ const config = {
2929
testMatch: ['**/*.spec.ts', '**/*.integration.spec.ts'],
3030

3131
coverageProvider: 'v8',
32-
32+
3333
coverageDirectory: '<rootDir>/coverage',
34-
34+
3535
coverageReporters: ['text', 'lcov', 'clover', 'json'],
36-
36+
3737
collectCoverageFrom: [
3838
'src/**/*.{ts,tsx}',
3939
'!src/**/*.d.ts',

src/auth/auth.service.spec.ts

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ describe('AuthService - Unit Tests', () => {
7575
const hashedPassword = '$2a$10$hashedPasswordExample';
7676
mockEm.findOne.mockResolvedValue(null);
7777
(bcrypt.hash as jest.Mock).mockResolvedValue(hashedPassword);
78-
78+
7979
mockEm.create.mockImplementation((entity, data) => data as any);
8080

8181
const registerData = {
@@ -146,23 +146,25 @@ describe('AuthService - Unit Tests', () => {
146146
} as User;
147147

148148
mockEm.findOne.mockResolvedValue(mockUser);
149-
mockEm.create.mockImplementation((entity, data) => ({ ...data, id: 'rt_123' }) as any);
150-
149+
mockEm.create.mockImplementation(
150+
(entity, data) => ({ ...data, id: 'rt_123' } as any)
151+
);
152+
151153
(bcrypt.compare as jest.Mock).mockResolvedValue(true);
152154
(jwt.sign as jest.Mock).mockReturnValue('jwt.access.token');
153155

154156
const result = await authService.login({
155157
mail: 'test@test.com',
156158
password_plaintext: 'correctPassword',
157-
rememberMe: true,
159+
rememberMe: true,
158160
});
159161

160162
expect(result).toHaveProperty('accessToken');
161163
expect(result.accessToken).toBe('jwt.access.token');
162-
164+
163165
expect(result).toHaveProperty('refreshToken');
164166
expect(result.refreshToken).toBe('mockRefreshToken');
165-
167+
166168
expect(mockEm.persistAndFlush).toHaveBeenCalled();
167169
});
168170

@@ -204,7 +206,7 @@ describe('AuthService - Unit Tests', () => {
204206
const existingToken = {
205207
token: 'oldToken',
206208
user: mockUser,
207-
expiresAt: new Date(Date.now() + 10000),
209+
expiresAt: new Date(Date.now() + 10000),
208210
revoked: false,
209211
} as RefreshToken;
210212

@@ -216,28 +218,34 @@ describe('AuthService - Unit Tests', () => {
216218

217219
expect(result.accessToken).toBe('new.access.token');
218220
expect(result.refreshToken).toBe('mockRefreshToken');
219-
220-
expect(existingToken.revoked).toBe(true);
221-
expect(existingToken.replacedByToken).toBe('mockRefreshToken');
222-
223-
expect(mockEm.persistAndFlush).toHaveBeenCalledWith(expect.arrayContaining([
224-
expect.objectContaining({ token: 'oldToken', revoked: true }),
225-
expect.objectContaining({ token: 'mockRefreshToken', revoked: false })
226-
]));
221+
222+
expect(existingToken.revoked).toBe(true);
223+
expect(existingToken.replacedByToken).toBe('mockRefreshToken');
224+
225+
expect(mockEm.persistAndFlush).toHaveBeenCalledWith(
226+
expect.arrayContaining([
227+
expect.objectContaining({ token: 'oldToken', revoked: true }),
228+
expect.objectContaining({
229+
token: 'mockRefreshToken',
230+
revoked: false,
231+
}),
232+
])
233+
);
227234
});
228235

229236
it('should detect reuse of revoked token and trigger security breach (revoke all)', async () => {
230237
const mockUser = { id: '123' } as User;
231238
const stolenToken = {
232239
token: 'stolenToken',
233240
user: mockUser,
234-
revoked: true,
241+
revoked: true,
235242
} as RefreshToken;
236243

237244
mockEm.findOne.mockResolvedValue(stolenToken);
238245

239-
await expect(authService.refreshToken('stolenToken'))
240-
.rejects.toThrow('Security breach detected. Please login again.');
246+
await expect(authService.refreshToken('stolenToken')).rejects.toThrow(
247+
'Security breach detected. Please login again.'
248+
);
241249

242250
expect(mockEm.nativeUpdate).toHaveBeenCalledWith(
243251
RefreshToken,
@@ -253,14 +261,16 @@ describe('AuthService - Unit Tests', () => {
253261
const tokenString = 'valid-refresh-token';
254262
const mockTokenEntity = {
255263
token: tokenString,
256-
revoked: false
264+
revoked: false,
257265
} as RefreshToken;
258266

259267
mockEm.findOne.mockResolvedValue(mockTokenEntity);
260268

261269
await authService.logout(tokenString);
262270

263-
expect(mockEm.findOne).toHaveBeenCalledWith(RefreshToken, { token: tokenString });
271+
expect(mockEm.findOne).toHaveBeenCalledWith(RefreshToken, {
272+
token: tokenString,
273+
});
264274
expect(mockTokenEntity.revoked).toBe(true);
265275
expect(mockEm.flush).toHaveBeenCalled();
266276
});
@@ -283,7 +293,7 @@ describe('AuthService - Unit Tests', () => {
283293
const reactEmail = await import('@react-email/render');
284294
sendEmail = emailService.sendEmail as jest.Mock;
285295
render = reactEmail.render as jest.Mock;
286-
296+
287297
jest.clearAllMocks();
288298
capturedProps = null;
289299
sendEmail.mockResolvedValue(true);
@@ -308,7 +318,7 @@ describe('AuthService - Unit Tests', () => {
308318
expect(mockUser.resetPasswordExpires).toBeDefined();
309319
const expirationTime = mockUser.resetPasswordExpires!.getTime();
310320
const expectedTime = startTime + 900000; // 15 minutes in milliseconds
311-
321+
312322
// Allow 1 second tolerance for test execution time
313323
expect(expirationTime).toBeGreaterThanOrEqual(expectedTime - 1000);
314324
expect(expirationTime).toBeLessThanOrEqual(expectedTime + 1000);
@@ -332,7 +342,9 @@ describe('AuthService - Unit Tests', () => {
332342

333343
// Assert
334344
expect(capturedProps).not.toBeNull();
335-
expect(capturedProps.resetUrl).toContain('https://up-skill.app/reset-password?token=');
345+
expect(capturedProps.resetUrl).toContain(
346+
'https://up-skill.app/reset-password?token='
347+
);
336348
expect(capturedProps.resetUrl).toContain('mockresettoken12345');
337349

338350
// Cleanup
@@ -357,7 +369,9 @@ describe('AuthService - Unit Tests', () => {
357369

358370
// Assert
359371
expect(capturedProps).not.toBeNull();
360-
expect(capturedProps.resetUrl).toContain('https://localhost:5173/reset-password?token=');
372+
expect(capturedProps.resetUrl).toContain(
373+
'https://localhost:5173/reset-password?token='
374+
);
361375
expect(capturedProps.resetUrl).toContain('mockresettoken12345');
362376

363377
// Cleanup
@@ -402,4 +416,4 @@ describe('AuthService - Unit Tests', () => {
402416
expect(mockEm.persistAndFlush).not.toHaveBeenCalled();
403417
});
404418
});
405-
});
419+
});

src/emails/templates/ResetPasswordEmail.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ describe('ResetPasswordEmail Component', () => {
2020
// Assert
2121
expect(component).toBeDefined();
2222
expect(component.props).toBeDefined();
23-
expect(component.props.children).toBeDefined();
23+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
24+
expect((component.props as any).children).toBeDefined();
2425
});
2526

2627
it('should accept resetUrl prop containing the password reset link', () => {

0 commit comments

Comments
 (0)