From 53e8a8b8071cc27bb28e52e66913a9f97f32b2b8 Mon Sep 17 00:00:00 2001 From: can1357 Date: Sat, 4 Jul 2026 14:21:01 +0200 Subject: [PATCH] test(ci): fixed event-controller and auth-storage test failures - Mocked messagePersistenceKey in event-controller-error-banner.test.ts and safe-guarded it in event-controller.ts to prevent TypeError. - Updated thinking loop retry test expectations to handle new dynamic recoveredErrors structure. - Updated schema version assertions in auth-storage-email-dedupe.test.ts to v5, preserving v6 for future schema test. - Simulated scrollback commitment in event-controller-message-start.test.ts by rendering container and committing rows before advancing timers. --- packages/ai/test/auth-storage-email-dedupe.test.ts | 10 +++++----- .../src/modes/controllers/event-controller.ts | 6 ++++-- .../test/agent-session-thinking-loop-retry.test.ts | 4 +++- .../test/event-controller-error-banner.test.ts | 2 ++ .../controllers/event-controller-message-start.test.ts | 4 ++++ 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/ai/test/auth-storage-email-dedupe.test.ts b/packages/ai/test/auth-storage-email-dedupe.test.ts index b0c62af4f..b98b00c08 100644 --- a/packages/ai/test/auth-storage-email-dedupe.test.ts +++ b/packages/ai/test/auth-storage-email-dedupe.test.ts @@ -431,7 +431,7 @@ describe("AuthStorage openai-codex email dedupe", () => { const freshDbPath = path.join(tempDir, "fresh-schema-agent.db"); const freshStore = await SqliteAuthCredentialStore.open(freshDbPath); try { - expect(readAuthSchemaVersion(freshDbPath)).toBe(4); + expect(readAuthSchemaVersion(freshDbPath)).toBe(5); expect(readTableSql(freshDbPath, "auth_credentials")).not.toContain("unixepoch("); expect(readTableSql(freshDbPath, "auth_credentials")).toContain("strftime('%s','now')"); } finally { @@ -449,7 +449,7 @@ describe("AuthStorage openai-codex email dedupe", () => { id INTEGER PRIMARY KEY CHECK (id = 1), version INTEGER NOT NULL ); - INSERT INTO auth_schema_version(id, version) VALUES (1, 5); + INSERT INTO auth_schema_version(id, version) VALUES (1, 6); CREATE TABLE auth_credentials ( id INTEGER PRIMARY KEY AUTOINCREMENT, provider TEXT NOT NULL, @@ -465,7 +465,7 @@ describe("AuthStorage openai-codex email dedupe", () => { const reopenedStore = await SqliteAuthCredentialStore.open(futureDbPath); try { - expect(readAuthSchemaVersion(futureDbPath)).toBe(5); + expect(readAuthSchemaVersion(futureDbPath)).toBe(6); } finally { reopenedStore.close(); } @@ -491,7 +491,7 @@ describe("AuthStorage openai-codex email dedupe", () => { const reopened = await SqliteAuthCredentialStore.open(reopenDbPath); try { expect(reopened.listAuthCredentials("openai")).toHaveLength(1); - expect(readAuthSchemaVersion(reopenDbPath)).toBe(4); + expect(readAuthSchemaVersion(reopenDbPath)).toBe(5); } finally { reopened.close(); } @@ -547,7 +547,7 @@ describe("AuthStorage openai-codex email dedupe", () => { const migratedStore = await SqliteAuthCredentialStore.open(legacyDbPath); try { - expect(readAuthSchemaVersion(legacyDbPath)).toBe(4); + expect(readAuthSchemaVersion(legacyDbPath)).toBe(5); expect(readTableSql(legacyDbPath, "auth_credentials")).not.toContain("unixepoch("); expect(readTableSql(legacyDbPath, "auth_credentials")).toContain("strftime('%s','now')"); expect(readStoredIdentityRows(legacyDbPath, "openai-codex")).toEqual([ diff --git a/packages/coding-agent/src/modes/controllers/event-controller.ts b/packages/coding-agent/src/modes/controllers/event-controller.ts index 94f0da561..45efed0be 100644 --- a/packages/coding-agent/src/modes/controllers/event-controller.ts +++ b/packages/coding-agent/src/modes/controllers/event-controller.ts @@ -329,7 +329,8 @@ export class EventController { #trackRetrySupersededAssistantComponent(component: AssistantMessageComponent | undefined): void { if (!component) return; - const persistenceKey = component.messagePersistenceKey(); + const persistenceKey = + typeof component.messagePersistenceKey === "function" ? component.messagePersistenceKey() : undefined; if (persistenceKey) this.#retrySupersededAssistantComponents.set(persistenceKey, component); if (!this.#retrySupersededAssistantQueue.includes(component)) { this.#retrySupersededAssistantQueue.push(component); @@ -350,7 +351,8 @@ export class EventController { while (this.#retrySupersededAssistantQueue.length > 0) { const component = this.#retrySupersededAssistantQueue.shift(); if (!component) continue; - const key = component.messagePersistenceKey(); + const key = + typeof component.messagePersistenceKey === "function" ? component.messagePersistenceKey() : undefined; if (key && this.#retrySupersededAssistantComponents.get(key) !== component) continue; if (key) this.#retrySupersededAssistantComponents.delete(key); return component; diff --git a/packages/coding-agent/test/agent-session-thinking-loop-retry.test.ts b/packages/coding-agent/test/agent-session-thinking-loop-retry.test.ts index 9e6fe705e..8f5025eef 100644 --- a/packages/coding-agent/test/agent-session-thinking-loop-retry.test.ts +++ b/packages/coding-agent/test/agent-session-thinking-loop-retry.test.ts @@ -181,7 +181,9 @@ describe("AgentSession thinking-loop retry", () => { expect(calls).toEqual(["openrouter/google/gemini-3.5-flash", "openrouter/google/gemini-3.5-flash"]); expect(retryStartEvents).toHaveLength(1); expect(AIError.is(retryStartEvents[0].errorId, AIError.Flag.ThinkingLoop)).toBe(true); - expect(retryEndEvents).toEqual([{ type: "auto_retry_end", success: true, attempt: 1 }]); + expect(retryEndEvents).toHaveLength(1); + expect(retryEndEvents[0]).toMatchObject({ type: "auto_retry_end", success: true, attempt: 1 }); + expect(retryEndEvents[0].recoveredErrors).toBeArray(); const assistants = session.agent.state.messages.filter( (message): message is AssistantMessage => message.role === "assistant", ); diff --git a/packages/coding-agent/test/event-controller-error-banner.test.ts b/packages/coding-agent/test/event-controller-error-banner.test.ts index eb982eaa4..a705f3342 100644 --- a/packages/coding-agent/test/event-controller-error-banner.test.ts +++ b/packages/coding-agent/test/event-controller-error-banner.test.ts @@ -60,6 +60,8 @@ function createFixture(streamingMessage?: AssistantMessage) { markTranscriptBlockFinalized: vi.fn(), setErrorPinned: vi.fn(), setHideThinkingBlock: vi.fn((hide: boolean) => componentCalls.push(`hide:${hide}`)), + messagePersistenceKey: vi.fn(() => "test-persistence-key"), + applyRetryRecovery: vi.fn(), }; const showPinnedError = vi.fn(); const clearPinnedError = vi.fn(); diff --git a/packages/coding-agent/test/modes/controllers/event-controller-message-start.test.ts b/packages/coding-agent/test/modes/controllers/event-controller-message-start.test.ts index 641177870..57bc880fe 100644 --- a/packages/coding-agent/test/modes/controllers/event-controller-message-start.test.ts +++ b/packages/coding-agent/test/modes/controllers/event-controller-message-start.test.ts @@ -245,6 +245,10 @@ describe("EventController IRC expiry", () => { await controller.handleEvent({ type: "irc_message", message }); expect(chatContainer.children).toHaveLength(1); + // Render the container and commit its rows to simulate entering native scrollback + const lines = chatContainer.render(80); + chatContainer.setNativeScrollbackCommittedRows(lines.length); + // Everything above the card is finalized, so its rows may already be in // native scrollback. Removing it would be an interior deletion of the // committed prefix — the engine repairs that by recommitting everything