@@ -27,6 +27,15 @@ cy.session(id, setup, options)
27
27
** <Icon name =" check-circle " color =" green " ></Icon > Correct Usage**
28
28
29
29
``` javascript
30
+ // Caching session when logging in via page visit
31
+ cy .session (name, () => {
32
+ cy .visit (' /login' )
33
+ cy .get (' [data-test=name]' ).type (name)
34
+ cy .get (' [data-test=password]' ).type (' s3cr3t' )
35
+ cy .get (' form' ).contains (' Log In' ).click ()
36
+ cy .url ().should (' contain' , ' /login-successful' )
37
+ })
38
+
30
39
// Caching session when logging in via API
31
40
cy .session (username, () => {
32
41
cy .request ({
@@ -37,15 +46,6 @@ cy.session(username, () => {
37
46
window .localStorage .setItem (' authToken' , body .token )
38
47
})
39
48
})
40
-
41
- // Caching session when logging in via page visit
42
- cy .session (name, () => {
43
- cy .visit (' /login' )
44
- cy .get (' [data-test=name]' ).type (name)
45
- cy .get (' [data-test=password]' ).type (' s3cr3t' )
46
- cy .get (' form' ).contains (' Log In' ).click ()
47
- cy .url ().should (' contain' , ' /login-successful' )
48
- })
49
49
```
50
50
51
51
** <Icon name =" exclamation-triangle " color =" red " ></Icon > Incorrect Usage**
@@ -98,9 +98,10 @@ serialize into an identifier, so exercise care with the data you specify.
98
98
99
99
This function is called whenever a session for the given ` id ` hasn't yet been
100
100
cached, or if it's no longer valid (see the ` validate ` option). After ` setup `
101
- runs, Cypress will preserve all cookies, ` sessionStorage ` , and ` localStorage ` ,
102
- so that subsequent calls to ` cy.session() ` with the same ` id ` will bypass
103
- ` setup ` and just restore the cached session data.
101
+ and ` validate ` runs for the first time, Cypress will preserve all cookies,
102
+ ` sessionStorage ` , and ` localStorage ` , so that subsequent calls to ` cy.session() `
103
+ with the same ` id ` will bypass setup and just restore and validate the cached
104
+ session data.
104
105
105
106
The page is cleared before ` setup ` when ` testIsolation ` is enabled and is not
106
107
cleared when ` testIsolation ` is disabled.
@@ -131,13 +132,11 @@ command with a call to `cy.session()`.
131
132
132
133
``` javascript
133
134
Cypress .Commands .add (' login' , (username , password ) => {
134
- cy .request ({
135
- method: ' POST' ,
136
- url: ' /login' ,
137
- body: { username, password },
138
- }).then (({ body }) => {
139
- window .localStorage .setItem (' authToken' , body .token )
140
- })
135
+ cy .visit (' /login' )
136
+ cy .get (' [data-test=name]' ).type (username)
137
+ cy .get (' [data-test=password]' ).type (password)
138
+ cy .get (' form' ).contains (' Log In' ).click ()
139
+ cy .url ().should (' contain' , ' /login-successful' )
141
140
})
142
141
```
143
142
@@ -146,13 +145,11 @@ Cypress.Commands.add('login', (username, password) => {
146
145
``` javascript
147
146
Cypress .Commands .add (' login' , (username , password ) => {
148
147
cy .session ([username, password], () => {
149
- cy .request ({
150
- method: ' POST' ,
151
- url: ' /login' ,
152
- body: { username, password },
153
- }).then (({ body }) => {
154
- window .localStorage .setItem (' authToken' , body .token )
155
- })
148
+ cy .visit (' /login' )
149
+ cy .get (' [data-test=name]' ).type (username)
150
+ cy .get (' [data-test=password]' ).type (password)
151
+ cy .get (' form' ).contains (' Log In' ).click ()
152
+ cy .url ().should (' contain' , ' /login-successful' )
156
153
})
157
154
})
158
155
```
@@ -164,13 +161,11 @@ Cypress.Commands.add('login', (username, password) => {
164
161
cy .session (
165
162
[username, password],
166
163
() => {
167
- cy .request ({
168
- method: ' POST' ,
169
- url: ' /login' ,
170
- body: { username, password },
171
- }).then (({ body }) => {
172
- window .localStorage .setItem (' authToken' , body .token )
173
- })
164
+ cy .visit (' /login' )
165
+ cy .get (' [data-test=name]' ).type (username)
166
+ cy .get (' [data-test=password]' ).type (password)
167
+ cy .get (' form' ).contains (' Log In' ).click ()
168
+ cy .url ().should (' contain' , ' /login-successful' )
174
169
},
175
170
{
176
171
validate () {
@@ -227,85 +222,15 @@ const login = (name, password) => {
227
222
},
228
223
{
229
224
validate () {
225
+ // Protected URLs should return a 40x http code if user is unauthorized,
226
+ // and by default this will cause cy.visit() to fail
230
227
cy .visit (' /account-details' )
231
228
},
232
229
}
233
230
)
234
231
}
235
232
```
236
233
237
- ### Asserting the session inside setup
238
-
239
- Because ` cy.session() ` caches session data immediately after the ` setup `
240
- function completes, it's a best practice to assert that the login process has
241
- completed at the end of session setup, to ensure that ` setup ` doesn't return
242
- before the session data is available to be cached.
243
-
244
- Asserting sessions in this way can help simplify your login custom command, and
245
- reduce the need to
246
- [ conditionally cache sessions] ( #Conditionally-caching-a-session ) .
247
-
248
- ``` javascript
249
- cy .session (' user' , () => {
250
- cy .visit (' /login' )
251
- cy .get (' [data-test=name]' ).type (name)
252
- cy .get (' [data-test=password]' ).type (' p4ssw0rd123' )
253
- cy .get (' #login' ).click ()
254
- // Wait for the post-login redirect to ensure that the
255
- // session actually exists to be cached
256
- cy .url ().should (' contain' , ' /login-successful' )
257
- })
258
- ```
259
-
260
- ### Conditionally caching a session
261
-
262
- Specs usually contain two types of tests where logins are necessary:
263
-
264
- 1 . Testing functionality that only exists for logged-in users
265
- 2 . Testing the act of logging in
266
-
267
- For the first, caching sessions can be incredibly useful for reducing the amount
268
- of time it takes to run tests. However, for the second, it may be necessary to
269
- _ not_ cache the session, so that other things can be asserted about the login
270
- process.
271
-
272
- In this case, it can be helpful to create a custom login command that will
273
- conditionally cache the session. However, wherever possible, it's better to
274
- [ assert the session inside setup] ( #Asserting-the-session-inside-setup ) .
275
-
276
- ``` javascript
277
- Cypress .Commands .add (' login' , (name , { cacheSession = true } = {}) => {
278
- const login = () => {
279
- cy .visit (' /login' )
280
- cy .get (' [data-test=name]' ).type (name)
281
- cy .get (' [data-test=password]' ).type (' p4ssw0rd123' )
282
- cy .get (' #login' ).click ()
283
- }
284
- if (cacheSession) {
285
- cy .session (name, login)
286
- } else {
287
- login ()
288
- }
289
- })
290
-
291
- // Testing the login flow itself
292
- describe (' login' , () => {
293
- it (' should redirect to the correct page after logging in' , () => {
294
- cy .login (' user' , { cacheSession: false })
295
- cy .url ().should (' contain' , ' /login-successful' )
296
- })
297
- })
298
-
299
- // Testing something that simply requires being logged in
300
- describe (' account details' , () => {
301
- it (' should have the correct document title' , () => {
302
- cy .login (' user' )
303
- cy .visit (' /account' )
304
- cy .title ().should (' eq' , ' User Account Details' )
305
- })
306
- })
307
- ```
308
-
309
234
### Switching sessions inside tests
310
235
311
236
Because ` cy.session() ` clears the page and all session data before running
@@ -472,9 +397,10 @@ const loginByApi = (name, password) => {
472
397
473
398
### Where to call ` cy.visit() `
474
399
475
- If you call [ ` cy.visit() ` ] ( /api/commands/visit ) immediately after ` cy.session() `
476
- in your login function or custom command, it will effectively behave the same as
477
- a login function without any session caching.
400
+ Intuitively it seems that you should call [ ` cy.visit() ` ] ( /api/commands/visit )
401
+ immediately after ` cy.session() ` in your login function or custom command, so it
402
+ behaves (from the point of view of the subsequent test) exactly the same as a
403
+ login function without ` cy.session() ` .
478
404
479
405
``` javascript
480
406
const login = (name ) => {
@@ -501,10 +427,11 @@ it('should test something else on the /home page', () => {
501
427
})
502
428
```
503
429
504
- However, any time you want to test something on a different page, you will need
505
- to call ` cy.visit() ` at the beginning of that test, which will then be
506
- effectively calling ` cy.visit() ` twice in a row, which will result in slightly
507
- slower tests.
430
+ However, if you want to test something on a different page, you will need to
431
+ call ` cy.visit() ` at the beginning of that test, which means you will be calling
432
+ ` cy.visit() ` a ** second** time in your test. Since ` cy.visit() ` waits for the
433
+ visited page to become active before continuing, this could add up to an
434
+ unacceptable waste of time.
508
435
509
436
``` javascript
510
437
// ...continued...
@@ -515,10 +442,10 @@ it('should test something on the /other page', () => {
515
442
})
516
443
```
517
444
518
- Tests will often be faster if you call ` cy.visit() ` only when necessary. This
519
- works especially well when
445
+ Tests will obviously be faster if you call ` cy.visit() ` only when necessary.
446
+ This can be easily realised by
520
447
[ organizing tests into suites] ( /guides/core-concepts/writing-and-organizing-tests#Test-Structure )
521
- and calling ` cy.visit() ` after logging in inside a
448
+ and calling ` cy.visit() ` ** after** logging in, inside a
522
449
[ ` beforeEach ` ] ( /guides/core-concepts/writing-and-organizing-tests#Hooks ) hook.
523
450
524
451
``` javascript
0 commit comments