2

A lot of this is wrapped in commands, but I've left that part out to make the problem more feasible.

Consider these two tests:

# Test1: Test login for user
 - Step1: Logs in manually (go to login-URL, fill out credentials and click 'Log in').
 - Step2: Save auth-cookies as fixtures.

# Test2: Test something is dashboard for user.
 - Step1: Set auth-cookies (generated in Test1)
 - Step2: Visits https:://example.org/dashboard and ensures the user can see the dashboard.

If they run as written as listed above, then everything is fine.

But if Test2 runs before Test1, then Test2 will fail, since Test1 hasn't to generated the cookies yet.

So Test1 is kind of a prerequisite for Test2.

But Test1 doesn't need to run every time Test2 runs - only if the auth-cookies aren't generated.

I wish I could define my Test2 to be like this instead:

Test2: Test something is dashboard for user.
  - Step1: Run ensureAuthCookiesExists-command
  - Step2: If the AuthCookies.json-fixture doesn't exist, then run Test1
  - Step3: Sets auth-cookies (generated in Test1)
  - Step4: Visits https:://example.org/dashboard and ensures the user can see the dashboard.

Solution attempt 1: Control by order

For a long time I've done this using this answer: How to control order of tests. And then having my tests defines like this:

{
  "baseUrl": "http://localhost:5000",
  "testFiles": [
    "preparations/*.js",
    "feature-1/check-header.spec.js",
    "feature-2/check-buttons.spec.js",
    "feature-3/check-images.spec.js",
    "feature-4/check-404-page.spec.js",
    //...
  ]
}

But that is annoying, since it means that I keep having to add to add new features to that list, which get's annoying.

And this only solves the problem if I want to run all the tests. If I want to run preparations.spec.js and thereafter: feature-2/check-buttons.spec.js. Then I can't do that easily.


Solution attempt 2: Naming tests smartly

I also tried simply naming them appropriately, like explain here: naming your tests in Cypress.

But that pollutes the naming of the tests, making it more cluttered. And it faces the same issues as solution attempt 1 (that I can't easily run two specific tests after one another).


Solution attempt 3: Making a command for it

I considered making a command that tests for it. Here is some pseudo-code:

beforeEach(() => {
  if( preparationsHasntCompleted() ){
    runPreparations();
  }
}

This seems smart, but it would add extra runtime to all my tests.

Zeth
  • 2,273
  • 4
  • 43
  • 91

2 Answers2

3

This may not suit your testing aims, but the new cy.session() can assure cookie is set regardless of test processing order.

Use it in support in beforeEach() to run before every test.

The first test that runs (either test1 or test2) will perform the request, subsequent tests will use cached values (not repeating the requests).

// cypress/support/e2e.js       -- v10 support file

beforeEach(() => {
  cy.session('init', () => {
    // request and set cookies
  })
})
// cypress/e2e/test1.spec.cy.js

it('first test', () => {
  // the beforeEach() for 1st test will fire the request
  ...
})
// cypress/e2e/test2.spec.cy.js

it('second test', () => {
  // the beforeEach() for 2nd test will set same values as before from cache
  // and not resend the request 
})

Upside:

  • performing login once per run (ref runtime concerns)
  • performing tests in any order
  • using the same token for all tests in session (if that's important)

Downside:

  • if obtaining auth cookies manually (vi UI), effectively moving the login test to a beforeEach()

Example logging in via request

Rather than obtaining the auth cookie via UI, it may be possible to get it via cy.request().

Example from the docs,

cy.session([username, password], () => {
  cy.request({
    method: 'POST',
    url: '/login',
    body: { username, password },
  }).then(({ body }) => {
    cy.setCookie('authToken', body.token)
  })
})
Fody
  • 23,754
  • 3
  • 20
  • 37
0

It is generally not recommended to write tests that depend on each other as stated in the best practices. You can never be sure that they run correctly. In your case if the first test fails all the other ones will fail, even if the component/functionality is functioning propperly. Especially if you test more than just the pure login procedure, e.g. design.

As @Fody said before you can ensure being logged in in the beforeEach() hook. I would do it like this:

  • Use one describe to test the login via UI.
  • Use another describe where you put the login (via REST) in the before() and the following command Cypress.Cookies.preserveOnce('<nameOfTheCookie>'); in the beforeEach() to not delete the test for the following it()s
PhilipAllStar
  • 120
  • 1
  • 9