1
+ /* Event listeners + custom commands for Cypress */
2
+
3
+ const browserStackLog = ( message ) => {
4
+ if ( ! Cypress . env ( 'BROWSERSTACK_LOGS' ) ) return ;
5
+ cy . task ( 'browserstack_log' , message ) ;
6
+ }
7
+
8
+ const commandsToWrap = [ 'visit' , 'click' , 'type' , 'request' , 'dblclick' , 'rightclick' , 'clear' , 'check' , 'uncheck' , 'select' , 'trigger' , 'selectFile' , 'scrollIntoView' , 'scroll' , 'scrollTo' , 'blur' , 'focus' , 'go' , 'reload' , 'submit' , 'viewport' , 'origin' ] ;
9
+
10
+ const performScan = ( win , payloadToSend ) =>
11
+ new Promise ( async ( resolve , reject ) => {
12
+ const isHttpOrHttps = / ^ ( h t t p | h t t p s ) : $ / . test ( win . location . protocol ) ;
13
+ if ( ! isHttpOrHttps ) {
14
+ resolve ( ) ;
15
+ }
16
+
17
+ function findAccessibilityAutomationElement ( ) {
18
+ return win . document . querySelector ( "#accessibility-automation-element" ) ;
19
+ }
20
+
21
+ function waitForScannerReadiness ( retryCount = 30 , retryInterval = 100 ) {
22
+ return new Promise ( async ( resolve , reject ) => {
23
+ let count = 0 ;
24
+ const intervalID = setInterval ( async ( ) => {
25
+ if ( count > retryCount ) {
26
+ clearInterval ( intervalID ) ;
27
+ reject (
28
+ new Error (
29
+ "Accessibility Automation Scanner is not ready on the page."
30
+ )
31
+ ) ;
32
+ } else if ( findAccessibilityAutomationElement ( ) ) {
33
+ clearInterval ( intervalID ) ;
34
+ resolve ( "Scanner set" ) ;
35
+ } else {
36
+ count += 1 ;
37
+ }
38
+ } , retryInterval ) ;
39
+ } ) ;
40
+ }
41
+
42
+ function startScan ( ) {
43
+ function onScanComplete ( ) {
44
+ win . removeEventListener ( "A11Y_SCAN_FINISHED" , onScanComplete ) ;
45
+ resolve ( ) ;
46
+ }
47
+
48
+ win . addEventListener ( "A11Y_SCAN_FINISHED" , onScanComplete ) ;
49
+ const e = new CustomEvent ( "A11Y_SCAN" , { detail : payloadToSend } ) ;
50
+ win . dispatchEvent ( e ) ;
51
+ }
52
+
53
+ if ( findAccessibilityAutomationElement ( ) ) {
54
+ startScan ( ) ;
55
+ } else {
56
+ waitForScannerReadiness ( )
57
+ . then ( startScan )
58
+ . catch ( async ( err ) => {
59
+ resolve ( "Scanner is not ready on the page after multiple retries. performscan" ) ;
60
+ } ) ;
61
+ }
62
+ } )
63
+
64
+ const getAccessibilityResultsSummary = ( win ) =>
65
+ new Promise ( ( resolve ) => {
66
+ const isHttpOrHttps = / ^ ( h t t p | h t t p s ) : $ / . test ( window . location . protocol ) ;
67
+ if ( ! isHttpOrHttps ) {
68
+ resolve ( ) ;
69
+ }
70
+
71
+ function findAccessibilityAutomationElement ( ) {
72
+ return win . document . querySelector ( "#accessibility-automation-element" ) ;
73
+ }
74
+
75
+ function waitForScannerReadiness ( retryCount = 30 , retryInterval = 100 ) {
76
+ return new Promise ( ( resolve , reject ) => {
77
+ let count = 0 ;
78
+ const intervalID = setInterval ( ( ) => {
79
+ if ( count > retryCount ) {
80
+ clearInterval ( intervalID ) ;
81
+ reject (
82
+ new Error (
83
+ "Accessibility Automation Scanner is not ready on the page."
84
+ )
85
+ ) ;
86
+ } else if ( findAccessibilityAutomationElement ( ) ) {
87
+ clearInterval ( intervalID ) ;
88
+ resolve ( "Scanner set" ) ;
89
+ } else {
90
+ count += 1 ;
91
+ }
92
+ } , retryInterval ) ;
93
+ } ) ;
94
+ }
95
+
96
+ function getSummary ( ) {
97
+ function onReceiveSummary ( event ) {
98
+ win . removeEventListener ( "A11Y_RESULTS_SUMMARY" , onReceiveSummary ) ;
99
+ resolve ( event . detail ) ;
100
+ }
101
+
102
+ win . addEventListener ( "A11Y_RESULTS_SUMMARY" , onReceiveSummary ) ;
103
+ const e = new CustomEvent ( "A11Y_GET_RESULTS_SUMMARY" ) ;
104
+ win . dispatchEvent ( e ) ;
105
+ }
106
+
107
+ if ( findAccessibilityAutomationElement ( ) ) {
108
+ getSummary ( ) ;
109
+ } else {
110
+ waitForScannerReadiness ( )
111
+ . then ( getSummary )
112
+ . catch ( ( err ) => {
113
+ resolve ( ) ;
114
+ } ) ;
115
+ }
116
+ } )
117
+
118
+ const getAccessibilityResults = ( win ) =>
119
+ new Promise ( ( resolve ) => {
120
+ const isHttpOrHttps = / ^ ( h t t p | h t t p s ) : $ / . test ( window . location . protocol ) ;
121
+ if ( ! isHttpOrHttps ) {
122
+ resolve ( ) ;
123
+ }
124
+
125
+ function findAccessibilityAutomationElement ( ) {
126
+ return win . document . querySelector ( "#accessibility-automation-element" ) ;
127
+ }
128
+
129
+ function waitForScannerReadiness ( retryCount = 30 , retryInterval = 100 ) {
130
+ return new Promise ( ( resolve , reject ) => {
131
+ let count = 0 ;
132
+ const intervalID = setInterval ( ( ) => {
133
+ if ( count > retryCount ) {
134
+ clearInterval ( intervalID ) ;
135
+ reject (
136
+ new Error (
137
+ "Accessibility Automation Scanner is not ready on the page."
138
+ )
139
+ ) ;
140
+ } else if ( findAccessibilityAutomationElement ( ) ) {
141
+ clearInterval ( intervalID ) ;
142
+ resolve ( "Scanner set" ) ;
143
+ } else {
144
+ count += 1 ;
145
+ }
146
+ } , retryInterval ) ;
147
+ } ) ;
148
+ }
149
+
150
+ function getResults ( ) {
151
+ function onReceivedResult ( event ) {
152
+ win . removeEventListener ( "A11Y_RESULTS_RESPONSE" , onReceivedResult ) ;
153
+ resolve ( event . detail ) ;
154
+ }
155
+
156
+ win . addEventListener ( "A11Y_RESULTS_RESPONSE" , onReceivedResult ) ;
157
+ const e = new CustomEvent ( "A11Y_GET_RESULTS" ) ;
158
+ win . dispatchEvent ( e ) ;
159
+ }
160
+
161
+ if ( findAccessibilityAutomationElement ( ) ) {
162
+ getResults ( ) ;
163
+ } else {
164
+ waitForScannerReadiness ( )
165
+ . then ( getResults )
166
+ . catch ( ( err ) => {
167
+ resolve ( ) ;
168
+ } ) ;
169
+ }
170
+ } ) ;
171
+
172
+ const saveTestResults = ( win , payloadToSend ) =>
173
+ new Promise ( ( resolve , reject ) => {
174
+ try {
175
+ const isHttpOrHttps = / ^ ( h t t p | h t t p s ) : $ / . test ( win . location . protocol ) ;
176
+ if ( ! isHttpOrHttps ) {
177
+ resolve ( "Unable to save accessibility results, Invalid URL." ) ;
178
+ }
179
+
180
+ function findAccessibilityAutomationElement ( ) {
181
+ return win . document . querySelector ( "#accessibility-automation-element" ) ;
182
+ }
183
+
184
+ function waitForScannerReadiness ( retryCount = 30 , retryInterval = 100 ) {
185
+ return new Promise ( ( resolve , reject ) => {
186
+ let count = 0 ;
187
+ const intervalID = setInterval ( async ( ) => {
188
+ if ( count > retryCount ) {
189
+ clearInterval ( intervalID ) ;
190
+ reject (
191
+ new Error (
192
+ "Accessibility Automation Scanner is not ready on the page."
193
+ )
194
+ ) ;
195
+ } else if ( findAccessibilityAutomationElement ( ) ) {
196
+ clearInterval ( intervalID ) ;
197
+ resolve ( "Scanner set" ) ;
198
+ } else {
199
+ count += 1 ;
200
+ }
201
+ } , retryInterval ) ;
202
+ } ) ;
203
+ }
204
+
205
+ function saveResults ( ) {
206
+ function onResultsSaved ( event ) {
207
+ resolve ( ) ;
208
+ }
209
+ win . addEventListener ( "A11Y_RESULTS_SAVED" , onResultsSaved ) ;
210
+ const e = new CustomEvent ( "A11Y_SAVE_RESULTS" , {
211
+ detail : payloadToSend ,
212
+ } ) ;
213
+ win . dispatchEvent ( e ) ;
214
+ }
215
+
216
+ if ( findAccessibilityAutomationElement ( ) ) {
217
+ saveResults ( ) ;
218
+ } else {
219
+ waitForScannerReadiness ( )
220
+ . then ( saveResults )
221
+ . catch ( async ( err ) => {
222
+ resolve ( "Scanner is not ready on the page after multiple retries. after run" ) ;
223
+ } ) ;
224
+ }
225
+ } catch ( er ) {
226
+ resolve ( )
227
+ }
228
+
229
+ } )
230
+
231
+ const shouldScanForAccessibility = ( attributes ) => {
232
+ if ( Cypress . env ( "IS_ACCESSIBILITY_EXTENSION_LOADED" ) !== "true" ) return false ;
233
+
234
+ const extensionPath = Cypress . env ( "ACCESSIBILITY_EXTENSION_PATH" ) ;
235
+ const isHeaded = Cypress . browser . isHeaded ;
236
+
237
+ if ( ! isHeaded || ( extensionPath === undefined ) ) return false ;
238
+
239
+ let shouldScanTestForAccessibility = true ;
240
+
241
+ if ( Cypress . env ( "INCLUDE_TAGS_FOR_ACCESSIBILITY" ) || Cypress . env ( "EXCLUDE_TAGS_FOR_ACCESSIBILITY" ) ) {
242
+ try {
243
+ let includeTagArray = [ ] ;
244
+ let excludeTagArray = [ ] ;
245
+ if ( Cypress . env ( "INCLUDE_TAGS_FOR_ACCESSIBILITY" ) ) {
246
+ includeTagArray = Cypress . env ( "INCLUDE_TAGS_FOR_ACCESSIBILITY" ) . split ( ";" )
247
+ }
248
+ if ( Cypress . env ( "EXCLUDE_TAGS_FOR_ACCESSIBILITY" ) ) {
249
+ excludeTagArray = Cypress . env ( "EXCLUDE_TAGS_FOR_ACCESSIBILITY" ) . split ( ";" )
250
+ }
251
+
252
+ const fullTestName = attributes . title ;
253
+ const excluded = excludeTagArray . some ( ( exclude ) => fullTestName . includes ( exclude ) ) ;
254
+ const included = includeTagArray . length === 0 || includeTags . some ( ( include ) => fullTestName . includes ( include ) ) ;
255
+ shouldScanTestForAccessibility = ! excluded && included ;
256
+ } catch ( error ) {
257
+ browserStackLog ( "Error while validating test case for accessibility before scanning. Error : " , error ) ;
258
+ }
259
+ }
260
+
261
+ return shouldScanTestForAccessibility ;
262
+ }
263
+
264
+ Cypress . on ( 'command:start' , async ( command ) => {
265
+ if ( ! command || ! command . attributes ) return ;
266
+ if ( command . attributes . name == 'window' || command . attributes . name == 'then' || command . attributes . name == 'wrap' ) {
267
+ return ;
268
+ }
269
+
270
+ if ( ! commandsToWrap . includes ( command . attributes . name ) ) return ;
271
+
272
+ const attributes = Cypress . mocha . getRunner ( ) . suite . ctx . currentTest || Cypress . mocha . getRunner ( ) . suite . ctx . _runnable ;
273
+
274
+ let shouldScanTestForAccessibility = shouldScanForAccessibility ( attributes ) ;
275
+ if ( ! shouldScanTestForAccessibility ) return ;
276
+
277
+ cy . window ( ) . then ( ( win ) => {
278
+ browserStackLog ( 'Performing scan form command ' + command . attributes . name ) ;
279
+ cy . wrap ( performScan ( win , { method : command . attributes . name } ) , { timeout : 30000 } ) ;
280
+ } )
281
+ } )
282
+
283
+ afterEach ( ( ) => {
284
+ const attributes = Cypress . mocha . getRunner ( ) . suite . ctx . currentTest ;
285
+ cy . window ( ) . then ( async ( win ) => {
286
+ let shouldScanTestForAccessibility = shouldScanForAccessibility ( attributes ) ;
287
+ if ( ! shouldScanTestForAccessibility ) return cy . wrap ( { } ) ;
288
+
289
+ cy . wrap ( performScan ( win ) , { timeout : 30000 } ) . then ( ( ) => {
290
+ try {
291
+ let os_data ;
292
+ if ( Cypress . env ( "OS" ) ) {
293
+ os_data = Cypress . env ( "OS" ) ;
294
+ } else {
295
+ os_data = Cypress . platform === 'linux' ? 'mac' : "win"
296
+ }
297
+ let filePath = '' ;
298
+ if ( attributes . invocationDetails !== undefined && attributes . invocationDetails . relativeFile !== undefined ) {
299
+ filePath = attributes . invocationDetails . relativeFile ;
300
+ }
301
+ const payloadToSend = {
302
+ "saveResults" : shouldScanTestForAccessibility ,
303
+ "testDetails" : {
304
+ "name" : attributes . title ,
305
+ "testRunId" : '5058' , // variable not consumed, shouldn't matter what we send
306
+ "filePath" : filePath ,
307
+ "scopeList" : [
308
+ filePath ,
309
+ attributes . title
310
+ ]
311
+ } ,
312
+ "platform" : {
313
+ "os_name" : os_data ,
314
+ "os_version" : Cypress . env ( "OS_VERSION" ) ,
315
+ "browser_name" : Cypress . browser . name ,
316
+ "browser_version" : Cypress . browser . version
317
+ }
318
+ } ;
319
+ browserStackLog ( `Saving accessibility test results` ) ;
320
+ cy . wrap ( saveTestResults ( win , payloadToSend ) , { timeout : 30000 } ) . then ( ( ) => {
321
+ browserStackLog ( `Saved accessibility test results` ) ;
322
+ } )
323
+
324
+ } catch ( er ) {
325
+ }
326
+ } )
327
+ } ) ;
328
+ } )
329
+
330
+ Cypress . Commands . add ( 'performScan' , ( ) => {
331
+ try {
332
+ const attributes = Cypress . mocha . getRunner ( ) . suite . ctx . currentTest || Cypress . mocha . getRunner ( ) . suite . ctx . _runnable ;
333
+ const shouldScanTestForAccessibility = shouldScanForAccessibility ( attributes ) ;
334
+ if ( ! shouldScanTestForAccessibility ) {
335
+ browserStackLog ( `Not a Accessibility Automation session, cannot perform scan.` ) ;
336
+ return cy . wrap ( { } ) ;
337
+ }
338
+ cy . window ( ) . then ( async ( win ) => {
339
+ browserStackLog ( `Performing accessibility scan` ) ;
340
+ await performScan ( win ) ;
341
+ } ) ;
342
+ } catch { }
343
+ } )
344
+
345
+ Cypress . Commands . add ( 'getAccessibilityResultsSummary' , ( ) => {
346
+ try {
347
+ const attributes = Cypress . mocha . getRunner ( ) . suite . ctx . currentTest || Cypress . mocha . getRunner ( ) . suite . ctx . _runnable ;
348
+ const shouldScanTestForAccessibility = shouldScanForAccessibility ( attributes ) ;
349
+ if ( ! shouldScanTestForAccessibility ) {
350
+ browserStackLog ( `Not a Accessibility Automation session, cannot retrieve Accessibility results summary.` ) ;
351
+ return cy . wrap ( { } ) ;
352
+ }
353
+ cy . window ( ) . then ( async ( win ) => {
354
+ await performScan ( win ) ;
355
+ browserStackLog ( 'Getting accessibility results summary' ) ;
356
+ return await getAccessibilityResultsSummary ( win ) ;
357
+ } ) ;
358
+ } catch { }
359
+
360
+ } ) ;
361
+
362
+ Cypress . Commands . add ( 'getAccessibilityResults' , ( ) => {
363
+ try {
364
+ const attributes = Cypress . mocha . getRunner ( ) . suite . ctx . currentTest || Cypress . mocha . getRunner ( ) . suite . ctx . _runnable ;
365
+ const shouldScanTestForAccessibility = shouldScanForAccessibility ( attributes ) ;
366
+ if ( ! shouldScanTestForAccessibility ) {
367
+ browserStackLog ( `Not a Accessibility Automation session, cannot retrieve Accessibility results.` ) ;
368
+ return cy . wrap ( { } ) ;
369
+ }
370
+
371
+ /* browserstack_accessibility_automation_script */
372
+
373
+ cy . window ( ) . then ( async ( win ) => {
374
+ await performScan ( win ) ;
375
+ browserStackLog ( 'Getting accessibility results' ) ;
376
+ return await getAccessibilityResults ( win ) ;
377
+ } ) ;
378
+
379
+ } catch { }
380
+
381
+ } ) ;
0 commit comments