@webcontainer/test
v0.3.0
Published
Utilities for testing applications in WebContainers
Readme
@webcontainer/test
Utilities for testing applications in WebContainers
Installation | Configuration | API
Test your applications and packages inside WebContainers.
Installation
Add @webcontainer/test to your development dependencies.
$ npm install --save-dev @webcontainer/testVitest is also required as peer dependency.
$ npm install --save-dev vitestConfiguration
Add vitestWebContainers plugin in your Vitest config and enable browser mode:
import { defineConfig } from "vitest/config";
import { vitestWebContainers } from "@webcontainer/test/plugin";
export default defineConfig({
plugins: [vitestWebContainers()],
test: {
browser: {
enabled: true,
},
},
});API
Webcontainer utilities are exposed as test fixtures:
import { test } from "@webcontainer/test";
test("run development server inside webcontainer", async ({
webcontainer,
preview,
}) => {
await webcontainer.mount("path/to/project");
await webcontainer.runCommand("npm", ["install"]);
const { exit } = webcontainer.runCommand("npm", ["run", "dev"]);
await preview.getByRole("heading", { level: 1, name: "Hello Vite!" });
await exit();
});To use test hooks, you can import fixture typings:
import { test, type TestContext } from "@webcontainer/test";
import { beforeEach } from "vitest";
// Mount project before each test
beforeEach<TestContext>(({ webcontainer }) => {
await webcontainer.mount("projects/example");
});preview
getByRole
Vitest's getByRole that's scoped to the preview window.
await preview.getByRole("heading", { level: 1, name: "Hello Vite!" });getByText
Vitest's getByText that's scoped to the preview window.
await preview.getByText("Hello Vite!");locator
Vitest's locator of the preview window.
await preview.locator.hover();webcontainer
mount
Mount file system inside webcontainer.
Accepts a path that is relative to the project root, or inlined FileSystemTree.
await webcontainer.mount("/path/to/project");
await webcontainer.mount({
"package.json": { file: { contents: '{ "name": "example-project" }' } },
src: {
directory: {
"index.ts": { file: { contents: "export default 'Hello!';" } },
},
},
});runCommand
Run command inside webcontainer.
await webcontainer.runCommand("npm", ["install"]);Calling await on the result resolves into the command output:
const files = await webcontainer.runCommand("ls", ["-l"]);To write into the output stream, use write method of the non-awaited output.
To verify output of continuous stream, use waitForText():
const { write, waitForText, exit } = webcontainer.runCommand("npm", [
"create",
"vite",
]);
await waitForText("What would you like to call your project?");
await write("Example Project\n");
await waitForText("Where should the project be created?");
await write("./example-project\n");
await exit();To capture each output chunk one-by-one, you can use onData callback.
This can be useful when debugging output of the stream.
const { isDone, onData } = webcontainer.runCommand("npm", ["run", "build"]);
onData((chunk) => console.log(chunk));
await isDone;readFile
WebContainer's readFile method.
const content = await webcontainer.readFile("/package.json");writeFile
WebContainer's writeFile method.
await webcontainer.writeFile("/main.ts", "console.log('Hello world!')");rename
WebContainer's rename method.
await webcontainer.rename("/before.ts", "/after.ts");mkdir
WebContainer's mkdir method.
await webcontainer.mkdir("/src/components");readdir
WebContainer's readdir method.
const contents = await webcontainer.readdir("/src");rm
WebContainer's rm method.
await webcontainer.rm("/node_modules");setup
If you have repetitive steps that are needed by multiple test cases, you can improve test performance by using setup.
It calls the given function once, saves WebContainer state in a snapshot, and restores that snapshot before each test.
import { test, type TestContext } from "@webcontainer/test";
import { beforeEach, expect, onTestFinished } from "vitest";
beforeEach<TestContext>(async ({ webcontainer, setup }) => {
// This is run once and cached for each next run
await setup(async () => {
await webcontainer.mount("./svelte-project");
await webcontainer.runCommand("npm", ["install"]);
});
});
// No need to re-mount file system or re-run install in test cases
test("user can build project", async ({ webcontainer }) => {
await webcontainer.runCommand("npm", ["run", "build"]);
});
test("user can start project", async ({ webcontainer, preview }) => {
void webcontainer.runCommand("npm", ["run", "dev"]);
await preview.getByRole("heading", { name: "Welcome to SvelteKit" });
});