Files
s1mba 731cc340d8 [packages/cli] Add comprehensive CLI test suite (#128)
* [packages/cli]test: add comprehensive CLI test suite with E2E browser tests

- Add unit tests for wrapper (actionbook.js), postinstall, config, profile,
  search, get, and sources commands
- Add Tier 1 browser tests (arg validation, help output, defaults)
- Add Tier 2 browser E2E tests (navigation, interaction, screenshots,
  cookies, tabs, error handling, JSON output)
- Fix E2E test reliability: add --wait for element readiness after navigation,
  use eval-based form submit for login flow, match actual CLI exit codes
- Suppress macOS Keychain dialogs in tests via --use-mock-keychain config
- Set testTimeout to 60s for browser E2E operations
- Export modules from actionbook.js and postinstall.js for testability

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* [packages/cli]fix: resolve Windows .exe suffix when locating test CLI binary

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* [packages/cli]fix: skip shell-script mock tests on Windows

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 14:36:15 +08:00

72 lines
2.3 KiB
TypeScript

import { describe, it, expect } from "vitest";
import path from "path";
import { readFileSync } from "fs";
import { runWrapper } from "./helpers/binary.js";
const pkgJsonPath = path.resolve(__dirname, "..", "package.json");
const pkg = JSON.parse(readFileSync(pkgJsonPath, "utf8"));
describe("Node.js wrapper integration", () => {
describe("version flag", () => {
it("--version outputs package.json version", async () => {
const result = await runWrapper(["--version"]);
expect(result.exitCode).toBe(0);
expect(result.stdout.trim()).toBe(`actionbook ${pkg.version}`);
});
it("-V outputs package.json version", async () => {
const result = await runWrapper(["-V"]);
expect(result.exitCode).toBe(0);
expect(result.stdout.trim()).toBe(`actionbook ${pkg.version}`);
});
});
describe.skipIf(process.platform === "win32")("ACTIONBOOK_BINARY_PATH", () => {
it("forwards arguments to mock binary", async () => {
const mockBinary = path.resolve(
__dirname,
"fixtures",
"mock-binary.sh"
);
const result = await runWrapper(["arg1", "arg2", "--flag"], {
env: { ACTIONBOOK_BINARY_PATH: mockBinary },
});
expect(result.exitCode).toBe(0);
expect(result.stdout).toContain("MOCK_ARGS:arg1 arg2 --flag");
});
it("propagates exit code from binary", async () => {
const mockBinary = path.resolve(
__dirname,
"fixtures",
"mock-binary-fail.sh"
);
const result = await runWrapper([], {
env: { ACTIONBOOK_BINARY_PATH: mockBinary },
});
expect(result.exitCode).toBe(42);
});
it("shows error when binary path is invalid", async () => {
const result = await runWrapper([], {
env: { ACTIONBOOK_BINARY_PATH: "/nonexistent/path/to/binary" },
});
expect(result.exitCode).toBe(1);
expect(result.stderr).toContain("Error executing binary");
});
it("captures stderr from failing binary", async () => {
const mockBinary = path.resolve(
__dirname,
"fixtures",
"mock-binary-error.sh"
);
const result = await runWrapper(["some", "args"], {
env: { ACTIONBOOK_BINARY_PATH: mockBinary },
});
expect(result.exitCode).toBe(1);
expect(result.stderr).toContain("Something went wrong");
});
});
});