@webcontainer/test
TypeScript icon, indicating that this package has built-in type declarations

0.1.0 • Public • Published

@webcontainer/test

Version

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/test

Vitest is also required as peer dependency.

$ npm install --save-dev vitest @vitest/browser

Configuration

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" });
});

Package Sidebar

Install

npm i @webcontainer/test

Weekly Downloads

112

Version

0.1.0

License

MIT

Unpacked Size

24.4 kB

Total Files

7

Last publish

Collaborators

  • apai4
  • ericmsimons
  • d3lm
  • _rvidal
  • stackblitz-devops
  • nemikolh