Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions src/tui/list-modal.test.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
import { describe, expect, test } from "bun:test";
import { afterEach, describe, expect, test } from "bun:test";

import { createHarness } from "./harness.js";
import { createHarness, type Harness } from "./harness.js";
import { runListModal } from "./list-modal.js";

let harness: Harness | undefined;

afterEach(() => {
harness?.destroy();
harness = undefined;
});

async function mountModal(): Promise<{
choice: Promise<string | null>;
harness: Awaited<ReturnType<typeof createHarness>>;
harness: Harness;
}> {
const harness = await createHarness({ width: 80, height: 24 });
harness = await createHarness({ width: 80, height: 24 });
const choice = runListModal({
title: "resume session",
options: [
{ id: "s-1", label: "First session" },
{ id: "s-2", label: "Second session" },
],
createRenderer: async () => harness.renderer,
createRenderer: async () => harness!.renderer,
});
await harness.renderOnce();
return { choice, harness };
Expand Down
8 changes: 6 additions & 2 deletions src/tui/mouse-reporting-disabled.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* `createCliRenderer` branch runs, and assert on the options it was
* actually called with.
*/
import { afterAll, describe, expect, mock, test } from "bun:test";
import { afterAll, afterEach, describe, expect, mock, test } from "bun:test";
import type { Harness } from "./harness.js";

interface CapturedRendererOptions {
Expand Down Expand Up @@ -49,6 +49,11 @@ afterAll(() => {
mock.module("@opentui/core", () => realCore);
});

afterEach(() => {
let harness: Harness | undefined;
while ((harness = mountedHarnesses.pop()) !== undefined) harness.destroy();
});

const { runListModal } = await import("./list-modal.js");
const { runProviderSetup } = await import("./provider-setup.js");

Expand All @@ -71,7 +76,6 @@ describe("default renderer mount disables DEC mouse reporting (CL-5540)", () =>
expect(capturedOptions).toHaveLength(1);
expect(capturedOptions[0]?.useMouse).toBe(false);
expect(capturedOptions[0]?.enableMouseMovement).toBe(false);
mountedHarnesses.pop()?.destroy();
});

test("runProviderSetup", async () => {
Expand Down
15 changes: 11 additions & 4 deletions src/tui/provider-connect.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { describe, test, expect } from "bun:test";
import { afterEach, describe, test, expect } from "bun:test";
import { mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";

import { createHarness } from "./harness.js";
import { createHarness, type Harness } from "./harness.js";
import { connectProviderInline } from "./provider-connect.js";
import { loadSettings } from "../config/settings.js";

Expand All @@ -12,17 +12,24 @@ import { loadSettings } from "../config/settings.js";
// pins that an empty key on a key-required preset is rejected here too,
// rather than silently downgraded to a keyless credential.
describe("connectProviderInline", () => {
let harness: Harness | undefined;

afterEach(() => {
harness?.destroy();
harness = undefined;
});

test("rejects an empty key on a key-required preset without persisting", async () => {
const dir = await mkdtemp(join(tmpdir(), "provider-connect-"));
const settingsPath = join(dir, "settings.json");
try {
const harness = await createHarness({ width: 80, height: 30 });
harness = await createHarness({ width: 80, height: 30 });
const resultPromise = connectProviderInline({
providerId: "openai",
settingsPath,
localSettingsPath: join(dir, "local.json"),
existing: null,
createRenderer: async () => harness.renderer,
createRenderer: async () => harness!.renderer,
});
await harness.renderOnce();

Expand Down
48 changes: 29 additions & 19 deletions src/tui/provider-setup.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, expect, test } from "bun:test";
import { afterEach, describe, expect, test } from "bun:test";

import { createHarness, type Harness } from "./harness.js";
import { createHarness as createRawHarness, type Harness } from "./harness.js";
import {
addProviderSelectorChoices,
connectedAccountCount,
Expand Down Expand Up @@ -41,6 +41,20 @@ const EMPTY: ProviderFormValues = {
oauthProfile: "",
};

// This file mounts a fresh renderer per test; track every one so a single
// afterEach can free them regardless of which assertion in a test fails.
const activeHarnesses: Harness[] = [];

async function createHarness(opts: { width: number; height: number }): Promise<Harness> {
const harness = await createRawHarness(opts);
activeHarnesses.push(harness);
return harness;
}

afterEach(() => {
while (activeHarnesses.length > 0) activeHarnesses.pop()!.destroy();
});

describe("provider setup pure helpers", () => {
test("only the API key may be left blank", () => {
expect(stepReady("name", "")).toBe(false);
Expand Down Expand Up @@ -1047,23 +1061,19 @@ describe("runProviderSetup paste", () => {
const { done, harness } = await mountSetup(async (values) => {
seen = values;
});
try {
await pickRow(harness, PROVIDER_IDS, "openai");
await flush(harness);
harness.pressKey("Enter");
await harness.renderOnce();
await harness.mockInput.pasteBracketedText(key);
await harness.renderOnce();
const frame = harness.captureCharFrame();
harness.pressKey("Enter");
await harness.renderOnce();
harness.pressKey("Enter");
await harness.renderOnce();
await done;
return { values: seen, frame };
} finally {
harness.destroy();
}
await pickRow(harness, PROVIDER_IDS, "openai");
await flush(harness);
harness.pressKey("Enter");
await harness.renderOnce();
await harness.mockInput.pasteBracketedText(key);
await harness.renderOnce();
const frame = harness.captureCharFrame();
harness.pressKey("Enter");
await harness.renderOnce();
harness.pressKey("Enter");
await harness.renderOnce();
await done;
return { values: seen, frame };
}

test("a pasted key lands in the field, never echoed in the clear", async () => {
Expand Down
Loading