{
  "doc": {
    "id": "app/core-concepts/variables-and-aliases",
    "title": "Variables and aliases in Cypress",
    "description": "Learn how to handle asynchronous code in Cypress, when to assign variables, how to use aliases to share objects between hooks and tests, and how to alias DOM elements, intercepts, and requests.",
    "section": "app",
    "source_path": "/llm/markdown/app/core-concepts/variables-and-aliases.md",
    "version": "29f95bf8bb06f320986f3749f5bf09a35a409eab",
    "updated_at": "2026-09-04T10:49:54.630Z",
    "headings": [
      {
        "id": "app/core-concepts/variables-and-aliases#variables-and-aliases",
        "text": "Variables and Aliases",
        "level": 1
      },
      {
        "id": "app/core-concepts/variables-and-aliases#closures",
        "text": "Closures",
        "level": 2
      },
      {
        "id": "app/core-concepts/variables-and-aliases#debugging",
        "text": "Debugging",
        "level": 2
      },
      {
        "id": "app/core-concepts/variables-and-aliases#variables",
        "text": "Variables",
        "level": 2
      },
      {
        "id": "app/core-concepts/variables-and-aliases#aliases",
        "text": "Aliases",
        "level": 2
      },
      {
        "id": "app/core-concepts/variables-and-aliases#sharing-context",
        "text": "Sharing Context",
        "level": 3
      },
      {
        "id": "app/core-concepts/variables-and-aliases#accessing-fixtures",
        "text": "Accessing Fixtures:",
        "level": 4
      },
      {
        "id": "app/core-concepts/variables-and-aliases#avoiding-the-use-of-this",
        "text": "Avoiding the use of this",
        "level": 4
      },
      {
        "id": "app/core-concepts/variables-and-aliases#elements",
        "text": "Elements",
        "level": 3
      },
      {
        "id": "app/core-concepts/variables-and-aliases#stale-elements",
        "text": "Stale Elements:",
        "level": 4
      },
      {
        "id": "app/core-concepts/variables-and-aliases#intercepts",
        "text": "Intercepts",
        "level": 3
      },
      {
        "id": "app/core-concepts/variables-and-aliases#accessing-multiple-intercepted-requests",
        "text": "Accessing multiple intercepted requests",
        "level": 4
      },
      {
        "id": "app/core-concepts/variables-and-aliases#requests",
        "text": "Requests",
        "level": 3
      },
      {
        "id": "app/core-concepts/variables-and-aliases#aliases-are-reset-before-each-test",
        "text": "Aliases are reset before each test",
        "level": 3
      }
    ]
  },
  "chunks": [
    {
      "id": "app/core-concepts/variables-and-aliases#closures",
      "doc_id": "app/core-concepts/variables-and-aliases",
      "heading": "Closures",
      "heading_level": 2,
      "content_markdown": "## Closures\n\nTo access what each Cypress command yields you use [`.then()`](/llm/markdown/api/commands/then.md).\n\n```\ncy.get('button').then(($btn) => {\n  // $btn is the object that the previous\n  // command yielded us\n})\n```\n\nIf you're familiar with [native Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises) the Cypress `.then()` works similarly. You can continue to nest more Cypress commands inside of the `.then()`.\n\nEach nested command has access to the work done in previous commands. This ends up reading very nicely.\n\n```\ncy.get('button').then(($btn) => {\n\n  // store the button's text\n  const txt = $btn.text()\n\n  // submit a form\n  cy.get('form').submit()\n\n  // compare the two buttons' text\n  // and make sure they are different\n  cy.get('button').should(($btn2) => {\n    expect($btn2.text()).not.to.eq(txt)\n  })\n})\n\n// these commands run after all of the\n// other previous commands have finished\ncy.get(...).find(...).should(...)\n```\n\nThe commands outside of the `.then()` will not run until all of the nested commands finish.\n\nBy using callback functions we've created a [closure](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures). Closures enable us to keep references around to refer to work done in previous commands.\n",
      "section": "app",
      "anchors": [
        "closures"
      ],
      "path": "/llm/json/chunked/app/core-concepts/variables-and-aliases.json",
      "token_estimate": 217
    },
    {
      "id": "app/core-concepts/variables-and-aliases#debugging",
      "doc_id": "app/core-concepts/variables-and-aliases",
      "heading": "Debugging",
      "heading_level": 2,
      "content_markdown": "## Debugging\n\nUsing `.then()` functions is an excellent opportunity to use [`debugger`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger). This can help you understand the order in which commands are run. This also enables you to inspect the objects that Cypress yields you in each command.\n\n```\ncy.get('button').then(($btn) => {\n  // inspect $btn <object>\n  debugger\n\n  cy.get('[data-testid=\"countries\"]')\n    .select('USA')\n    .then(($select) => {\n      // inspect $select <object>\n      debugger\n\n      cy.clock().then(($clock) => {\n        // inspect $clock <object>\n        debugger\n\n        $btn // is still available\n        $select // is still available too\n      })\n    })\n})\n```\n",
      "section": "app",
      "anchors": [
        "debugging"
      ],
      "path": "/llm/json/chunked/app/core-concepts/variables-and-aliases.json",
      "token_estimate": 108
    },
    {
      "id": "app/core-concepts/variables-and-aliases#variables",
      "doc_id": "app/core-concepts/variables-and-aliases",
      "heading": "Variables",
      "heading_level": 2,
      "content_markdown": "## Variables\n\nTypically in Cypress you hardly need to ever use `const`, `let`, or `var`. When using closures you'll always have access to the objects that were yielded to you without assigning them.\n\nThe one exception to this rule is when you are dealing with mutable objects (that change state). When things change state you often want to compare an object's previous value to the next value.\n\nHere's a great use case for a `const`.\n\n```\n<button>increment</button>\n\nyou clicked button <span data-testid=\"num\">0</span> times\n```\n\n```\n// app code\nlet count = 0\n\n$('button').on('click', () => {\n  $('[data-testid=\"num\"]').text((count += 1))\n})\n```\n\n```\n// cypress test code\ncy.get('[data-testid=\"num\"]').then(($span) => {\n  // capture what num is right now\n  const num1 = parseFloat($span.text())\n\n  cy.get('button')\n    .click()\n    .then(() => {\n      // now capture it again\n      const num2 = parseFloat($span.text())\n\n      // make sure it's what we expected\n      expect(num2).to.eq(num1 + 1)\n    })\n})\n```\n\nThe reason for using `const` is because the `$span` object is mutable. Whenever you have mutable objects and you're trying to compare them, you'll need to store their values. Using `const` is a perfect way to do that.\n",
      "section": "app",
      "anchors": [
        "variables"
      ],
      "path": "/llm/json/chunked/app/core-concepts/variables-and-aliases.json",
      "token_estimate": 247
    },
    {
      "id": "app/core-concepts/variables-and-aliases#aliases",
      "doc_id": "app/core-concepts/variables-and-aliases",
      "heading": "Aliases",
      "heading_level": 2,
      "content_markdown": "## Aliases\n\nUsing `.then()` callback functions to access the previous command values is great—but what happens when you're running code in hooks like `before` or `beforeEach`?\n\n```\nbeforeEach(() => {\n  cy.get('button').then(($btn) => {\n    const text = $btn.text()\n  })\n})\n\nit('does not have access to text', () => {\n  // how do we get access to text ?!?!\n})\n```\n\nHow will we get access to `text`?\n\nWe could make our code do some ugly backflips using `let` to get access to it.\n\n**Do not do this**\n\nThis code below is just for demonstration.\n\n```\ndescribe('a suite', () => {\n  // this creates a closure around\n  // 'text' so we can access it\n  let text\n\n  beforeEach(() => {\n    cy.get('button').then(($btn) => {\n      // redefine text reference\n      text = $btn.text()\n    })\n  })\n\n  it('does have access to text', () => {\n    // now text is available to us\n    // but this is not a great solution :(\n    text\n  })\n})\n```\n\nFortunately, you don't have to make your code do backflips. With Cypress, we can better handle these situations.\n\n**Introducing Aliases**\n\nAliases are a powerful construct in Cypress that have many uses. We'll explore each of their capabilities below.\n\nAt first, we'll use them to share objects between your hooks and your tests.\n\n### Sharing Context\n\nSharing context is the simplest way to use aliases.\n\nTo alias something you'd like to share use the [`.as()`](/llm/markdown/api/commands/as.md) command.\n\nLet's look at our previous example with aliases.\n\n```\nbeforeEach(() => {\n  // alias the $btn.text() as 'text'\n  cy.get('button').invoke('text').as('text')\n})\n\nit('has access to text', function () {\n  this.text // is now available\n})\n```\n\nUnder the hood, aliasing basic objects and primitives utilizes Mocha's shared [`context`](https://github.com/mochajs/mocha/wiki/Shared-Behaviours) object: that is, aliases are available as `this.*`.\n\nMocha automatically shares contexts for us across all applicable hooks for each test. Additionally these aliases and properties are automatically cleaned up after each test.\n\n```\ndescribe('parent', () => {\n  beforeEach(() => {\n    cy.wrap('one').as('a')\n  })\n\n  context('child', () => {\n    beforeEach(() => {\n      cy.wrap('two').as('b')\n    })\n\n    describe('grandchild', () => {\n      beforeEach(() => {\n        cy.wrap('three').as('c')\n      })\n\n      it('can access all aliases as properties', function () {\n        expect(this.a).to.eq('one') // true\n        expect(this.b).to.eq('two') // true\n        expect(this.c).to.eq('three') // true\n      })\n    })\n  })\n})\n```\n\n#### Accessing Fixtures:\n\nThe most common use case for sharing context is when dealing with [`cy.fixture()`](/llm/markdown/api/commands/fixture.md).\n\nOften times you may load a fixture in a `beforeEach` hook but want to utilize the values in your tests.\n\n```\nbeforeEach(() => {\n  // alias the users fixtures\n  cy.fixture('users.json').as('users')\n})\n\nit('utilize users in some way', function () {\n  // access the users property\n  const user = this.users[0]\n\n  // make sure the header contains the first\n  // user's name\n  cy.get('header').should('contain', user.name)\n})\n```\n\n**Watch out for async commands**\n\nDo not forget that **Cypress commands are async**!\n\nYou cannot use a `this.*` reference until the `.as()` command runs.\n\n```\nit('is not using aliases correctly', function () {\n  cy.fixture('users.json').as('users')\n\n  // nope this won't work\n  //\n  // this.users is not defined\n  // because the 'as' command has only\n  // been enqueued - it has not run yet\n  const user = this.users[0]\n})\n```\n\nThe same principles we introduced before apply to this situation. If you want to access what a command yields you have to do it in a closure using a [`.then()`](/llm/markdown/api/commands/then.md).\n\n```\n// yup all good\ncy.fixture('users.json').then((users) => {\n  // now we can avoid the alias altogether\n  // and use a callback function\n  const user = users[0]\n\n  // passes\n  cy.get('header').should('contain', user.name)\n})\n```\n\n#### Avoiding the use of `this`\n\n**Arrow Functions**\n\nAccessing aliases as properties with `this.*` will not work if you use [arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) for your tests or hooks.\n\nThis is why all of our examples use the regular `function () {}` syntax as opposed to the lambda \"fat arrow\" syntax `() => {}`.\n\nInstead of using the `this.*` syntax, there is another way to access aliases.\n\nThe [`cy.get()`](/llm/markdown/api/commands/get.md) command is capable of accessing aliases with a special syntax using the `@` character:\n\n```\nbeforeEach(() => {\n  // alias the users fixtures\n  cy.fixture('users.json').as('users')\n})\n\nit('utilize users in some way', function () {\n  // use the special '@' syntax to access aliases\n  // which avoids the use of 'this'\n  cy.get('@users').then((users) => {\n    // access the users argument\n    const user = users[0]\n\n    // make sure the header contains the first\n    // user's name\n    cy.get('header').should('contain', user.name)\n  })\n})\n```\n\nBy using [`cy.get()`](/llm/markdown/api/commands/get.md) we avoid the use of `this`.\n\nKeep in mind that there are use cases for both approaches because they have one major difference.\n\n`this.users` is stored on the Mocha context when `.as()` first runs and never re-evaluates — it behaves like a static snapshot. `cy.get('@users')` re-executes the full query chain every time it is accessed, returning fresh results.\n\n```\nconst favorites = { color: 'blue' }\n\ncy.wrap(favorites).its('color').as('favoriteColor')\n\ncy.then(function () {\n  favorites.color = 'red'\n})\n\ncy.get('@favoriteColor').then(function (aliasValue) {\n  expect(aliasValue).to.eql('red')\n\n  expect(this.favoriteColor).to.eql('blue')\n})\n```\n\nIn the second `.then()` block, `cy.get('@favoriteColor')` runs `cy.wrap(favorites).its('color')` fresh each time, but `this.favoriteColor` was set when the alias was first stored, back when our favorite color was blue.\n\n### Elements\n\nAliases have other special characteristics when being used with DOM elements.\n\nAfter you alias DOM elements, you can then later access them for reuse.\n\n```\n// alias all of the tr's found in the table as 'rows'\ncy.get('table').find('tr').as('rows')\n```\n\nInternally, Cypress stores the **query chain** that produced the `<tr>` collection — not the elements themselves. To access the alias later, use the [`cy.get()`](/llm/markdown/api/commands/get.md) command with the `@` prefix.\n\n```\n// Cypress re-runs the query chain to get fresh <tr>'s,\n// then chains .first() and .click() on the result.\ncy.get('@rows').first().click()\n```\n\nBecause we've used the `@` character in [`cy.get()`](/llm/markdown/api/commands/get.md), Cypress looks up the alias called `rows` and **re-executes its query chain** against the current DOM — it does not return a cached element reference.\n\n#### Stale Elements:\n\nIn many single-page applications, the JavaScript re-renders parts of the DOM constantly. Because Cypress stores the **query chain** — not the resolved elements — every access of a default alias re-runs those queries against the current DOM, so you never end up with stale element references.\n\n```\n<ul id=\"todos\">\n  <li>\n    Walk the dog\n    <button class=\"edit\">edit</button>\n  </li>\n  <li>\n    Feed the cat\n    <button class=\"edit\">edit</button>\n  </li>\n</ul>\n```\n\nLet's imagine when we click the `.edit` button that our `<li>` is re-rendered in the DOM. Instead of displaying the edit button it instead displays an `<input />` text field allowing you to edit the todo. The previous `<li>` has been _completely_ removed from the DOM and a new `<li>` is rendered in its place.\n\n```\ncy.get('[data-testid=\"todos\"] li').first().as('firstTodo')\n\ncy.get('@firstTodo').find('.edit').click()\n\ncy.get('@firstTodo')\n  .should('have.class', 'editing')\n  .find('input')\n  .type('Clean the kitchen')\n```\n\nEvery time we reference `@firstTodo`, Cypress re-runs the queries leading up to the alias definition.\n\nIn our case it would re-query the DOM using: `cy.get('#todos li').first()`. Everything works because the new `<li>` is found.\n\n_Usually_, replaying previous commands will return what you expect, but not always. It is recommended that you **alias elements before running commands**.\n\n*   `cy.get('nav').find('header').find('[data-testid=\"user\"]').as('user').click()` (good)\n*   `cy.get('nav').find('header').find('[data-testid=\"user\"]').click().as('user')` (bad)\n\n### Intercepts\n\nAliases can also be used with [cy.intercept()](/llm/markdown/api/commands/intercept.md). Aliasing your intercepted routes enables you to:\n\n*   ensure your application makes the intended requests\n*   wait for your server to send the response\n*   access the actual request object for assertions\n\nHere's an example of aliasing an intercepted route and waiting on it to complete.\n\n```\ncy.intercept('POST', '/users', { id: 123 }).as('postUser')\n\ncy.get('form').submit()\n\ncy.wait('@postUser').then(({ request }) => {\n  expect(request.body).to.have.property('name', 'Brian')\n})\n\ncy.contains('Successfully created user: Brian')\n```\n\n**New to Cypress?**\n\n[We have a much more detailed and comprehensive guide on routing Network Requests.](/llm/markdown/app/guides/network-requests.md)\n\n#### Accessing multiple intercepted requests\n\nWhen you alias a `cy.intercept()` route, Cypress silently tracks **every** request that matches it — not just the most recent one. By default, `cy.get('@alias')` and `cy.wait('@alias')` only surface the most recent matching request. The `.all` suffix and numeric index notation expose the full history Cypress was already keeping.\n\nThis is useful in several situations:\n\n**Asserting request count.** The most common need is proving your app made _exactly_ the expected number of requests — not just that it made at least one. For example, verifying a polling interval doesn't fire again after some time:\n\n```\ncy.wait('@getList')\ncy.tick(10000)\ncy.get('@getList.all').should('have.length', 1) // still only one request\n```\n\nWithout `.all` there is no clean way to assert count. You can only assert whether a request happened, not how many times.\n\n**Sequential requests with different data.** When your app paginates or retries, requests share a route but carry different parameters. The numeric index lets you validate each one independently:\n\n```\ncy.get('@getUsers.1').its('request.url').should('include', 'page=1')\ncy.get('@getUsers.2').its('request.url').should('include', 'page=2')\n```\n\n**Why not multiple `cy.wait()` calls?** `cy.wait('@alias')` called twice will consume two requests in order, which is useful for _sequencing_ — but it doesn't catch a third unexpected request, and once consumed you can't go back to inspect an earlier one. `cy.get('@alias.all')` is backward-looking: it queries everything Cypress has already captured. The two complement each other — use `cy.wait()` to let requests settle, then `cy.get('@alias.all')` to assert on the full history:\n\n```\ncy.wait('@getUsers') // let requests settle\ncy.get('@getUsers.all') // then assert on everything captured\n  .should('have.length', 2)\n```\n\n```\ncy.intercept('GET', '/users').as('getUsers')\n\n// trigger multiple requests\ncy.visit('/users')\ncy.visit('/users')\n\n// yields an array of all interceptions for this alias\ncy.get('@getUsers.all').then((interceptions) => {\n  expect(interceptions).to.have.length(2)\n})\n```\n\nYou can also retrieve a specific intercept by its 1-based numeric index. Without any suffix, `cy.get('@alias')` returns the most recent intercepted request.\n\n```\ncy.intercept('GET', '/users').as('getUsers')\n\ncy.visit('/users')\ncy.visit('/users')\n\n// yields the first intercepted request\ncy.get('@getUsers.1').its('response.statusCode').should('eq', 200)\n\n// yields the second intercepted request\ncy.get('@getUsers.2').its('response.statusCode').should('eq', 200)\n```\n\nIndex `0` is not valid — indices start at `1`. These suffixes are **not** supported by [`cy.wait()`](/llm/markdown/api/commands/wait.md). Use `cy.get('@alias.all')` instead of `cy.wait('@alias.all')`.\n\n### Requests\n\nAliases can also be used with [requests](/llm/markdown/api/commands/request.md).\n\nHere's an example of aliasing a request and accessing its properties later.\n\n```\ncy.request('https://jsonplaceholder.cypress.io/comments').as('comments')\n\n// other test code here\n\ncy.get('@comments').should((response) => {\n  if (response.status === 200) {\n      expect(response).to.have.property('duration')\n    } else {\n      // whatever you want to check here\n    }\n  })\n})\n```\n\n### Aliases are reset before each test\n\n**Note:** all aliases are reset before each test. A common user mistake is to create aliases using the `before` hook. Such aliases work in the first test only!\n\n```\n// 🚨 THIS EXAMPLE DOES NOT WORK\nbefore(() => {\n  // notice this alias is created just once using \"before\" hook\n  cy.wrap('some value').as('exampleValue')\n})\n\nit('works in the first test', () => {\n  cy.get('@exampleValue').should('equal', 'some value')\n})\n\n// NOTE the second test is failing because the alias is reset\nit('does not exist in the second test', () => {\n  // there is not alias because it is created once before\n  // the first test, and is reset before the second test\n  cy.get('@exampleValue').should('equal', 'some value')\n})\n```\n\nThe solution is to create the aliases before each test using the `beforeEach` hook\n\n```\n// ✅ THE CORRECT EXAMPLE\nbeforeEach(() => {\n  // we will create a new alias before each test\n  cy.wrap('some value').as('exampleValue')\n})\n\nit('works in the first test', () => {\n  cy.get('@exampleValue').should('equal', 'some value')\n})\n\nit('works in the second test', () => {\n  cy.get('@exampleValue').should('equal', 'some value')\n})\n```\n",
      "section": "app",
      "anchors": [
        "aliases"
      ],
      "path": "/llm/json/chunked/app/core-concepts/variables-and-aliases.json",
      "token_estimate": 2420
    },
    {
      "id": "app/core-concepts/variables-and-aliases#sharing-context",
      "doc_id": "app/core-concepts/variables-and-aliases",
      "heading": "Sharing Context",
      "heading_level": 3,
      "content_markdown": "### Sharing Context\n\nSharing context is the simplest way to use aliases.\n\nTo alias something you'd like to share use the [`.as()`](/llm/markdown/api/commands/as.md) command.\n\nLet's look at our previous example with aliases.\n\n```\nbeforeEach(() => {\n  // alias the $btn.text() as 'text'\n  cy.get('button').invoke('text').as('text')\n})\n\nit('has access to text', function () {\n  this.text // is now available\n})\n```\n\nUnder the hood, aliasing basic objects and primitives utilizes Mocha's shared [`context`](https://github.com/mochajs/mocha/wiki/Shared-Behaviours) object: that is, aliases are available as `this.*`.\n\nMocha automatically shares contexts for us across all applicable hooks for each test. Additionally these aliases and properties are automatically cleaned up after each test.\n\n```\ndescribe('parent', () => {\n  beforeEach(() => {\n    cy.wrap('one').as('a')\n  })\n\n  context('child', () => {\n    beforeEach(() => {\n      cy.wrap('two').as('b')\n    })\n\n    describe('grandchild', () => {\n      beforeEach(() => {\n        cy.wrap('three').as('c')\n      })\n\n      it('can access all aliases as properties', function () {\n        expect(this.a).to.eq('one') // true\n        expect(this.b).to.eq('two') // true\n        expect(this.c).to.eq('three') // true\n      })\n    })\n  })\n})\n```\n\n#### Accessing Fixtures:\n\nThe most common use case for sharing context is when dealing with [`cy.fixture()`](/llm/markdown/api/commands/fixture.md).\n\nOften times you may load a fixture in a `beforeEach` hook but want to utilize the values in your tests.\n\n```\nbeforeEach(() => {\n  // alias the users fixtures\n  cy.fixture('users.json').as('users')\n})\n\nit('utilize users in some way', function () {\n  // access the users property\n  const user = this.users[0]\n\n  // make sure the header contains the first\n  // user's name\n  cy.get('header').should('contain', user.name)\n})\n```\n\n**Watch out for async commands**\n\nDo not forget that **Cypress commands are async**!\n\nYou cannot use a `this.*` reference until the `.as()` command runs.\n\n```\nit('is not using aliases correctly', function () {\n  cy.fixture('users.json').as('users')\n\n  // nope this won't work\n  //\n  // this.users is not defined\n  // because the 'as' command has only\n  // been enqueued - it has not run yet\n  const user = this.users[0]\n})\n```\n\nThe same principles we introduced before apply to this situation. If you want to access what a command yields you have to do it in a closure using a [`.then()`](/llm/markdown/api/commands/then.md).\n\n```\n// yup all good\ncy.fixture('users.json').then((users) => {\n  // now we can avoid the alias altogether\n  // and use a callback function\n  const user = users[0]\n\n  // passes\n  cy.get('header').should('contain', user.name)\n})\n```\n\n#### Avoiding the use of `this`\n\n**Arrow Functions**\n\nAccessing aliases as properties with `this.*` will not work if you use [arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) for your tests or hooks.\n\nThis is why all of our examples use the regular `function () {}` syntax as opposed to the lambda \"fat arrow\" syntax `() => {}`.\n\nInstead of using the `this.*` syntax, there is another way to access aliases.\n\nThe [`cy.get()`](/llm/markdown/api/commands/get.md) command is capable of accessing aliases with a special syntax using the `@` character:\n\n```\nbeforeEach(() => {\n  // alias the users fixtures\n  cy.fixture('users.json').as('users')\n})\n\nit('utilize users in some way', function () {\n  // use the special '@' syntax to access aliases\n  // which avoids the use of 'this'\n  cy.get('@users').then((users) => {\n    // access the users argument\n    const user = users[0]\n\n    // make sure the header contains the first\n    // user's name\n    cy.get('header').should('contain', user.name)\n  })\n})\n```\n\nBy using [`cy.get()`](/llm/markdown/api/commands/get.md) we avoid the use of `this`.\n\nKeep in mind that there are use cases for both approaches because they have one major difference.\n\n`this.users` is stored on the Mocha context when `.as()` first runs and never re-evaluates — it behaves like a static snapshot. `cy.get('@users')` re-executes the full query chain every time it is accessed, returning fresh results.\n\n```\nconst favorites = { color: 'blue' }\n\ncy.wrap(favorites).its('color').as('favoriteColor')\n\ncy.then(function () {\n  favorites.color = 'red'\n})\n\ncy.get('@favoriteColor').then(function (aliasValue) {\n  expect(aliasValue).to.eql('red')\n\n  expect(this.favoriteColor).to.eql('blue')\n})\n```\n\nIn the second `.then()` block, `cy.get('@favoriteColor')` runs `cy.wrap(favorites).its('color')` fresh each time, but `this.favoriteColor` was set when the alias was first stored, back when our favorite color was blue.\n",
      "section": "app",
      "anchors": [
        "sharing-context"
      ],
      "path": "/llm/json/chunked/app/core-concepts/variables-and-aliases.json",
      "token_estimate": 823
    },
    {
      "id": "app/core-concepts/variables-and-aliases#accessing-fixtures",
      "doc_id": "app/core-concepts/variables-and-aliases",
      "heading": "Accessing Fixtures:",
      "heading_level": 4,
      "content_markdown": "#### Accessing Fixtures:\n\nThe most common use case for sharing context is when dealing with [`cy.fixture()`](/llm/markdown/api/commands/fixture.md).\n\nOften times you may load a fixture in a `beforeEach` hook but want to utilize the values in your tests.\n\n```\nbeforeEach(() => {\n  // alias the users fixtures\n  cy.fixture('users.json').as('users')\n})\n\nit('utilize users in some way', function () {\n  // access the users property\n  const user = this.users[0]\n\n  // make sure the header contains the first\n  // user's name\n  cy.get('header').should('contain', user.name)\n})\n```\n\n**Watch out for async commands**\n\nDo not forget that **Cypress commands are async**!\n\nYou cannot use a `this.*` reference until the `.as()` command runs.\n\n```\nit('is not using aliases correctly', function () {\n  cy.fixture('users.json').as('users')\n\n  // nope this won't work\n  //\n  // this.users is not defined\n  // because the 'as' command has only\n  // been enqueued - it has not run yet\n  const user = this.users[0]\n})\n```\n\nThe same principles we introduced before apply to this situation. If you want to access what a command yields you have to do it in a closure using a [`.then()`](/llm/markdown/api/commands/then.md).\n\n```\n// yup all good\ncy.fixture('users.json').then((users) => {\n  // now we can avoid the alias altogether\n  // and use a callback function\n  const user = users[0]\n\n  // passes\n  cy.get('header').should('contain', user.name)\n})\n```\n",
      "section": "app",
      "anchors": [
        "accessing-fixtures"
      ],
      "path": "/llm/json/chunked/app/core-concepts/variables-and-aliases.json",
      "token_estimate": 277
    },
    {
      "id": "app/core-concepts/variables-and-aliases#avoiding-the-use-of-this",
      "doc_id": "app/core-concepts/variables-and-aliases",
      "heading": "Avoiding the use of this",
      "heading_level": 4,
      "content_markdown": "#### Avoiding the use of `this`\n\n**Arrow Functions**\n\nAccessing aliases as properties with `this.*` will not work if you use [arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) for your tests or hooks.\n\nThis is why all of our examples use the regular `function () {}` syntax as opposed to the lambda \"fat arrow\" syntax `() => {}`.\n\nInstead of using the `this.*` syntax, there is another way to access aliases.\n\nThe [`cy.get()`](/llm/markdown/api/commands/get.md) command is capable of accessing aliases with a special syntax using the `@` character:\n\n```\nbeforeEach(() => {\n  // alias the users fixtures\n  cy.fixture('users.json').as('users')\n})\n\nit('utilize users in some way', function () {\n  // use the special '@' syntax to access aliases\n  // which avoids the use of 'this'\n  cy.get('@users').then((users) => {\n    // access the users argument\n    const user = users[0]\n\n    // make sure the header contains the first\n    // user's name\n    cy.get('header').should('contain', user.name)\n  })\n})\n```\n\nBy using [`cy.get()`](/llm/markdown/api/commands/get.md) we avoid the use of `this`.\n\nKeep in mind that there are use cases for both approaches because they have one major difference.\n\n`this.users` is stored on the Mocha context when `.as()` first runs and never re-evaluates — it behaves like a static snapshot. `cy.get('@users')` re-executes the full query chain every time it is accessed, returning fresh results.\n\n```\nconst favorites = { color: 'blue' }\n\ncy.wrap(favorites).its('color').as('favoriteColor')\n\ncy.then(function () {\n  favorites.color = 'red'\n})\n\ncy.get('@favoriteColor').then(function (aliasValue) {\n  expect(aliasValue).to.eql('red')\n\n  expect(this.favoriteColor).to.eql('blue')\n})\n```\n\nIn the second `.then()` block, `cy.get('@favoriteColor')` runs `cy.wrap(favorites).its('color')` fresh each time, but `this.favoriteColor` was set when the alias was first stored, back when our favorite color was blue.\n",
      "section": "app",
      "anchors": [
        "avoiding-the-use-of-this"
      ],
      "path": "/llm/json/chunked/app/core-concepts/variables-and-aliases.json",
      "token_estimate": 341
    },
    {
      "id": "app/core-concepts/variables-and-aliases#elements",
      "doc_id": "app/core-concepts/variables-and-aliases",
      "heading": "Elements",
      "heading_level": 3,
      "content_markdown": "### Elements\n\nAliases have other special characteristics when being used with DOM elements.\n\nAfter you alias DOM elements, you can then later access them for reuse.\n\n```\n// alias all of the tr's found in the table as 'rows'\ncy.get('table').find('tr').as('rows')\n```\n\nInternally, Cypress stores the **query chain** that produced the `<tr>` collection — not the elements themselves. To access the alias later, use the [`cy.get()`](/llm/markdown/api/commands/get.md) command with the `@` prefix.\n\n```\n// Cypress re-runs the query chain to get fresh <tr>'s,\n// then chains .first() and .click() on the result.\ncy.get('@rows').first().click()\n```\n\nBecause we've used the `@` character in [`cy.get()`](/llm/markdown/api/commands/get.md), Cypress looks up the alias called `rows` and **re-executes its query chain** against the current DOM — it does not return a cached element reference.\n\n#### Stale Elements:\n\nIn many single-page applications, the JavaScript re-renders parts of the DOM constantly. Because Cypress stores the **query chain** — not the resolved elements — every access of a default alias re-runs those queries against the current DOM, so you never end up with stale element references.\n\n```\n<ul id=\"todos\">\n  <li>\n    Walk the dog\n    <button class=\"edit\">edit</button>\n  </li>\n  <li>\n    Feed the cat\n    <button class=\"edit\">edit</button>\n  </li>\n</ul>\n```\n\nLet's imagine when we click the `.edit` button that our `<li>` is re-rendered in the DOM. Instead of displaying the edit button it instead displays an `<input />` text field allowing you to edit the todo. The previous `<li>` has been _completely_ removed from the DOM and a new `<li>` is rendered in its place.\n\n```\ncy.get('[data-testid=\"todos\"] li').first().as('firstTodo')\n\ncy.get('@firstTodo').find('.edit').click()\n\ncy.get('@firstTodo')\n  .should('have.class', 'editing')\n  .find('input')\n  .type('Clean the kitchen')\n```\n\nEvery time we reference `@firstTodo`, Cypress re-runs the queries leading up to the alias definition.\n\nIn our case it would re-query the DOM using: `cy.get('#todos li').first()`. Everything works because the new `<li>` is found.\n\n_Usually_, replaying previous commands will return what you expect, but not always. It is recommended that you **alias elements before running commands**.\n\n*   `cy.get('nav').find('header').find('[data-testid=\"user\"]').as('user').click()` (good)\n*   `cy.get('nav').find('header').find('[data-testid=\"user\"]').click().as('user')` (bad)\n",
      "section": "app",
      "anchors": [
        "elements"
      ],
      "path": "/llm/json/chunked/app/core-concepts/variables-and-aliases.json",
      "token_estimate": 429
    },
    {
      "id": "app/core-concepts/variables-and-aliases#stale-elements",
      "doc_id": "app/core-concepts/variables-and-aliases",
      "heading": "Stale Elements:",
      "heading_level": 4,
      "content_markdown": "#### Stale Elements:\n\nIn many single-page applications, the JavaScript re-renders parts of the DOM constantly. Because Cypress stores the **query chain** — not the resolved elements — every access of a default alias re-runs those queries against the current DOM, so you never end up with stale element references.\n\n```\n<ul id=\"todos\">\n  <li>\n    Walk the dog\n    <button class=\"edit\">edit</button>\n  </li>\n  <li>\n    Feed the cat\n    <button class=\"edit\">edit</button>\n  </li>\n</ul>\n```\n\nLet's imagine when we click the `.edit` button that our `<li>` is re-rendered in the DOM. Instead of displaying the edit button it instead displays an `<input />` text field allowing you to edit the todo. The previous `<li>` has been _completely_ removed from the DOM and a new `<li>` is rendered in its place.\n\n```\ncy.get('[data-testid=\"todos\"] li').first().as('firstTodo')\n\ncy.get('@firstTodo').find('.edit').click()\n\ncy.get('@firstTodo')\n  .should('have.class', 'editing')\n  .find('input')\n  .type('Clean the kitchen')\n```\n\nEvery time we reference `@firstTodo`, Cypress re-runs the queries leading up to the alias definition.\n\nIn our case it would re-query the DOM using: `cy.get('#todos li').first()`. Everything works because the new `<li>` is found.\n\n_Usually_, replaying previous commands will return what you expect, but not always. It is recommended that you **alias elements before running commands**.\n\n*   `cy.get('nav').find('header').find('[data-testid=\"user\"]').as('user').click()` (good)\n*   `cy.get('nav').find('header').find('[data-testid=\"user\"]').click().as('user')` (bad)\n",
      "section": "app",
      "anchors": [
        "stale-elements"
      ],
      "path": "/llm/json/chunked/app/core-concepts/variables-and-aliases.json",
      "token_estimate": 263
    },
    {
      "id": "app/core-concepts/variables-and-aliases#intercepts",
      "doc_id": "app/core-concepts/variables-and-aliases",
      "heading": "Intercepts",
      "heading_level": 3,
      "content_markdown": "### Intercepts\n\nAliases can also be used with [cy.intercept()](/llm/markdown/api/commands/intercept.md). Aliasing your intercepted routes enables you to:\n\n*   ensure your application makes the intended requests\n*   wait for your server to send the response\n*   access the actual request object for assertions\n\nHere's an example of aliasing an intercepted route and waiting on it to complete.\n\n```\ncy.intercept('POST', '/users', { id: 123 }).as('postUser')\n\ncy.get('form').submit()\n\ncy.wait('@postUser').then(({ request }) => {\n  expect(request.body).to.have.property('name', 'Brian')\n})\n\ncy.contains('Successfully created user: Brian')\n```\n\n**New to Cypress?**\n\n[We have a much more detailed and comprehensive guide on routing Network Requests.](/llm/markdown/app/guides/network-requests.md)\n\n#### Accessing multiple intercepted requests\n\nWhen you alias a `cy.intercept()` route, Cypress silently tracks **every** request that matches it — not just the most recent one. By default, `cy.get('@alias')` and `cy.wait('@alias')` only surface the most recent matching request. The `.all` suffix and numeric index notation expose the full history Cypress was already keeping.\n\nThis is useful in several situations:\n\n**Asserting request count.** The most common need is proving your app made _exactly_ the expected number of requests — not just that it made at least one. For example, verifying a polling interval doesn't fire again after some time:\n\n```\ncy.wait('@getList')\ncy.tick(10000)\ncy.get('@getList.all').should('have.length', 1) // still only one request\n```\n\nWithout `.all` there is no clean way to assert count. You can only assert whether a request happened, not how many times.\n\n**Sequential requests with different data.** When your app paginates or retries, requests share a route but carry different parameters. The numeric index lets you validate each one independently:\n\n```\ncy.get('@getUsers.1').its('request.url').should('include', 'page=1')\ncy.get('@getUsers.2').its('request.url').should('include', 'page=2')\n```\n\n**Why not multiple `cy.wait()` calls?** `cy.wait('@alias')` called twice will consume two requests in order, which is useful for _sequencing_ — but it doesn't catch a third unexpected request, and once consumed you can't go back to inspect an earlier one. `cy.get('@alias.all')` is backward-looking: it queries everything Cypress has already captured. The two complement each other — use `cy.wait()` to let requests settle, then `cy.get('@alias.all')` to assert on the full history:\n\n```\ncy.wait('@getUsers') // let requests settle\ncy.get('@getUsers.all') // then assert on everything captured\n  .should('have.length', 2)\n```\n\n```\ncy.intercept('GET', '/users').as('getUsers')\n\n// trigger multiple requests\ncy.visit('/users')\ncy.visit('/users')\n\n// yields an array of all interceptions for this alias\ncy.get('@getUsers.all').then((interceptions) => {\n  expect(interceptions).to.have.length(2)\n})\n```\n\nYou can also retrieve a specific intercept by its 1-based numeric index. Without any suffix, `cy.get('@alias')` returns the most recent intercepted request.\n\n```\ncy.intercept('GET', '/users').as('getUsers')\n\ncy.visit('/users')\ncy.visit('/users')\n\n// yields the first intercepted request\ncy.get('@getUsers.1').its('response.statusCode').should('eq', 200)\n\n// yields the second intercepted request\ncy.get('@getUsers.2').its('response.statusCode').should('eq', 200)\n```\n\nIndex `0` is not valid — indices start at `1`. These suffixes are **not** supported by [`cy.wait()`](/llm/markdown/api/commands/wait.md). Use `cy.get('@alias.all')` instead of `cy.wait('@alias.all')`.\n",
      "section": "app",
      "anchors": [
        "intercepts"
      ],
      "path": "/llm/json/chunked/app/core-concepts/variables-and-aliases.json",
      "token_estimate": 579
    },
    {
      "id": "app/core-concepts/variables-and-aliases#accessing-multiple-intercepted-requests",
      "doc_id": "app/core-concepts/variables-and-aliases",
      "heading": "Accessing multiple intercepted requests",
      "heading_level": 4,
      "content_markdown": "#### Accessing multiple intercepted requests\n\nWhen you alias a `cy.intercept()` route, Cypress silently tracks **every** request that matches it — not just the most recent one. By default, `cy.get('@alias')` and `cy.wait('@alias')` only surface the most recent matching request. The `.all` suffix and numeric index notation expose the full history Cypress was already keeping.\n\nThis is useful in several situations:\n\n**Asserting request count.** The most common need is proving your app made _exactly_ the expected number of requests — not just that it made at least one. For example, verifying a polling interval doesn't fire again after some time:\n\n```\ncy.wait('@getList')\ncy.tick(10000)\ncy.get('@getList.all').should('have.length', 1) // still only one request\n```\n\nWithout `.all` there is no clean way to assert count. You can only assert whether a request happened, not how many times.\n\n**Sequential requests with different data.** When your app paginates or retries, requests share a route but carry different parameters. The numeric index lets you validate each one independently:\n\n```\ncy.get('@getUsers.1').its('request.url').should('include', 'page=1')\ncy.get('@getUsers.2').its('request.url').should('include', 'page=2')\n```\n\n**Why not multiple `cy.wait()` calls?** `cy.wait('@alias')` called twice will consume two requests in order, which is useful for _sequencing_ — but it doesn't catch a third unexpected request, and once consumed you can't go back to inspect an earlier one. `cy.get('@alias.all')` is backward-looking: it queries everything Cypress has already captured. The two complement each other — use `cy.wait()` to let requests settle, then `cy.get('@alias.all')` to assert on the full history:\n\n```\ncy.wait('@getUsers') // let requests settle\ncy.get('@getUsers.all') // then assert on everything captured\n  .should('have.length', 2)\n```\n\n```\ncy.intercept('GET', '/users').as('getUsers')\n\n// trigger multiple requests\ncy.visit('/users')\ncy.visit('/users')\n\n// yields an array of all interceptions for this alias\ncy.get('@getUsers.all').then((interceptions) => {\n  expect(interceptions).to.have.length(2)\n})\n```\n\nYou can also retrieve a specific intercept by its 1-based numeric index. Without any suffix, `cy.get('@alias')` returns the most recent intercepted request.\n\n```\ncy.intercept('GET', '/users').as('getUsers')\n\ncy.visit('/users')\ncy.visit('/users')\n\n// yields the first intercepted request\ncy.get('@getUsers.1').its('response.statusCode').should('eq', 200)\n\n// yields the second intercepted request\ncy.get('@getUsers.2').its('response.statusCode').should('eq', 200)\n```\n\nIndex `0` is not valid — indices start at `1`. These suffixes are **not** supported by [`cy.wait()`](/llm/markdown/api/commands/wait.md). Use `cy.get('@alias.all')` instead of `cy.wait('@alias.all')`.\n",
      "section": "app",
      "anchors": [
        "accessing-multiple-intercepted-requests"
      ],
      "path": "/llm/json/chunked/app/core-concepts/variables-and-aliases.json",
      "token_estimate": 456
    },
    {
      "id": "app/core-concepts/variables-and-aliases#requests",
      "doc_id": "app/core-concepts/variables-and-aliases",
      "heading": "Requests",
      "heading_level": 3,
      "content_markdown": "### Requests\n\nAliases can also be used with [requests](/llm/markdown/api/commands/request.md).\n\nHere's an example of aliasing a request and accessing its properties later.\n\n```\ncy.request('https://jsonplaceholder.cypress.io/comments').as('comments')\n\n// other test code here\n\ncy.get('@comments').should((response) => {\n  if (response.status === 200) {\n      expect(response).to.have.property('duration')\n    } else {\n      // whatever you want to check here\n    }\n  })\n})\n```\n",
      "section": "app",
      "anchors": [
        "requests"
      ],
      "path": "/llm/json/chunked/app/core-concepts/variables-and-aliases.json",
      "token_estimate": 68
    },
    {
      "id": "app/core-concepts/variables-and-aliases#aliases-are-reset-before-each-test",
      "doc_id": "app/core-concepts/variables-and-aliases",
      "heading": "Aliases are reset before each test",
      "heading_level": 3,
      "content_markdown": "### Aliases are reset before each test\n\n**Note:** all aliases are reset before each test. A common user mistake is to create aliases using the `before` hook. Such aliases work in the first test only!\n\n```\n// 🚨 THIS EXAMPLE DOES NOT WORK\nbefore(() => {\n  // notice this alias is created just once using \"before\" hook\n  cy.wrap('some value').as('exampleValue')\n})\n\nit('works in the first test', () => {\n  cy.get('@exampleValue').should('equal', 'some value')\n})\n\n// NOTE the second test is failing because the alias is reset\nit('does not exist in the second test', () => {\n  // there is not alias because it is created once before\n  // the first test, and is reset before the second test\n  cy.get('@exampleValue').should('equal', 'some value')\n})\n```\n\nThe solution is to create the aliases before each test using the `beforeEach` hook\n\n```\n// ✅ THE CORRECT EXAMPLE\nbeforeEach(() => {\n  // we will create a new alias before each test\n  cy.wrap('some value').as('exampleValue')\n})\n\nit('works in the first test', () => {\n  cy.get('@exampleValue').should('equal', 'some value')\n})\n\nit('works in the second test', () => {\n  cy.get('@exampleValue').should('equal', 'some value')\n})\n```\n",
      "section": "app",
      "anchors": [
        "aliases-are-reset-before-each-test"
      ],
      "path": "/llm/json/chunked/app/core-concepts/variables-and-aliases.json",
      "token_estimate": 243
    }
  ]
}