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

Cypress 12.7+TypeScript读取Excel报错:xlsx.read is not a function

Cypress 12.7 + TypeScript 读取Excel报错:xlsx.read is not a function

错误信息

CypressError
cy.task('readXlsx')执行失败,错误信息:
xlsx.read is not a function

Node.js内部异常栈:

From Node.js Internals:
  TypeError: xlsx.read is not a function
      at readXlsx (/local0/xxxxxxx/cypress.config.ts:113:33)
      at invoke (/local0/jonas_home/.cache/Cypress/12.7.0/Cypress/resources/app/node_modules/@packages/server/lib/plugins/child/run_plugins.js:235:16)
      at <unknown> (/local0/jonas_home/.cache/Cypress/12.7.0/Cypress/resources/app/node_modules/@packages/server/lib/plugins/util.js:59:14)
      ...(省略后续栈信息)

现有代码片段

cypress.config.ts 任务定义

on("task", {
    readXlsx({filePath, sheetname}) {
      const buf = fs.readFileSync(filePath);
      const workbook = xlsx.read(buf, { type: 'buffer' });
      const rows = xlsx.utils.sheet_to_json(workbook.Sheets[sheetname]);
      return rows
    },
  });

cy-commands.ts 自定义命令

Cypress.Commands.add('readXlsx', (InputFile, string) => cy.task(
  'readXlsx',
  { filePath: InputFile, sheetName: string },
));

index.d.ts 类型声明

readXlsx(filePath: InputFile, sheetName: string): Chainable<CyQElem>;

测试调用代码

cy.get<string>('@LASTDOWNLOADEDFILE').then((templateFile) => {
   cy.log(`TEMPLATE FILE NAME: ${templateFile}`);
   cy.readXlsx(`${templateFile}`, 'SheetName1').then((rows) => {
   cy.log(`ROW: ${rdw}`);
   expect(rows[0].data[1]).to.contain(data);
   cy.log(`ROW DATA: ${rows[0].data[1]}`);
});

问题根源

  1. xlsx库导入错误:SheetJS(xlsx)在ES/CommonJS模块环境下导出方式不同,若导入方式不正确会导致xlsx.read方法不存在。
  2. 参数大小写不匹配:自定义命令传递sheetName(驼峰),但任务接收sheetname(全小写),导致无法定位工作表。
  3. 命令参数命名违规:自定义命令中用关键字string作为参数名,属于语法错误。
  4. 类型声明不匹配:返回值类型Chainable<CyQElem>不符合Excel数据结构,且InputFile未定义。
  5. 数据访问逻辑错误:sheet_to_json默认返回表头为键的对象数组,而非嵌套data属性的结构,直接访问rows[0].data[1]会报错。

解决步骤

1. 修正xlsx库导入方式

根据项目模块系统选择正确的导入方式:

  • CommonJS导入:
const { read, utils } = require('xlsx');
  • ES模块导入(需确保package.json中type: "module"或使用.mts后缀):
import { read, utils } from 'xlsx';

对应修改任务代码:

readXlsx({filePath, sheetName}) {
  const buf = fs.readFileSync(filePath);
  const workbook = read(buf, { type: 'buffer' });
  const rows = utils.sheet_to_json(workbook.Sheets[sheetName]);
  return rows;
}

2. 统一参数大小写

将任务接收的参数名改为sheetName,与自定义命令传递的参数一致:

on("task", {
    readXlsx({filePath, sheetName}) { // 此处改为sheetName
      const buf = fs.readFileSync(filePath);
      const workbook = xlsx.read(buf, { type: 'buffer' });
      const rows = xlsx.utils.sheet_to_json(workbook.Sheets[sheetName]);
      return rows;
    },
  });

3. 修复自定义命令参数命名

将参数名从string改为合法变量名:

Cypress.Commands.add('readXlsx', (inputFile, sheetName) => cy.task(
  'readXlsx',
  { filePath: inputFile, sheetName: sheetName },
));

4. 修正类型声明

更新index.d.ts中的类型定义,确保匹配实际返回值:

// 定义Excel行数据类型,根据表头结构调整
type ExcelRow = Record<string, string | number | boolean>;

declare global {
  namespace Cypress {
    interface Chainable {
      readXlsx(filePath: string, sheetName: string): Chainable<ExcelRow[]>;
    }
  }
}

export {};

5. 调整测试代码的数据访问逻辑

sheet_to_json默认返回表头为键的对象数组,修改访问方式:

cy.get<string>('@LASTDOWNLOADEDFILE').then((templateFile) => {
   cy.log(`TEMPLATE FILE NAME: ${templateFile}`);
   cy.readXlsx(`${templateFile}`, 'SheetName1').then((rows) => {
     // 示例:假设表头有"用户名"字段,直接通过键访问
     expect(rows[0].用户名).to.contain(data);
     // 若需按索引访问,可在任务中添加配置:utils.sheet_to_json(..., {header: 1})
     // 此时返回二维数组,rows[1][1]代表第一行数据的第二列
   });
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 20:23:15