-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'BC-5629-batch-deletion-mechanism' of https://github.com…
…/hpi-schul-cloud/schulcloud-server into BC-5629-batch-deletion-mechanism
- Loading branch information
Showing
75 changed files
with
8,951 additions
and
171 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
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
178 changes: 178 additions & 0 deletions
178
apps/server/src/modules/h5p-editor/controller/api-test/h5p-editor-ajax.api.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,178 @@ | ||
import { DeepMocked, createMock } from '@golevelup/ts-jest'; | ||
import { H5PAjaxEndpoint } from '@lumieducation/h5p-server'; | ||
import { EntityManager } from '@mikro-orm/core'; | ||
import { HttpStatus, INestApplication } from '@nestjs/common'; | ||
import { Test } from '@nestjs/testing'; | ||
import { S3ClientAdapter } from '@shared/infra/s3-client'; | ||
import { TestApiClient, UserAndAccountTestFactory } from '@shared/testing'; | ||
import { H5PEditorTestModule } from '../../h5p-editor-test.module'; | ||
import { H5P_CONTENT_S3_CONNECTION, H5P_LIBRARIES_S3_CONNECTION } from '../../h5p-editor.config'; | ||
|
||
describe('H5PEditor Controller (api)', () => { | ||
let app: INestApplication; | ||
let em: EntityManager; | ||
let testApiClient: TestApiClient; | ||
|
||
let ajaxEndpoint: DeepMocked<H5PAjaxEndpoint>; | ||
|
||
beforeAll(async () => { | ||
const module = await Test.createTestingModule({ | ||
imports: [H5PEditorTestModule], | ||
}) | ||
.overrideProvider(H5P_CONTENT_S3_CONNECTION) | ||
.useValue(createMock<S3ClientAdapter>()) | ||
.overrideProvider(H5P_LIBRARIES_S3_CONNECTION) | ||
.useValue(createMock<S3ClientAdapter>()) | ||
.overrideProvider(H5PAjaxEndpoint) | ||
.useValue(createMock<H5PAjaxEndpoint>()) | ||
.compile(); | ||
|
||
app = module.createNestApplication(); | ||
await app.init(); | ||
em = app.get(EntityManager); | ||
ajaxEndpoint = app.get(H5PAjaxEndpoint); | ||
testApiClient = new TestApiClient(app, 'h5p-editor'); | ||
}); | ||
|
||
afterEach(() => { | ||
jest.resetAllMocks(); | ||
}); | ||
|
||
afterAll(async () => { | ||
await app.close(); | ||
}); | ||
|
||
describe('when calling AJAX GET', () => { | ||
describe('when user not exists', () => { | ||
it('should respond with unauthorized exception', async () => { | ||
const response = await testApiClient.get('ajax'); | ||
|
||
expect(response.statusCode).toEqual(HttpStatus.UNAUTHORIZED); | ||
expect(response.body).toEqual({ | ||
type: 'UNAUTHORIZED', | ||
title: 'Unauthorized', | ||
message: 'Unauthorized', | ||
code: 401, | ||
}); | ||
}); | ||
}); | ||
|
||
describe('when user is logged in', () => { | ||
const createStudent = () => UserAndAccountTestFactory.buildStudent(); | ||
|
||
const setup = async () => { | ||
const { studentAccount, studentUser } = createStudent(); | ||
|
||
await em.persistAndFlush([studentAccount, studentUser]); | ||
em.clear(); | ||
|
||
const loggedInClient = await testApiClient.login(studentAccount); | ||
|
||
return { loggedInClient, studentUser }; | ||
}; | ||
|
||
it('should call H5PAjaxEndpoint', async () => { | ||
const { | ||
loggedInClient, | ||
studentUser: { id }, | ||
} = await setup(); | ||
|
||
const dummyResponse = { | ||
apiVersion: { major: 1, minor: 1 }, | ||
details: [], | ||
libraries: [], | ||
outdated: false, | ||
recentlyUsed: [], | ||
user: 'DummyUser', | ||
}; | ||
|
||
ajaxEndpoint.getAjax.mockResolvedValueOnce(dummyResponse); | ||
|
||
const response = await loggedInClient.get(`ajax?action=content-type-cache`); | ||
|
||
expect(response.statusCode).toEqual(HttpStatus.OK); | ||
expect(response.body).toEqual(dummyResponse); | ||
expect(ajaxEndpoint.getAjax).toHaveBeenCalledWith( | ||
'content-type-cache', | ||
undefined, // MachineName | ||
undefined, // MajorVersion | ||
undefined, // MinorVersion | ||
'de', // Language | ||
expect.objectContaining({ id }) | ||
); | ||
}); | ||
}); | ||
|
||
describe('when calling AJAX POST', () => { | ||
describe('when user not exists', () => { | ||
it('should respond with unauthorized exception', async () => { | ||
const response = await testApiClient.post('ajax'); | ||
|
||
expect(response.statusCode).toEqual(HttpStatus.UNAUTHORIZED); | ||
expect(response.body).toEqual({ | ||
type: 'UNAUTHORIZED', | ||
title: 'Unauthorized', | ||
message: 'Unauthorized', | ||
code: 401, | ||
}); | ||
}); | ||
}); | ||
|
||
describe('when user is logged in', () => { | ||
const createStudent = () => UserAndAccountTestFactory.buildStudent(); | ||
|
||
const setup = async () => { | ||
const { studentAccount, studentUser } = createStudent(); | ||
|
||
await em.persistAndFlush([studentAccount, studentUser]); | ||
em.clear(); | ||
|
||
const loggedInClient = await testApiClient.login(studentAccount); | ||
|
||
return { loggedInClient, studentUser }; | ||
}; | ||
|
||
it('should call H5PAjaxEndpoint', async () => { | ||
const { | ||
loggedInClient, | ||
studentUser: { id }, | ||
} = await setup(); | ||
|
||
const dummyResponse = [ | ||
{ | ||
majorVersion: 1, | ||
minorVersion: 2, | ||
metadataSettings: {}, | ||
name: 'Dummy Library', | ||
restricted: false, | ||
runnable: true, | ||
title: 'Dummy Library', | ||
tutorialUrl: '', | ||
uberName: 'dummyLibrary-1.1', | ||
}, | ||
]; | ||
|
||
const dummyBody = { contentId: 'id', field: 'field', libraries: ['dummyLibrary-1.0'], libraryParameters: '' }; | ||
|
||
ajaxEndpoint.postAjax.mockResolvedValueOnce(dummyResponse); | ||
|
||
const response = await loggedInClient.post(`ajax?action=libraries`, dummyBody); | ||
|
||
expect(response.statusCode).toEqual(HttpStatus.CREATED); | ||
expect(response.body).toEqual(dummyResponse); | ||
expect(ajaxEndpoint.postAjax).toHaveBeenCalledWith( | ||
'libraries', | ||
dummyBody, | ||
'de', | ||
expect.objectContaining({ id }), | ||
undefined, | ||
undefined, | ||
undefined, | ||
undefined, | ||
undefined | ||
); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); |
106 changes: 106 additions & 0 deletions
106
apps/server/src/modules/h5p-editor/controller/api-test/h5p-editor-delete.api.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,106 @@ | ||
import { DeepMocked, createMock } from '@golevelup/ts-jest/lib/mocks'; | ||
import { EntityManager, ObjectId } from '@mikro-orm/mongodb'; | ||
import { ExecutionContext, INestApplication } from '@nestjs/common'; | ||
import { Test } from '@nestjs/testing'; | ||
import { Permission } from '@shared/domain'; | ||
import { S3ClientAdapter } from '@shared/infra/s3-client'; | ||
import { cleanupCollections, mapUserToCurrentUser, roleFactory, schoolFactory, userFactory } from '@shared/testing'; | ||
import { ICurrentUser } from '@src/modules/authentication'; | ||
import { JwtAuthGuard } from '@src/modules/authentication/guard/jwt-auth.guard'; | ||
import { Request } from 'express'; | ||
import request from 'supertest'; | ||
import { H5PEditorTestModule } from '../../h5p-editor-test.module'; | ||
import { H5P_CONTENT_S3_CONNECTION, H5P_LIBRARIES_S3_CONNECTION } from '../../h5p-editor.config'; | ||
import { H5PEditorUc } from '../../uc/h5p.uc'; | ||
|
||
class API { | ||
constructor(private app: INestApplication) { | ||
this.app = app; | ||
} | ||
|
||
async deleteH5pContent(contentId: string) { | ||
return request(this.app.getHttpServer()).post(`/h5p-editor/delete/${contentId}`); | ||
} | ||
} | ||
|
||
const setup = () => { | ||
const contentId = new ObjectId(0).toString(); | ||
const notExistingContentId = new ObjectId(1).toString(); | ||
const badContentId = ''; | ||
|
||
return { contentId, notExistingContentId, badContentId }; | ||
}; | ||
|
||
describe('H5PEditor Controller (api)', () => { | ||
let app: INestApplication; | ||
let api: API; | ||
let em: EntityManager; | ||
let currentUser: ICurrentUser; | ||
let h5PEditorUc: DeepMocked<H5PEditorUc>; | ||
|
||
beforeAll(async () => { | ||
const module = await Test.createTestingModule({ | ||
imports: [H5PEditorTestModule], | ||
}) | ||
.overrideGuard(JwtAuthGuard) | ||
.useValue({ | ||
canActivate(context: ExecutionContext) { | ||
const req: Request = context.switchToHttp().getRequest(); | ||
req.user = currentUser; | ||
return true; | ||
}, | ||
}) | ||
.overrideProvider(H5P_CONTENT_S3_CONNECTION) | ||
.useValue(createMock<S3ClientAdapter>()) | ||
.overrideProvider(H5P_LIBRARIES_S3_CONNECTION) | ||
.useValue(createMock<S3ClientAdapter>()) | ||
.overrideProvider(H5PEditorUc) | ||
.useValue(createMock<H5PEditorUc>()) | ||
.compile(); | ||
|
||
app = module.createNestApplication(); | ||
await app.init(); | ||
h5PEditorUc = module.get(H5PEditorUc); | ||
|
||
api = new API(app); | ||
em = module.get(EntityManager); | ||
}); | ||
|
||
afterAll(async () => { | ||
await app.close(); | ||
}); | ||
|
||
describe('delete h5p content', () => { | ||
beforeEach(async () => { | ||
await cleanupCollections(em); | ||
const school = schoolFactory.build(); | ||
const roles = roleFactory.buildList(1, { | ||
permissions: [Permission.FILESTORAGE_CREATE, Permission.FILESTORAGE_VIEW], | ||
}); | ||
const user = userFactory.build({ school, roles }); | ||
|
||
await em.persistAndFlush([user, school]); | ||
em.clear(); | ||
|
||
currentUser = mapUserToCurrentUser(user); | ||
}); | ||
describe('with valid request params', () => { | ||
it('should return 200 status', async () => { | ||
const { contentId } = setup(); | ||
|
||
h5PEditorUc.deleteH5pContent.mockResolvedValueOnce(true); | ||
const response = await api.deleteH5pContent(contentId); | ||
expect(response.status).toEqual(201); | ||
}); | ||
}); | ||
describe('with bad request params', () => { | ||
it('should return 500 status', async () => { | ||
const { notExistingContentId } = setup(); | ||
|
||
h5PEditorUc.deleteH5pContent.mockRejectedValueOnce(new Error('Could not delete H5P content')); | ||
const response = await api.deleteH5pContent(notExistingContentId); | ||
expect(response.status).toEqual(500); | ||
}); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.