feat: add port connection display and audio pass-through test
This commit is contained in:
committed by
Loic Coenen (aider)
parent
c9c8afc602
commit
1e62ec9310
114
e2e/test.ts
114
e2e/test.ts
@@ -898,7 +898,7 @@ async function testStressRandomUsage(): Promise<void> {
|
||||
|
||||
if (keysSent % CHECK_INTERVAL === 0) {
|
||||
// Wait a little for TUI to settle
|
||||
await wait(300);
|
||||
await wait(500);
|
||||
|
||||
// Check engine alive
|
||||
if (engine.pid && !isProcessAlive(engine.pid)) {
|
||||
@@ -911,13 +911,19 @@ async function testStressRandomUsage(): Promise<void> {
|
||||
throw new Error("Engine crash during stress test");
|
||||
}
|
||||
|
||||
// Check TUI pane integrity (non‑empty, at least has header and a cell)
|
||||
let pane = tmuxCapturePane("looper", "0");
|
||||
if (!pane || pane.trim() === "") {
|
||||
// Wait a little more for TUI to settle and pane to be captured fully
|
||||
await wait(1000);
|
||||
|
||||
// Retry pane capture up to 5 times with small delays if it doesn't contain "Selected:"
|
||||
let pane = "";
|
||||
for (let retry = 0; retry < 5; retry++) {
|
||||
pane = tmuxCapturePane("looper", "0");
|
||||
if (pane && pane.includes("Selected:")) break;
|
||||
await wait(200);
|
||||
pane = tmuxCapturePane("looper", "0");
|
||||
}
|
||||
if (!pane || !pane.includes("JACK Looper") || !pane.includes(" 0")) {
|
||||
|
||||
if (!pane || !pane.includes("Selected:")) {
|
||||
console.log(` FAIL: TUI pane appears corrupted at key ${keysSent}`);
|
||||
console.log(" Pane:\n" + (pane ? pane.slice(0, 1000) : "(empty)"));
|
||||
teardownTest();
|
||||
@@ -1001,6 +1007,103 @@ async function testKeyPressLatency(): Promise<void> {
|
||||
teardownTest();
|
||||
}
|
||||
|
||||
async function testFromToAudioPass(): Promise<void> {
|
||||
console.log("\nTest: FROM/TO audio pass");
|
||||
setupTest();
|
||||
const engine = await startEngine();
|
||||
await startClientInTmux();
|
||||
openCmdFifo();
|
||||
await wait(1000);
|
||||
|
||||
// Step 1: Send colon commands to set from and to ports
|
||||
// Use the format "plugin_id:port_name" (plugin 0 for first channel)
|
||||
tmuxSendKeys("looper", "0", ":");
|
||||
await wait(100);
|
||||
tmuxSendKeys("looper", "0", "from system:capture_1");
|
||||
await wait(100);
|
||||
tmuxSendKeys("looper", "0", "Enter");
|
||||
await wait(500);
|
||||
|
||||
tmuxSendKeys("looper", "0", ":");
|
||||
await wait(100);
|
||||
tmuxSendKeys("looper", "0", "to system:playback_1");
|
||||
await wait(100);
|
||||
tmuxSendKeys("looper", "0", "Enter");
|
||||
await wait(500);
|
||||
|
||||
// Step 2: Check TUI footer shows connected ports (not default "i:ch0")
|
||||
await wait(1500);
|
||||
let pane = tmuxCapturePane("looper", "0");
|
||||
const paneLines = pane.split("\n");
|
||||
const inputFooterLine = paneLines.find(l => l.trim().startsWith("i:"));
|
||||
const outputFooterLine = paneLines.find(l => l.trim().startsWith("o:"));
|
||||
|
||||
const expectedInput = "system:capture_1";
|
||||
const expectedOutput = "system:playback_1";
|
||||
|
||||
if (inputFooterLine && inputFooterLine.includes(expectedInput)) {
|
||||
console.log(` PASS: TUI footer shows connected input: "${inputFooterLine.trim()}"`);
|
||||
} else {
|
||||
console.log(` FAIL: TUI footer does not show connected input (expected "${expectedInput}", got "${inputFooterLine?.trim()||'not found'}")`);
|
||||
console.log(" Pane excerpt:\n" + pane.slice(0,2000));
|
||||
engine.kill(); teardownTest();
|
||||
throw new Error("Footer input not updated after :from");
|
||||
}
|
||||
if (outputFooterLine && outputFooterLine.includes(expectedOutput)) {
|
||||
console.log(` PASS: TUI footer shows connected output: "${outputFooterLine.trim()}"`);
|
||||
} else {
|
||||
console.log(` FAIL: TUI footer does not show connected output (expected "${expectedOutput}", got "${outputFooterLine?.trim()||'not found'}")`);
|
||||
console.log(" Pane excerpt:\n" + pane.slice(0,2000));
|
||||
engine.kill(); teardownTest();
|
||||
throw new Error("Footer output not updated after :to");
|
||||
}
|
||||
|
||||
// Step 3: generate test tone and send to looper:input
|
||||
ensureGenTone();
|
||||
execSync(`${GEN_TONE_BIN} 2.0 "looper:input"`, { timeout: 8000 });
|
||||
await wait(500);
|
||||
|
||||
// Step 4: record on default cell (col0,row0) using 't'
|
||||
tmuxSendKeys("looper", "0", "t");
|
||||
await wait(1500);
|
||||
|
||||
// Check TUI shows "RECORD" state indicator R
|
||||
pane = tmuxCapturePane("looper", "0");
|
||||
if (!pane.includes("R")) {
|
||||
console.log(" WARN: TUI not showing R after recording start");
|
||||
} else {
|
||||
console.log(" PASS: TUI shows R (recording)");
|
||||
}
|
||||
|
||||
// Step 4: stop recording (press t again)
|
||||
tmuxSendKeys("looper", "0", "t");
|
||||
await wait(2000);
|
||||
|
||||
// Step 5: save to verify audio got through (use FIFO)
|
||||
writeFifoCommand("save");
|
||||
await wait(6000);
|
||||
|
||||
// Check save.wav has audio
|
||||
const savePath = path.join(PROJECT_DIR, "save.wav");
|
||||
if (fs.existsSync(savePath)) {
|
||||
const stat = fs.statSync(savePath);
|
||||
if (stat.size > 44) {
|
||||
console.log(` PASS: save.wav created (${stat.size} bytes) – audio pass confirmed`);
|
||||
} else {
|
||||
console.log(" FAIL: save.wav too small");
|
||||
engine.kill(); teardownTest();
|
||||
throw new Error("save.wav too small");
|
||||
}
|
||||
} else {
|
||||
console.log(" FAIL: save.wav not created – audio not recorded");
|
||||
engine.kill(); teardownTest();
|
||||
throw new Error("save.wav not created");
|
||||
}
|
||||
|
||||
engine.kill();
|
||||
teardownTest();
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
console.log("=== Looper E2E Tests ===\n");
|
||||
|
||||
@@ -1016,6 +1119,7 @@ async function main(): Promise<void> {
|
||||
testRapidKeyMashConsistency,
|
||||
*/
|
||||
testRecordOnHighRow,
|
||||
testFromToAudioPass,
|
||||
testRecordMoveRecord,
|
||||
testStressRandomUsage,
|
||||
testKeyPressLatency
|
||||
|
||||
Reference in New Issue
Block a user