0

Using Python Playwright and Page Object Model

Scenario: Clicking a link opens a new tab. Rest of the oprations needs to be performed in new page.

Without Page Object model: I was able to accomplish this. Code below:

    def run(playwright:Playwright) -> None:
    browser = playwright.chromium.launch()
    context = browser.new_context()
    page= context.new_page()
    page.goto(URL)
with context.expect_page as Account_setup_page:
     accountSetup_link.click()
new_page = Account_setup_page.value
startaccount = new_page.locator('<<Xpath>>')

Above code is working fine, since the browser context is in the same code file.

Now, using page object model: Need some direction on how should we switchto new tab?

conftest.py file has the context reference:

@pytest.fixture(scope="function")
def accsetup(request,playwright)
    browser=playwright.chromium.launch()    
    context=browser.new_context()
    page=context.new_page()
    page.goto(URL)
    yield page
    context.close()
    browser.close()

Now, in the page code file:

filename: AccountSetupE2E.py
class AccountSetup:
     def __init__(self,page)
     self.page = page
     self.username = page.locator(<<Xpath>>)
     self.pwd = page.locator(<<Xpath>>)
     self.login = page.locator(<<Xpath>>)
  def fillaccountdetails(self):
      self.username.fill("test")
      self.pwd.fill("testpwd")
      self.login.click()

Once login is successful, clicking on accountSetup_link will open new tab. I am unable to figure out a way to reference the new tab to perform accountsetup operations.

Application URL is opening..but unable to click even on username. It worked, when context was not returned. Only for this scenario, I need to use new tab to validate the test case.

I tried below and its not working:

contest.py:
@pytest.fixture(scope="function")
def accsetup(request,playwright)
    browser=playwright.chromium.launch()    
    context=browser.new_context()
    page=context.new_page()
    page.goto(URL)
    yield page,context
    context.close()
    browser.close()

filename: AccountSetupE2E.py
class AccountSetup:
     def __init__(self,page,context)
     self.page = page
     self.context=context
     self.username = page.locator(<<Xpath>>)
     self.pwd = page.locator(<<Xpath>>)
     self.login = page.locator(<<Xpath>>)
     self.accountSetup_link =page.locator(<<xpath>>)
     with context.expect_page() as Account_setup_page:
          self.accountSetup_link.click()
    new_page = Account_setup_page.value
    self.startaccount = new_page.locator('<<Xpath>>')
     
  def fillaccountdetails(self):
      self.username.fill("test")
      self.pwd.fill("testpwd")
      self.login.click()
      self.startaccount .click()
  TestCasefile -> Test_Accountsetup.py
  class Test_accsetup:
  def test_accSetup(self,accsetup):
      page,context=acc_setup
      acpage = acc_setup(page,context)
      acpage.fillaccountdetails()


     



      
2
  • Indentation won't compile. I suggest providing runnable, syntactically correct code to reduce the burden on answers and eliminate potential confusion. Paste the code verbatim and add 3 backticks around each block, without messing with the code once it's in the textarea. Also provide the site this is automating, so others can reproduce the problem. See minimal reproducible example. Thanks Commented Oct 25, 2024 at 5:30
  • Check context.pages. That should be a list containing the tabs. Your page objects could have an url or something which may be used to test against if the tab matches the page object. Or you can just index the tabs and map your page objects that way if your project is simple enough. Commented Nov 26, 2024 at 21:54

2 Answers 2

0

Sadly playwright does not have a concept of "active tab" so you can't just switch tab like you could in selenium. Playwright has a page pool (tabs).

A sophisticated solution would be a get_page_object method which could map the appropriate page to your page object model. That requires some kind of attribute or classmethod on the page object, like page url or page state.

So if your AccountSetup page ends with /AccountSetup and the opened TestAccountSetup page ends with /TestAccountSetup then you can add these url values to them as url. Then check if the rule for the page object matches any tab ("page" in playwright terminology).

like

def get_tab_for(context, page_object):
    for page in context.pages:
        if page_object.url in page.url:
            return page_object(page, context)
    raise ValueError(f'Could not map {page_object} for any tab')

so you could

account_setup_page_instance = get_tab_for(context, AccountSetup)
account_setup_page_instance.fillaccountdetails()

later on.

But you could do a method which checks all the tabs and auto maps them to a page object by url or other rule. So you could do things like account_setup_page_instance = page_mapping[AccountSetup]

The base idea is that you need to introduce some kind of rule, how the program should know what makes a specific page object that given page object.

The get_tab_for implementation above is the most basic one, which may be good enough if you have just a few pages and your project is simple. You can use regex for matching or even locators on the page. I used to work on a single page app where the url was not good enough and I had to parse the page metadata to know which page object should be used. Its up to the project what fits for you.

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

Comments

0

try using this approach for working with new tabs:

contest.py:
@pytest.fixture(scope="function")
def accsetup(request,playwright)
    browser=playwright.chromium.launch()    
    context=browser.new_context()
    page=context.new_page()
    page.goto(URL)
    yield page,context
    context.close()
    browser.close()

filename: login.py
class Login:
     def __init__(self,page,context)
     self.page = page
     self.context=context
     self.accountSetup_link = page.locator(<<xpath>>)

filename: AccountSetupE2E.py
class AccountSetup:
     def __init__(self,page,context)
     self.page = page
     self.context=context
     self.username = page.locator(<<Xpath>>)
     self.pwd = page.locator(<<Xpath>>)
     self.login = page.locator(<<Xpath>>)
     self.startaccount = page.locator('<<Xpath>>')
     
  def fillaccountdetails(self):
      self.username.fill("test")
      self.pwd.fill("testpwd")
      self.login.click()
      self.startaccount .click()
  
TestCasefile -> Test_Accountsetup.py
  class Test_accsetup:
  def test_accSetup(self,accsetup):
      page,context=acc_setup

      login = Login(page,context)

      with context.expect_page() as new_tab:
          login.accountSetup_link.click()
      tab = new_tab.value
      acc_setup = AccountSetup(tab, context)
      
      acc_setup.fillaccountdetails()

1 Comment

As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.

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.