fix: list files again when the real client takes over from the local copy

This commit is contained in:
Linus Rath
2026-11-03 09:53:04 +01:00
parent 87b15b12f6
commit 1dde703993
3 changed files with 28 additions and 2 deletions
+3 -1
View File
@@ -842,7 +842,9 @@ test('nothing of a kept message is readable on the device', async ({ browser })
await enableOffline(page);
await expect(async () => {
const client = await jmapAs(ENT.alice);
const total = await client.request([['Email/query', { accountId: client.accountId, calculateTotal: true, limit: 0 }, '0']]);
// The default window: the old message of the cap test stays out.
const after = new Date(Date.now() - 90 * 86_400_000).toISOString().replace(/\.\d+Z$/, 'Z');
const total = await client.request([['Email/query', { accountId: client.accountId, filter: { after }, calculateTotal: true, limit: 0 }, '0']]);
expect(await keptMessages(page)).toBeGreaterThanOrEqual(total.methodResponses[0][1].total);
}).toPass({ timeout: 180_000, intervals: [2000] });
await toMail(page);
+19 -1
View File
@@ -1,4 +1,4 @@
import { describe, it, expect, beforeEach } from 'vitest';
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { useFileStore, linkedPreviewResource, resourceServerRef, sharedFilesLocation } from '../file-store';
import type { IJMAPClient } from '@/lib/jmap/client-interface';
import type { FileNode } from '@/lib/jmap/types';
@@ -106,6 +106,24 @@ const file = (id: string, name: string, parentId: string | null): FileNode => ({
id, parentId, name, type: 'text/plain', blobId: `b-${id}`, size: 10, created: '', modified: '',
});
describe('after a start from the local copy', () => {
it('lists again when the real client takes over, and the error of asking the device goes', async () => {
const local = makeMockClient([]);
(local as unknown as { isOfflineOnly: () => boolean }).isOfflineOnly = () => true;
local.listAllFileNodes = async () => { throw new Error('Not available offline'); };
useFileStore.setState({ client: null, supportsFiles: null, resources: [], error: null, currentParentId: null, pathStack: [{ id: null, name: '' }] } as never);
useFileStore.getState().initClient(local as unknown as IJMAPClient, 'acc');
useFileStore.setState({ supportsFiles: true });
await useFileStore.getState().navigate(null);
expect(useFileStore.getState().error).toBeTruthy();
const real = makeMockClient([{ id: 'f1', parentId: null, name: 'kept.txt', type: 'text/plain', blobId: 'b', size: 1, created: '', modified: '' }]);
useFileStore.getState().initClient(real as unknown as IJMAPClient, 'acc');
await vi.waitFor(() => expect(useFileStore.getState().resources.map((r) => r.name)).toEqual(['kept.txt']));
expect(useFileStore.getState().error).toBeFalsy();
});
});
describe('file-store hierarchy (issue #379)', () => {
beforeEach(() => {
useFileStore.setState({
+6
View File
@@ -649,9 +649,15 @@ export const useFileStore = create<FileState>((set, get) => ({
})(),
initClient: (client: IJMAPClient, accountId?: string | null) => {
const before = get().client as (IJMAPClient & { isOfflineOnly?: () => boolean }) | null;
const patch: Partial<FileState> = { client };
if (accountId !== undefined) patch.currentAccountId = accountId;
set(patch);
// A start from the local copy: the real client just took over, and what's
// listed is what the device had, or the error of asking it.
const offlineBefore = before !== client && before?.isOfflineOnly?.();
const offlineNow = (client as IJMAPClient & { isOfflineOnly?: () => boolean }).isOfflineOnly?.();
if (offlineBefore && !offlineNow && get().supportsFiles) void get().refresh();
},
clearClient: () => {