假设我有一个包含页面对象的类。如果我在测试中实例化该类,那么我可以像通常使用剧作家一样使用页面对象。我想从这些页面对象之一获取 css 值作为字符串,以便我可以在自定义函数中使用它。
这应该让你明白我的意思
export class PageObjects{
constructor(page){
this.obj1 = page.locator('#table tbody tr')
}
}
test('Get Values and header names from a table', async({page})=> {
// Page objects
const pageObjects = new PageObjects(page)
// I want the css from the page object?? in other words
// how do I pull out the '#table tbody tr' css value as a string?
// in other words I want cssString value to be #table tbody tr
// I have tried _selector but it just returns an empty string
cssString = pageObjects.obj1.??????
})
有没有办法从定位器中获取 css 值?
测试不应直接暴露在定位器上。
使用页面对象模型这是一个软件设计模式更好的代码抽象,可重用性和长期维护。
在页面对象模型中,所有应用程序功能都以页面对象方法的形式捕获为黑框,它还封装了 UI 对象(CSS/Xpath),以便可以从单个引用位置添加或更新它们- DRY原则。
完整代码示例:
页面对象:
// playwright-dev-page.js
const { expect } = require('@playwright/test');
exports.PlaywrightDevPage = class PlaywrightDevPage {
/**
* @param {import('@playwright/test').Page} page
*/
constructor(page) {
this.page = page;
this.getStartedLink = page.locator('a', { hasText: 'Get started' });
this.gettingStartedHeader = page.locator('h1', { hasText: 'Installation' });
this.pomLink = page.locator('li', { hasText: 'Guides' }).locator('a', { hasText: 'Page Object Model' });
this.tocList = page.locator('article div.markdown ul > li > a');
}
async goto() {
await this.page.goto('https://playwright.dev');
}
async getStarted() {
await this.getStartedLink.first().click();
await expect(this.gettingStartedHeader).toBeVisible();
}
async pageObjectModel() {
await this.getStarted();
await this.pomLink.click();
}
}
测试:
// example.spec.js
const { test, expect } = require('@playwright/test');
const { PlaywrightDevPage } = require('./playwright-dev-page');
test('getting started should contain table of contents', async ({ page }) => {
const playwrightDev = new PlaywrightDevPage(page);
await playwrightDev.goto();
await playwrightDev.getStarted();
await expect(playwrightDev.tocList).toHaveText([
`How to install Playwright`,
`What's Installed`,
`How to run the example test`,
`How to open the HTML test report`,
`Write tests using web first assertions, page fixtures and locators`,
`Run single test, multiple tests, headed mode`,
`Generate tests with Codegen`,
`See a trace of your tests`
]);
});
test('should show Page Object Model article', async ({ page }) => {
const playwrightDev = new PlaywrightDevPage(page);
await playwrightDev.goto();
await playwrightDev.pageObjectModel();
await expect(page.locator('article')).toContainText('Page Object Model is a common pattern');
});
我不确定我是否遵循了这种模式的动机(剧作家已经有了一个
Page
抽象——你为什么要用另一个来包装它?)它闻起来像一个潜在的xy问题,但我不不明白为什么你不能在你的实例上将该参数设置为变量:
export class PageObject {
constructor(page) {
this.selector = '#table tbody tr';
this.locator = page.locator(this.selector);
}
}
// ...
const pageObject = new PageObject();
consolelog(pageObject.selector);
我冒昧地重命名了几个变量:复数通常是指集合,如数组和对象,所以
PageObjects
会被键入PageObject[]
,而obj1
是一个不清楚的名字。我不喜欢在每个类名后加上“对象”,但我不太确定它应该做什么,所以我不知道一个更好的名字。
硬编码那个选择器有点奇怪。这有效地使该类仅用于单一用途,因此您可以考虑将其作为参数,具体取决于您的用例。
我建议退后一步,从上到下重新设计您的设计。从您的目标出发,询问这是否真的是实现这些目标的正确抽象。通常,如果事情看起来很难做,并且你发现你在与你的设计或语言作斗争,这可能不是正确的方法。
如果我理解错了,你想获取元素的CSS样式,你可以使用
getComputedStyle
:
await page.locator("#table tbody tr")
.evaluateAll(els => els.map(e => getComputedStyle(e));