如何设计量角器页面对象导航以避免" window.angular未定义"错误

时间:2017-06-23 16:30:27

标签: javascript protractor

我遇到了" window.angular未定义"错误,我确定它与JavaScript的异步执行有关,但我不知道如何解决这个问题。登录页面和初始登录页面是非Angular页面,应用程序的其余部分是Angular。因此,我需要使用非Angular页面登录,然后在加载非Angular登录页面后,打开下拉菜单并单击加载Angular页面的链接。似乎所有的操作都在飞,没有人在检查Angular是否加载之前等待导航完成。

我有这个页面对象的基类:

export class AbstractLoadable {

    constructor(isAngularComponent) {
        this.isAngularComponent = isAngularComponent;
    }

    initComponent() {

        console.log("Initializing: " + this.isAngularComponent);

        browser.waitForAngularEnabled(this.isAngularComponent);

        if(this.isAngularComponent) {
            console.log("Waiting for angular");
            browser.waitForAngular();
        }

        return this;
    }
}

我有这个登录页面:

import {AbstractLoadable} from "./AbstractLoadable";
import {HomePage} from "./HomePage";

export class LoginPage extends AbstractLoadable {

    constructor() {
        super(false);

        this.usernameInput = element(by.id("username"));
        this.passwordInput = element(by.id("password"));
        this.loginButton = element(by.css("[name='login']"));
    }

    load(baseUrl) {
        browser.driver.get(baseUrl);
        return this.initComponent();
    }

    login(username, password) {
        this.usernameInput.sendKeys(username);
        this.passwordInput.sendKeys(password);
        this.loginButton.click();

        return new HomePage().initComponent();

    }
}

我有这个主页:

import {AbstractLoadable} from "./AbstractLoadable";
import {LoginPage} from "./LoginPage";
import {AngularPage} from "./AngularPage";
import {ExtendedExpectedConditions} from "../ExtendedExpectedConditions";

export class HomePage extends  AbstractLoadable {

    constructor() {
        super(false);

        this.menuButton = element(by.id("some locator"));
        this.menuContainer = element(by.css("some locator"));
        this.menuOptionLink = element(by.css("some locator"));
    }

    isMenuButtonPresent() {
        return ExtendedExpectedConditions.isElementPresent(this.menuButton);
    }

    isMenuExpanded() {
        return ExtendedExpectedConditions.isElementDisplayed(this.menuContainer);
    }

    expandMenu() {
        this.isMenuButtonPresent().then(isPresent => {
            if(!isPresent) {
                ExtendedExpectedConditions.waitForElementVisible(this.menuButton, 120000)
            }
        });

        this.isMenuExpanded().then(isExpanded => {
            if(!isExpanded) {
                this.menuButton.click();
                ExtendedExpectedConditions.waitForElementVisible(this.menuContainer);
            }
        });
    }

    loadAngularPage() {
        this.expandMenu();
        this.menuOptionLink.click();
        return new AngularPage().initComponent();
    }
}

wait类是此类中的静态实用程序方法:

export class ExtendedExpectedConditions {

    static waitForElementPresent(element, timeout = 30000) {
        browser.wait(ExpectedConditions.presenceOf(element), timeout);
    }

    static waitForElementVisible(element, timeout = 30000) {
        browser.wait(ExpectedConditions.visibilityOf(element), timeout);
    }

    static isElementPresent(element) {
        return element.isPresent()
    }
}

angular页面类有这个构造函数,它传递了真正的'到基类构造函数,表明它是一个Angular页面:

import {AbstractLoadable} from "./AbstractLoadable";

export class AngularPage extends AbstractLoadable {

    constructor() {
        super(true);

        this.loadDialogButton = element(by.css("some locator"));
    }

    loadDialog() {
        this.loadDialogButton.click();
        //This class also extends the base class and has a constructor that passes true to the base class constructor, indicating that it is an Angular component
        return new AngularDialog().initComponent();
    }
}

当我尝试执行此测试时,我一直得到" window.angular未定义"错误:

import {LoginPage} from "../pageobject/LoginPage.js";

describe("Test", () => {
    it("Login and navigate", () => {
        let hp = new LoginPage().load(browser.baseUrl).login("user", "pass");
        let ap = hp.loadAngularPage();
        let dialog = ap.loadDialog();

        //isLoaded() checks visibility of dialog container element
        expect(dialog.isLoaded()).toBeTruthy();
    });
});

