Skip to content

Commit

Permalink
Merge branch 'BC-6871-board-refactor' of github.com:hpi-schul-cloud/s…
Browse files Browse the repository at this point in the history
…chulcloud-server into BC-6871-board-refactor
  • Loading branch information
uidp committed Jun 13, 2024
2 parents 2bc45dd + 18a6a8e commit b521db4
Show file tree
Hide file tree
Showing 5 changed files with 280 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ import { BoardLayout } from '../../../domain/types';
export class LayoutBodyParams {
@IsEnum(BoardLayout)
@NotEquals(BoardLayout[BoardLayout.COLUMNS])
@ApiProperty({ enum: BoardLayout, enumName: 'BoardLayout' })
@ApiProperty({ enum: BoardLayout, enumName: 'MediaBoardLayoutType' })
layout!: BoardLayout;
}
8 changes: 7 additions & 1 deletion apps/server/src/modules/board/domain/type-mapping.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getBoardNodeType } from './type-mapping';
import { getBoardNodeType, handleNonExhaustiveSwitch } from './type-mapping';

import { BoardNodeType } from './types/board-node-type.enum';

Expand Down Expand Up @@ -44,3 +44,9 @@ describe('getBoardNodeType', () => {
expect(() => getBoardNodeType(new UnknownType() as any)).toThrow();
});
});

