From 61e382444a69409b066a6c8382379f86492d579f Mon Sep 17 00:00:00 2001 From: Jacob Richman Date: Thu, 31 Jul 2025 16:16:29 -0700 Subject: fix(ux) bug in replaceRange dealing with newLines that was breaking vim support (#5320) --- packages/cli/src/test-utils/customMatchers.ts | 63 +++++++++++++++++++++++ packages/cli/src/test-utils/mockCommandContext.ts | 2 + 2 files changed, 65 insertions(+) create mode 100644 packages/cli/src/test-utils/customMatchers.ts (limited to 'packages/cli/src/test-utils') diff --git a/packages/cli/src/test-utils/customMatchers.ts b/packages/cli/src/test-utils/customMatchers.ts new file mode 100644 index 00000000..c0b4df6b --- /dev/null +++ b/packages/cli/src/test-utils/customMatchers.ts @@ -0,0 +1,63 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/// + +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { expect } from 'vitest'; +import type { TextBuffer } from '../ui/components/shared/text-buffer.js'; + +// RegExp to detect invalid characters: backspace, and ANSI escape codes +// eslint-disable-next-line no-control-regex +const invalidCharsRegex = /[\b\x1b]/; + +function toHaveOnlyValidCharacters(this: vi.Assertion, buffer: TextBuffer) { + const { isNot } = this; + let pass = true; + const invalidLines: Array<{ line: number; content: string }> = []; + + for (let i = 0; i < buffer.lines.length; i++) { + const line = buffer.lines[i]; + if (line.includes('\n')) { + pass = false; + invalidLines.push({ line: i, content: line }); + break; // Fail fast on newlines + } + if (invalidCharsRegex.test(line)) { + pass = false; + invalidLines.push({ line: i, content: line }); + } + } + + return { + pass, + message: () => + `Expected buffer ${isNot ? 'not ' : ''}to have only valid characters, but found invalid characters in lines:\n${invalidLines + .map((l) => ` [${l.line}]: "${l.content}"`) /* This line was changed */ + .join('\n')}`, + actual: buffer.lines, + expected: 'Lines with no line breaks, backspaces, or escape codes.', + }; +} + +expect.extend({ + toHaveOnlyValidCharacters, +}); + +// Extend Vitest's `expect` interface with the custom matcher's type definition. +declare module 'vitest' { + interface Assertion { + toHaveOnlyValidCharacters(): T; + } + interface AsymmetricMatchersContaining { + toHaveOnlyValidCharacters(): void; + } +} diff --git a/packages/cli/src/test-utils/mockCommandContext.ts b/packages/cli/src/test-utils/mockCommandContext.ts index cf450484..4137dbff 100644 --- a/packages/cli/src/test-utils/mockCommandContext.ts +++ b/packages/cli/src/test-utils/mockCommandContext.ts @@ -53,8 +53,10 @@ export const createMockCommandContext = ( setPendingItem: vi.fn(), loadHistory: vi.fn(), toggleCorgiMode: vi.fn(), + toggleVimEnabled: vi.fn(), }, session: { + sessionShellAllowlist: new Set(), stats: { sessionStartTime: new Date(), lastPromptTokenCount: 0, -- cgit v1.2.3