Automated testing is a necessity for any application that's being developed. If you're not writing automated tests, then it only makes sense that you're spending more time on manual testing. What's worse is when a customer notifies you first. End-to-end testing is an essential part of your development cycle, where you are able to simulate the experience of using your site as a customer would. To help with this process, this blog will show you how to use Nodejs' Puppeteer and Playwright libraries to write end-to-end tests for your websites and applications.
The need for end-to-end testing
End-to-end testing is a crucial part of any development cycle. It involves testing your site the way a real person experiences it. This means taking into account their device, browser, and location in the world when they use your site.
The best way to learn is by example, so let's write a first test with each library.
Writing a test with Playwright
The first step is to install the library with npm or yarn:
npm install playwrightOnce you have the package installed, you can start writing tests with Playwright. A test might look like this:
const { chromium } = require('playwright')
const expect = require('expect')
;(async () => {
const browser = await chromium.launch()
const page = await browser.newPage()
await page.goto('https://github.com/login')
await page.fill('#login_field', process.env.LOGIN_EMAIL)
await page.fill('#password', process.env.LOGIN_PASSWORD)
await Promise.all([
page.waitForNavigation(),
page.click('.js-sign-in-button'),
])
const content = await page.textContent('.auth-form-header h1')
expect(content).toBe('Two-factor authentication')
await browser.close()
})()In this example, we navigate to Github's login page and enter our login and password into the appropriate fields, using environment variables set beforehand. The script then clicks the submit button, waits for the next page to load, and asserts that it contains an element that only appears after a successful login. If the assertion fails, the script throws an error, and if you run it as a browser check, Hyperping catches that error and sends you alerts through your preferred channels.
If you install Playwright through npm init playwright@latest instead, you also get the @playwright/test runner, which replaces the manual browser setup above with test fixtures, auto-waiting locators, and built-in assertions. Our Playwright guides cover that style of test in depth.
Writing a test with Puppeteer
Puppeteer follows the same pattern. Install it first:
npm install puppeteerThen a minimal check looks like this:
const puppeteer = require('puppeteer')
;(async () => {
const browser = await puppeteer.launch()
const page = await browser.newPage()
await page.goto('https://example.com')
const title = await page.title()
if (title !== 'Example Domain') {
throw new Error(`Unexpected title: ${title}`)
}
await browser.close()
})()The main practical difference is browser coverage: Puppeteer is built around Chrome and Chromium, while Playwright also bundles Firefox and WebKit, so it can cover Safari behavior too.
Automate the tests
Writing the test is half the work. To get value from it, the test has to run without you thinking about it:
- Run the suite in CI on every push, so a broken flow blocks the deploy instead of reaching users.
- Schedule your most critical flows, like login and checkout, to run continuously against production. Failures caused by DNS, certificates, or third-party outages only show up there, never in CI.
Conclusion
End-to-end testing is a type of testing that is designed to test the whole of the application, from start to finish, in a real browser.
Puppeteer is a Node.js library that provides a high-level API to control Chrome or Chromium over the DevTools Protocol, and it runs headless by default, which makes it a good fit for servers and CI environments.
Playwright is a Node.js library for automating Chromium, Firefox, and WebKit with a single API, and it ships with a dedicated test runner built for end-to-end suites.
Both are excellent tools for end-to-end testing. Start with one critical user flow, get it running automatically, and grow the suite from there.
FAQ
What is end-to-end testing? ▼
End-to-end testing verifies a complete user flow through your application in a real browser, from loading the page to reaching the expected result. Instead of testing functions in isolation, it simulates what an actual user does: navigating, clicking, typing, and checking what appears on screen.
What is the difference between Puppeteer and Playwright? ▼
Both are Node.js libraries for driving real browsers. Puppeteer focuses on Chrome and Chromium, while Playwright bundles Chromium, Firefox, and WebKit and ships with its own test runner. Playwright was created by engineers who previously worked on Puppeteer, so the APIs feel related.
Do I need both Puppeteer and Playwright? ▼
No, pick one. Playwright is the stronger choice for cross-browser test suites thanks to its test runner and auto-waiting. Puppeteer works well when you only care about Chrome or want a lightweight automation library for tasks like scraping and PDF generation.
How do I run end-to-end tests automatically? ▼
Run the suite in CI on every push so regressions are caught before deploy, and schedule your most critical flows to run continuously against production. Scheduled browser checks catch failures that only show up with real DNS, infrastructure, and third-party services.



