Protractor测试两个Angular应用时跨应用导航的ScriptTimeoutError问题解决方案咨询
我手头有两个Angular应用,一个负责登录流程,另一个处理核心业务逻辑。在用Protractor做自动化测试时,登录第一个应用的流程完全正常,但切换到第二个应用后,尝试获取元素时总是碰到超时错误——明明浏览器里能看到元素,Protractor却死活找不到。而且两个都是Angular应用,我不想通过禁用waitForAngular来绕开问题,有没有合适的解决办法?
我的测试用例顺序
specs: [ 'login.js',// 第一个登录应用 'navigatetoRegisterReport.js',// 从第一个应用导航的页面 'requestCreation.js',// 通过`browser.get(第二个应用Url)`加载的业务应用页面 'navigateToDcOtherInvoice.js'// 业务应用内的页面跳转 ]
登录逻辑(运行正常)
async first() { await browser.driver.get(browser.baseUrl).then(async () => { await browser.wait(ExpectedConditions.elementToBeClickable(element(by.linkText("Other User"))), 30000); await element(by.linkText("Other User")).click().then(() => { browser.wait(ExpectedConditions.elementToBeClickable(element(by.css('#username'))), 30000); element(by.css('#username')).sendKeys('XXXXX').then(() => { browser.wait(ExpectedConditions.elementToBeClickable(element(by.id("password-field"))), 30000); element(by.id("password-field")).sendKeys('XXXXX').then(() => { browser.wait(ExpectedConditions.elementToBeClickable(element(by.id('login-submit'))), 30000); element(by.id('login-submit')).click().then(async () => { const dashboardImage = await element(by.css("app-dashboard .dashboard-image")); browser.wait(ExpectedConditions.elementToBeClickable(dashboardImage), 30000); dashboardImage.isDisplayed().then((value) => { if (value == true) { console.log('dashborad image is displayed') } else { console.log('dashborad image is not identified') } }).catch(error => console.error('caught error while login', error));; }).catch(error => console.error('caught error 7', error));; }).catch(error => console.error('caught error on password', error));; }).catch(error => console.error('caught error on user name', error));; }).catch(error => console.error('caught error tab click', error));; }).catch(error => console.error('caught error on load', error)); }
第二个应用的操作代码(报错)
async requestCreation(date: string, report: string) { await browser.get('https://2ndapplication/xxx/xxxx').then(async () => { var selectDate = element(by.xpath("//input[@id='icon-right']")); var reportType = element(by.xpath("//input[@placeholder='Report Type']")); browser.wait(ExpectedConditions.elementToBeClickable(selectDate), 30000); selectDate.clear(); selectDate.sendKeys(date) browser.wait(ExpectedConditions.elementToBeClickable(reportType), 30000); reportType.click(); reportType.clear(); reportType.sendKeys(report) }).catch(error => console.error('caught error on requestCreation', error)); }
报错信息
Error: ScriptTimeoutError: script timeout
(Session info: chrome=88.0.4324.190)
(Driver info: chromedriver=88.0.4324.96 (68dba2d8a0b149a1d3afac56fa74648032bcf46b-refs/branch-heads/4324@{#1784}),platform=Windows NT 10.0.18363 x86_64)
at Object.checkLegacyResponse (E:\updatedCode\backup\node_modules\selenium-webdriver\lib\error.js:546:15)
at parseHttpResponse (E:\updatedCode\backup\node_modules\selenium-webdriver\lib\http.js:509:13)
at doSend.then.response (E:\updatedCode\backup\node_modules\selenium-webdriver\lib\http.js:441:30)
at process._tickCallback (internal/process/next_tick.js:68:7)
From: Task: Protractor.waitForAngular() **- Locator: By(xpath, //input[@id='icon-right'])
解决方案
1. 切换应用时手动重置Angular上下文
Protractor默认会绑定当前页面的Angular实例,当你跳转到第二个独立的Angular应用时,它不会自动切换上下文。所以在加载第二个应用后,需要手动让Protractor重新识别新的Angular环境:
async requestCreation(date: string, report: string) { try { await browser.get('https://2ndapplication/xxx/xxxx'); // 重置Angular等待状态,确保Protractor监听新应用的Angular await browser.waitForAngularEnabled(true); // 等待第二个应用的Angular完全初始化 await browser.wait(async () => { // 执行脚本检查当前页面是否有可用的Angular实例 return await browser.executeScript(` return window.angular !== undefined && window.angular.element(document).injector() !== undefined; `); }, 30000, '第二个Angular应用加载超时'); // 后续元素操作 const selectDate = element(by.xpath("//input[@id='icon-right']")); await browser.wait(ExpectedConditions.elementToBeClickable(selectDate), 30000); await selectDate.clear(); await selectDate.sendKeys(date); const reportType = element(by.xpath("//input[@placeholder='Report Type']")); await browser.wait(ExpectedConditions.elementToBeClickable(reportType), 30000); await reportType.click(); await reportType.clear(); await reportType.sendKeys(report); } catch (error) { console.error('caught error on requestCreation', error); } }
2. 用async/await替代嵌套then
你的代码里嵌套了大量的then,这很容易导致异步时序混乱,可读性也差。全部改用async/await可以让代码逻辑更清晰,也能避免很多异步相关的bug,就像上面重构后的代码那样。
3. 检查应用兼容性与配置
- 确认第二个应用的Angular版本和Protractor 7.0.0兼容(Protractor 7.x支持Angular 2+,一般没问题,但如果是特别旧的版本可能需要调整)。
- 在
protractor.conf.js里添加useAllAngular2AppRoots: true,确保Protractor能识别到应用的根组件:exports.config = { // 其他配置... useAllAngular2AppRoots: true }
4. 验证URL与跨域问题
确保browser.get()的第二个应用URL完全正确,手动在测试用的Chrome里打开这个URL,确认能正常加载Angular应用,没有跨域拦截的情况。
内容的提问来源于stack exchange,提问作者Ramesh Rajendran

