/**
* text-input-harness.test.tsx — Tests for the standalone TextInput test harness.
*
* The harness is an interactive tool, so tests verify:
* - The harness module exports render-ready components
* - The harness mounts and unmounts cleanly
* - Mode switching works (single/multi)
*/
import { describe, test, expect } from "bun:test";
import React from "react";
import { render, renderToString, Box, Text } from "ink";
import { TextInput } from "./text-input";
import { useTextInput } from "./use-text-input";
import { PassThrough } from "node:stream";
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
function createTestStreams() {
const stdout = new PassThrough() as unknown as NodeJS.WriteStream;
(stdout as any).columns = 80;
(stdout as any).rows = 24;
const stdin = new PassThrough() as unknown as NodeJS.ReadStream;
(stdin as any).isTTY = true;
(stdin as any).setRawMode = () => stdin;
(stdin as any).ref = () => stdin;
(stdin as any).unref = () => stdin;
return { stdin, stdout };
}
// ---------------------------------------------------------------------------
// Harness-style component for testing
// ---------------------------------------------------------------------------
function HarnessLike(): React.ReactElement {
const { value, onChange } = useTextInput({ initialValue: "test value" });
return (
TextInput Harness
current:{value}
);
}
// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------
describe("TextInput harness", () => {
test("harness-like component renders without crashing", () => {
const output = renderToString();
expect(output).toContain("TextInput Harness");
expect(output).toContain("test value");
});
test("harness mounts and unmounts cleanly", async () => {
const { stdin, stdout } = createTestStreams();
const instance = render(, {
stdout,
stdin,
debug: true,
exitOnCtrlC: false,
patchConsole: false,
});
await new Promise((r) => setTimeout(r, 50));
instance.unmount();
await instance.waitUntilExit();
});
test("harness accepts input and updates value", async () => {
const { stdin, stdout } = createTestStreams();
const chunks: string[] = [];
stdout.on("data", (chunk: Buffer) => chunks.push(chunk.toString()));
const instance = render(, {
stdout,
stdin,
debug: true,
exitOnCtrlC: false,
patchConsole: false,
});
// Type a character
(stdin as any as PassThrough).write("X");
await new Promise((r) => setTimeout(r, 100));
instance.unmount();
await instance.waitUntilExit();
const output = chunks.join("");
expect(output).toContain("current:test valueX");
});
test("TextInput with useTextInput hook integration", () => {
// Verify the hook + component integration renders correctly
function IntegrationTest(): React.ReactElement {
const single = useTextInput({ initialValue: "single" });
const multi = useTextInput({ initialValue: "line1\nline2" });
return (
);
}
const output = renderToString();
expect(output).toContain("single");
expect(output).toContain("line1");
expect(output).toContain("line2");
});
});