chore: prepare local.3 release with query regression coverage
This commit is contained in:
+1
-1
@@ -2,7 +2,7 @@ name: immich_mobile
|
|||||||
description: Immich - selfhosted backup media file on mobile phone
|
description: Immich - selfhosted backup media file on mobile phone
|
||||||
|
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
version: 3.3.3-local.2+3030401
|
version: 3.3.3-local.3+3030402
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=3.12.0 <4.0.0'
|
sdk: '>=3.12.0 <4.0.0'
|
||||||
|
|||||||
Generated
+21
-26
@@ -824,7 +824,7 @@ importers:
|
|||||||
version: 5.15.1(@photo-sphere-viewer/core@5.15.1)
|
version: 5.15.1(@photo-sphere-viewer/core@5.15.1)
|
||||||
'@tanstack/svelte-query':
|
'@tanstack/svelte-query':
|
||||||
specifier: ^6.3.2
|
specifier: ^6.3.2
|
||||||
version: 6.3.2(svelte@5.57.2(@typescript-eslint/types@8.71.2))
|
version: 6.3.2(svelte@5.57.1(@typescript-eslint/types@8.70.1))
|
||||||
'@types/geojson':
|
'@types/geojson':
|
||||||
specifier: ^7946.0.16
|
specifier: ^7946.0.16
|
||||||
version: 7946.0.16
|
version: 7946.0.16
|
||||||
@@ -862,8 +862,8 @@ importers:
|
|||||||
specifier: ^1.6.16
|
specifier: ^1.6.16
|
||||||
version: 1.7.3
|
version: 1.7.3
|
||||||
intl-messageformat:
|
intl-messageformat:
|
||||||
specifier: ^11.0.0
|
specifier: ^12.0.0
|
||||||
version: 11.2.15
|
version: 12.1.3
|
||||||
justified-layout:
|
justified-layout:
|
||||||
specifier: ^4.1.0
|
specifier: ^4.1.0
|
||||||
version: 4.1.0
|
version: 4.1.0
|
||||||
@@ -2734,18 +2734,15 @@ packages:
|
|||||||
'@formatjs/icu-messageformat-parser@2.11.4':
|
'@formatjs/icu-messageformat-parser@2.11.4':
|
||||||
resolution: {integrity: sha512-7kR78cRrPNB4fjGFZg3Rmj5aah8rQj9KPzuLsmcSn4ipLXQvC04keycTI1F7kJYDwIXtT2+7IDEto842CfZBtw==}
|
resolution: {integrity: sha512-7kR78cRrPNB4fjGFZg3Rmj5aah8rQj9KPzuLsmcSn4ipLXQvC04keycTI1F7kJYDwIXtT2+7IDEto842CfZBtw==}
|
||||||
|
|
||||||
'@formatjs/icu-messageformat-parser@3.5.18':
|
|
||||||
resolution: {integrity: sha512-wX1efcL8d7K5QapOTRsP/OLTA/kpwe4LwqWyNxDNg5iRs8i9jJbCyxB5P8jc4KOW5oiLzz2DJr+BRY5xMV9+bA==}
|
|
||||||
|
|
||||||
'@formatjs/icu-messageformat-parser@3.5.20':
|
'@formatjs/icu-messageformat-parser@3.5.20':
|
||||||
resolution: {integrity: sha512-DUzCb2iskGDKvLU7P+nz/rjpmN59luoTRbWHFFNYNnZTxWCKvwPI94rNll99TGZaI6XoTbDF0QGegk21GFrQZQ==}
|
resolution: {integrity: sha512-DUzCb2iskGDKvLU7P+nz/rjpmN59luoTRbWHFFNYNnZTxWCKvwPI94rNll99TGZaI6XoTbDF0QGegk21GFrQZQ==}
|
||||||
|
|
||||||
|
'@formatjs/icu-messageformat-parser@3.5.21':
|
||||||
|
resolution: {integrity: sha512-Vnl7IOSyMRaP4Pjv48etkT2nlcIwzh4QWIa3hewzGlZZPBbft+TbMir4MijpDViOLN/1hvkGC10oYMuilsG+fw==}
|
||||||
|
|
||||||
'@formatjs/icu-skeleton-parser@1.8.16':
|
'@formatjs/icu-skeleton-parser@1.8.16':
|
||||||
resolution: {integrity: sha512-H13E9Xl+PxBd8D5/6TVUluSpxGNvFSlN/b3coUp0e0JpuWXXnQDiavIpY3NnvSp4xhEMoXyyBvVfdFX8jglOHQ==}
|
resolution: {integrity: sha512-H13E9Xl+PxBd8D5/6TVUluSpxGNvFSlN/b3coUp0e0JpuWXXnQDiavIpY3NnvSp4xhEMoXyyBvVfdFX8jglOHQ==}
|
||||||
|
|
||||||
'@formatjs/icu-skeleton-parser@2.1.11':
|
|
||||||
resolution: {integrity: sha512-j8cUmOJzVgkHuS0QiQ6ga76UIoLOFSAMWhs7aZJztH3aAdCOAE6vpC8KVvFB4cU10ON0y2/5oOVmPJ43s2lTwA==}
|
|
||||||
|
|
||||||
'@formatjs/icu-skeleton-parser@2.1.12':
|
'@formatjs/icu-skeleton-parser@2.1.12':
|
||||||
resolution: {integrity: sha512-ca7tZMLpfHX3sUD7hP6gE/qr6Iq89EDd3ZLeRhbsB7r0UD55DGJq+tmFLzrGrnx5StahUevQmQQVtbDRHsfDHA==}
|
resolution: {integrity: sha512-ca7tZMLpfHX3sUD7hP6gE/qr6Iq89EDd3ZLeRhbsB7r0UD55DGJq+tmFLzrGrnx5StahUevQmQQVtbDRHsfDHA==}
|
||||||
|
|
||||||
@@ -8502,8 +8499,8 @@ packages:
|
|||||||
intl-messageformat@10.7.18:
|
intl-messageformat@10.7.18:
|
||||||
resolution: {integrity: sha512-m3Ofv/X/tV8Y3tHXLohcuVuhWKo7BBq62cqY15etqmLxg2DZ34AGGgQDeR+SCta2+zICb1NX83af0GJmbQ1++g==}
|
resolution: {integrity: sha512-m3Ofv/X/tV8Y3tHXLohcuVuhWKo7BBq62cqY15etqmLxg2DZ34AGGgQDeR+SCta2+zICb1NX83af0GJmbQ1++g==}
|
||||||
|
|
||||||
intl-messageformat@11.2.15:
|
intl-messageformat@12.1.3:
|
||||||
resolution: {integrity: sha512-W4VNytsXyWgW5lvVchmsb9xgA5rSKqoflu3/IQ9UCtB0z4R+Bx9MoEkwFT/+30RCl/KzUoH0QGGe9lppF5SuvQ==}
|
resolution: {integrity: sha512-JXi5wk8R/oSECKyxSIZ00VS8KG6MZkHM0qU4NS7RrvIWWXkiv3wVqGlCvEvyXiDvKlt2yqwZMiZGIv+I8rrnZQ==}
|
||||||
|
|
||||||
invariant@2.2.4:
|
invariant@2.2.4:
|
||||||
resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
|
resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
|
||||||
@@ -15743,21 +15740,19 @@ snapshots:
|
|||||||
'@formatjs/icu-skeleton-parser': 1.8.16
|
'@formatjs/icu-skeleton-parser': 1.8.16
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
|
|
||||||
'@formatjs/icu-messageformat-parser@3.5.18':
|
|
||||||
dependencies:
|
|
||||||
'@formatjs/icu-skeleton-parser': 2.1.11
|
|
||||||
|
|
||||||
'@formatjs/icu-messageformat-parser@3.5.20':
|
'@formatjs/icu-messageformat-parser@3.5.20':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@formatjs/icu-skeleton-parser': 2.1.12
|
'@formatjs/icu-skeleton-parser': 2.1.12
|
||||||
|
|
||||||
|
'@formatjs/icu-messageformat-parser@3.5.21':
|
||||||
|
dependencies:
|
||||||
|
'@formatjs/icu-skeleton-parser': 2.1.12
|
||||||
|
|
||||||
'@formatjs/icu-skeleton-parser@1.8.16':
|
'@formatjs/icu-skeleton-parser@1.8.16':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@formatjs/ecma402-abstract': 2.3.6
|
'@formatjs/ecma402-abstract': 2.3.6
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
|
|
||||||
'@formatjs/icu-skeleton-parser@2.1.11': {}
|
|
||||||
|
|
||||||
'@formatjs/icu-skeleton-parser@2.1.12': {}
|
'@formatjs/icu-skeleton-parser@2.1.12': {}
|
||||||
|
|
||||||
'@formatjs/intl-localematcher@0.6.2':
|
'@formatjs/intl-localematcher@0.6.2':
|
||||||
@@ -17636,10 +17631,10 @@ snapshots:
|
|||||||
|
|
||||||
'@tanstack/query-core@5.104.2': {}
|
'@tanstack/query-core@5.104.2': {}
|
||||||
|
|
||||||
'@tanstack/svelte-query@6.3.2(svelte@5.57.2(@typescript-eslint/types@8.71.2))':
|
'@tanstack/svelte-query@6.3.2(svelte@5.57.1(@typescript-eslint/types@8.70.1))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@tanstack/query-core': 5.104.2
|
'@tanstack/query-core': 5.104.2
|
||||||
svelte: 5.57.2(@typescript-eslint/types@8.71.2)
|
svelte: 5.57.1(@typescript-eslint/types@8.70.1)
|
||||||
|
|
||||||
'@testing-library/dom@10.4.1':
|
'@testing-library/dom@10.4.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -18251,7 +18246,7 @@ snapshots:
|
|||||||
|
|
||||||
'@types/through@0.0.33':
|
'@types/through@0.0.33':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 24.19.0
|
'@types/node': 24.19.2
|
||||||
|
|
||||||
'@types/trusted-types@2.0.7':
|
'@types/trusted-types@2.0.7':
|
||||||
optional: true
|
optional: true
|
||||||
@@ -18268,7 +18263,7 @@ snapshots:
|
|||||||
|
|
||||||
'@types/ws@8.18.1':
|
'@types/ws@8.18.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 24.19.0
|
'@types/node': 24.19.2
|
||||||
|
|
||||||
'@types/yargs-parser@21.0.3': {}
|
'@types/yargs-parser@21.0.3': {}
|
||||||
|
|
||||||
@@ -19249,7 +19244,7 @@ snapshots:
|
|||||||
|
|
||||||
buffer-image-size@0.6.4:
|
buffer-image-size@0.6.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 24.19.0
|
'@types/node': 24.19.2
|
||||||
|
|
||||||
buffer@5.7.1:
|
buffer@5.7.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -21566,7 +21561,7 @@ snapshots:
|
|||||||
|
|
||||||
happy-dom@20.14.5:
|
happy-dom@20.14.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 24.19.0
|
'@types/node': 24.19.2
|
||||||
'@types/whatwg-mimetype': 3.0.2
|
'@types/whatwg-mimetype': 3.0.2
|
||||||
'@types/ws': 8.18.1
|
'@types/ws': 8.18.1
|
||||||
buffer-image-size: 0.6.4
|
buffer-image-size: 0.6.4
|
||||||
@@ -22069,10 +22064,10 @@ snapshots:
|
|||||||
'@formatjs/icu-messageformat-parser': 2.11.4
|
'@formatjs/icu-messageformat-parser': 2.11.4
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
|
|
||||||
intl-messageformat@11.2.15:
|
intl-messageformat@12.1.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@formatjs/fast-memoize': 3.1.7
|
'@formatjs/fast-memoize': 3.1.7
|
||||||
'@formatjs/icu-messageformat-parser': 3.5.18
|
'@formatjs/icu-messageformat-parser': 3.5.21
|
||||||
|
|
||||||
invariant@2.2.4:
|
invariant@2.2.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -22382,7 +22377,7 @@ snapshots:
|
|||||||
|
|
||||||
jest-worker@27.5.1:
|
jest-worker@27.5.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 24.19.0
|
'@types/node': 24.19.2
|
||||||
merge-stream: 2.0.0
|
merge-stream: 2.0.0
|
||||||
supports-color: 8.1.1
|
supports-color: 8.1.1
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,131 @@
|
|||||||
|
import {
|
||||||
|
deleteLibrary,
|
||||||
|
getConfig,
|
||||||
|
getStorage,
|
||||||
|
updateConfig,
|
||||||
|
updateLibrary,
|
||||||
|
type AdminConfigDto,
|
||||||
|
type LibraryResponseDto,
|
||||||
|
} from '@immich/sdk';
|
||||||
|
import { eventManager } from '$lib/managers/event-manager.svelte';
|
||||||
|
import { executeMutation, queryClient } from '$lib/queries/client';
|
||||||
|
import {
|
||||||
|
deleteLibraryMutation,
|
||||||
|
getAllLibrariesQuery,
|
||||||
|
getLibraryStatisticsQuery,
|
||||||
|
updateLibraryMutation,
|
||||||
|
} from '$lib/queries/library.query';
|
||||||
|
import { getStorageQuery } from '$lib/queries/server.query';
|
||||||
|
import { getConfigQuery, updateConfigMutation } from '$lib/queries/system-config.query';
|
||||||
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
|
|
||||||
|
vi.mock('@immich/ui', () => ({ toastManager: { primary: vi.fn(), info: vi.fn() } }));
|
||||||
|
vi.mock('$lib/utils/handle-error', () => ({ handleError: vi.fn() }));
|
||||||
|
vi.mock('$lib/utils/i18n', () => ({ getFormatter: async () => (key: string) => key }));
|
||||||
|
vi.mock('@immich/sdk', () => ({
|
||||||
|
createLibrary: vi.fn(),
|
||||||
|
deleteLibrary: vi.fn(),
|
||||||
|
getAllLibraries: vi.fn(),
|
||||||
|
getLibraryStatistics: vi.fn(),
|
||||||
|
scanLibrary: vi.fn(),
|
||||||
|
updateLibrary: vi.fn(),
|
||||||
|
getAboutInfo: vi.fn(),
|
||||||
|
getVersionHistory: vi.fn(),
|
||||||
|
getStorage: vi.fn(),
|
||||||
|
getServerStatistics: vi.fn(),
|
||||||
|
getConfig: vi.fn(),
|
||||||
|
getConfigDefaults: vi.fn(),
|
||||||
|
updateConfig: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const first = { id: 'first', name: 'Photos' } as LibraryResponseDto;
|
||||||
|
const second = { id: 'second', name: 'Archive' } as LibraryResponseDto;
|
||||||
|
|
||||||
|
describe('shared queries after the upstream migration', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
queryClient.clear();
|
||||||
|
vi.resetAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => queryClient.clear());
|
||||||
|
|
||||||
|
it('clears account data on logout', () => {
|
||||||
|
queryClient.setQueryData(getAllLibrariesQuery().queryKey, [first]);
|
||||||
|
queryClient.setQueryData(getConfigQuery().queryKey, {} as AdminConfigDto);
|
||||||
|
eventManager.emit('AuthLogout');
|
||||||
|
expect(queryClient.getQueryCache().getAll()).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shares a storage request between consumers', async () => {
|
||||||
|
const storage = { diskSizeRaw: 100, diskUseRaw: 20 } as Awaited<ReturnType<typeof getStorage>>;
|
||||||
|
vi.mocked(getStorage).mockResolvedValue(storage);
|
||||||
|
const values = await Promise.all([queryClient.query(getStorageQuery()), queryClient.query(getStorageQuery())]);
|
||||||
|
expect(values).toEqual([storage, storage]);
|
||||||
|
expect(getStorage).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('preserves libraries and statistics when deletion fails', async () => {
|
||||||
|
queryClient.setQueryData(getAllLibrariesQuery().queryKey, [first, second]);
|
||||||
|
queryClient.setQueryData(getLibraryStatisticsQuery(first.id).queryKey, {
|
||||||
|
photos: 5,
|
||||||
|
videos: 0,
|
||||||
|
usage: 100,
|
||||||
|
total: 5,
|
||||||
|
});
|
||||||
|
vi.mocked(deleteLibrary).mockRejectedValue(new Error('offline'));
|
||||||
|
await executeMutation(deleteLibraryMutation, [{ id: first.id }]);
|
||||||
|
expect(queryClient.getQueryData(getAllLibrariesQuery().queryKey)).toEqual([first, second]);
|
||||||
|
expect(queryClient.getQueryData(getLibraryStatisticsQuery(first.id).queryKey)?.photos).toBe(5);
|
||||||
|
expect(handleError).toHaveBeenCalledOnce();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('removes only the deleted library from the cache after success', async () => {
|
||||||
|
queryClient.setQueryData(getAllLibrariesQuery().queryKey, [first, second]);
|
||||||
|
queryClient.setQueryData(getLibraryStatisticsQuery(first.id).queryKey, {
|
||||||
|
photos: 5,
|
||||||
|
videos: 0,
|
||||||
|
usage: 100,
|
||||||
|
total: 5,
|
||||||
|
});
|
||||||
|
vi.mocked(deleteLibrary).mockResolvedValue(undefined as never);
|
||||||
|
await executeMutation(deleteLibraryMutation, [{ id: first.id }]);
|
||||||
|
expect(queryClient.getQueryData(getAllLibrariesQuery().queryKey)).toEqual([second]);
|
||||||
|
expect(queryClient.getQueryData(getLibraryStatisticsQuery(first.id).queryKey)).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses the saved library response and refreshes its statistics', async () => {
|
||||||
|
queryClient.setQueryData(getAllLibrariesQuery().queryKey, [first, second]);
|
||||||
|
queryClient.setQueryData(getLibraryStatisticsQuery(first.id).queryKey, {
|
||||||
|
photos: 5,
|
||||||
|
videos: 0,
|
||||||
|
usage: 100,
|
||||||
|
total: 5,
|
||||||
|
});
|
||||||
|
const saved = { ...first, name: 'Renamed' };
|
||||||
|
vi.mocked(updateLibrary).mockResolvedValue(saved);
|
||||||
|
await executeMutation(updateLibraryMutation, [{ id: first.id, updateLibraryDto: { name: saved.name } }]);
|
||||||
|
expect(queryClient.getQueryData(getAllLibrariesQuery().queryKey)).toEqual([saved, second]);
|
||||||
|
expect(queryClient.getQueryState(getLibraryStatisticsQuery(first.id).queryKey)?.isInvalidated).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('merges a settings edit with the latest server configuration', async () => {
|
||||||
|
const current = { server: { externalDomain: 'https://example.com' }, trash: { enabled: true, days: 30 } };
|
||||||
|
const update = { trash: { enabled: true, days: 60 } };
|
||||||
|
const saved = { ...current, ...update } as AdminConfigDto;
|
||||||
|
vi.mocked(getConfig).mockResolvedValue(current as AdminConfigDto);
|
||||||
|
vi.mocked(updateConfig).mockResolvedValue(saved);
|
||||||
|
await executeMutation(updateConfigMutation, update);
|
||||||
|
expect(updateConfig).toHaveBeenCalledWith({ adminConfigDto: saved });
|
||||||
|
expect(queryClient.getQueryData(getConfigQuery().queryKey)).toEqual(saved);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('keeps the previous settings if saving fails', async () => {
|
||||||
|
const current = { trash: { enabled: true, days: 30 } } as AdminConfigDto;
|
||||||
|
queryClient.setQueryData(getConfigQuery().queryKey, current);
|
||||||
|
vi.mocked(getConfig).mockResolvedValue(current);
|
||||||
|
vi.mocked(updateConfig).mockRejectedValue(new Error('offline'));
|
||||||
|
await executeMutation(updateConfigMutation, { trash: { enabled: true, days: 60 } });
|
||||||
|
expect(queryClient.getQueryData(getConfigQuery().queryKey)).toEqual(current);
|
||||||
|
expect(handleError).toHaveBeenCalledOnce();
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user