Skip to content

Commit

Permalink
add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
virgilchiriac committed Oct 24, 2023
1 parent 1ebbf3e commit 73595f4
Show file tree
Hide file tree
Showing 4 changed files with 248 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,101 +37,161 @@ describe(`content element create (api)`, () => {
});

describe('with valid user', () => {
const setup = async () => {
await cleanupCollections(em);
describe('when parent is a card', () => {
const setup = async () => {
await cleanupCollections(em);

const { teacherAccount, teacherUser } = UserAndAccountTestFactory.buildTeacher();
const { teacherAccount, teacherUser } = UserAndAccountTestFactory.buildTeacher();

const course = courseFactory.build({ teachers: [teacherUser] });
await em.persistAndFlush([teacherAccount, teacherUser, course]);
const course = courseFactory.build({ teachers: [teacherUser] });
await em.persistAndFlush([teacherAccount, teacherUser, course]);

const columnBoardNode = columnBoardNodeFactory.buildWithId({
context: { id: course.id, type: BoardExternalReferenceType.Course },
const columnBoardNode = columnBoardNodeFactory.buildWithId({
context: { id: course.id, type: BoardExternalReferenceType.Course },
});
const columnNode = columnNodeFactory.buildWithId({ parent: columnBoardNode });
const cardNode = cardNodeFactory.buildWithId({ parent: columnNode });

await em.persistAndFlush([columnBoardNode, columnNode, cardNode]);
em.clear();

const loggedInClient = await testApiClient.login(teacherAccount);

return { loggedInClient, columnBoardNode, columnNode, cardNode };
};

it('should return status 201', async () => {
const { loggedInClient, cardNode } = await setup();

const response = await loggedInClient.post(`${cardNode.id}/elements`, { type: ContentElementType.RICH_TEXT });

expect(response.statusCode).toEqual(201);
});
const columnNode = columnNodeFactory.buildWithId({ parent: columnBoardNode });
const cardNode = cardNodeFactory.buildWithId({ parent: columnNode });

await em.persistAndFlush([columnBoardNode, columnNode, cardNode]);
em.clear();
it('should return the created content element of type RICH_TEXT', async () => {
const { loggedInClient, cardNode } = await setup();

const loggedInClient = await testApiClient.login(teacherAccount);
const response = await loggedInClient.post(`${cardNode.id}/elements`, { type: ContentElementType.RICH_TEXT });

return { loggedInClient, columnBoardNode, columnNode, cardNode };
};
expect((response.body as AnyContentElementResponse).type).toEqual(ContentElementType.RICH_TEXT);
});

it('should return status 201', async () => {
const { loggedInClient, cardNode } = await setup();
it('should return the created content element of type FILE', async () => {
const { loggedInClient, cardNode } = await setup();

const response = await loggedInClient.post(`${cardNode.id}/elements`, { type: ContentElementType.RICH_TEXT });
const response = await loggedInClient.post(`${cardNode.id}/elements`, { type: ContentElementType.FILE });

expect(response.statusCode).toEqual(201);
});
expect((response.body as AnyContentElementResponse).type).toEqual(ContentElementType.FILE);
});

it('should return the created content element of type RICH_TEXT', async () => {
const { loggedInClient, cardNode } = await setup();
it('should return the created content element of type EXTERNAL_TOOL', async () => {
const { loggedInClient, cardNode } = await setup();

const response = await loggedInClient.post(`${cardNode.id}/elements`, { type: ContentElementType.RICH_TEXT });
const response = await loggedInClient.post(`${cardNode.id}/elements`, {
type: ContentElementType.EXTERNAL_TOOL,
});

expect((response.body as AnyContentElementResponse).type).toEqual(ContentElementType.RICH_TEXT);
});
expect((response.body as AnyContentElementResponse).type).toEqual(ContentElementType.EXTERNAL_TOOL);
});

it('should return the created content element of type FILE', async () => {
const { loggedInClient, cardNode } = await setup();
it('should return the created content element of type SUBMISSION_CONTAINER with dueDate set to null', async () => {
const { loggedInClient, cardNode } = await setup();

const response = await loggedInClient.post(`${cardNode.id}/elements`, { type: ContentElementType.FILE });
const response = await loggedInClient.post(`${cardNode.id}/elements`, {
type: ContentElementType.SUBMISSION_CONTAINER,
});

expect((response.body as AnyContentElementResponse).type).toEqual(ContentElementType.FILE);
});
expect((response.body as AnyContentElementResponse).type).toEqual(ContentElementType.SUBMISSION_CONTAINER);
expect((response.body as SubmissionContainerElementResponse).content.dueDate).toBeNull();
});

it('should return the created content element of type EXTERNAL_TOOL', async () => {
const { loggedInClient, cardNode } = await setup();
it('should actually create the content element', async () => {
const { loggedInClient, cardNode } = await setup();
const response = await loggedInClient.post(`${cardNode.id}/elements`, { type: ContentElementType.RICH_TEXT });

const response = await loggedInClient.post(`${cardNode.id}/elements`, { type: ContentElementType.EXTERNAL_TOOL });
const elementId = (response.body as AnyContentElementResponse).id;

expect((response.body as AnyContentElementResponse).type).toEqual(ContentElementType.EXTERNAL_TOOL);
});
const result = await em.findOneOrFail(RichTextElementNode, elementId);
expect(result.id).toEqual(elementId);
});

it('should throw an error if toPosition param is not a number', async () => {
const { loggedInClient, cardNode } = await setup();

it('should return the created content element of type SUBMISSION_CONTAINER with dueDate set to null', async () => {
const { loggedInClient, cardNode } = await setup();
const response = await loggedInClient.post(`${cardNode.id}/elements`, {
type: ContentElementType.RICH_TEXT,
toPosition: 'not a number',
});

const response = await loggedInClient.post(`${cardNode.id}/elements`, {
type: ContentElementType.SUBMISSION_CONTAINER,
expect(response.statusCode).toEqual(400);
});

expect((response.body as AnyContentElementResponse).type).toEqual(ContentElementType.SUBMISSION_CONTAINER);
expect((response.body as SubmissionContainerElementResponse).content.dueDate).toBeNull();
it('should throw an error if toPosition param is a negative number', async () => {
const { loggedInClient, cardNode } = await setup();

const response = await loggedInClient.post(`${cardNode.id}/elements`, {
type: ContentElementType.RICH_TEXT,
toPosition: -1,
});

expect(response.statusCode).toEqual(400);
});
});

it('should actually create the content element', async () => {
const { loggedInClient, cardNode } = await setup();
const response = await loggedInClient.post(`${cardNode.id}/elements`, { type: ContentElementType.RICH_TEXT });
describe('when parent is a submission item', () => {
const setup = async () => {
await cleanupCollections(em);

const { teacherAccount, teacherUser } = UserAndAccountTestFactory.buildTeacher();

const elementId = (response.body as AnyContentElementResponse).id;
const course = courseFactory.build({ teachers: [teacherUser] });
await em.persistAndFlush([teacherAccount, teacherUser, course]);

const result = await em.findOneOrFail(RichTextElementNode, elementId);
expect(result.id).toEqual(elementId);
});
const columnBoardNode = columnBoardNodeFactory.buildWithId({
context: { id: course.id, type: BoardExternalReferenceType.Course },
});
const columnNode = columnNodeFactory.buildWithId({ parent: columnBoardNode });
const cardNode = cardNodeFactory.buildWithId({ parent: columnNode });
const submissionContainerNode = columnNodeFactory.buildWithId({ parent: cardNode });
const submissionItemNode = cardNodeFactory.buildWithId({ parent: submissionContainerNode });

await em.persistAndFlush([columnBoardNode, columnNode, cardNode, submissionContainerNode, submissionItemNode]);
em.clear();

const loggedInClient = await testApiClient.login(teacherAccount);

return { loggedInClient, cardNode, submissionItemNode };
};

it('should throw an error if toPosition param is not a number', async () => {
const { loggedInClient, cardNode } = await setup();
it('should return status 201', async () => {
const { loggedInClient, submissionItemNode } = await setup();

const response = await loggedInClient.post(`${cardNode.id}/elements`, {
type: ContentElementType.RICH_TEXT,
toPosition: 'not a number',
const response = await loggedInClient.post(`${submissionItemNode.id}/elements`, {
type: ContentElementType.RICH_TEXT,
});

expect(response.statusCode).toEqual(201);
});

expect(response.statusCode).toEqual(400);
});
it('should return the created content element of type RICH_TEXT', async () => {
const { loggedInClient, submissionItemNode } = await setup();

it('should throw an error if toPosition param is a negative number', async () => {
const { loggedInClient, cardNode } = await setup();
const response = await loggedInClient.post(`${submissionItemNode.id}/elements`, {
type: ContentElementType.RICH_TEXT,
});

const response = await loggedInClient.post(`${cardNode.id}/elements`, {
type: ContentElementType.RICH_TEXT,
toPosition: -1,
expect((response.body as AnyContentElementResponse).type).toEqual(ContentElementType.RICH_TEXT);
});

expect(response.statusCode).toEqual(400);
it('should return the created content element of type FILE', async () => {
const { loggedInClient, submissionItemNode } = await setup();

const response = await loggedInClient.post(`${submissionItemNode.id}/elements`, {
type: ContentElementType.FILE,
});

expect((response.body as AnyContentElementResponse).type).toEqual(ContentElementType.FILE);
});
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,43 @@ describe(ContentElementService.name, () => {
});
});

describe('findParentOfId', () => {
describe('when parent is a vaid node', () => {
const setup = () => {
const card = cardFactory.build();
const element = richTextElementFactory.build();

return { element, card };
};

it('should call the repo', async () => {
const { element, card } = setup();
boardDoRepo.findParentOfId.mockResolvedValueOnce(card);

await service.findParentOfId(element.id);

expect(boardDoRepo.findParentOfId).toHaveBeenCalledWith(element.id);
});

it('should throw NotFoundException', async () => {
const { element } = setup();

boardDoRepo.findParentOfId.mockResolvedValue(undefined);

await expect(service.findParentOfId(element.id)).rejects.toThrowError(NotFoundException);
});

it('should return the parent', async () => {
const { element, card } = setup();
boardDoRepo.findParentOfId.mockResolvedValueOnce(card);

const result = await service.findParentOfId(element.id);

expect(result).toEqual(card);
});
});
});

describe('create', () => {
describe('when creating a content element of type', () => {
const setup = () => {
Expand Down
70 changes: 63 additions & 7 deletions apps/server/src/modules/board/uc/element.uc.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ import {
userFactory,
} from '@shared/testing';
import { Logger } from '@src/core/logger';
import { AuthorizationService } from '@modules/authorization';
import { AuthorizationService, Action } from '@modules/authorization';
import { ObjectId } from 'bson';
import { ForbiddenException } from '@nestjs/common';
import { BoardDoAuthorizableService, ContentElementService, SubmissionItemService } from '../service';
import { ElementUc } from './element.uc';

Expand Down Expand Up @@ -123,6 +124,61 @@ describe(ElementUc.name, () => {
});

describe('deleteElement', () => {
describe('when deleting an element which has a submission item parent', () => {
const setup = () => {
const user = userFactory.build();
const element = richTextElementFactory.build();
const submissionItem = submissionItemFactory.build({ userId: user.id });

boardDoAuthorizableService.getBoardAuthorizable.mockResolvedValue(
new BoardDoAuthorizable({ users: [], id: new ObjectId().toHexString() })
);

elementService.findById.mockResolvedValueOnce(element);
return { element, user, submissionItem };
};

it('should call the service to find the element', async () => {
const { element, user } = setup();
await uc.deleteElement(user.id, element.id);

expect(elementService.findById).toHaveBeenCalledWith(element.id);
});

it('should call the service to find the parent of the element', async () => {
const { element, user } = setup();
await uc.deleteElement(user.id, element.id);

expect(elementService.findParentOfId).toHaveBeenCalledWith(element.id);
});

it('should throw if the user is not the owner of the submission item', async () => {
const { element, user } = setup();
const otherSubmissionItem = submissionItemFactory.build({ userId: new ObjectId().toHexString() });
elementService.findParentOfId.mockResolvedValueOnce(otherSubmissionItem);

await expect(uc.deleteElement(user.id, element.id)).rejects.toThrow(new ForbiddenException());
});

it('should authorize the user to delete the element', async () => {
const { element, user, submissionItem } = setup();
elementService.findParentOfId.mockResolvedValueOnce(submissionItem);
const boardDoAuthorizable = await boardDoAuthorizableService.getBoardAuthorizable(submissionItem);
const context = { action: Action.read, requiredPermissions: [] };
await uc.deleteElement(user.id, element.id);

expect(authorizationService.checkPermission).toHaveBeenCalledWith(user, boardDoAuthorizable, context);
});

it('should call the service to delete the element', async () => {
const { user, element, submissionItem } = setup();
elementService.findParentOfId.mockResolvedValueOnce(submissionItem);

await uc.deleteElement(user.id, element.id);

expect(elementService.delete).toHaveBeenCalledWith(element);
});
});
describe('when deleting a content element', () => {
const setup = () => {
const user = userFactory.build();
Expand Down Expand Up @@ -160,9 +216,9 @@ describe(ElementUc.name, () => {
const user = userFactory.build();
const fileElement = fileElementFactory.build();

const elementSpy = elementService.findById.mockResolvedValue(fileElement);
elementService.findById.mockResolvedValue(fileElement);

return { fileElement, user, elementSpy };
return { fileElement, user };
};

it('should throw', async () => {
Expand All @@ -181,9 +237,9 @@ describe(ElementUc.name, () => {

const submissionContainer = submissionContainerElementFactory.build({ children: [fileElement] });

const elementSpy = elementService.findById.mockResolvedValue(submissionContainer);
elementService.findById.mockResolvedValue(submissionContainer);

return { submissionContainer, fileElement, user, elementSpy };
return { submissionContainer, fileElement, user };
};

it('should throw', async () => {
Expand All @@ -202,9 +258,9 @@ describe(ElementUc.name, () => {
const submissionItem = submissionItemFactory.build({ userId: user.id });
const submissionContainer = submissionContainerElementFactory.build({ children: [submissionItem] });

const elementSpy = elementService.findById.mockResolvedValue(submissionContainer);
elementService.findById.mockResolvedValue(submissionContainer);

return { submissionContainer, submissionItem, user, elementSpy };
return { submissionContainer, submissionItem, user };
};

it('should throw', async () => {
Expand Down
Loading

0 comments on commit 73595f4

Please sign in to comment.