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 playwright

Once 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 puppeteer

Then 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.