feat(schedule): add durable after reminders
This commit is contained in:
75
packages/client/ui-schedule/tests/browser-plugin.spec.ts
Normal file
75
packages/client/ui-schedule/tests/browser-plugin.spec.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { Context } from 'cordis'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { LocaleService } from '@deepseek-ai/dsh-client-locale/client'
|
||||
import { apply, inject } from '../src/client/index.ts'
|
||||
import { ReminderRow } from '../src/client/ReminderRow.tsx'
|
||||
import { apply as nodeApply } from '../src/index.ts'
|
||||
import {
|
||||
apply as invariantApply,
|
||||
inject as invariantInject,
|
||||
name as invariantName,
|
||||
} from '../src/invariant.ts'
|
||||
|
||||
interface CapturedEntry {
|
||||
name: string
|
||||
key?: string
|
||||
locale?: string
|
||||
component: unknown
|
||||
}
|
||||
|
||||
function bench() {
|
||||
const ctx = new Context()
|
||||
let entry: CapturedEntry | undefined
|
||||
ctx.provide('slots', {
|
||||
register(options: Omit<CapturedEntry, 'component'>, component: unknown) {
|
||||
entry = { ...options, component }
|
||||
return () => { entry = undefined }
|
||||
},
|
||||
})
|
||||
ctx.provide('conversation', {})
|
||||
ctx.provide('locale', new LocaleService(ctx))
|
||||
const fiber = ctx.plugin({ inject: [...inject], apply })
|
||||
return { ctx, fiber, entry: () => entry }
|
||||
}
|
||||
|
||||
describe('ui-schedule browser plugin', () => {
|
||||
it('registers the keyed reminder renderer and unloads it with the fiber', async () => {
|
||||
const b = bench()
|
||||
await b.fiber.await()
|
||||
expect(b.entry()).toEqual({
|
||||
name: 'conversation.chat.eventview',
|
||||
key: 'schedule/reminder',
|
||||
locale: 'schedule',
|
||||
component: ReminderRow,
|
||||
})
|
||||
|
||||
await b.fiber.dispose()
|
||||
expect(b.entry()).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('ui-schedule node and invariant companions', () => {
|
||||
it('keeps the node half inert', () => {
|
||||
expect(() => { nodeApply() }).not.toThrow()
|
||||
})
|
||||
|
||||
it('registers exact package ownership and returns its disposer', async () => {
|
||||
const ctx = new Context()
|
||||
let owner: string | undefined
|
||||
let disposed = false
|
||||
ctx.provide('invariants', {
|
||||
register(packageName: string, install: unknown) {
|
||||
expect(install).toBeTypeOf('function')
|
||||
owner = packageName
|
||||
return () => { disposed = true }
|
||||
},
|
||||
})
|
||||
|
||||
expect(invariantName).toBe('client-ui-schedule-invariant')
|
||||
expect(invariantInject).toEqual(['invariants'])
|
||||
const dispose = await invariantApply(ctx)
|
||||
expect(owner).toBe('@deepseek-ai/dsh-client-ui-schedule')
|
||||
dispose()
|
||||
expect(disposed).toBe(true)
|
||||
})
|
||||
})
|
||||
55
packages/client/ui-schedule/tests/reminder-row.spec.tsx
Normal file
55
packages/client/ui-schedule/tests/reminder-row.spec.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
// @vitest-environment jsdom
|
||||
|
||||
import { cleanup, render, screen } from '@testing-library/react'
|
||||
import { afterEach, describe, expect, it } from 'vitest'
|
||||
import { makeTranslate } from '@deepseek-ai/dsh-client-test-runtime'
|
||||
import type { PresentedEventNode } from '@deepseek-ai/dsh-client-runtime/client'
|
||||
import { ReminderRow, type ReminderRowProps } from '../src/client/ReminderRow.tsx'
|
||||
import { zh } from '../src/client/locales.ts'
|
||||
|
||||
const t: ReminderRowProps['t'] = makeTranslate(zh)
|
||||
|
||||
afterEach(cleanup)
|
||||
|
||||
function props(view: unknown): ReminderRowProps {
|
||||
const node: PresentedEventNode = {
|
||||
kind: 'presented-event',
|
||||
seq: 4,
|
||||
time: Date.parse('2026-08-05T08:00:00.000Z'),
|
||||
presentationKey: 'schedule/reminder',
|
||||
view,
|
||||
}
|
||||
return { node, t } as ReminderRowProps
|
||||
}
|
||||
|
||||
describe('ReminderRow', () => {
|
||||
it('shows the durable reminder payload and its session-local boundary', () => {
|
||||
render(<ReminderRow {...props({
|
||||
scheduleId: 'schedule-7',
|
||||
prompt: 'Check the deploy',
|
||||
occurrenceAt: '2026-08-05T08:00:00.000Z',
|
||||
deliveryMode: 'session-local',
|
||||
})} />)
|
||||
|
||||
expect(screen.getByRole('note')).toBeTruthy()
|
||||
expect(screen.getByText('定时提醒')).toBeTruthy()
|
||||
expect(screen.getByText('仅在当前会话中交付')).toBeTruthy()
|
||||
expect(screen.getByText('Check the deploy')).toBeTruthy()
|
||||
expect(screen.getByText('编号 schedule-7')).toBeTruthy()
|
||||
const time = screen.getByText('触发时间 2026-08-05T08:00:00.000Z')
|
||||
expect(time.getAttribute('datetime')).toBe('2026-08-05T08:00:00.000Z')
|
||||
})
|
||||
|
||||
it('contains an incompatible sidecar as a visible unavailable receipt', () => {
|
||||
render(<ReminderRow {...props({
|
||||
scheduleId: '',
|
||||
prompt: 'not trusted',
|
||||
occurrenceAt: 123,
|
||||
deliveryMode: 'external',
|
||||
})} />)
|
||||
|
||||
expect(screen.getByText('提醒回执不可用 · schedule/reminder')).toBeTruthy()
|
||||
expect(screen.queryByText('not trusted')).toBeNull()
|
||||
expect(screen.queryByText('仅在当前会话中交付')).toBeNull()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user