英文:
Playwright How To Return page from a function that creates a browser context?
问题
以下是您要翻译的内容:
我正在尝试创建一个函数,该函数打开浏览器并使用基本身份验证登录页面。我希望该函数返回页面,以便我可以在测试中使用它并继续使用它。
当我将`browser`传递给函数时,我需要在函数内部创建一个新的上下文,以便我可以使用基本身份验证登录。
在函数中创建一个新的浏览器上下文可以正常打开页面并登录。
问题在于我无法从函数中返回新页面。从函数返回的页面没有智能提示,并在我尝试以正常方式使用它时失败,例如执行`page.locator('#id1').click()`,导致测试失败。
// 自定义打开浏览器登录功能
export async function openBrowserAndLogin(browser, username, password){
const context = await browser.newContext({
httpCredentials:{
username: username,
password: password
},
})
const page = await context.newPage()
await page.goto('websiteurl.com')
return page
}
// 测试
import { test } from '@playwright/test';
import {openBrowserAndLogin} from '../customfunctions.openBrowser.mjs';
test('登录并执行操作', async ({ browser }) => {
const page = openBrowserAndLogin(browser,'user1', 'secretpassword')
page.locator('#account').click() // 此页面对象上没有任何方法???测试失败
})
希望这有所帮助。如果您需要更多信息,请随时提问。
英文:
I am trying to make a function that opens the browser and logs into the page using basic auth. I would like the function to return the page so I can pick it up in the test and continue to use it.
When I pass browser
to the function I need to create a new context inside the function so I can login with basic auth.
Creating a new browser context in the function works fine to open the page and login.
The problem is that I cannot return the new page from the function. The page that is returned from the function has no intellisense and fails when I attempt to use it in the normal way --- such as doing: page.locator('#id1').click()
---> test fails
// Custom Open Browser Login Function
export async function openBrowserAndLogin(browser, username, password){
const context = await browser.newContext({
httpCredentials:{
username: username,
password: password
},
})
const page = await context.newPage()
await page.goto('websiteurl.com')
return page
}
// Test
import { test } from '@playwright/test';
import {openBrowserAndLogin} from '../customfunctions.openBrowser.mjs'
test('login and do stuff', async ({ browser }) => {
const page = openBrowserAndLogin(browser,'user1', 'secretpassword')
page.locator('#account').click() // no methods exist on this page object???? Test Fail
})
So basically I am importing a function into the test. I pass the browser to the function. The function uses browser to create a new context, logs into application, and returns a new page.
The page returned from the function is dead.
Does anyone know a way to return a page from a context created inside an imported function?
Or if there is some other way to accomplish this that would be helpful too.
答案1
得分: 3
openBrowserAndLogin
不是一个好的模式。这会放弃对浏览器上下文对象的引用,因此您永远无法关闭它,从而导致内存泄漏并可能使进程挂起(除非测试套件以不友好的方式为您终止它)。
相反,建议让 Playwright 管理 page
:
test('登录并执行操作', async ({ page }) => {
// ^^^^
现在,您可以使用 Playwright 的 config 或 test.use
来添加凭据:
import {test} from "@playwright/test"; // ^1.30.0
test.describe("带有凭据", () => {
test.use({
httpCredentials: {
username: "user1",
password: "secretpassword"
}
});
test("登录并执行操作", async ({page}) => {
await page.goto("https://example.com/");
await page.locator("#account").click();
});
});
请注意,我使用了 await
来等待 page.locator('#account').click()
。
另一个选项是使用 fixtures。
英文:
openBrowserAndLogin
is not a good pattern. This abandons the reference to the browser context object so you can never close it, thereby leaking memory and potentially hanging the process (unless the test suite ungracefully terminates it for you).
Instead, prefer to let Playwright manage the page
:
test('login and do stuff', async ({ page }) => {
// ^^^^
Now you can add credentials with Playwright's config or test.use
:
import {test} from "@playwright/test"; // ^1.30.0
test.describe("with credentials", () => {
test.use({
httpCredentials: {
username: "user1",
password: "secretpassword"
}
});
test("login and do stuff", async ({page}) => {
await page.goto("https://example.com/");
await page.locator("#account").click();
});
});
Notice that I've await
ed page.locator('#account').click()
.
Another option is to use fixtures.
答案2
得分: 3
你只是缺少await
。
openBrowserAndLogin
是一个async
函数,因此它返回一个Promise,不会具有页面方法本身。你需要首先解包它,就像这样:
const page = await openBrowserAndLogin(browser, 'user1', 'secretpassword')
话虽如此,如果你需要每个测试都进行相同的登录,我绝对建议使用带有storageState的全局设置中进行身份验证,然后只使用page
fixture,或者你还可以覆盖page
fixture或添加自己的fixture等。还有其他潜在的方法。但就你的情况而言,只缺少这一小部分。
请注意,如果你手动创建上下文,最好是close
你的上下文。
英文:
You’re just missing await
.
openBrowserAndLogin
is an async
function, so it’s returning a promise, which wouldn’t have the page methods itself. You need to unwrap it first, like so:
const page = await openBrowserAndLogin(browser,'user1', 'secretpassword')
That being said, I would definitely recommend doing the auth in global setup with storageState if you need the same login for every test and then just use the page
fixture, or you could always override the page
fixture or add your own or something similar. There are other potential ways too. But for what you have, just that small piece was missing.
Note that it’s also good practice to close
your context if you manually create one.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论