Testing with Vitest
Develop with calm and joy through component testing.
We now have TypeScript for Eleventy with TSX as a template language. This lets us use component-driven development in 11ty. This also opens up the possibility to write tests for our components, validating they behave (and keep behaving) as expected.
For example, we can work on small chunks -- in isolation -- and work happily in tests, using Vitest. We'll start by adding a dependency and a script:
{
"name": "eleventy-tsx",
"version": "1.0.0",
"description": "Demo of Eleventy 3, ESM, and TS/TSX",
"scripts": {
"build": "tsx node_modules/@11ty/eleventy/cmd.cjs --config=eleventy.config.ts",
"start": "tsx node_modules/@11ty/eleventy/cmd.cjs --config=eleventy.config.ts --serve --incremental",
"test": "vitest run"
},
"keywords": [],
"author": "Paul Everitt <pauleveritt@me.com>",
"license": "ISC",
"type": "module",
"dependencies": {
"@11ty/eleventy": "^3.0.0-alpha.6",
"jsx-async-runtime": "^0.1.8"
},
"devDependencies": {
"prettier": "^3.2.5",
"tsx": "^4.7.0",
"vitest": "^1.5.0"
}
}
We need to wire up Vitest in a vitest.config.js
file at the root:
import { defineConfig } from "vitest/config";
export default defineConfig({
esbuild: {
jsx: "transform",
jsxInject: "import { jsx } from 'jsx-async-runtime/jsx-runtime'",
jsxFactory: "jsx",
jsxImportSource: "jsx-async-runtime",
},
test: {
include: ["./site/**/*.test.tsx"],
},
});
This overrides the same settings used by tsx
for running Eleventy builds. Vitest uses esbuild
(as does tsx
) but
for whatever reason, doesn't respect the tsconfig.json
settings without help. Big shoutout
to Joaquín Sánchez from Vite/Vitest fame for helping solve the issues.
Next, let's rewrite index.11ty.tsx
to have a named-export component, which we then re-export for Eleventy's render
protocol for templates. This is for convenience, so you don't have all of your components named render
:
export function Index(): JSX.Element {
return <h1>Hello TSX</h1>;
}
export const render = Index;
Now we can write a test of the Index
component, using Vitest. Save this in site/index.test.tsx
:
import { expect, test } from "vitest";
import { renderToString } from "jsx-async-runtime";
import { Index } from "./index.11ty";
test("render index", async () => {
const result = <Index />;
const rendered = await renderToString(result);
expect(rendered).toEqual("<h1>Hello TSX</h1>");
});
This test passes when we run npm test
. Even better, we get full integration into the IDE's Vitest support:
Having tests is great, but we can do better. We're doing string-based testing, and ideally we want to validate the resulting DOM. Curious? Find out more in the next step!