1

In Playwright (Like many other automation frameworks) you can create page objects. Using an example from Playwrights documentation: https://playwright.dev/docs/test-fixtures#without-fixtures

You have a .spec file that looks like this (The actual page object class itself can be seen above, not posting it just because it's long):

const { test } = require('@playwright/test');
const { TodoPage } = require('./todo-page');

test.describe('todo tests', () => {
  let todoPage;

  test.beforeEach(async ({ page }) => {
    todoPage = new TodoPage(page);
    await todoPage.goto();
    await todoPage.addToDo('item1');
    await todoPage.addToDo('item2');
  });

  test.afterEach(async () => {
    await todoPage.removeAll();
  });

  test('should add an item', async () => {
    await todoPage.addToDo('my item');
    // ...
  });

  test('should remove an item', async () => {
    await todoPage.remove('item1');
    // ...
  });
});

However I wonder in such a case is there really a need to re-create the page object before each test? Wouldn't creating the page object once be good enough? (Since we would have access to all the methods/etc... and those shouldn't be changing between tests?

Is there any reason to re-create a page object for each test?

0

2 Answers 2

3

Use beforeAll to instantiate page object so that all tests in a file can share the page object as todoPage is suite level variable declared outside any test.

test.beforeAll(async ({ page }) => {
    todoPage = new TodoPage(page);
  });

The Playwright Docs suggest to use as beforeEach to promote test isolation so that tests can be run in parallel as they should be absolutely independent.

Sign up to request clarification or add additional context in comments.

6 Comments

Thats sort of what I assumed you should do, so I was curious why the official docs had them as beforeEach
The reason playwright docs suggest that to promote test isolation so that they can also be run in parallel.
Thats a good point. But even with beforeAll wouldn't it still not matter? Since we aren't really doing anything besides using methods/locators (and therefore aren't really "sharing" anything between the tests)
I faced a problem where I shared an "orderID" on class level and incidentally changed that value in one of the tests and many other tests started failing for no reason. Eventually it turned out that unexpected value was causing the problem.
Good point. I guess that could happen if you are passing values to any of the methods (for filling out forms/etc...). I guess the object is destroyed at the end of each block anyways so execution time doesn't really matter anyways.
|
0

We can create static PageObjects like:

class StaticPageObject() {
  // no constructor

  static clickSomeBtn(page) {
   // now page should be feed to the PO methods
   page.locator("some-static-selector").click()
  }
}

With this we can use PageObject methods like:

StaticPageObject.clickSomeBtn(page) // no initialization required

If page is made global (which is not a good approach), then,

class StaticPageObject() {
  // no constructor

  static clickSomeBtn() {
   // now page should be feed to the PO methods
   global.page.locator("some-static-selector").click()
  }
}

3 Comments

Static methods act as global variables which in general a bad approach as they are against the core philosophy of OOP as they violate base principles like data hiding, encapsulation.
Anything can access and modify them without explicit object initiation.
It is true that explicit object initiation is not required for Static variables or method invocation, but they do not act as global variables or methods, but they are scoped to the class.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.