Skip to content

Commit

Permalink
test(backend): write integration tests on folder
Browse files Browse the repository at this point in the history
  • Loading branch information
tericcabrel committed Jun 9, 2024
1 parent 3d327ca commit d5797a8
Show file tree
Hide file tree
Showing 5 changed files with 275 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ describe('Test Authentication', () => {
password: 'password',
};

const { authToken, userId } = await testHelper.createAuthenticatedUser({ ...input });
const { authToken, user } = await testHelper.createAuthenticatedUser({ ...input });

const authenticatedUserQuery = `
query AuthenticatedUser {
Expand Down Expand Up @@ -241,7 +241,7 @@ describe('Test Authentication', () => {
expect(authenticatedUser).toMatchObject({
createdAt: expect.any(Number),
email: input.email,
id: userId,
id: user.id,
isEnabled: true,
name: input.name,
oauthProvider: 'email',
Expand All @@ -259,7 +259,7 @@ describe('Test Authentication', () => {
});

test('Log out the authenticated user', async () => {
const { authToken, userId } = await testHelper.createAuthenticatedUser({
const { authToken, user } = await testHelper.createAuthenticatedUser({
email: '[email protected]',
name: 'Jane Doe',
password: 'password',
Expand All @@ -281,7 +281,7 @@ describe('Test Authentication', () => {

const { authenticatedUser } = response.body.data;

expect(authenticatedUser.id).toEqual(userId);
expect(authenticatedUser.id).toEqual(user.id);

const logoutQuery = `
mutation LogoutUser {
Expand Down
2 changes: 0 additions & 2 deletions apps/backend/src/features/auth/graphql/auth.resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@ export class AuthResolvers {
@Mutation('logoutUser')
@UseGuards(AuthGuard)
async logoutUser(@UserId() userId: string | undefined): Promise<boolean> {
console.log('user logged out', userId);

if (!userId) {
return false;
}
Expand Down
175 changes: 175 additions & 0 deletions apps/backend/src/features/folders/graphql/folder.integration.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import request from 'supertest';

import { TestHelper } from '../../../utils/tests/helpers';
import { TestServer, startTestServer } from '../../../utils/tests/server';

const graphqlEndpoint = '/graphql';

describe('Test Folder', () => {
let server: TestServer;
let testHelper: TestHelper;

beforeAll(async () => {
server = await startTestServer();

testHelper = new TestHelper(server.app, graphqlEndpoint);
});

beforeEach(async () => {
await testHelper.cleanDatabase();
});

afterAll(async () => {
await server.close();
});

test("Fail to create a folder when the parent folder doesn't exist", async () => {
const { authToken } = await testHelper.createAuthenticatedUser({});

const query = `
mutation CreateFolder($input: CreateFolderInput!) {
createFolder(input: $input) {
id
}
}
`;

const variables = {
input: {
name: 'My First Folder',
parentId: 'non-existent-folder-id',
},
};

const response = await request(server.app.getHttpServer())
.post(graphqlEndpoint)
.set('Authorization', authToken)
.send({ query, variables })
.expect(200);

const [error] = response.body.errors;

expect(error.extensions.code).toEqual('FOLDER_NOT_FOUND');
expect(error.message).toEqual('The folder with the id non-existent-folder-id not found');
});

test('Fail to create a folder when a folder with the same name already exists in the parent folder', async () => {
const { authToken, user } = await testHelper.createAuthenticatedUser({});

await testHelper.createFolder(authToken, {
name: 'My First Folder',
parentId: user.rootFolderId,
});

const query = `
mutation CreateFolder($input: CreateFolderInput!) {
createFolder(input: $input) {
id
}
}
`;

const variables = {
input: {
name: 'My First Folder',
parentId: user.rootFolderId,
},
};

const response = await request(server.app.getHttpServer())
.post(graphqlEndpoint)
.set('Authorization', authToken)
.send({ query, variables })
.expect(200);

const [error] = response.body.errors;

expect(error.extensions.code).toEqual('FOLDER_ALREADY_EXIST');
expect(error.message).toEqual('A folder named "My First Folder" already exists');
});

// eslint-disable-next-line jest/no-disabled-tests
test.skip("Fail to create a folder when the parent folder doesn't belong to the authenticated user", async () => {
const { authToken } = await testHelper.createAuthenticatedUser({});
const { user: user2 } = await testHelper.createAuthenticatedUser({});

const query = `
mutation CreateFolder($input: CreateFolderInput!) {
createFolder(input: $input) {
id
}
}
`;

const variables = {
input: {
name: 'My First Folder',
parentId: user2.rootFolderId,
},
};

const response = await request(server.app.getHttpServer())
.post(graphqlEndpoint)
.set('Authorization', authToken)
.send({ query, variables })
.expect(200);

const [error] = response.body.errors;

expect(error.extensions.code).toEqual('FOLDER_NOT_BELONG_TO_USER');
expect(error.message).toEqual(
`The folder with the id ${user2.rootFolderId} does not belong to the authenticated user`,
);
});

test('Successfully create a folder', async () => {
const { authToken, user } = await testHelper.createAuthenticatedUser({});

const query = `
mutation CreateFolder($input: CreateFolderInput!) {
createFolder(input: $input) {
__typename
id
name
isFavorite
subFolders {
id
}
subFoldersCount
parent {
id
}
user {
id
}
}
}
`;

const variables = {
input: {
name: 'My First Folder',
parentId: user.rootFolderId,
},
};

const response = await request(server.app.getHttpServer())
.post(graphqlEndpoint)
.set('Authorization', authToken)
.send({ query, variables })
.expect(200);

const { createFolder } = response.body.data;

expect(createFolder).toMatchObject({
__typename: 'Folder',
id: expect.any(String),
isFavorite: false,
name: 'My First Folder',
parent: { id: user.rootFolderId },
subFolders: [],
subFoldersCount: 0,
user: { id: user.id },
});
});
});
8 changes: 6 additions & 2 deletions apps/backend/src/features/folders/graphql/folder.resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,12 @@ export class FolderResolvers {
}

@ResolveField()
async parent(@Parent() folder: Folder): Promise<Folder> {
return this.folderService.findById(folder.id);
async parent(@Parent() folder: Folder): Promise<Folder | null> {
if (!folder.parentId) {
return null;
}

return this.folderService.findById(folder.parentId);
}

@ResolveField()
Expand Down
102 changes: 90 additions & 12 deletions apps/backend/src/utils/tests/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
import { INestApplication } from '@nestjs/common';
import { randEmail, randFullName, randPassword } from '@ngneat/falso';
import { randEmail, randFullName, randPassword, randWord } from '@ngneat/falso';
import { PrismaService, RoleName } from '@snipcode/domain';
import { generateJwtToken } from '@snipcode/utils';
import request from 'supertest';

export type CreateUserInputArgs = {
type CreateUserInputArgs = {
email: string;
isEnabled: boolean;
name: string;
password: string | null;
role: RoleName;
};

type CreateAuthenticatedUserResult = {
authToken: string;
user: {
id: string;
rootFolderId: string;
};
};

type CreateFolderArgs = {
name: string;
parentId: string;
};

export class TestHelper {
constructor(
private readonly app: INestApplication,
Expand All @@ -21,8 +35,15 @@ export class TestHelper {
const prismaService = this.app.get(PrismaService);

await prismaService.snippet.deleteMany();

const childFolders = await prismaService.folder.findMany({ where: { NOT: { parent: null } } });

await prismaService.folder.deleteMany({ where: { id: { in: childFolders.map((folder) => folder.id) } } });

await prismaService.folder.deleteMany();

await prismaService.session.deleteMany();

await prismaService.user.deleteMany();
}

Expand Down Expand Up @@ -73,17 +94,17 @@ export class TestHelper {
return response.body.data.signupUser.userId;
}

async createAuthenticatedUser(input: Partial<CreateUserInputArgs>): Promise<{ authToken: string; userId: string }> {
async createAuthenticatedUser(args: Partial<CreateUserInputArgs>): Promise<CreateAuthenticatedUserResult> {
const createUserInput: Partial<CreateUserInputArgs> = {
...input,
email: input.email ?? randEmail(),
isEnabled: input.isEnabled ?? true,
password: input.password ?? randPassword(),
...args,
email: args.email ?? randEmail(),
isEnabled: args.isEnabled ?? true,
password: args.password ?? randPassword(),
};

const userId = await this.signupUser(createUserInput);
await this.signupUser(createUserInput);

const query = `
const loginQuery = `
mutation LoginUser($email: String!, $password: String!) {
loginUser(email: $email, password: $password) {
token
Expand All @@ -96,11 +117,68 @@ export class TestHelper {
password: createUserInput.password,
};

const response = await request(this.app.getHttpServer()).post(this.graphqlEndpoint).send({ query, variables });
const loginResponse = await request(this.app.getHttpServer())
.post(this.graphqlEndpoint)
.send({ query: loginQuery, variables });

const authToken = loginResponse.body.data.loginUser.token;

const authenticatedUserQuery = `
query AuthenticatedUser {
authenticatedUser {
id
name
rootFolder {
id
name
}
}
}
`;

const authenticatedUserResponse = await request(this.app.getHttpServer())
.post(this.graphqlEndpoint)
.set('Authorization', authToken)
.send({ query: authenticatedUserQuery })
.expect(200);

const { authenticatedUser } = authenticatedUserResponse.body.data;

return {
authToken: response.body.data.loginUser.token,
userId,
authToken,
user: {
id: authenticatedUser.id,
rootFolderId: authenticatedUser.rootFolder.id,
},
};
}

async createFolder(authToken: string, args: Partial<CreateFolderArgs>): Promise<string> {
const createFolderInput: Partial<CreateFolderArgs> = {
...args,
name: args.name ?? randWord(),
};

const query = `
mutation CreateFolder($input: CreateFolderInput!) {
createFolder(input: $input) {
id
}
}
`;

const variables = {
input: {
name: createFolderInput.name,
parentId: createFolderInput.parentId,
},
};

const response = await request(this.app.getHttpServer())
.post(this.graphqlEndpoint)
.set('Authorization', authToken)
.send({ query, variables });

return response.body.data.createFolder.id;
}
}

0 comments on commit d5797a8

Please sign in to comment.