我遇到了" 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);
});
}
};
答案 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;
}
你必须重构你的函数才能返回承诺,所以你可以一个接一个地链接它们。