diff --git a/packages/api/gateway/tests/journal-stream.client.spec.ts b/packages/api/gateway/tests/journal-stream.client.spec.ts index 3c50506acc..17d02cf8c5 100644 --- a/packages/api/gateway/tests/journal-stream.client.spec.ts +++ b/packages/api/gateway/tests/journal-stream.client.spec.ts @@ -261,7 +261,7 @@ describe('RemoteJournalStream', () => { ], [ signal => new Promise((_resolve, reject) => { - const aborted = (): void => { reject(signal.reason) } + const aborted = (): void => { reject(new Error('page aborted')) } signal.addEventListener('abort', aborted, { once: true }) if (signal.aborted) aborted() }), diff --git a/packages/api/session-controller/tests/session-projections.host.spec.ts b/packages/api/session-controller/tests/session-projections.host.spec.ts index 71c2516b1f..dfd55d6a52 100644 --- a/packages/api/session-controller/tests/session-projections.host.spec.ts +++ b/packages/api/session-controller/tests/session-projections.host.spec.ts @@ -120,10 +120,10 @@ describe('session.history projections block', () => { if (!response.ok) throw new Error('history failed') expect(response.value.events.map(entry => entry.event.seq)).toEqual([0]) - expect(response.value.projections).toEqual({ - asOfSeq: 0, - values: expect.objectContaining({ 'test/last-user': { text: 'm0' } }), - }) + expect(response.value.projections?.asOfSeq).toBe(0) + expect(response.value.projections?.values).toEqual( + expect.objectContaining({ 'test/last-user': { text: 'm0' } }), + ) }) it('projects an empty log at cursor -1', async () => { @@ -134,10 +134,10 @@ describe('session.history projections block', () => { if (!response.ok) throw new Error('history failed') expect(response.value.events).toEqual([]) - expect(response.value.projections).toEqual({ - asOfSeq: -1, - values: expect.objectContaining({ 'test/last-user': null }), - }) + expect(response.value.projections?.asOfSeq).toBe(-1) + expect(response.value.projections?.values).toEqual( + expect.objectContaining({ 'test/last-user': null }), + ) }) it('publishes the attachments imageLimits as a constant unit while both seams are composed', async () => { diff --git a/packages/client/connection/src/client/index.ts b/packages/client/connection/src/client/index.ts index 0a459b17c3..9c386a8752 100644 --- a/packages/client/connection/src/client/index.ts +++ b/packages/client/connection/src/client/index.ts @@ -205,22 +205,23 @@ export function apply(ctx: Context): void { const source = generationSource if (source === undefined) throw new Error('connection: no generation source is registered') const token = {} + const ownsGeneration = (): boolean => owner?.token === token const controller = new ConnectionController(api, source, { ...sinks, onConnected: (next) => { - if (owner?.token !== token) return + if (!ownsGeneration()) return publishDescription(next) // A description subscriber may synchronously stop the loop. In that // case publishDescription(undefined) has already retracted this // generation, so do not leak its stale connected notification to // the consumer sink afterward. - if (owner?.token !== token || !Object.is(description, next)) return + if (!ownsGeneration() || !Object.is(description, next)) return sinks.onConnected?.(next) }, onStateChange: (state) => { - if (owner?.token !== token) return + if (!ownsGeneration()) return if (state === 'reconnecting') publishDescription(undefined) - if (owner?.token !== token) return + if (!ownsGeneration()) return sinks.onStateChange?.(state) }, }, config ?? {}) diff --git a/packages/client/runtime/tests/session.client.spec.ts b/packages/client/runtime/tests/session.client.spec.ts index 0ffd526ffa..13a29270c9 100644 --- a/packages/client/runtime/tests/session.client.spec.ts +++ b/packages/client/runtime/tests/session.client.spec.ts @@ -816,9 +816,9 @@ describe('remaining branches', () => { expect(session.getSnapshot().promptError).toBeNull() }) - it('dispose is a reserved no-op on resident instances', () => { + it('dispose is a reserved no-op on resident instances', async () => { const { session } = makeSession() - expect(() => { session.dispose() }).not.toThrow() + await expect(session.dispose()).resolves.toBeUndefined() }) it('carries history-entry and follow-frame views into the business-neutral Event input', async () => { diff --git a/packages/client/ui-conversation/tests/chat-view.client.spec.tsx b/packages/client/ui-conversation/tests/chat-view.client.spec.tsx index 6923f32ec1..f7e05f61f6 100644 --- a/packages/client/ui-conversation/tests/chat-view.client.spec.tsx +++ b/packages/client/ui-conversation/tests/chat-view.client.spec.tsx @@ -1342,7 +1342,7 @@ describe('ChatView', () => { const h = makeHarness({ pending: [ new PendingWait('approval', 'r1', SID, - { approvalId: 'ap1', toolName: 'bash' } as PendingWait<'approval'>['payload'], vi.fn()), + { approvalId: 'ap1', toolName: 'bash' }, vi.fn()), new PendingWait('question', 'r2', SID, { questions: [{ id: 'q1', question: '选择' }] }, vi.fn()), ], diff --git a/packages/interaction/user-questions/tests/user-questions.spec.ts b/packages/interaction/user-questions/tests/user-questions.spec.ts index 596aeb06ee..98b0c49375 100644 --- a/packages/interaction/user-questions/tests/user-questions.spec.ts +++ b/packages/interaction/user-questions/tests/user-questions.spec.ts @@ -88,18 +88,19 @@ describe('UserQuestionService', () => { const pending = Promise.withResolvers() ctx.userQuestions.registerProvider({ ask: () => pending.promise }) const controller = new AbortController() + const abortReason = new DOMException('This operation was aborted', 'AbortError') const answer = ctx.userQuestions.ask({ questions: [{ id: 'confirm', question: 'Proceed?' }], signal: controller.signal, }) - controller.abort() - pending.reject(controller.signal.reason) + controller.abort(abortReason) + pending.reject(abortReason) await expect(answer).rejects.toMatchObject({ name: 'UserQuestionError', code: 'ASK_ABORTED', - cause: controller.signal.reason, + cause: abortReason, }) })