如何在Cypress每个it块中独立更新CSV文件
解决Cypress每个it块独立更新CSV文件的问题
问题描述
希望在Cypress测试的每个it块中独立更新CSV文件的orderId、日期等数据,但当前第一个it块更新后的CSV会被后续it块复用,无法实现独立更新。
相关代码
uploadOrders.cy.js
/// <reference types='Cypress'/> import { ORDERS } from '../../selector/orders'; import BU from '../../fixtures/BU.json'; import Helper from '../../e2e/utils/Helper'; const helper = new Helper(); let getTodaysDate = helper.getTodaysDate(); let getTomorrowssDate = helper.getTomorrowsDate(); let getYesterdaysDate = helper.getYesterdaysDate(); describe('Upload Orders', () => { before(() => { cy.login(); cy.get(ORDERS.ORDER_ICON).click(); }); beforeEach(() => { cy.writeFile('cypress/fixtures/finalCsvToBeUploaded.csv', ''); }); it('Upload orders and check its successful', () => { let csvData = { orderId: 'OrderId_' + helper.getCurrentDateAndTimeInMiliseconds(), orderDate: getTomorrowssDate, homebaseExecutionDate: getTomorrowssDate, customerExecutionDate: getTomorrowssDate, } cy.readFile('cypress/fixtures/referenceCsvFile.csv') .then((data) => { cy.task('csvToJson', data) .then(finalJsonArray => { cy.task('updateCsvData', { csvData, finalJsonArray }) .then(finalUpdatedJsonArray => { cy.log("Update JSON array: " + finalUpdatedJsonArray[0]['Order ID']); cy.task('finalCsv', finalUpdatedJsonArray); }); }) }) cy.get(ORDERS.ORDER_UPLOAD).click(); cy.attachCsvFile('finalCsvToBeUploaded.csv'); cy.validateToastMsg('Orders uploaded successfully'); cy.log('Order is uploaded successfully via csv file and orderId is '); }); it('Upload orders and check validation for past customer execution date', () => { cy.wait(5000); let csvData = { orderId: 'OrderId_' + helper.getCurrentDateAndTimeInMiliseconds(), orderDate: getTomorrowssDate, homebaseExecutionDate: getYesterdaysDate, customerExecutionDate: getYesterdaysDate, } cy.readFile('cypress/fixtures/finalCsvToBeUploaded.csv') .then((data) => { cy.task('csvToJson', data) .then(finalJsonArray => { cy.task('updateCsvData', { csvData, finalJsonArray }) .then(finalUpdatedJsonArray => { cy.log("Update JSON array: " + finalUpdatedJsonArray); cy.task('finalCsv', finalUpdatedJsonArray); }); }) }) cy.get(ORDERS.ORDER_UPLOAD).click(); cy.attachCsvFile('finalCsvToBeUploaded.csv'); cy.validateToastMsg('Orders uploaded successfully'); cy.log('Order is uploaded successfully via csv file and orderId is'); }); after(() => { cy.clearCookies(); cy.clearLocalStorage(); }); });
cypress.config.js
const { defineConfig } = require("cypress"); const converter = require('json-2-csv'); const csv = require('csv-parser'); const fs = require('fs'); const { default: Helper } = require("./cypress/e2e/utils/Helper"); const csvToJson1 = require('convert-csv-to-json'); const helper = require("csvtojson"); module.exports = defineConfig({ chromeWebSecurity: false, watchFileForChanges: false, defaultCommandTimeout: 10000, pageLoadTimeout: 50000, viewportWidth: 1280, viewportHeight: 800, video: false, screenshotOnRunFailure: true, "reporter": "mochawesome", "reporterOptions": { "charts": true, "overwrite": false, "html": false, "json": true, "timestamp": 'dd_mm_yy_HH_MM_ss', "reportDir": "cypress/reports/mochawesome-report" }, e2e: { specPattern: 'cypress/e2e/**/*.cy.js', setupNodeEvents(on, config) { require('@cypress/code-coverage/task')(on, config) on('before:browser:launch', (browser = {}, launchOptions) => { console.log(launchOptions.args); if (browser.family === 'chromium' && browser.name !== 'electron') { launchOptions.args.push('--start-fullscreen'); } if (browser.name === 'electron') { launchOptions.preferences.fullscreen = true; } return launchOptions; }); on('task', { csvToJson(data) { var lines = data.split("\n"); var result = []; var headers = lines[0].split(","); for (var i = 1; i < (lines.length); i++) { var obj = {}; var currentline = lines[i].split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/); for (var j = 0; j < headers.length; j++) { obj[headers[j]] = currentline[j].replace(/["']/g, ""); } result.push(obj); } console.log(result); return result; } }) on('task', { finalCsv(updatedJSON) { converter.json2csvAsync(updatedJSON).then(updatedCsv => { fs.writeFileSync('cypress/fixtures/finalCsvToBeUploaded.csv', updatedCsv); }).catch(err => console.log(err)); return null; } }); on('task', { log(message) { console.log(message); return null; }, }); on('task', { updateCsvData({ csvData, finalJsonArray }) { let updatedJSON,orderIds = []; for (let i = 0; i < (finalJsonArray.length); i++) { if ('orderId' in csvData) { orderIds[i] = csvData.orderId; finalJsonArray[i]['Order ID'] = csvData.orderId; } else { orderIds[i] = 'OrderId_' + Date.now(); finalJsonArray[i]['Order ID'] = orderIds[i]; } if ('orderDate' in csvData) { finalJsonArray[i]['Order Date'] = csvData.orderDate; } if ('homebaseExecutionDate' in csvData) { finalJsonArray[i]['Homebase Execution Date'] = csvData.homebaseExecutionDate; } if ('customerExecutionDate' in csvData) { finalJsonArray[i]['Customer Execution Date'] = csvData.customerExecutionDate; } } updatedJSON = finalJsonArray; return updatedJSON; } }) on('task', { updateCsvFile(csvData) { const finalJsonArray = []; let updatedJSON, orderIds = []; fs.createReadStream('cypress/fixtures/referenceCsvFile.csv') .pipe(csv()) .on('data', (data) => finalJsonArray.push(data)) .on('end', () => { console.log(finalJsonArray); for (let i = 0; i < (finalJsonArray.length); i++) { if ('orderId' in csvData) { orderIds[i] = csvData.orderId; finalJsonArray[i]['Order ID'] = csvData.orderId; } else { orderIds[i] = 'OrderId_' + this.getCurrentDateAndTimeInMiliseconds(); finalJsonArray[i]['Order ID'] = orderIds[i]; } if ('orderDate' in csvData) { finalJsonArray[i]['Order Date'] = csvData.orderDate; } if ('homebaseExecutionDate' in csvData) { finalJsonArray[i]['Homebase Execution Date'] = csvData.homebaseExecutionDate; } if ('customerExecutionDate' in csvData) { finalJsonArray[i]['Customer Execution Date'] = csvData.customerExecutionDate; } } updatedJSON = finalJsonArray; converter.json2csvAsync(updatedJSON).then(csvFile => { fs.writeFileSync('cypress/fixtures/' + fileName, csvFile) }).catch(err => console.log(err)); }) return orderIds; } }) return config; } } });
问题原因分析
- 第二个测试用例读取错误文件:第二个
it块中读取的是被beforeEach清空的finalCsvToBeUploaded.csv,而非原始模板referenceCsvFile.csv,导致无法基于模板生成新的测试数据。 - 异步文件写入未等待完成:
finalCsv任务中使用converter.json2csvAsync异步生成CSV,但任务直接返回null,没有等待写入完成,导致后续上传操作可能读取到未更新完成的旧文件。
解决方案
1. 修正第二个测试用例的文件读取逻辑
将第二个it块中的文件读取路径改为原始模板文件,确保每次测试都从干净的模板生成数据:
// 第二个it块修改后 it('Upload orders and check validation for past customer execution date', () => { let csvData = { orderId: 'OrderId_' + helper.getCurrentDateAndTimeInMiliseconds(), orderDate: getTomorrowssDate, homebaseExecutionDate: getYesterdaysDate, customerExecutionDate: getYesterdaysDate, } // 改为读取reference模板文件 cy.readFile('cypress/fixtures/referenceCsvFile.csv') .then((data) => { cy.task('csvToJson', data) .then(finalJsonArray => { cy.task('updateCsvData', { csvData, finalJsonArray }) .then(finalUpdatedJsonArray => { cy.log("Update JSON array: " + finalUpdatedJsonArray[0]['Order ID']); cy.task('finalCsv', finalUpdatedJsonArray); }); }) }) cy.get(ORDERS.ORDER_UPLOAD).click(); cy.attachCsvFile('finalCsvToBeUploaded.csv'); cy.validateToastMsg('Orders uploaded successfully'); cy.log('Order is uploaded successfully via csv file and orderId is ' + csvData.orderId); });
2. 修复finalCsv任务的异步等待问题
修改cypress.config.js中的finalCsv任务,使用async/await等待异步操作完成,确保Cypress等待文件写入后再执行后续命令:
// 修正后的finalCsv任务 on('task', { async finalCsv(updatedJSON) { try { const updatedCsv = await converter.json2csvAsync(updatedJSON); fs.writeFileSync('cypress/fixtures/finalCsvToBeUploaded.csv', updatedCsv); return null; } catch (err) { console.error(err); throw err; // 抛出错误让Cypress捕获并终止测试 } } });
3. 优化测试流程,确保命令顺序执行
将上传操作放在cy.task('finalCsv')的回调中,确保文件完全写入后再执行上传,避免异步命令顺序问题:
// 第一个it块优化后 it('Upload orders and check its successful', () => { let csvData = { orderId: 'OrderId_' + helper.getCurrentDateAndTimeInMiliseconds(), orderDate: getTomorrowssDate, homebaseExecutionDate: getTomorrowssDate, customerExecutionDate: getTomorrowssDate, } cy.readFile('cypress/fixtures/referenceCsvFile.csv') .then((data) => { cy.task('csvToJson', data) .then(finalJsonArray => { cy.task('updateCsvData', { csvData, finalJsonArray }) .then(finalUpdatedJsonArray => { cy.log("Update JSON array: " + finalUpdatedJsonArray[0]['Order ID']); return cy.task('finalCsv', finalUpdatedJsonArray); }) .then(() => { // 文件写入完成后执行上传操作 cy.get(ORDERS.ORDER_UPLOAD).click(); cy.attachCsvFile('finalCsvToBeUploaded.csv'); cy.validateToastMsg('Orders uploaded successfully'); cy.log('Order is uploaded successfully via csv file and orderId is ' + csvData.orderId); }); }) }) });
额外建议
移除第二个it块中的cy.wait(5000),Cypress的异步命令会自动等待前序操作完成,硬编码等待时间会降低测试稳定性和效率。
内容的提问来源于stack exchange,提问作者Chethan CP
相关产品推荐
相关产品推荐

