chore: prepare local.3 release with query regression coverage

This commit is contained in:
Codex
2026-10-16 20:58:44 +03:00
parent ae7cb3192e
commit 4649313c29
3 changed files with 153 additions and 27 deletions
@@ -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();
});
});