控制台输出是:

Initializing: false
Initializing: false
Initializing: true
Waiting for angular
Initializing: true
Waiting for angular

Failed: Error while waiting for Protractor to sync with the page: "window.angular is undefined.  This could be either because this is a non-angular page or because your test involves client-side navigation, which can interfere with Protractor's bootstrapping.  See http://git.io/v4gXM for details"
Error: Error while waiting for Protractor to sync with the page: "window.angular is undefined.  This could be either because this is a non-angular page or because your test involves client-side navigation, which can interfere with Protractor's bootstrapping.  See http://git.io/v4gXM for details"

我的package.json是这样的:

{
  "name": "ui-tests",
  "version": "1.0.0",
  "description": "A description",
  "scripts": {
    "test": "node_modules/protractor/bin/protractor conf.js",
    "start_selenium": "node_modules/protractor/node_modules/webdriver-manager/bin/webdriver-manager start",
    "update_selenium": "node_modules/protractor/node_modules/webdriver-manager/bin/webdriver-manager update"
  },
  "dependencies": {
    "babel-preset-es2015": "^6.24.1",
    "babel-register": "^6.24.1",
    "jasmine-reporters": "^2.2.1",
    "protractor": "^5.1.2"
  },
  "keywords": [
    "es6"
  ],
  "babel": {
    "presets": [
      "es2015"
    ]
  }
}

我的conf.js是这样的:

require("babel-register");

exports.config = {

    framework: 'jasmine2',
    rootElement: 'body',
    seleniumServerJar:'./node_modules/protractor/node_modules/webdriver-manager/selenium/selenium-server-standalone-3.4.0.jar',
    chromeDriver: './node_modules/protractor/node_modules/webdriver-manager/selenium/chromedriver_2.30',
    specs: ['tests/*Spec.js'],
    capabilities: {
        browserName: 'chrome',
        acceptSslCerts: true,
        trustAllSSLCertificates: true,
        chromeOptions: {
            args: ['--no-sandbox']
        },
    },
    baseUrl: 'https://www.myurl.com',

    suites: {
        login: '../tests/theTestSpec.js'
    },

    jasmineNodeOpts: {
        showColors: true,
        defaultTimeoutInterval: 3600000,
        isVerbose: true
    },

    getPageTimeout: 120000,
    allScriptsTimeout: 3600000,
    delayBrowserTimeInSeconds: 0,

    onPrepare: function() {

        require("babel-register");

        let origFn = browser.driver.controlFlow().execute;

        browser.driver.controlFlow().execute = function () {
            let args = arguments;

            origFn.call(browser.driver.controlFlow(), function () {
                return protractor.promise.delayed(this.delayBrowserTimeInSeconds * 100);
            });

            return origFn.apply(browser.driver.controlFlow(), args);
        };

        let getScreenSize = function() {
            return browser.driver.executeScript(function() {
                return {
                    width: window.screen.availWidth,
                    height: window.screen.availHeight
                };
            });
        };

        getScreenSize().then(function(screenSize) {
            browser.driver.manage().window().setSize(screenSize.width, screenSize.height);
        });
    }
};

1 个答案:

答案 0 :(得分:0)

所有量角器调用都会返回promise。在您当前的代码中,您创建它们但不总是等待它们解决。需要在彼此之后发生的所有事情都需要使用then关键字进行链接。 promises

例如,

这两项检查都是在同一时间完成的。

expandMenu() {
    this.isMenuButtonPresent().then(isPresent => {
        if(!isPresent) {
            ExtendedExpectedConditions.waitForElementVisible(this.menuButton, 120000)
        }
    });

    this.isMenuExpanded().then(isExpanded => {
        if(!isExpanded) {
            this.menuButton.click();
            ExtendedExpectedConditions.waitForElementVisible(this.menuContainer);
        }
    });
}

此处'this'会在browser.waitForAngular()异步等待时立即返回。

initComponent() {

    console.log("Initializing: " + this.isAngularComponent);

    browser.waitForAngularEnabled(this.isAngularComponent);

    if(this.isAngularComponent) {
        console.log("Waiting for angular");
        browser.waitForAngular();
    }

    return this;
}

你必须重构你的函数才能返回承诺,所以你可以一个接一个地链接它们。