-
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: write integration tests for authentication
- Loading branch information
1 parent
d6f8f03
commit 67856a7
Showing
25 changed files
with
659 additions
and
199 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
NODE_ENV=test | ||
APP_VERSION=1.1.0 | ||
HOST=http:https://localhost | ||
PORT=7509 | ||
INTROSPECTION_ENABLED=false | ||
DATABASE_URL="mysql:https://root:[email protected]:3313/snipcode" | ||
ADMIN_PASSWORD=qwerty | ||
CONVERTKIT_API_KEY=convertkit-api-key | ||
CONVERTKIT_FORM_ID=convertkit-form-id | ||
CONVERTKIT_TAG_ID=convertkit-tag-id | ||
GITHUB_CLIENT_ID=github-client-id | ||
GITHUB_CLIENT_SECRET=github-client-secret | ||
WEB_APP_URL=http:https://localhost:7500 | ||
WEB_AUTH_SUCCESS_URL=http:https://localhost:7500/auth/success | ||
WEB_AUTH_ERROR_URL=http:https://localhost:7500/auth/error | ||
SESSION_LIFETIME=90 | ||
SENTRY_DSN=sentry-dsn | ||
SENTRY_ENABLED=false | ||
SNIPPET_RENDERER_API_URL=http:https://localhost:3000/dev |
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 was deleted.
Oops, something went wrong.
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,22 @@ | ||
import request from 'supertest'; | ||
|
||
import { TestServer, startTestServer } from '../../utils/tests/server'; | ||
|
||
describe('Application Common Endpoints', () => { | ||
let server: TestServer; | ||
|
||
beforeAll(async () => { | ||
server = await startTestServer(); | ||
}); | ||
|
||
afterAll(async () => { | ||
await server.close(); | ||
}); | ||
|
||
test('The entry endpoint returns a Hello world message', async () => { | ||
const response = await request(server.app.getHttpServer()).get('/').expect(200); | ||
|
||
expect(response.body).toEqual({}); | ||
expect(response.text).toBe('Hello from Snipcode!'); | ||
}); | ||
}); |
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,51 @@ | ||
import { ConfigService } from '@nestjs/config'; | ||
import { Test, TestingModule } from '@nestjs/testing'; | ||
import { PrismaService, RoleService, UserService } from '@snipcode/domain'; | ||
import { mock } from 'jest-mock-extended'; | ||
|
||
import { AppService } from './app.service'; | ||
|
||
const prismaServiceMock = mock<PrismaService>(); | ||
const roleServiceMock = mock<RoleService>(); | ||
const userServiceMock = mock<UserService>(); | ||
|
||
describe('Test App Service', () => { | ||
let appService: AppService; | ||
let roleService: RoleService; | ||
let userService: UserService; | ||
|
||
beforeEach(async () => { | ||
const app: TestingModule = await Test.createTestingModule({ | ||
providers: [ | ||
{ provide: PrismaService, useValue: prismaServiceMock }, | ||
ConfigService, | ||
{ provide: UserService, useValue: userServiceMock }, | ||
{ provide: RoleService, useValue: roleServiceMock }, | ||
AppService, | ||
], | ||
}).compile(); | ||
|
||
appService = app.get<AppService>(AppService); | ||
roleService = app.get<RoleService>(RoleService); | ||
userService = app.get<UserService>(UserService); | ||
}); | ||
|
||
test('load default roles and users on service initialization', async () => { | ||
const role = { | ||
createdAt: new Date(), | ||
description: 'Administrator', | ||
id: '1', | ||
level: 1, | ||
name: 'admin' as const, | ||
updatedAt: new Date(), | ||
}; | ||
|
||
roleServiceMock.findByName.mockResolvedValueOnce(role); | ||
|
||
await expect(appService.onModuleInit()).resolves.not.toThrow(); | ||
|
||
expect(roleService.loadRoles).toHaveBeenCalledTimes(1); | ||
expect(userService.loadAdminUser).toHaveBeenCalledTimes(1); | ||
expect(userService.loadAdminUser).toHaveBeenCalledWith(role, 'qwerty'); | ||
}); | ||
}); |
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
172 changes: 172 additions & 0 deletions
172
apps/backend/src/features/auth/graphql/auth.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,172 @@ | ||
import { PrismaService, RoleService, UserService } from '@snipcode/domain'; | ||
import { isValidUUIDV4 } from '@snipcode/utils'; | ||
import request from 'supertest'; | ||
|
||
import { TestHelper } from '../../../utils/tests/helpers'; | ||
import { TestServer, startTestServer } from '../../../utils/tests/server'; | ||
|
||
const graphqlEndpoint = '/graphql'; | ||
|
||
describe('Test Authentication', () => { | ||
let server: TestServer; | ||
let testHelper: TestHelper; | ||
let prismaService: PrismaService; | ||
let roleService: RoleService; | ||
let userService: UserService; | ||
|
||
beforeAll(async () => { | ||
server = await startTestServer(); | ||
|
||
prismaService = server.app.get<PrismaService>(PrismaService); | ||
userService = server.app.get<UserService>(UserService); | ||
roleService = server.app.get<RoleService>(RoleService); | ||
|
||
testHelper = new TestHelper(prismaService, roleService, userService); | ||
}); | ||
|
||
beforeEach(async () => { | ||
await testHelper.cleanDatabase(); | ||
}); | ||
|
||
afterAll(async () => { | ||
await server.close(); | ||
}); | ||
|
||
test('Register a user', async () => { | ||
const query = ` | ||
mutation SignupUser($input: SignupUserInput!) { | ||
signupUser(input: $input) { | ||
__typename | ||
message | ||
} | ||
} | ||
`; | ||
const variables = { | ||
input: { | ||
email: '[email protected]', | ||
name: 'John Doe', | ||
password: 'password', | ||
}, | ||
}; | ||
|
||
const response = await request(server.app.getHttpServer()) | ||
.post(graphqlEndpoint) | ||
.send({ query, variables }) | ||
.expect(200); | ||
|
||
expect(response.body.data.signupUser).toMatchObject({ | ||
__typename: 'SignupUserResult', | ||
message: 'Account created successfully!', | ||
}); | ||
}); | ||
|
||
test('Register a user with an existing email address will returns an error', async () => { | ||
const query = ` | ||
mutation SignupUser($input: SignupUserInput!) { | ||
signupUser(input: $input) { | ||
__typename | ||
message | ||
} | ||
} | ||
`; | ||
const variables = { | ||
input: { | ||
email: '[email protected]', | ||
name: 'John Doe', | ||
password: 'password', | ||
}, | ||
}; | ||
|
||
await testHelper.createTestUser({ email: variables.input.email }); | ||
|
||
const response = await request(server.app.getHttpServer()) | ||
.post(graphqlEndpoint) | ||
.send({ query, variables }) | ||
.expect(200); | ||
|
||
expect(response.body.errors[0].extensions.code).toEqual('EMAIL_ALREADY_TAKEN'); | ||
expect(response.body.errors[0].message).toEqual('The email address is already taken'); | ||
}); | ||
|
||
test('Returns an error when authenticating with bad credentials', async () => { | ||
const query = ` | ||
mutation LoginUser($email: String!, $password: String!) { | ||
loginUser(email: $email, password: $password) { | ||
token | ||
} | ||
} | ||
`; | ||
const variables = { | ||
email: '[email protected]', | ||
password: '123456', | ||
}; | ||
|
||
const response = await request(server.app.getHttpServer()) | ||
.post(graphqlEndpoint) | ||
.send({ query, variables }) | ||
.expect(200); | ||
|
||
expect(response.body.errors[0].extensions.code).toEqual('LOGIN_FAILED'); | ||
expect(response.body.errors[0].message).toEqual('Invalid email address or password.'); | ||
}); | ||
|
||
test('Returns a token when authenticating with correct credentials', async () => { | ||
const query = ` | ||
mutation LoginUser($email: String!, $password: String!) { | ||
loginUser(email: $email, password: $password) { | ||
token | ||
} | ||
} | ||
`; | ||
|
||
await testHelper.createTestUser({ | ||
email: '[email protected]', | ||
isEnabled: true, | ||
password: 'password', | ||
role: 'user', | ||
}); | ||
|
||
const variables = { | ||
email: '[email protected]', | ||
password: 'password', | ||
}; | ||
|
||
const response = await request(server.app.getHttpServer()) | ||
.post(graphqlEndpoint) | ||
.send({ query, variables }) | ||
.expect(200); | ||
|
||
expect(response.body.data.loginUser.token).toBeDefined(); | ||
expect(isValidUUIDV4(response.body.data.loginUser.token)).toBe(true); | ||
}); | ||
|
||
test('Returns an error message when trying to authenticate with a disabled account', async () => { | ||
const query = ` | ||
mutation LoginUser($email: String!, $password: String!) { | ||
loginUser(email: $email, password: $password) { | ||
token | ||
} | ||
} | ||
`; | ||
|
||
await testHelper.createTestUser({ | ||
email: '[email protected]', | ||
isEnabled: false, | ||
password: 'password', | ||
role: 'user', | ||
}); | ||
|
||
const variables = { | ||
email: '[email protected]', | ||
password: 'password', | ||
}; | ||
|
||
const response = await request(server.app.getHttpServer()) | ||
.post(graphqlEndpoint) | ||
.send({ query, variables }) | ||
.expect(200); | ||
|
||
expect(response.body.errors[0].extensions.code).toEqual('ACCOUNT_DISABLED'); | ||
expect(response.body.errors[0].message).toEqual('Your account is disabled!'); | ||
}); | ||
}); |
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
Oops, something went wrong.