DEV Community

Cover image for Using Codegen
Corina: Web for Everyone
Corina: Web for Everyone

Posted on • Edited on

Using Codegen

Start with confidence with autogenerated tests! 🎭


Playwright allows you to generate test scripts based on your interactions with the UI. This feature is known as Playwright's code generation capability. When you interact with your app's UI elements during a testing session, Playwright records these interactions and generates corresponding test scripts. Quite straightforward!

Steps to Get Started with Codegen


Step 1. Open the Testing sidebar and click Record new.
Playwright will open a new test file, as well as a blank browser page.

test('test', async ({ page }) => {
  // Recording...
});

Enter fullscreen mode Exit fullscreen mode

Step 2. In the browser, type the URL for the site you want to test.

Step 3. Once typed in, the URL automatically gets recorded inside the testing file:

test('test', async ({ page }) => {
    await page.goto('https://corinamurg.netlify.app/');
})
Enter fullscreen mode Exit fullscreen mode

Step 4. Now Playwright expects you to manually perform actions on that site, so it can translate these actions into test scripts.

For more details, visit Playwright's documentation on codegen

My Codegen Session

My goal was to test the links inside my navbar. As I was manually clicking every link in my navbar, Playwright translated these actions into test scripts. At the end, my test function looked like this:

test('test navigation links', async ({ page }) => {
  await page.goto('https://corinamurg.netlify.app/');
  await page.getByRole('banner').getByRole('link', { name: 'Corina Murg' }).click();

  await page.getByRole('navigation').getByRole('link', { name: 'Home' }).click();

  await page.getByRole('navigation').getByRole('link', { name: 'Projects' }).click();

  await page.getByRole('navigation').getByRole('link', { name: 'Accessibility' }).click();

  await page.getByRole('navigation').getByRole('link', { name: 'About' }).click();

  const page2Promise = page.waitForEvent('popup');
  await page.getByRole('navigation').getByRole('link', { name: 'Blog' }).click();
  const page2 = await page2Promise;
});
Enter fullscreen mode Exit fullscreen mode

My assumption was that the automated test would

  • check that each link is clickable, and
  • check that it opens the expected page.

It just happens that when I learn, I like to break the code and notice how it reflects in the browser. So, I disabled the paths to the Blog and the About links and expected an error for each link.

Well, this did not happen! At least not for both links, that is. I received the error for the Blog link (note: this link connects to an external site and has an target="_blank" attribute), but I did not receive the error for the About link. 🤔

Help came from the (awesome) Playwright documentation! Here's what it says about .click() method:

Under the hood, this and other pointer-related methods:

  • wait for the element with the given selector to be in the DOM
  • wait for it to become displayed, i.e., not empty, no display: none, no visibility: hidden
  • wait for it to stop moving, for example, until the CSS transition finishes
  • scroll the element into view
  • wait for it to receive pointer events at the action point, for example, wait until the element becomes non-obscured by other elements
  • retry if the element is detached during any of the above checks

It turns out that in the case of my 'About' link, the .click() method checks if an element with the role of 'link' and the name 'About' exists within the navigation, and then it clicks on that element. BUT it does not check whether the link leads to a specific destination!

Checking a Link to an External Page

There was no error for the About link, but then why did I get the error about the Blog link? The clue was in the last three lines of code:

const page2Promise = page.waitForEvent('popup');

await page.getByRole('navigation').getByRole('link', { name: 'Blog' }).click();

const page2 = await page2Promise;

Enter fullscreen mode Exit fullscreen mode

When a page is opened by a target="_blank" link, we get a reference to it by listening to the popup event on the page. The waitForEvent() method waits for the popup to happen within a given timeout. If the popup event doesn't occur, Playwright will throw an error.

One caveat: the waitForEvent() method and the popup event help confirm the link's functionality by triggering its action, yet they don't verify if the link navigates to a specific URL. To make sure the link led to my blog page, I had to add additional lines of code. I also personalized the code by renaming the popup promise variable:

const blogPromise = page.waitForEvent('popup');

await page.getByRole('navigation').getByRole('link', { name: 'Blog' }).click();

const blog = await blogPromise;

// WAIT FOR THE BLOG PAGE TO LOAD, THEN CHECK URL AND TITLE
await blog.waitForLoadState();
await expect(blog).toHaveURL('https://dev.to/corinamurg');
await expect(blog).toHaveTitle('Corina: Web is for Everyone - DEV Community');

Enter fullscreen mode Exit fullscreen mode

Checking the Link to an Internal Page

As I mentioned above, using .click() is a necessary start, but not sufficient on its own. We have to add extra checks or assertions to verify the full functionality of a link.

For my (internal) navbar links, I added assertions for all the URLs and a check for the 'About' page that a certain text was visible:

await page.getByRole('navigation').getByRole('link', { name: 'Projects' }).click();
await expect(page).toHaveURL('https://corinamurg.netlify.app/projects');

await page.getByRole('navigation').getByRole('link', { name: 'Accessibility' }).click();
await expect(page).toHaveURL('https://corinamurg.netlify.app/accessibility');

await page.getByRole('navigation').getByRole('link', { name: 'About' }).click();
await expect(page).toHaveURL('https://corinamurg.netlify.app/about');
await expect(page.getByText('My Career in a Nutshell')).toBeVisible();
Enter fullscreen mode Exit fullscreen mode

Conclusion

What should you focus on while in codegen mode?

First, decide on what tests you want to automate. Then, when using the codegen feature, interact with those elements of your web application that are relevant to the test you want to automate.

The idea is to mimic the actions a real user would perform to achieve a certain task or navigate through a particular flow in your application. The code generated by Playwright will reflect these interactions, creating a baseline script.

I ❤️ how the codegen feature significantly simplifies the initial setup of a test, especially for those who are new to writing test scripts (moi!). I don't have to write code from scratch and I can quickly get started. But of course, as I shared above, the auto-generated code has to be refined and expanded upon to create comprehensive automated tests. For that, don't forget to make use of the documentation!

So, what are you waiting for? Start playing! 🎭

Coming up: testing for accessibility!

Note: My site is still in construction, so expect to find UI and accessibility bugs/errors beyond those tested here.

Resources

Debbie O’Brien’s Playwright Series on dev.to

Playwright Documentation

Image credit: Photo by Alex Kondratiev

Description: The image shows a hand pouring a blue liquid from a glass test tube into a flask with red liquid, and another hand pouring a green liquid into the flask. The background is plain white.

Top comments (0)