98 lines
2.9 KiB
TypeScript
98 lines
2.9 KiB
TypeScript
/**
|
|
* Integration tests for session listing with real tmux sessions.
|
|
*
|
|
* Requires:
|
|
* - tmux installed and running
|
|
*
|
|
* Creates real tmux sessions and verifies they appear in list-sessions output.
|
|
*/
|
|
|
|
import { execFile } from "node:child_process";
|
|
import { mkdtemp, rm, realpath } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { promisify } from "node:util";
|
|
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
import {
|
|
isTmuxAvailable,
|
|
killSessionsByPrefix,
|
|
createSession,
|
|
killSession,
|
|
capturePane,
|
|
} from "./helpers/tmux.js";
|
|
import { sleep } from "./helpers/polling.js";
|
|
|
|
const execFileAsync = promisify(execFile);
|
|
|
|
const SESSION_PREFIX = "ao-inttest-ls-";
|
|
|
|
const tmuxOk = await isTmuxAvailable();
|
|
|
|
describe.skipIf(!tmuxOk)("CLI session listing (integration)", () => {
|
|
const session1 = `${SESSION_PREFIX}1-${Date.now()}`;
|
|
const session2 = `${SESSION_PREFIX}2-${Date.now()}`;
|
|
let tmpDir: string;
|
|
|
|
beforeAll(async () => {
|
|
await killSessionsByPrefix(SESSION_PREFIX);
|
|
const raw = await mkdtemp(join(tmpdir(), "ao-inttest-ls-"));
|
|
tmpDir = await realpath(raw);
|
|
|
|
// Create two sessions
|
|
await createSession(session1, "bash", tmpDir);
|
|
await createSession(session2, "bash", tmpDir);
|
|
await sleep(500);
|
|
}, 30_000);
|
|
|
|
afterAll(async () => {
|
|
await killSession(session1);
|
|
await killSession(session2);
|
|
if (tmpDir) {
|
|
await rm(tmpDir, { recursive: true, force: true }).catch(() => {});
|
|
}
|
|
}, 30_000);
|
|
|
|
it("lists both sessions from tmux", async () => {
|
|
const { stdout } = await execFileAsync("tmux", ["list-sessions", "-F", "#{session_name}"], {
|
|
timeout: 5_000,
|
|
});
|
|
|
|
const sessions = stdout.trim().split("\n");
|
|
expect(sessions).toContain(session1);
|
|
expect(sessions).toContain(session2);
|
|
});
|
|
|
|
it("captures terminal output from specific session", async () => {
|
|
// Send a command to session1 only
|
|
const marker = `LS_TEST_${Date.now()}`;
|
|
await execFileAsync("tmux", ["send-keys", "-t", session1, "-l", `echo ${marker}`], {
|
|
timeout: 5_000,
|
|
});
|
|
await sleep(200);
|
|
await execFileAsync("tmux", ["send-keys", "-t", session1, "Enter"], { timeout: 5_000 });
|
|
await sleep(1_000);
|
|
|
|
const output1 = await capturePane(session1);
|
|
const output2 = await capturePane(session2);
|
|
|
|
// Marker should be in session1 but not session2
|
|
expect(output1).toContain(marker);
|
|
expect(output2).not.toContain(marker);
|
|
});
|
|
|
|
it("reports session activity timestamp", async () => {
|
|
const { stdout } = await execFileAsync(
|
|
"tmux",
|
|
["display-message", "-t", session1, "-p", "#{session_activity}"],
|
|
{ timeout: 5_000 },
|
|
);
|
|
|
|
const ts = parseInt(stdout.trim(), 10);
|
|
expect(isNaN(ts)).toBe(false);
|
|
// Should be within the last 5 minutes
|
|
const now = Math.floor(Date.now() / 1000);
|
|
expect(ts).toBeGreaterThan(now - 300);
|
|
expect(ts).toBeLessThanOrEqual(now + 5);
|
|
});
|
|
});
|