Skip to content

Commit 39af96f

Browse files
authored
Merge pull request #13 from OpenNBS/unit-testing
Add Unit Tests for Backend Services and Controllers
2 parents e67663a + 9fcf4ae commit 39af96f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+4500
-479
lines changed

.vscode/extensions.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"recommendations": [
33
"dbaeumer.vscode-eslint",
44
"esbenp.prettier-vscode",
5-
"unifiedjs.vscode-mdx"
5+
"unifiedjs.vscode-mdx",
6+
"orta.vscode-jest"
67
]
78
}

NoteBlockWorld.code-workspace

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"folders": [
3+
{
4+
"path": ".",
5+
"name": "Root"
6+
},
7+
{
8+
"path": "./server",
9+
"name": "Backend"
10+
},
11+
{
12+
"path": "./shared",
13+
"name": "Shared"
14+
},
15+
{
16+
"path": "./web",
17+
"name": "Frontend"
18+
}
19+
],
20+
"settings": {
21+
"mdx.server.enable": true,
22+
"jest.disabledWorkspaceFolders": ["Root", "Frontend"]
23+
}
24+
}

server/jest.config.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
module.exports = {
2+
moduleFileExtensions: ['js', 'json', 'ts'],
3+
rootDir: '.',
4+
testRegex: '.*\\.spec\\.ts$',
5+
transform: {
6+
'^.+\\.(t|j)s$': [
7+
'ts-jest',
8+
{
9+
tsconfig: '<rootDir>/tsconfig.json',
10+
ignoreCodes: ['TS151001'],
11+
},
12+
],
13+
},
14+
collectCoverageFrom: ['**/*.(t|j)s'],
15+
coverageDirectory: './coverage',
16+
testEnvironment: 'node',
17+
moduleNameMapper: {
18+
'^@shared/(.*)$': '<rootDir>/../shared/$1',
19+
'^@server/(.*)$': '<rootDir>/src/$1',
20+
},
21+
testPathIgnorePatterns: [
22+
'<rootDir>/node_modules/',
23+
'<rootDir>/dist/',
24+
'<rootDir>/coverage/',
25+
],
26+
coveragePathIgnorePatterns: [
27+
'<rootDir>/node_modules/',
28+
'<rootDir>/coverage/',
29+
'<rootDir>/dist/',
30+
'<rootDir>/src/.*\\.module\\.ts$',
31+
'<rootDir>/src/main.ts',
32+
'.eslintrc.js',
33+
'jest.config.js',
34+
],
35+
};

server/package.json

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -76,22 +76,5 @@
7676
"ts-node": "^10.9.1",
7777
"tsconfig-paths": "^4.2.0",
7878
"typescript": "^5.1.3"
79-
},
80-
"jest": {
81-
"moduleFileExtensions": [
82-
"js",
83-
"json",
84-
"ts"
85-
],
86-
"rootDir": "src",
87-
"testRegex": ".*\\.spec\\.ts$",
88-
"transform": {
89-
"^.+\\.(t|j)s$": "ts-jest"
90-
},
91-
"collectCoverageFrom": [
92-
"**/*.(t|j)s"
93-
],
94-
"coverageDirectory": "../coverage",
95-
"testEnvironment": "node"
9679
}
9780
}

server/src/GetRequestUser.spec.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { ExecutionContext, HttpException, HttpStatus } from '@nestjs/common';
2+
3+
import { GetRequestToken, validateUser } from './GetRequestUser';
4+
import { UserDocument } from './user/entity/user.entity';
5+
6+
describe('GetRequestToken', () => {
7+
it('should be a defined decorator', () => {
8+
const mockExecutionContext = {
9+
switchToHttp: jest.fn().mockReturnThis(),
10+
} as unknown as ExecutionContext;
11+
12+
const result = GetRequestToken(null, mockExecutionContext);
13+
14+
expect(typeof result).toBe('function');
15+
});
16+
});
17+
18+
describe('validateUser', () => {
19+
it('should return the user if the user exists', () => {
20+
const mockUser = {
21+
_id: 'test-id',
22+
username: 'testuser',
23+
} as unknown as UserDocument;
24+
25+
const result = validateUser(mockUser);
26+
27+
expect(result).toEqual(mockUser);
28+
});
29+
30+
it('should throw an error if the user does not exist', () => {
31+
expect(() => validateUser(null)).toThrowError(
32+
new HttpException(
33+
{
34+
error: {
35+
user: 'User not found',
36+
},
37+
},
38+
HttpStatus.UNAUTHORIZED,
39+
),
40+
);
41+
});
42+
});

