Files
webmail/lib/__tests__/email-prefetch.test.ts

54 lines
2.1 KiB
TypeScript

import { afterEach, describe, expect, it, vi } from 'vitest';
import { forgetEmailPrefetches, prefetchEmailContent, requestEmailContent } from '../email-prefetch';
import type { IJMAPClient } from '@/lib/jmap/client-interface';
import type { Email } from '@/lib/jmap/types';
// A mouse press on a row starts the body request; the click that follows
// takes that request over instead of sending a second one.
const client = (getEmail = vi.fn(async (id: string) => ({ id }) as Email)) =>
({ getAccountId: () => 'login', getEmail }) as unknown as IJMAPClient & { getEmail: typeof getEmail };
describe('email prefetch', () => {
afterEach(() => {
forgetEmailPrefetches();
vi.useRealTimers();
});
it('hands the open the request the press started', async () => {
const c = client();
prefetchEmailContent(c, 'e1', 'acct');
prefetchEmailContent(c, 'e1', 'acct'); // a second press does not ask again
const email = await requestEmailContent(c, 'e1', 'acct');
expect(email?.id).toBe('e1');
expect(c.getEmail).toHaveBeenCalledTimes(1);
expect(c.getEmail).toHaveBeenCalledWith('e1', 'acct');
});
it('asks again when the press was for another account or message', async () => {
const c = client();
prefetchEmailContent(c, 'e1', 'acct');
await requestEmailContent(c, 'e1', 'other');
await requestEmailContent(c, 'e2', 'acct');
expect(c.getEmail).toHaveBeenCalledTimes(3);
});
it('does not hand out a request older than a few seconds', async () => {
vi.useFakeTimers();
const c = client();
prefetchEmailContent(c, 'e1');
vi.advanceTimersByTime(6_000);
await requestEmailContent(c, 'e1');
expect(c.getEmail).toHaveBeenCalledTimes(2);
});
it('lets the open see a failed prefetch, and an unclaimed one fail quietly', async () => {
const failing = client(vi.fn(async () => { throw new Error('offline'); }));
prefetchEmailContent(failing, 'e1');
await expect(requestEmailContent(failing, 'e1')).rejects.toThrow('offline');
prefetchEmailContent(failing, 'e2'); // never claimed: no unhandled rejection
await new Promise((r) => setTimeout(r, 0));
});
});