The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Use Excel to define Cypress scenarios by parsing the workbook in Node.js while Cypress loads its configuration, then expose the resulting rows with config.expose. In the spec, read them with Cypress.expose() and synchronously create one it() block per row. This timing is essential: Cypress builds the suite when the spec is evaluated, so asynchronous commands such as cy.fixture() and cy.task() cannot create tests after loading.
The architecture that works
A reliable Excel-driven suite has three stages:
- Node configuration: read the
.xlsxfile with Node’s filesystem API and parse it with SheetJS. - Configuration handoff: place only the normalized scenario data your browser code needs in
config.expose. - Spec evaluation: call
Cypress.expose('scenarios')and synchronously loop over the rows to define the tests.
The browser then executes ordinary Cypress commands inside each generated test. Excel is a source of test definitions, not a runtime replacement for Cypress’s command queue.
Install the parser and arrange the workbook
Install SheetJS
Install the xlsx package in the project that runs Cypress:
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallnpm install --save-dev xlsx
Confirm the package’s current installation guidance and compatibility with the Node.js and Cypress versions used by your project. Keep the workbook at a predictable path such as cypress/fixtures/scenarios.xlsx.
#1 Best Overall
- The Microsoft Office 365 Bible: The Most Updated and Complete Guide to Excel, Word, PowerPoint, Outlook, OneNote, OneDrive, Teams, Access, and Publisher from Beginners to Advanced
- ABIS BOOK
Design a stable worksheet
Put column headers in the first row. For example:
| title | username | password | expectedMessage |
|---|---|---|---|
| Valid login | [email protected] | correct-password | Welcome, Alice |
| Unknown user | [email protected] | correct-password | Invalid credentials |
Use a unique, descriptive title for every row. Treat headers as an interface: normalize them or reject the workbook when a required column is missing. Do not place production credentials or other secrets in this file, especially if it is committed to source control.
Parse Excel in cypress.config.js
This configuration reads the first worksheet, converts rows to objects, validates the shape, and exposes the safe values to the spec. The validation is deliberately explicit so an empty row or misspelled header fails before a confusing test is generated.
const { defineConfig } = require('cypress')
const XLSX = require('xlsx')
const { readFileSync } = require('fs')
const requiredColumns = ['title', 'username', 'password', 'expectedMessage']
function readScenarios() {
const workbook = XLSX.read(
readFileSync('cypress/fixtures/scenarios.xlsx'),
{ type: 'buffer' }
)
if (!workbook.SheetNames.length) {
throw new Error('scenarios.xlsx contains no worksheets')
}
const firstSheet = workbook.Sheets[workbook.SheetNames[0]]
const rawRows = XLSX.utils.sheet_to_json(firstSheet, {
defval: '',
raw: false,
})
if (!rawRows.length) {
throw new Error('The first worksheet contains no scenario rows')
}
const rows = rawRows.map((row, index) => {
const normalized = Object.fromEntries(
Object.entries(row).map(([key, value]) => [
key.trim(),
typeof value === 'string' ? value.trim() : value,
])
)
for (const column of requiredColumns) {
if (!normalized[column]) {
throw new Error(`Row ${index + 2} is missing ${column}`)
}
}
return {
title: String(normalized.title),
username: String(normalized.username),
password: String(normalized.password),
expectedMessage: String(normalized.expectedMessage),
}
})
const titles = new Set()
for (const row of rows) {
if (titles.has(row.title)) {
throw new Error(`Duplicate scenario title: ${row.title}`)
}
titles.add(row.title)
}
return rows
}
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
const scenarios = readScenarios()
config.expose = {
...config.expose,
scenarios,
}
return config
},
},
})
XLSX.read parses the workbook buffer, while sheet_to_json turns the selected worksheet into JavaScript objects. Selecting the sheet by name instead of position is also reasonable when a workbook has multiple tabs; fail clearly if the expected name is absent.
Recommended Free Tools
Generate one Cypress test per Excel row
Because Cypress.expose() returns an ordinary value during spec evaluation, the loop below runs synchronously and creates the complete suite before Cypress starts executing commands.
const scenarios = Cypress.expose('scenarios') || []
describe('Excel-driven login scenarios', () => {
scenarios.forEach((scenario) => {
it(scenario.title, () => {
cy.visit('/login')
cy.get('[data-testid="username"]').clear().type(scenario.username)
cy.get('[data-testid="password"]').clear().type(scenario.password)
cy.get('[data-testid="submit"]').click()
cy.contains(scenario.expectedMessage).should('be.visible')
})
})
})
Use selectors that are stable in your application, preferably dedicated data-testid attributes. Keep each row independently understandable: the title should identify the case, and the expected result should be explicit rather than inferred from row order.
Why cy.fixture() cannot create the tests
Cypress evaluates describe() and it() while loading the spec. Cypress commands are queued and resolve later. Therefore this pattern does not work:
cy.fixture('scenarios.xlsx').then((rows) => {
rows.forEach((row) => {
it(row.title, () => {})
})
})
Fixtures are useful for fixed input consumed inside an already-defined test. Cypress recognizes CSV as a fixture extension and returns it as text by default; an .xlsx fixture is not automatically parsed into workbook rows. For Excel-driven test generation, parse in Node configuration and expose the result.
Choose the right data-loading method
| Situation | Recommended method | Reason and limitation |
|---|---|---|
| Checked-in, stable data used during a test | cy.fixture() |
Intended for fixed test inputs and cached after the first read; it does not create new test blocks asynchronously. |
| Data determines which tests exist | Node parsing in setupNodeEvents plus Cypress.expose() |
Rows are available while the spec is loaded, allowing synchronous it() definitions. |
| File changes during a run or is produced by the application | cy.readFile() |
Reads during test execution and retries while assertions are pending; it is too late to define the suite. |
| Large or Node-only processing | cy.task() |
Keeps filesystem and parsing work in Node and returns only needed results; asynchronous tasks cannot generate test blocks. |
| Testing an upload control | Workbook fixture plus .selectFile() |
Tests the application’s upload behavior. It is separate from using workbook rows to generate scenarios. |
Security, size and determinism safeguards
- Expose the minimum: values in
config.exposeare accessible in the browser context. Never expose passwords, API keys, tokens or customer secrets. Prefer opaque test identifiers and retrieve secrets through a protected server-side mechanism when necessary. - Filter in Node: for a large workbook, select the worksheet, columns and rows in configuration. Passing the entire workbook to the browser increases memory use and exposes unnecessary data.
- Validate before generation: reject missing headers, blank required cells, duplicate titles, unexpected worksheet shape and an empty result. A configuration error is easier to diagnose than dozens of skipped or malformed tests.
- Normalize deliberately: trim headers and string fields, but preserve values such as leading-zero IDs when they are meaningful. Decide whether numbers should be read as numbers or formatted text before parsing.
- Do not depend on row order: give every case a stable key or title. If order matters for a business workflow, state that dependency explicitly and isolate the ordering logic.
- Version the input: review workbook changes like code. A changed column name or formula result can change the suite even when the spec is untouched.
Handling multiple worksheets and richer scenarios
Select a named worksheet
When the workbook contains tabs such as Login, Checkout and Search, select deliberately:
const sheetName = 'Login'
const sheet = workbook.Sheets[sheetName]
if (!sheet) throw new Error(`Worksheet not found: ${sheetName}`)
const rows = XLSX.utils.sheet_to_json(sheet, { defval: '', raw: false })
Map columns to an internal contract
Keep spreadsheet labels separate from test code by mapping them once:
return {
title: String(row['Case name']).trim(),
path: String(row['Path']).trim(),
method: String(row['Method']).trim().toUpperCase(),
expectedStatus: Number(row['Expected status']),
}
Then the spec consumes scenario.path and scenario.expectedStatus without knowing how the worksheet is labeled. For optional columns, apply defaults in Node and document them.
Keep scenario logic readable
When rows represent several workflows, dispatch to small functions rather than placing a large conditional in every it() block:
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →function runScenario(scenario) {
if (scenario.kind === 'login') return runLogin(scenario)
if (scenario.kind === 'checkout') return runCheckout(scenario)
throw new Error(`Unknown scenario kind: ${scenario.kind}`)
}
describe('Excel scenarios', () => {
scenarios.forEach((scenario) => {
it(scenario.title, () => runScenario(scenario))
})
})
Troubleshooting common failures
“Cannot find module xlsx”
Install xlsx in the package where Cypress runs, then verify the lockfile and workspace resolution. In monorepos, run the install from the Cypress project’s package rather than an unrelated parent directory.
Rank #3
The suite has zero tests
Check that the workbook path is relative to the project working directory, the first sheet contains a header row and at least one data row, and config.expose.scenarios is returned from setupNodeEvents. Add a configuration-time error for an empty array instead of silently producing an empty suite.
“Cypress.expose is undefined”
Use a Cypress version that supports the documented expose handoff and follow that version’s configuration format. Confirm the value is assigned to config.expose, not a similarly named custom property, and that the returned config is the one Cypress uses.
Excel dates or numbers look wrong
Excel stores dates and numeric cells in ways that may not match their displayed formatting. Decide whether the application needs a serial number, an ISO date or the formatted text, then normalize the value in Node. Use raw: false when formatted strings are preferable, and validate the resulting representation.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsSpecial characters break test titles or inputs
Keep titles as strings and avoid constructing selectors from untrusted cell text. For passwords or punctuation-heavy values, pass the string directly to .type() and ensure the application accepts the characters. Escape only when building a selector or regular expression.
One bad row prevents all tests
That is usually preferable to running an incomplete suite. Report the worksheet row number in the validation error, fix the source data, and rerun. If your process requires partial execution, filter rows explicitly in Node and record which rows were excluded.
Tests are slow or memory-heavy
Parse once during configuration, expose only the selected fields and avoid passing the workbook object itself. Split very large datasets into suites or use a CI matrix. Do not call the parser separately inside every test.
Rank #4
Performance and reliability considerations
Workbook parsing happens once per Cypress configuration load, while browser commands run per scenario. The dominant cost is normally the application interaction, not converting a worksheet to objects. Keep the input deterministic so retries rerun the same cases. If the workbook is generated immediately before Cypress starts, ensure the generation step completes and the file is closed before configuration reads it.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
For changing data, do not pretend a mutable file is a static fixture. Read it at the point the test needs it with cy.readFile(), or use a task for Node-side processing. If the changing data determines the number of cases, generate or update the workbook before launching Cypress so it is available during spec loading.
Or skip the browser setup
If your workflow also needs screenshots of the pages under test, ScreenshotNeo can capture a URL through one HTTP request instead of maintaining browser automation for that artifact. It removes cookie-consent banners, newsletter popups and chat widgets before capture; bot checks, blank pages, timeouts, failed loads and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server provides take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients.
For a direct capture, see the ScreenshotNeo API documentation:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
The same request in Python:
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
And Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
const fs = require('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
ScreenshotNeo includes full-page and element capture, device presets, custom viewport and retina scale, PDF output, custom CSS and JavaScript, clicks, waits, request blocking, headers, cookies, user-agent, timezone, geolocation, transparent backgrounds, resizing, selectable caching TTLs, signed links, asynchronous jobs, webhooks, bulk capture of up to 100 URLs per call, usage reporting and an OpenAPI specification. Its parameter names are compatible with those used by other screenshot APIs, which can simplify migration.
Free tools Windows power users keep installed
One-click scans. No signup required.
The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; yearly billing provides two months free. Every feature is available on every plan. Create a free ScreenshotNeo account to get started.
FAQ
Can I generate tests from an Excel file created during the Cypress run?
Not in the same spec load. Generate the file before Cypress starts, or use runtime file-reading methods for data consumed by tests rather than for creating new test blocks.
Best Value
Should I expose the workbook itself?
No. Parse and filter it in Node, then expose only the small, non-sensitive scenario objects required by the spec.
Is this approach suitable for testing an Excel upload feature?
Use a representative workbook fixture and .selectFile() to test upload behavior. That is a separate concern from using workbook rows to define the suite.
Frequently Asked Questions
Can I generate tests from an Excel file created during the Cypress run?
Not in the same spec load. Generate the file before Cypress starts, or use runtime file-reading methods for data consumed by tests rather than for creating new test blocks.
Should I expose the workbook itself?
No. Parse and filter it in Node, then expose only the small, non-sensitive scenario objects required by the spec.
Is this approach suitable for testing an Excel upload feature?
Use a representative workbook fixture and .selectFile() to test upload behavior. That is separate from using workbook rows to define the suite.
The Bottom Line
Parse Excel in Node during Cypress configuration, validate and minimize the rows, expose them with config.expose, and synchronously define the tests with Cypress.expose(). Use fixtures, cy.readFile() or cy.task() when the data’s job is different.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

