forked from cypress-io/cypress
-
Notifications
You must be signed in to change notification settings - Fork 0
/
stability.ts
102 lines (80 loc) · 2.98 KB
/
stability.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import Promise from 'bluebird'
import type { ICypress } from '../cypress'
import type { StateFunc } from '../cypress/state'
// eslint-disable-next-line @cypress/dev/arrow-body-multiline-braces
export const create = (Cypress: ICypress, state: StateFunc) => ({
isStable: (stable: boolean = true, event: string) => {
if (state('isStable') === stable) {
return
}
const whenStable = state('whenStable')
if (stable && whenStable) {
whenStable()
}
state('isStable', stable)
// we notify the outside world because this is what the runner uses to
// show the 'loading spinner' during an app page loading transition event
Cypress.action('cy:stability:changed', stable, event)
},
whenStable: (fn: () => any) => {
if (state('isStable') !== false) {
return Promise.try(fn)
}
return new Promise((resolve, reject) => {
// then when we become stable
state('whenStable', () => {
// reset this callback function
state('whenStable', null)
// and invoke the original function
Promise.try(fn)
.then(resolve)
.catch(reject)
})
})
},
isAnticipatingCrossOriginResponseFor (request: {href: string}): void {
if (state('anticipatingCrossOriginResponse') === request) {
return
}
const whenAnticipatingCrossOriginResponse = state('whenAnticipatingCrossOriginResponse')
if (!!request?.href && whenAnticipatingCrossOriginResponse) {
whenAnticipatingCrossOriginResponse()
}
state('anticipatingCrossOriginResponse', request)
},
whenStableOrAnticipatingCrossOriginResponse (fn, command?) {
const commandIsOrigin = command?.get('name') === 'origin'
const commandIsEndLogGroup = command?.get('name') === 'end-logGroup'
if (
// cy.origin() needs to run when unstable (if we're anticipating
// a cross-origin response) in order to allow it to set up a spec bridge
// before the page loads and stability is restored
(!!state('anticipatingCrossOriginResponse') && commandIsOrigin)
// the end-logGroup command is inserted internally to mark the end of
// a command group and needs to be allowed or stability will hang things
// up if chaining cy.origin commands
|| commandIsEndLogGroup
|| state('isStable') !== false
) {
return Promise.try(fn)
}
return new Promise((resolve, reject) => {
let fulfilled = false
const onSignal = () => {
if (fulfilled) return
fulfilled = true
state('whenStable', null)
state('whenAnticipatingCrossOriginResponse', null)
Promise.try(fn)
.then(resolve)
.catch(reject)
}
state('whenStable', onSignal)
// We only care to listen for anticipating cross origin request when the command we're waiting for is origin
if (commandIsOrigin) {
state('whenAnticipatingCrossOriginResponse', onSignal)
}
})
},
})
export interface IStability extends ReturnType<typeof create> {}