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:

  • 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/) 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:

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:

  • 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,

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

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

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:

  • 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

Have a nice day!