✅ test: 覆盖弹窗生命周期、存储合并与插件页的时长选项
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
// The popup stack's lifetime: the user's choice decides it, and "never" really
|
||||
// means the card waits for the user rather than for a timer.
|
||||
import { test } from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
|
||||
import { createStore } from '../../src/client/core/store.js'
|
||||
import { createToastStack } from '../../src/client/core/toasts.js'
|
||||
import { createCopy } from '../../src/client/core/copy.js'
|
||||
import { createTranslator } from '../../src/client/i18n/index.js'
|
||||
import { TOAST_DURATION_MS } from '../../src/client/constants.js'
|
||||
|
||||
const tr = createTranslator({ getSnapshot: () => ({ active: 'zh' }) })
|
||||
const candidate = { kind: 'completion', sessionId: 's1', title: '标题', detail: '', pendingKind: '' }
|
||||
|
||||
/** A stack over a store whose only interesting field is the popup lifetime. */
|
||||
function stack(dismissAfterMs) {
|
||||
const store = createStore({ dismissAfterMs, toasts: [] })
|
||||
return { store, toasts: createToastStack({ store, copy: createCopy(tr) }) }
|
||||
}
|
||||
|
||||
const ids = (store) => store.getSnapshot().toasts.map((toast) => toast.id)
|
||||
|
||||
test('a card closes itself after the configured lifetime', (context) => {
|
||||
context.mock.timers.enable({ apis: ['setTimeout'] })
|
||||
const { store, toasts } = stack(6000)
|
||||
toasts.showToast(candidate)
|
||||
|
||||
assert.equal(ids(store).length, 1)
|
||||
context.mock.timers.tick(5999)
|
||||
assert.equal(ids(store).length, 1, 'the card must outlive its countdown')
|
||||
context.mock.timers.tick(1)
|
||||
assert.deepEqual(ids(store), [])
|
||||
})
|
||||
|
||||
test('a lifetime of zero leaves the card until it is dismissed', (context) => {
|
||||
context.mock.timers.enable({ apis: ['setTimeout'] })
|
||||
const { store, toasts } = stack(0)
|
||||
toasts.showToast(candidate)
|
||||
|
||||
context.mock.timers.tick(60 * 60 * 1000)
|
||||
assert.equal(ids(store).length, 1, 'nothing may close a "never" card')
|
||||
|
||||
toasts.closeToast(ids(store)[0])
|
||||
assert.deepEqual(ids(store), [])
|
||||
})
|
||||
|
||||
test('hovering holds the card, and the lifetime chosen while held applies afterwards', (context) => {
|
||||
context.mock.timers.enable({ apis: ['setTimeout'] })
|
||||
const { store, toasts } = stack(3000)
|
||||
toasts.showToast(candidate)
|
||||
const id = ids(store)[0]
|
||||
|
||||
toasts.holdToast(id)
|
||||
context.mock.timers.tick(30 * 1000)
|
||||
assert.equal(ids(store).length, 1, 'a held card has no timer left')
|
||||
|
||||
// The settings page switches to "never" while the pointer is still on the card.
|
||||
store.set({ ...store.getSnapshot(), dismissAfterMs: 0 })
|
||||
toasts.armToast(id)
|
||||
context.mock.timers.tick(60 * 60 * 1000)
|
||||
assert.equal(ids(store).length, 1)
|
||||
})
|
||||
|
||||
test('a lifetime change applies to the cards already on screen, but never to a held one', (context) => {
|
||||
context.mock.timers.enable({ apis: ['setTimeout'] })
|
||||
const { store, toasts } = stack(30000)
|
||||
toasts.showToast(candidate)
|
||||
toasts.showToast({ ...candidate, sessionId: 's2' })
|
||||
const [newest, oldest] = ids(store)
|
||||
toasts.holdToast(oldest)
|
||||
|
||||
// The settings page shortens the lifetime while both cards are visible.
|
||||
store.set({ ...store.getSnapshot(), dismissAfterMs: 3000 })
|
||||
toasts.rearmAll()
|
||||
context.mock.timers.tick(3000)
|
||||
assert.deepEqual(ids(store), [oldest], 'the visible card followed the new choice, the held one did not')
|
||||
|
||||
toasts.armToast(oldest)
|
||||
context.mock.timers.tick(3000)
|
||||
assert.deepEqual(ids(store), [], 'once the pointer leaves, the held card counts down again')
|
||||
void newest
|
||||
})
|
||||
|
||||
test('a lifetime this version cannot use falls back to the shipped default', (context) => {
|
||||
context.mock.timers.enable({ apis: ['setTimeout'] })
|
||||
const { store, toasts } = stack(undefined)
|
||||
toasts.showToast(candidate)
|
||||
|
||||
context.mock.timers.tick(TOAST_DURATION_MS)
|
||||
assert.deepEqual(ids(store), [])
|
||||
})
|
||||
|
||||
test('the stack never grows past its bound, however long the cards live', (context) => {
|
||||
context.mock.timers.enable({ apis: ['setTimeout'] })
|
||||
const { store, toasts } = stack(0)
|
||||
for (let index = 0; index < 5; index += 1) toasts.showToast({ ...candidate, sessionId: `s${index}` })
|
||||
|
||||
assert.equal(ids(store).length, 3)
|
||||
assert.deepEqual(ids(store), ['dsn-5', 'dsn-4', 'dsn-3'], 'newest first')
|
||||
})
|
||||
Reference in New Issue
Block a user