From 0207d4803575221427e7ec35ada1776190830dec Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 19 Oct 2026 15:22:40 +0200 Subject: [PATCH] chore(deps): update vitest monorepo to v5 (#31912) Co-authored-by: Daniel Dietzler --- e2e/package.json | 2 +- .../server/database-backups.e2e-spec.ts | 14 +- .../server/maintenance.e2e-spec.ts | 6 +- .../specs/server/api/integrity.e2e-spec.ts | 223 ++++++++++-------- e2e/src/specs/web/auth.e2e-spec.ts | 2 +- e2e/src/specs/web/shared-link.e2e-spec.ts | 2 +- .../ui/specs/timeline/timeline.e2e-spec.ts | 14 +- packages/cli/package.json | 4 +- packages/scripts/package.json | 2 +- server/package.json | 4 +- .../specs/services/user.service.spec.ts | 2 +- web/package.json | 4 +- .../album-page/__tests__/AlbumCard.spec.ts | 11 + .../album-page/__tests__/AlbumSummary.spec.ts | 3 + .../asset-viewer/AssetViewer.spec.ts | 2 + .../asset-viewer/AssetViewerNavBar.spec.ts | 2 + .../DetailPanelDescription.spec.ts | 4 + .../asset-viewer/actions/DeleteAction.spec.ts | 2 + .../MaintenanceBackupEntry.spec.ts | 1 + .../search-bar/SearchTagsSection.spec.ts | 1 + .../side-bar/RecentAlbums.spec.ts | 3 + .../elements/__test__/FormatMessage.spec.ts | 5 + .../lib/elements/__test__/StarRating.spec.ts | 1 + web/src/lib/modals/AlbumPickerModal.spec.ts | 6 + .../AssetSelectionChangeDateModal.spec.ts | 2 + .../[[assetId=id]]/AlbumDescription.spec.ts | 2 + 26 files changed, 193 insertions(+), 131 deletions(-) diff --git a/e2e/package.json b/e2e/package.json index c1366935e..b92255d73 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -55,6 +55,6 @@ "typescript": "npm:@typescript/typescript6@^6.0.2", "typescript-eslint": "^8.28.0", "utimes": "^5.2.1", - "vitest": "^4.0.0" + "vitest": "^5.0.0" } } diff --git a/e2e/src/specs/maintenance/server/database-backups.e2e-spec.ts b/e2e/src/specs/maintenance/server/database-backups.e2e-spec.ts index f0e7a05a2..094633872 100644 --- a/e2e/src/specs/maintenance/server/database-backups.e2e-spec.ts +++ b/e2e/src/specs/maintenance/server/database-backups.e2e-spec.ts @@ -91,7 +91,7 @@ describe('/admin/database-backups', () => { // => action: restore database flow - describe.sequential('POST /start-restore', () => { + describe('POST /start-restore', { concurrent: false }, () => { afterAll(async () => { await request(app).post('/admin/maintenance').set('cookie', cookie!).send({ action: 'end' }); await utils.poll( @@ -104,14 +104,14 @@ describe('/admin/database-backups', () => { }); }); - it.sequential('should not work when the server is configured', async () => { + it('should not work when the server is configured', { concurrent: false }, async () => { const { status, body } = await request(app).post('/admin/database-backups/start-restore').send(); expect(status).toBe(400); expect(body).toEqual(errorDto.badRequest('Admin setup is not available')); }); - it.sequential('should enter maintenance mode in "database restore mode"', async () => { + it('should enter maintenance mode in "database restore mode"', { concurrent: false }, async () => { await utils.resetDatabase(); // reset database before running this test const { status, headers } = await request(app).post('/admin/database-backups/start-restore').send(); @@ -145,7 +145,7 @@ describe('/admin/database-backups', () => { // => action: restore database - describe.sequential('POST /backups/restore', () => { + describe('POST /backups/restore', { concurrent: false }, () => { beforeAll(async () => { await utils.disconnectDatabase(); }); @@ -154,7 +154,7 @@ describe('/admin/database-backups', () => { await utils.connectDatabase(); }); - it.sequential('should restore a backup', { timeout: 60_000 }, async () => { + it('should restore a backup', { timeout: 60_000, concurrent: false }, async () => { let filename = await utils.createBackup(admin.accessToken); // work-around until test is running on released version @@ -212,7 +212,7 @@ describe('/admin/database-backups', () => { .toBeFalsy(); }); - it.sequential('fail to restore a corrupted backup', { timeout: 60_000 }, async () => { + it('fail to restore a corrupted backup', { timeout: 60_000, concurrent: false }, async () => { await utils.prepareTestBackup('corrupted'); const { status, headers } = await request(app) @@ -283,7 +283,7 @@ describe('/admin/database-backups', () => { ); }); - it.sequential('rollback to restore point if backup is missing admin', { timeout: 60_000 }, async () => { + it('rollback to restore point if backup is missing admin', { timeout: 60_000, concurrent: false }, async () => { await utils.prepareTestBackup('empty'); const { status, headers } = await request(app) diff --git a/e2e/src/specs/maintenance/server/maintenance.e2e-spec.ts b/e2e/src/specs/maintenance/server/maintenance.e2e-spec.ts index 35c95194b..9fe6f27c9 100644 --- a/e2e/src/specs/maintenance/server/maintenance.e2e-spec.ts +++ b/e2e/src/specs/maintenance/server/maintenance.e2e-spec.ts @@ -45,7 +45,7 @@ describe('/admin/maintenance', () => { // => enter maintenance mode - describe.sequential('POST /', () => { + describe('POST /', { concurrent: false }, () => { it('should be a no-op if try to exit maintenance mode', async () => { const { status } = await request(app) .post('/admin/maintenance') @@ -87,7 +87,7 @@ describe('/admin/maintenance', () => { // => in maintenance mode - describe.sequential('in maintenance mode', () => { + describe('in maintenance mode', { concurrent: false }, () => { describe('GET ~/server/config', async () => { it('should indicate we are in maintenance mode', async () => { const { status, body } = await request(app).get('/server/config'); @@ -152,7 +152,7 @@ describe('/admin/maintenance', () => { // => exit maintenance mode - describe.sequential('POST /', () => { + describe('POST /', { concurrent: false }, () => { it('should exit maintenance mode', async () => { const { status } = await request(app).post('/admin/maintenance').set('cookie', cookie!).send({ action: 'end', diff --git a/e2e/src/specs/server/api/integrity.e2e-spec.ts b/e2e/src/specs/server/api/integrity.e2e-spec.ts index 04fd46f92..bf22708de 100644 --- a/e2e/src/specs/server/api/integrity.e2e-spec.ts +++ b/e2e/src/specs/server/api/integrity.e2e-spec.ts @@ -96,7 +96,7 @@ describe('/admin/integrity', () => { }); describe('POST /summary (& jobs)', async () => { - it.sequential('reports no issues', async () => { + it('reports no issues', { concurrent: false }, async () => { await utils.createJob(admin.accessToken, { name: ManualJobName.IntegrityUntrackedFiles, }); @@ -130,7 +130,7 @@ describe('/admin/integrity', () => { }); }); - it.sequential('should detect an untracked file (job: check untracked files)', async () => { + it('should detect an untracked file (job: check untracked files)', { concurrent: false }, async () => { await utils.putTextFile('untracked', `/data/upload/${admin.userId}/untracked1.png`); await utils.createJob(admin.accessToken, { @@ -152,31 +152,35 @@ describe('/admin/integrity', () => { ); }); - it.sequential('should detect outdated untracked file reports (job: refresh untracked files)', async () => { - // these should not be detected: - await utils.putTextFile('untracked', `/data/upload/${admin.userId}/untracked2.png`); - await utils.putTextFile('untracked', `/data/upload/${admin.userId}/untracked3.png`); + it( + 'should detect outdated untracked file reports (job: refresh untracked files)', + { concurrent: false }, + async () => { + // these should not be detected: + await utils.putTextFile('untracked', `/data/upload/${admin.userId}/untracked2.png`); + await utils.putTextFile('untracked', `/data/upload/${admin.userId}/untracked3.png`); - await utils.createJob(admin.accessToken, { - name: ManualJobName.IntegrityUntrackedFilesRefresh, - }); + await utils.createJob(admin.accessToken, { + name: ManualJobName.IntegrityUntrackedFilesRefresh, + }); - await utils.waitForQueueFinish(admin.accessToken, QueueName.IntegrityCheck); + await utils.waitForQueueFinish(admin.accessToken, QueueName.IntegrityCheck); - const { status, body } = await request(app) - .get('/admin/integrity/summary') - .set('Authorization', `Bearer ${admin.accessToken}`) - .send(); + const { status, body } = await request(app) + .get('/admin/integrity/summary') + .set('Authorization', `Bearer ${admin.accessToken}`) + .send(); - expect(status).toBe(200); - expect(body).toEqual( - expect.objectContaining({ - untracked_file: 0, - }), - ); - }); + expect(status).toBe(200); + expect(body).toEqual( + expect.objectContaining({ + untracked_file: 0, + }), + ); + }, + ); - it.sequential('should delete untracked files (job: delete all untracked file reports)', async () => { + it('should delete untracked files (job: delete all untracked file reports)', { concurrent: false }, async () => { await utils.putTextFile('untracked', `/data/upload/${admin.userId}/untracked1.png`); await utils.createJob(admin.accessToken, { @@ -204,30 +208,34 @@ describe('/admin/integrity', () => { ); }); - it.sequential('should detect a missing file and not a checksum mismatch (job: check missing files)', async () => { - await utils.deleteFolder(`/data/upload/${admin.userId}`); + it( + 'should detect a missing file and not a checksum mismatch (job: check missing files)', + { concurrent: false }, + async () => { + await utils.deleteFolder(`/data/upload/${admin.userId}`); - await utils.createJob(admin.accessToken, { - name: ManualJobName.IntegrityMissingFiles, - }); + await utils.createJob(admin.accessToken, { + name: ManualJobName.IntegrityMissingFiles, + }); - await utils.waitForQueueFinish(admin.accessToken, QueueName.IntegrityCheck); + await utils.waitForQueueFinish(admin.accessToken, QueueName.IntegrityCheck); - const { status, body } = await request(app) - .get('/admin/integrity/summary') - .set('Authorization', `Bearer ${admin.accessToken}`) - .send(); + const { status, body } = await request(app) + .get('/admin/integrity/summary') + .set('Authorization', `Bearer ${admin.accessToken}`) + .send(); - expect(status).toBe(200); - expect(body).toEqual( - expect.objectContaining({ - missing_file: 1, - checksum_mismatch: 0, - }), - ); - }); + expect(status).toBe(200); + expect(body).toEqual( + expect.objectContaining({ + missing_file: 1, + checksum_mismatch: 0, + }), + ); + }, + ); - it.sequential('should detect outdated missing file reports (job: refresh missing files)', async () => { + it('should detect outdated missing file reports (job: refresh missing files)', { concurrent: false }, async () => { await utils.createJob(admin.accessToken, { name: ManualJobName.IntegrityMissingFilesRefresh, }); @@ -248,53 +256,57 @@ describe('/admin/integrity', () => { ); }); - it.sequential('should delete assets with missing files (job: delete all missing file reports)', async () => { - await utils.deleteFolder(`/data/upload/${user1.userId}`); + it( + 'should delete assets with missing files (job: delete all missing file reports)', + { concurrent: false }, + async () => { + await utils.deleteFolder(`/data/upload/${user1.userId}`); - await utils.createJob(admin.accessToken, { - name: ManualJobName.IntegrityMissingFiles, - }); + await utils.createJob(admin.accessToken, { + name: ManualJobName.IntegrityMissingFiles, + }); - await utils.waitForQueueFinish(admin.accessToken, QueueName.IntegrityCheck); + await utils.waitForQueueFinish(admin.accessToken, QueueName.IntegrityCheck); - const { status: listStatus, body: listBody } = await request(app) - .get('/admin/integrity/summary') - .set('Authorization', `Bearer ${admin.accessToken}`) - .send(); + const { status: listStatus, body: listBody } = await request(app) + .get('/admin/integrity/summary') + .set('Authorization', `Bearer ${admin.accessToken}`) + .send(); - expect(listStatus).toBe(200); - expect(listBody).toEqual( - expect.objectContaining({ - missing_file: 1, - }), - ); + expect(listStatus).toBe(200); + expect(listBody).toEqual( + expect.objectContaining({ + missing_file: 1, + }), + ); - await utils.createJob(admin.accessToken, { - name: ManualJobName.IntegrityMissingFilesDeleteAll, - }); + await utils.createJob(admin.accessToken, { + name: ManualJobName.IntegrityMissingFilesDeleteAll, + }); - await utils.waitForQueueFinish(admin.accessToken, QueueName.IntegrityCheck); + await utils.waitForQueueFinish(admin.accessToken, QueueName.IntegrityCheck); - const { status, body } = await request(app) - .get('/admin/integrity/summary') - .set('Authorization', `Bearer ${admin.accessToken}`) - .send(); + const { status, body } = await request(app) + .get('/admin/integrity/summary') + .set('Authorization', `Bearer ${admin.accessToken}`) + .send(); - expect(status).toBe(200); - expect(body).toEqual( - expect.objectContaining({ - missing_file: 0, - }), - ); + expect(status).toBe(200); + expect(body).toEqual( + expect.objectContaining({ + missing_file: 0, + }), + ); - await expect(utils.getAssetInfo(user1.accessToken, asset1.id)).resolves.toEqual( - expect.objectContaining({ - isTrashed: true, - }), - ); - }); + await expect(utils.getAssetInfo(user1.accessToken, asset1.id)).resolves.toEqual( + expect.objectContaining({ + isTrashed: true, + }), + ); + }, + ); - it.sequential('should detect a checksum mismatch (job: check file checksums)', async () => { + it('should detect a checksum mismatch (job: check file checksums)', { concurrent: false }, async () => { await utils.truncateFolder(`/data/upload/${admin.userId}`); await utils.createJob(admin.accessToken, { @@ -316,28 +328,33 @@ describe('/admin/integrity', () => { ); }); - it.sequential('should detect outdated checksum mismatch reports (job: refresh file checksums)', async () => { - await utils.createJob(admin.accessToken, { - name: ManualJobName.IntegrityChecksumMismatchRefresh, - }); + it( + 'should detect outdated checksum mismatch reports (job: refresh file checksums)', + { concurrent: false }, + async () => { + await utils.createJob(admin.accessToken, { + name: ManualJobName.IntegrityChecksumMismatchRefresh, + }); - await utils.waitForQueueFinish(admin.accessToken, QueueName.IntegrityCheck); + await utils.waitForQueueFinish(admin.accessToken, QueueName.IntegrityCheck); - const { status, body } = await request(app) - .get('/admin/integrity/summary') - .set('Authorization', `Bearer ${admin.accessToken}`) - .send(); + const { status, body } = await request(app) + .get('/admin/integrity/summary') + .set('Authorization', `Bearer ${admin.accessToken}`) + .send(); - expect(status).toBe(200); - expect(body).toEqual( - expect.objectContaining({ - checksum_mismatch: 0, - }), - ); - }); + expect(status).toBe(200); + expect(body).toEqual( + expect.objectContaining({ + checksum_mismatch: 0, + }), + ); + }, + ); - it.sequential( + it( 'should delete assets with mismatched checksum (job: delete all checksum mismatch reports)', + { concurrent: false }, async () => { await utils.truncateFolder(`/data/upload/${user2.userId}`); @@ -387,7 +404,7 @@ describe('/admin/integrity', () => { }); describe('POST /report', async () => { - it.sequential('reports untracked files', async () => { + it('reports untracked files', { concurrent: false }, async () => { await utils.putTextFile('untracked', `/data/upload/${admin.userId}/untracked1.png`); await utils.createJob(admin.accessToken, { @@ -417,7 +434,7 @@ describe('/admin/integrity', () => { }); }); - it.sequential('reports missing files', async () => { + it('reports missing files', { concurrent: false }, async () => { await utils.deleteFolder(`/data/upload/${admin.userId}`); await utils.createJob(admin.accessToken, { @@ -447,7 +464,7 @@ describe('/admin/integrity', () => { }); }); - it.sequential('reports checksum mismatched files', async () => { + it('reports checksum mismatched files', { concurrent: false }, async () => { await utils.truncateFolder(`/data/upload/${admin.userId}`); await utils.createJob(admin.accessToken, { @@ -479,7 +496,7 @@ describe('/admin/integrity', () => { }); describe('DELETE /report/:id', async () => { - it.sequential('delete untracked files', async () => { + it('delete untracked files', { concurrent: false }, async () => { await utils.putTextFile('untracked', `/data/upload/${admin.userId}/untracked1.png`); await utils.createJob(admin.accessToken, { @@ -529,7 +546,7 @@ describe('/admin/integrity', () => { ); }); - it.sequential('delete assets missing files', async () => { + it('delete assets missing files', { concurrent: false }, async () => { await utils.deleteFolder(`/data/upload/${admin.userId}`); await utils.createJob(admin.accessToken, { @@ -570,7 +587,7 @@ describe('/admin/integrity', () => { expect(listBody2.items.length).toBe(0); }); - it.sequential('delete assets with failing checksum', async () => { + it('delete assets with failing checksum', { concurrent: false }, async () => { await utils.truncateFolder(`/data/upload/${admin.userId}`); await utils.createJob(admin.accessToken, { @@ -613,7 +630,7 @@ describe('/admin/integrity', () => { }); describe('GET /report/:type/csv', () => { - it.sequential('exports untracked files as csv', async () => { + it('exports untracked files as csv', { concurrent: false }, async () => { await utils.putTextFile('untracked', `/data/upload/${admin.userId}/untracked1.png`); await utils.createJob(admin.accessToken, { @@ -637,7 +654,7 @@ describe('/admin/integrity', () => { }); describe('GET /report/:id/file', () => { - it.sequential('downloads untracked file', async () => { + it('downloads untracked file', { concurrent: false }, async () => { await utils.putTextFile('untracked-content', `/data/upload/${admin.userId}/untracked1.png`); await utils.createJob(admin.accessToken, { diff --git a/e2e/src/specs/web/auth.e2e-spec.ts b/e2e/src/specs/web/auth.e2e-spec.ts index c19fe2023..633bad05f 100644 --- a/e2e/src/specs/web/auth.e2e-spec.ts +++ b/e2e/src/specs/web/auth.e2e-spec.ts @@ -27,7 +27,7 @@ test.describe('Registration', () => { await expect(page).toHaveTitle(/Login/); await page.goto('/auth/login?autoLaunch=0'); await page.getByLabel('Email').fill('admin@immich.app'); - await page.getByLabel('Password').fill('password'); + await page.getByLabel('Password', { exact: true }).fill('password'); await page.getByRole('button', { name: 'Login' }).click(); // onboarding diff --git a/e2e/src/specs/web/shared-link.e2e-spec.ts b/e2e/src/specs/web/shared-link.e2e-spec.ts index 3eed0ae51..acd793039 100644 --- a/e2e/src/specs/web/shared-link.e2e-spec.ts +++ b/e2e/src/specs/web/shared-link.e2e-spec.ts @@ -80,7 +80,7 @@ test.describe('Shared Links', () => { const input = page.getByPlaceholder('Password'); await input.fill('test-password'); await page.getByRole('button', { name: 'Show password' }).click(); - // await page.getByText('test-password', { exact: true }).waitFor(); + // await page.getByText('test-password').waitFor(); await expect(input).toHaveAttribute('type', 'text'); }); diff --git a/e2e/src/ui/specs/timeline/timeline.e2e-spec.ts b/e2e/src/ui/specs/timeline/timeline.e2e-spec.ts index 71524ab01..29b008b3c 100644 --- a/e2e/src/ui/specs/timeline/timeline.e2e-spec.ts +++ b/e2e/src/ui/specs/timeline/timeline.e2e-spec.ts @@ -494,7 +494,7 @@ test.describe('Timeline', () => { force: false, ids: [assetToTrash.id], }); - await page.getByText('Trash', { exact: true }).click(); + await page.getByRole('link', { name: 'Trash' }).click(); await thumbnailUtils.expectInViewport(page, assetToTrash.id); await thumbnailUtils.withAssetId(page, assetToTrash.id).hover(); await thumbnailUtils.selectButton(page, assetToTrash.id).click(); @@ -507,12 +507,12 @@ test.describe('Timeline', () => { json: { count: requestJson.ids.length }, }); }); - await page.getByText('Restore', { exact: true }).click(); + await page.getByText('Restore').click(); await expect(restoreRequest).resolves.toEqual({ ids: [assetToTrash.id], }); await expect(thumbnailUtils.withAssetId(page, assetToTrash.id)).toHaveCount(0); - await page.getByText('Photos', { exact: true }).click(); + await page.getByRole('link', { name: 'Photos' }).click(); await thumbnailUtils.expectInViewport(page, assetToTrash.id); }); test('open album, trash photo, open /trash, restore', async ({ page }) => { @@ -537,7 +537,7 @@ test.describe('Timeline', () => { ids: [assetToTrash.id], }); await page.locator('#control-bar').getByLabel('Close').click(); - await page.getByText('Trash', { exact: true }).click(); + await page.getByRole('link', { name: 'Trash' }).click(); await timelineUtils.waitForTimelineLoad(page); await thumbnailUtils.expectInViewport(page, assetToTrash.id); await thumbnailUtils.withAssetId(page, assetToTrash.id).hover(); @@ -551,7 +551,7 @@ test.describe('Timeline', () => { json: { count: requestJson.ids.length }, }); }); - await page.getByText('Restore', { exact: true }).click(); + await page.getByText('Restore').click(); await expect(restoreRequest).resolves.toEqual({ ids: [assetToTrash.id], }); @@ -603,7 +603,7 @@ test.describe('Timeline', () => { ids: [assetToArchive.id], }); await expect(thumbnailUtils.withAssetId(page, assetToArchive.id)).toHaveCount(0); - await page.getByText('Photos', { exact: true }).click(); + await page.getByRole('link', { name: 'Photos' }).click(); await thumbnailUtils.expectInViewport(page, assetToArchive.id); }); test('open /archive, favorite photo, unfavorite', async ({ page }) => { @@ -749,7 +749,7 @@ test.describe('Timeline', () => { ids: [assetToFavorite.id], }); await expect(thumbnailUtils.withAssetId(page, assetToFavorite.id)).toHaveCount(0); - await page.getByText('Photos', { exact: true }).click(); + await page.getByRole('link', { name: 'Photos' }).click(); await thumbnailUtils.expectInViewport(page, assetToFavorite.id); }); test.skip('open /favorites, archive photo, unarchive photo', async ({ page }) => { diff --git a/packages/cli/package.json b/packages/cli/package.json index a1731c8ef..bfc1125d3 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -26,7 +26,7 @@ "@types/micromatch": "^4.0.9", "@types/mock-fs": "^4.13.1", "@types/node": "^24.19.2", - "@vitest/coverage-v8": "^4.0.0", + "@vitest/coverage-v8": "^5.0.0", "byte-size": "^9.0.0", "cli-progress": "^3.12.0", "commander": "^15.0.0", @@ -42,7 +42,7 @@ "typescript": "npm:@typescript/typescript6@^6.0.2", "typescript-eslint": "^8.58.0", "vite": "^8.0.0", - "vitest": "^4.0.0", + "vitest": "^5.0.0", "vitest-fetch-mock": "^0.4.0", "yaml": "^2.3.1" }, diff --git a/packages/scripts/package.json b/packages/scripts/package.json index 0aa3073b2..499e1c3c7 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -31,7 +31,7 @@ "@types/node": "^24.19.2", "@types/semver": "^7.7.1", "vite": "^8.0.16", - "vitest": "^4.1.8" + "vitest": "^5.0.0" }, "packageManager": "pnpm@11.27.1" } diff --git a/server/package.json b/server/package.json index 6265a69c6..940e42450 100644 --- a/server/package.json +++ b/server/package.json @@ -148,7 +148,7 @@ "@types/ua-parser-js": "^0.7.36", "@types/validator": "^13.15.2", "@typescript/native": "npm:typescript@^7.0.2", - "@vitest/coverage-v8": "^4.0.0", + "@vitest/coverage-v8": "^5.0.0", "eslint": "^10.0.0", "eslint-config-prettier": "^10.1.8", "eslint-import-resolver-typescript": "^4.4.5", @@ -166,7 +166,7 @@ "typescript": "npm:@typescript/typescript6@^6.0.2", "typescript-eslint": "^8.28.0", "unplugin-swc": "^1.4.5", - "vitest": "^4.0.0" + "vitest": "^5.0.0" }, "overrides": { "sharp": "^0.35.3" diff --git a/server/test/medium/specs/services/user.service.spec.ts b/server/test/medium/specs/services/user.service.spec.ts index 117792228..b2efa4bde 100644 --- a/server/test/medium/specs/services/user.service.spec.ts +++ b/server/test/medium/specs/services/user.service.spec.ts @@ -330,7 +330,7 @@ describe(UserService.name, () => { }); }); - describe.sequential('handleUserDeleteCheck', () => { + describe('handleUserDeleteCheck', { concurrent: false }, () => { beforeEach(async () => { const { sut } = setup(); // These tests specifically have to be sequential otherwise we hit race conditions with config changes applying in incorrect tests diff --git a/web/package.json b/web/package.json index a238f9ac3..e24245ee2 100644 --- a/web/package.json +++ b/web/package.json @@ -93,7 +93,7 @@ "@types/luxon": "^3.4.2", "@types/qrcode": "^1.5.5", "@typescript/native": "npm:typescript@^7.0.2", - "@vitest/coverage-v8": "^4.0.0", + "@vitest/coverage-v8": "^5.0.0", "dotenv": "^17.0.0", "eslint": "^10.2.1", "eslint-config-prettier": "^10.1.8", @@ -116,6 +116,6 @@ "typescript": "npm:@typescript/typescript6@^6.0.2", "typescript-eslint": "8.71.1", "vite": "^8.0.0", - "vitest": "^4.0.0" + "vitest": "^5.0.0" } } diff --git a/web/src/lib/components/album-page/__tests__/AlbumCard.spec.ts b/web/src/lib/components/album-page/__tests__/AlbumCard.spec.ts index f14db2d6c..0134dfa92 100644 --- a/web/src/lib/components/album-page/__tests__/AlbumCard.spec.ts +++ b/web/src/lib/components/album-page/__tests__/AlbumCard.spec.ts @@ -43,15 +43,21 @@ describe('AlbumCard component', () => { const albumDetailsElement = sut.getByTestId('album-details'); const detailsText = `${count} items` + (shared ? ' . Shared' : ''); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(albumImgElement).toHaveAttribute('src'); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(albumImgElement).toHaveAttribute('alt', album.albumName); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes await waitFor(() => expect(albumImgElement).toHaveAttribute('src')); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(albumImgElement).toHaveAttribute('alt', album.albumName); expect(sdkMock.viewAsset).not.toHaveBeenCalled(); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(albumNameElement).toHaveTextContent(album.albumName); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(albumDetailsElement).toHaveTextContent(new RegExp(detailsText)); }); @@ -66,10 +72,14 @@ describe('AlbumCard component', () => { const albumNameElement = sut.getByTestId('album-name'); const albumDetailsElement = sut.getByTestId('album-details'); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(albumImgElement).toHaveAttribute('alt', album.albumName); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(albumImgElement).toHaveAttribute('src'); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(albumNameElement).toHaveTextContent('some album name'); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(albumDetailsElement).toHaveTextContent(`${album.assetCount} item`); }); @@ -78,6 +88,7 @@ describe('AlbumCard component', () => { sut = render(AlbumCard, { album }); const contextButtonParent = sut.queryByTestId('context-button-parent'); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(contextButtonParent).not.toBeInTheDocument(); }); }); diff --git a/web/src/lib/components/album-page/__tests__/AlbumSummary.spec.ts b/web/src/lib/components/album-page/__tests__/AlbumSummary.spec.ts index 7a4dfeeb8..cefad1d1a 100644 --- a/web/src/lib/components/album-page/__tests__/AlbumSummary.spec.ts +++ b/web/src/lib/components/album-page/__tests__/AlbumSummary.spec.ts @@ -23,12 +23,15 @@ describe('AlbumSummary component', () => { assetCount: 3, }); const { rerender } = render(AlbumSummary, { album }); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(screen.getByTestId('album-details')).toHaveTextContent('Jun 10'); await rerender({ album: { ...album, startDate: '2026-06-15T12:00:00.000Z', assetCount: 2 } }); const details = screen.getByTestId('album-details'); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(details).toHaveTextContent('Jun 15'); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(details).not.toHaveTextContent('Jun 10'); }); }); diff --git a/web/src/lib/components/asset-viewer/AssetViewer.spec.ts b/web/src/lib/components/asset-viewer/AssetViewer.spec.ts index a1498ed2f..4d6bb1eb3 100644 --- a/web/src/lib/components/asset-viewer/AssetViewer.spec.ts +++ b/web/src/lib/components/asset-viewer/AssetViewer.spec.ts @@ -66,6 +66,7 @@ describe('AssetViewer', () => { showNavigation: false, }); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(getByLabelText('to_favorite')).toBeInTheDocument(); expect(queryByLabelText('unfavorite')).toBeNull(); @@ -74,6 +75,7 @@ describe('AssetViewer', () => { await waitFor(() => expect(updateAsset).toHaveBeenCalledWith({ id: asset.id, updateAssetDto: { isFavorite: true } }), ); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes await waitFor(() => expect(getByLabelText('unfavorite')).toBeInTheDocument()); }); }); diff --git a/web/src/lib/components/asset-viewer/AssetViewerNavBar.spec.ts b/web/src/lib/components/asset-viewer/AssetViewerNavBar.spec.ts index 7c2c3a6be..2c118f347 100644 --- a/web/src/lib/components/asset-viewer/AssetViewerNavBar.spec.ts +++ b/web/src/lib/components/asset-viewer/AssetViewerNavBar.spec.ts @@ -50,6 +50,7 @@ describe('AssetViewerNavBar component', () => { const asset = assetFactory.build({ isTrashed: false }); const { getByLabelText } = renderWithTooltips(AssetViewerNavBar, { asset, ...additionalProps }); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(getByLabelText('go_back')).toBeInTheDocument(); }); @@ -64,6 +65,7 @@ describe('AssetViewerNavBar component', () => { authManager.setPreferences(preferences); const { getByLabelText } = renderWithTooltips(AssetViewerNavBar, { asset, ...additionalProps }); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(getByLabelText('delete')).toBeInTheDocument(); }); }); diff --git a/web/src/lib/components/asset-viewer/DetailPanelDescription.spec.ts b/web/src/lib/components/asset-viewer/DetailPanelDescription.spec.ts index e449f057c..488c2ac12 100644 --- a/web/src/lib/components/asset-viewer/DetailPanelDescription.spec.ts +++ b/web/src/lib/components/asset-viewer/DetailPanelDescription.spec.ts @@ -26,6 +26,7 @@ describe('DetailPanelDescription', () => { const textarea = screen.getByTestId('autogrow-textarea') as HTMLTextAreaElement; await user.type(textarea, 'unsaved draft'); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(textarea).toHaveValue('unsaved draft'); await rerender({ @@ -33,6 +34,7 @@ describe('DetailPanelDescription', () => { isOwner: true, }); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(screen.getByTestId('autogrow-textarea')).toHaveValue(''); }); @@ -53,6 +55,7 @@ describe('DetailPanelDescription', () => { }, }); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(screen.getByTestId('autogrow-textarea')).toHaveValue('first description'); await rerender({ @@ -60,6 +63,7 @@ describe('DetailPanelDescription', () => { isOwner: true, }); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(screen.getByTestId('autogrow-textarea')).toHaveValue('second description'); }); }); diff --git a/web/src/lib/components/asset-viewer/actions/DeleteAction.spec.ts b/web/src/lib/components/asset-viewer/actions/DeleteAction.spec.ts index d715540d3..2b9f9bb9c 100644 --- a/web/src/lib/components/asset-viewer/actions/DeleteAction.spec.ts +++ b/web/src/lib/components/asset-viewer/actions/DeleteAction.spec.ts @@ -23,6 +23,7 @@ describe('DeleteAction component', () => { onAction: vi.fn(), preAction: vi.fn(), }); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(getByLabelText('delete')).toBeInTheDocument(); expect(queryByTitle('deletePermanently')).toBeNull(); }); @@ -39,6 +40,7 @@ describe('DeleteAction component', () => { onAction: vi.fn(), preAction: vi.fn(), }); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(getByLabelText('permanently_delete')).toBeInTheDocument(); expect(queryByTitle('delete')).toBeNull(); }); diff --git a/web/src/lib/components/maintenance/MaintenanceBackupEntry.spec.ts b/web/src/lib/components/maintenance/MaintenanceBackupEntry.spec.ts index 56e4a2baa..548c69172 100644 --- a/web/src/lib/components/maintenance/MaintenanceBackupEntry.spec.ts +++ b/web/src/lib/components/maintenance/MaintenanceBackupEntry.spec.ts @@ -49,6 +49,7 @@ describe('MaintenanceBackupEntry', () => { timezone: 'Asia/Tokyo', }); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(screen.getByText(expectedRelativeTime!)).toBeInTheDocument(); }); }); diff --git a/web/src/lib/components/shared-components/search-bar/SearchTagsSection.spec.ts b/web/src/lib/components/shared-components/search-bar/SearchTagsSection.spec.ts index 72c6e43cb..0778ba1cd 100644 --- a/web/src/lib/components/shared-components/search-bar/SearchTagsSection.spec.ts +++ b/web/src/lib/components/shared-components/search-bar/SearchTagsSection.spec.ts @@ -40,6 +40,7 @@ describe('SearchTagsSection component', () => { await user.click(await screen.findByRole('button', { name: 'holiday' })); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(screen.queryByRole('button', { name: 'holiday' })).not.toBeInTheDocument(); expect([...(searchManager.filter.tagIds ?? [])]).toEqual(['tag-2']); }); diff --git a/web/src/lib/components/shared-components/side-bar/RecentAlbums.spec.ts b/web/src/lib/components/shared-components/side-bar/RecentAlbums.spec.ts index 1745aa022..bc6cb3578 100644 --- a/web/src/lib/components/shared-components/side-bar/RecentAlbums.spec.ts +++ b/web/src/lib/components/shared-components/side-bar/RecentAlbums.spec.ts @@ -24,8 +24,11 @@ describe('RecentAlbums component', () => { const links = screen.getAllByRole('link'); expect(links).toHaveLength(3); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(links[0]).toHaveAttribute('href', `/albums/${albums[2].id}`); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(links[1]).toHaveAttribute('href', `/albums/${albums[1].id}`); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(links[2]).toHaveAttribute('href', `/albums/${albums[3].id}`); }); }); diff --git a/web/src/lib/elements/__test__/FormatMessage.spec.ts b/web/src/lib/elements/__test__/FormatMessage.spec.ts index dc1268039..5c066d897 100644 --- a/web/src/lib/elements/__test__/FormatMessage.spec.ts +++ b/web/src/lib/elements/__test__/FormatMessage.spec.ts @@ -30,6 +30,7 @@ describe('FormatMessage component', () => { key: 'hello' as Translations, values: { name: 'test' }, }); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(screen.getByText('Hello test')).toBeInTheDocument(); }); @@ -43,6 +44,7 @@ describe('FormatMessage component', () => { render(FormatMessage, { key: 'hello' as Translations, }); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(screen.getByText('Hello {name}')).toBeInTheDocument(); }); @@ -51,6 +53,7 @@ describe('FormatMessage component', () => { key: 'html' as Translations, values: { name: 'test' }, }); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(screen.getByText('Hello test')).toBeInTheDocument(); }); @@ -74,11 +77,13 @@ describe('FormatMessage component', () => { render(FormatMessage, { key: 'xss' as Translations, }); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(screen.getByText('')).toBeInTheDocument(); }); it('displays the message key when not found', () => { render(FormatMessage, { key: 'invalid.key' as Translations }); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(screen.getByText('invalid.key')).toBeInTheDocument(); }); diff --git a/web/src/lib/elements/__test__/StarRating.spec.ts b/web/src/lib/elements/__test__/StarRating.spec.ts index 827e33621..53fdbcd44 100644 --- a/web/src/lib/elements/__test__/StarRating.spec.ts +++ b/web/src/lib/elements/__test__/StarRating.spec.ts @@ -19,6 +19,7 @@ describe('StarRating component', () => { const labelText = component.getAllByText('rating_count') as HTMLSpanElement[]; expect(labelText.length).toBe(3); const clearButton = component.getByRole('button') as HTMLButtonElement; + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(clearButton).toBeInTheDocument(); // Check the clear button content diff --git a/web/src/lib/modals/AlbumPickerModal.spec.ts b/web/src/lib/modals/AlbumPickerModal.spec.ts index 4245f3e17..f8cdda0d1 100644 --- a/web/src/lib/modals/AlbumPickerModal.spec.ts +++ b/web/src/lib/modals/AlbumPickerModal.spec.ts @@ -34,7 +34,9 @@ describe('AlbumPickerModal component', () => { render(AlbumPickerModal, { props: { onClose, selectedItemsCount: 1 } }); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(await screen.findByText('Add 1 item to album')).toBeInTheDocument(); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(screen.queryByText('Select albums')).not.toBeInTheDocument(); }); @@ -43,7 +45,9 @@ describe('AlbumPickerModal component', () => { render(AlbumPickerModal, { props: { onClose, selectedItemsCount: 3 } }); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(await screen.findByText('Add 3 items to album')).toBeInTheDocument(); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(screen.queryByText('Select albums')).not.toBeInTheDocument(); }); @@ -52,7 +56,9 @@ describe('AlbumPickerModal component', () => { render(AlbumPickerModal, { props: { onClose } }); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(await screen.findByText('Select albums')).toBeInTheDocument(); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(screen.queryByText('Add 1 item to album')).not.toBeInTheDocument(); }); }); diff --git a/web/src/lib/modals/AssetSelectionChangeDateModal.spec.ts b/web/src/lib/modals/AssetSelectionChangeDateModal.spec.ts index fdd338123..7a9eae0c5 100644 --- a/web/src/lib/modals/AssetSelectionChangeDateModal.spec.ts +++ b/web/src/lib/modals/AssetSelectionChangeDateModal.spec.ts @@ -86,6 +86,7 @@ describe('DateSelectionModal component', () => { expect(getTimeZoneInput().value).toBe('Europe/Berlin (+01:00)'); await fireEvent.focus(getTimeZoneInput()); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(screen.queryByText('no_results')).not.toBeInTheDocument(); }); @@ -100,6 +101,7 @@ describe('DateSelectionModal component', () => { expect(getTimeZoneInput().value).toBe('Europe/Berlin (+01:00)'); await fireEvent.focus(getTimeZoneInput()); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(screen.queryByText('no_results')).not.toBeInTheDocument(); }); diff --git a/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/AlbumDescription.spec.ts b/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/AlbumDescription.spec.ts index e9990cf5b..d5de4f80e 100644 --- a/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/AlbumDescription.spec.ts +++ b/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/AlbumDescription.spec.ts @@ -7,12 +7,14 @@ describe('AlbumDescription component', () => { it('shows an AutogrowTextarea component when isOwned is true', () => { render(AlbumDescription, { isEditor: true, id: '', description: '' }); const autogrowTextarea = screen.getByTestId('autogrow-textarea'); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(autogrowTextarea).toBeInTheDocument(); }); it('does not show an AutogrowTextarea component when isOwned is false', () => { render(AlbumDescription, { isEditor: false, id: '', description: '' }); const autogrowTextarea = screen.queryByTestId('autogrow-textarea'); + // @ts-expect-error pending a type fix: https://github.com/testing-library/jest-dom/pull/742/changes expect(autogrowTextarea).not.toBeInTheDocument(); }); });