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

如何通过Node JS/Webdriver.io/Chimp实现PDF打印及结果验证?

我来帮你解决这个测试@media print CSS的问题,结合Node.js、Chimp、Webdriver.io和Selenium,分两个核心部分拆解:生成与实际打印一致的PDF,以及验证PDF的正确性。

生成与实际打印一致的PDF(Chrome/Firefox)

要保证PDF和实际打印效果完全匹配,必须调用浏览器原生的打印渲染引擎生成文件,而非截图转PDF。下面分别给出Chrome和Firefox的实现方案:

Chrome 实现方案

Chrome的DevTools协议提供了Page.printToPDF命令,能直接触发浏览器的打印渲染流程,完美遵循@media print规则。在Webdriver.io/Chimp中可以通过cdp方法调用这个命令:

// 在Chimp/Webdriver.io测试中生成Chrome PDF
async function generateChromePrintPDF(outputPath = 'print-result.pdf') {
  // 调用Chrome DevTools的printToPDF命令
  const pdfResult = await browser.cdp('Page', 'printToPDF', {
    printBackground: true, // 关键:启用背景渲染,匹配实际打印(默认不开启)
    displayHeaderFooter: false, // 关闭默认页眉页脚(按需调整)
    mediaType: 'print', // 强制使用print媒体类型,确保@media print样式生效
    paperWidth: 8.5, // 纸张宽度(英寸,A4可设为8.27)
    paperHeight: 11, // 纸张高度(英寸,A4可设为11.69)
    marginTop: 0, // 自定义边距(可选)
    marginBottom: 0,
    marginLeft: 0,
    marginRight: 0
  });

  // 将返回的base64数据写入文件
  const fs = require('fs');
  fs.writeFileSync(outputPath, Buffer.from(pdfResult.data, 'base64'));
  console.log(`PDF已生成:${outputPath}`);
}

调用后生成的PDF,就是Chrome实际打印时的渲染结果,完全贴合你的@media print CSS配置。

Firefox 实现方案

Firefox需要先配置打印偏好,将默认打印机设为「保存到PDF」,再触发页面打印生成文件:

// 在Chimp/Webdriver.io测试中生成Firefox PDF
async function generateFirefoxPrintPDF(outputPath = 'firefox-print-result.pdf') {
  // 设置Firefox打印偏好,静默保存为PDF
  await browser.setPreferences({
    'print.always_print_silent': true, // 静默打印,不弹出对话框
    'print.printer_Mozilla_Save_to_PDF.print_to_file': true, // 保存到文件
    'print.printer_Mozilla_Save_to_PDF.print_to_filename': outputPath, // 指定输出路径
    'print.printer_Mozilla_Save_to_PDF.paper_size_type': '0', // 自定义纸张尺寸
    'print.printer_Mozilla_Save_to_PDF.paper_width': 8.5,
    'print.printer_Mozilla_Save_to_PDF.paper_height': 11,
    'print.print_bgcolor': true, // 打印背景颜色
    'print.print_bgimages': true // 打印背景图片
  });

  // 触发页面打印
  await browser.executeScript(() => window.print());

  // 等待文件生成(根据页面复杂度调整延迟时间)
  await browser.pause(2000);
  console.log(`PDF已生成:${outputPath}`);
}

注意:Firefox的偏好设置可能随版本略有调整,建议使用绝对路径避免权限问题。


扫描PDF验证结果正确性

生成PDF后,我们可以从内容准确性和样式符合性两个维度验证,下面是几种实用方法:

1. 文本内容验证(基础)

用pdf-parse库提取PDF文本,检查关键内容的存在/缺失,对应@media print中元素的显示/隐藏规则:

const fs = require('fs');
const pdfParse = require('pdf-parse');

async function verifyPDFContent(pdfPath) {
  const pdfBuffer = fs.readFileSync(pdfPath);
  const { text } = await pdfParse(pdfBuffer);

  // 验证应该显示的内容存在
  if (!text.includes('订单编号:20240501')) {
    throw new Error('PDF中缺失预期的打印内容');
  }

  // 验证@media print中隐藏的内容不存在
  if (text.includes('网站导航栏')) {
    throw new Error('PDF中包含不应显示的内容(导航栏)');
  }

  console.log('文本内容验证通过');
}

2. 样式/布局验证(进阶)

如果需要验证布局(比如元素位置、分页是否正确),可以用pdfjs-dist解析PDF页面结构,检查元素的坐标和尺寸:

const fs = require('fs');
const pdfjsLib = require('pdfjs-dist');

async function verifyPDFLayout(pdfPath) {
  const pdfData = new Uint8Array(fs.readFileSync(pdfPath));
  const pdf = await pdfjsLib.getDocument({ data: pdfData }).promise;
  const page = await pdf.getPage(1);
  const { viewport } = page;
  const textContent = await page.getTextContent();

  // 查找特定文本的位置,验证是否在预期区域
  const targetText = '总计:¥100.00';
  const targetItem = textContent.items.find(item => item.str === targetText);
  if (!targetItem) {
    throw new Error('未找到目标文本');
  }

  // 转换为页面坐标(示例:验证文本是否在页面底部区域)
  const { x, y } = viewport.convertToViewportPoint(targetItem.transform[4], targetItem.transform[5]);
  if (y < 50) { // 假设底部50px以内是预期位置
    console.log('布局验证通过:总计文本在页面底部');
  } else {
    throw new Error('总计文本位置不符合预期');
  }
}

3. 视觉对比验证(精准)

如果需要完全匹配视觉效果,可以将PDF转换为图片,用resemblejs和预期的基准图片对比:

const pdfPoppler = require('pdf-poppler');
const resemble = require('resemblejs');
const fs = require('fs');

async function verifyPDFVisual(pdfPath, expectedImagePath) {
  // 将PDF第一页转换为PNG图片
  const convertOptions = {
    format: 'png',
    out_dir: './temp',
    out_prefix: 'print-preview',
    page: 1
  };
  await pdfPoppler.convert(pdfPath, convertOptions);
  const generatedImagePath = './temp/print-preview-1.png';

  // 对比生成图片和预期图片
  return new Promise((resolve, reject) => {
    resemble(generatedImagePath)
      .compareTo(expectedImagePath)
      .ignoreMinor() // 忽略微小差异(如字体渲染的细微差别)
      .onComplete(data => {
        if (data.misMatchPercentage < 0.5) { // 允许0.5%以内的差异
          console.log('视觉验证通过');
          fs.unlinkSync(generatedImagePath); // 清理临时文件
          resolve();
        } else {
          reject(new Error(`视觉差异过大:${data.misMatchPercentage}%`));
        }
      });
  });
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:57:41