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: https://blog.logrocket.com/playwright-vs-puppeteer/) 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

or

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 - kodziak.com/blog/", () => {
  // Will trigger methods before tests
  beforeAll(async () => {
    // Load blog page
    await page.goto("https://kodziak.com/blog/");
  });

  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("css=.post", elems =>
      elems.map(el => {
        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
    expect(blogPosts.length).toBeGreaterThan(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
      page.click("css=.post-title"),
      // Wait for networkidle event, promise resolves after event
      page.waitForLoadState("networkidle"),
    ]);

    // 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
      page.url(),
    ]);

    // 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
    expect(title).toBe(articleTitle);
    // Check if the current article content includes description from posts list, compare output with boolean true
    expect(articleContent.includes(description)).toBe(true);
    // Compare href from posts list with current article's href
    expect(href).toBe(articleHref);
  });
});

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:

CLI-logs

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: https://github.com/microsoft/playwright-cli which allows you to record your browser interactions and automatically generate a fully working code – an automated test with Playwright.

Conclusion

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: https://github.com/Kodziak/playwright-first-steps

Have a nice day!