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

35 lines
1.0 KiB
TypeScript

/**
* Check if the Actionbook API is available.
* Used to skip network-dependent tests when API is unreachable.
* Matches the Rust integration_test.rs is_api_available() pattern.
*/
export async function isApiAvailable(): Promise<boolean> {
const apiUrl =
process.env.ACTIONBOOK_API_URL || "https://api.actionbook.dev";
try {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 3000);
const response = await fetch(`${apiUrl}/health`, {
signal: controller.signal,
});
clearTimeout(timeout);
if (response.ok) return true;
// Fallback: try search endpoint (401 means API is up but needs auth)
const controller2 = new AbortController();
const timeout2 = setTimeout(() => controller2.abort(), 5000);
const searchResponse = await fetch(
`${apiUrl}/api/actions/search?q=test&limit=1`,
{ signal: controller2.signal }
);
clearTimeout(timeout2);
return searchResponse.ok || searchResponse.status === 401;
} catch {
return false;
}
}