Chrome无头模式下Protractor测试新标签页加载异常排查
无头Chrome下PDF测试失败?这几个坑得踩对!
嘿,我之前也碰到过一模一样的问题!正常模式下跑好好的,无头模式就掉链子,核心原因是无头Chrome对PDF的默认处理逻辑和正常模式完全不同,再加上你的测试代码里有几个不够健壮的地方,才导致了这个问题。
先回顾下你的场景:点击打印生成PDF新标签页,切换后检查URL,正常模式稳,无头模式下URL一直没加载,测试卡壳。
问题到底出在哪?
- 无头模式默认不加载PDF预览:正常Chrome会自动渲染PDF,但无头模式默认只是打开空白标签页,不会触发PDF的加载/渲染流程,所以你切换过去后URL根本不会更新。
- 硬编码sleep太不靠谱:
browser.sleep(18000)完全靠碰运气,无头模式下资源加载时序和正常模式不一样,哪怕等18秒也可能赶不上,而且如果加载快了还浪费时间。 - 窗口切换逻辑有风险:
handles[1]不一定是新打开的标签页,如果之前有其他残留的标签页,你切换的窗口根本不对。 - 没有显式等待页面就绪:切换窗口后直接拿URL,此时页面可能还处于初始化状态,自然拿不到目标URL。
一步步解决问题
1. 给无头Chrome加PDF支持参数
启动Chrome时必须加特定参数,让它在无头模式下能处理PDF:
// 你的Chrome配置需要改成这样 const chromeOptions = { args: [ '--headless=new', // 新版Chrome推荐用这个,旧版用--headless '--disable-gpu', '--print-to-pdf', // 关键:启用PDF打印/预览支持 '--no-sandbox', '--disable-dev-shm-usage', '--enable-features=NetworkService,NetworkServiceInProcess' ] }; // 把配置传入浏览器构建器 const browser = await webdriver.Builder() .forBrowser('chrome') .setChromeOptions(chromeOptions) .build();
如果是Chrome 112以下版本,把--headless=new换成--headless,再加--disable-web-security辅助解决资源加载问题
2. 把硬编码sleep换成显式等待
永远不要用固定时长的sleep!改用Protractor的ExpectedConditions等待URL加载完成:
const EC = protractor.ExpectedConditions; // 等待URL包含目标路径,超时时间20秒 await browser.wait(EC.urlContains(mUrl), 20000, 'PDF页面超过20秒仍未加载');
如果PDF页面有可见的元素(比如预览容器),也可以等待元素出现:
await browser.wait(EC.presenceOf(element(by.css('embed[src*=".pdf"]'))), 20000);
3. 优化窗口切换逻辑,精准找到新标签页
之前用handles[1]太草率,应该对比切换前后的窗口handle,精准定位新打开的标签页:
// 点击打印前先保存原窗口的handle const originalHandle = await browser.getWindowHandle(); await mTherapyReportView.btnPrintform.click(); // 等待新窗口出现,最多等10秒 await browser.wait(async () => { const handles = await browser.getAllWindowHandles(); return handles.length > 1; }, 10000, '新标签页10秒内未打开'); // 找到和原窗口不同的那个handle,就是新标签页 const handles = await browser.getAllWindowHandles(); const newHandle = handles.find(handle => handle !== originalHandle); await browser.switchTo().window(newHandle);
4. 给关闭标签页加容错处理
万一关闭标签页出错,也要确保切回原窗口,避免整个测试套件中断:
try { await browser.close(); } catch (err) { console.warn('关闭PDF标签页时出错了:', err); } finally { // 不管怎样都切回原窗口 await browser.switchTo().window(originalHandle); }
优化后的完整测试代码
it("should open document as PDF-file in new browser-tab", async () => { const mUrl = "TherapyReportForm/Export"; // 保存原窗口handle const originalHandle = await browser.getWindowHandle(); // 点击打印按钮 await mTherapyReportView.btnPrintform.click(); // 等待新窗口出现并切换过去 await browser.wait(async () => { const handles = await browser.getAllWindowHandles(); return handles.length > 1; }, 10000, '新标签页未在指定时间内打开'); const handles = await browser.getAllWindowHandles(); const newHandle = handles.find(handle => handle !== originalHandle); await browser.switchTo().window(newHandle); // 显式等待URL加载完成 const EC = protractor.ExpectedConditions; await browser.wait(EC.urlContains(mUrl), 20000, 'PDF页面URL未在指定时间内匹配'); expect(await browser.getCurrentUrl()).toContain(mUrl); // 关闭新标签页并切回原窗口,加容错 try { await browser.close(); } catch (err) { console.warn('关闭PDF标签页失败:', err); } finally { await browser.switchTo().window(originalHandle); } });
内容的提问来源于stack exchange,提问作者Jan and RESTless
相关产品推荐
相关产品推荐

