Skip to content

First steps with end-to-end testing using jest + playwright (puppeteer)

Posted on:December 3, 2020

This post is a continuation of the “First steps with test automation” article.

Recently I wrote a post about my first steps with test automation. I tried to answer questions related to the topic and guide you where and what to search for (if you’re interested - click here!). Now, I want to expand on it with technical steps you need to take and show you how easily you can create a basic test with a real world example (my blog 🥳).

We will create a base repository with Playwright and JestJS and write a basic test which will:

To achieve it, I think you need a little more knowledge, so I split the article into three topics (+bonus):

Before starting the game, here are some topics which you should be familiar with:

What do I need to start with automatization?

First of all, you need a library/tool which allows you to control a browser using code. Today, I’ll use NodeJS library called Playwright (which is very similar to Puppeteer – here you can find a nice article about the differences: to automate our actions with an API. You need a tool like this to write tests that will imitate the behaviour of end user (behave like our clients).

Basically, doing a test manually, you’re using a mouse to click and scroll or a keyboard to fill in the forms. In automated tests, you’re using a library API to do the same things but the browser is controlled by automation software, not a user.

Next, we need assertions. Playwright provides their own ones, but honestly – I’ve never used them. I like JestJS, which, besides that, is a test runner, which gives you more opportunities to control the whole test base. With an easy way to do parallelisation or configs for dev/production envs, writing tests is only a pleasure 🥰.

In summary, you need:

Project setup with Playwright and JestJS

So we will use:

And if you decided to stick with puppeteer:

Note: When using puppeteer, you need to change selectors because the API is slighty different. In our basic test, it is enough to remove css= part and change waitForLoadStatewaitForNavigation. After those two changes, everything should work.

Before we start writing our first automated test, we need to set up the repository:

Let’s initialize it first:

Then install the required dependencies:

yarn install jest jest-playwright-preset playwright


npm install jest jest-playwright-preset playwright

And create two config files,

// jest.config.js
module.exports = {
  preset: "jest-playwright-preset",
// jest-playwright.config.js
module.exports = {
  // Describe which browsers we want to run
  browsers: ["chromium", "firefox", "webkit"],
  launchOptions: {
    // If we want to run browsers in headless mode or not,
    headless: false,
    // If we want to have opened devtools from start
    devtools: false,

Also, we need to an execute script to our package.json:

"scripts": {
    "test": "jest"

Now, you can yarn test or npm run test which will run all files matching *.test.js names – but we don’t have any tests yet 🙈

One more thing that I added is tests/ directory where we will store our test.

Let’s write an automated test

First we need to know what we want to test 🙈

I created a basic flow relating to my blog, which you’re reading now:

In the directory tests/ I added a file example.test.js. And to make it easier for you, I coded the above scenario, adding comments line by line, describing what’s happening.

let blogPosts = [];

describe("Blog -", () => {
  // Will trigger methods before tests
  beforeAll(async () => {
    // Load blog page
    await page.goto("");

  test('title should be "Blog | Przemysław Paczoski"', async () => {
    // Get website title
    const title = await page.title();

    // Compare title of current page
    expect(title).toBe("Blog | Przemysław Paczoski");

  test("should display list of blog posts", async () => {
    // Get all blog posts as an array of objects
    blogPosts = await page.$$eval("", elems => => {
        return {
          title: el.querySelector(".post-title").textContent.trim(),
          description: el.querySelector(".post-description").textContent.trim(),
          href: el.href,

    // Check if list length is greater than 0

  test("click on blog post should redirect to article", async () => {
    // Go to first blog post, there we're waiting to resolve all promises from array
    await Promise.all([
      // Click oo .post-title css class element""),
      // Wait for networkidle event, promise resolves after event

    // Get title, content and href of current article
    const [articleTitle, articleContent, articleHref] = await Promise.all([
      // Get article title, we use here array destructuring
      page.$eval("css=h2", el => el.textContent.trim()),
      // Get article content
      page.$eval("css=.content", el => el.textContent),
      // Get article href

    // Destructuring first element from an blog posts array. First we use array destructuring and then object destructuring
    const [{ title, description, href }] = blogPosts;

    // Compare title from posts list with current article's title
    // Check if the current article content includes description from posts list, compare output with boolean true
    // Compare href from posts list with current article's href

After we finish coding our test, let’s run it using the command yarn test.

Playwright will open three browsers which we described earlier: chromium, firefox, webkit.

And if everything goes well, we should see the following log:


And that’s it! We ran our tests positively in three different browsers.

Bonus: Test recorder!

Lastly, a good way to start with test automation could be to use test recorders. Nice one, created with playwright is: which allows you to record your browser interactions and automatically generate a fully working code – an automated test with Playwright.


In this article, I wanted to show you how easy it is to automate a basic test scenario using tools such as Playwright and JestJS. I hope that will be a good start for you to explore this part of software engineering.

After reading it, you should have learned:

Fully working, implemented code from this article can be found in my repository:

Have a nice day!