mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	refactor: e2e tests (#4536)
This commit is contained in:
		
							
								
								
									
										2
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
								
							| @@ -21,7 +21,7 @@ jobs: | |||||||
|           submodules: "recursive" |           submodules: "recursive" | ||||||
|  |  | ||||||
|       - name: Run e2e tests |       - name: Run e2e tests | ||||||
|         run: docker-compose -f ./docker/docker-compose.test.yml -p immich-test-e2e up --renew-anon-volumes --abort-on-container-exit --exit-code-from immich-server-test --remove-orphans --build |         run: docker compose -f ./docker/docker-compose.test.yml up --renew-anon-volumes --abort-on-container-exit --exit-code-from immich-server --remove-orphans --build | ||||||
|  |  | ||||||
|   doc-tests: |   doc-tests: | ||||||
|     name: Run documentation checks |     name: Run documentation checks | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							| @@ -20,7 +20,7 @@ pull-stage: | |||||||
| 	docker-compose -f ./docker/docker-compose.staging.yml pull | 	docker-compose -f ./docker/docker-compose.staging.yml pull | ||||||
|  |  | ||||||
| test-e2e: | test-e2e: | ||||||
| 	docker-compose -f ./docker/docker-compose.test.yml -p immich-test-e2e up  --renew-anon-volumes --abort-on-container-exit --exit-code-from immich-server-test --remove-orphans --build | 	docker compose -f ./docker/docker-compose.test.yml up --renew-anon-volumes --abort-on-container-exit --exit-code-from immich-server --remove-orphans --build | ||||||
|  |  | ||||||
| prod: | prod: | ||||||
| 	docker-compose -f ./docker/docker-compose.prod.yml up --build -V --remove-orphans | 	docker-compose -f ./docker/docker-compose.prod.yml up --build -V --remove-orphans | ||||||
|   | |||||||
| @@ -1,10 +1,10 @@ | |||||||
| version: "3.8" | version: "3.8" | ||||||
|  |  | ||||||
| # Compose file for dockerized end-to-end testing of the backend | name: "immich-test-e2e" | ||||||
|  |  | ||||||
| services: | services: | ||||||
|   immich-server-test: |   immich-server: | ||||||
|     image: immich-server-test |     image: immich-server-dev:latest | ||||||
|     build: |     build: | ||||||
|       context: ../server |       context: ../server | ||||||
|       dockerfile: Dockerfile |       dockerfile: Dockerfile | ||||||
| @@ -14,27 +14,20 @@ services: | |||||||
|       - ../server:/usr/src/app |       - ../server:/usr/src/app | ||||||
|       - /usr/src/app/node_modules |       - /usr/src/app/node_modules | ||||||
|     environment: |     environment: | ||||||
|       - DB_HOSTNAME=immich-database-test |       - DB_HOSTNAME=database | ||||||
|       - DB_USERNAME=postgres |       - DB_USERNAME=postgres | ||||||
|       - DB_PASSWORD=postgres |       - DB_PASSWORD=postgres | ||||||
|       - DB_DATABASE_NAME=e2e_test |       - DB_DATABASE_NAME=e2e_test | ||||||
|       - IMMICH_RUN_ALL_TESTS=true |       - IMMICH_RUN_ALL_TESTS=true | ||||||
|     depends_on: |     depends_on: | ||||||
|       - immich-database-test |       - database | ||||||
|     networks: |  | ||||||
|       - immich-test-network |  | ||||||
|  |  | ||||||
|   immich-database-test: |   database: | ||||||
|     container_name: immich-database-test |  | ||||||
|     image: postgres:14-alpine@sha256:28407a9961e76f2d285dc6991e8e48893503cc3836a4755bbc2d40bcc272a441 |     image: postgres:14-alpine@sha256:28407a9961e76f2d285dc6991e8e48893503cc3836a4755bbc2d40bcc272a441 | ||||||
|  |     command: -c fsync=off | ||||||
|     environment: |     environment: | ||||||
|       POSTGRES_PASSWORD: postgres |       POSTGRES_PASSWORD: postgres | ||||||
|       POSTGRES_USER: postgres |       POSTGRES_USER: postgres | ||||||
|       POSTGRES_DB: e2e_test |       POSTGRES_DB: e2e_test | ||||||
|     networks: |  | ||||||
|       - immich-test-network |  | ||||||
|     logging: |     logging: | ||||||
|       driver: none |       driver: none | ||||||
|  |  | ||||||
| networks: |  | ||||||
|   immich-test-network: |  | ||||||
|   | |||||||
| @@ -26,7 +26,7 @@ | |||||||
|     "test:watch": "jest --watch", |     "test:watch": "jest --watch", | ||||||
|     "test:cov": "jest --coverage", |     "test:cov": "jest --coverage", | ||||||
|     "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", |     "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", | ||||||
|     "test:e2e": "NODE_OPTIONS='--experimental-vm-modules --max_old_space_size=4096' jest --config test/e2e/jest-e2e.json --runInBand --forceExit", |     "test:e2e": "NODE_OPTIONS='--experimental-vm-modules --max_old_space_size=4096' jest --config test/e2e/jest-e2e.json --runInBand", | ||||||
|     "typeorm": "typeorm", |     "typeorm": "typeorm", | ||||||
|     "typeorm:migrations:create": "typeorm migration:create", |     "typeorm:migrations:create": "typeorm migration:create", | ||||||
|     "typeorm:migrations:generate": "typeorm migration:generate -d ./dist/infra/database.config.js", |     "typeorm:migrations:generate": "typeorm migration:generate -d ./dist/infra/database.config.js", | ||||||
|   | |||||||
| @@ -109,6 +109,10 @@ export class MetadataService { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   async teardown() { | ||||||
|  |     await this.repository.teardown(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   async handleLivePhotoLinking(job: IEntityJob) { |   async handleLivePhotoLinking(job: IEntityJob) { | ||||||
|     const { id } = job; |     const { id } = job; | ||||||
|     const [asset] = await this.assetRepository.getByIds([id]); |     const [asset] = await this.assetRepository.getByIds([id]); | ||||||
|   | |||||||
| @@ -26,6 +26,7 @@ export interface ImmichTags extends Omit<Tags, 'FocalLength'> { | |||||||
|  |  | ||||||
| export interface IMetadataRepository { | export interface IMetadataRepository { | ||||||
|   init(options: Partial<InitOptions>): Promise<void>; |   init(options: Partial<InitOptions>): Promise<void>; | ||||||
|  |   teardown(): Promise<void>; | ||||||
|   reverseGeocode(point: GeoPoint): Promise<ReverseGeocodeResult>; |   reverseGeocode(point: GeoPoint): Promise<ReverseGeocodeResult>; | ||||||
|   deleteCache(): Promise<void>; |   deleteCache(): Promise<void>; | ||||||
|   getExifTags(path: string): Promise<ImmichTags | null>; |   getExifTags(path: string): Promise<ImmichTags | null>; | ||||||
|   | |||||||
| @@ -45,6 +45,10 @@ export class MetadataRepository implements IMetadataRepository { | |||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   async teardown() { | ||||||
|  |     await exiftool.end(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   async deleteCache() { |   async deleteCache() { | ||||||
|     const dumpDirectory = REVERSE_GEOCODING_DUMP_DIRECTORY; |     const dumpDirectory = REVERSE_GEOCODING_DUMP_DIRECTORY; | ||||||
|     if (dumpDirectory) { |     if (dumpDirectory) { | ||||||
|   | |||||||
| @@ -103,4 +103,8 @@ export class AppService { | |||||||
|     await this.metadataService.init(); |     await this.metadataService.init(); | ||||||
|     await this.searchService.init(); |     await this.searchService.init(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   async teardown() { | ||||||
|  |     await this.metadataService.teardown(); | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,11 +2,10 @@ import { AlbumResponseDto, LoginResponseDto } from '@app/domain'; | |||||||
| import { AlbumController } from '@app/immich'; | import { AlbumController } from '@app/immich'; | ||||||
| import { AssetFileUploadResponseDto } from '@app/immich/api-v1/asset/response-dto/asset-file-upload-response.dto'; | import { AssetFileUploadResponseDto } from '@app/immich/api-v1/asset/response-dto/asset-file-upload-response.dto'; | ||||||
| import { SharedLinkType } from '@app/infra/entities'; | import { SharedLinkType } from '@app/infra/entities'; | ||||||
| import { INestApplication } from '@nestjs/common'; |  | ||||||
| import { api } from '@test/api'; | import { api } from '@test/api'; | ||||||
| import { db } from '@test/db'; | import { db } from '@test/db'; | ||||||
| import { errorStub, uuidStub } from '@test/fixtures'; | import { errorStub, uuidStub } from '@test/fixtures'; | ||||||
| import { createTestApp } from '@test/test-utils'; | import { testApp } from '@test/test-utils'; | ||||||
| import request from 'supertest'; | import request from 'supertest'; | ||||||
|  |  | ||||||
| const user1SharedUser = 'user1SharedUser'; | const user1SharedUser = 'user1SharedUser'; | ||||||
| @@ -17,7 +16,6 @@ const user2SharedLink = 'user2SharedLink'; | |||||||
| const user2NotShared = 'user2NotShared'; | const user2NotShared = 'user2NotShared'; | ||||||
|  |  | ||||||
| describe(`${AlbumController.name} (e2e)`, () => { | describe(`${AlbumController.name} (e2e)`, () => { | ||||||
|   let app: INestApplication; |  | ||||||
|   let server: any; |   let server: any; | ||||||
|   let admin: LoginResponseDto; |   let admin: LoginResponseDto; | ||||||
|   let user1: LoginResponseDto; |   let user1: LoginResponseDto; | ||||||
| @@ -27,9 +25,11 @@ describe(`${AlbumController.name} (e2e)`, () => { | |||||||
|   let user2Albums: AlbumResponseDto[]; |   let user2Albums: AlbumResponseDto[]; | ||||||
|  |  | ||||||
|   beforeAll(async () => { |   beforeAll(async () => { | ||||||
|     app = await createTestApp(); |     [server] = await testApp.create(); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|     server = app.getHttpServer(); |   afterAll(async () => { | ||||||
|  |     await testApp.teardown(); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   beforeEach(async () => { |   beforeEach(async () => { | ||||||
| @@ -37,24 +37,30 @@ describe(`${AlbumController.name} (e2e)`, () => { | |||||||
|     await api.authApi.adminSignUp(server); |     await api.authApi.adminSignUp(server); | ||||||
|     admin = await api.authApi.adminLogin(server); |     admin = await api.authApi.adminLogin(server); | ||||||
|  |  | ||||||
|     await api.userApi.create(server, admin.accessToken, { |     await Promise.all([ | ||||||
|  |       api.userApi.create(server, admin.accessToken, { | ||||||
|         email: 'user1@immich.app', |         email: 'user1@immich.app', | ||||||
|         password: 'Password123', |         password: 'Password123', | ||||||
|         firstName: 'User 1', |         firstName: 'User 1', | ||||||
|         lastName: 'Test', |         lastName: 'Test', | ||||||
|     }); |       }), | ||||||
|     user1 = await api.authApi.login(server, { email: 'user1@immich.app', password: 'Password123' }); |       api.userApi.create(server, admin.accessToken, { | ||||||
|  |  | ||||||
|     await api.userApi.create(server, admin.accessToken, { |  | ||||||
|         email: 'user2@immich.app', |         email: 'user2@immich.app', | ||||||
|         password: 'Password123', |         password: 'Password123', | ||||||
|         firstName: 'User 2', |         firstName: 'User 2', | ||||||
|         lastName: 'Test', |         lastName: 'Test', | ||||||
|     }); |       }), | ||||||
|     user2 = await api.authApi.login(server, { email: 'user2@immich.app', password: 'Password123' }); |     ]); | ||||||
|  |  | ||||||
|  |     [user1, user2] = await Promise.all([ | ||||||
|  |       api.authApi.login(server, { email: 'user1@immich.app', password: 'Password123' }), | ||||||
|  |       api.authApi.login(server, { email: 'user2@immich.app', password: 'Password123' }), | ||||||
|  |     ]); | ||||||
|  |  | ||||||
|     user1Asset = await api.assetApi.upload(server, user1.accessToken, 'example'); |     user1Asset = await api.assetApi.upload(server, user1.accessToken, 'example'); | ||||||
|     user1Albums = await Promise.all([ |  | ||||||
|  |     const albums = await Promise.all([ | ||||||
|  |       // user 1 | ||||||
|       api.albumApi.create(server, user1.accessToken, { |       api.albumApi.create(server, user1.accessToken, { | ||||||
|         albumName: user1SharedUser, |         albumName: user1SharedUser, | ||||||
|         sharedWithUserIds: [user2.userId], |         sharedWithUserIds: [user2.userId], | ||||||
| @@ -62,15 +68,8 @@ describe(`${AlbumController.name} (e2e)`, () => { | |||||||
|       }), |       }), | ||||||
|       api.albumApi.create(server, user1.accessToken, { albumName: user1SharedLink, assetIds: [user1Asset.id] }), |       api.albumApi.create(server, user1.accessToken, { albumName: user1SharedLink, assetIds: [user1Asset.id] }), | ||||||
|       api.albumApi.create(server, user1.accessToken, { albumName: user1NotShared, assetIds: [user1Asset.id] }), |       api.albumApi.create(server, user1.accessToken, { albumName: user1NotShared, assetIds: [user1Asset.id] }), | ||||||
|     ]); |  | ||||||
|  |  | ||||||
|     // add shared link to user1SharedLink album |       // user 2 | ||||||
|     await api.sharedLinkApi.create(server, user1.accessToken, { |  | ||||||
|       type: SharedLinkType.ALBUM, |  | ||||||
|       albumId: user1Albums[1].id, |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|     user2Albums = await Promise.all([ |  | ||||||
|       api.albumApi.create(server, user2.accessToken, { |       api.albumApi.create(server, user2.accessToken, { | ||||||
|         albumName: user2SharedUser, |         albumName: user2SharedUser, | ||||||
|         sharedWithUserIds: [user1.userId], |         sharedWithUserIds: [user1.userId], | ||||||
| @@ -80,16 +79,22 @@ describe(`${AlbumController.name} (e2e)`, () => { | |||||||
|       api.albumApi.create(server, user2.accessToken, { albumName: user2NotShared }), |       api.albumApi.create(server, user2.accessToken, { albumName: user2NotShared }), | ||||||
|     ]); |     ]); | ||||||
|  |  | ||||||
|  |     user1Albums = albums.slice(0, 3); | ||||||
|  |     user2Albums = albums.slice(3); | ||||||
|  |  | ||||||
|  |     await Promise.all([ | ||||||
|  |       // add shared link to user1SharedLink album | ||||||
|  |       api.sharedLinkApi.create(server, user1.accessToken, { | ||||||
|  |         type: SharedLinkType.ALBUM, | ||||||
|  |         albumId: user1Albums[1].id, | ||||||
|  |       }), | ||||||
|  |  | ||||||
|       // add shared link to user2SharedLink album |       // add shared link to user2SharedLink album | ||||||
|     await api.sharedLinkApi.create(server, user2.accessToken, { |       api.sharedLinkApi.create(server, user2.accessToken, { | ||||||
|         type: SharedLinkType.ALBUM, |         type: SharedLinkType.ALBUM, | ||||||
|         albumId: user2Albums[1].id, |         albumId: user2Albums[1].id, | ||||||
|     }); |       }), | ||||||
|   }); |     ]); | ||||||
|  |  | ||||||
|   afterAll(async () => { |  | ||||||
|     await db.disconnect(); |  | ||||||
|     await app.close(); |  | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   describe('GET /album', () => { |   describe('GET /album', () => { | ||||||
|   | |||||||
| @@ -12,7 +12,7 @@ import { AssetEntity, AssetType, SharedLinkType } from '@app/infra/entities'; | |||||||
| import { INestApplication } from '@nestjs/common'; | import { INestApplication } from '@nestjs/common'; | ||||||
| import { api } from '@test/api'; | import { api } from '@test/api'; | ||||||
| import { errorStub, uuidStub } from '@test/fixtures'; | import { errorStub, uuidStub } from '@test/fixtures'; | ||||||
| import { createTestApp, db } from '@test/test-utils'; | import { db, testApp } from '@test/test-utils'; | ||||||
| import { randomBytes } from 'crypto'; | import { randomBytes } from 'crypto'; | ||||||
| import request from 'supertest'; | import request from 'supertest'; | ||||||
|  |  | ||||||
| @@ -86,12 +86,14 @@ describe(`${AssetController.name} (e2e)`, () => { | |||||||
|   let asset4: AssetEntity; |   let asset4: AssetEntity; | ||||||
|  |  | ||||||
|   beforeAll(async () => { |   beforeAll(async () => { | ||||||
|     app = await createTestApp(); |     [server, app] = await testApp.create(); | ||||||
|  |  | ||||||
|     server = app.getHttpServer(); |  | ||||||
|     assetRepository = app.get<IAssetRepository>(IAssetRepository); |     assetRepository = app.get<IAssetRepository>(IAssetRepository); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|  |   afterAll(async () => { | ||||||
|  |     await testApp.teardown(); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|   beforeEach(async () => { |   beforeEach(async () => { | ||||||
|     await db.reset(); |     await db.reset(); | ||||||
|     await api.authApi.adminSignUp(server); |     await api.authApi.adminSignUp(server); | ||||||
| @@ -123,11 +125,6 @@ describe(`${AssetController.name} (e2e)`, () => { | |||||||
|     }); |     }); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   afterAll(async () => { |  | ||||||
|     await db.disconnect(); |  | ||||||
|     await app.close(); |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   describe('POST /asset/upload', () => { |   describe('POST /asset/upload', () => { | ||||||
|     it('should require authentication', async () => { |     it('should require authentication', async () => { | ||||||
|       const { status, body } = await request(server) |       const { status, body } = await request(server) | ||||||
| @@ -589,9 +586,11 @@ describe(`${AssetController.name} (e2e)`, () => { | |||||||
|  |  | ||||||
|   describe('GET /asset/map-marker', () => { |   describe('GET /asset/map-marker', () => { | ||||||
|     beforeEach(async () => { |     beforeEach(async () => { | ||||||
|       await assetRepository.save({ id: asset1.id, isArchived: true }); |       await Promise.all([ | ||||||
|       await assetRepository.upsertExif({ assetId: asset1.id, latitude: 0, longitude: 0 }); |         assetRepository.save({ id: asset1.id, isArchived: true }), | ||||||
|       await assetRepository.upsertExif({ assetId: asset2.id, latitude: 0, longitude: 0 }); |         assetRepository.upsertExif({ assetId: asset1.id, latitude: 0, longitude: 0 }), | ||||||
|  |         assetRepository.upsertExif({ assetId: asset2.id, latitude: 0, longitude: 0 }), | ||||||
|  |       ]); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     it('should require authentication', async () => { |     it('should require authentication', async () => { | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| import { AuthController } from '@app/immich'; | import { AuthController } from '@app/immich'; | ||||||
| import { INestApplication } from '@nestjs/common'; |  | ||||||
| import { api } from '@test/api'; | import { api } from '@test/api'; | ||||||
| import { db } from '@test/db'; | import { db } from '@test/db'; | ||||||
| import { | import { | ||||||
| @@ -12,7 +11,7 @@ import { | |||||||
|   signupResponseStub, |   signupResponseStub, | ||||||
|   uuidStub, |   uuidStub, | ||||||
| } from '@test/fixtures'; | } from '@test/fixtures'; | ||||||
| import { createTestApp } from '@test/test-utils'; | import { testApp } from '@test/test-utils'; | ||||||
| import request from 'supertest'; | import request from 'supertest'; | ||||||
|  |  | ||||||
| const firstName = 'Immich'; | const firstName = 'Immich'; | ||||||
| @@ -21,13 +20,16 @@ const password = 'Password123'; | |||||||
| const email = 'admin@immich.app'; | const email = 'admin@immich.app'; | ||||||
|  |  | ||||||
| describe(`${AuthController.name} (e2e)`, () => { | describe(`${AuthController.name} (e2e)`, () => { | ||||||
|   let app: INestApplication; |  | ||||||
|   let server: any; |   let server: any; | ||||||
|   let accessToken: string; |   let accessToken: string; | ||||||
|  |  | ||||||
|   beforeAll(async () => { |   beforeAll(async () => { | ||||||
|     app = await createTestApp(); |     await testApp.reset(); | ||||||
|     server = app.getHttpServer(); |     [server] = await testApp.create(); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   afterAll(async () => { | ||||||
|  |     await testApp.teardown(); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   beforeEach(async () => { |   beforeEach(async () => { | ||||||
| @@ -37,11 +39,6 @@ describe(`${AuthController.name} (e2e)`, () => { | |||||||
|     accessToken = response.accessToken; |     accessToken = response.accessToken; | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   afterAll(async () => { |  | ||||||
|     await db.disconnect(); |  | ||||||
|     await app.close(); |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   describe('POST /auth/admin-sign-up', () => { |   describe('POST /auth/admin-sign-up', () => { | ||||||
|     beforeEach(async () => { |     beforeEach(async () => { | ||||||
|       await db.reset(); |       await db.reset(); | ||||||
|   | |||||||
| @@ -1,11 +1,9 @@ | |||||||
| import { LoginResponseDto } from '@app/domain'; | import { LoginResponseDto } from '@app/domain'; | ||||||
| import { AssetType, LibraryType } from '@app/infra/entities'; | import { AssetType, LibraryType } from '@app/infra/entities'; | ||||||
| import { INestApplication } from '@nestjs/common'; |  | ||||||
| import { api } from '@test/api'; | import { api } from '@test/api'; | ||||||
| import { IMMICH_TEST_ASSET_PATH, createTestApp, db, runAllTests } from '@test/test-utils'; | import { IMMICH_TEST_ASSET_PATH, db, runAllTests, testApp } from '@test/test-utils'; | ||||||
|  |  | ||||||
| describe(`Supported file formats (e2e)`, () => { | describe(`Supported file formats (e2e)`, () => { | ||||||
|   let app: INestApplication; |  | ||||||
|   let server: any; |   let server: any; | ||||||
|   let admin: LoginResponseDto; |   let admin: LoginResponseDto; | ||||||
|  |  | ||||||
| @@ -170,8 +168,11 @@ describe(`Supported file formats (e2e)`, () => { | |||||||
|   const testsToRun = formatTests.filter((formatTest) => formatTest.runTest); |   const testsToRun = formatTests.filter((formatTest) => formatTest.runTest); | ||||||
|  |  | ||||||
|   beforeAll(async () => { |   beforeAll(async () => { | ||||||
|     app = await createTestApp(true); |     [server] = await testApp.create({ jobs: true }); | ||||||
|     server = app.getHttpServer(); |   }); | ||||||
|  |  | ||||||
|  |   afterAll(async () => { | ||||||
|  |     await testApp.teardown(); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   beforeEach(async () => { |   beforeEach(async () => { | ||||||
| @@ -181,11 +182,6 @@ describe(`Supported file formats (e2e)`, () => { | |||||||
|     await api.userApi.setExternalPath(server, admin.accessToken, admin.userId, '/'); |     await api.userApi.setExternalPath(server, admin.accessToken, admin.userId, '/'); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   afterAll(async () => { |  | ||||||
|     await db.disconnect(); |  | ||||||
|     await app.close(); |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   it.each(testsToRun)('should import file of format $format', async (testedFormat) => { |   it.each(testsToRun)('should import file of format $format', async (testedFormat) => { | ||||||
|     const library = await api.libraryApi.create(server, admin.accessToken, { |     const library = await api.libraryApi.create(server, admin.accessToken, { | ||||||
|       type: LibraryType.EXTERNAL, |       type: LibraryType.EXTERNAL, | ||||||
|   | |||||||
| @@ -1,22 +1,14 @@ | |||||||
| import { LibraryResponseDto, LoginResponseDto } from '@app/domain'; | import { LibraryResponseDto, LoginResponseDto } from '@app/domain'; | ||||||
| import { LibraryController } from '@app/immich'; | import { LibraryController } from '@app/immich'; | ||||||
| import { AssetType, LibraryType } from '@app/infra/entities'; | import { AssetType, LibraryType } from '@app/infra/entities'; | ||||||
| import { INestApplication } from '@nestjs/common'; |  | ||||||
| import { api } from '@test/api'; | import { api } from '@test/api'; | ||||||
| import { | import { IMMICH_TEST_ASSET_PATH, IMMICH_TEST_ASSET_TEMP_PATH, db, restoreTempFolder, testApp } from '@test/test-utils'; | ||||||
|   IMMICH_TEST_ASSET_PATH, |  | ||||||
|   IMMICH_TEST_ASSET_TEMP_PATH, |  | ||||||
|   createTestApp, |  | ||||||
|   db, |  | ||||||
|   restoreTempFolder, |  | ||||||
| } from '@test/test-utils'; |  | ||||||
| import * as fs from 'fs'; | import * as fs from 'fs'; | ||||||
| import request from 'supertest'; | import request from 'supertest'; | ||||||
| import { utimes } from 'utimes'; | import { utimes } from 'utimes'; | ||||||
| import { errorStub, uuidStub } from '../fixtures'; | import { errorStub, uuidStub } from '../fixtures'; | ||||||
|  |  | ||||||
| describe(`${LibraryController.name} (e2e)`, () => { | describe(`${LibraryController.name} (e2e)`, () => { | ||||||
|   let app: INestApplication; |  | ||||||
|   let server: any; |   let server: any; | ||||||
|   let admin: LoginResponseDto; |   let admin: LoginResponseDto; | ||||||
|  |  | ||||||
| @@ -35,8 +27,12 @@ describe(`${LibraryController.name} (e2e)`, () => { | |||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   beforeAll(async () => { |   beforeAll(async () => { | ||||||
|     app = await createTestApp(true); |     [server] = await testApp.create({ jobs: true }); | ||||||
|     server = app.getHttpServer(); |   }); | ||||||
|  |  | ||||||
|  |   afterAll(async () => { | ||||||
|  |     await testApp.teardown(); | ||||||
|  |     await restoreTempFolder(); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   beforeEach(async () => { |   beforeEach(async () => { | ||||||
| @@ -46,12 +42,6 @@ describe(`${LibraryController.name} (e2e)`, () => { | |||||||
|     admin = await api.authApi.adminLogin(server); |     admin = await api.authApi.adminLogin(server); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   afterAll(async () => { |  | ||||||
|     await db.disconnect(); |  | ||||||
|     await app.close(); |  | ||||||
|     await restoreTempFolder(); |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   describe('GET /library', () => { |   describe('GET /library', () => { | ||||||
|     it('should require authentication', async () => { |     it('should require authentication', async () => { | ||||||
|       const { status, body } = await request(server).get('/library'); |       const { status, body } = await request(server).get('/library'); | ||||||
|   | |||||||
| @@ -1,18 +1,19 @@ | |||||||
| import { OAuthController } from '@app/immich'; | import { OAuthController } from '@app/immich'; | ||||||
| import { INestApplication } from '@nestjs/common'; |  | ||||||
| import { api } from '@test/api'; | import { api } from '@test/api'; | ||||||
| import { db } from '@test/db'; | import { db } from '@test/db'; | ||||||
| import { errorStub } from '@test/fixtures'; | import { errorStub } from '@test/fixtures'; | ||||||
| import { createTestApp } from '@test/test-utils'; | import { testApp } from '@test/test-utils'; | ||||||
| import request from 'supertest'; | import request from 'supertest'; | ||||||
|  |  | ||||||
| describe(`${OAuthController.name} (e2e)`, () => { | describe(`${OAuthController.name} (e2e)`, () => { | ||||||
|   let app: INestApplication; |  | ||||||
|   let server: any; |   let server: any; | ||||||
|  |  | ||||||
|   beforeAll(async () => { |   beforeAll(async () => { | ||||||
|     app = await createTestApp(); |     [server] = await testApp.create(); | ||||||
|     server = app.getHttpServer(); |   }); | ||||||
|  |  | ||||||
|  |   afterAll(async () => { | ||||||
|  |     await testApp.teardown(); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   beforeEach(async () => { |   beforeEach(async () => { | ||||||
| @@ -20,11 +21,6 @@ describe(`${OAuthController.name} (e2e)`, () => { | |||||||
|     await api.authApi.adminSignUp(server); |     await api.authApi.adminSignUp(server); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   afterAll(async () => { |  | ||||||
|     await db.disconnect(); |  | ||||||
|     await app.close(); |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   describe('POST /oauth/authorize', () => { |   describe('POST /oauth/authorize', () => { | ||||||
|     beforeEach(async () => { |     beforeEach(async () => { | ||||||
|       await db.reset(); |       await db.reset(); | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ import { INestApplication } from '@nestjs/common'; | |||||||
| import { api } from '@test/api'; | import { api } from '@test/api'; | ||||||
| import { db } from '@test/db'; | import { db } from '@test/db'; | ||||||
| import { errorStub } from '@test/fixtures'; | import { errorStub } from '@test/fixtures'; | ||||||
| import { createTestApp } from '@test/test-utils'; | import { testApp } from '@test/test-utils'; | ||||||
| import request from 'supertest'; | import request from 'supertest'; | ||||||
|  |  | ||||||
| const user1Dto = { | const user1Dto = { | ||||||
| @@ -31,27 +31,29 @@ describe(`${PartnerController.name} (e2e)`, () => { | |||||||
|   let user2: LoginResponseDto; |   let user2: LoginResponseDto; | ||||||
|  |  | ||||||
|   beforeAll(async () => { |   beforeAll(async () => { | ||||||
|     app = await createTestApp(); |     [server, app] = await testApp.create(); | ||||||
|     server = app.getHttpServer(); |  | ||||||
|     repository = app.get<IPartnerRepository>(IPartnerRepository); |     repository = app.get<IPartnerRepository>(IPartnerRepository); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|  |   afterAll(async () => { | ||||||
|  |     await testApp.teardown(); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|   beforeEach(async () => { |   beforeEach(async () => { | ||||||
|     await db.reset(); |     await db.reset(); | ||||||
|     await api.authApi.adminSignUp(server); |     await api.authApi.adminSignUp(server); | ||||||
|     loginResponse = await api.authApi.adminLogin(server); |     loginResponse = await api.authApi.adminLogin(server); | ||||||
|     accessToken = loginResponse.accessToken; |     accessToken = loginResponse.accessToken; | ||||||
|  |  | ||||||
|     await api.userApi.create(server, accessToken, user1Dto); |     await Promise.all([ | ||||||
|     user1 = await api.authApi.login(server, { email: user1Dto.email, password: user1Dto.password }); |       api.userApi.create(server, accessToken, user1Dto), | ||||||
|  |       api.userApi.create(server, accessToken, user2Dto), | ||||||
|  |     ]); | ||||||
|  |  | ||||||
|     await api.userApi.create(server, accessToken, user2Dto); |     [user1, user2] = await Promise.all([ | ||||||
|     user2 = await api.authApi.login(server, { email: user2Dto.email, password: user2Dto.password }); |       api.authApi.login(server, { email: user1Dto.email, password: user1Dto.password }), | ||||||
|   }); |       api.authApi.login(server, { email: user2Dto.email, password: user2Dto.password }), | ||||||
|  |     ]); | ||||||
|   afterAll(async () => { |  | ||||||
|     await db.disconnect(); |  | ||||||
|     await app.close(); |  | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   describe('GET /partner', () => { |   describe('GET /partner', () => { | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ import { INestApplication } from '@nestjs/common'; | |||||||
| import { api } from '@test/api'; | import { api } from '@test/api'; | ||||||
| import { db } from '@test/db'; | import { db } from '@test/db'; | ||||||
| import { errorStub, uuidStub } from '@test/fixtures'; | import { errorStub, uuidStub } from '@test/fixtures'; | ||||||
| import { createTestApp } from '@test/test-utils'; | import { testApp } from '@test/test-utils'; | ||||||
| import request from 'supertest'; | import request from 'supertest'; | ||||||
|  |  | ||||||
| describe(`${PersonController.name}`, () => { | describe(`${PersonController.name}`, () => { | ||||||
| @@ -18,11 +18,14 @@ describe(`${PersonController.name}`, () => { | |||||||
|   let hiddenPerson: PersonEntity; |   let hiddenPerson: PersonEntity; | ||||||
|  |  | ||||||
|   beforeAll(async () => { |   beforeAll(async () => { | ||||||
|     app = await createTestApp(); |     [server, app] = await testApp.create(); | ||||||
|     server = app.getHttpServer(); |  | ||||||
|     personRepository = app.get<IPersonRepository>(IPersonRepository); |     personRepository = app.get<IPersonRepository>(IPersonRepository); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|  |   afterAll(async () => { | ||||||
|  |     await testApp.teardown(); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|   beforeEach(async () => { |   beforeEach(async () => { | ||||||
|     await db.reset(); |     await db.reset(); | ||||||
|     await api.authApi.adminSignUp(server); |     await api.authApi.adminSignUp(server); | ||||||
| @@ -46,11 +49,6 @@ describe(`${PersonController.name}`, () => { | |||||||
|     await personRepository.createFace({ assetId: faceAsset.id, personId: hiddenPerson.id }); |     await personRepository.createFace({ assetId: faceAsset.id, personId: hiddenPerson.id }); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   afterAll(async () => { |  | ||||||
|     await db.disconnect(); |  | ||||||
|     await app.close(); |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   describe('GET /person', () => { |   describe('GET /person', () => { | ||||||
|     beforeEach(async () => {}); |     beforeEach(async () => {}); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,21 +1,22 @@ | |||||||
| import { LoginResponseDto } from '@app/domain'; | import { LoginResponseDto } from '@app/domain'; | ||||||
| import { ServerInfoController } from '@app/immich'; | import { ServerInfoController } from '@app/immich'; | ||||||
| import { INestApplication } from '@nestjs/common'; |  | ||||||
| import { api } from '@test/api'; | import { api } from '@test/api'; | ||||||
| import { db } from '@test/db'; | import { db } from '@test/db'; | ||||||
| import { errorStub } from '@test/fixtures'; | import { errorStub } from '@test/fixtures'; | ||||||
| import { createTestApp } from '@test/test-utils'; | import { testApp } from '@test/test-utils'; | ||||||
| import request from 'supertest'; | import request from 'supertest'; | ||||||
|  |  | ||||||
| describe(`${ServerInfoController.name} (e2e)`, () => { | describe(`${ServerInfoController.name} (e2e)`, () => { | ||||||
|   let app: INestApplication; |  | ||||||
|   let server: any; |   let server: any; | ||||||
|   let accessToken: string; |   let accessToken: string; | ||||||
|   let loginResponse: LoginResponseDto; |   let loginResponse: LoginResponseDto; | ||||||
|  |  | ||||||
|   beforeAll(async () => { |   beforeAll(async () => { | ||||||
|     app = await createTestApp(); |     [server] = await testApp.create(); | ||||||
|     server = app.getHttpServer(); |   }); | ||||||
|  |  | ||||||
|  |   afterAll(async () => { | ||||||
|  |     await testApp.teardown(); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   beforeEach(async () => { |   beforeEach(async () => { | ||||||
| @@ -25,11 +26,6 @@ describe(`${ServerInfoController.name} (e2e)`, () => { | |||||||
|     accessToken = loginResponse.accessToken; |     accessToken = loginResponse.accessToken; | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   afterAll(async () => { |  | ||||||
|     await db.disconnect(); |  | ||||||
|     await app.close(); |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   describe('GET /server-info', () => { |   describe('GET /server-info', () => { | ||||||
|     it('should require authentication', async () => { |     it('should require authentication', async () => { | ||||||
|       const { status, body } = await request(server).get('/server-info'); |       const { status, body } = await request(server).get('/server-info'); | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| import { PostgreSqlContainer } from '@testcontainers/postgresql'; | import { PostgreSqlContainer } from '@testcontainers/postgresql'; | ||||||
| import * as fs from 'fs'; | import { access } from 'fs/promises'; | ||||||
| import path from 'path'; | import path from 'path'; | ||||||
|  |  | ||||||
| export default async () => { | export default async () => { | ||||||
| @@ -23,8 +23,7 @@ export default async () => { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   const directoryExists = async (dirPath: string) => |   const directoryExists = async (dirPath: string) => | ||||||
|     await fs.promises |     await access(dirPath) | ||||||
|       .access(dirPath) |  | ||||||
|       .then(() => true) |       .then(() => true) | ||||||
|       .catch(() => false); |       .catch(() => false); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,16 +1,10 @@ | |||||||
| import { AlbumResponseDto, LoginResponseDto, SharedLinkResponseDto } from '@app/domain'; | import { AlbumResponseDto, LoginResponseDto, SharedLinkResponseDto } from '@app/domain'; | ||||||
| import { PartnerController } from '@app/immich'; | import { PartnerController } from '@app/immich'; | ||||||
| import { LibraryType, SharedLinkType } from '@app/infra/entities'; | import { LibraryType, SharedLinkType } from '@app/infra/entities'; | ||||||
| import { INestApplication } from '@nestjs/common'; |  | ||||||
| import { api } from '@test/api'; | import { api } from '@test/api'; | ||||||
| import { db } from '@test/db'; | import { db } from '@test/db'; | ||||||
| import { errorStub, uuidStub } from '@test/fixtures'; | import { errorStub, uuidStub } from '@test/fixtures'; | ||||||
| import { | import { IMMICH_TEST_ASSET_PATH, IMMICH_TEST_ASSET_TEMP_PATH, restoreTempFolder, testApp } from '@test/test-utils'; | ||||||
|   IMMICH_TEST_ASSET_PATH, |  | ||||||
|   IMMICH_TEST_ASSET_TEMP_PATH, |  | ||||||
|   createTestApp, |  | ||||||
|   restoreTempFolder, |  | ||||||
| } from '@test/test-utils'; |  | ||||||
| import { cp } from 'fs/promises'; | import { cp } from 'fs/promises'; | ||||||
| import request from 'supertest'; | import request from 'supertest'; | ||||||
|  |  | ||||||
| @@ -22,7 +16,6 @@ const user1Dto = { | |||||||
| }; | }; | ||||||
|  |  | ||||||
| describe(`${PartnerController.name} (e2e)`, () => { | describe(`${PartnerController.name} (e2e)`, () => { | ||||||
|   let app: INestApplication; |  | ||||||
|   let server: any; |   let server: any; | ||||||
|   let admin: LoginResponseDto; |   let admin: LoginResponseDto; | ||||||
|   let user1: LoginResponseDto; |   let user1: LoginResponseDto; | ||||||
| @@ -30,8 +23,12 @@ describe(`${PartnerController.name} (e2e)`, () => { | |||||||
|   let sharedLink: SharedLinkResponseDto; |   let sharedLink: SharedLinkResponseDto; | ||||||
|  |  | ||||||
|   beforeAll(async () => { |   beforeAll(async () => { | ||||||
|     app = await createTestApp(true); |     [server] = await testApp.create({ jobs: true }); | ||||||
|     server = app.getHttpServer(); |   }); | ||||||
|  |  | ||||||
|  |   afterAll(async () => { | ||||||
|  |     await testApp.teardown(); | ||||||
|  |     await restoreTempFolder(); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   beforeEach(async () => { |   beforeEach(async () => { | ||||||
| @@ -49,12 +46,6 @@ describe(`${PartnerController.name} (e2e)`, () => { | |||||||
|     }); |     }); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   afterAll(async () => { |  | ||||||
|     await db.disconnect(); |  | ||||||
|     await app.close(); |  | ||||||
|     await restoreTempFolder(); |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   describe('GET /shared-link', () => { |   describe('GET /shared-link', () => { | ||||||
|     it('should require authentication', async () => { |     it('should require authentication', async () => { | ||||||
|       const { status, body } = await request(server).get('/shared-link'); |       const { status, body } = await request(server).get('/shared-link'); | ||||||
|   | |||||||
| @@ -2,10 +2,11 @@ import { LoginResponseDto, UserResponseDto, UserService } from '@app/domain'; | |||||||
| import { AppModule, UserController } from '@app/immich'; | import { AppModule, UserController } from '@app/immich'; | ||||||
| import { UserEntity } from '@app/infra/entities'; | import { UserEntity } from '@app/infra/entities'; | ||||||
| import { INestApplication } from '@nestjs/common'; | import { INestApplication } from '@nestjs/common'; | ||||||
|  | import { getRepositoryToken } from '@nestjs/typeorm'; | ||||||
| import { api } from '@test/api'; | import { api } from '@test/api'; | ||||||
| import { db } from '@test/db'; | import { db } from '@test/db'; | ||||||
| import { errorStub, userSignupStub, userStub } from '@test/fixtures'; | import { errorStub, userSignupStub, userStub } from '@test/fixtures'; | ||||||
| import { createTestApp } from '@test/test-utils'; | import { testApp } from '@test/test-utils'; | ||||||
| import request from 'supertest'; | import request from 'supertest'; | ||||||
| import { Repository } from 'typeorm'; | import { Repository } from 'typeorm'; | ||||||
|  |  | ||||||
| @@ -18,10 +19,12 @@ describe(`${UserController.name}`, () => { | |||||||
|   let userRepository: Repository<UserEntity>; |   let userRepository: Repository<UserEntity>; | ||||||
|  |  | ||||||
|   beforeAll(async () => { |   beforeAll(async () => { | ||||||
|     app = await createTestApp(); |     [server, app] = await testApp.create(); | ||||||
|     userRepository = app.select(AppModule).get('UserEntityRepository'); |     userRepository = app.select(AppModule).get(getRepositoryToken(UserEntity)); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|     server = app.getHttpServer(); |   afterAll(async () => { | ||||||
|  |     await testApp.teardown(); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   beforeEach(async () => { |   beforeEach(async () => { | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ export const newMetadataRepositoryMock = (): jest.Mocked<IMetadataRepository> => | |||||||
|     deleteCache: jest.fn(), |     deleteCache: jest.fn(), | ||||||
|     getExifTags: jest.fn(), |     getExifTags: jest.fn(), | ||||||
|     init: jest.fn(), |     init: jest.fn(), | ||||||
|  |     teardown: jest.fn(), | ||||||
|     reverseGeocode: jest.fn(), |     reverseGeocode: jest.fn(), | ||||||
|   }; |   }; | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -1,9 +1,8 @@ | |||||||
| import { dataSource } from '@app/infra'; |  | ||||||
|  |  | ||||||
| import { IJobRepository, JobItem, JobItemHandler, QueueName } from '@app/domain'; | import { IJobRepository, JobItem, JobItemHandler, QueueName } from '@app/domain'; | ||||||
| import { AppModule } from '@app/immich'; | import { AppModule } from '@app/immich'; | ||||||
| import { INestApplication, Logger } from '@nestjs/common'; | import { dataSource } from '@app/infra'; | ||||||
| import { Test, TestingModule } from '@nestjs/testing'; | import { INestApplication } from '@nestjs/common'; | ||||||
|  | import { Test } from '@nestjs/testing'; | ||||||
| import * as fs from 'fs'; | import * as fs from 'fs'; | ||||||
| import path from 'path'; | import path from 'path'; | ||||||
| import { AppService } from '../src/microservices/app.service'; | import { AppService } from '../src/microservices/app.service'; | ||||||
| @@ -36,37 +35,47 @@ export const db = { | |||||||
|  |  | ||||||
| let _handler: JobItemHandler = () => Promise.resolve(); | let _handler: JobItemHandler = () => Promise.resolve(); | ||||||
|  |  | ||||||
| export async function createTestApp(runJobs = false, log = false): Promise<INestApplication> { | interface TestAppOptions { | ||||||
|   const moduleBuilder = Test.createTestingModule({ |   jobs: boolean; | ||||||
|     imports: [AppModule], | } | ||||||
|     providers: [AppService], |  | ||||||
|   }) | let app: INestApplication; | ||||||
|  |  | ||||||
|  | export const testApp = { | ||||||
|  |   create: async (options?: TestAppOptions): Promise<[any, INestApplication]> => { | ||||||
|  |     const { jobs } = options || { jobs: false }; | ||||||
|  |  | ||||||
|  |     const moduleFixture = await Test.createTestingModule({ imports: [AppModule], providers: [AppService] }) | ||||||
|       .overrideProvider(IJobRepository) |       .overrideProvider(IJobRepository) | ||||||
|       .useValue({ |       .useValue({ | ||||||
|         addHandler: (_queueName: QueueName, _concurrency: number, handler: JobItemHandler) => (_handler = handler), |         addHandler: (_queueName: QueueName, _concurrency: number, handler: JobItemHandler) => (_handler = handler), | ||||||
|       queue: (item: JobItem) => runJobs && _handler(item), |         queue: (item: JobItem) => jobs && _handler(item), | ||||||
|         resume: jest.fn(), |         resume: jest.fn(), | ||||||
|         empty: jest.fn(), |         empty: jest.fn(), | ||||||
|         setConcurrency: jest.fn(), |         setConcurrency: jest.fn(), | ||||||
|         getQueueStatus: jest.fn(), |         getQueueStatus: jest.fn(), | ||||||
|         getJobCounts: jest.fn(), |         getJobCounts: jest.fn(), | ||||||
|         pause: jest.fn(), |         pause: jest.fn(), | ||||||
|     } as IJobRepository); |       } as IJobRepository) | ||||||
|  |       .compile(); | ||||||
|  |  | ||||||
|   const moduleFixture: TestingModule = await moduleBuilder.compile(); |     app = await moduleFixture.createNestApplication().init(); | ||||||
|  |  | ||||||
|   const app = moduleFixture.createNestApplication(); |     if (jobs) { | ||||||
|   if (log) { |       await app.get(AppService).init(); | ||||||
|     app.useLogger(new Logger()); |  | ||||||
|   } else { |  | ||||||
|     app.useLogger(false); |  | ||||||
|     } |     } | ||||||
|   await app.init(); |  | ||||||
|   const appService = app.get(AppService); |  | ||||||
|   await appService.init(); |  | ||||||
|  |  | ||||||
|   return app; |     return [app.getHttpServer(), app]; | ||||||
| } |   }, | ||||||
|  |   reset: async () => { | ||||||
|  |     await db.reset(); | ||||||
|  |   }, | ||||||
|  |   teardown: async () => { | ||||||
|  |     await app.get(AppService).teardown(); | ||||||
|  |     await db.disconnect(); | ||||||
|  |     await app.close(); | ||||||
|  |   }, | ||||||
|  | }; | ||||||
|  |  | ||||||
| export const runAllTests: boolean = process.env.IMMICH_RUN_ALL_TESTS === 'true'; | export const runAllTests: boolean = process.env.IMMICH_RUN_ALL_TESTS === 'true'; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user