server/src/app.module.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,7 @@ import { UserModule } from './user/user.module';
2424
useFactory: (
2525
configService: ConfigService,
2626
): MongooseModuleFactoryOptions => {
27-
const url = configService.get<string>('MONGO_URL');
28-
if (!url) {
29-
throw new Error('Missing DB config');
30-
}
27+
const url = configService.getOrThrow<string>('MONGO_URL');
3128
Logger.debug(`Connecting to ${url}`);
3229

3330
return {
@@ -39,8 +36,8 @@ import { UserModule } from './user/user.module';
3936
}),
4037
SongModule,
4138
UserModule,
42-
AuthModule,
43-
FileModule,
39+
AuthModule.forRootAsync(),
40+
FileModule.forRootAsync(),
4441
SongBrowserModule,
4542
],
4643
controllers: [],
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import { Test, TestingModule } from '@nestjs/testing';
2+
import { Request, Response } from 'express';
3+
4+
import { AuthController } from './auth.controller';
5+
import { AuthService } from './auth.service';
6+
7+
const mockAuthService = {
8+
githubLogin: jest.fn(),
9+
googleLogin: jest.fn(),
10+
discordLogin: jest.fn(),
11+
verifyToken: jest.fn(),
12+
};
13+
14+
describe('AuthController', () => {
15+
let controller: AuthController;
16+
let authService: AuthService;
17+
18+
beforeEach(async () => {
19+
const module: TestingModule = await Test.createTestingModule({
20+
controllers: [AuthController],
21+
providers: [
22+
{
23+
provide: AuthService,
24+
useValue: mockAuthService,
25+
},
26+
],
27+
}).compile();
28+
29+
controller = module.get<AuthController>(AuthController);
30+
authService = module.get<AuthService>(AuthService);
31+
});
32+
33+
it('should be defined', () => {
34+
expect(controller).toBeDefined();
35+
});
36+
37+
describe('githubRedirect', () => {
38+
it('should call AuthService.githubLogin', async () => {
39+
const req = {} as Request;
40+
const res = {} as Response;
41+
42+
await controller.githubRedirect(req, res);
43+
44+
expect(authService.githubLogin).toHaveBeenCalledWith(req, res);
45+
});
46+
47+
it('should handle exceptions', async () => {
48+
const req = {} as Request;
49+
const res = {} as Response;
50+
const error = new Error('Test error');
51+
(authService.githubLogin as jest.Mock).mockRejectedValueOnce(error);
52+
53+
await expect(controller.githubRedirect(req, res)).rejects.toThrow(
54+
'Test error',
55+
);
56+
});
57+
});
58+
59+
describe('googleRedirect', () => {
60+
it('should call AuthService.googleLogin', async () => {
61+
const req = {} as Request;
62+
const res = {} as Response;
63+
64+
await controller.googleRedirect(req, res);
65+
66+
expect(authService.googleLogin).toHaveBeenCalledWith(req, res);
67+
});
68+
69+
it('should handle exceptions', async () => {
70+
const req = {} as Request;
71+
const res = {} as Response;
72+
const error = new Error('Test error');
73+
(authService.googleLogin as jest.Mock).mockRejectedValueOnce(error);
74+
75+
await expect(controller.googleRedirect(req, res)).rejects.toThrow(
76+
'Test error',
77+
);
78+
});
79+
});
80+
81+
describe('discordRedirect', () => {
82+
it('should call AuthService.discordLogin', async () => {
83+
const req = {} as Request;
84+
const res = {} as Response;
85+
86+
await controller.discordRedirect(req, res);
87+
88+
expect(authService.discordLogin).toHaveBeenCalledWith(req, res);
89+
});
90+
91+
it('should handle exceptions', async () => {
92+
const req = {} as Request;
93+
const res = {} as Response;
94+
const error = new Error('Test error');
95+
(authService.discordLogin as jest.Mock).mockRejectedValueOnce(error);
96+
97+
await expect(controller.discordRedirect(req, res)).rejects.toThrow(
98+
'Test error',
99+
);
100+
});
101+
});
102+
103+
describe('verify', () => {
104+
it('should call AuthService.verifyToken', async () => {
105+
const req = {} as Request;
106+
const res = {} as Response;
107+
108+
await controller.verify(req, res);
109+
110+
expect(authService.verifyToken).toHaveBeenCalledWith(req, res);
111+
});
112+
});
113+
});

0 commit comments

Comments
 (0)