describe('handleNonExhaustiveSwitch', () => {
it('should throw error', () => {
expect(() => handleNonExhaustiveSwitch('unknown' as never)).toThrow();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,18 @@ describe(BoardNodePermissionService.name, () => {
const result = service.isUserBoardEditor(user.id, boardDoAuthorizable.users);
expect(result).toBe(false);
});

it('should return false if user is not part of board', () => {
const { anyBoardDo, user } = setup();
const boardDoAuthorizable = new BoardNodeAuthorizable({
users: [],
id: anyBoardDo.id,
boardNode: anyBoardDo,
rootNode: anyBoardDo,
});
const result = service.isUserBoardEditor(user.id, boardDoAuthorizable.users);
expect(result).toBe(false);
});
});

describe('isUserBoardReader', () => {
Expand Down
125 changes: 125 additions & 0 deletions apps/server/src/modules/board/service/column-board.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { Test, TestingModule } from '@nestjs/testing';
import { EntityId } from '@shared/domain/types';
import { createMock, DeepMocked } from '@golevelup/ts-jest';
import { ColumnBoardService } from './column-board.service';
import { BoardNodeRepo } from '../repo';
import { BoardNodeService } from './board-node.service';
import { ColumnBoardCopyService, ColumnBoardLinkService } from './internal';
import { ColumnBoard, BoardExternalReference, BoardExternalReferenceType } from '../domain';

import { columnBoardFactory } from '../testing';
import { CopyElementType, CopyStatus, CopyStatusEnum } from '../../copy-helper';

describe('ColumnBoardService', () => {
let service: ColumnBoardService;
let repo: jest.Mocked<BoardNodeRepo>;
let boardNodeService: jest.Mocked<BoardNodeService>;
let columnBoardCopyService: DeepMocked<ColumnBoardCopyService>;
let columnBoardLinkService: DeepMocked<ColumnBoardLinkService>;

beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
ColumnBoardService,
{
provide: BoardNodeRepo,
useValue: createMock<BoardNodeRepo>(),
},
{
provide: BoardNodeService,
useValue: createMock<BoardNodeService>(),
},
{
provide: ColumnBoardCopyService,
useValue: createMock<ColumnBoardCopyService>(),
},
{
provide: ColumnBoardLinkService,
useValue: createMock<ColumnBoardLinkService>(),
},
],
}).compile();

service = module.get<ColumnBoardService>(ColumnBoardService);
repo = module.get(BoardNodeRepo);
boardNodeService = module.get(BoardNodeService);
columnBoardCopyService = module.get(ColumnBoardCopyService);
columnBoardLinkService = module.get(ColumnBoardLinkService);
});

beforeEach(() => {
jest.clearAllMocks();
});

it('should find ColumnBoard by id', async () => {
const columnBoard = columnBoardFactory.build();
boardNodeService.findByClassAndId.mockResolvedValue(columnBoard);

const result = await service.findById('1');

expect(result).toBe(columnBoard);
expect(boardNodeService.findByClassAndId).toHaveBeenCalledWith(ColumnBoard, '1', undefined);
});

it('should find ColumnBoards by external reference', async () => {
const columnBoard = columnBoardFactory.build();
repo.findByExternalReference.mockResolvedValue([columnBoard]);
const reference: BoardExternalReference = {
type: BoardExternalReferenceType.Course,
id: '1',
};

const result = await service.findByExternalReference(reference);

expect(result).toEqual([columnBoard]);
expect(repo.findByExternalReference).toHaveBeenCalledWith(reference, undefined);
});

it('should update ColumnBoard visibility', async () => {
const columnBoard = columnBoardFactory.build();

await service.updateVisibility(columnBoard, true);

expect(boardNodeService.updateVisibility).toHaveBeenCalledWith(columnBoard, true);
});

it('should delete ColumnBoards by course id', async () => {
const columnBoard = columnBoardFactory.build();
repo.findByExternalReference.mockResolvedValue([columnBoard]);
const reference: BoardExternalReference = {
type: BoardExternalReferenceType.Course,
id: '1',
};

await service.deleteByCourseId('1');

expect(repo.findByExternalReference).toHaveBeenCalledWith(reference, undefined);
expect(repo.delete).toHaveBeenCalledWith([columnBoard]);
});

it('should copy ColumnBoard', async () => {
const copyStatus: CopyStatus = { status: CopyStatusEnum.SUCCESS, type: CopyElementType.COLUMNBOARD };
columnBoardCopyService.copyColumnBoard.mockResolvedValue(copyStatus);
const result = await service.copyColumnBoard({
originalColumnBoardId: '1',
destinationExternalReference: {
type: BoardExternalReferenceType.Course,
id: '1',
},
userId: '1',
});

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

it('should swap Linked Ids', async () => {
const idMap = new Map<EntityId, EntityId>();
idMap.set('1', '2');
const columnBoard = columnBoardFactory.build();
columnBoardLinkService.swapLinkedIds.mockResolvedValue(columnBoard);

const result = await service.swapLinkedIds('1', idMap);

expect(result).toEqual(columnBoard);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import { createMock, DeepMocked } from '@golevelup/ts-jest';
import { Test, TestingModule } from '@nestjs/testing';
import { InputFormat } from '@shared/domain/types';
import { ContentElementUpdateService } from './content-element-update.service';
import {
FileContentBody,
LinkContentBody,
RichTextContentBody,
DrawingContentBody,
SubmissionContainerContentBody,
ExternalToolContentBody,
} from '../../controller/dto';
import { BoardNodeRepo } from '../../repo';

import {
drawingElementFactory,
externalToolElementFactory,
fileElementFactory,
linkElementFactory,
richTextElementFactory,
submissionContainerElementFactory,
} from '../../testing';

describe('ContentElementUpdateService', () => {
let module: TestingModule;
let service: ContentElementUpdateService;
let repo: DeepMocked<BoardNodeRepo>;

beforeAll(async () => {
module = await Test.createTestingModule({
providers: [
ContentElementUpdateService,
{
provide: BoardNodeRepo,
useValue: createMock<BoardNodeRepo>(),
},
],
}).compile();

service = module.get(ContentElementUpdateService);
repo = module.get(BoardNodeRepo);
});

beforeEach(() => {
jest.clearAllMocks();
});

it('should update FileElement', async () => {
const element = fileElementFactory.build();
const content = new FileContentBody();
content.caption = 'caption';
content.alternativeText = 'alternativeText';

await service.updateContent(element, content);

expect(element.caption).toBe('caption');
expect(element.alternativeText).toBe('alternativeText');
expect(repo.save).toHaveBeenCalledWith(element);
});

it('should update LinkElement', async () => {
const element = linkElementFactory.build();
const content = new LinkContentBody();
content.url = 'http://example.com/';
content.title = 'title';
content.description = 'description';
content.imageUrl = 'relative-image.jpg';

await service.updateContent(element, content);

expect(element.url).toBe('http://example.com/');
expect(element.title).toBe('title');
expect(element.description).toBe('description');
expect(element.imageUrl).toBe('relative-image.jpg');
expect(repo.save).toHaveBeenCalledWith(element);
});

it('should update RichTextElement', async () => {
const element = richTextElementFactory.build();
const content = new RichTextContentBody();
content.text = 'text';
content.inputFormat = InputFormat.PLAIN_TEXT;

await service.updateContent(element, content);

expect(element.text).toBe('text');
expect(element.inputFormat).toBe(InputFormat.PLAIN_TEXT);
expect(repo.save).toHaveBeenCalledWith(element);
});

it('should update DrawingElement', async () => {
const element = drawingElementFactory.build();
const content = new DrawingContentBody();
content.description = 'description';

await service.updateContent(element, content);

expect(element.description).toBe('description');
expect(repo.save).toHaveBeenCalledWith(element);
});

it('should update SubmissionContainerElement', async () => {
const element = submissionContainerElementFactory.build();
const content = new SubmissionContainerContentBody();
content.dueDate = new Date();

await service.updateContent(element, content);

expect(element.dueDate).toEqual(content.dueDate);
expect(repo.save).toHaveBeenCalledWith(element);
});

it('should update ExternalToolElement', async () => {
const element = externalToolElementFactory.build();
const content = new ExternalToolContentBody();
content.contextExternalToolId = 'contextExternalToolId';

await service.updateContent(element, content);

expect(element.contextExternalToolId).toBe('contextExternalToolId');
expect(repo.save).toHaveBeenCalledWith(element);
});

it('should throw error for unknown element type', async () => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const element = {} as any;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const content = {} as any;

// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
await expect(service.updateContent(element, content)).rejects.toThrowError(
"Cannot update element of type: 'Object'"
);
});
});

0 comments on commit b521db4

Please sign in to comment.