Going further with Playwright

Photo by Andrew Neel on Unsplash

Going further with Playwright

Frontend end-to-end testing

Today I'm going to develop a test that will let us know if everything on the main page of my blog is showing up as expected. This will be a longer example of what is possible to achieve with Playwright testing.

If you want to follow along with this post, but don't yet know how to use Playwright, check out my post Getting Started with Playwright.

Expanding on the test

I'm going to take my two tests from the last post and combine them into one test whose goal will be to verify that certain elements are visible and clickable on the main page of my blog.

Imports, goto, and verify title

First, import test and expect from playwright/test. We'll then start by opening up an instance of the test() method, naming our test 'verify main page content is visible and links are clickable', and filling the second argument with the async keyword and an empty callback function.

const { test, expect } = require('@playwright/test');

test('verify main page content is visible and links are clickable', async ({ page }) => {
});

The first thing we'll do within the test is navigate to the url we want to test.

test('verify main page content is visible and links are clickable', async ({ page }) => {
    await page.goto('https://madelinecaples.hashnode.dev/');
});

Then we'll check to see if our page has the title we expect it to have.

// Expect a title "to contain" a substring.
await expect(page).toHaveTitle('Madeline\'s Machine Learning Log');

Check header for image and title

Next, we'll use a locator to find the header section, and see whether the header has the title and tiny image of the author that we expect. The locator getByRole will allow us to search the page for links. Then we can narrow down that search to links that have the name 'Madeline\'s Machine Learning Log' (don't forget to escape before the apostrophe). We'll save that locator to a variable named headerTitle so that we can use it below to check if it's visible with the method toBeVisible.

We'll use our headerTitle variable to also find the img within the header title, using the getByRole locator. We'll save that locator to the variable name headerTitleImage, and then check to see if the image is visible. We'll also check if headerTitleImage has the correct alt text with the method toHaveAttribute which takes two arguments: the attribute you're looking for, and the text you expect the attribute to have.

// Expect header to contain image and correct title
  const headerTitle = page.getByRole('link', { name: 'Madeline\'s Machine Learning Log'}); 
  await expect(headerTitle).toBeVisible();
  const headerTitleImage = headerTitle.getByRole('img'); 
  await expect(headerTitleImage).toBeVisible(); 
  await expect(headerTitleImage).toHaveAttribute('alt', 'Madeline Caples');

Check author container for image and text

Next, we'll check to see if the section containing the blog author looks the way we expect it to. Conveniently, we can locate the author container element with the class name 'blog-author-container' and save it to a variable, blogAuthorContainer.

Then we can use that locator to further narrow down elements within the author container. We'll get the blogAuthorImage with blogAuthorContainer.getByRole('img') and we'll get the blogAuthorTitle with blogAuthorContainer.getByRole('link').last(). We have to use last because there are two links within the author container and we want the second one. We'll expect the title to have the text 'Madeline Caples.

Finally, we'll find the headline by searching within blogAuthorContainer for paragraph elements, and expect it to have the text "I explain machine learning concepts in plain English."

 // check if blog author container has the expected elements 
  const blogAuthorContainer = page.locator('.blog-author-container'); 
  const blogAuthorImage = blogAuthorContainer.getByRole('img'); 
  await expect(blogAuthorImage).toBeVisible(); 
  await expect(blogAuthorImage).toHaveAttribute('alt', 'Madeline Caples'); 
  const blogAuthorTitle = blogAuthorContainer.getByRole('link').last();
  await expect(blogAuthorTitle).toHaveText('Madeline Caples'); 
  const headline = blogAuthorContainer.getByRole('paragraph'); 
  await expect(headline).toHaveText('I explain machine learning concepts in plain English');

A quick note: If I ever change the headline of my blog, these tests will fail, which is a downside of hardcoding these values into the tests, rather than having them be populated in some other way.

Our last portion for this test is to make sure that all links on the page are enabled (clickable). We can use the all() method on our locator to select all elements that match that locator and do something to them. Since we're going to be doing the same thing - checking if links are enabled - multiple times, it makes sense to use a for-loop. Within the loop, we can expect the link to be enabled.

// expect all links on page to be enabled 
  for (const link of await page.getByRole('link').all()) {
    await expect(link).toBeEnabled(); 
  }

Closing comments

There's much more that can be added to make this test better. There are two options for refactoring what we already have which will make the test more readable and easier to debug. Stay tuned for future articles where I describe those options!