First steps with end-to-end testing using jest + playwright (puppeteer)
Published: 2020-12-03 19:06:46

> Oryginally posted at: https://kodziak.com/blog/first-steps-with-e2e-testing-using-jest-playwright

> This post is a continuation of the “[First steps with test automation](https://kodziak.com/blog/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!](https://kodziak.com/blog/first-steps-with-test-automation)). 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:

- Load the blog page,
- Check if the blog title contains the author’s name,
- Check if the posts list isn't empty,
- Click on the first post title and check if it loaded correctly.

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

- What do I need to start with automation?
- Project setup with **Playwright** and **JestJS**
- Let's write an automated test
- Bonus: Test recorder!

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

- Basic knowledge of JavaScript,
- You know how to use CLI and NPM/Yarn,
- You're familiar with HTML/CSS.

### 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/](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:

- A library to control a browser → we'll use **Playwright**,
- A test runner → we'll use **JestJS**

### Project setup with Playwright and JestJS

So we will use:

- [Playwright](https://playwright.dev/)
- [JestJS](https://jestjs.io/en/)
- [Jest-Playwright](https://github.com/playwright-community/jest-playwright)

And if you decided to stick with puppeteer:

- [Puppeteer](https://pptr.dev/)
- [Jest-Puppeteer](https://github.com/smooth-code/jest-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 `waitForLoadState` ⇒ `waitForNavigation`. 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:

- `yarn init` or `npm install`
- `git init`

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,

```jsx
// jest.config.js
module.exports = {
  preset: 'jest-playwright-preset',
}
```

```jsx
// 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`:

```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:

- Check if the blog title contains the author’s name,
- Check if the posts list isn't empty,
- Click on the first post title and check if it loaded correctly.

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.

```jsx
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:

![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/078899a2-7963-484e-a55c-3379ca482c54/Untitled.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/078899a2-7963-484e-a55c-3379ca482c54/Untitled.png)

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](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:

- What Playwright (Puppeteer) and JestJS are used for,
- How to set up a repository using those technologies,
- How to write a basic test.

Fully working, implemented code from this article can be found in my repository: [https://github.com/Kodziak/playwright-first-steps](https://github.com/Kodziak/playwright-first-steps)

Have a nice day!