1
1
const { assertLogLength } = require ( '../../support/utils' )
2
2
const { $, _ } = Cypress
3
3
4
+ const captureCommands = ( ) => {
5
+ const commands = [ ]
6
+
7
+ let current
8
+
9
+ cy . on ( 'command:start' , ( command ) => {
10
+ current = command
11
+ commands . push ( {
12
+ name : command . attributes . name ,
13
+ snapshots : 0 ,
14
+ retries : 0 ,
15
+ } )
16
+ } )
17
+
18
+ cy . on ( 'command:retry' , ( ) => {
19
+ commands [ commands . length - 1 ] . retries ++
20
+ } )
21
+
22
+ cy . on ( 'snapshot' , ( ) => {
23
+ // Snapshots can occur outside the context of a command - for example, `expect(foo).to.exist` without any wrapping cy command.
24
+ // So we keep track of the current command when one starts, and if we're not inside that, create an 'empty' command
25
+ // for the snapshot to belong to
26
+ if ( ! commands . length || current !== cy . state ( 'current' ) ) {
27
+ current = null
28
+ commands . push ( { name : null , snapshots : 0 , retries : 0 } )
29
+ }
30
+
31
+ commands [ commands . length - 1 ] . snapshots ++
32
+ } )
33
+
34
+ return ( ) => _ . cloneDeep ( commands )
35
+ }
36
+
4
37
describe ( 'src/cy/commands/assertions' , ( ) => {
5
38
before ( ( ) => {
6
39
cy
@@ -10,10 +43,14 @@ describe('src/cy/commands/assertions', () => {
10
43
} )
11
44
} )
12
45
46
+ let testCommands
47
+
13
48
beforeEach ( function ( ) {
14
49
const doc = cy . state ( 'document' )
15
50
16
51
$ ( doc . body ) . empty ( ) . html ( this . body )
52
+
53
+ testCommands = captureCommands ( )
17
54
} )
18
55
19
56
context ( '#should' , ( ) => {
@@ -29,8 +66,14 @@ describe('src/cy/commands/assertions', () => {
29
66
} )
30
67
31
68
it ( 'returns the subject for chainability' , ( ) => {
32
- cy . noop ( { foo : 'bar' } ) . should ( 'deep.eq' , { foo : 'bar' } ) . then ( ( obj ) => {
33
- expect ( obj ) . to . deep . eq ( { foo : 'bar' } )
69
+ cy
70
+ . noop ( { foo : 'bar' } ) . should ( 'deep.eq' , { foo : 'bar' } )
71
+ . then ( ( obj ) => {
72
+ expect ( testCommands ( ) ) . to . eql ( [
73
+ { name : 'noop' , snapshots : 0 , retries : 0 } ,
74
+ { name : 'should' , snapshots : 1 , retries : 0 } ,
75
+ { name : 'then' , snapshots : 0 , retries : 0 } ,
76
+ ] )
34
77
} )
35
78
} )
36
79
@@ -121,11 +164,19 @@ describe('src/cy/commands/assertions', () => {
121
164
cy . wrap ( obj ) . then ( ( ) => {
122
165
setTimeout ( ( ) => {
123
166
obj . foo = 'baz'
124
- }
125
- , 100 )
167
+ } , 100 )
126
168
127
169
cy . wrap ( obj )
128
- } ) . should ( 'deep.eq' , { foo : 'baz' } )
170
+ } )
171
+ . should ( 'deep.eq' , { foo : 'baz' } )
172
+ . then ( ( ) => {
173
+ expect ( testCommands ( ) ) . to . containSubset ( [
174
+ { name : 'wrap' , snapshots : 1 , retries : 0 } ,
175
+ { name : 'then' , snapshots : 0 , retries : 0 } ,
176
+ { name : 'wrap' , snapshots : 2 , retries : ( r ) => r > 1 } ,
177
+ { name : 'then' , snapshots : 0 , retries : 0 } ,
178
+ ] )
179
+ } )
129
180
} )
130
181
131
182
// https://github.com/cypress-io/cypress/issues/16006
@@ -151,6 +202,18 @@ describe('src/cy/commands/assertions', () => {
151
202
cy . get ( 'button:first' ) . should ( ( $button ) => {
152
203
expect ( $button ) . to . have . class ( 'ready' )
153
204
} )
205
+ . then ( ( ) => {
206
+ expect ( testCommands ( ) ) . to . eql ( [
207
+ // cy.get() has 2 snapshots, 1 for itself, and 1
208
+ // for the .should(...) assertion.
209
+
210
+ // TODO: Investigate whether or not the 2 commands are
211
+ // snapshotted at the same time. If there's no tick between
212
+ // them, we could reuse the snapshots
213
+ { name : 'get' , snapshots : 2 , retries : 2 } ,
214
+ { name : 'then' , snapshots : 0 , retries : 0 } ,
215
+ ] )
216
+ } )
154
217
} )
155
218
156
219
it ( 'works with regular objects' , ( ) => {
@@ -1475,7 +1538,7 @@ describe('src/cy/commands/assertions', () => {
1475
1538
done ( )
1476
1539
} )
1477
1540
1478
- cy . get ( 'div' ) . should ( ( $divs ) => {
1541
+ cy . get ( 'div' , { timeout : 100 } ) . should ( ( $divs ) => {
1479
1542
expect ( $divs , 'Filter should have 1 items' ) . to . have . length ( 1 )
1480
1543
} )
1481
1544
} )
@@ -2927,4 +2990,42 @@ describe('src/cy/commands/assertions', () => {
2927
2990
cy . get ( '.foo' ) . should ( 'not.exist' )
2928
2991
} )
2929
2992
} )
2993
+
2994
+ context ( 'implicit assertions' , ( ) => {
2995
+ // https://github.com/cypress-io/cypress/issues/18549
2996
+ // A targeted test for the above issue - in the absence of retries, only a single snapshot
2997
+ // should be taken.
2998
+ it ( 'only snapshots once when failing to find DOM elements and not retrying' , ( done ) => {
2999
+ cy . on ( 'fail' , ( err ) => {
3000
+ expect ( testCommands ( ) ) . to . eql ( [ {
3001
+ name : 'get' ,
3002
+ snapshots : 1 ,
3003
+ retries : 0 ,
3004
+ } ] )
3005
+
3006
+ done ( )
3007
+ } )
3008
+
3009
+ cy . get ( '.badId' , { timeout : 0 } )
3010
+ } )
3011
+
3012
+ // https://github.com/cypress-io/cypress/issues/18549
3013
+ // This issue was also causing two DOM snapshots to be taken every 50ms
3014
+ // while waiting for an element to exist. The first test is sufficient to
3015
+ // prevent regressions of the specific issue, but this one is intended to
3016
+ // more generally assert that retries do not trigger multiple snapshots.
3017
+ it ( 'only snapshots once when retrying assertions' , ( done ) => {
3018
+ cy . on ( 'fail' , ( err ) => {
3019
+ expect ( testCommands ( ) ) . to . containSubset ( [ {
3020
+ name : 'get' ,
3021
+ snapshots : 1 ,
3022
+ retries : ( v ) => v > 1 ,
3023
+ } ] )
3024
+
3025
+ done ( )
3026
+ } )
3027
+
3028
+ cy . get ( '.badId' , { timeout : 1000 } )
3029
+ } )
3030
+ } )
2930
3031
} )
0 commit comments