Skip to content

Commit

Permalink
Merge branch 'n21-2357-extend-copying-of-boards-for-board-card-links'…
Browse files Browse the repository at this point in the history
… of https://github.com/hpi-schul-cloud/schulcloud-server into n21-2357-extend-copying-of-boards-for-board-card-links
  • Loading branch information
sdinkov committed Jan 31, 2025
2 parents 4031955 + 9374b73 commit 7e276a7
Show file tree
Hide file tree
Showing 111 changed files with 3,124 additions and 1,534 deletions.
107 changes: 107 additions & 0 deletions apps/server/src/infra/boards-client/boards-client.adapter.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { Test, TestingModule } from '@nestjs/testing';
import { createMock } from '@golevelup/ts-jest';
import { faker } from '@faker-js/faker';
import { axiosResponseFactory } from '@testing/factory/axios-response.factory';
import { BoardsClientAdapter } from './boards-client.adapter';
import { BoardApi, BoardResponse, CreateBoardBodyParams, CreateBoardResponse } from './generated';

describe(BoardsClientAdapter.name, () => {
let module: TestingModule;
let sut: BoardsClientAdapter;

const boardApiMock = createMock<BoardApi>();

beforeAll(async () => {
module = await Test.createTestingModule({
providers: [
BoardsClientAdapter,
{
provide: BoardApi,
useValue: boardApiMock,
},
],
}).compile();
sut = module.get(BoardsClientAdapter);
});

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

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

it('should be defined', () => {
expect(sut).toBeDefined();
});

describe('createBoard', () => {
describe('when creating a board', () => {
const setup = () => {
const params: CreateBoardBodyParams = {
title: faker.lorem.words(),
layout: 'columns',
parentId: faker.string.uuid(),
parentType: 'course',
};
const responseData: CreateBoardResponse = {
id: faker.string.uuid(),
};

boardApiMock.boardControllerCreateBoard.mockResolvedValue(axiosResponseFactory.build({ data: responseData }));

return {
params,
responseData,
};
};

it('should call boardApi.boardControllerCreateBoard', async () => {
const { params, responseData } = setup();

const response = await sut.createBoard(params);

expect(response).toEqual(responseData);
expect(boardApiMock.boardControllerCreateBoard).toHaveBeenCalledWith(params);
});
});
});

describe('getBoardSkeletonById', () => {
describe('when reading a board', () => {
const setup = () => {
const boardId = faker.string.uuid();
const responseData: BoardResponse = {
id: boardId,
title: faker.lorem.words(),
layout: 'columns',
columns: [],
isVisible: true,
timestamps: {
createdAt: faker.date.recent().toISOString(),
lastUpdatedAt: faker.date.recent().toISOString(),
},
};

boardApiMock.boardControllerGetBoardSkeleton.mockResolvedValue(
axiosResponseFactory.build({ data: responseData })
);

return {
boardId,
responseData,
};
};

it('should call boardApi.boardControllerGetBoardSkeleton', async () => {
const { boardId, responseData } = setup();

const response = await sut.getBoardSkeletonById(boardId);

expect(response).toEqual(responseData);
expect(boardApiMock.boardControllerGetBoardSkeleton).toHaveBeenCalledWith(boardId);
});
});
});
});
19 changes: 19 additions & 0 deletions apps/server/src/infra/boards-client/boards-client.adapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Injectable } from '@nestjs/common';
import { BoardApi, BoardResponse, CreateBoardBodyParams, CreateBoardResponse } from './generated';

@Injectable()
export class BoardsClientAdapter {
constructor(private readonly boardApi: BoardApi) {}

public async createBoard(params: CreateBoardBodyParams): Promise<CreateBoardResponse> {
const response = await this.boardApi.boardControllerCreateBoard(params);

return response.data;
}

public async getBoardSkeletonById(boardId: string): Promise<BoardResponse> {
const response = await this.boardApi.boardControllerGetBoardSkeleton(boardId);

return response.data;
}
}
3 changes: 3 additions & 0 deletions apps/server/src/infra/boards-client/boards-client.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface BoardsClientConfig {
API_HOST: string;
}
60 changes: 60 additions & 0 deletions apps/server/src/infra/boards-client/boards-client.module.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Test, TestingModule } from '@nestjs/testing';
import { ConfigModule } from '@nestjs/config';
import { faker } from '@faker-js/faker';
import { Request } from 'express';
import { createMock } from '@golevelup/ts-jest';
import { REQUEST } from '@nestjs/core';
import { BoardsClientAdapter } from './boards-client.adapter';
import { BoardsClientConfig } from './boards-client.config';
import { BoardsClientModule } from './boards-client.module';

describe(BoardsClientModule.name, () => {
let module: TestingModule;

const requestMock = createMock<Request>({
headers: {
authorization: `Bearer ${faker.string.alphanumeric(42)}`,
},
});

beforeEach(async () => {
module = await Test.createTestingModule({
imports: [
BoardsClientModule,
ConfigModule.forRoot({
isGlobal: true,
load: [
(): BoardsClientConfig => {
return {
API_HOST: faker.internet.url(),
};
},
],
}),
],
})
.overrideProvider(REQUEST)
.useValue(requestMock)
.compile();
});

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

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

it('should be defined', () => {
expect(module).toBeDefined();
});

describe('when resolving dependencies', () => {
it('should resolve BoardsClientAdapter', async () => {
const adapter = await module.resolve(BoardsClientAdapter);

expect(adapter).toBeInstanceOf(BoardsClientAdapter);
});
});
});
31 changes: 31 additions & 0 deletions apps/server/src/infra/boards-client/boards-client.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Module, Scope } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { REQUEST } from '@nestjs/core';
import { Request } from 'express';
import { JwtExtractor } from '@shared/common/utils';
import { BoardsClientAdapter } from './boards-client.adapter';
import { BoardsClientConfig } from './boards-client.config';
import { Configuration, BoardApi } from './generated';

@Module({
providers: [
BoardsClientAdapter,
{
provide: BoardApi,
scope: Scope.REQUEST,
useFactory: (configService: ConfigService<BoardsClientConfig, true>, request: Request): BoardApi => {
const basePath = configService.getOrThrow<string>('API_HOST');
const accessToken = JwtExtractor.extractJwtFromRequest(request);
const configuration = new Configuration({
basePath: `${basePath}/v3`,
accessToken,
});

return new BoardApi(configuration);
},
inject: [ConfigService, REQUEST],
},
],
exports: [BoardsClientAdapter],
})
export class BoardsClientModule {}
Original file line number Diff line number Diff line change
@@ -1,24 +1,19 @@
.gitignore
.npmignore
api.ts
api/board-api.ts
base.ts
common.ts
configuration.ts
git_push.sh
index.ts
models/api-validation-error.ts
models/board-context-response.ts
models/board-external-reference-type.ts
models/board-layout.ts
models/board-parent-type.ts
models/board-response.ts
models/card-skeleton-response.ts
models/column-response.ts
models/copy-api-response.ts
models/create-board-body-params.ts
models/create-board-response.ts
models/index.ts
models/timestamps-response.ts
models/update-board-title-params.ts
models/visibility-body-params.ts
.gitignore
.npmignore
.openapi-generator-ignore
api.ts
api/board-api.ts
base.ts
common.ts
configuration.ts
git_push.sh
index.ts
models/board-layout.ts
models/board-parent-type.ts
models/board-response.ts
models/card-skeleton-response.ts
models/column-response.ts
models/create-board-body-params.ts
models/create-board-response.ts
models/index.ts
models/timestamps-response.ts
Loading

0 comments on commit 7e276a7

Please sign in to comment.