我刚刚开始使用WebDriver,我正在尝试学习最佳实践,特别是使用PageObjects和PageFactory.
我的理解是,PageObjects应该在网页上公开各种操作,并将WebDriver代码与测试类隔离开来.通常,相同的操作可能导致导航到不同的页面,具体取决于所使用的数据.
例如,在此假设的登录方案中,提供管理员凭据会将您带到AdminWelcome页面,并且提供客户凭据会将您带到CustomerWelcome页面.
所以最简单的方法是公开两个返回不同PageObjects的方法...
package example;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
public class Login {
@FindBy(id = "username")
private WebElement username;
@FindBy(id = "password")
private WebElement password;
@FindBy(id = "submitButton")
private WebElement submitButton;
private WebDriver driver;
public Login(WebDriver driver){
this.driver = driver;
}
public AdminWelcome loginAsAdmin(String user, String pw){
username.sendKeys(user);
password.sendKeys(pw);
submitButton.click();
return PageFactory.initElements(driver, AdminWelcome.class);
}
public CustomerWelcome loginAsCustomer(String user, String pw){
username.sendKeys(user);
password.sendKeys(pw);
submitButton.click();
return PageFactory.initElements(driver, CustomerWelcome.class);
}
} …Run Code Online (Sandbox Code Playgroud) 我们使用Page Object模式来组织我们的内部AngularJS应用程序测试.
这是我们拥有的示例页面对象:
var LoginPage = function () {
this.username = element(by.id("username"));
this.password = element(by.id("password"));
this.loginButton = element(by.id("submit"));
}
module.exports = LoginPage;
Run Code Online (Sandbox Code Playgroud)
在单浏览器测试中,很清楚如何使用它:
var LoginPage = require("./../po/login.po.js");
describe("Login functionality", function () {
var scope = {};
beforeEach(function () {
browser.get("/#login");
scope.page = new LoginPage();
});
it("should successfully log in a user", function () {
scope.page.username.clear();
scope.page.username.sendKeys(login);
scope.page.password.sendKeys(password);
scope.page.loginButton.click();
// assert we are logged in
});
});
Run Code Online (Sandbox Code Playgroud)
但是,当涉及多个浏览器实例化的测试并且需要在单个测试中在它们之间切换时,如何在多个浏览器中使用相同的页面对象变得不清楚:
describe("Login functionality", function () {
var scope = {};
beforeEach(function () …Run Code Online (Sandbox Code Playgroud) 我们一直在使用Page Object模式.它绝对有助于组织端到端测试并使测试更具可读性和清洁性.
由于使用页面对象来组织测试的量角器文档页面告诉我们,我们定义每一页对象作为一个功能及使用方法new为"实例"吧:
"use strict";
var HeaderPage = function () {
this.logo = element(by.css("div.navbar-header img"));
}
module.exports = HeaderPage;
Run Code Online (Sandbox Code Playgroud)
用法:
"use strict";
var HeaderPage = require("./../po/header.po.js");
describe("Header Look and Feel", function () {
var header;
beforeEach(function () {
browser.get("/#login");
header = new HeaderPage();
});
it("should show logo", function () {
expect(header.logo.isDisplayed()).toBe(true);
});
});
Run Code Online (Sandbox Code Playgroud)
但是,最近在量角器:角度测试变得简单的谷歌测试博客帖子,我注意到页面对象被定义为一个对象:
var angularHomepage = {
nameInput : element(by.model('yourName')),
greeting : element(by.binding('yourName')),
get : function() {
browser.get('index.html');
},
setName : …Run Code Online (Sandbox Code Playgroud) 当我尝试使用class = "country name"在页面对象中有空格的类名时,我得到:
Compound class names not permitted Selenium::WebDriver::Error::UnknownError)
Run Code Online (Sandbox Code Playgroud)
如何使用具有空格的类名.
例如:
class = "country name"
Run Code Online (Sandbox Code Playgroud) 只要我使用PageObject模式,我就想知道在哪里等待动态页面上的元素.假设我们有测试方法和pageObject类.我应该做什么(在测试方法中):
或者也许有其他好的做法等待元素?也许我们应该等待PageObject.class中的方法isElementDisplayed中的元素?
我正在尝试学习PageFactory模型.我理解这样一个事实,当我们这样做时initElements,WebElements就位于其中.比如说,我点击了一个webelement,因此DOM中的其他一个元素发生了变化.现在,显然我会在StaleElementReferenceException这里得到一个.我该如何解决这个问题?
我是否应该再次发现特定的WebElement知道DOM中的WebElement属性可能发生了变化?还是有另一种方法来处理这个问题?
selenium pageobjects selenium-webdriver page-factory staleelementreferenceexception
关于selenium webdriver中页面对象的快速问题.我们的网站非常动态,有很多ajax和各种身份验证状态.很难弄清楚如何定义每个页面对象但是我可以说我已经想出来并定义了几个代表我们网站的页面对象.
你如何处理页面之间的交叉.所以我得到了一个主页的页面对象,一个用于我的帐户页面,另一个用于我的结果页面.然后我需要编写一个遍历所有页面的测试来模拟执行多个操作的用户.
How do you say给我一个HomePage对象来创建一个新的用途 - >然后获取一个帐户页面对象去执行一些用户操作 - 然后得到一个结果页面对象来验证这些操作都来自一个脚本.
人们如何做到这一点?
谢谢
我正在使用PageFactory在Selenium WebDriver中为C#构建一个页面对象模型.
不幸的是,我发现FindsByAttribute不会初始化SelectElement(HTML <select>标签/下拉菜单).到目前为止,我已经碰巧或提出了一些想法来解决它,但它们都不是理想的:
PageFactory和FindsByAttribute是sealed的,所以我不能只继承那些它强制.SelectElement来自IWebElement在每个方法是相当混乱和重复的.它也忽略了明显的内置等待PageFactory和抛出NoSuchElementExceptions,除非我每次都添加一个等待 - 这需要在整个地方重复定位器,从而击败(部分)POM的目的.IWebElement属性包装每个属性SelectElement不那么混乱,但仍然具有与上面相同的等待问题.到目前为止,最好的选择是#3,为此编写一个包装SelectElement只会为每个方法添加一个等待.虽然这个解决方案可行,但它会大量增加每个页面的代码,而不是这个(假设的)漂亮的代码:
[FindsBy(How = How.Id, Using = "MonthDropdown")]
public SelectElement MonthDropdown;
Run Code Online (Sandbox Code Playgroud)
我坚持使用包装器包装(我宁愿避免使用),并且:
[FindsBy(How = How.Id, Using = "MonthDropdown")]
private IWebElement _monthDropdown;
public Selector MonthDropdown
{
get { return new Selector(MonthDropdown, Wait); }
}
Run Code Online (Sandbox Code Playgroud)
随着Selector作为SelectElement包装,也必须采取的IWait<IWebDriver>,因此它可以等待,和一个新的实例Selector访问它的每一次.
有没有更好的方法呢?
编辑:瞌睡放入错误的访问修饰符.固定.谢谢,@ JimEvans.
我们一直在广泛使用Protractor框架,并建立了一个相当大的测试代码库.我们也一直在关注Page Object模式来组织我们的测试.
最近,我们开始使用Galen框架填补视觉/布局/响应式设计测试的空白.我们非常喜欢这个框架,并希望继续使用它.
现在最大的问题是Page Objects.两个框架都有自己的定义页面对象的方法.
这是Protractor页面对象的示例:
var LoginPage = function () {
this.username = element(by.id("username"));
this.password = element(by.id("password"));
this.loginButton = element(by.binding("buttonText"));
};
module.exports = new LoginPage();
Run Code Online (Sandbox Code Playgroud)
而且,这是一个示例Galen页面对象:
this.LoginPage = $page("Login page", {
username: '#username',
password: '#password',
loginButton: 'button[ng-click*=login]'
});
Run Code Online (Sandbox Code Playgroud)
目前,我们正在复制定位器并重复自己 - 违反DRY原则.而且,另一个后续问题是Galen目前仅支持"by css","by id"或"by xpath"定位技术 - 这意味着页面对象不会一对一地映射.
有没有办法避免重复将Protractor和Galen结合在一起的页面对象和元素定位器?
我刚刚进入了 puppeteer 和 jest 的测试世界,我想知道在文件夹架构和逻辑方面的最佳实践是什么。
我以前从未做过测试,我认为我对不同的原则和概念以及它们如何组合在一起有点迷失。
我学会了基于页面对象模型进行测试,因此我为每个页面以及每个模块(或组件)都有类。例如,在我的应用程序中,标题或登录模式是组件。
然后我每个页面或每个组件都有一个测试文件。(例如landingPage.tests.js文件,它使用文件中LandingPage类的模型LandingPage.js)
这是一个具体的例子:我有不同的登录案例,我想测试它们。例如,我想测试与“普通”用户的连接,该过程只是登录然后输入密码。然后,我需要与已激活 2FA 的用户或使用 SSO 的公司的用户进行测试。
我首先考虑将我的不同测试放在authentication.tests.js不同的describe块中,认为它每次都会打开一个新标签,但它没有......我在隐身模式下使用 puppeteer 来确保每个标签都是一个独立的会话。
所以我的问题是:
哪里是做这些测试套件的最佳地点?
我是否应该拥有“描述”页面的测试文件(例如,按钮必须存在,此类文本必须在此处等)并且还有“场景类型”测试文件(对用户的一组上下文操作,例如对于我不同的登录情况)?
这是authentication.tests.js,我想测试我所有不同的登录方式:
import HeaderComponent from "../../../pages/components/HeaderComponent";
import AuthenticationComponent from "../../../pages/components/AuthenticationComponent";
import LandingPage from "../../../pages/landing/LandingPage";
import {
JEST_TIMEOUT,
CREDENTIALS
} from "../../../config";
describe('Component:Authentication', () => {
let headerComponent;
let authenticationComponent;
let landingPage;
beforeAll(async () => {
jest.setTimeout(JEST_TIMEOUT);
headerComponent = new HeaderComponent;
authenticationComponent = new AuthenticationComponent;
landingPage = new LandingPage;
});
describe('Normal login ', …Run Code Online (Sandbox Code Playgroud) pageobjects ×10
selenium ×7
javascript ×3
protractor ×3
testing ×3
webdriver ×3
java ×2
angularjs ×1
c# ×1
galen ×1
jestjs ×1
page-factory ×1
puppeteer ×1