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]}`); });
问题根源
- xlsx库导入错误:SheetJS(
xlsx)在ES/CommonJS模块环境下导出方式不同,若导入方式不正确会导致xlsx.read方法不存在。 - 参数大小写不匹配:自定义命令传递
sheetName(驼峰),但任务接收sheetname(全小写),导致无法定位工作表。 - 命令参数命名违规:自定义命令中用关键字
string作为参数名,属于语法错误。 - 类型声明不匹配:返回值类型
Chainable<CyQElem>不符合Excel数据结构,且InputFile未定义。 - 数据访问逻辑错误:
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
相关产品推荐
相关产品推荐

