This content originally appeared on Go Make Things and was authored by Go Make Things
Kelp, my UI library for people who love HTML, officially launched as v1 stable yesterday!
I was chatting about my approach to unit testing last week, and a few folks were surprised to learn that I use Playwright for unit testing.
Today, I wanted to take a quick look at why it’s a superior option to Jest and other tools, and how to use it. Let’s dig in!
Why Playwright?
The single best reason, in my opinion, is that it runs in a real browser.
Most frontend testing tools use Node-based emulated browsers. They’re often out-of-sync with real DOM features, requiring you to do stuff like mock up the fetch()
function or do weird shit to get native ES imports to work.
With Playwright, anything that runs in the browser “just works.”
It also has built in waiting, so you can tasks that are asynchronous (via setTimeout()
, requestAnimationFrame()
, etc.), and it automatically waits for them to complete using the await
operator.
Playwright advertises itself as an end-to-end testing tool—and it is!—but at the end of the day, it’s loading up tests and running JavaScript. It’s an excellent tool for unit testing!
Getting Setup
Step one is to install Playwright.
The installer walks you through configuration. I recommend the JavaScript (not Typescript) setup, but that’s just my personal preference.
Here’s the config I use for my Playwright projects. For speed, it runs tests only in Chrome.
If I were using it for end-to-end testing, I’d run a larger suite of browsers.
Running a server
Despite what the docs might make you think, you do not need to run a server or have any sort of application setup to use Playwright.
However… when testing DOM libraries, I prefer to write my HTML in an actual HTML file rather than doing the whole “inject HTML with JS” thing.
I usually install Node http-server
, which spins up a tiny little HTTP server so I can access raw HTML files with my HTML. Totally optional, though!
I’ll show you how to do things “the traditional way” in just a minute.
Writing and running tests
Let’s say I have an add()
function that adds two or more numbers together.
/**
* Add two or more numbers together
* @param {...Number} nums The numbers to add together
* @return Number The total
*/
export function add (...nums) {
let total = 0;
for (let num of nums) {
total = total + num;
}
return total;
}
I want to make sure it does what it’s supposed to.
In my /tests
directory, I create a calculator.spec.js
file. I import
the test()
and expect()
functions from Playwright, and add()
from my calculator.js
file.
Because Playwright runs in a real browser, you can use native ES imports without any nonsense!
import { test, expect } from '@playwright/test';
import { add } from '../../src/calculator.js';
````
I `describe()` my `test` (this creates a group of related tests), and then `test()` my `add()` function.
Just like with Jest, I `expect()` a certain input to have a specific outcome. Here, I'm testing that two numbers add together, that passing in only one number outputs itself, and passing in no numbers returns `0`.
[Playwright has a bunch of assertions](https://playwright.dev/docs/test-assertions), and they're all pretty intuitive.
```js
test.describe('calculator.js', () => {
test('add()', async () => {
// Should add two or more numbers together
expect(add(4, 6, 8)).toEqual(18);
// Should return the original value when one number is provided
expect(add(42)).toEqual(42);
// Should return 0 if no numbers are provided
expect(add()).toEqual(0);
});
});
In my Terminal window, I can run npx playwright test
to run my tests.
Testing DOM
This is where Playwright really shines over a tool like Jest.
The callback function on the test()
method can expose a page
variable that represents the current document in the browser.
test('DOM stuff', async ({ page }) => {
// ...
});
If you want to generate your HTML in your test()
, you can do that with the page.setContent()
method.
test('DOM stuff', async ({ page }) => {
await page.setContent('<button>Hi</button>');
});
Playwright uses locators to get elements in the DOM.
These work like querySelectorAll()
under-the-hood, and act as placeholders for the element you’re trying to get. When you go to actually test against the element, they’ll grab the latest version of it in the DOM, and try multiple times to find it if not available immediately.
As a result, you should await
any action that uses a locator
.
Here, I’m injecting a button, locating it, and testing that it exists.
test('inject content', async ({ page }) => {
await page.setContent('<button>Hi</button>');
const btn = page.locator('button');
await expect(btn).toBeTruthy();
});
A boilerplate
Interested in using Playwright to test your projects? I setup a simple little boilerplate on GitHub that you can use.
Download it, run npm install
, and you’re off to the races!
It’s the same basic testing structure I’m using in Kelp.
Like this? A Lean Web Club membership is the best way to support my work and help me create more free content.
This content originally appeared on Go Make Things and was authored by Go Make Things

Go Make Things | Sciencx (2025-08-18T14:30:00+00:00) How to use Playwright for unit testing. Retrieved from https://www.scien.cx/2025/08/18/how-to-use-playwright-for-unit-testing/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.