test(pi-tui): add regression tests for loader, cancellable-loader, input
First test coverage for pi-tui components (8 tests): - Loader: start() idempotency, dispose() cleanup, stop() safety - CancellableLoader: abort on dispose, callback cleanup, signal state - Input: paste buffer reset on focus loss, focused getter/setter
This commit is contained in:
parent
b448bf9400
commit
ea2b626c98
3 changed files with 125 additions and 0 deletions
|
|
@ -0,0 +1,45 @@
|
|||
// pi-tui CancellableLoader component regression tests
|
||||
// Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
|
||||
|
||||
import { describe, it, mock, beforeEach, afterEach } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { CancellableLoader } from "../cancellable-loader.js";
|
||||
|
||||
function makeMockTUI() {
|
||||
return { requestRender: mock.fn() } as any;
|
||||
}
|
||||
|
||||
describe("CancellableLoader", () => {
|
||||
let loader: CancellableLoader;
|
||||
let tui: ReturnType<typeof makeMockTUI>;
|
||||
|
||||
beforeEach(() => {
|
||||
tui = makeMockTUI();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
loader?.dispose();
|
||||
});
|
||||
|
||||
it("dispose() aborts the AbortController signal", () => {
|
||||
loader = new CancellableLoader(tui, (s) => s, (s) => s, "test");
|
||||
assert.equal(loader.aborted, false);
|
||||
loader.dispose();
|
||||
assert.equal(loader.aborted, true);
|
||||
});
|
||||
|
||||
it("dispose() clears the onAbort callback", () => {
|
||||
loader = new CancellableLoader(tui, (s) => s, (s) => s, "test");
|
||||
loader.onAbort = () => {};
|
||||
loader.dispose();
|
||||
assert.equal(loader.onAbort, undefined);
|
||||
});
|
||||
|
||||
it("signal is aborted after dispose()", () => {
|
||||
loader = new CancellableLoader(tui, (s) => s, (s) => s, "test");
|
||||
const signal = loader.signal;
|
||||
assert.equal(signal.aborted, false);
|
||||
loader.dispose();
|
||||
assert.equal(signal.aborted, true);
|
||||
});
|
||||
});
|
||||
35
packages/pi-tui/src/components/__tests__/input.test.ts
Normal file
35
packages/pi-tui/src/components/__tests__/input.test.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// pi-tui Input component regression tests
|
||||
// Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
|
||||
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { Input } from "../input.js";
|
||||
|
||||
describe("Input", () => {
|
||||
it("paste buffer is cleared when focus is lost", () => {
|
||||
const input = new Input();
|
||||
input.focused = true;
|
||||
|
||||
// Simulate starting a paste (bracket paste start marker)
|
||||
input.handleInput("\x1b[200~partial");
|
||||
|
||||
// Now lose focus mid-paste
|
||||
input.focused = false;
|
||||
|
||||
// Regain focus — should not have stale paste state
|
||||
input.focused = true;
|
||||
|
||||
// Typing normal text should work without paste buffer corruption
|
||||
input.handleInput("hello");
|
||||
assert.equal(input.getValue(), "hello");
|
||||
});
|
||||
|
||||
it("focused getter/setter works correctly", () => {
|
||||
const input = new Input();
|
||||
assert.equal(input.focused, false);
|
||||
input.focused = true;
|
||||
assert.equal(input.focused, true);
|
||||
input.focused = false;
|
||||
assert.equal(input.focused, false);
|
||||
});
|
||||
});
|
||||
45
packages/pi-tui/src/components/__tests__/loader.test.ts
Normal file
45
packages/pi-tui/src/components/__tests__/loader.test.ts
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
// pi-tui Loader component regression tests
|
||||
// Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
|
||||
|
||||
import { describe, it, mock, beforeEach, afterEach } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { Loader } from "../loader.js";
|
||||
|
||||
function makeMockTUI() {
|
||||
return { requestRender: mock.fn() } as any;
|
||||
}
|
||||
|
||||
describe("Loader", () => {
|
||||
let loader: Loader;
|
||||
let tui: ReturnType<typeof makeMockTUI>;
|
||||
|
||||
beforeEach(() => {
|
||||
tui = makeMockTUI();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
loader?.stop();
|
||||
});
|
||||
|
||||
it("start() is idempotent — calling twice does not leak intervals", () => {
|
||||
loader = new Loader(tui, (s) => s, (s) => s, "test");
|
||||
// Constructor calls start() once, call it again
|
||||
loader.start();
|
||||
// stop() should clear the interval cleanly without orphaned timers
|
||||
loader.stop();
|
||||
});
|
||||
|
||||
it("dispose() stops the interval and nulls the TUI reference", () => {
|
||||
loader = new Loader(tui, (s) => s, (s) => s, "test");
|
||||
loader.dispose();
|
||||
// After dispose, calling stop() again should be safe (no-op)
|
||||
loader.stop();
|
||||
});
|
||||
|
||||
it("stop() is safe to call multiple times", () => {
|
||||
loader = new Loader(tui, (s) => s, (s) => s, "test");
|
||||
loader.stop();
|
||||
loader.stop();
|
||||
loader.stop();
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue