|
| 1 | +import type { DevframeMessageEntry, DevframeMessagesListDelta } from '@devframes/hub' |
| 2 | +import type { DocksContext } from '@devframes/hub/client' |
| 3 | +import { afterEach, expect, it, vi } from 'vitest' |
| 4 | + |
| 5 | +afterEach(async () => { |
| 6 | + const { dismissToast, useToasts } = await import('./toasts') |
| 7 | + for (const toast of [...useToasts()]) dismissToast(toast.id) |
| 8 | + vi.restoreAllMocks() |
| 9 | + vi.resetModules() |
| 10 | + vi.useRealTimers() |
| 11 | +}) |
| 12 | + |
| 13 | +async function fixture() { |
| 14 | + const { useMessages } = await import('./messages') |
| 15 | + const { useToasts } = await import('./toasts') |
| 16 | + let delta: DevframeMessagesListDelta = { entries: [], removedIds: [], version: 0, full: true } |
| 17 | + let refresh = () => {} |
| 18 | + const call = vi.fn(async () => delta) |
| 19 | + // eslint-disable-next-line slop/no-chained-type-assertions -- Only the RPC feed participates in this state test. |
| 20 | + const state = useMessages({ rpc: { |
| 21 | + call, |
| 22 | + isTrusted: true, |
| 23 | + ensureTrusted: async () => {}, |
| 24 | + client: { register: (command: { handler: () => void }) => { refresh = command.handler } }, |
| 25 | + } } as unknown as DocksContext) |
| 26 | + await vi.waitUntil(() => call.mock.calls.length === 1) |
| 27 | + await Promise.resolve() |
| 28 | + async function publish(next: DevframeMessagesListDelta) { |
| 29 | + delta = next |
| 30 | + refresh() |
| 31 | + await Promise.resolve() |
| 32 | + } |
| 33 | + const message: DevframeMessageEntry = { id: 'pending', message: 'Pending approval', level: 'info', from: 'browser', timestamp: 0, notify: true, autoDismiss: 60_000 } |
| 34 | + await publish({ entries: [message], removedIds: [], version: 1, full: false }) |
| 35 | + return { state, toasts: useToasts(), publish, message } |
| 36 | +} |
| 37 | + |
| 38 | +it.each([false, true])('removes visible toasts and timers when the message is removed (full=%s)', async (full) => { |
| 39 | + expect.assertions(5) |
| 40 | + const { state, toasts, publish } = await fixture() |
| 41 | + const clearTimer = vi.spyOn(globalThis, 'clearTimeout') |
| 42 | + expect(state.entries).toHaveLength(1) |
| 43 | + expect(toasts).toHaveLength(1) |
| 44 | + await publish({ entries: [], removedIds: full ? [] : ['pending'], version: 2, full }) |
| 45 | + expect(state.entries).toHaveLength(0) |
| 46 | + expect(toasts).toHaveLength(0) |
| 47 | + expect(clearTimer).toHaveBeenCalledOnce() |
| 48 | +}) |
| 49 | + |
| 50 | +it('keeps surviving toasts and unread counts when receiving a full snapshot', async () => { |
| 51 | + expect.assertions(3) |
| 52 | + const { state, toasts, publish, message } = await fixture() |
| 53 | + await publish({ entries: [message], removedIds: [], version: 2, full: true }) |
| 54 | + expect(state.entries).toHaveLength(1) |
| 55 | + expect(toasts).toHaveLength(1) |
| 56 | + expect(state.unreadCount).toBe(1) |
| 57 | +}) |
0 commit comments