-
Notifications
You must be signed in to change notification settings - Fork 3.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Question] How to make test() use the same browser instance as the beforeAll. (Ignore test isolation) #14508
Comments
Doesn't this work for you? // my-test.ts
import { Page, test as base } from '@playwright/test';
interface MyFixtures {
myPage: Page;
}
export const myTest = base.extend<MyFixtures>({
myPage: async ({ browser }, use) => {
// Create page once and sign in.
const page = await browser.newPage();
await page.goto('https://github.com/login');
await page.fill('input[name="user"]', 'user');
await page.fill('input[name="password"]', 'password');
await page.click('text=Sign in');
use(page);
},
});
// example.spec.ts
myTest.describe('My suite', () => {
myTest('My test', async ({ myPage }) => {
await myPage.click('selector');
});
}); |
Unfortunately no. I am using a similar idea to this one When I go to the next test() it opens another browser instance instead of using the one created in beforeall. I did what you said in a different file and extended it changing the line 14 and 15 for the { browser }
|
Yeah, got it now. This might work then. But I don't know if it behaves as you wish for multiple test suites. // my-test.ts
import { Page, test as base } from '@playwright/test';
interface MyWorkerScopedFixtures {
myPage: Page;
}
export const myTest = base.extend<{}, MyWorkerScopedFixtures>({
myPage: [
async ({ browser }, use) => {
// Create page once and sign in.
const page = await browser.newPage();
await page.goto('https://github.com/login');
await page.fill('input[name="user"]', 'user');
await page.fill('input[name="password"]', 'password');
await page.click('text=Sign in');
use(page);
},
{ scope: 'worker' },
],
});
// example.spec.ts
myTest.describe('My suite', () => {
myTest('My test 1', async ({ myPage }) => {
await myPage.click('selector');
});
myTest('My test 2', async ({ myPage }) => {
await myPage.click('selector');
});
}); |
It always open a new browser instance. I have no idea why. Let me review my points:
// fixture-list.ts
const test = baseTest.extend<{
loginContext: LoginContext;
processPage: ProcessPage;
cranePage: CranePage;}>({
loginContext: async ({ browser }, use) => {
await use(new LoginContext(browser));
},
processPage: async ({ page }, use) => {
await use(new ProcessPage(page));
},
cranePage: async ({ page }, use) => {
await use(new CranePage(page));
},
// -------------------------------------------------
// test.spec.ts
test.beforeAll(async ({ loginContext }) => {
await loginContext.adminUser();
})
test('Test 1', async ({ processPage }) => {
await processPage.navigateToLibrary();
...
});
test('Test 2', async ({ cranePage }) => {
await cranePage.navigateToLibrary();
...
}); For any reason, it is always opening a new instance of the browser when it goes to the Test1, test2 ...
export default class LoginContext {
readonly context: Browser;
constructor(context: Browser) {
this.context = context;
}
async adminUser(): Promise<void> {
const page = await this.context.newPage();
await page.goto('/');
await page.fill(xxxx, xxxxx);
await page.fill(xxxxx, xxxx);
await page.click(xxxxx);
export class WebActions {
readonly page: Page;
constructor(page: Page) {
this.page = page;
}
async navigateToLibrary(url: string) {
await this.page.goto(url);
// and assert if the page was loaded properly
...
} Do you think that is something related for one being Page type and the other being Browser? Sorry for the stupid question, I am struggling a lot. |
@gegoncalves Check out this documentation entry on a single page re-use: https://playwright.dev/docs/test-retries#reuse-single-page-between-tests Would it help you? |
Thanks for the reply @aslushnikov . I tried to do that way, the problem is: I am using POM and fixtures. I don't know how to make all the pages to use the same the way I implemented it is going to 2 different browser instances:
I try to explain a little bit more here #14508 (comment) |
@gegoncalves yes, this way won't work. The only way forward for you is to re-use the single page like we explain in the documentation and to not use the
Since you re-use the same page, it'll be the context as well. Can you elaborate what's your problem? |
Now I got it. So my problem is exactly that: using My basic methods all are configured based on //common-actions.ts
export class generalActions{
readonly page: Page;
constructor(page: Page) {
this.page = page;
}
async navigateToURL(url: string) {
await this.page.goto(url);
}
async waitForElementAttached(locator: string): Promise<void> {
await this.page.locator(locator).waitFor();
}
async clickElement(locator: string): Promise<void> {
await this.waitForElementAttached(locator);
await this.page.locator(locator).click();
} So, when I use the beforeAll with the Do you recommend any workaround @aslushnikov ? |
@gegoncalves the workaround would be to use the 'single-page re-use pattern' and create POMs next to it. Like this: import { test, Page } from '@playwright/test';
test.describe.configure({ mode: 'serial' });
let page: Page;
let actions: generalActions;
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
actions = new generalActions(page);
});
test.afterAll(async () => {
await page.close();
});
test('runs first', async () => {
await actions.navigateToURL('https://playwright.dev/');
});
test('runs second', async () => {
await actions.clickElement('text=Get Started');
}); |
I got your point. We are using this way:
generalActions -> page file -> fixture -> test.spec.ts Ex: // fixtures-list.ts
import { test as baseTest } from "@playwright/test";
import ProcessPage from "@pages/ProcessPage";
import CranePage from "@pages/CranePage";
import LoginContext from "@pages/login-context";
const test = baseTest.extend<{
loginContext: LoginContext;
processPage: ProcessPage;
cranePage: CranePage;}>({
loginContext: async ({ browser }, use) => {
await use(new LoginContext(browser));
},
processPage: async ({ page }, use) => {
await use(new ProcessPage(page));
},
cranePage: async ({ page }, use) => {
await use(new CranePage(page));
},
//test.spec.ts
test.beforeAll(async ({ loginContext }) => {
await loginContext.adminUser();
})
test('check nav', async ({ processPage }) => {
await processPage.navigateToLibrary();
const modal = await processPage.addProcess();
expect(modal).toBeVisible(); Do you have any hint for this scenario @aslushnikov ? Thank you for helping me with this and sorry for disturb |
@gegoncalves i see what you do, but it won't work. It might be that I'm missing something: why don't you want to not use fixtures for your POM objects and instead have a global variable, like it's shown here? |
I don't know if I understood your question @aslushnikov correctly So you are asking to use a global variable instead of the custom fixtures? I was thinking to use the custom fixtures due to the fact of being easier to just call the related pages through fixtures per test case than create an instance of each used POM The async clickElement(locator: string): Promise<void> {
await this.page.locator(locator).waitFor();
await this.page.locator(locator).click();
} this method we use inside of each PO we have. Ex: // process-page.ts
...
async addProcess(): Promise<Locator> {
await generalActions.clickElement(list_locator);
await generalActions.clickElement(process_locator);
return this.getModal();
};
...
async getModal(): Promise<Locator> {
await generalActions.waitForElementAttached(tab_locator);
return generalActions.page.locator(MODAL_DIV);
}; And after we have the fixture creation for each page that I shown here Should I not use the custom fixture and just do every time a instance of each PO per test set file? Probably I am doing something stupid without noticing 😅 For real, thanks for giving your time to help me with that |
@gegoncalves Yeah, I'd do it without fixtures! It should work reliably in case of single-page re-use. |
I got it. I was thinking here: It will be nice if there was an option in the future to "turn off" a test() isolation using something in a beforeAll which allowed the usage of Maybe you are wondering why we are doing that. The reason is: we are trying to make a TC that use the same login instance to different steps (without the need of reuse signed in state / we just need the state for one TC and not the whole project), it is readable as test steps and generate reports that are easier for the devs to find the issue. We tried to use as
Do you think that is a possibility to improvements/fixes for the |
This does look like a bug; but would you mind filing a separate issue with a minimal repro for that? |
Yeap, I am gonna do it, no problem at all @aslushnikov . Regarding the |
Folding this into #14584! |
@gegoncalves |
Hi @msmith1114 I am not sure if I got your question: If you have a await it gonna fail there but will not be able to continue |
Hi @gegoncalves , |
@aslushnikov On the similar front, Any luck with your attemts @gegoncalves |
UPDATE: Check my comment #14508 (comment)UPDATE 2: Check my comment #14508 (comment)
I am trying to reuse the authentication example provided at the documentation for multiple .spec files (I know that is not recommended but it is necessary for my case)
Is there any recommendation of POM with fixture that I can do to solve that issue?
I want to avoid rewrite this part multiple times:
The text was updated successfully, but these errors were encountered: