import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { apiGet, apiPost, vergeetGedeeldeVerzoeken } from './client' function antwoord(data: unknown) { return { ok: true, status: 200, json: async () => ({ data }), } as unknown as Response } describe('apiGet deelt verzoeken', () => { beforeEach(() => { vi.useFakeTimers() }) afterEach(() => { vi.runOnlyPendingTimers() vi.useRealTimers() vi.restoreAllMocks() }) it('stuurt één verzoek wanneer drie aanroepers tegelijk hetzelfde vragen', async () => { const fetchSpy = vi.fn().mockResolvedValue(antwoord({ items: [1] })) vi.stubGlobal('fetch', fetchSpy) const [a, b, c] = await Promise.all([ apiGet<{ items: number[] }>('/api/v1/projects'), apiGet<{ items: number[] }>('/api/v1/projects'), apiGet<{ items: number[] }>('/api/v1/projects'), ]) expect(fetchSpy).toHaveBeenCalledTimes(1) expect(a).toEqual({ items: [1] }) expect(b).toBe(a) expect(c).toBe(a) }) it('deelt ook wanneer het tweede verzoek kort ná het eerste komt', async () => { // Dit was het echte geval bij het opstarten: twee effecten die ongeveer // negentig milliseconde na elkaar dezelfde gegevens opvroegen, dus de // eerste was al klaar voordat de tweede begon. const fetchSpy = vi.fn().mockResolvedValue(antwoord({ items: [] })) vi.stubGlobal('fetch', fetchSpy) await apiGet('/api/v1/projects/p-1/datasets') await vi.advanceTimersByTimeAsync(90) await apiGet('/api/v1/projects/p-1/datasets') expect(fetchSpy).toHaveBeenCalledTimes(1) }) it('haalt opnieuw op zodra het deelvenster voorbij is', async () => { const fetchSpy = vi.fn().mockResolvedValue(antwoord({ items: [] })) vi.stubGlobal('fetch', fetchSpy) await apiGet('/api/v1/projects/p-1/areas') await vi.advanceTimersByTimeAsync(400) await apiGet('/api/v1/projects/p-1/areas') expect(fetchSpy).toHaveBeenCalledTimes(2) }) it('houdt verschillende paden uit elkaar', async () => { const fetchSpy = vi.fn().mockResolvedValue(antwoord({ items: [] })) vi.stubGlobal('fetch', fetchSpy) await Promise.all([ apiGet('/api/v1/projects'), apiGet('/api/v1/projects?name=Kempen&limit=1'), ]) expect(fetchSpy).toHaveBeenCalledTimes(2) }) it('deelt geen POST — twee keer versturen is een andere handeling', async () => { const fetchSpy = vi.fn().mockResolvedValue(antwoord({ ok: true })) vi.stubGlobal('fetch', fetchSpy) await Promise.all([ apiPost('/api/v1/projects', { name: 'a' }), apiPost('/api/v1/projects', { name: 'a' }), ]) expect(fetchSpy).toHaveBeenCalledTimes(2) }) it('deelt niets meer over een identiteitswissel heen', async () => { // Uitloggen herlaadt de pagina niet, dus de tabel leeft door. Zonder deze // reset zou de volgende gebruiker binnen het deelvenster het antwoord van // de vorige kunnen krijgen. const fetchSpy = vi.fn() .mockResolvedValueOnce(antwoord({ items: ['werkruimte van A'] })) .mockResolvedValueOnce(antwoord({ items: ['werkruimte van B'] })) vi.stubGlobal('fetch', fetchSpy) const vanA = await apiGet<{ items: string[] }>('/api/v1/projects') vergeetGedeeldeVerzoeken() const vanB = await apiGet<{ items: string[] }>('/api/v1/projects') expect(fetchSpy).toHaveBeenCalledTimes(2) expect(vanA.items).toEqual(['werkruimte van A']) expect(vanB.items).toEqual(['werkruimte van B']) }) it('wist de tabel ook wanneer de sessie verloopt', async () => { const fetchSpy = vi.fn().mockResolvedValue(antwoord({ items: [] })) vi.stubGlobal('fetch', fetchSpy) await apiGet('/api/v1/projects') window.dispatchEvent(new CustomEvent('geointel:session-expired')) await apiGet('/api/v1/projects') expect(fetchSpy).toHaveBeenCalledTimes(2) }) it('laat een mislukt verzoek niet in de tabel achter', async () => { const fetchSpy = vi.fn() .mockRejectedValueOnce(new Error('netwerk weg')) .mockResolvedValue(antwoord({ items: [] })) vi.stubGlobal('fetch', fetchSpy) await expect(apiGet('/api/v1/detection/models')).rejects.toThrow('netwerk weg') await vi.advanceTimersByTimeAsync(400) await expect(apiGet('/api/v1/detection/models')).resolves.toEqual({ items: [] }) expect(fetchSpy).toHaveBeenCalledTimes(2) }) })