Protractor中exceljs readFile与it-expect组合使用问题求助
问题分析与解决方案
你的问题核心出在两个点上:异步操作没有正确告知Protractor等待,以及试图在测试运行时动态创建it()测试块(Jasmine不支持这种写法)。我们一步步来解决:
1. 为什么你的代码会报错?
- 第一个错误:你在
it()里调用了wb.xlsx.readFile(),但没有把这个Promise返回给Protractor。Protractor会认为这个it()已经执行完成,而后续的expect()是在测试上下文之外运行的,所以会抛出"expectwas used when there was no current spec"。 - 第二个问题:你尝试在循环里动态创建
it()块,Jasmine的测试套件是静态解析的,运行时动态添加的it()不会被识别执行,所以即使你取消注释那些it(),它们也不会跑起来。
2. 正确的解决方案
步骤一:提前加载Excel数据
我们需要在所有测试运行前就加载好Excel数据,用beforeAll结合async/await(exceljs的方法都返回Promise,用async/await比then链更清晰),确保Protractor等待数据加载完成后再执行测试。
步骤二:基于Excel数据生成静态测试用例
在describe块内部,遍历加载好的Excel数据,提前创建对应的it()测试块——Jasmine会在运行前扫描所有it(),这样每个测试用例都会被正确识别。
修改后的完整代码
import { AppPage } from './app.po'; import { browser, logging, element, by } from 'protractor' import { Workbook, Row, Cell, Worksheet } from 'exceljs'; // 先初始化日志配置(可以放在这里,避免在describe里重复初始化) const log4js = require('log4js'); log4js.configure({ appenders: { igwan: { type: 'file', filename: 'cheese.log' } }, categories: { default: { appenders: ['igwan'], level: 'error' } } }); const logger = log4js.getLogger('IGWAN'); logger.level = 'trace'; describe('E2E Tests', () => { let page = new AppPage(); let dataContainer: any[] = []; // 存储Excel加载的数据 // 在所有测试前加载Excel数据 beforeAll(async () => { const wb: Workbook = new Workbook(); // 等待Excel文件读取完成 await wb.xlsx.readFile('e2e/src/testsE2E.xlsx'); const sheet: Worksheet = wb.getWorksheet("Eqpt"); // 解析Excel数据到dataContainer for (let l = 1; l <= sheet.rowCount; l++) { const rowObject = sheet.getRow(l); const rowData: string[] = []; for (let m = 1; m <= sheet.columnCount; m++) { const cellObject = rowObject.getCell(m); rowData.push(cellObject.toString()); } dataContainer.push(rowData); } console.log("Excel数据加载完成:", dataContainer); console.log("hello2"); // 现在这个日志会正常输出了 }); // 设置全局隐式等待并打开页面 beforeAll(() => { browser.manage().timeouts().implicitlyWait(30000); page.navigateToPark(); }); // 遍历Excel数据,生成对应的测试用例 dataContainer.forEach((row, rowIndex) => { // 跳过标记为"1"以外的行 if (row[0].toString() !== "1") { console.log(`第${rowIndex+1}行被作者标记为跳过`); return; } const deviceName = row[1]; // 为每个设备创建一个测试块,包含所有字段验证 it(`应该正确显示设备${deviceName}的所有信息`, async () => { // 输入设备名并搜索 await element(by.id('device_input')).clear(); await element(by.id('device_input')).sendKeys(deviceName); await element(by.id('search_button')).click(); // 验证各个字段 await expect(element(by.id('type')).getText()).toEqual(row[2]); await expect(element(by.id('pop')).getText()).toEqual(row[3]); await expect(element(by.id('ipMngt')).getText()).toEqual(row[4]); await expect(element(by.id('internalState')).getText()).toEqual(row[5]); await expect(element(by.id('prodState')).getText()).toEqual(row[6]); await expect(element(by.id('currentSwRelease')).getText()).toEqual(row[7]); await expect(element(by.id('hwChassis')).getText()).toEqual(row[8]); await expect(element(by.id('rfsNode')).getText()).toEqual(row[9]); await expect(element(by.id('peId')).getText()).toEqual(row[10]); }); }); afterEach(async () => { // 检查浏览器日志 const logs = await browser.manage().logs().get(logging.Type.BROWSER); expect(logs).not.toContain(jasmine.objectContaining({ level: logging.Level.SEVERE, } as logging.Entry)); }); });
关键改进点说明
- 用
beforeAll+async/await加载Excel:确保Protractor等待数据加载完成后再执行测试,避免异步操作导致的上下文丢失。 - 静态生成
it()测试块:在describe内部遍历Excel数据,提前创建所有测试用例,Jasmine会正确识别并执行它们。 - 简化异步操作:用
await替代then链,代码更易读,也确保Protractor等待每个操作完成。 - 统一页面初始化:把
navigateToPark()放在beforeAll里,避免重复执行。
这样修改后,你的Excel读取会正常执行("hello2"会输出),每个设备的验证也会作为独立的测试用例运行,不会再出现expect上下文错误。
内容的提问来源于stack exchange,提问作者C DV
相关产品推荐
相关产品推荐

