Angular 量角器 - 验证页面重定向
Angular Protractor - Verifying page redirect
我正在 Angular 应用程序中编写一些 E2E 测试。我遇到的一个问题是,每当我重定向到新路由时,我都想验证是否显示了正确的组件。由于某种原因,这总是导致失败并出现以下错误:
- Failed: script timeout
我一直在网上搜索以尝试找到解决方案,但我找到的所有解决方案都不适合我。
例子
- 等待Angular
browser.waitForAngular();
Reference
- 检查浏览器当前 URL 并与预期 URL:
进行比较
browser.driver.wait(() => {
browser.driver.getCurrentUrl().then((url) => {
return /expected-url/.test(url);
});
}, 10000);
代码示例
以下是测试登录功能的代码示例。
登录页面对象Class
import { browser, element, by } from 'protractor';
export class LoginPage {
private credentials: { username: string, password: string } = {
username: 'admin',
password: 'admin'
};
navigateTo() {
return browser.get(browser.baseUrl) as Promise<any>;
}
getLoginComponent() {
return element(by.css('ra-login'));
}
getUsernameTextbox() {
return element(by.css('ra-login [data-test-id="username"]'));
}
getPasswordTextbox() {
return element(by.css('ra-login [data-test-id="password"]'));
}
getLoginButton() {
return element(by.css('ra-login [data-test-id="login-btn"]'));
}
getSecurePage() {
return element(by.css('ra-secure-content'));
}
login(credentials: { username: string, password: string } = this.credentials) {
this.getUsernameTextbox().sendKeys(credentials.username);
this.getPasswordTextbox().sendKeys(credentials.password);
this.getLoginButton().click();
}
getErrorMessage() {
return element(by.css('ra-login [data-test-id="login-error"]'));
}
}
登录 E2E 规范文件
describe('Login Functionality', () => {
let loginPage: LoginPage;
beforeEach(() => {
loginPage = new LoginPage();
});
// Test runs successfully
it('should display login', () => {
loginPage.navigateTo();
expect(loginPage.getLoginComponent().isPresent()).toBeTruthy();
});
// Test runs successfully
it('should have the login button disabled', () => {
loginPage.navigateTo();
expect(loginPage.getLoginButton().isEnabled()).toBe(false);
});
// Test runs fails
it('should redirect to a secure page', () => {
loginPage.navigateTo();
loginPage.login();
expect(loginPage.getSecurePage().isPresent()).toBeTruthy();
});
afterEach(async () => {
// Assert that there are no errors emitted from the browser
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
expect(logs).not.toContain(jasmine.objectContaining({
level: logging.Level.SEVERE,
} as logging.Entry));
});
});
使用上面的代码,测试 'should redirect to a secure page'
失败了。此测试试图验证在成功登录后,显示 "secure content" 组件。此组件是一个包装器组件,用于托管只有在用户登录后才能显示的页面。
页面重定向总是成功的,并且正在显示正确的页面。我怀疑测试以某种方式试图在实际重定向之前获取元素?
我是 E2E 的新手,所以我不确定这是否是问题所在。
以防万一这里是重要包的版本号:
- Angular: 8.2.14
- Angular CLI: 8.2.2
- 量角器: 5.4.2
- 茉莉: 2.8.0
我建议您使用 async/await 语句结构。您的怀疑似乎是正确的,您面临的问题是由于承诺处理不当。
您可以尝试将规范写成:
it('should redirect to a secure page', async() => {
await loginPage.navigateTo();
await loginPage.login();
expect(await(await loginPage.getSecurePage()).isPresent()).toBeTruthy();
});
并将导航和登录功能更改为:
async navigateTo() {
return await browser.get(browser.baseUrl);
}
您可以在有浏览器交互时添加 await,如果有任何 await 语句则使函数异步。
参考:[1]:https://hackernoon.com/should-i-use-promises-or-async-await-126ab5c98789
你必须对运算符使用 promise then
这个解决方案对我有用
如果你知道回复时间,你可以使用
browser.driver.sleep(1000)
但这是一种不好的做法
注意:如果应用程序速度很慢,则需要报告性能问题。
在我的例子中,除了等待某些 Promise 对象外,还有其他原因导致了错误。长话短说,我有一个时间间隔负责向用户显示当前时间。由于间隔是一个异步函数,Protractor 将假设 Angular 仍然是 运行 一些函数,因此继续等待 Angular 成为 "responsive".
在 Angular 2+ 中,为了满足这种情况,setInterval()
函数需要 运行 在 Angular 区域之外。
例子
ngOnInit() {
this.now = new Date();
setInterval(() => {
this.now = new Date();
}, 1000);
}
只要页面上存在具有间隔的组件,以上代码将导致 Protractor 超时。
要解决此问题,我们可以使用 NgZone
。
例子
import { NgZone } from '@angular/core';
constructor(private ngZone: NgZone) { }
ngOnInit() {
this.now = new Date();
// running setInterval() function outside angular
// this sets the asynchronous call to not run within the angular zone
this.ngZone.runOutsideAngular(() => {
setInterval(() => {
// update the date within angular, so that change detection is triggered
this.ngZone.runTask(() => {
this.now = new Date();
});
}, 1000);
});
}
参考资料
- https://github.com/angular/protractor/issues/3349
- https://www.youtube.com/watch?v=DltUEDy7ItY(好好谈谈
zone.js
及其在Angular中的作用)
- https://christianliebel.com/2016/11/angular-2-protractor-timeout-heres-fix/
在我的测试中,我还添加了一个实用函数,它有助于等待元素显示在屏幕上。
import { ElementFinder, ExpectedConditions, browser } from 'protractor';
const until = ExpectedConditions;
export const waitForElement = (elementToFind: ElementFinder, timeout = 10000) => {
return browser.wait(until.presenceOf(elementToFind), timeout, 'Element not found');
};
然后在测试中使用如下:
it('should redirect to a secure page', async () => {
loginPage.navigateTo();
loginPage.login();
const secureContent = loginPage.getSecureContentComponent();
waitForElement(secureContent);
expect(secureContent.isPresent()).toBe(true);
});
参考资料
我正在 Angular 应用程序中编写一些 E2E 测试。我遇到的一个问题是,每当我重定向到新路由时,我都想验证是否显示了正确的组件。由于某种原因,这总是导致失败并出现以下错误:
- Failed: script timeout
我一直在网上搜索以尝试找到解决方案,但我找到的所有解决方案都不适合我。
例子
- 等待Angular
browser.waitForAngular();
Reference
- 检查浏览器当前 URL 并与预期 URL: 进行比较
browser.driver.wait(() => {
browser.driver.getCurrentUrl().then((url) => {
return /expected-url/.test(url);
});
}, 10000);
代码示例
以下是测试登录功能的代码示例。
登录页面对象Class
import { browser, element, by } from 'protractor';
export class LoginPage {
private credentials: { username: string, password: string } = {
username: 'admin',
password: 'admin'
};
navigateTo() {
return browser.get(browser.baseUrl) as Promise<any>;
}
getLoginComponent() {
return element(by.css('ra-login'));
}
getUsernameTextbox() {
return element(by.css('ra-login [data-test-id="username"]'));
}
getPasswordTextbox() {
return element(by.css('ra-login [data-test-id="password"]'));
}
getLoginButton() {
return element(by.css('ra-login [data-test-id="login-btn"]'));
}
getSecurePage() {
return element(by.css('ra-secure-content'));
}
login(credentials: { username: string, password: string } = this.credentials) {
this.getUsernameTextbox().sendKeys(credentials.username);
this.getPasswordTextbox().sendKeys(credentials.password);
this.getLoginButton().click();
}
getErrorMessage() {
return element(by.css('ra-login [data-test-id="login-error"]'));
}
}
登录 E2E 规范文件
describe('Login Functionality', () => {
let loginPage: LoginPage;
beforeEach(() => {
loginPage = new LoginPage();
});
// Test runs successfully
it('should display login', () => {
loginPage.navigateTo();
expect(loginPage.getLoginComponent().isPresent()).toBeTruthy();
});
// Test runs successfully
it('should have the login button disabled', () => {
loginPage.navigateTo();
expect(loginPage.getLoginButton().isEnabled()).toBe(false);
});
// Test runs fails
it('should redirect to a secure page', () => {
loginPage.navigateTo();
loginPage.login();
expect(loginPage.getSecurePage().isPresent()).toBeTruthy();
});
afterEach(async () => {
// Assert that there are no errors emitted from the browser
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
expect(logs).not.toContain(jasmine.objectContaining({
level: logging.Level.SEVERE,
} as logging.Entry));
});
});
使用上面的代码,测试 'should redirect to a secure page'
失败了。此测试试图验证在成功登录后,显示 "secure content" 组件。此组件是一个包装器组件,用于托管只有在用户登录后才能显示的页面。
页面重定向总是成功的,并且正在显示正确的页面。我怀疑测试以某种方式试图在实际重定向之前获取元素?
我是 E2E 的新手,所以我不确定这是否是问题所在。
以防万一这里是重要包的版本号:
- Angular: 8.2.14
- Angular CLI: 8.2.2
- 量角器: 5.4.2
- 茉莉: 2.8.0
我建议您使用 async/await 语句结构。您的怀疑似乎是正确的,您面临的问题是由于承诺处理不当。
您可以尝试将规范写成:
it('should redirect to a secure page', async() => {
await loginPage.navigateTo();
await loginPage.login();
expect(await(await loginPage.getSecurePage()).isPresent()).toBeTruthy();
});
并将导航和登录功能更改为:
async navigateTo() {
return await browser.get(browser.baseUrl);
}
您可以在有浏览器交互时添加 await,如果有任何 await 语句则使函数异步。
参考:[1]:https://hackernoon.com/should-i-use-promises-or-async-await-126ab5c98789
你必须对运算符使用 promise then
这个解决方案对我有用
如果你知道回复时间,你可以使用
browser.driver.sleep(1000)
但这是一种不好的做法
注意:如果应用程序速度很慢,则需要报告性能问题。
在我的例子中,除了等待某些 Promise 对象外,还有其他原因导致了错误。长话短说,我有一个时间间隔负责向用户显示当前时间。由于间隔是一个异步函数,Protractor 将假设 Angular 仍然是 运行 一些函数,因此继续等待 Angular 成为 "responsive".
在 Angular 2+ 中,为了满足这种情况,setInterval()
函数需要 运行 在 Angular 区域之外。
例子
ngOnInit() {
this.now = new Date();
setInterval(() => {
this.now = new Date();
}, 1000);
}
只要页面上存在具有间隔的组件,以上代码将导致 Protractor 超时。
要解决此问题,我们可以使用 NgZone
。
例子
import { NgZone } from '@angular/core';
constructor(private ngZone: NgZone) { }
ngOnInit() {
this.now = new Date();
// running setInterval() function outside angular
// this sets the asynchronous call to not run within the angular zone
this.ngZone.runOutsideAngular(() => {
setInterval(() => {
// update the date within angular, so that change detection is triggered
this.ngZone.runTask(() => {
this.now = new Date();
});
}, 1000);
});
}
参考资料
- https://github.com/angular/protractor/issues/3349
- https://www.youtube.com/watch?v=DltUEDy7ItY(好好谈谈
zone.js
及其在Angular中的作用) - https://christianliebel.com/2016/11/angular-2-protractor-timeout-heres-fix/
在我的测试中,我还添加了一个实用函数,它有助于等待元素显示在屏幕上。
import { ElementFinder, ExpectedConditions, browser } from 'protractor';
const until = ExpectedConditions;
export const waitForElement = (elementToFind: ElementFinder, timeout = 10000) => {
return browser.wait(until.presenceOf(elementToFind), timeout, 'Element not found');
};
然后在测试中使用如下:
it('should redirect to a secure page', async () => {
loginPage.navigateTo();
loginPage.login();
const secureContent = loginPage.getSecureContentComponent();
waitForElement(secureContent);
expect(secureContent.isPresent()).toBe(true);
});
参考资料