In Cypress, a room row is aliased with `.as('firstRoom')` and then re-renders. What does `cy.get('@firstRoom')` yield?
answer
- Ask what the name actually points at
- Something is re-run, not remembered
- A stale element reference never forms
- The as() options object has one key
- this.name and the at-sign can disagree
basics
~20 sThe freshly rendered row. By default Cypress stores the chain of queries that produced the subject rather than the element itself, so reading the alias re-runs those queries against the current DOM instead of returning a stale reference.
solid answer
~40 sAs of Cypress 16, `.as()` creates a **query alias** by default: Cypress records the queries that produced the subject — here `cy.get('.room-list li').first()` — and `cy.get('@firstRoom')` re-executes them against the current DOM every time you read it. When the row re-renders, the alias resolves to the new row, and nothing goes stale. Two things opt out of that. `.as('firstRoom', { type: 'static' })` resolves the value once and never re-evaluates it, and `this.firstRoom` — the Mocha context property Cypress also sets — is a snapshot taken when `.as()` ran, so it can disagree with `cy.get('@firstRoom')` after the page changes. Alias *before* you act: putting `.as()` after a command leaves Cypress a resolved element with no queries left to replay. All aliases are cleared before each test.
code
javascript · 7 lines// the room row is torn out and re-rendered when its date picker opens
cy.get('.room-list li').first().as('firstRoom')
cy.get('@firstRoom').find('.change-dates').click()
// the old <li> is gone; reading the alias replays get + first
cy.get('@firstRoom').find('input[name="checkIn"]').type('2026-10-02')go deeper
Recall the two halves: .as('name') creates the alias and cy.get('@name') reads it back. Knowing that aliases are wiped before each test saves you from a genuinely confusing failure.
Explain what Cypress stores - the queries, not the element - and what the type option changes. Expect to be pushed on why that makes a re-rendered row still resolve correctly.
This is where lived experience shows. Describe a suite where an alias resolved to something other than the row its author meant, why aliasing after an action caused it, and the rule you adopted afterwards.
Own the convention: which subjects deserve an alias at all, whether static aliases are permitted, and how you stop a shared beforeEach from handing every spec a subject it did not expect.
## An alias is a recipe, not a reference `.as('firstRoom')` does not put the `<li>` in a box. As of Cypress 16, an alias created by `.as()` is a **query alias** by default: Cypress records the chain of queries that produced the subject — for `cy.get('.room-list li').first().as('firstRoom')` that is *get these list items, then take the first* — and stores that chain under the name. Reading it with `cy.get('@firstRoom')` re-executes the recorded queries against the DOM **as it is right now**. So when the room row is torn out and re-rendered because the guest opened its date picker, the alias resolves to the new row. There was never a pointer to the old node to go stale. That is the answer to the question, and it is worth saying the reason out loud: a browser suite spends its life against an app that re-renders under it, and an alias that held an element reference would be wrong more often than right. ## Three ways to read the same alias Cypress sets a Mocha context property at the same time, which is why `this.firstRoom` also works and why the two can disagree. | how you read it | what you get | changes when the page does | |---|---|---| | `cy.get('@firstRoom')` | the queries re-run against the current DOM | yes | | `this.firstRoom` (needs `function () {}`, not an arrow) | the value captured when `.as()` ran | no | | `.as('firstRoom', { type: 'static' })`, then `cy.get('@firstRoom')` | the value captured when `.as()` ran | no | The `type` option takes `query` (the default) or `static`. A static alias is resolved once, at the moment it is stored, and never re-evaluated. That is genuinely useful for a **value** you want to compare against later — the advertised nightly rate before a discount code is applied, say — and exactly wrong for an element you expect to be re-rendered. ## The trap: aliasing after you act The recorded chain only replays as far as Cypress can recompute it. Queries are replayable; commands are not. If you write the `.as()` after an action, what gets stored is a resolved element with nothing left to re-run: ```js // good - the alias records get + first, both replayable cy.get('.room-list li').first().as('firstRoom') cy.get('@firstRoom').find('.change-dates').click() // risky - the chain ends at a command, so the alias holds a resolved element cy.get('.room-list li').first().click().as('firstRoom') ``` The documented rule is short: **alias elements before running commands on them**. Replaying previous commands usually returns what you expect, but "usually" is doing real work in that sentence, and putting `.as()` at the end of a chain that acted on the page is how you land on the exception. ## What aliases are actually for Worth saying, because the mechanism is easier to remember once the purpose is clear. Aliases exist to move a subject across a boundary a chain cannot cross: - **From a hook into a test.** A `beforeEach` that opens the booking page and aliases the room list gives every `it` in the block a named handle without a module-level variable. - **Across a gap in the test.** You alias the guest form early, drive the date picker for ten lines, and come back to `cy.get('@guestForm')` without re-typing the chain that found it. - **Away from `this`.** The `@` form works in arrow-function tests, where `this.guestForm` does not, because arrow functions do not get Mocha's context binding. Named subjects also read better in a failure: the Command Log shows the alias name, so a reader sees *firstRoom* rather than a selector they have to decode. ## Housekeeping that catches people out - **Aliases are reset before each test.** One created in a `beforeEach` is available to every test in that block; one created in `it` A is gone in `it` B. - **`.as()` is asynchronous like every other command.** You cannot read `this.firstRoom` on the line after `.as()` in the same test body — the command has only been queued. Read it inside a callback, or with `cy.get('@firstRoom')`. - **Some names are reserved.** `test`, `runnable`, `timeout`, `slow`, `skip` and `inspect` are rejected as alias names, because they would collide with Mocha's own context. - **A missing alias fails immediately** with *cy.get() could not find a registered alias for: `@firstRoom`*, listing the aliases that do exist. Cypress does not fall back to treating the string as a CSS selector, so a typo is reported as a typo. ## What to demonstrate The junior half of this is "`.as()` names it, `cy.get('@name')` reads it back". The part that shows experience is the failure story: an alias defined at the end of a chain that had already clicked, which then resolved to a row that no longer existed after a re-render, producing a failure whose message pointed at a command several lines away from the actual mistake. The fix is one line moved, and the rule that prevents it — alias first, act second — is worth stating as a convention rather than as a fact you happen to know.
- When is `.as('nightlyRate', { type: 'static' })` the right choice in a Cypress test?When you want the value exactly as it was when you captured it — a room's advertised nightly rate before a discount code is applied, say — so you can compare it with the value shown afterwards. A static alias is resolved once and never re-evaluated, which is precisely what you do not want for an element you expect to re-render.
- What does Cypress do when `cy.get('@guestForm')` names an alias that was never created?It fails immediately with *cy.get() could not find a registered alias for: `@guestForm`* and lists the aliases that do exist, or says you have not aliased anything yet. It never falls back to treating the string as a CSS selector, so a mistyped alias is reported as the test-code mistake it is rather than as a missing element.
saying these in an interview costs you the question
- Says an alias stores the DOM element itself
- Thinks this.firstRoom and cy.get('@firstRoom') always agree
- Expects aliases to survive into the next test
- Aliases an element after clicking it, then reuses it