Skip to content

How to test Hem modules

Run Vitest against .hem sources with hem test, filter and watch, and handle React and Effect test suites.

Updated View as Markdown
hem test

hem test emits the project’s siblings, then runs Vitest with the Hem plugin wired in and the emitted TSX transform pinned to a JSX runtime. Use it for suites without a Vite or Vitest config. If a standard config exists in the current directory, the command stops before emitting or testing and directs you to your project’s Vitest command.

Vitest and @hem-lang/vite-plugin resolve from your project, not from the CLI, so your installed versions are the ones that run. If either is missing the command says so and exits.

Write the test

Tests are ordinary TypeScript. Import the .hem module and the specifier resolves to its emitted sibling:

src/schedule.test.tsts
import { expect, test } from "vitest";
import { nextOccurrence } from "./schedule.hem";

test("advances to the next month", () => {
  expect(nextOccurrence(new Date("2026-01-31"), 1)).toEqual(new Date("2026-02-28"));
});

You can also import the emitted .tsx directly when you want to assert on the generated output itself.

Narrow what runs

hem test schedule

Positional arguments pass through to Vitest as test file path filters. Use -- before a path filter beginning with -. Other Vitest options such as -t and --coverage are rejected; run your project’s Vitest command for those modes. hem test --help lists the supported options.

Re-run on change

hem test --watch

Leaves Vitest running. Editing a .hem file re-emits its sibling and re-runs the affected tests.

Point the JSX transform somewhere else

The emitted TSX transform defaults to react. For another runtime:

hem test --jsx-import-source preact

Test Effect code against a different transport

hem test --effect effect

This overrides hem.effectImportSource for the test run only, which is what you want when checking whether a newer Effect release satisfies the capability probe. Leave it off and the tsconfig value applies, so tests and builds agree by default.

Use the project’s Vitest config

Register @hem-lang/vite-plugin alongside the existing plugins in your Vite or Vitest config and run vitest directly. Preserve the project’s setup files, environment, coverage, and test selection. The application owns JSX configuration when using the plugin directly; see Vite integration.

import { defineConfig } from "vitest/config";
import { hem } from "@hem-lang/vite-plugin";

export default defineConfig({
  plugins: [hem()],
  test: { setupFiles: ["./test/setup.ts"] },
});
vitest run

hem test refuses standard vitest.config.* and vite.config.* files in the current directory, including JavaScript and TypeScript module variants. It does not load custom config paths; use your project’s command for those too.

For the full option list, see the CLI reference.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close