You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Protractor:验证新标签页中PDF文档与JSON内容的方法

解决Protractor测试新标签页PDF/JSON验证及同步错误问题

首先咱们先搞定那个同步错误——这个问题太常见了,因为你新打开的PDF页面根本不是Angular应用,而Protractor默认会一直等Angular加载完成,自然就报出同步失败的错误了。然后再来说怎么验证页面是PDF还是JSON。

一、先修复页面同步错误

切换到新窗口后,第一时间禁用Protractor的Angular同步机制,这样它就不会再傻等Angular初始化了:

browser.switchTo().window(newWindowHandle).then(() => {
    browser.waitForAngularEnabled(false); // 关键一步:告诉Protractor这是非Angular页面
});

如果你的项目支持async/await,代码会清爽很多,后面的示例我都用这种写法,可读性更高。

二、验证页面是PDF还是JSON的几种方法

PDF在浏览器里是特殊渲染的,没法像普通网页那样定位DOM元素,所以得换思路:

方法1:检查响应头的Content-Type(最可靠)

不管是PDF还是JSON,服务器返回的响应头里都会有Content-Type字段——PDF对应application/pdf,JSON对应application/json。你可以先拿到新页面的URL,然后发个HEAD请求查看响应头:

首先得装个HTTP请求库,比如request-promise:

npm install request-promise --save-dev

然后在测试里使用:

const request = require('request-promise');

it('验证点击按钮后打开PDF而非JSON', async () => {
    // 记录原窗口句柄
    const originalHandle = await browser.getWindowHandle();
    
    // 点击按钮
    await element(by.id('MyButton')).click();
    
    // 等待新窗口出现,避免直接取handles[1]可能出错
    await browser.wait(async () => {
        const handles = await browser.getAllWindowHandles();
        return handles.length === 2;
    }, 5000, '超时:新窗口未打开');
    
    // 切换到新窗口并禁用Angular同步
    const newWindowHandle = (await browser.getAllWindowHandles()).find(h => h !== originalHandle);
    await browser.switchTo().window(newWindowHandle);
    await browser.waitForAngularEnabled(false);
    
    // 获取当前页面URL并检查响应头
    const pageUrl = await browser.getCurrentUrl();
    const response = await request.head(pageUrl);
    const contentType = response.headers['content-type'];
    
    // 断言页面是PDF
    expect(contentType).toContain('application/pdf');
    
    // 切回原窗口,恢复Angular同步,不影响后续测试
    await browser.switchTo().window(originalHandle);
    await browser.waitForAngularEnabled(true);
});

方法2:尝试解析页面内容(适合JSON错误场景)

如果测试失败时页面显示JSON,浏览器会直接把JSON文本展示在页面里;而PDF页面你拿不到可解析的文本。所以可以尝试获取页面body文本,看能不能解析成JSON:

it('验证点击按钮后打开PDF而非JSON', async () => {
    // 前面的步骤和上面一致:获取原句柄、点击按钮、切换新窗口、禁用同步
    
    try {
        const bodyText = await element(by.tagName('body')).getText();
        // 尝试解析成JSON,如果成功说明是错误页
        JSON.parse(bodyText);
        fail('页面显示了JSON,测试失败');
    } catch (e) {
        // 解析失败,说明是PDF,测试通过
        expect(true).toBe(true);
    }
    
    // 切回原窗口恢复同步
    await browser.switchTo().window(originalHandle);
    await browser.waitForAngularEnabled(true);
});

方法3:检查URL后缀(简单但不够可靠)

如果你的PDF URL固定带.pdf后缀,那直接断言URL包含这个后缀就行:

const pageUrl = await browser.getCurrentUrl();
expect(pageUrl).toContain('.pdf');

不过这个方法有局限性,如果是动态生成的PDF(比如URL是/generate-pdf?id=123)就没用了。

三、优化你的原代码

你原来的嵌套then太绕了,用async/await重构后会清晰很多,而且不容易出错:

it('点击按钮打开PDF新标签页', async () => {
    const originalHandle = await browser.getWindowHandle();
    
    // 点击按钮
    await element(by.id('MyButton')).click();
    
    // 等待新窗口出现
    await browser.wait(async () => {
        const handles = await browser.getAllWindowHandles();
        return handles.length === 2;
    }, 5000, '超时:新窗口未打开');
    
    const handles = await browser.getAllWindowHandles();
    const newWindowHandle = handles.find(handle => handle !== originalHandle);
    
    // 切换到新窗口并禁用Angular同步
    await browser.switchTo().window(newWindowHandle);
    await browser.waitForAngularEnabled(false);
    
    // 这里放入你选择的验证逻辑(比如检查Content-Type)
    
    // 切回原窗口,恢复Angular同步
    await browser.switchTo().window(originalHandle);
    await browser.waitForAngularEnabled(true);
});

一些注意事项

  • 一定要记得切回原窗口后重新启用Angular同步,不然后面的Angular页面测试会出问题。
  • 如果你的PDF是通过POST请求生成的,HEAD请求的方法可能无效(因为HEAD没法携带POST参数),这时候可以考虑用浏览器的Performance API监听网络请求来获取响应头。
  • 不同浏览器的PDF查看器DOM结构不一样,别想着去定位PDF里的元素,咱们从响应头或者页面内容类型入手更靠谱。

内容的提问来源于stack exchange,提问作者jissay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:38:44