nodepup
v3.0.13
Published
run tests with puppeteer and the nodejs test runner
Readme
Getting started
Run component tests in a real browser - without the hassle.
Why does this exist?
So we can test web components without compromise and without long feedback cycles.
- simulated DOM environments (like JSDOM) don't (plan) to fully implement every Web API
- e2e testing tools like cypress and/or playwright are too heavy handed - component testing is not their main focus
So this sits kind of in the middle between simulated, very fast tests and emulated but very slow tests.
Architecture
It is useful to understand what nodepup does differently under the hood so you can make informed decisions in your tests.
With simulated DOM environments (like jsdom) your tests run on the server and things like e.g. CSS will never be tested. Querying nodes and interacting with your components happens on the basis of a simulated environment which is fast but can only return stand-ins, which e.g. - at the time of writing - do not support form-associated custom elements.
Full e2e suites on the other hand start a headless browser and your test code also runs on the server. Your tests then execute a series of commands that are sent to that browser, meaning that interacting with elements is done either asynchronously or by injecting larger bits of code into the page and executing them there, creating a divide where server side code lives just a few lines away from client side code yet the two are completely separated contexts.
Nodepup takes a different approach: it bundles your tests with esbuild and serves that bundle via a small web server. Your tests run exclusively on the client and as such you can easily listen for events, assert the DOM structure synchronously and all that stuff.
This would however normally come with the same drawback however that a simulated environment has: user interactions can only be "faked". Libraries like user-event have been created to address this issue in a best-effort manner, but they can conceptually never reach the level of the e2e solutions.
For this reason nodepup enables user interactions by flipping the classical e2e approach on its head - instead of the server test code sending commands to the client the client test code tells the servere to execute the commands. While this might seem a like a roundabout way of doing things it has the benefit of combining the performance of a simulated environment with the capabilities of a real browser.
(Recommended) Usage
// Testbed.tsx
/**
* This module exposes utility functions around testing.
*
* @module
*/
import { toHtml } from "tsx-to-html";
import * as Chai from "chai";
import chaiDom from "chai-dom";
Chai.use(chaiDom);
export const expect = Chai.expect;
export const render = (element: JSX.Element) => {
// render the component to a plain HTML string.
// You could also bootstrap your favorite framework here
document.body.innerHTML = toHtml(element);
return document;
};
export * from "@testing-library/dom";
export * from "nodepup";
// [...]
// MyComponent.test.tsx
import {
describe,
it,
user,
expect,
render,
getByRole,
getCenterPoint,
user,
} from "./Testbed.js";
describe("my component", () => {
it("should match :hover when mouse hovers", async () => {
// setup - could be abstracted on a "by component" basis
const container = render(<my-input />);
const input = getByRole(container, "textbox");
// act
const { x, y } = getCenterPoint(input); // util function from nodepup
await user.mouse.move(x, y); // user tries to alias the puppeteer functions here
// assert
expect(input).to.match(":hover");
});
});Configuration
// nodepup.config.js
/**
* @type import("nodepup/server").NodepupConfig
*/
export default {
esbuild: {}, // changeable esbuild options
coverage: {}, // changeable monocart-coverage-reporter options
glob: "**/*.test.{ts,tsx}", // an extended glob to find your test files
bodyContent: "", // html that replaces the document body before every test run
};CLI Usage
See npx nodepup --help.
