Testing Introduction
Brisa utilizes the Bun test runner to execute tests, coupled with @happy-dom/global-registrator for DOM manipulation within the tests. Additionally, Brisa exposes a testing API and extends test matchers with to streamline integration with components in the tests.
Take a look at the Bun test runner documentation for more information on how to run tests and the available options.
Getting started
To use tests in Brisa, you need to have the bunfig.toml
file on the root of the project with this configuration:
[test]
preload = "brisa/test"
This allows to preload all the matchers from Brisa and it will also take care of initializing happy-dom library to manipulate the DOM.
Testing Server Actions
After rendering the component, you can interact with it thanks to userEvent
. For example, you can simulate a click event on a button:
import { render, userEvent } from "brisa/test";
import { test, mock } from "bun:test";
test("server action test", async () => {
const mockServerAction = mock(() => {});
const { container } = await render(
<button onClick={mockServerAction}>Click me</button>,
);
const button = container.querySelector("button");
userEvent.click(button);
expect(mockServerAction).toHaveBeenCalled();
});
It's very similar to browser events, but it has some differences, for example in onSubmit
of a form, you can access directly to event.formData
, because the browser event was already handled by the RPC layer and the form was submitted to the server, converting the SubmitEvent
into a FormDataEvent
.
import { render, userEvent } from "brisa/test";
import { test, mock } from "bun:test";
test("server action test", async () => {
const mockServerAction = mock(() => {});
const { container } = await render(
<form onSubmit={(e) => mockServerAction(e.formData.get("name"))}>
<input type="text" name="name" value="foo" />
<button type="submit">Submit</button>
</form>,
);
const form = container.querySelector("form");
userEvent.submit(form);
expect(mockServerAction).toHaveBeenCalledWith("foo");
});
rerenderInAction
,navigate
, and other actions that change the state of the application are not available in the test environment. You can use themock
function to simulate the server action and test the component behavior.
Testing Web Components
You can also test Web Components after rendering them. For example, you can test a custom element:
import { render, userEvent } from "brisa/test";
import { test, expect } from "bun:test";
test("web component", async () => {
const { container } = await render(<custom-counter />);
const counter = container.querySelector("custom-counter")!.shadowRoot!;
const [increment, decrement] = counter.querySelectorAll("button");
expect(counter).toContainTextContent("0");
userEvent.click(increment);
expect(counter).toContainTextContent("1");
userEvent.click(decrement);
expect(counter).toContainTextContent("0");
});
You can use the
shadowRoot
property to access the shadow DOM of a custom element.
Testing API Endpoints
You can test API endpoints using the serveRoute
function. This function allows you to request a Brisa route and return the Response. These routes can be API endpoints, pages, assets, or any other type of route.
Example:
import { serveRoute } from "brisa/test";
import { test, expect } from "bun:test";
test("route", async () => {
const response = await serveRoute("/api/hello");
const data = await response.json();
expect(data).toEqual({ message: "Hello, world!" });
});
For the pages, you can use it with the render
function to render the page:
import { render, serveRoute } from "brisa/test";
import { test, expect } from "bun:test";
test("page", async () => {
const response = await serveRoute("/about");
const { container } = await render(response);
expect(container).toHaveTextContent("About us");
});
Types of tests
Unit testing
Involves testing individual units (or blocks of code) in isolation. In Brisa, a unit can be a single function or component.
Example:
import { sum } from "./sum";
import { test, expect } from "bun:test";
test("sum", () => {
expect(sum(1, 2)).toBe(3);
});
Component testing
Is a more focused version of unit testing where the primary subject of the tests is Brisa components. This may involve testing how components are rendered, their interaction with props, and their behavior in response to user events.
Example:
import { render, userEvent } from "brisa/test";
import { test, expect } from "bun:test";
function Button() {
return <button onClick={() => console.log("clicked")}>Click me</button>;
}
test("component", async () => {
const { container } = await render(<Button />);
const button = container.querySelector("button");
expect(button).toHaveTextContent("Click me");
await userEvent.click(button);
expect(console.log).toHaveBeenCalledWith("clicked");
});
Integration testing
Involves testing how multiple units work together. This can be a combination of components and functions.
Example:
import { render, userEvent, serveRoute } from "brisa/test";
import { test, expect } from "bun:test";
test("integration", async () => {
const response = await serveRoute("/");
const { container } = await render(response);
const button = container.querySelector("button");
expect(button).toHaveTextContent("Click me");
await userEvent.click(button);
expect(console.log).toHaveBeenCalledWith("clicked");
});
Brisa provides a testing API to help you interact with entrypoints and test their behavior. This is not considered full E2E testing because it doesn't simulate real user scenarios like a browser would do, but it can be used to test entrypoints of your application.
End-to-End (E2E) Testing
Involves testing user flows in an environment that simulates real user scenarios, like the browser. This means testing specific tasks (e.g. signup flow) in a production-like environment.
Example with Playwright:
import { test, expect } from "bun:test";
import { webkit } from "playwright"; // Or 'chromium' or 'firefox'.
test("e2e", async () => {
const browser = await webkit.launch();
const context = await browser.newContext();
const page = await context.newPage();
await page.goto("https://example.com");
await page.screenshot({ path: "screenshot.png" });
await browser.close();
});
Brisa does not provide built-in support for E2E testing. You can use any E2E testing library like Playwright, Cypress, or Puppeteer.
Snapshot testing
Involves capturing the rendered output of a component and saving it to a snapshot file. When tests run, the current rendered output of the component is compared against the saved snapshot. Changes in the snapshot are used to indicate unexpected changes in behavior.
Example:
import { render } from "brisa/test";
import { test, expect } from "bun:test";
test("snapshot", async () => {
const { container } = await render(<div>Hello, World!</div>);
expect(container.innerHTML).toMatchSnapshot();
});
To update snapshots, use the --update-snapshots
flag.
bun test --update-snapshots