使用Protractor调用browser.setLocation('/')报“angular is not defined”求助
browser.setLocation 等旧 Protractor API 你猜的没错——Angular 6及以上版本确实已经不再支持browser.setLocation、by.model、by.binding这些旧的Protractor API。原因是Angular从版本5开始就逐步移除了对全局angular对象的依赖,而这些旧API正是基于这个全局对象工作的,到Angular 6时,这个全局对象已经彻底不存在了,所以调用browser.setLocation时会抛出“angular is not defined”的错误,这和你遇到的情况完全吻合。
为什么await browser.waitForAngular()没用?
browser.waitForAngular()的作用是等待Angular的异步任务(比如HTTP请求、变更检测)完成,但它解决不了“API本身已经被废弃”的问题。因为browser.setLocation本身依赖的全局angular对象已经不存在了,所以不管等多久,这个调用都会失败。
替代方案:用Angular Router实现页面导航
要在Angular 6+的单页应用内保持同步导航,你可以通过browser.executeScript直接调用Angular的Router服务,这是最贴近原browser.setLocation行为的方式:
// 导航到根路径 '/' await browser.executeScript(() => { // 获取根组件的注入器,进而拿到Router服务 const rootComponent = window.ng.getComponent(document.body); const router = rootComponent.injector.get(window.ng.coreTokens.Router); return router.navigate(['/']); });
如果你的应用结构特殊,根组件不在document.body上,也可以换成其他根元素的选择器(比如app-root):
await browser.executeScript(() => { const rootElement = document.querySelector('app-root'); const rootComponent = window.ng.getComponent(rootElement); const router = rootComponent.injector.get(window.ng.coreTokens.Router); return router.navigate(['/']); });
保持Angular与Protractor同步的注意事项
- 用
browser.waitForAngularEnabled(true)替代旧的browser.ignoreSynchronization = false——后者在新版本Protractor中已经被废弃,前者是官方推荐的保持同步的方式。 - 对于元素定位,彻底放弃
by.model、by.binding,改用by.css、by.cssContainingText或者by.id等现代定位方式,比如:- 原
by.model('username')可以替换为by.css('[formControlName="username"]')(如果用响应式表单)或者by.css('input[name="username"]') - 原
by.binding('user.name')可以替换为by.cssContainingText('.user-name', user.name)
- 原
其他可选方案
如果你只是需要导航到根路径,也可以直接用browser.get('/')——只要browser.waitForAngularEnabled(true)处于启用状态,Protractor会自动等待Angular加载完成并稳定后再继续执行后续代码,这也是一种简单有效的方式。
内容的提问来源于stack exchange,提问作者Maxime Dupré

