Files
jackwener__opencli/tests/e2e/public-commands.test.ts
AlexYue 788b069c02 feat: add E2E testing infrastructure with real Chrome in CI
## Changes

### E2E Test Suite (~52 test cases)
- public-commands.test.ts — Public API commands (hackernews, v2ex)
- browser-public.test.ts — Browser commands for public data across all sites
- browser-auth.test.ts — Graceful failure verification for login-required commands
- management.test.ts — Full coverage of management commands
- output-formats.test.ts — Output format validation (json/yaml/csv/md)
- smoke/api-health.test.ts — Scheduled API health checks

### Auto-detect Browser Mode
- buildMcpArgs uses CI env var to select mode:
  - Local (no CI) → --extension (connect to user's Chrome)
  - CI → standalone (launches its own browser)

### CI Pipeline
- e2e-headed.yml — Real Chrome via setup-chrome + xvfb in headed mode
- ci.yml — build + unit-test (2 shards) + smoke-test (scheduled/manual)
- Composite action for shared Chrome + xvfb setup

### Documentation
- New TESTING.md — Architecture, coverage, local setup, how to add tests

Co-authored-by: AlexYue <yj976240184@qq.com>
2026-03-16 17:35:16 +08:00

57 lines
2.1 KiB
TypeScript

/**
* E2E tests for public API commands (browser: false).
* These commands use Node.js fetch directly — no browser needed.
*/
import { describe, it, expect } from 'vitest';
import { runCli, parseJsonOutput } from './helpers.js';
describe('public commands E2E', () => {
// ── hackernews ──
it('hackernews top returns structured data', async () => {
const { stdout, code } = await runCli(['hackernews', 'top', '--limit', '3', '-f', 'json']);
expect(code).toBe(0);
const data = parseJsonOutput(stdout);
expect(Array.isArray(data)).toBe(true);
expect(data.length).toBe(3);
expect(data[0]).toHaveProperty('title');
expect(data[0]).toHaveProperty('score');
expect(data[0]).toHaveProperty('rank');
}, 30_000);
it('hackernews top respects --limit', async () => {
const { stdout, code } = await runCli(['hackernews', 'top', '--limit', '1', '-f', 'json']);
expect(code).toBe(0);
const data = parseJsonOutput(stdout);
expect(data.length).toBe(1);
}, 30_000);
// ── v2ex (public API, browser: false) ──
it('v2ex hot returns topics', async () => {
const { stdout, code } = await runCli(['v2ex', 'hot', '--limit', '3', '-f', 'json']);
expect(code).toBe(0);
const data = parseJsonOutput(stdout);
expect(Array.isArray(data)).toBe(true);
expect(data.length).toBeGreaterThanOrEqual(1);
expect(data[0]).toHaveProperty('title');
}, 30_000);
it('v2ex latest returns topics', async () => {
const { stdout, code } = await runCli(['v2ex', 'latest', '--limit', '3', '-f', 'json']);
expect(code).toBe(0);
const data = parseJsonOutput(stdout);
expect(Array.isArray(data)).toBe(true);
expect(data.length).toBeGreaterThanOrEqual(1);
}, 30_000);
it('v2ex topic returns topic detail', async () => {
// Topic 1000001 is a well-known V2EX topic
const { stdout, code } = await runCli(['v2ex', 'topic', '--id', '1000001', '-f', 'json']);
// May fail if V2EX rate-limits, but should return structured data
if (code === 0) {
const data = parseJsonOutput(stdout);
expect(data).toBeDefined();
}
}, 30_000);
});