当前位置: 首页 > 面试题库 >

多个浏览器和页面对象模式

乜建柏
2023-03-14
问题内容

我们正在使用 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;

在单浏览器测试中,非常清楚如何使用它:

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
    });
});

但是,当涉及到实例化多个浏览器并且需要在单个测试中在它们之间进行切换的测试时,变得不清楚如何在多个浏览器中使用同一页面对象:

describe("Login functionality", function () {
    var scope = {};

    beforeEach(function () {
        browser.get("/#login");

        scope.page = new LoginPage();
    });

    it("should warn there is an opened session", function () {
        scope.page.username.clear();
        scope.page.username.sendKeys(login);
        scope.page.password.sendKeys(password);
        scope.page.loginButton.click();

        // assert we are logged in

        // fire up a different browser and log in
        var browser2 = browser.forkNewDriverInstance();

        // the problem is here - scope.page.username.clear() would be applied to the main "browser"
    });
});

问题:

分叉新浏览器后,如何使用相同的Page Object字段和函数,但将其应用于新实例化的浏览器(browser2在这种情况下)?

换句话说,element()此处的所有调用都将应用于browser,但需要应用于browser2。我们如何切换上下文?

想法:

  • 一种可能的方法是在的情况下临时[重新定义全局element=browser2.element``browser2。这种方法的问题在于,browser.wait()在页面对象函数内部也有调用。这意味着也browser = browser2应该设置。在这种情况下,我们需要记住browser临时变量中的全局对象,并在切换回主browser上下文后将其还原。

  • 另一种可能的方法是将浏览器实例传递给page对象,例如:

    var LoginPage = function (browserInstance) {
    browser = browserInstance ? browserInstance : browser;
    var element = browser.element;
    
    // ...
    

    }

但这可能需要更改我们拥有的每个页面对象。

希望问题清楚-让我知道是否需要澄清。


问题答案:

看我的解决方案。我简化了示例,但是我们在当前项目中使用了这种方法。我的应用程序具有两种用户权限类型的页面,并且我需要在两种浏览器中同时执行一些复杂的操作。我希望这可以向您展示一些新的更好的方法!

"use strict";

//In config, you should declare global browser roles. I only have 2 roles - so i make 2 global instances
//Somewhere in onPrepare() function
global.admin = browser;
admin.admin = true;

global.guest = browser.forkNewDriverInstance();
guest.guest = true;

//Notice that default browser will be 'admin' example:
// let someElement = $('someElement'); // this will be tried to be found in admin browser.



class BasePage {
    //Other shared logic also can be added here.
    constructor (browser = admin) {
        //Simplified example
        this._browser = browser
    }
}

class HomePage extends BasePage {
    //You will not directly create this object. Instead you should use .getPageFor(browser)
    constructor(browser) {
        super(browser);

        this.rightToolbar = ToolbarFragment.getFragmentFor(this._browser);
        this.chat = ChatFragment.getFragmentFor(this._browser);
        this.someOtherNiceButton = this._browser.$('button.menu');
    }

    //This function relies on params that we have patched for browser instances in onPrepare();
    static getPageFor(browser) {
        if (browser.guest) return new GuestHomePage(browser);
        else if (browser.admin) return new AdminHomePage(browser);
    }

    openProfileMenu() {
        let menu = ProfileMenuFragment.getFragmentFor(this._browser);
        this.someOtherNiceButton.click();

        return menu;
    }
}


class GuestHomePage extends RoomPage {
    constructor(browser) {
        super(browser);
    }

    //Some feature that is only available for guest
    login() {
        // will be 'guest' browser in this case.
        this._browser.$('input.login').sendKeys('sdkfj'); //blabla
        this._browser.$('input.pass').sendKeys('2345'); //blabla
        this._browser.$('button.login').click();
    }
}


class AdminHomePage extends RoomPage {
    constructor(browser) {
        super(browser);
    }

    acceptGuest() {
        let acceptGuestButton = this._browser.$('.request-admission .control-btn.admit-user');
        this._browser.wait(EC.elementToBeClickable(acceptGuestButton), 10000,
                'Admin should be able to see and click accept guest button. ' +
                'Make sure that guest is currently trying to connect to the page');

        acceptGuestButton.click();
        //Calling browser directly since we need to do complex action. Just example.
        guest.wait(EC.visibilityOf(guest.$('.central-content')), 10000, 'Guest should be dropped to the page');
    }

}

//Then in your tests
let guestHomePage = HomePage.getPageFor(guest);
guestHomePage.login();
let adminHomePage = HomePage.getPageFor(admin);
adminHomePage.acceptGuest();
adminHomePage.openProfileMenu();
guestHomePage.openProfileMenu();


 类似资料:
  • 我正在编写一个使用水豚和网页对象模型的网络应用程序的框架。这是我第一次编写自己的框架并使用PoM进行自动化。 我的基本“页面对象”本质上是初始化驱动程序,并在每个其他页面对象子类中使用(用于各个页面) 在PoM的大多数示例中,我看到返回该页面对象实例的方法,但通常它们使用一些传递的实例变量。在我的测试脚本中,我简单地通过调用Base page对象类的一个实例,然后然后创建另一个的新实例通过页面对象

  • JavaScript可以获取浏览器提供的很多对象,并进行操作。 window window对象不但充当全局作用域,而且表示浏览器窗口。 window对象有innerWidth和innerHeight属性,可以获取浏览器窗口的内部宽度和高度。内部宽高是指除去菜单栏、工具栏、边框等占位元素后,用于显示网页的净宽高。 兼容性:IE<=8不支持。 'use strict'; ---- // 可以调整浏览器

  • ECMAScript 是 JavaScript 的核心,但如果要在 Web 中使用 JavaScript,那么 BOM(浏览器对象模型)则无疑才是真正的核心。BOM 提供了很多对象,用于访问浏览器的功能,这些功能与任何网页内容无关。多年来,缺少事实上的规范导致 BOM 有很多问题,因为浏览器提供商会按照各自的想法随意去扩展它。W3C 为了把浏览器中 JavaScript 最基本的部分标准化,已经将

  • 我想在我的页面对象中使用剧作家的定位器。我找到了一个Javascript示例(为了简洁起见,将其剥离): 试图在我的Java代码中做同样的事情: 引发空指针异常,因为初始化登录按钮时,尚未启动。 我可以 但是对于大型页面对象类来说,这将变得有点冗长/混乱。 有没有关于如何在Java中实现这一点的想法? 谢谢

  • 页面浏览分为两部分: 时间/页面筛选 和 页面浏览详情 1.时间/页面筛选 1)便捷按钮有今日、昨日、前日、上周 X、近七天 2)能自定义选择时间段,同时能搜索出个别字眼的页面来得出想要的结果报表 2.页面浏览详情 1)页面浏览,是指被浏览的网页,点击表头可以按相应的项目排序 2)如有需要,亦可点击下载当前报表及更多数据下载,将报表下载到个人电脑,以供存档及分析 3)点击 [细] 可查看访

  • 本文向大家介绍如何创建ajax对象并兼容多个浏览器,包括了如何创建ajax对象并兼容多个浏览器的使用技巧和注意事项,需要的朋友参考一下 这篇文章主要介绍了如何创建ajax对象并兼容多个浏览器,需要的朋友可以参考下