1

I am planning to update the Cypress version of an existing project from 6.9.1 to 12.6.0.

Currently we are navigating to a web page and logging in with ntlm-auth in a before() hook. After that the web page remains opened and can be used in all tests which are coming next.

In the latest Cypress version it seems that the page is being cleared and closed after each test case, which is the desired behavior to have better test cases as I understand.

But is there a way in the latest Cypress version to navigate to a web page in a before hook or in the first test, leave the page opened, then in the second test case to interact with it and navigate to another sections of the same page, leave the page opened, etc.?

The existing code structure looks like that:

before(() => {

  cy.ntlm(
    ['<url>'],
    <username>,
    <password>
  );

  cy.visit(<url>);

});

it('Test 1', () => {
  cy.contains('something').click();
});

it('Test 2', () => {
  cy.get('#something').type('{enter}');
});

I have tried to save the session with cy.session() in the before hook and my idea was to restore the session/page in the next tests, but I am not sure if this would be the right approach.

Briana
  • 204
  • 7
Petar
  • 13
  • 5
  • Another way is use BeforeEach() instead of Before() hook. – jjhelguero Feb 24 '23 at 15:23
  • Yes, but in my case I am opening the home page in the before() hook and in the next tests I am navigating to another sections of the page. My tests are 'chained' by each other (not the best approach... I know). When I used beforeEach() I was navigating to the home page before every test and I was not on the right place for the next tests. Of course, in every test I can then navigate to the url I need and not rely on the last opened page. But I don't want to change the existing code base that much, because it would be a lot of effort. – Petar Feb 24 '23 at 16:49
  • If the steps are not much between each test, then could you compile it all into one bigger test? – jjhelguero Feb 25 '23 at 01:54
  • Yes, combining the steps into bigger one is working as well. – Petar Feb 25 '23 at 05:50

2 Answers2

3

You should not turn off test isolation.

Reading through your description, the better approach is to use the cy.session() pattern.

beforeEach(() => {
  cy.session('login', () => {
    cy.ntlm(
      ['<url>'],
      <username>,
      <password>
    );
  })
});

it('Test 1', () => {

  cy.visit('/home-page')

  // test this url
});

it('Test 2', () => {

  cy.visit('/about-page')
  // or 
  cy.visit('/home-page')
  cy.get('menu .about').click()
  
  // test this url
});

What is happening with this pattern

  • beforeEach() is called for every test, making a call to cy.session()

  • cy.session() caches data generated within it's callback, in this case it's login. First test actually does the login. Second test restores the data from previous call - effectively before() logic (i.e login only happens once).

  • cy.visit() is done in each test so that you are at the right page for that test

  • tests remain isolated, you get flaky bugs that are hard to track down.


If you are finding cy.session() difficult to cache everything you need to cache, try cypress-data-session.

Presentation: Flexible Data Setup And Caching For E2E Tests
Repository: bahmutov/cypress-data-session

Example of cypress-data-session

Here is an example of preserving the id from URL across tests (mentioned in comments).

import 'cypress-data-session'

context('data session passing data from one test to another', () => {

  it('test 1 - saves some data to session store', () => {

    // visit a page with an id in the URL
    // note - this is a fake URL, so I'm suppressing the 404 error
    cy.visit('https://example.com/123', {failOnStatusCode:false}) 

    cy.url().then(url => {
      const slug = url.split('/').pop()  // last part of URL

      // save the piece of data I want preserved
      cy.dataSession('slug', () => slug)
    })
  });

  it('test 2 - reads data from context (using function callback)', function() {
    // here we use the variable slug set on the "this" context
    // note - the "function" keyword above is required
    expect(this.slug).to.eq('123')                         // passes
  })

  it('test 3 - reads data from session using getDataSession()', () => {
    // here we use the explict getter for slug
    // which does not require the "function" keyword
    const slug = Cypress.getDataSession('slug')
    expect(slug).to.eq('123')                              // passes
  })
})
Fody
  • 23,754
  • 3
  • 20
  • 37
  • 1
    Thank you. Yes, I have tried first this approach and can confirm that it is working. Just in my case, when I navigate through the pages and open specific object, the number IDs of those objects are being set in the URL. I have to take the IDs from the URL, store them in a variables and after that in the next test I can navigate to the desired page, something like cy.visit('/1234/about-page/5678'). I am going to use this approach in the future, but at the moment I am not able to spend much effort to change all of the spec files, and I have set testIsolation: false in the cypress.config.js – Petar Feb 24 '23 at 23:10
1

There is a Cypress configuration option to disable test isolation. This can be easily set in your cypress.config.js, in your e2e object.

const { defineConfig } = require('cypress')

module.exports = defineConfig({
  e2e: {
    // e2e options here
    testIsolation: false,
    // more e2e options here
  },
})

By default, testIsolation is set to true, so that should explain the behavior you are currently seeing. Additionally, this Cypress page describes what happens when testIsolation is set to false.

When test isolation is disabled, Cypress will not alter the browser context before the test starts. The page does not clear between tests and cookies, local storage and session storage will be available across tests in that suite. Additionally, the cy.session() command will only clear the current browser context when establishing the browser session - the current page is not cleared.

agoff
  • 5,818
  • 1
  • 7
  • 20
  • 1
    Thank you a lot, @agoff, the configuration option to disable test isolation was exactly what I needed. Now I can open a web page within the hook and work further with it in the next tests. – Petar Feb 24 '23 at 15:20