0

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)

Jonas
  • 166
  • 1
  • 13
  • We also tried this: window.localStorage.setItem('JSESSIONID', cookie?.value); however the cookie is not preserved when it goes to the next test [it()] – Jonas Jan 11 '23 at 14:43

2 Answers2

2

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
  ...
})
Paolo
  • 3,530
  • 7
  • 21
  • Thanks for the input. This is kind of surprising! Why does the session have to be restored for every test, every single time within the same spec file. There is even a flag call cacheAcrossSpecs= true, but even then you need to restore it every time. What does deactivate the session after it()? – Jonas Jan 12 '23 at 16:43
  • I suppose it's because of the [test isolation](https://docs.cypress.io/guides/core-concepts/test-isolation) principle? There is a flag for turning off test isolation, you could try playing with that, but I think it won't do what you want. There where many issues raised where running a multiple specs together were causing hard-to-debug problems, so the default Cypress went for is to isolate as much as possible. – Paolo Jan 12 '23 at 18:45
0

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.

agoff
  • 5,818
  • 1
  • 7
  • 20
  • Maybe I have to add that the login() is in before(), and below there are several tests. The first test is working, the second not with not showing the session cookie. No matter if I preserve with window.localStorage.setItem() or not. – Jonas Jan 11 '23 at 15:33