@microsoft/fast-test-harness
v0.3.1
Published
Playwright testing harness for FAST web components
Readme
FAST Test Harness
The fast-test-harness package is a Playwright testing harness for FAST Element web components with CSR and SSR support.
Requirements
- Node.js 22.18 or later
- Playwright 1.56 or later
Installation
To install fast-test-harness using npm:
npm install --save-dev @microsoft/fast-test-harnessTest directory setup
The harness serves a Vite dev server from a test/ directory in your project. CSR and SSR modes use different entry points from the same directory.
test/
├── index.html # CSR: loads main.ts
├── ssr.html # SSR: template with comment placeholders
├── vite.config.ts # Vite config (shared by both modes)
└── src/
├── main.ts # CSR: registers components, applies theme
├── entry-client.ts # SSR: registers components for hydration
└── entry-server.ts # SSR: exports render() for fixture generationWriting tests
Import test and expect from the harness. Configure the component tag name with test.use(), then call fastPage.setTemplate() in each test to render it.
import { expect, test } from "@microsoft/fast-test-harness";
test.describe("Button", () => {
test.use({ tagName: "my-button", innerHTML: "Click me" });
test("should render", async ({ fastPage }) => {
await fastPage.setTemplate();
await expect(fastPage.element).toBeVisible();
});
test("should accept attributes", async ({ fastPage }) => {
await fastPage.setTemplate({
attributes: { appearance: "primary", disabled: true },
});
await expect(fastPage.element).toHaveAttribute("appearance", "primary");
});
test("should work inside a form", async ({ fastPage }) => {
await fastPage.setTemplate(`
<form>
<my-button type="submit">Submit</my-button>
</form>
`);
await expect(fastPage.element).toBeVisible();
});
});Use updateTemplate() to modify attributes or innerHTML after the initial render without navigating away from the page:
await fastPage.setTemplate();
await fastPage.updateTemplate(fastPage.element, { attributes: { disabled: true } });The toHaveCustomState assertion checks ElementInternals custom states:
await expect(element).toHaveCustomState("checked");Fixture options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| tagName | string | "" | Custom element tag name |
| innerHTML | string | "" | Default inner HTML |
| waitFor | string[] | [] | Additional elements to wait for before testing |
| ssr | boolean | false | Use SSR mode (or set PLAYWRIGHT_TEST_SSR=true) |
CSR files
index.html loads a script that registers your components:
<!doctype html>
<html lang="en">
<head><meta charset="UTF-8" /></head>
<body>
<script type="module" src="/src/main.ts"></script>
</body>
</html>main.ts registers components and applies global config. The body starts empty; setTemplate() injects HTML per test.
import "./define-all.js";
import { setTheme } from "./theme.js";
setTheme(lightTheme);SSR files
ssr.html contains comment placeholders the server fills in per request:
<!doctype html>
<html lang="en">
<head>
<title><!--fixturetitle--></title>
<!--stylespreload-->
</head>
<body>
<!--fixture-->
<!--templates-->
<script type="module" src="/src/entry-client.ts"></script>
</body>
</html>entry-client.ts imports the harness SSR entry (which defines the <f-template> element) and registers components for DSD hydration using defineAsync:
import "@microsoft/fast-test-harness/ssr/entry-client.js";
import { RenderableFASTElement } from "@microsoft/fast-html";
import { MyButton, definition } from "../../src/button/index.js";
RenderableFASTElement(MyButton).defineAsync({
name: definition.name,
templateOptions: "defer-and-hydrate",
});entry-server.ts exports a render() function that the server calls for each setTemplate() request. It returns three strings that get injected into ssr.html:
export function render(queryObj: Record<string, string>): {
template: string; // <f-template> HTML → <!--templates-->
fixture: string; // rendered element HTML → <!--fixture-->
preloadLinks: string; // <link> tags → <!--stylespreload-->
};Use createSSRRenderer from the harness to build the render() function. It scans for component build artifacts (f-templates, stylesheets) and uses the @microsoft/fast-build WASM renderer to produce declarative shadow DOM on each request.
Multi-component package (all components in one package):
import { createSSRRenderer } from "@microsoft/fast-test-harness/ssr/render.js";
const { render } = createSSRRenderer({
packageName: "@my-scope/web-components",
tagPrefix: "my",
});
export { render };Per-component packages (each component is a separate npm package):
import { createSSRRenderer } from "@microsoft/fast-test-harness/ssr/render.js";
const { render } = createSSRRenderer({
tagPrefix: "my",
components: [
{ name: "button", packageName: "@my-scope/button" },
{ name: "checkbox", packageName: "@my-scope/checkbox" },
],
});
export { render };Server
The package includes a Node.js HTTP server with Vite middleware that handles both CSR page serving and SSR fixture generation. Run it directly or let Playwright manage it via webServer:
// playwright.config.ts
export default defineConfig({
webServer: {
command: "fast-test-harness",
port: 3278,
reuseExistingServer: true,
},
});For custom setup, import startServer:
import { startServer } from "@microsoft/fast-test-harness/server.mjs";
await startServer(process.cwd(), "./test", "./test/vite.config.ts", {
port: 4000,
debug: true,
});| Parameter | Default | Description |
| --------- | ------- | ----------- |
| cwd | process.cwd() | Static file serving root |
| root | <cwd>/test | Vite root (contains index.html, ssr.html) |
| configFile | Vite auto-discovery | Vite config path |
| options.port | 3278 | Server port |
| options.base | / | Base URL path |
| options.debug | false | Write SSR fixtures to temp/ for inspection |
CLI flags
fast-test-harness [command] [options]
Commands:
serve Start the test harness dev server (default)
generate-templates Generate <f-template> HTML files from compiled templates
generate-stylesheets Generate CSS files from compiled ElementStyles
generate-webui-templates Generate WebUI-compatible DSD templates
Serve options:
-p, --port <number> Server port (default: 3278)
-b, --base <path> Base URL path (default: /)
-r, --root <path> Vite root directory (default: <cwd>/test)
-c, --config <path> Vite config file path (default: Vite auto-discovery)
-d, --debug Write SSR fixtures to temp/ for inspection
-v, --version Show version number
-h, --help Show help messageCLI flags take precedence over environment variables.
| Environment variable | Default | Description |
| -------------------- | ------- | ----------- |
| PORT | 3278 | Server port (overridden by --port) |
| BASE | / | Base URL path (overridden by --base) |
| FAST_DEBUG | — | Set "true" to enable debug mode (overridden by --debug) |
| PLAYWRIGHT_TEST_SSR | — | Set "true" for SSR mode |
SSR renderer
createSSRRenderer(options) scans for component build artifacts and returns a { render } object compatible with the server's entry-server.ts contract. It uses the @microsoft/fast-build WASM module to render f-templates into declarative shadow DOM.
| Option | Type | Description |
|--------|------|-------------|
| tagPrefix | string | Tag name prefix for custom elements (e.g., "fluent", "contoso") |
| packageName | string? | Monolithic package name — scans subdirectories for component artifacts. Mutually exclusive with components. |
| components | ComponentRegistration[]? | Explicit list of per-component packages. Mutually exclusive with packageName. |
| distDir | string? | Artifact directory relative to the package root (default: "dist/esm"). Only used with packageName. |
| themeStylesheet | string? | URL or package specifier for a global theme stylesheet. |
Exports
| Specifier | Contents |
|-----------|----------|
| @microsoft/fast-test-harness | test, expect, CSRFixture, SSRFixture, toHaveCustomState, installDomShim, createSSRRenderer |
| @microsoft/fast-test-harness/build/*.js | installDomShim, generateStylesheets, generateFTemplates, generateWebuiTemplates, definitionAsyncResolver, shadowOptionsToAttributes, ShadowOptionsResolver |
| @microsoft/fast-test-harness/fixtures/*.js | CSRFixture, SSRFixture, toHaveCustomState, extended test and expect |
| @microsoft/fast-test-harness/ssr/render.js | createSSRRenderer, renderTemplate, buildEntryHtml, buildState |
| @microsoft/fast-test-harness/server.mjs | startServer |
| @microsoft/fast-test-harness/playwright.config.mjs | Shared Playwright configuration |
| @microsoft/fast-test-harness/vite.config.mjs | Shared Vite configuration |
| @microsoft/fast-test-harness/public/* | Static assets (base CSS) |
