-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test(backend): integration test for github authentication
- Loading branch information
1 parent
a53c069
commit 7a26b7e
Showing
11 changed files
with
571 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
109 changes: 109 additions & 0 deletions
109
apps/backend/src/features/auth/rest/auth.provider.integration.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
import * as url from 'node:url'; | ||
|
||
import { SessionService } from '@snipcode/domain'; | ||
import { HttpResponse, http } from 'msw'; | ||
import { setupServer } from 'msw/node'; | ||
import request from 'supertest'; | ||
|
||
import { TestHelper } from '../../../utils/tests/helpers'; | ||
import { TestServer, startTestServer } from '../../../utils/tests/server'; | ||
import { GitHubUserResponse } from '../types'; | ||
|
||
const mockServer = setupServer( | ||
http.post('https://github.com/login/oauth/access_token', ({ request }) => { | ||
const url = new URL(request.url); | ||
|
||
const code = url.searchParams.get('code'); | ||
const clientId = url.searchParams.get('client_id'); | ||
const clientSecret = url.searchParams.get('client_secret'); | ||
|
||
if (!code || !clientId || !clientSecret) { | ||
return HttpResponse.json({ message: 'Invalid request' }, { status: 400 }); | ||
} | ||
|
||
if (code === 'valid_code') { | ||
const data = { | ||
access_token: 'valid_token', | ||
}; | ||
|
||
return HttpResponse.json(data); | ||
} | ||
|
||
return HttpResponse.json({ message: 'Invalid token' }, { status: 401 }); | ||
}), | ||
|
||
http.get('https://api.github.com/user', ({ request }) => { | ||
const authHeader = request.headers.get('Authorization'); | ||
|
||
if (authHeader === 'token valid_token') { | ||
const user: GitHubUserResponse = { | ||
avatar_url: 'https://avatars.githubusercontent.com/u/1?v=4', | ||
email: '[email protected]', | ||
login: 'octocat', | ||
name: 'monalisa octocat', | ||
}; | ||
|
||
return HttpResponse.json(user); | ||
} | ||
|
||
return HttpResponse.json({ message: 'Invalid token' }, { status: 401 }); | ||
}), | ||
); | ||
|
||
describe('Test Authentication controller', () => { | ||
let server: TestServer; | ||
let testHelper: TestHelper; | ||
let sessionService: SessionService; | ||
|
||
beforeAll(async () => { | ||
server = await startTestServer(); | ||
|
||
sessionService = server.app.get<SessionService>(SessionService); | ||
|
||
testHelper = new TestHelper(server.app); | ||
|
||
mockServer.listen({ | ||
onUnhandledRequest: (req) => { | ||
if (req.url.includes('127.0.0.1') || req.url.includes('localhost')) { | ||
return; | ||
} | ||
console.error(`No request mock for [${req.method}] ${req.url}`); | ||
}, | ||
}); | ||
}); | ||
|
||
beforeEach(async () => { | ||
await testHelper.cleanDatabase(); | ||
}); | ||
|
||
afterEach(() => mockServer.resetHandlers()); | ||
|
||
afterAll(async () => { | ||
mockServer.close(); | ||
await server.close(); | ||
}); | ||
|
||
test('Authenticate with GitHub', async () => { | ||
const response = await request(server.app.getHttpServer()) | ||
.get('/auth/github/callback?code=valid_code') | ||
.send({}) | ||
.expect(302); | ||
|
||
const parsedUrl = url.parse(response.headers.location, true); | ||
|
||
expect(`${parsedUrl.protocol}//${parsedUrl.host}${parsedUrl.pathname}`).toBe('http:https://localhost:7500/auth/success'); | ||
expect(parsedUrl.query.token).toBeDefined(); | ||
|
||
const sessionToken = parsedUrl.query.token as string; | ||
const session = await sessionService.findByToken(sessionToken); | ||
|
||
expect(session).toBeDefined(); | ||
|
||
const user = await testHelper.getAuthenticatedUser(sessionToken); | ||
|
||
expect(user).toMatchObject({ | ||
id: expect.any(String), | ||
rootFolderId: expect.any(String), | ||
}); | ||
}); | ||
}); |
159 changes: 159 additions & 0 deletions
159
apps/backend/src/features/auth/services/github.service.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
import { ConfigService } from '@nestjs/config'; | ||
import { Test, TestingModule } from '@nestjs/testing'; | ||
import { User } from '@snipcode/domain'; | ||
import { HttpResponse, http } from 'msw'; | ||
import { setupServer } from 'msw/node'; | ||
|
||
import { GithubService } from './github.service'; | ||
import { GitHubUserResponse } from '../types'; | ||
|
||
const server = setupServer( | ||
http.get('https://api.github.com/user', ({ request }) => { | ||
const authHeader = request.headers.get('Authorization'); | ||
|
||
if (authHeader === 'token valid_token') { | ||
const user: GitHubUserResponse = { | ||
avatar_url: 'https://avatars.githubusercontent.com/u/1?v=4', | ||
email: '[email protected]', | ||
login: 'octocat', | ||
name: 'monalisa octocat', | ||
}; | ||
|
||
return HttpResponse.json(user); | ||
} | ||
|
||
return HttpResponse.json({ message: 'Invalid token' }, { status: 401 }); | ||
}), | ||
|
||
http.post('https://github.com/login/oauth/access_token', ({ request }) => { | ||
const url = new URL(request.url); | ||
|
||
const code = url.searchParams.get('code'); | ||
const clientId = url.searchParams.get('client_id'); | ||
const clientSecret = url.searchParams.get('client_secret'); | ||
|
||
if (!code || !clientId || !clientSecret) { | ||
return HttpResponse.json({ message: 'Invalid request' }, { status: 400 }); | ||
} | ||
|
||
if (code === 'valid_code') { | ||
const data = { | ||
access_token: 'valid_token', | ||
}; | ||
|
||
return HttpResponse.json(data); | ||
} | ||
|
||
return HttpResponse.json({ message: 'Invalid token' }, { status: 401 }); | ||
}), | ||
); | ||
|
||
describe('Test GithubService', () => { | ||
let githubService: GithubService; | ||
|
||
beforeAll(() => | ||
server.listen({ | ||
onUnhandledRequest: (req) => console.error(`No request mock for [${req.method}] ${req.url}`), | ||
}), | ||
); | ||
|
||
beforeEach(async () => { | ||
const app: TestingModule = await Test.createTestingModule({ | ||
providers: [ConfigService, GithubService], | ||
}).compile(); | ||
|
||
githubService = app.get<GithubService>(GithubService); | ||
}); | ||
|
||
afterEach(() => server.resetHandlers()); | ||
|
||
afterAll(() => server.close()); | ||
|
||
it('should return user data when access token is valid', async () => { | ||
const result = await githubService.retrieveGitHubUserData('valid_token'); | ||
|
||
expect(result).toEqual({ | ||
avatar_url: 'https://avatars.githubusercontent.com/u/1?v=4', | ||
email: '[email protected]', | ||
login: 'octocat', | ||
name: 'monalisa octocat', | ||
}); | ||
}); | ||
|
||
it('should throw an error when access token is invalid', async () => { | ||
await expect(githubService.retrieveGitHubUserData('invalid_token')).rejects.toThrow(); | ||
}); | ||
|
||
it('should return access token when code is valid', async () => { | ||
const result = await githubService.requestAccessTokenFromCode('valid_code'); | ||
|
||
expect(result).toEqual('valid_token'); | ||
}); | ||
|
||
it('should throw an error when code is invalid', async () => { | ||
await expect(githubService.requestAccessTokenFromCode('invalid_code')).rejects.toThrow(); | ||
}); | ||
|
||
it('should generate user registration input from GitHub data', () => { | ||
const data: GitHubUserResponse = { | ||
avatar_url: 'https://avatars.githubusercontent.com/u/1?v=4', | ||
email: '[email protected]', | ||
login: 'octocat', | ||
name: 'monalisa octocat', | ||
}; | ||
|
||
const result = githubService.generateUserRegistrationInputFromGitHubData(data, 'role_id'); | ||
|
||
expect(result).toMatchObject({ | ||
_input: { | ||
email: '[email protected]', | ||
name: 'monalisa octocat', | ||
oauthProvider: 'github', | ||
pictureUrl: 'https://avatars.githubusercontent.com/u/1?v=4', | ||
roleId: 'role_id', | ||
timezone: null, | ||
username: 'octocat', | ||
}, | ||
enabled: true, | ||
hashedPassword: null, | ||
userId: expect.any(String), | ||
}); | ||
}); | ||
|
||
it('should generate user update input from GitHub data', () => { | ||
const data: GitHubUserResponse = { | ||
avatar_url: 'https://avatars.githubusercontent.com/u/2?v=4', | ||
email: '[email protected]', | ||
login: 'octocat', | ||
name: 'monalisa octocat 2', | ||
}; | ||
|
||
const user: User = { | ||
createdAt: new Date(), | ||
email: '[email protected]', | ||
id: 'userId', | ||
isEnabled: true, | ||
name: 'octocat', | ||
oauthProvider: 'github', | ||
password: 'password', | ||
pictureUrl: 'https://avatars.githubusercontent.com/u/1?v=4', | ||
roleId: 'roleId', | ||
timezone: null, | ||
updatedAt: new Date(), | ||
username: 'octocat', | ||
}; | ||
|
||
const result = githubService.generateUserUpdateInputFromGitHubData(user, data); | ||
|
||
expect(result).toMatchObject({ | ||
_input: { | ||
name: 'monalisa octocat 2', | ||
oauthProvider: 'github', | ||
pictureUrl: 'https://avatars.githubusercontent.com/u/2?v=4', | ||
roleId: 'roleId', | ||
timezone: null, | ||
}, | ||
enabled: true, | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.