Javascript 如何设计量角器页面对象导航以避免;window.angular未定义;错误
我遇到了“window.angular是未定义的”错误,我确信这与JavaScript的异步执行有关,但我不知道如何解决这个问题。登录页面和初始登录页面是非角度页面,应用程序的其余部分是角度页面。因此,我需要使用非角度页面登录,然后一旦非角度登录页面加载,打开下拉菜单并单击加载角度页面的链接。似乎所有的动作都在继续,没有一个动作在检查Angular是否加载之前等待导航完成 我有一个页面对象的基类:Javascript 如何设计量角器页面对象导航以避免;window.angular未定义;错误,javascript,protractor,Javascript,Protractor,我遇到了“window.angular是未定义的”错误,我确信这与JavaScript的异步执行有关,但我不知道如何解决这个问题。登录页面和初始登录页面是非角度页面,应用程序的其余部分是角度页面。因此,我需要使用非角度页面登录,然后一旦非角度登录页面加载,打开下拉菜单并单击加载角度页面的链接。似乎所有的动作都在继续,没有一个动作在检查Angular是否加载之前等待导航完成 我有一个页面对象的基类: export class AbstractLoadable { constructor(
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 page类具有此构造函数,该构造函数将“true”传递给基类构造函数,表示它是一个angular page:
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未定义”错误:
控制台输出如下:
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"
My 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);
});
}
};
所有量角器调用都返回承诺。在当前代码中,您创建了它们,但并不总是等待它们得到解决。每件事都需要用then关键字链接起来 例如,这两项检查同时进行
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);
}
});
}
这里,当browser.waitForAngular()异步等待时,立即返回“this”
initComponent() {
console.log("Initializing: " + this.isAngularComponent);
browser.waitForAngularEnabled(this.isAngularComponent);
if(this.isAngularComponent) {
console.log("Waiting for angular");
browser.waitForAngular();
}
return this;
}
您必须重构您的函数以返回承诺,这样您就可以一个接一个地链接它们
initComponent() {
console.log("Initializing: " + this.isAngularComponent);
browser.waitForAngularEnabled(this.isAngularComponent);
if(this.isAngularComponent) {
console.log("Waiting for angular");
browser.waitForAngular();
}
return this;
}