Skip to content

Latest commit

 

History

History
65 lines (45 loc) · 3.76 KB

testing.md

File metadata and controls

65 lines (45 loc) · 3.76 KB

Testing

Free Provider ships a node:test suite covering the server, both providers, and the underlying clients — plus a coverage gate that fails if any tracked file drops below 85% line coverage.


Running the tests

npm test             # run all suites (test/*.test.mjs)
npm run test:coverage    # run the suite with per-file coverage reporting
npm run coverage:check   # run the suite and enforce the coverage gate

coverage:check runs everything through scripts/check-coverage.mjs, which fails on:

  • any test failure, or
  • any tracked source file with line coverage below 85%.

On Node 20.12+ no extra dependencies are needed (native node:test, fetch, and V8 coverage); the --experimental-test-coverage / --test flags come from the runtime itself.

Important: the test glob is "test/*.test.mjs" — running node --test test/ (the bare directory) fails on Node 24.


What's covered

Suite Focus
test/server-index.test.mjs Express app wiring, auth mount, startup banner, startServer on an ephemeral port
test/server-routes.test.mjs /v1/models, /v1/chat/completions (stream + non-stream), auto-model alternation, cooldown 429, /v1/health, /v1/pool
test/server-providers.test.mjs Router: isAutoModel, nextAutoSlot pairing/sequence, explicit-model routing; pinned agentIndex for both providers
test/server-auth.test.mjs Bearer-token auth middleware (valid/missing/invalid keys)
test/server-config.test.mjs server/config.mjs parsing: env overrides, .env loading, proxy list, model list
test/gemini-client.test.mjs Gemini guest client: init token grabbing, StreamGenerate frames, delta aggregation (prefix/tail/full-LCS), error codes (e.g. 1037 usage limit, 1060 IP block), flagged/plain stream failures
test/cloudflare.test.mjs CFBypass transport: retries, backoff, cookie jar, extractCookies, pacing/throttle, proxy rotation + bench, and socks4/socks5/dispatcher handling
test/chatgpt.test.mjs, test/chatgpt-auth.test.mjs Anonymous + authenticated ChatGPT client chat/auth flows and their edge cases
test/client-index.test.mjs The ChatGPT client class the server uses (ask/streamAsk, init/token caching, upload paths)
test/upload.test.mjs, test/sentinel.test.mjs, test/pow.test.mjs, test/turnstile.test.mjs, test/sse.test.mjs, test/tempmail.test.mjs Shared client internals: Azure upload builder, sentinel token, FNV-1a POW, Turnstile VM, SSE parser, temp-mail helper

Auto-balancing behavior in tests

Auto-mode scheduling is deterministic and easy to assert:

const { isAutoModel, nextAutoSlot, resetAutoScheduler } = await import("../server/providers/router.mjs");

resetAutoScheduler();
nextAutoSlot(); // → { provider: "chatgpt", agentIndex: 0 }
nextAutoSlot(); // → { provider: "gemini",  agentIndex: 0 }
nextAutoSlot(); // → { provider: "chatgpt", agentIndex: 1 }
nextAutoSlot(); // → { provider: "gemini",  agentIndex: 1 }
// … wraps after AGENT_COUNT pairs

isAutoModel("auto") → true, isAutoModel("gpt-4o") → false. Route-level tests assert the same sequence comes out of /v1/chat/completions by injecting stub providers.


Coverage gotchas

  • Don't dynamic-re-import a module with a cache-busting query (e.g. await import("../server/index.mjs?id=again")) inside a test — it corrupts V8's per-file coverage attribution and can crater a file's reported percentage to ~0%. Reuse the top-level import instead.
  • Unreachable-by-design code stays uncovered: the getNestedValue string-key branch in client/gemini.mjs (all call sites use numeric keys) and the server/index.mjs main-guard (only runs as an entrypoint). Both are accepted rows below 100% so they don't fail the gate.