{
  "doc": {
    "id": "api/commands/session",
    "title": "session | Cypress Documentation",
    "description": "Cache and restore cookies, localStorage, and sessionStorage in order to recreate a consistent browser context between tests in Cypress.",
    "section": "api",
    "source_path": "/llm/markdown/api/commands/session.md",
    "version": "e6988a974973e9090ce70406c38cb2b9e0eac9fa",
    "updated_at": "2026-05-15T15:50:22.536Z",
    "headings": [
      {
        "id": "api/commands/session#session",
        "text": "session",
        "level": 1
      },
      {
        "id": "api/commands/session#syntax",
        "text": "Syntax",
        "level": 2
      },
      {
        "id": "api/commands/session#usage",
        "text": "Usage",
        "level": 3
      },
      {
        "id": "api/commands/session#arguments",
        "text": "Arguments",
        "level": 3
      },
      {
        "id": "api/commands/session#yields-learn-about-subject-management",
        "text": "Yields Learn about subject management",
        "level": 3
      },
      {
        "id": "api/commands/session#examples",
        "text": "Examples",
        "level": 2
      },
      {
        "id": "api/commands/session#updating-an-existing-login-custom-command",
        "text": "Updating an existing login custom command",
        "level": 3
      },
      {
        "id": "api/commands/session#updating-an-existing-login-helper-function",
        "text": "Updating an existing login helper function",
        "level": 3
      },
      {
        "id": "api/commands/session#switching-sessions-inside-tests",
        "text": "Switching sessions inside tests",
        "level": 3
      },
      {
        "id": "api/commands/session#validating-the-session",
        "text": "Validating the session",
        "level": 3
      },
      {
        "id": "api/commands/session#modifying-session-data-before-caching",
        "text": "Modifying session data before caching",
        "level": 3
      },
      {
        "id": "api/commands/session#caching-session-data-across-specs",
        "text": "Caching session data across specs",
        "level": 3
      },
      {
        "id": "api/commands/session#multiple-login-commands",
        "text": "Multiple login commands",
        "level": 3
      },
      {
        "id": "api/commands/session#where-to-call-cy-visit",
        "text": "Where to call cy.visit()",
        "level": 3
      },
      {
        "id": "api/commands/session#updating-a-login-function-that-returns-a-value",
        "text": "Updating a login function that returns a value",
        "level": 3
      },
      {
        "id": "api/commands/session#cross-domain-sessions",
        "text": "Cross-domain sessions",
        "level": 3
      },
      {
        "id": "api/commands/session#notes",
        "text": "Notes",
        "level": 2
      },
      {
        "id": "api/commands/session#when-the-page-and-session-data-are-cleared",
        "text": "When the page and session data are cleared",
        "level": 3
      },
      {
        "id": "api/commands/session#test-isolation-enabled",
        "text": "Test Isolation Enabled",
        "level": 3
      },
      {
        "id": "api/commands/session#test-isolation-disabled",
        "text": "Test Isolation Disabled",
        "level": 3
      },
      {
        "id": "api/commands/session#session-caching",
        "text": "Session caching",
        "level": 3
      },
      {
        "id": "api/commands/session#explicitly-clearing-sessions",
        "text": "Explicitly clearing sessions",
        "level": 3
      },
      {
        "id": "api/commands/session#where-to-call-cy-session",
        "text": "Where to call cy.session()",
        "level": 3
      },
      {
        "id": "api/commands/session#choosing-the-correct-id-to-cache-a-session",
        "text": "Choosing the correct id to cache a session",
        "level": 3
      },
      {
        "id": "api/commands/session#common-questions",
        "text": "Common Questions",
        "level": 3
      },
      {
        "id": "api/commands/session#why-are-all-my-cypress-commands-failing-after-calling-cy-session",
        "text": "Why are all my Cypress commands failing after calling cy.session()?",
        "level": 4
      },
      {
        "id": "api/commands/session#why-am-i-seeing-401-errors-after-calling-cy-session",
        "text": "Why am I seeing 401 errors after calling cy.session()?",
        "level": 4
      },
      {
        "id": "api/commands/session#command-log",
        "text": "Command Log",
        "level": 2
      },
      {
        "id": "api/commands/session#the-instrument-panel",
        "text": "The Instrument Panel",
        "level": 3
      },
      {
        "id": "api/commands/session#history",
        "text": "History",
        "level": 2
      },
      {
        "id": "api/commands/session#see-also",
        "text": "See also",
        "level": 2
      }
    ]
  },
  "chunks": [
    {
      "id": "api/commands/session#syntax",
      "doc_id": "api/commands/session",
      "heading": "Syntax",
      "heading_level": 2,
      "content_markdown": "## Syntax\n\n```\ncy.session(id, setup)cy.session(id, setup, options)\n```\n\n### Usage\n\n**Correct Usage**\n\n```\n// Caching session when logging in via page visitcy.session(name, () => {  cy.visit('/login')  cy.get('[data-test=name]').type(name)  cy.get('[data-test=password]').type('s3cr3t')  cy.get('form').contains('Log In').click()  cy.url().should('contain', '/login-successful')})// Caching session when logging in via APIcy.session(username, () => {  cy.request({    method: 'POST',    url: '/login',    body: { username, password },  }).then(({ body }) => {    window.localStorage.setItem('authToken', body.token)  })})\n```\n\n**Incorrect Usage**\n\n```\n// visiting before calling cy.session() is redundant, it needs to// be done inside the setup functioncy.visit('/login')cy.session(name, () => {  // need to call cy.visit() here because the page is blank when  // the setup function runs  cy.get('[data-test=name]').type(name)  cy.get('[data-test=password]').type('s3cr3t')  cy.get('form').contains('Log In').click()  // should assert that login was successful here to guarantee the  // login process completes before it is cached})// should have asserted this inside the cy.session() setup// function because the page is blank herecy.url().should('contain', '/login-successful')\n```\n\n### Arguments\n\n**id _(String, Array, Object)_**\n\nA unique identifier that will be used to cache and restore a given session. In simple cases, a `String` value is sufficient. In order to simplify generation of more complex ids, if you pass an `Array` or `Object`, Cypress will generate an id for you by deterministically stringifying the value you pass in. For example, if you pass `['Jane', '123', 'admin']`, an id of `[\"Jane\",\"123\",\"admin\"]` will be generated for you.\n\nSee the [choosing the correct id to cache a session](#Choosing-the-correct-id-to-cache-a-session) section for a more thorough explanation with examples.\n\nNote that large or cyclical data structures may be slow or difficult to serialize into an identifier, so exercise care with the data you specify.\n\n**setup _(Function)_**\n\nThis function is called whenever a session for the given `id` hasn't yet been cached, or if it's no longer valid (see the `validate` option). After `setup` and `validate` runs for the first time, Cypress will preserve all cookies, `sessionStorage`, and `localStorage`, so that subsequent calls to `cy.session()` with the same `id` will bypass setup and just restore and validate the cached session data.\n\nThe page is cleared before `setup` when `testIsolation` is enabled and is not cleared when `testIsolation` is disabled.\n\nCookies, local storage and session storage in all domains are always cleared before `setup` runs, regardless of the `testIsolation` configuration.\n\n**options _(Object)_**\n\n| Option | Default | Description |\n| --- | --- | --- |\n| `validate` | `undefined` | Validates the newly-created or restored session. Function to run immediately after the session is created and `setup` function runs or after a session is restored and the page is cleared. If it throws an exception, contains any failing Cypress command, returns a Promise which rejects or resolves to `false`, or the last Cypress command yielded `false`, the session is considered invalid.  \n  \n\\- If validation fails immediately after `setup`, the test will fail.  \n\\- If validation fails after restoring a session, `setup` will re-run. |\n| `cacheAcrossSpecs` | `false` | When enabled, the newly created session is considered \"global\" and can be restored in any spec during the test execution in the same Cypress run on the same machine. Use this option for a session that will be used multiple times, across many specs. |\n\n### Yields [Learn about subject management](/llm/markdown/app/core-concepts/introduction-to-cypress.md#Subject-Management)\n\n*   `cy.session()` yields `null`.\n",
      "section": "api",
      "anchors": [
        "syntax"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 704
    },
    {
      "id": "api/commands/session#usage",
      "doc_id": "api/commands/session",
      "heading": "Usage",
      "heading_level": 3,
      "content_markdown": "### Usage\n\n**Correct Usage**\n\n```\n// Caching session when logging in via page visitcy.session(name, () => {  cy.visit('/login')  cy.get('[data-test=name]').type(name)  cy.get('[data-test=password]').type('s3cr3t')  cy.get('form').contains('Log In').click()  cy.url().should('contain', '/login-successful')})// Caching session when logging in via APIcy.session(username, () => {  cy.request({    method: 'POST',    url: '/login',    body: { username, password },  }).then(({ body }) => {    window.localStorage.setItem('authToken', body.token)  })})\n```\n\n**Incorrect Usage**\n\n```\n// visiting before calling cy.session() is redundant, it needs to// be done inside the setup functioncy.visit('/login')cy.session(name, () => {  // need to call cy.visit() here because the page is blank when  // the setup function runs  cy.get('[data-test=name]').type(name)  cy.get('[data-test=password]').type('s3cr3t')  cy.get('form').contains('Log In').click()  // should assert that login was successful here to guarantee the  // login process completes before it is cached})// should have asserted this inside the cy.session() setup// function because the page is blank herecy.url().should('contain', '/login-successful')\n```\n",
      "section": "api",
      "anchors": [
        "usage"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 176
    },
    {
      "id": "api/commands/session#arguments",
      "doc_id": "api/commands/session",
      "heading": "Arguments",
      "heading_level": 3,
      "content_markdown": "### Arguments\n\n**id _(String, Array, Object)_**\n\nA unique identifier that will be used to cache and restore a given session. In simple cases, a `String` value is sufficient. In order to simplify generation of more complex ids, if you pass an `Array` or `Object`, Cypress will generate an id for you by deterministically stringifying the value you pass in. For example, if you pass `['Jane', '123', 'admin']`, an id of `[\"Jane\",\"123\",\"admin\"]` will be generated for you.\n\nSee the [choosing the correct id to cache a session](#Choosing-the-correct-id-to-cache-a-session) section for a more thorough explanation with examples.\n\nNote that large or cyclical data structures may be slow or difficult to serialize into an identifier, so exercise care with the data you specify.\n\n**setup _(Function)_**\n\nThis function is called whenever a session for the given `id` hasn't yet been cached, or if it's no longer valid (see the `validate` option). After `setup` and `validate` runs for the first time, Cypress will preserve all cookies, `sessionStorage`, and `localStorage`, so that subsequent calls to `cy.session()` with the same `id` will bypass setup and just restore and validate the cached session data.\n\nThe page is cleared before `setup` when `testIsolation` is enabled and is not cleared when `testIsolation` is disabled.\n\nCookies, local storage and session storage in all domains are always cleared before `setup` runs, regardless of the `testIsolation` configuration.\n\n**options _(Object)_**\n\n| Option | Default | Description |\n| --- | --- | --- |\n| `validate` | `undefined` | Validates the newly-created or restored session. Function to run immediately after the session is created and `setup` function runs or after a session is restored and the page is cleared. If it throws an exception, contains any failing Cypress command, returns a Promise which rejects or resolves to `false`, or the last Cypress command yielded `false`, the session is considered invalid.  \n  \n\\- If validation fails immediately after `setup`, the test will fail.  \n\\- If validation fails after restoring a session, `setup` will re-run. |\n| `cacheAcrossSpecs` | `false` | When enabled, the newly created session is considered \"global\" and can be restored in any spec during the test execution in the same Cypress run on the same machine. Use this option for a session that will be used multiple times, across many specs. |\n",
      "section": "api",
      "anchors": [
        "arguments"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 504
    },
    {
      "id": "api/commands/session#examples",
      "doc_id": "api/commands/session",
      "heading": "Examples",
      "heading_level": 2,
      "content_markdown": "## Examples\n\n### Updating an existing login custom command\n\nYou can add session caching to your login [custom command](/llm/markdown/api/cypress-api/custom-commands.md). Wrap the inside of the command with a call to `cy.session()`.\n\n**Before**\n\n```\nCypress.Commands.add('login', (username, password) => {  cy.visit('/login')  cy.get('[data-test=name]').type(username)  cy.get('[data-test=password]').type(password)  cy.get('form').contains('Log In').click()  cy.url().should('contain', '/login-successful')})\n```\n\n**After**\n\n```\nCypress.Commands.add('login', (username, password) => {  cy.session([username, password], () => {    cy.visit('/login')    cy.get('[data-test=name]').type(username)    cy.get('[data-test=password]').type(password)    cy.get('form').contains('Log In').click()    cy.url().should('contain', '/login-successful')  })})\n```\n\n**With session validation**\n\n```\nCypress.Commands.add('login', (username, password) => {  cy.session(    [username, password],    () => {      cy.visit('/login')      cy.get('[data-test=name]').type(username)      cy.get('[data-test=password]').type(password)      cy.get('form').contains('Log In').click()      cy.url().should('contain', '/login-successful')    },    {      validate() {        cy.request('/whoami').its('status').should('eq', 200)      },    }  )})\n```\n\n### Updating an existing login helper function\n\nYou can add session caching to a login helper function by wrapping the inside of the function with a call to `cy.session()`.\n\n**Before**\n\n```\nconst login = (name, password) => {  cy.visit('/login')  cy.get('[data-test=name]').type(name)  cy.get('[data-test=password]').type(password)  cy.get('#submit').click()  cy.url().should('contain', '/home')}\n```\n\n**After**\n\n```\nconst login = (name, password) => {  cy.session([name, password], () => {    cy.visit('/login')    cy.get('[data-test=name]').type(name)    cy.get('[data-test=password]').type(password)    cy.get('#submit').click()    cy.url().should('contain', '/home')  })}\n```\n\n**With session validation**\n\n```\nconst login = (name, password) => {  cy.session(    [name, password],    () => {      cy.visit('/login')      cy.get('[data-test=name]').type(name)      cy.get('[data-test=password]').type(password)      cy.get('#submit').click()      cy.url().should('contain', '/home')    },    {      validate() {        // Protected URLs should return a 40x http code if user is unauthorized,        // and by default this will cause cy.visit() to fail        cy.visit('/account-details')      },    }  )}\n```\n\n### Switching sessions inside tests\n\nBecause `cy.session()` clears the page and all session data before running `setup`, you can use it to easily switch between sessions without first needing to log the previous user out. This allows tests to more accurately represent real-world scenarios and helps keep test run times short.\n\n```\nconst login = (name) => {  cy.session(name, () => {    cy.request({      method: 'POST',      url: '/login',      body: { name, password: 's3cr3t' },    }).then(({ body }) => {      window.localStorage.setItem('authToken', body.token)    })  })}it('should transfer money between users', () => {  login('user')  cy.visit('/transfer')  cy.get('#amount').type('100.00')  cy.get('#send-money').click()  login('other-user')  cy.visit('/account_balance')  cy.get('#balance').should('eq', '100.00')})\n```\n\n### Validating the session\n\nThe `validate` function is used to ensure the session has been correctly established. This is especially helpful when a cached session is being restored, because if the session is not valid, `cy.session()` will recreate the session by re-running `setup`.\n\nThe following scenarios will mark the session as invalid:\n\n*   the `validate` function throws an exception\n*   the `validate` function returns a Promise that resolves to `false` or rejects\n*   the `validate` function contains failing Cypress command\n*   the last Cypress command in the `validate` function yielded `false`\n\nHere are a few `validate` examples:\n\n```\n// Attempt to visit a page that only a logged-in user can seefunction validate() {  cy.visit('/private')}// Make an API request that returns a 200 only when logged infunction validate() {  cy.request('/api/user').its('status').should('eq', 200)}// Run any Cypress command that fails if the user is not logged infunction validate() {  cy.visit('/account', { failOnStatusCode: false })  cy.url().should('match', /^/account/)}\n```\n\n### Modifying session data before caching\n\nIf you want to change which session data is cached, you can modify cookies, `localStorage`, `sessionStorage` as-necessary in `setup`.\n\n```\ncy.session('user', () => {  cy.visit('/login')  cy.get('name').type('user')  cy.get('password').type('p4ssw0rd123')  cy.get('#submit').click()  cy.url().should('contain', '/home')  // Remove session data we don't want to cache  cy.clearCookie('authId')  cy.window().then((win) => {    win.localStorage.removeItem('authToken')  })  // Add session data we do want to cache  cy.setCookie('session_id', '189jd09sufh33aaiidhf99d09')})\n```\n\n### Caching session data across specs\n\nIf you want to use the same session across multiple specs in the same Cypress run on the same machine, add `cacheAcrossSpecs=true` to the session options to leverage the session through the run.\n\n```\nconst login = (name = 'user1') => {  cy.session(    name,    () => {      cy.request({        method: 'POST',        url: '/login',        body: { name, password: 's3cr3t' },      }).then(({ body }) => {        window.localStorage.setItem('authToken', body.token)      })    },    {      validate() {        cy.visit('/user_profile')        cy.contains(`Hello ${name}`)      },      cacheAcrossSpecs: true,    }  )}// profile.cy.jsit('can view profile', () => {  login()})// add_blog.cy.jsit('can create a blog post', () => {  login()})\n```\n\n### Multiple login commands\n\nA more complex app may require multiple login commands, which may require multiple uses of `cy.session()`. However, because the `id` value is used as a unique identifier to save and restore sessions, it's very important that it's actually unique per session.\n\nIn the following example, if the resulting session data that `loginByForm` and `loginByApi` create is different _in any way_, it would be a mistake to specify `[name, password]` as the `id` for both, because there would be no way to distinguish between the sessions created by `loginByForm(\"user\", \"p4ssw0rd\")` and `loginByApi(\"user\", \"p4ssw0rd\")`. Instead, you can modify the `id` to differentiate its value between both login functions, so that each will always be cached uniquely.\n\n```\nconst loginByForm = (name, password) => {  cy.session(['loginByForm', name], () => {    cy.visit('/login')    cy.get('[data-test=name]').type(name)    cy.get('[data-test=password]').type(password)    cy.get('#submit').click()    cy.url().should('contain', '/home')  })}const loginByApi = (name, password) => {  cy.session(['loginByApi', name], () => {    cy.request({      method: 'POST',      url: '/api/login',      body: { name, password },    }).then(({ body }) => {      window.localStorage.setItem('authToken', body.token)    })  })}\n```\n\n### Where to call `cy.visit()`\n\nIntuitively it seems that you should call [`cy.visit()`](/llm/markdown/api/commands/visit.md) immediately after `cy.session()` in your login function or custom command, so it behaves (from the point of view of the subsequent test) exactly the same as a login function without `cy.session()`.\n\n```\nconst login = (name) => {  cy.session(name, () => {    cy.visit('/login')    cy.get('[data-test=name]').type(name)    cy.get('[data-test=password]').type('s3cr3t')    cy.get('#submit').click()    cy.url().should('contain', '/home')  })  cy.visit('/home')}beforeEach(() => {  login('user')})it('should test something on the /home page', () => {  // assertions})it('should test something else on the /home page', () => {  // assertions})\n```\n\nHowever, if you want to test something on a different page, you will need to call `cy.visit()` at the beginning of that test, which means you will be calling `cy.visit()` a **second** time in your test. Since `cy.visit()` waits for the visited page to become active before continuing, this could add up to an unacceptable waste of time.\n\n```\n// ...continued...it('should test something on the /other page', () => {  cy.visit('/other')  // assertions})\n```\n\nTests will obviously be faster if you call `cy.visit()` only when necessary. This can be easily realised by [organizing tests into suites](/llm/markdown/app/core-concepts/writing-and-organizing-tests.md#Test-Structure) and calling `cy.visit()` **after** logging in, inside a [`beforeEach`](/llm/markdown/app/core-concepts/writing-and-organizing-tests.md#Hooks) hook.\n\n```\nconst login = (name) => {  cy.session(name, () => {    cy.visit('/login')    cy.get('[data-test=name]').type(name)    cy.get('[data-test=password]').type('s3cr3t')    cy.get('#submit').click()    cy.url().should('contain', '/home')  })  // no visit here}describe('home page tests', () => {  beforeEach(() => {    login('user')    cy.visit('/home')  })  it('should test something on the /home page', () => {    // assertions  })  it('should test something else on the /home page', () => {    // assertions  })})describe('other page tests', () => {  beforeEach(() => {    login('user')    cy.visit('/other')  })  it('should test something on the /other page', () => {    // assertions  })})\n```\n\n### Updating a login function that returns a value\n\nIf your custom login command returns a value that you use to assert in a test, wrapping it with `cy.session()` will break that test. However, it's usually easy to solve this by refactoring the login code to assert directly inside `setup`.\n\n**Before**\n\n```\nCypress.Commands.add('loginByApi', (username, password) => {  return cy.request('POST', `/api/login`, {    username,    password,  })})it('should return the correct value', () => {  cy.loginByApi('user', 's3cr3t').then((response) => {    expect(response.status).to.eq(200)  })})\n```\n\n**After**\n\n```\nCypress.Commands.add('loginByApi', (username, password) => {  cy.session(username, () => {    cy.request('POST', `/api/login`, {      username,      password,    }).then((response) => {      expect(response.status).to.eq(200)    })  })})it('is a redundant test', () => {  /* which you can now delete! */})\n```\n\n### Cross-domain sessions\n\nIt's possible to switch domains while caching sessions, just be sure to explicitly visit the domain in your login command before calling `cy.session()`.\n\n```\nconst login = (name) => {  if (location.hostname !== 'cypress.io') {    cy.visit('https://example.cypress.io')  }  cy.session(name, () => {    cy.visit('/login')    // etc  }, {    validate() {      cy.request('/whoami', {        headers: { 'Authorization' : localStorage.token }        method: 'POST'      }).its('status').should('equal', 200)    }  })}it('t1', () => {  login('bob')  // do things on cypress.io})it('t2', () => {  cy.visit('http://www.cypress-dx.com')  // do things on anotherexample.com})it('t3', () => {  login('bob')  // do things on cypress.io})\n```\n",
      "section": "api",
      "anchors": [
        "examples"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 1723
    },
    {
      "id": "api/commands/session#updating-an-existing-login-custom-command",
      "doc_id": "api/commands/session",
      "heading": "Updating an existing login custom command",
      "heading_level": 3,
      "content_markdown": "### Updating an existing login custom command\n\nYou can add session caching to your login [custom command](/llm/markdown/api/cypress-api/custom-commands.md). Wrap the inside of the command with a call to `cy.session()`.\n\n**Before**\n\n```\nCypress.Commands.add('login', (username, password) => {  cy.visit('/login')  cy.get('[data-test=name]').type(username)  cy.get('[data-test=password]').type(password)  cy.get('form').contains('Log In').click()  cy.url().should('contain', '/login-successful')})\n```\n\n**After**\n\n```\nCypress.Commands.add('login', (username, password) => {  cy.session([username, password], () => {    cy.visit('/login')    cy.get('[data-test=name]').type(username)    cy.get('[data-test=password]').type(password)    cy.get('form').contains('Log In').click()    cy.url().should('contain', '/login-successful')  })})\n```\n\n**With session validation**\n\n```\nCypress.Commands.add('login', (username, password) => {  cy.session(    [username, password],    () => {      cy.visit('/login')      cy.get('[data-test=name]').type(username)      cy.get('[data-test=password]').type(password)      cy.get('form').contains('Log In').click()      cy.url().should('contain', '/login-successful')    },    {      validate() {        cy.request('/whoami').its('status').should('eq', 200)      },    }  )})\n```\n",
      "section": "api",
      "anchors": [
        "updating-an-existing-login-custom-command"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 128
    },
    {
      "id": "api/commands/session#updating-an-existing-login-helper-function",
      "doc_id": "api/commands/session",
      "heading": "Updating an existing login helper function",
      "heading_level": 3,
      "content_markdown": "### Updating an existing login helper function\n\nYou can add session caching to a login helper function by wrapping the inside of the function with a call to `cy.session()`.\n\n**Before**\n\n```\nconst login = (name, password) => {  cy.visit('/login')  cy.get('[data-test=name]').type(name)  cy.get('[data-test=password]').type(password)  cy.get('#submit').click()  cy.url().should('contain', '/home')}\n```\n\n**After**\n\n```\nconst login = (name, password) => {  cy.session([name, password], () => {    cy.visit('/login')    cy.get('[data-test=name]').type(name)    cy.get('[data-test=password]').type(password)    cy.get('#submit').click()    cy.url().should('contain', '/home')  })}\n```\n\n**With session validation**\n\n```\nconst login = (name, password) => {  cy.session(    [name, password],    () => {      cy.visit('/login')      cy.get('[data-test=name]').type(name)      cy.get('[data-test=password]').type(password)      cy.get('#submit').click()      cy.url().should('contain', '/home')    },    {      validate() {        // Protected URLs should return a 40x http code if user is unauthorized,        // and by default this will cause cy.visit() to fail        cy.visit('/account-details')      },    }  )}\n```\n",
      "section": "api",
      "anchors": [
        "updating-an-existing-login-helper-function"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 163
    },
    {
      "id": "api/commands/session#switching-sessions-inside-tests",
      "doc_id": "api/commands/session",
      "heading": "Switching sessions inside tests",
      "heading_level": 3,
      "content_markdown": "### Switching sessions inside tests\n\nBecause `cy.session()` clears the page and all session data before running `setup`, you can use it to easily switch between sessions without first needing to log the previous user out. This allows tests to more accurately represent real-world scenarios and helps keep test run times short.\n\n```\nconst login = (name) => {  cy.session(name, () => {    cy.request({      method: 'POST',      url: '/login',      body: { name, password: 's3cr3t' },    }).then(({ body }) => {      window.localStorage.setItem('authToken', body.token)    })  })}it('should transfer money between users', () => {  login('user')  cy.visit('/transfer')  cy.get('#amount').type('100.00')  cy.get('#send-money').click()  login('other-user')  cy.visit('/account_balance')  cy.get('#balance').should('eq', '100.00')})\n```\n",
      "section": "api",
      "anchors": [
        "switching-sessions-inside-tests"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 131
    },
    {
      "id": "api/commands/session#validating-the-session",
      "doc_id": "api/commands/session",
      "heading": "Validating the session",
      "heading_level": 3,
      "content_markdown": "### Validating the session\n\nThe `validate` function is used to ensure the session has been correctly established. This is especially helpful when a cached session is being restored, because if the session is not valid, `cy.session()` will recreate the session by re-running `setup`.\n\nThe following scenarios will mark the session as invalid:\n\n*   the `validate` function throws an exception\n*   the `validate` function returns a Promise that resolves to `false` or rejects\n*   the `validate` function contains failing Cypress command\n*   the last Cypress command in the `validate` function yielded `false`\n\nHere are a few `validate` examples:\n\n```\n// Attempt to visit a page that only a logged-in user can seefunction validate() {  cy.visit('/private')}// Make an API request that returns a 200 only when logged infunction validate() {  cy.request('/api/user').its('status').should('eq', 200)}// Run any Cypress command that fails if the user is not logged infunction validate() {  cy.visit('/account', { failOnStatusCode: false })  cy.url().should('match', /^/account/)}\n```\n",
      "section": "api",
      "anchors": [
        "validating-the-session"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 204
    },
    {
      "id": "api/commands/session#modifying-session-data-before-caching",
      "doc_id": "api/commands/session",
      "heading": "Modifying session data before caching",
      "heading_level": 3,
      "content_markdown": "### Modifying session data before caching\n\nIf you want to change which session data is cached, you can modify cookies, `localStorage`, `sessionStorage` as-necessary in `setup`.\n\n```\ncy.session('user', () => {  cy.visit('/login')  cy.get('name').type('user')  cy.get('password').type('p4ssw0rd123')  cy.get('#submit').click()  cy.url().should('contain', '/home')  // Remove session data we don't want to cache  cy.clearCookie('authId')  cy.window().then((win) => {    win.localStorage.removeItem('authToken')  })  // Add session data we do want to cache  cy.setCookie('session_id', '189jd09sufh33aaiidhf99d09')})\n```\n",
      "section": "api",
      "anchors": [
        "modifying-session-data-before-caching"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 84
    },
    {
      "id": "api/commands/session#caching-session-data-across-specs",
      "doc_id": "api/commands/session",
      "heading": "Caching session data across specs",
      "heading_level": 3,
      "content_markdown": "### Caching session data across specs\n\nIf you want to use the same session across multiple specs in the same Cypress run on the same machine, add `cacheAcrossSpecs=true` to the session options to leverage the session through the run.\n\n```\nconst login = (name = 'user1') => {  cy.session(    name,    () => {      cy.request({        method: 'POST',        url: '/login',        body: { name, password: 's3cr3t' },      }).then(({ body }) => {        window.localStorage.setItem('authToken', body.token)      })    },    {      validate() {        cy.visit('/user_profile')        cy.contains(`Hello ${name}`)      },      cacheAcrossSpecs: true,    }  )}// profile.cy.jsit('can view profile', () => {  login()})// add_blog.cy.jsit('can create a blog post', () => {  login()})\n```\n",
      "section": "api",
      "anchors": [
        "caching-session-data-across-specs"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 135
    },
    {
      "id": "api/commands/session#multiple-login-commands",
      "doc_id": "api/commands/session",
      "heading": "Multiple login commands",
      "heading_level": 3,
      "content_markdown": "### Multiple login commands\n\nA more complex app may require multiple login commands, which may require multiple uses of `cy.session()`. However, because the `id` value is used as a unique identifier to save and restore sessions, it's very important that it's actually unique per session.\n\nIn the following example, if the resulting session data that `loginByForm` and `loginByApi` create is different _in any way_, it would be a mistake to specify `[name, password]` as the `id` for both, because there would be no way to distinguish between the sessions created by `loginByForm(\"user\", \"p4ssw0rd\")` and `loginByApi(\"user\", \"p4ssw0rd\")`. Instead, you can modify the `id` to differentiate its value between both login functions, so that each will always be cached uniquely.\n\n```\nconst loginByForm = (name, password) => {  cy.session(['loginByForm', name], () => {    cy.visit('/login')    cy.get('[data-test=name]').type(name)    cy.get('[data-test=password]').type(password)    cy.get('#submit').click()    cy.url().should('contain', '/home')  })}const loginByApi = (name, password) => {  cy.session(['loginByApi', name], () => {    cy.request({      method: 'POST',      url: '/api/login',      body: { name, password },    }).then(({ body }) => {      window.localStorage.setItem('authToken', body.token)    })  })}\n```\n",
      "section": "api",
      "anchors": [
        "multiple-login-commands"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 225
    },
    {
      "id": "api/commands/session#where-to-call-cy-visit",
      "doc_id": "api/commands/session",
      "heading": "Where to call cy.visit()",
      "heading_level": 3,
      "content_markdown": "### Where to call `cy.visit()`\n\nIntuitively it seems that you should call [`cy.visit()`](/llm/markdown/api/commands/visit.md) immediately after `cy.session()` in your login function or custom command, so it behaves (from the point of view of the subsequent test) exactly the same as a login function without `cy.session()`.\n\n```\nconst login = (name) => {  cy.session(name, () => {    cy.visit('/login')    cy.get('[data-test=name]').type(name)    cy.get('[data-test=password]').type('s3cr3t')    cy.get('#submit').click()    cy.url().should('contain', '/home')  })  cy.visit('/home')}beforeEach(() => {  login('user')})it('should test something on the /home page', () => {  // assertions})it('should test something else on the /home page', () => {  // assertions})\n```\n\nHowever, if you want to test something on a different page, you will need to call `cy.visit()` at the beginning of that test, which means you will be calling `cy.visit()` a **second** time in your test. Since `cy.visit()` waits for the visited page to become active before continuing, this could add up to an unacceptable waste of time.\n\n```\n// ...continued...it('should test something on the /other page', () => {  cy.visit('/other')  // assertions})\n```\n\nTests will obviously be faster if you call `cy.visit()` only when necessary. This can be easily realised by [organizing tests into suites](/llm/markdown/app/core-concepts/writing-and-organizing-tests.md#Test-Structure) and calling `cy.visit()` **after** logging in, inside a [`beforeEach`](/llm/markdown/app/core-concepts/writing-and-organizing-tests.md#Hooks) hook.\n\n```\nconst login = (name) => {  cy.session(name, () => {    cy.visit('/login')    cy.get('[data-test=name]').type(name)    cy.get('[data-test=password]').type('s3cr3t')    cy.get('#submit').click()    cy.url().should('contain', '/home')  })  // no visit here}describe('home page tests', () => {  beforeEach(() => {    login('user')    cy.visit('/home')  })  it('should test something on the /home page', () => {    // assertions  })  it('should test something else on the /home page', () => {    // assertions  })})describe('other page tests', () => {  beforeEach(() => {    login('user')    cy.visit('/other')  })  it('should test something on the /other page', () => {    // assertions  })})\n```\n",
      "section": "api",
      "anchors": [
        "where-to-call-cy-visit"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 375
    },
    {
      "id": "api/commands/session#updating-a-login-function-that-returns-a-value",
      "doc_id": "api/commands/session",
      "heading": "Updating a login function that returns a value",
      "heading_level": 3,
      "content_markdown": "### Updating a login function that returns a value\n\nIf your custom login command returns a value that you use to assert in a test, wrapping it with `cy.session()` will break that test. However, it's usually easy to solve this by refactoring the login code to assert directly inside `setup`.\n\n**Before**\n\n```\nCypress.Commands.add('loginByApi', (username, password) => {  return cy.request('POST', `/api/login`, {    username,    password,  })})it('should return the correct value', () => {  cy.loginByApi('user', 's3cr3t').then((response) => {    expect(response.status).to.eq(200)  })})\n```\n\n**After**\n\n```\nCypress.Commands.add('loginByApi', (username, password) => {  cy.session(username, () => {    cy.request('POST', `/api/login`, {      username,      password,    }).then((response) => {      expect(response.status).to.eq(200)    })  })})it('is a redundant test', () => {  /* which you can now delete! */})\n```\n",
      "section": "api",
      "anchors": [
        "updating-a-login-function-that-returns-a-value"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 152
    },
    {
      "id": "api/commands/session#cross-domain-sessions",
      "doc_id": "api/commands/session",
      "heading": "Cross-domain sessions",
      "heading_level": 3,
      "content_markdown": "### Cross-domain sessions\n\nIt's possible to switch domains while caching sessions, just be sure to explicitly visit the domain in your login command before calling `cy.session()`.\n\n```\nconst login = (name) => {  if (location.hostname !== 'cypress.io') {    cy.visit('https://example.cypress.io')  }  cy.session(name, () => {    cy.visit('/login')    // etc  }, {    validate() {      cy.request('/whoami', {        headers: { 'Authorization' : localStorage.token }        method: 'POST'      }).its('status').should('equal', 200)    }  })}it('t1', () => {  login('bob')  // do things on cypress.io})it('t2', () => {  cy.visit('http://www.cypress-dx.com')  // do things on anotherexample.com})it('t3', () => {  login('bob')  // do things on cypress.io})\n```\n",
      "section": "api",
      "anchors": [
        "cross-domain-sessions"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 124
    },
    {
      "id": "api/commands/session#notes",
      "doc_id": "api/commands/session",
      "heading": "Notes",
      "heading_level": 2,
      "content_markdown": "## Notes\n\n### When the page and session data are cleared\n\n### Test Isolation Enabled\n\nThe page is cleared and cookies, local storage and session storage (session data) in all domains are cleared automatically when `cy.session()` runs and test isolation is enabled with `testIsolation=true`, This guarantees consistent behavior whether a session is being created or restored and allows you to switch sessions without first having to explicitly log out.\n\n| When cleared? | Page cleared (test) | Session data cleared |\n| --- | --- | --- |\n| Before `setup` |  |  |\n| Before `cy.session()` ends |  |  |\n\nNote: [`cy.visit()`](/llm/markdown/api/commands/visit.md) must be explicitly called afterwards to ensure the page to test is loaded.\n\n### Test Isolation Disabled\n\nWhen test isolation is disabled with `testIsolation=false`, the page will not clear, however, the session data will clear when `cy.session()` runs.\n\n| When cleared | Page cleared (test) | Session data cleared |\n| --- | --- | --- |\n| Before `setup` |  |  |\n| Before `cy.session()` ends |  |  |\n\n[`cy.visit()`](/llm/markdown/api/commands/visit.md) does not need to be called afterwards to ensure the page to test is loaded.\n\nNOTE: Disabling test isolation may improve performance of end-to-end tests, however, previous tests could impact the browser state of the next test and cause inconsistency when using .only(). Be mindful to write isolated tests when test isolation is disabled.\n\nWhen test isolation is disabled, it is encouraged to setup your session in a before hook or in the first test to ensure a clean setup.\n\n### Session caching\n\nOnce created, a session for a given `id` is cached for the duration of the spec file. You can't modify a stored session after it has been cached, but you can always create a new session with a different `id`.\n\nIn order to reduce development time, when running Cypress in \"open\" mode, sessions will be cached _for spec file reruns_.\n\nTo persist a session across multiple specs, use the option `cacheAcrossSpecs=true`.\n\n### Explicitly clearing sessions\n\nWhen running Cypress in \"open\" mode, you can explicitly clear all spec and global sessions and re-run the spec file by clicking the \"Clear All Sessions\" button in the [Instrument Panel](#The-Instrument-Panel).\n\nFor debugging purposes, all spec and global sessions can be cleared with the [`Cypress.session.clearAllSavedSessions()`](/llm/markdown/api/cypress-api/session.md) method.\n\n### Where to call `cy.session()`\n\nWhile it is possible to call `cy.session()` explicitly inside a test or `beforeEach`, it is considered a best practice to call `cy.session()` inside a login [custom command](/llm/markdown/api/cypress-api/custom-commands.md) or reusable wrapper function. See the [Updating an existing login custom command](#Updating-an-existing-login-custom-command) and [Updating an existing login helper function](#Updating-an-existing-login-helper-function) examples for more details.\n\n### Choosing the correct id to cache a session\n\nIn order for sessions to be cached uniquely, the [`id` argument](#Arguments) must be unique for each new session created. The `id` provided to `cy.session()` will display in the reporter, thus we do not recommend using sensitive data like passwords or tokens as unique identifiers.\n\n```\n// If your session setup code uses a string variable, pass in the// string as the idconst login = (name) => {  cy.session(name, () => {    loginWith(name)  })}// If your session setup code uses a single object, pass in the// object as the id and it will be serialized into an identifierconst login = (params = {}) => {  cy.session(params, () => {    loginWith(params)  })}// If your session setup code uses multiple variables, pass in an// array of those variables and it will be serialized into an// identifierconst login = (name, email, params = {}) => {  cy.session([name, email, params], () => {    loginWith(name, email, params)  })}// If your session setup code uses external constants, they don't// need to be included in the id, since they will never changeconst API_KEY = 'I_AM_AN_API_KEY'const login = (name, email) => {  cy.session([name, email], () => {    loginWith(name, email, API_KEY)  })}\n```\n\n**Incorrect Usage**\n\nIf you have custom `login` code that uses multiple parameters (in this example, a name, a token, and a password), in order to be able to log in many different users, but the `id` only included one of them (in this example, `name`):\n\n```\nconst login = (name, token, password) => {  cy.session(name, () => {    cy.visit('/login')    cy.get('[data-test=name]').type(name)    cy.get('[data-test=token]').type(token)    cy.get('[data-test=password]').type(password)    cy.get('#submit').click()  })}\n```\n\nIf you ran this, `user1` would be logged in with `token1` and `p4ssw0rd`, and a session would be created and cached using `\"user1\"` as the `id`.\n\n```\nlogin('user1', 'token1', 'p4ssw0rd')\n```\n\nNow let's say you wanted to try to log in the same user, but with a different token and/or password, and expect a different session to be created and cached. You run this, but because `cy.session()` is only being passed `name` as its `id`, it won't create a new session, but will instead load the saved session for `\"user1\"`.\n\n```\nlogin('user1', 'different-token', 'p4ssw0rd')\n```\n\nIn summary, you need to ensure that the `id` is unique. Create it from all the parameters used inside the `setup` function that may change, otherwise `id` values may collide and create unexpected results.\n\n**Correct Usage**\n\nIn this example, setting the `id` to `[name, uniqueKey]` guarantees that calling `login()` with different `name`, `token` and `password` values will create and cache unique sessions.\n\n```\nconst login = (name, token, password, uniqueKey) => {  cy.session([name, uniqueKey], () => {    cy.visit('/login')    cy.get('[data-test=name]').type(name)    cy.get('[data-test=token]').type(token)    cy.get('[data-test=password]').type(password)    cy.get('#submit').click()  })}\n```\n\nThe [`uuid`](https://www.npmjs.com/package/uuid) npm package can be used to generate random unique ids if an arbitrary name-space does not meet your needs.\n\n### Common Questions\n\n#### Why are all my Cypress commands failing after calling `cy.session()`?\n\nWhen [`testIsolation`](/llm/markdown/app/core-concepts/writing-and-organizing-tests.md#Test-Isolation) is enabled, ensure that you're calling [`cy.visit()`](/llm/markdown/api/commands/visit.md) after calling `cy.session()`, otherwise your tests will be running on a blank page.\n\n#### Why am I seeing `401` errors after calling `cy.session()`?\n\nIt's possible that your session is not valid or was not fully established before the session was saved and the command ended. Be sure to specify a `validate` function so that `cy.session()` can validate and recreate the session if necessary.\n",
      "section": "api",
      "anchors": [
        "notes"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 1315
    },
    {
      "id": "api/commands/session#test-isolation-enabled",
      "doc_id": "api/commands/session",
      "heading": "Test Isolation Enabled",
      "heading_level": 3,
      "content_markdown": "### Test Isolation Enabled\n\nThe page is cleared and cookies, local storage and session storage (session data) in all domains are cleared automatically when `cy.session()` runs and test isolation is enabled with `testIsolation=true`, This guarantees consistent behavior whether a session is being created or restored and allows you to switch sessions without first having to explicitly log out.\n\n| When cleared? | Page cleared (test) | Session data cleared |\n| --- | --- | --- |\n| Before `setup` |  |  |\n| Before `cy.session()` ends |  |  |\n\nNote: [`cy.visit()`](/llm/markdown/api/commands/visit.md) must be explicitly called afterwards to ensure the page to test is loaded.\n",
      "section": "api",
      "anchors": [
        "test-isolation-enabled"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 140
    },
    {
      "id": "api/commands/session#test-isolation-disabled",
      "doc_id": "api/commands/session",
      "heading": "Test Isolation Disabled",
      "heading_level": 3,
      "content_markdown": "### Test Isolation Disabled\n\nWhen test isolation is disabled with `testIsolation=false`, the page will not clear, however, the session data will clear when `cy.session()` runs.\n\n| When cleared | Page cleared (test) | Session data cleared |\n| --- | --- | --- |\n| Before `setup` |  |  |\n| Before `cy.session()` ends |  |  |\n\n[`cy.visit()`](/llm/markdown/api/commands/visit.md) does not need to be called afterwards to ensure the page to test is loaded.\n\nNOTE: Disabling test isolation may improve performance of end-to-end tests, however, previous tests could impact the browser state of the next test and cause inconsistency when using .only(). Be mindful to write isolated tests when test isolation is disabled.\n\nWhen test isolation is disabled, it is encouraged to setup your session in a before hook or in the first test to ensure a clean setup.\n",
      "section": "api",
      "anchors": [
        "test-isolation-disabled"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 184
    },
    {
      "id": "api/commands/session#session-caching",
      "doc_id": "api/commands/session",
      "heading": "Session caching",
      "heading_level": 3,
      "content_markdown": "### Session caching\n\nOnce created, a session for a given `id` is cached for the duration of the spec file. You can't modify a stored session after it has been cached, but you can always create a new session with a different `id`.\n\nIn order to reduce development time, when running Cypress in \"open\" mode, sessions will be cached _for spec file reruns_.\n\nTo persist a session across multiple specs, use the option `cacheAcrossSpecs=true`.\n",
      "section": "api",
      "anchors": [
        "session-caching"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 99
    },
    {
      "id": "api/commands/session#explicitly-clearing-sessions",
      "doc_id": "api/commands/session",
      "heading": "Explicitly clearing sessions",
      "heading_level": 3,
      "content_markdown": "### Explicitly clearing sessions\n\nWhen running Cypress in \"open\" mode, you can explicitly clear all spec and global sessions and re-run the spec file by clicking the \"Clear All Sessions\" button in the [Instrument Panel](#The-Instrument-Panel).\n\nFor debugging purposes, all spec and global sessions can be cleared with the [`Cypress.session.clearAllSavedSessions()`](/llm/markdown/api/cypress-api/session.md) method.\n",
      "section": "api",
      "anchors": [
        "explicitly-clearing-sessions"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 67
    },
    {
      "id": "api/commands/session#where-to-call-cy-session",
      "doc_id": "api/commands/session",
      "heading": "Where to call cy.session()",
      "heading_level": 3,
      "content_markdown": "### Where to call `cy.session()`\n\nWhile it is possible to call `cy.session()` explicitly inside a test or `beforeEach`, it is considered a best practice to call `cy.session()` inside a login [custom command](/llm/markdown/api/cypress-api/custom-commands.md) or reusable wrapper function. See the [Updating an existing login custom command](#Updating-an-existing-login-custom-command) and [Updating an existing login helper function](#Updating-an-existing-login-helper-function) examples for more details.\n",
      "section": "api",
      "anchors": [
        "where-to-call-cy-session"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 73
    },
    {
      "id": "api/commands/session#choosing-the-correct-id-to-cache-a-session",
      "doc_id": "api/commands/session",
      "heading": "Choosing the correct id to cache a session",
      "heading_level": 3,
      "content_markdown": "### Choosing the correct id to cache a session\n\nIn order for sessions to be cached uniquely, the [`id` argument](#Arguments) must be unique for each new session created. The `id` provided to `cy.session()` will display in the reporter, thus we do not recommend using sensitive data like passwords or tokens as unique identifiers.\n\n```\n// If your session setup code uses a string variable, pass in the// string as the idconst login = (name) => {  cy.session(name, () => {    loginWith(name)  })}// If your session setup code uses a single object, pass in the// object as the id and it will be serialized into an identifierconst login = (params = {}) => {  cy.session(params, () => {    loginWith(params)  })}// If your session setup code uses multiple variables, pass in an// array of those variables and it will be serialized into an// identifierconst login = (name, email, params = {}) => {  cy.session([name, email, params], () => {    loginWith(name, email, params)  })}// If your session setup code uses external constants, they don't// need to be included in the id, since they will never changeconst API_KEY = 'I_AM_AN_API_KEY'const login = (name, email) => {  cy.session([name, email], () => {    loginWith(name, email, API_KEY)  })}\n```\n\n**Incorrect Usage**\n\nIf you have custom `login` code that uses multiple parameters (in this example, a name, a token, and a password), in order to be able to log in many different users, but the `id` only included one of them (in this example, `name`):\n\n```\nconst login = (name, token, password) => {  cy.session(name, () => {    cy.visit('/login')    cy.get('[data-test=name]').type(name)    cy.get('[data-test=token]').type(token)    cy.get('[data-test=password]').type(password)    cy.get('#submit').click()  })}\n```\n\nIf you ran this, `user1` would be logged in with `token1` and `p4ssw0rd`, and a session would be created and cached using `\"user1\"` as the `id`.\n\n```\nlogin('user1', 'token1', 'p4ssw0rd')\n```\n\nNow let's say you wanted to try to log in the same user, but with a different token and/or password, and expect a different session to be created and cached. You run this, but because `cy.session()` is only being passed `name` as its `id`, it won't create a new session, but will instead load the saved session for `\"user1\"`.\n\n```\nlogin('user1', 'different-token', 'p4ssw0rd')\n```\n\nIn summary, you need to ensure that the `id` is unique. Create it from all the parameters used inside the `setup` function that may change, otherwise `id` values may collide and create unexpected results.\n\n**Correct Usage**\n\nIn this example, setting the `id` to `[name, uniqueKey]` guarantees that calling `login()` with different `name`, `token` and `password` values will create and cache unique sessions.\n\n```\nconst login = (name, token, password, uniqueKey) => {  cy.session([name, uniqueKey], () => {    cy.visit('/login')    cy.get('[data-test=name]').type(name)    cy.get('[data-test=token]').type(token)    cy.get('[data-test=password]').type(password)    cy.get('#submit').click()  })}\n```\n\nThe [`uuid`](https://www.npmjs.com/package/uuid) npm package can be used to generate random unique ids if an arbitrary name-space does not meet your needs.\n",
      "section": "api",
      "anchors": [
        "choosing-the-correct-id-to-cache-a-session"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 623
    },
    {
      "id": "api/commands/session#common-questions",
      "doc_id": "api/commands/session",
      "heading": "Common Questions",
      "heading_level": 3,
      "content_markdown": "### Common Questions\n\n#### Why are all my Cypress commands failing after calling `cy.session()`?\n\nWhen [`testIsolation`](/llm/markdown/app/core-concepts/writing-and-organizing-tests.md#Test-Isolation) is enabled, ensure that you're calling [`cy.visit()`](/llm/markdown/api/commands/visit.md) after calling `cy.session()`, otherwise your tests will be running on a blank page.\n\n#### Why am I seeing `401` errors after calling `cy.session()`?\n\nIt's possible that your session is not valid or was not fully established before the session was saved and the command ended. Be sure to specify a `validate` function so that `cy.session()` can validate and recreate the session if necessary.\n",
      "section": "api",
      "anchors": [
        "common-questions"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 115
    },
    {
      "id": "api/commands/session#why-are-all-my-cypress-commands-failing-after-calling-cy-session",
      "doc_id": "api/commands/session",
      "heading": "Why are all my Cypress commands failing after calling cy.session()?",
      "heading_level": 4,
      "content_markdown": "#### Why are all my Cypress commands failing after calling `cy.session()`?\n\nWhen [`testIsolation`](/llm/markdown/app/core-concepts/writing-and-organizing-tests.md#Test-Isolation) is enabled, ensure that you're calling [`cy.visit()`](/llm/markdown/api/commands/visit.md) after calling `cy.session()`, otherwise your tests will be running on a blank page.\n",
      "section": "api",
      "anchors": [
        "why-are-all-my-cypress-commands-failing-after-calling-cy-session"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 44
    },
    {
      "id": "api/commands/session#why-am-i-seeing-401-errors-after-calling-cy-session",
      "doc_id": "api/commands/session",
      "heading": "Why am I seeing 401 errors after calling cy.session()?",
      "heading_level": 4,
      "content_markdown": "#### Why am I seeing `401` errors after calling `cy.session()`?\n\nIt's possible that your session is not valid or was not fully established before the session was saved and the command ended. Be sure to specify a `validate` function so that `cy.session()` can validate and recreate the session if necessary.\n",
      "section": "api",
      "anchors": [
        "why-am-i-seeing-401-errors-after-calling-cy-session"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 67
    },
    {
      "id": "api/commands/session#command-log",
      "doc_id": "api/commands/session",
      "heading": "Command Log",
      "heading_level": 2,
      "content_markdown": "## Command Log\n\n### The Instrument Panel\n\nWhenever a session is created or restored inside a test, an extra instrument panel is displayed at the top of the test to give more information about the state of your sessions.\n\nClicking any session `id` in the panel will print that session's details to the console, and clicking the \"Clear All Sessions\" button will clear all saved spec and global sessions and re-run the spec file (see [Session caching](#Session-caching) for more details).\n\nWhenever `cy.session()` is called, the command log will show one of the following lines, which includes the status of the session call along with the session `id` value:\n\n*   No saved session was found, so a new session was created and saved:\n    \n*   A saved session was found, and used:\n    \n*   A saved session was found, but the `validate` function failed, so the session was recreated and saved:\n    \n\nNote that in cases where the `validate` function fails immediately after `setup` creates the session, the test will fail with an error.\n\nExpanding the session group in the command log will show all of the commands that were run when creating and/or validating the session.\n\nIn this image, a saved session is restored, but when `/personal` is visited in the `validate` function, the app redirects to `/signin`, which invalidates the session. A new session is created by visiting `/signin` where the user is logged in, after which, validation succeeds, and the session is available for the remainder of the test.\n\nClicking a session `id` in the Instrument Panel or clicking the first line under an expanded session group in the command log will print that session's details to the console. This information contains the `id` along with any cached session data, including cookies, `localStorage` and `sessionStorage`.\n",
      "section": "api",
      "anchors": [
        "command-log"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 392
    },
    {
      "id": "api/commands/session#the-instrument-panel",
      "doc_id": "api/commands/session",
      "heading": "The Instrument Panel",
      "heading_level": 3,
      "content_markdown": "### The Instrument Panel\n\nWhenever a session is created or restored inside a test, an extra instrument panel is displayed at the top of the test to give more information about the state of your sessions.\n\nClicking any session `id` in the panel will print that session's details to the console, and clicking the \"Clear All Sessions\" button will clear all saved spec and global sessions and re-run the spec file (see [Session caching](#Session-caching) for more details).\n\nWhenever `cy.session()` is called, the command log will show one of the following lines, which includes the status of the session call along with the session `id` value:\n\n*   No saved session was found, so a new session was created and saved:\n    \n*   A saved session was found, and used:\n    \n*   A saved session was found, but the `validate` function failed, so the session was recreated and saved:\n    \n\nNote that in cases where the `validate` function fails immediately after `setup` creates the session, the test will fail with an error.\n\nExpanding the session group in the command log will show all of the commands that were run when creating and/or validating the session.\n\nIn this image, a saved session is restored, but when `/personal` is visited in the `validate` function, the app redirects to `/signin`, which invalidates the session. A new session is created by visiting `/signin` where the user is logged in, after which, validation succeeds, and the session is available for the remainder of the test.\n\nClicking a session `id` in the Instrument Panel or clicking the first line under an expanded session group in the command log will print that session's details to the console. This information contains the `id` along with any cached session data, including cookies, `localStorage` and `sessionStorage`.\n",
      "section": "api",
      "anchors": [
        "the-instrument-panel"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 388
    },
    {
      "id": "api/commands/session#history",
      "doc_id": "api/commands/session",
      "heading": "History",
      "heading_level": 2,
      "content_markdown": "## History\n\n| Version | Changes |\n| --- | --- |\n| [12.0.0](/llm/markdown/app/references/changelog.md#12-0-0) | Removed `experimentalSessionAndOrigin` and made the command available by default. |\n| [11.0.0](/llm/markdown/app/references/changelog.md#11-0-0) | The `setup` option is now required. |\n| [10.9.0](/llm/markdown/app/references/changelog.md#10-9-0) | Added `cacheAcrossSpecs` property. |\n| [9.6.0](/llm/markdown/app/references/changelog.md#9-6-0) | Added support for `experimentalSessionAndOrigin` and removed `experimentalSessionSupport`. |\n| [8.2.0](/llm/markdown/app/references/changelog.md#8-2-0) | `cy.session()` command added and can be used when `experimentalSessionSupport` is enabled. |\n",
      "section": "api",
      "anchors": [
        "history"
      ],
      "path": "/llm/json/chunked/api/commands/session.json",
      "token_estimate": 91
    }
  ]
}