In a Cypress test, how do you read fixture data aliased with .as('receipts')?
answer
- Where a non-DOM alias is actually stored
- The object Mocha shares across hooks
- One form needs a classic function
- The at-sign form avoids that keyword
- Queued, so not readable on the next line
basics
~20 sTwo ways: this.receipts inside a test written with function(), because Cypress stores non-DOM aliases on Mocha's shared test context, or cy.get('@receipts') followed by .then(). Either only works after the queued .as() command has actually run.
solid answer
~40 s`cy.fixture('receipts').as('receipts')` in a `beforeEach` gives you two ways to read it back. Because the value is not a DOM element, Cypress stores it on Mocha's shared test context, so a test written as `function () { ... }` can read `this.receipts` directly. The alternative is `cy.get('@receipts').then((receipts) => ...)`, which needs no `this` and therefore works inside arrow functions. The trap is timing: `.as()` is a queued command, so `this.receipts` is `undefined` on the very next line of the same test — it is only populated once the queue reaches that command. And the two forms are not identical: `this.receipts` is the value captured when `.as()` ran, while `cy.get('@receipts')` re-runs the aliased chain each time you ask.
code
javascript · 13 linesbeforeEach(() => {
cy.fixture('receipts.json').as('receipts')
})
it('reads the alias off the Mocha context', function () {
expect(this.receipts[0].merchant).to.equal('Blue Bottle')
})
it('reads the same alias without this', () => {
cy.get('@receipts').then((receipts) => {
expect(receipts).to.have.length(3)
})
})go deeper
Be ready to alias a fixture in a beforeEach and read it in the test. Remember the at-sign form, cy.get('@receipts'), and that a test using this must be written with function rather than an arrow.
Explain where a non-DOM alias is stored and why that is Mocha's context object. Being able to say why the value is missing on the next line, and why arrow functions lose it, is the expected depth here.
Show the judgment behind a house rule: picking one access form for a whole suite so nobody breaks tests by converting a callback to an arrow, and knowing when the snapshot and re-run semantics actually diverge.
Own the convention across teams: whether shared data is aliased in hooks at all, what belongs in a support file versus a spec, and how you keep a linting or review rule enforcing the choice you made.
## What `.as()` does with a loaded file `.as()` names whatever the previous command yielded. For a DOM query, Cypress remembers the query chain. For a **non-DOM value** — an object parsed out of `cypress/fixtures/receipts.json`, a string, a number — there is no chain to re-run against the page, so Cypress stores the value on **Mocha's shared test context**: the same `this` that Mocha hands your hooks and tests. That single implementation detail explains almost every question people have about fixture aliases: - Aliases are visible as `this.<name>` because they are properties on the Mocha context object. - Mocha shares that context across the hooks and the test for one test case, so an alias created in `beforeEach` is readable in the test body. - Mocha clears it between tests, so the alias does not leak into the next expense-report test. - A `describe`/`context` nested inside another can read aliases created by every enclosing hook. ## The two ways to read it back | | `this.receipts` | `cy.get('@receipts')` | |---|---|---| | Test function form | must be `function () {}` | works with arrow functions too | | When it resolves | read synchronously inside the callback | enqueued like any other command | | What you get | the value captured when `.as()` ran | the aliased chain re-run on each access | | Chaining | plain JavaScript from there on | yields into `.then()`, `.its()`, assertions | Both are correct; teams usually pick one and stay with it. `cy.get('@receipts')` is the safer house style, because a suite that never depends on `this` never breaks when somebody converts a test to an arrow function. ## Why arrow functions break `this` An arrow function does not get its own `this`; it closes over whatever `this` was where the function was written. Mocha calls your test with the shared context as `this`, and an arrow function throws that away, so `this.receipts` comes back `undefined` with no error to explain it. There are only two fixes: write the test as `it('...', function () { ... })`, or stop using `this` and read the alias with `cy.get('@receipts')`. ## Why the value is not there on the next line Cypress commands are enqueued rather than executed where they are written, so this fails: ```js it('totals the approved receipts', function () { cy.fixture('receipts.json').as('receipts') const first = this.receipts[0] // TypeError: undefined }) ``` At the moment that second line runs, `.as()` has only been *queued*. The usual shapes that work are to alias in a `beforeEach` — so the queue has drained before the test body runs — or to skip the alias entirely and take the value in a callback: 1. `beforeEach(() => cy.fixture('receipts.json').as('receipts'))`, then read `this.receipts` in a `function () {}` test. 2. `cy.get('@receipts').then((receipts) => { ... })` inside the test, which queues the read behind the alias. 3. `cy.fixture('receipts.json').then((receipts) => { ... })` with no alias at all, when only one test needs the data. ## Snapshot versus re-run The two access forms diverge once something mutates the value. `this.receipts` is the value stored at the moment `.as()` ran and never re-evaluates. `cy.get('@receipts')` re-executes the chain that produced the alias, so it reflects the current state of that chain. For a fixture that nobody touches the two agree, and for one you deliberately edit mid-test they do not — worth knowing before you spend an afternoon on the difference. ## When an alias is not worth it An alias is machinery, and machinery should earn its place: - A fixture used by exactly one test reads better inline, as `cy.fixture('receipts.json').then(...)` — the data and the assertion that depends on it stay next to each other. - An alias earns its keep when several tests in a spec share the same canned expense data, or when a hook loads it and the test body is the thing that needs it. - Aliasing a narrowed value says more than aliasing the whole file: `cy.fixture('receipts.json').its('approved').as('approvedReceipts')` tells the next reader what this spec actually cares about. - Alias names collide silently. Two hooks that both call `.as('receipts')` leave the innermost one standing, and nothing warns you that the outer fixture is now unreachable. ## A practical shape for an expense-report suite ```js beforeEach(function () { cy.fixture('receipts.json').as('receipts') cy.fixture('approvals.json').as('approvals') }) it('renders one row per receipt', function () { cy.get('[data-testid="receipt-row"]').should('have.length', this.receipts.length) }) ``` Aliasing in the hook, reading in the test, and using `function () {}` for any test that touches `this` keeps the whole file consistent. If a reviewer objects to `this`, the same file works with `cy.get('@receipts').its('length')` and arrow functions throughout — what does not work is mixing the arrow-function form with `this.receipts`.
- Why is this.receipts undefined immediately after cy.fixture('receipts').as('receipts')?Because `.as()` was only queued, not run. Cypress enqueues commands and drains the queue after the test body finishes executing, so the Mocha context has no `receipts` property yet on the next line. Alias in a `beforeEach`, or read the value inside `.then()` or `cy.get('@receipts')` so the read is queued too.
- Does a fixture alias survive into the next test in the same spec?No. Mocha clears its shared context between tests, so `this.receipts` is gone in the following test and `cy.get('@receipts')` fails to find the alias. Recreate it in a `beforeEach` hook. The file's parsed contents may still be cached by Cypress, but the alias itself is per-test.
saying these in an interview costs you the question
- Uses this.receipts inside an arrow-function test
- Reads this.receipts on the line after .as()
- Thinks .as() returns the value to a variable
- Believes a fixture alias persists across tests
- Cannot name a way to read an alias without this