Jonas
Jonas

Reputation: 396

Cypress: preserve cookies in version 10+

We used to login into our application using the cy.request() method and here the JSESSIONID cookie is set.

login(): void {
    cy.clearCookie('JSESSIONID');
    cy.request({
      method: 'POST',
      url: `${apiUrl()}/sessions`,
      body: {
        userName: 'xxx',
        password: 'yyy',
      },
    });
}

I had the JSESSIONID cookie preserved once with:

Cypress.Cookies.defaults({ preserve: 'JSESSIONID',});

in the file support/index.js

Now we want to migrate to Cypress 12. But there the "Cypress.Cookies.defaults" has been deprecated. It said, you have to use cy.session, instead.

After the migration process the above code is located in e2e.js. But how would you there preserve the cookie? I tried several ways but with now luck so far.

e.g.: in cypress documentation is this code snippet:

// Caching session when logging in via API
cy.session(username, () => {
  cy.request({
    method: 'POST',
    url: '/login',
    body: { username, password },
 }).then(({ body }) => {
    window.localStorage.setItem('authToken', body.token)
  })
})

This does not work as body.token does not exist (at least in version 12.3.0)

Upvotes: 0

Views: 782

Answers (2)

Paolo
Paolo

Reputation: 5441

cy.session() would be called in a beforeEach() if you want to preserve data across multiple tests.

General approach:

beforeEach(() => {
  cy.session('session name', callback_function)
})

These are the steps:

  • On the every test cy.session() checks it's cache for key 'session name'

  • On first test, nothing is found so callback_function is called

  • After callback_function finishes, all the session data is stored under the key 'session name'

  • On second test, the cache key 'session name' is found, so cy.session() restores that data to the browser. It doesn't call the callback a second time.


So in your case you can change the POM login method to this.

Note the key should be login instead of username, so data is preserved using the same key.

login(): void {
  cy.session('login', () => {
    cy.request({
      method: 'POST',
      url: `${apiUrl()}/sessions`,
      body: {
        userName: 'xxx',
        password: 'yyy',
      },
    });
  })
}

In the test code you can wrap the login in a beforeEach()

const loginPage = new LoginPage()

beforeEach(() => {
  loginPage.login('Jon')
})

it('test 1 logged in', () => {
  ...
})

it('test 2 logged in', () => {
  ...
})

Or you can just call .login() where the test needs to be logged in.

const loginPage = new LoginPage()

it('test 1 logged in', () => {
  loginPage.login('Jon')
  ...
})

it('test 2 logged in', () => {
  loginPage.login('Jack')
  ...
})


it('test 3 not logged in', () => {
  // don't call login here
  ...
})

Upvotes: 4

agoff
agoff

Reputation: 7125

From the session() documentation

[Use cy.session() to] Cache and restore cookies, localStorage, and sessionStorage (i.e. session data) in order to recreate a consistent browser context between tests.

So, cy.session() should be caching your cookies that have been set in previous tests that use the same cy.session() identifier. Your login() function could look something like this:

login(userName: string = 'xxx'): void {
  cy.session(userName) {
      cy.request({
      method: 'POST',
      url: `${apiUrl()}/sessions`,
      body: {
        userName,
        password: 'yyy',
      },
    });
  }
}

As for the Cypress documentation not working, it would be because your request to /login does not return a response with a body object that contains the field token.

Upvotes: 0

Related Questions