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...
});
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/');
})
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;
});
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;
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');
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();
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
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)