Lesson ยท 25 min
Page objects
The problem with copied steps
Imagine 40 tests for the shop. Each one adds a product with the same four lines of code. One day the developers change the button text from Add to cart to Buy. Now you must change 40 tests.
A page object solves this. It is a class that knows how to use one page. It holds the locators and the steps of the page in one place. The tests call the steps by name.
A page object in JavaScript
A page object is a plain class. It gets the page in its constructor, and it saves the locators in properties.
class ShopPage {
constructor(page) {
this.page = page;
this.cards = page.getByTestId('product-card');
}
async addToCart(name) {
const card = this.cards.filter({ hasText: name });
await card.getByRole('button', { name: 'Add to cart' }).click();
}
}
A test makes one for its own page, and calls the methods:
test('adds a product', async ({ page }) => {
const shop = new ShopPage(page);
await shop.open();
await shop.addToCart('Blue Mug');
});
Now the test says what happens, and the class says how. When the button changes, you change one line in the class.
What belongs in a page object
- Locators. Save the locators that the tests use often, as properties.
- Steps. Add a method for each thing that a user does on the page:
search(text),addToCart(name),openCart(). - Waits. A step that changes the page should wait for its result, so that the next line of the test starts at a calm page. In
addToCart, wait for the confirmation text.
What does not belong in a page object
Assertions about the behavior that a test checks. The test says what must be true. The page object says how to get there. If you hide the expect calls in the class, a reader cannot see what the test checks. Return a locator from the class, and let the test check it.
It is fine for a page object to wait with an assertion, as open() does when it waits for the six products. That wait is part of "the page is ready".
Several pages
A real app has many pages. Make one class for each page, or for each large part of a page, such as a header or a dialog. A test can use several of them together.
Your turn
The file has a start of ShopPage. Add the steps, and write three tests that use them. Each test names a bug that the tests must catch.
Tasks
3 to do
Task 1, not checked yet. Add the method
addToCart(name)toShopPage. It finds the card of the product with that name, clicksAdd to carton it, and waits until the textAdded <name> to your cart.is visible. Then add a test namedshows the number of products in the cart. It usesShopPageto open the shop, addBlue MugandNotebook, and check thatcartCountshows1and then2.Task 2, not checked yet. Add the method
search(text)toShopPage. It fills the search box and pressesEnter. Add a test namedsearches without caring about casethat searches forLAMPand checks that there is one product card with the headingDesk Lamp.Task 3, not checked yet. Add the method
openCart()toShopPage. It clicks the link that has the textCart. Add a test namedships for free over 50 dollars. Add theBackpack, open the cart, and check that the shipping isFreeand the total is$59.00.
Task 1 of 3
Add the method addToCart(name) to ShopPage. It finds the card of the product with that name, clicks Add to cart on it, and waits until the text Added <name> to your cart. is visible. Then add a test named shows the number of products in the cart. It uses ShopPage to open the shop, add Blue Mug and Notebook, and check that cartCount shows 1 and then 2.