microsoft / playwright

Playwright is a framework for Web Testing and Automation. It allows testing Chromium, Firefox and WebKit with a single API.
https://playwright.dev
Apache License 2.0
67.23k stars 3.7k forks source link

[Question] Handling mutlitab in PageObject Model #11055

Closed jithinjosejacob closed 2 years ago

jithinjosejacob commented 2 years ago

I am using Page Object Model for my tests using Playwright Test Runner and TypeScript

I have a scenario where i need to handle multitab

I am trying to access context inside one of the pages, so that i can work with new tab

But i am getting following error

TypeError: Cannot read properties of undefined (reading 'waitForEvent')

Is the below approach correct or is there any other way to handle this.

Base Page

const test = baseTest.extend<{
    shopifyAdminPage: ShopifyAdminPage;
    afterpayLoginPage: AfterpayLoginPage;
    afterpayAdminPage: AfterpayAdminPage;
    storePage: StorePage;
    consumerPage: ConsumerPage;
}>({
    shopifyAdminPage: async ({ page, request }, use) => {
        await use(new ShopifyAdminPage(page, request));
    },
    afterpayLoginPage: async ({ page, context }, use) => {
        await use(new AfterpayLoginPage(page, context));
    },
    afterpayAdminPage: async ({ page }, use) => {
        await use(new AfterpayAdminPage(page));
    },
    storePage: async ({ page }, use) => {
        await use(new StorePage(page));
    },
    consumerPage: async ({ page }, use) => {
        await use(new ConsumerPage(page));
    },
});

export default test;

Master Page

export class MasterPage {

    readonly page: Page;
    context: BrowserContext;

    constructor(page: Page, context: BrowserContext) {
        this.page = page;
        this.context = context;
    }
}

AfterpayLoginPage

export class AfterpayLoginPage extends MasterPage {
    page: Page;

    context: BrowserContext

    constructor(page: Page, context:BrowserContext) {
        super(page, context);
        this.page = page;
        this.context= context
        webActions = new WebActions(this.page);
    }

    // Login to Admin.
    async loginToAfterpayAdmin() {
        await webActions.navigateToURL(url);

        const [newPage] = await Promise.all([
            this.context.waitForEvent('page'),
            this.page.click('a[target="_blank"]') // Opens a new tab
          ])
        await newPage.waitForLoadState();
        console.log(await newPage.title());
     }
}
yury-s commented 2 years ago

TypeError: Cannot read properties of undefined (reading 'waitForEvent')

It looks like the context that you pass into AfterpayLoginPage is undefined or it gets reset to undefined before calling this.context.waitForEvent. Is afterpayLoginPage a test fixture? Can you share its code?

jithinjosejacob commented 2 years ago

@yury-s - i have updated the initial message with the whole script

yury-s commented 2 years ago

The code looks correct, it appears that AfterpayLoginPage.context gets cleared at some point after the object is constructed but it's hard to tell for sure without seeing full code and the error. Can you please provide a repro?

Is there a reason you redefine page and context fields in AfterpayLoginPage when they already exist in the superclass?

jithinjosejacob commented 2 years ago

i have removed the redinition of page and context and defined context for every fixture. Now i am able to access the context properly in the tests. Only problem i am seeing right now is when i open a new tab ,it opens up a new window instead of a new tab in existing browser (but tab2 opened has the same cache and cookies as that of tab1). i will raise this a seperate question for this with a repro