---
title: "How to test Hem modules"
description: "Run Vitest against .hem sources with hem test, filter and watch, and handle React and Effect test suites."
image: "https://hem.run/social/hem.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://hem.run/llms.txt
> Use this file to discover all available pages before exploring further.

# How to test Hem modules

```sh
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:

```ts title="src/schedule.test.ts"
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

```sh
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

```sh
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:

```sh
hem test --jsx-import-source preact
```

## Test Effect code against a different transport

```sh
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](/guides/set-up-a-project).

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

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

```sh
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](/reference/cli).

Source: https://hem.run/guides/test-hem-code/index.mdx
