Files
hypit/docs/guide/testing.md
T
rpone a413b3c5c6 fix: the environment-gated test scripts stop depending on sh
Three scripts were written in shell that only one shell speaks. pnpm hands a
script body to /bin/sh on POSIX and to cmd.exe on Windows, and what sh reads as
syntax cmd.exe reads as text.

`VAR=1 command` is the loud one: cmd.exe has no such form and looks for a
program named `HYPIT_BROWSER_TESTS=1`. It fails where you can see it.

The quoted discovery pattern is the quiet one, and it is the same defect this
repository already found in its main suite. sh strips the quotes and unittest
receives `test_*.py`; cmd.exe does not, and unittest receives six characters
that match no file. Both exit 0:

    -p 'test_*.py'    stripped   Ran 11 tests   OK             exit 0
    -p 'test_*.py'    literal    Ran 0 tests    NO TESTS RAN   exit 0

Double quotes are stripped by both shells, so the pattern needs no runner —
only the right quote. The two environment gates move into the runner that
already exists for this, as named suites, where they are assignments rather
than syntax. That also settles the third defect: the OpenCV script named the
POSIX interpreter path outright, though `deployment.ts` has branched on the
platform for that venv all along.

An environment already set by the caller still wins. These are defaults for
running a suite, not a policy about it.
2026-08-20 23:43:04 +08:00

4.0 KiB

title, description
title description
Testing Test runner, patterns and environment-gated tests.

Testing

Test runner

Hypit uses the Node.js built-in test runner (node:test), not Jest, Vitest or Mocha.

pnpm test          # package tests + boundary tests

Test files live in packages/<name>/test/ with the .test.ts extension. They are discovered by the glob packages/*/test/**/*.test.ts.

Writing a test

import assert from "node:assert/strict";
import { describe, test } from "node:test";

import { someFunction } from "@hypit/example";

describe("someFunction", () => {
  test("returns the expected result", () => {
    const result = someFunction(input);
    assert.deepStrictEqual(result, expected);
  });
});

Admission rule

A test belongs in the default suite only when it protects an observable contract, an architectural boundary, or a failure mode that could corrupt work, repeat paid execution, or make an environment unsafe. Test that fact once at its owning layer; use one checked-in graph fixture for cross-package assembly instead of rebuilding the same partial video in every higher layer.

Do not add tests merely to make every package appear covered, mirror a Manifest array, preserve a removed pre-release flag or database shape, or exercise documentation-only UI helpers. Component registration already rejects Manifest/implementation drift. Obsolete tests are deleted with obsolete behavior rather than retained as project history.

Test patterns

Pure compilation tests

The most common pattern. Compile an Author or Run Source and assert on the resulting graph, exports, Records or plan steps. Never calls an external service.

test("compiles the expected exports", async () => {
  const compiler = createCompiler({ root, packageContributions });
  const workspace = await compiler.openFile("fixture.svml");
  const result = await compiler.compileSource(workspace.entry, workspace);
  assert.equal(result.exports.length, 3);
});

Provider tests

Test Endpoint implementations with real or simulated external services. Environment-gated: check for required credentials or executables and skip when absent.

test("generates a video", async (t) => {
  if (!process.env.KIE_API_KEY) {
    t.skip("KIE_API_KEY not set");
    return;
  }
  // ... real API call
});

Architecture boundaries

Package boundaries are expressed by package manifests, public entry points and shared contracts. Tests exercise observable behavior at those boundaries. The repository deliberately does not use source-text regex tests as a substitute for dependency analysis or architectural review.

Do not commit customer or brand fixtures, credential traces, paid output artifacts, absolute workstation paths or one-off delivery harnesses. Generic live tests may remain only when they are explicitly opt-in, use no committed secret and fail before spending money unless their gate is set.

Environment-gated tests

Command What it tests Prerequisites
pnpm test:whisperx-service Python WhisperX service Python 3.13, uv, frozen sync
pnpm test:image-opencv the shared OpenCV Raster interpreter across both request variants the service's own interpreter at services/image-opencv/.venv; set HYPIT_OPENCV_PYTHON to use another
pnpm test:browser-visual rendered geometry, stacking and clipping in a real browser a Chrome the HyperFrames CLI can start, ffmpeg, and HYPIT_TEST_FONT_PATH off macOS
pnpm smoke:kie Live paid KIE generation KIE_API_KEY

Test fixtures

Test fixtures go in packages/<name>/test/fixtures/. They are ordinary .svml, .svs and .svrun files that exercise specific compilation paths.

The examples/ directory also serves as integration-level fixtures:

  • examples/bootstrap/ — smallest source closure check
  • examples/talking-film-graph-check/ — complete graph compilation without Providers
  • examples/talking-head-aroll/ — live example with explicit prior-Build Candidate reuse