Skip to content

Commit

Permalink
Update cy.session API docs for v12 (#4851)
Browse files Browse the repository at this point in the history
Co-authored-by: Emily Rohrbough <emilyrohrbough@users.noreply.github.com>
Closes #4507
  • Loading branch information
debrisapron authored Dec 5, 2022
1 parent 7cacb1d commit d74889a
Showing 1 changed file with 42 additions and 115 deletions.
157 changes: 42 additions & 115 deletions content/api/commands/session.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ cy.session(id, setup, options)
**<Icon name="check-circle" color="green"></Icon> Correct Usage**

```javascript
// Caching session when logging in via page visit
cy.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 API
cy.session(username, () => {
cy.request({
Expand All @@ -37,15 +46,6 @@ cy.session(username, () => {
window.localStorage.setItem('authToken', body.token)
})
})

// Caching session when logging in via page visit
cy.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')
})
```

**<Icon name="exclamation-triangle" color="red"></Icon> Incorrect Usage**
Expand Down Expand Up @@ -98,9 +98,10 @@ serialize into an identifier, so exercise care with the data you specify.

This 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`
runs, 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 the cached session data.
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.

The page is cleared before `setup` when `testIsolation` is enabled and is not
cleared when `testIsolation` is disabled.
Expand Down Expand Up @@ -131,13 +132,11 @@ command with a call to `cy.session()`.

```javascript
Cypress.Commands.add('login', (username, password) => {
cy.request({
method: 'POST',
url: '/login',
body: { username, password },
}).then(({ body }) => {
window.localStorage.setItem('authToken', body.token)
})
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')
})
```

Expand All @@ -146,13 +145,11 @@ Cypress.Commands.add('login', (username, password) => {
```javascript
Cypress.Commands.add('login', (username, password) => {
cy.session([username, password], () => {
cy.request({
method: 'POST',
url: '/login',
body: { username, password },
}).then(({ body }) => {
window.localStorage.setItem('authToken', body.token)
})
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')
})
})
```
Expand All @@ -164,13 +161,11 @@ Cypress.Commands.add('login', (username, password) => {
cy.session(
[username, password],
() => {
cy.request({
method: 'POST',
url: '/login',
body: { username, password },
}).then(({ body }) => {
window.localStorage.setItem('authToken', body.token)
})
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() {
Expand Down Expand Up @@ -227,85 +222,15 @@ const login = (name, password) => {
},
{
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')
},
}
)
}
```

### Asserting the session inside setup

Because `cy.session()` caches session data immediately after the `setup`
function completes, it's a best practice to assert that the login process has
completed at the end of session setup, to ensure that `setup` doesn't return
before the session data is available to be cached.

Asserting sessions in this way can help simplify your login custom command, and
reduce the need to
[conditionally cache sessions](#Conditionally-caching-a-session).

```javascript
cy.session('user', () => {
cy.visit('/login')
cy.get('[data-test=name]').type(name)
cy.get('[data-test=password]').type('p4ssw0rd123')
cy.get('#login').click()
// Wait for the post-login redirect to ensure that the
// session actually exists to be cached
cy.url().should('contain', '/login-successful')
})
```

### Conditionally caching a session

Specs usually contain two types of tests where logins are necessary:

1. Testing functionality that only exists for logged-in users
2. Testing the act of logging in

For the first, caching sessions can be incredibly useful for reducing the amount
of time it takes to run tests. However, for the second, it may be necessary to
_not_ cache the session, so that other things can be asserted about the login
process.

In this case, it can be helpful to create a custom login command that will
conditionally cache the session. However, wherever possible, it's better to
[assert the session inside setup](#Asserting-the-session-inside-setup).

```javascript
Cypress.Commands.add('login', (name, { cacheSession = true } = {}) => {
const login = () => {
cy.visit('/login')
cy.get('[data-test=name]').type(name)
cy.get('[data-test=password]').type('p4ssw0rd123')
cy.get('#login').click()
}
if (cacheSession) {
cy.session(name, login)
} else {
login()
}
})

// Testing the login flow itself
describe('login', () => {
it('should redirect to the correct page after logging in', () => {
cy.login('user', { cacheSession: false })
cy.url().should('contain', '/login-successful')
})
})

// Testing something that simply requires being logged in
describe('account details', () => {
it('should have the correct document title', () => {
cy.login('user')
cy.visit('/account')
cy.title().should('eq', 'User Account Details')
})
})
```

### Switching sessions inside tests

Because `cy.session()` clears the page and all session data before running
Expand Down Expand Up @@ -472,9 +397,10 @@ const loginByApi = (name, password) => {

### Where to call `cy.visit()`

If you call [`cy.visit()`](/api/commands/visit) immediately after `cy.session()`
in your login function or custom command, it will effectively behave the same as
a login function without any session caching.
Intuitively it seems that you should call [`cy.visit()`](/api/commands/visit)
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()`.

```javascript
const login = (name) => {
Expand All @@ -501,10 +427,11 @@ it('should test something else on the /home page', () => {
})
```

However, any time you want to test something on a different page, you will need
to call `cy.visit()` at the beginning of that test, which will then be
effectively calling `cy.visit()` twice in a row, which will result in slightly
slower tests.
However, 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.

```javascript
// ...continued...
Expand All @@ -515,10 +442,10 @@ it('should test something on the /other page', () => {
})
```

Tests will often be faster if you call `cy.visit()` only when necessary. This
works especially well when
Tests will obviously be faster if you call `cy.visit()` only when necessary.
This can be easily realised by
[organizing tests into suites](/guides/core-concepts/writing-and-organizing-tests#Test-Structure)
and calling `cy.visit()` after logging in inside a
and calling `cy.visit()` **after** logging in, inside a
[`beforeEach`](/guides/core-concepts/writing-and-organizing-tests#Hooks) hook.

```javascript
Expand Down

0 comments on commit d74889a

Please sign in to comment.