itemengine-cypress-automation 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. package/.build_wna +4 -0
  2. package/README.md +3 -0
  3. package/currents.config.js +6 -0
  4. package/cypress/API/createItem/toggleItemMode.js +15 -0
  5. package/cypress/config-files/ildev.json +15 -0
  6. package/cypress/config-files/ilprod.json +15 -0
  7. package/cypress/config-files/ilqa.json +15 -0
  8. package/cypress/config-files/ilstage.json +15 -0
  9. package/cypress/e2e/ILC/sorry-cypress-test/spec1.js +18 -0
  10. package/cypress/e2e/ILC/sorry-cypress-test/spec2.js +18 -0
  11. package/cypress/e2e/ILC/sorry-cypress-test/spec3.js +18 -0
  12. package/cypress/fixtures/accessibilityConfig.json +6 -0
  13. package/cypress/fixtures/constants.js +18 -0
  14. package/cypress/fixtures/equationEditorCategoriesAndSymbols .js +2271 -0
  15. package/cypress/fixtures/specialAndMathCharacters.js +118 -0
  16. package/cypress/fixtures/theme/ilc.json +150 -0
  17. package/cypress/fixtures/theme/ngie.json +26 -0
  18. package/cypress/fixtures/uploads/20mbFile.png +0 -0
  19. package/cypress/fixtures/uploads/80mbFile.pdf +0 -0
  20. package/cypress/fixtures/uploads/highlightImage.jpg +0 -0
  21. package/cypress/fixtures/uploads/image.png +0 -0
  22. package/cypress/fixtures/uploads/sample.aac +0 -0
  23. package/cypress/fixtures/uploads/sample.accdb +0 -0
  24. package/cypress/fixtures/uploads/sample.csv +100 -0
  25. package/cypress/fixtures/uploads/sample.doc +0 -0
  26. package/cypress/fixtures/uploads/sample.gif +0 -0
  27. package/cypress/fixtures/uploads/sample.heic +0 -0
  28. package/cypress/fixtures/uploads/sample.heif +0 -0
  29. package/cypress/fixtures/uploads/sample.hevc +0 -0
  30. package/cypress/fixtures/uploads/sample.jpeg +0 -0
  31. package/cypress/fixtures/uploads/sample.jpg +0 -0
  32. package/cypress/fixtures/uploads/sample.mp3 +0 -0
  33. package/cypress/fixtures/uploads/sample.mp4 +0 -0
  34. package/cypress/fixtures/uploads/sample.pdf +0 -0
  35. package/cypress/fixtures/uploads/sample.ppt +0 -0
  36. package/cypress/fixtures/uploads/sample.pub +0 -0
  37. package/cypress/fixtures/uploads/sample.rtf +7902 -0
  38. package/cypress/fixtures/uploads/sample.svg +10 -0
  39. package/cypress/fixtures/uploads/sample.txt +1 -0
  40. package/cypress/fixtures/uploads/sample.wav +0 -0
  41. package/cypress/fixtures/uploads/sample.xlsx +0 -0
  42. package/cypress/fixtures/uploads/sample.xps +0 -0
  43. package/cypress/fixtures/uploads/sample.zip +0 -0
  44. package/cypress/fixtures/uploads/sample1.jpg +0 -0
  45. package/cypress/fixtures/uploads/sample1.mp3 +0 -0
  46. package/cypress/fixtures/uploads/sample1.zip +0 -0
  47. package/cypress/fixtures/uploads/sample10Sec.mp3 +0 -0
  48. package/cypress/fixtures/uploads/sample2.jpg +0 -0
  49. package/cypress/fixtures/uploads/sample2.mp3 +0 -0
  50. package/cypress/fixtures/uploads/sampleVirus.zip +0 -0
  51. package/cypress/pages/audioPlayerPage.js +628 -0
  52. package/cypress/pages/audioResponsePage.js +264 -0
  53. package/cypress/pages/components/additionalSettingsPanel.js +174 -0
  54. package/cypress/pages/components/answerNumerationComponent.js +109 -0
  55. package/cypress/pages/components/autoScoredAdditionalSettings.js +183 -0
  56. package/cypress/pages/components/autoScoredPreviewBase.js +94 -0
  57. package/cypress/pages/components/autoScoredScoringSection.js +195 -0
  58. package/cypress/pages/components/autoScoredScoringSectionMultipleResponsesType.js +268 -0
  59. package/cypress/pages/components/autoScoredSetCorrectAnswerSection.js +291 -0
  60. package/cypress/pages/components/ckEditorToolbar.js +64 -0
  61. package/cypress/pages/components/colorPopupComponent.js +293 -0
  62. package/cypress/pages/components/commonComponents.js +93 -0
  63. package/cypress/pages/components/componentsFlowChart/figFlowChart.png +0 -0
  64. package/cypress/pages/components/createCustomCategoryFlyout.js +138 -0
  65. package/cypress/pages/components/createQuestionBasePage.js +225 -0
  66. package/cypress/pages/components/customizeHighlightPropertiesComponent.js +318 -0
  67. package/cypress/pages/components/dragAndDropResponseOptions.js +738 -0
  68. package/cypress/pages/components/dragAndDropSetCorrectAnswerCheckboxComponents.js +124 -0
  69. package/cypress/pages/components/draggableOptionsContainer.js +857 -0
  70. package/cypress/pages/components/editCategoryFlyout.js +40 -0
  71. package/cypress/pages/components/equationEditorFlyout.js +158 -0
  72. package/cypress/pages/components/essayResponseCommonComponents.js +86 -0
  73. package/cypress/pages/components/figOverImageCommonComponent.js +924 -0
  74. package/cypress/pages/components/fillInTheGapsCommonComponents.js +687 -0
  75. package/cypress/pages/components/fillInTheGapsDropdownCommonComponent.js +442 -0
  76. package/cypress/pages/components/fillInTheGapsTextCommonComponent.js +884 -0
  77. package/cypress/pages/components/gridCommonComponents.js +951 -0
  78. package/cypress/pages/components/index.js +38 -0
  79. package/cypress/pages/components/listSortingAndOrderingBase.js +401 -0
  80. package/cypress/pages/components/maximumRecorderLengthComponent.js +116 -0
  81. package/cypress/pages/components/mcqAdditionalSettingsBase.js +390 -0
  82. package/cypress/pages/components/mcqOptionsComponent.js +263 -0
  83. package/cypress/pages/components/mcqPreviewComponents.js +78 -0
  84. package/cypress/pages/components/mcqQuestionCommonComponents.js +265 -0
  85. package/cypress/pages/components/mcqScoringComponent.js +120 -0
  86. package/cypress/pages/components/mcqSetCorrectAnswerSection.js +143 -0
  87. package/cypress/pages/components/optionsWrapperComponent.js +221 -0
  88. package/cypress/pages/components/playbackControlsBaseComponent.js +163 -0
  89. package/cypress/pages/components/previewScoringAndShowCorrectAnswerComponent.js +90 -0
  90. package/cypress/pages/components/questionInstructionsComponent.js +112 -0
  91. package/cypress/pages/components/scoringSectionBase.js +308 -0
  92. package/cypress/pages/components/setPointsPopupBase.js +79 -0
  93. package/cypress/pages/components/specialAndCustomSpecialCharactersComponent.js +79 -0
  94. package/cypress/pages/components/specialCharactersFlyoutComponent.js +58 -0
  95. package/cypress/pages/components/studentResponseAreaAndLayoutComponent.js +28 -0
  96. package/cypress/pages/components/uploadImageSectionComponent.js +594 -0
  97. package/cypress/pages/createItemPage.js +28 -0
  98. package/cypress/pages/dialogBoxBase.js +111 -0
  99. package/cypress/pages/dragAndDropIntoCategoriesAllOrNothingScoring.js +1161 -0
  100. package/cypress/pages/dragAndDropIntoCategoriesCellsScoring.js +1559 -0
  101. package/cypress/pages/dragAndDropIntoCategoriesPage.js +1556 -0
  102. package/cypress/pages/dragAndDropIntoCategoriesResponseScoring.js +1396 -0
  103. package/cypress/pages/essayResponseBasicPage.js +57 -0
  104. package/cypress/pages/essayResponseMathPage.js +47 -0
  105. package/cypress/pages/essayResponsePage.js +385 -0
  106. package/cypress/pages/feedbackScalePage.js +698 -0
  107. package/cypress/pages/fillInTheGapsDragAndDropPage.js +742 -0
  108. package/cypress/pages/fillInTheGapsDropdownPage.js +99 -0
  109. package/cypress/pages/fillInTheGapsOverImageDropdownPage.js +232 -0
  110. package/cypress/pages/fillInTheGapsOverImageTextPage.js +135 -0
  111. package/cypress/pages/fillInTheGapsScoring.js +5974 -0
  112. package/cypress/pages/fillInTheGapsSetCorrectAnswerSection.js +260 -0
  113. package/cypress/pages/fillInTheGapsTextPage.js +225 -0
  114. package/cypress/pages/highlightImagePage.js +1316 -0
  115. package/cypress/pages/highlightPage.js +870 -0
  116. package/cypress/pages/index.js +30 -0
  117. package/cypress/pages/listMatchingPage.js +1330 -0
  118. package/cypress/pages/listMatchingScoring.js +2635 -0
  119. package/cypress/pages/listOrderingPage.js +751 -0
  120. package/cypress/pages/listSortingPage.js +1201 -0
  121. package/cypress/pages/multipleSelectionGridPage.js +359 -0
  122. package/cypress/pages/multipleSelectionPage.js +88 -0
  123. package/cypress/pages/passagePage.js +426 -0
  124. package/cypress/pages/readingRulerPage.js +302 -0
  125. package/cypress/pages/selectQuestionResourceToolPage.js +64 -0
  126. package/cypress/pages/shortTextResponsePage.js +197 -0
  127. package/cypress/pages/singleSelectionGridPage.js +370 -0
  128. package/cypress/pages/singleSelectionPage.js +65 -0
  129. package/cypress/pages/uploadResponsePage.js +110 -0
  130. package/cypress/pages/videoResponsePage.js +375 -0
  131. package/cypress/support/commands.js +140 -0
  132. package/cypress/support/e2e.js +14 -0
  133. package/cypress/support/helpers/abortEarly.js +19 -0
  134. package/cypress/support/helpers/accessibility.js +34 -0
  135. package/cypress/support/helpers/cypressUtilities.js +64 -0
  136. package/cypress/support/helpers/localStorage.js +13 -0
  137. package/cypress/support/helpers/selectText.js +77 -0
  138. package/cypress/support/helpers/utilities.js +126 -0
  139. package/cypress.config.js +76 -0
  140. package/il.yaml +14 -0
  141. package/language +1 -0
  142. package/package.json +26 -0
@@ -0,0 +1,375 @@
1
+ import utilities from "../support/helpers/utilities"
2
+ import { additionalSettingsPanel, commonComponents, createQuestionBasePage, previewScoringAndShowCorrectAnswerComponent, questionInstructionsComponent, scoringSectionBase, maximumRecorderLengthComponent, playbackControlsBaseComponent } from "./components"
3
+ import { dialogBoxBase } from "./dialogBoxBase";
4
+ const css = Cypress.env('css');
5
+
6
+ const selectors = {
7
+ ...commonComponents,
8
+ ...scoringSectionBase,
9
+ ...additionalSettingsPanel,
10
+ ...questionInstructionsComponent,
11
+ ...scoringSectionBase,
12
+ ...dialogBoxBase,
13
+ ...previewScoringAndShowCorrectAnswerComponent,
14
+ ...maximumRecorderLengthComponent,
15
+ ...playbackControlsBaseComponent,
16
+ videoRecorderWrapper: () => cy.get('.video-recorder-wrapper'),
17
+ clickTapAnywhereArea: () => cy.get('.camera-permission'),
18
+ recordButton: () => cy.get('.rec-button'),
19
+ startRecordingText: () => cy.get('.record-text'),
20
+ recordingStatusText: () => cy.get('.recording-status-text'),
21
+ startRecordingCountDown: () => cy.get('.count-down-number'),
22
+ recordingTimer: () => cy.get('[class*="VideoRecorderstyle__RecordTimer"]'),
23
+ recordingStatusIcon: () => cy.get('.recording-wrapper svg'),
24
+ pauseButton: () => cy.get('button[aria-label="Pause recording"]'),
25
+ stopButton: () => cy.get('button[aria-label="Stop recording"]'),
26
+ resumeButton: () => cy.get('button[aria-label="Resume recording"]'),
27
+ recordAgainButton: () => cy.get('button[aria-label="Record again"]'),
28
+ playerTimer: () => cy.get('[class*="VideoRecorderstyle__PlayerTimerWrapper"]'),
29
+ playbackSpeedButton: () => cy.get('button[aria-label="Playback speed"]'),
30
+ fullScreenButton: () => cy.get('button[aria-label="Full screen"]'),
31
+ savedResponseText: () => cy.get('[class*="VideoRecorderstyle__ResponseTextWrapper"]'),
32
+ maxRecorderLengthInputField: () => cy.get('input[aria-label="Maximum recorder length"]'),
33
+ playbackSpeedOptionsList: () => cy.get('[class*="VideoRecorderstyle__PlaybackSpeedOptions"]'),
34
+ playbackSpeedOption: (ariaLabel = null) => {
35
+ if (ariaLabel) {
36
+ return cy.get(`.speed-option[aria-label="${ariaLabel}"]`)
37
+ } else {
38
+ return cy.get('.speed-option')
39
+ }
40
+ },
41
+ confirmRetakeButton: () => cy.get('.delete-action-btn-wrapper button').eq(1),
42
+ cancelRetakeButton: () => cy.get('.delete-action-btn-wrapper button').eq(0),
43
+ retakePopupContent: () => cy.get('.retake-popup-content'),
44
+ advancedPlaybackOptionsLabel: () => cy.get('.advanced-recorder-settings .ngie-toggle-button-title'),
45
+ playbackSpeedAdvancedPlaybackOptionButton: () => cy.get('button[data-ngie-testid="playback-speed-toggle-button"]'),
46
+ fullScreenAdvancedPlaybackOptionButton: () => cy.get('button[data-ngie-testid="full-screen-toggle-button"]'),
47
+ recordAgainAdvancedPlaybackOptionButton: () => cy.get('button[data-ngie-testid="record-again-toggle-button"]'),
48
+ advancedPlaybackOptionButtonSelectedIcon: () => cy.get('.ngie-toggle-button-tick-icon'),
49
+ advancedPlaybackOptionButtonLabel: () => cy.get('.customized_button_label'),
50
+ studentResponseAreaAndLayoutLabel: () => cy.get('.student-response-area-layout-warpper')
51
+ }
52
+
53
+ const steps = {
54
+ ...createQuestionBasePage.steps,
55
+ ...scoringSectionBase.steps,
56
+ ...questionInstructionsComponent.steps,
57
+ ...maximumRecorderLengthComponent.steps,
58
+ ...additionalSettingsPanel.steps,
59
+ ...playbackControlsBaseComponent.steps,
60
+ /**
61
+ * @param {string} recordingStatus - The expected recording status, such as 'Allow access to your camera and microphone.',
62
+ * 'Preparing to record', 'Recording...', 'Recording paused', or 'Saving'.
63
+ * @throws {Error} Throws an error if an invalid recording status is provided.
64
+ * @description this function verifies the display of recording status and associated icons in the video response interface.
65
+ */
66
+ verifyRecordingStatus: (recordingStatus) => {
67
+ const statusIcon = videoResponsePage.recordingStatusIcon();
68
+
69
+ let expectedIconId = null;
70
+
71
+ switch (recordingStatus) {
72
+ case 'Allow access to your camera and microphone.':
73
+ expectedIconId = 'g#Ellipse_99';
74
+ break;
75
+ case 'Preparing to record':
76
+ case 'Recording...':
77
+ expectedIconId = 'g#Recording\\.\\.\\.';
78
+ break;
79
+ case 'Recording paused':
80
+ expectedIconId = 'path#pause';
81
+ break;
82
+ case 'Saving':
83
+ expectedIconId = 'g#Saving';
84
+ break;
85
+ default:
86
+ throw new Error('Invalid recording status');
87
+ }
88
+
89
+ statusIcon.find(`${expectedIconId}`).should('be.visible');
90
+ utilities.verifyInnerText(videoResponsePage.recordingStatusText(), recordingStatus);
91
+ utilities.verifyElementVisibilityState(videoResponsePage.recordingStatusText(), 'visible');
92
+ },
93
+
94
+ startRecording: () => {
95
+ videoResponsePage.clickTapAnywhereArea()
96
+ .click();
97
+ },
98
+
99
+ verifyPauseButtonDisabledState: () => {
100
+ videoResponsePage.pauseButton()
101
+ .should('be.disabled');
102
+ },
103
+
104
+ verifyPauseButtonEnabledState: () => {
105
+ videoResponsePage.pauseButton()
106
+ .should('be.enabled');
107
+ },
108
+
109
+ waitForRecordingToStart: () => {
110
+ utilities.verifyElementVisibilityState(videoResponsePage.recordingTimer(), 'visible');
111
+ videoResponsePage.recordingTimer()
112
+ .should('contain', '00:01 /')
113
+ },
114
+
115
+ pauseRecording: () => {
116
+ videoResponsePage.pauseButton()
117
+ .click();
118
+ },
119
+
120
+ resumeRecording: () => {
121
+ videoResponsePage.resumeButton()
122
+ .click();
123
+ },
124
+
125
+ stopRecording: () => {
126
+ videoResponsePage.stopButton()
127
+ .click();
128
+ },
129
+
130
+ recordAgain: () => {
131
+ videoResponsePage.recordAgainButton()
132
+ .click();
133
+ },
134
+
135
+ /**
136
+ * @description Records a video and saves it for a specified duration.
137
+ * @param {number} time - The duration (in milliseconds) for which the video should be recorded.
138
+ * @throws {Error} Throws an error if any step in the recording process fails.
139
+ */
140
+ recordAndSaveVideo: (time) => {
141
+ videoResponsePage.steps.startRecording();
142
+ utilities.verifyElementVisibilityState(videoResponsePage.startRecordingCountDown(), 'visible')
143
+ utilities.verifyElementVisibilityState(videoResponsePage.startRecordingCountDown(), 'notExist')
144
+ videoResponsePage.steps.waitForRecordingToStart()
145
+ videoResponsePage.steps.addWaitToRecord(time - 1000);
146
+ videoResponsePage.steps.stopRecording();
147
+ },
148
+
149
+ /**
150
+ * @param {string} time for recording a video
151
+ * @description this function adds a wait to record a video
152
+ */
153
+ addWaitToRecord: (time) => {
154
+ cy.wait(time)
155
+ },
156
+
157
+ /**
158
+ * @param {string} time of the recorded video
159
+ * @description this function is used to verify the recording time of a video
160
+ */
161
+ verifyRecordingTime: (time) => {
162
+ utilities.verifyInnerText(videoResponsePage.recordingTimer(), time);
163
+ },
164
+
165
+ /**
166
+ * @param {string} time playing time of the recorded video
167
+ * @description this function is used to verify the playing time of a recorded video
168
+ */
169
+ verifyVideoPlaybackTimer: (time) => {
170
+ videoResponsePage.playerTimer()
171
+ .should('have.text', time);
172
+ },
173
+
174
+ /**
175
+ * @description Waits for the video playback to begin and verifies the displayed time.
176
+ */
177
+ waitForPlaybackToBegin: () => {
178
+ videoResponsePage.playerTimer()
179
+ .should('contain', '00:01/');
180
+ },
181
+
182
+ /**
183
+ * @param {*} elementToHover selector of element whose tooltip CSS needs to be verified
184
+ * @description this function is used to verify tooltip CSS of an element in video response preview
185
+ * @example videoResponsePage.steps.verifyTooltipCSS(videoResponsePage.pauseButton())
186
+ */
187
+ verifyTooltipCSS: (elementToHover) => {
188
+ const tooltipStyles = {
189
+ 'background-color': css.color.defaultBackground,
190
+ 'color': css.color.helperText,
191
+ 'font-size': css.fontSize.normal,
192
+ 'font-weight': css.fontWeight.regular
193
+ };
194
+ elementToHover.trigger('mouseover');
195
+ utilities.verifyElementVisibilityState(videoResponsePage.tooltipText(), 'visible');
196
+ utilities.verifyCSS(videoResponsePage.tooltipText(), tooltipStyles);
197
+ elementToHover.trigger('mouseout');
198
+ utilities.verifyElementVisibilityState(videoResponsePage.tooltipText(), 'notExist');
199
+ },
200
+
201
+ stopAndVerifySavingAndRecordingLength: () => {
202
+ videoResponsePage.recordingTimer()
203
+ .invoke('text')
204
+ .then(text => {
205
+ const recordedTime = text.split('/')[0]
206
+ videoResponsePage.steps.stopRecording();
207
+ videoResponsePage.steps.verifyRecordingStatus('Saving');
208
+ videoResponsePage.playerTimer()
209
+ .invoke('text')
210
+ .then(text => {
211
+ const playbackTime = text.split('/')[1]
212
+ expect(playbackTime).to.be.eq(recordedTime)
213
+ });
214
+ });
215
+ },
216
+
217
+ /**
218
+ * @param {*} elementToHover selector of element whose tooltip accessibility needs to be verified
219
+ * @description this function is used to verify accessibility of tooltip of an element in video response preview
220
+ * @example videoResponsePage.steps.verifyTooltipAccessibility(videoResponsePage.pauseButton())
221
+ */
222
+ verifyTooltipAccessibility: (elementToHover) => {
223
+ elementToHover.trigger('mouseover');
224
+ utilities.verifyElementVisibilityState(commonComponents.tooltipText(), 'visible');
225
+ cy.checkAccessibility(commonComponents.tooltipText());
226
+ elementToHover.trigger('mouseout');
227
+ utilities.verifyElementVisibilityState(commonComponents.tooltipText(), 'notExist');
228
+ },
229
+
230
+ hoverOnPlaybackSpeedButton: () => {
231
+ videoResponsePage.playbackSpeedButton()
232
+ .trigger('mouseover');
233
+ },
234
+
235
+ verifyPlaybackSpeedListOptions: () => {
236
+ const playbackSpeedOptions = ['1x', '1.25x', '1.5x', '2x'];
237
+ for (let index = 0; index < 4; index++) {
238
+ utilities.verifyInnerText(videoResponsePage.playbackSpeedOption().eq(index), playbackSpeedOptions[index]);
239
+ }
240
+ },
241
+
242
+ /**
243
+ * @description Selects a playback speed option for the video player.
244
+ * @param {string} playbackSpeed - The desired playback speed to be selected from "1x", "1.25x" "1.5x", "2x".
245
+ * @throws {Error} Throws an error if the specified playback speed option is not found.
246
+ */
247
+ selectPlaybackSpeed: (playbackSpeed) => {
248
+ videoResponsePage.playbackSpeedOption(playbackSpeed)
249
+ .click();
250
+ },
251
+
252
+ /**
253
+ * @description Verifies that the current playback time on the video player matches the expected time.
254
+ * This function extracts the elapsed time from the video player, calculates the total elapsed time in seconds,
255
+ * and then compares it to the expected time.
256
+ * @param {number} time - The expected playback time in seconds.
257
+ * @throws {Error} Throws an error if the actual playback time does not match the expected time.
258
+ */
259
+ verifyPlaybackElapsedTime: (time) => {
260
+ videoResponsePage.playerTimer()
261
+ .invoke('text')
262
+ .then(text => {
263
+ let elapsedTime = text.split('/')[0]
264
+ let currentElapsedTimerMinutes = Number(elapsedTime.split(':')[0])
265
+ let currentElapsedTimerSeconds = Number(elapsedTime.split(':')[1])
266
+ let currentTotalElapsedTimerSeconds = currentElapsedTimerMinutes * 60 + currentElapsedTimerSeconds
267
+ currentTotalElapsedTimerSeconds.should.equal(time)
268
+ });
269
+ },
270
+
271
+ /**
272
+ * @description Adds a waiting period in milliseconds before playing a video.
273
+ * This function pauses test execution for the specified duration to simulate waiting
274
+ * before initiating video playback.
275
+ * @param {number} time - The duration to wait in milliseconds before playing the video.
276
+ */
277
+ addWaitToPlayVideo: (time) => {
278
+ cy.wait(time);
279
+ },
280
+
281
+ recordAgain: () => {
282
+ videoResponsePage.recordAgainButton()
283
+ .click();
284
+ },
285
+
286
+ cancelRetake: () => {
287
+ videoResponsePage.cancelRetakeButton()
288
+ .click();
289
+ },
290
+
291
+ confirmRetake: () => {
292
+ videoResponsePage.confirmRetakeButton()
293
+ .click();
294
+ },
295
+
296
+ verifyPlaybackSpeedAdvancedPlaybackOptionSelectedState: () => {
297
+ videoResponsePage.playbackSpeedAdvancedPlaybackOptionButton()
298
+ .should('have.class', 'Mui-selected')
299
+ .within(() => {
300
+ utilities.verifyElementVisibilityState(videoResponsePage.advancedPlaybackOptionButtonSelectedIcon(), 'visible');
301
+ });
302
+ },
303
+
304
+ verifyPlaybackSpeedAdvancedPlaybackOptionDeselectedState: () => {
305
+ videoResponsePage.playbackSpeedAdvancedPlaybackOptionButton()
306
+ .should('not.have.class', 'Mui-selected')
307
+ .within(() => {
308
+ utilities.verifyElementVisibilityState(videoResponsePage.advancedPlaybackOptionButtonSelectedIcon(), 'notExist');
309
+ });
310
+ },
311
+
312
+ verifyFullScreenAdvancedPlaybackOptionSelectedState: () => {
313
+ videoResponsePage.fullScreenAdvancedPlaybackOptionButton()
314
+ .should('have.class', 'Mui-selected')
315
+ .within(() => {
316
+ utilities.verifyElementVisibilityState(videoResponsePage.advancedPlaybackOptionButtonSelectedIcon(), 'visible');
317
+ });
318
+ },
319
+
320
+ verifyFullScreenAdvancedPlaybackOptionDeselectedState: () => {
321
+ videoResponsePage.fullScreenAdvancedPlaybackOptionButton()
322
+ .should('not.have.class', 'Mui-selected')
323
+ .within(() => {
324
+ utilities.verifyElementVisibilityState(videoResponsePage.advancedPlaybackOptionButtonSelectedIcon(), 'notExist');
325
+ });
326
+ },
327
+
328
+ verifyRecordAgainAdvancedPlaybackOptionSelectedState: () => {
329
+ videoResponsePage.recordAgainAdvancedPlaybackOptionButton()
330
+ .should('have.class', 'Mui-selected')
331
+ .within(() => {
332
+ utilities.verifyElementVisibilityState(videoResponsePage.advancedPlaybackOptionButtonSelectedIcon(), 'visible');
333
+ });
334
+ },
335
+
336
+ verifyRecordAgainAdvancedPlaybackOptionDeselectedState: () => {
337
+ videoResponsePage.recordAgainAdvancedPlaybackOptionButton()
338
+ .should('not.have.class', 'Mui-selected')
339
+ .within(() => {
340
+ utilities.verifyElementVisibilityState(videoResponsePage.advancedPlaybackOptionButtonSelectedIcon(), 'notExist');
341
+ });
342
+ },
343
+
344
+ clickOnPlaybackSpeedAdvancedPlaybackOption: () => {
345
+ videoResponsePage.playbackSpeedAdvancedPlaybackOptionButton()
346
+ .click();
347
+ },
348
+
349
+ clickOnFullScreenAdvancedPlaybackOption: () => {
350
+ videoResponsePage.fullScreenAdvancedPlaybackOptionButton()
351
+ .click();
352
+ },
353
+
354
+ clickOnRecordAgainAdvancedPlaybackOption: () => {
355
+ videoResponsePage.recordAgainAdvancedPlaybackOptionButton()
356
+ .click();
357
+ }
358
+ }
359
+
360
+ const tests = {
361
+ ...questionInstructionsComponent.tests,
362
+ ...scoringSectionBase.tests,
363
+ ...previewScoringAndShowCorrectAnswerComponent.tests,
364
+ ...commonComponents.tests,
365
+ ...additionalSettingsPanel.tests,
366
+ ...createQuestionBasePage.tests,
367
+ ...commonComponents.tests,
368
+ ...maximumRecorderLengthComponent.tests
369
+ }
370
+
371
+ export const videoResponsePage = {
372
+ ...selectors,
373
+ steps,
374
+ tests
375
+ }
@@ -0,0 +1,140 @@
1
+ import crypto from 'crypto';
2
+ import { v4 as uuidv4 } from 'uuid';
3
+ import "cypress-real-events/support";
4
+ import 'cypress-file-upload';
5
+ require('cy-verify-downloads').addCustomCommand();
6
+ import addContext from "mochawesome/addContext";
7
+
8
+ const randomUser = (j, username, i) => ({
9
+ id: uuidv4(),
10
+ role: j,
11
+ serialNo: i,
12
+ userName: `${username} ${i}`,
13
+ firstName: `${username} ${i}`,
14
+ lastName: `${username} ${i}`,
15
+ });
16
+
17
+ const generateInitialSessionData = () => {
18
+ const users = [
19
+ randomUser(2, 'student', 1),
20
+ randomUser(2, 'student', 2),
21
+ randomUser(1, 'teacher', 1),
22
+ ];
23
+ const sessionData = { users, itemActivityMap: [] };
24
+ const sessionToken = crypto.randomBytes(4).toString('hex');
25
+ return {
26
+ sessionData,
27
+ sessionToken,
28
+ };
29
+ };
30
+
31
+ Cypress.Commands.add('loginAs', (roleName = 'admin') => {
32
+ if (roleName == 'admin') {
33
+ var username = `${Cypress.env('admin_username')}`;
34
+ var password = `${Cypress.env('admin_password')}`
35
+ };
36
+ cy.logout();
37
+ cy.request({
38
+ method: 'POST',
39
+ url: `${Cypress.env('AUTH_URL')}/login`,
40
+ form: true,
41
+ failOnStatusCode: false,
42
+ body: {
43
+ "username": username,
44
+ "password": password
45
+ },
46
+ }).then((response) => {
47
+ const atoken = response.headers["x-auth-token"];
48
+ const rtoken = response.headers["refresh-token"];
49
+ const firstName = response.body["givenName"];
50
+ const lastName = response.body["familyName"];
51
+ const userId = response.body["id"];
52
+ const userSettings = response.body["userSettings"];
53
+ const { sessionData, sessionToken } = generateInitialSessionData();
54
+ const { users } = sessionData;
55
+ const { itemActivityMap } = sessionData;
56
+ window.localStorage.setItem('ngie_roleId', '3');
57
+ window.localStorage.setItem('ngie_itemActivityMap', JSON.stringify(itemActivityMap));
58
+ window.localStorage.setItem('ngie_userToken', 'true');
59
+ window.localStorage.setItem('ngie_organisationId', 'undefined');
60
+ window.localStorage.setItem('ngie_accessToken', atoken);
61
+ window.localStorage.setItem('ngie_userId', userId);
62
+ window.localStorage.setItem('ngie_firstName', firstName);
63
+ window.localStorage.setItem('ngie_lastName', lastName);
64
+ window.localStorage.setItem('ngie_users', JSON.stringify(users));
65
+ window.localStorage.setItem('ngie_userRole', 'ADMIN');
66
+ window.localStorage.setItem('ngie_sessionId', 'undefined');
67
+ window.localStorage.setItem('ngie_sessionToken', sessionToken);
68
+ window.localStorage.setItem('ngie_refreshToken', rtoken);
69
+ window.localStorage.setItem('ngie_districtId', 'undefined');
70
+ window.localStorage.setItem('user-settings', JSON.stringify(userSettings));
71
+ window.localStorage.setItem('env-config', userSettings["envConfig"]);
72
+ window.localStorage.setItem('defaultItemId', userSettings["defaultItemId"]);
73
+ });
74
+ cy.saveLocalStorage();
75
+ });
76
+
77
+ Cypress.Commands.add('logout', () => {
78
+ const rtoken = window.localStorage.getItem('ngie_refreshToken');
79
+ if (rtoken !== null) {
80
+ const atoken = window.localStorage.getItem('ngie_accessToken');
81
+ cy.request({
82
+ headers: {
83
+ Authorization: `Bearer ${atoken}`,
84
+ 'content-type': 'application/json',
85
+ },
86
+ method: 'POST',
87
+ url: `${Cypress.env('AUTH_URL')}/destroy/refresh-token`,
88
+ form: true,
89
+ failOnStatusCode: false,
90
+ body: {
91
+ "token": `${rtoken}`
92
+ },
93
+ });
94
+ };
95
+ const atoken = window.localStorage.getItem('ngie_accessToken');
96
+ if (atoken !== null) {
97
+ cy.clearLocalStorage();
98
+ cy.clearCookies();
99
+ };
100
+ });
101
+
102
+ Cypress.Commands.add('setGraphqlWait', () => {
103
+ cy.intercept({
104
+ method: 'POST',
105
+ url: `${Cypress.env('GRAPHQL_URL')}`,
106
+ }).as('graphql');
107
+ });
108
+
109
+ Cypress.Commands.add('pageLoadWait', (operationName = null) => {
110
+ if (operationName == null) {
111
+ cy.wait('@graphql');
112
+ } else {
113
+ cy.wait(`@${operationName}`);
114
+ }
115
+ cy.get('.MuiCircularProgress-svg')
116
+ .should('not.be.visible');
117
+ });
118
+
119
+ Cypress.Commands.add('interceptGraphql', (operationName) => {
120
+ cy.intercept('POST', /graphql/, (req) => {
121
+ if (req.body.hasOwnProperty('operationName') && req.body.operationName === operationName) {
122
+ req.alias = `${operationName}`;
123
+ }
124
+ });
125
+ });
126
+
127
+ Cypress.Commands.add('fill', { prevSubject: 'element' }, ($subj, text) => {
128
+ $subj.val(text);
129
+ return cy.wrap($subj).type('{enter}');
130
+ });
131
+
132
+ Cypress.Commands.add('addContext', (context) => {
133
+ cy.once('test:after:run', (test) => addContext({ test }, context));
134
+ });
135
+
136
+ Cypress.Commands.add('barsPreLoaderWait', () => {
137
+ cy.get('[id="question-item-instruction-loader"]')
138
+ .find('img')
139
+ .should('not.be.visible');
140
+ });
@@ -0,0 +1,14 @@
1
+ import './commands'
2
+ import './helpers/localStorage';
3
+ import 'cypress-mochawesome-reporter/register';
4
+ import 'cypress-axe';
5
+ import './helpers/cypressUtilities';
6
+ import './helpers/accessibility';
7
+ import './helpers/selectText';
8
+
9
+ Cypress.on('uncaught:exception', () => {
10
+ return false
11
+ });
12
+
13
+ const registerCypressGrep = require('@cypress/grep')
14
+ registerCypressGrep()
@@ -0,0 +1,19 @@
1
+ function abortEarly() {
2
+ if (this.currentTest.state === 'failed') {
3
+ cy.task('shouldSkip', true);
4
+ console.log(this)
5
+ }
6
+ cy.task('shouldSkip').then(value => {
7
+ if (value) this.skip();
8
+ });
9
+ };
10
+
11
+ function abortEarlySetup() {
12
+ before(() => {
13
+ cy.task('resetShouldSkipFlag')
14
+ });
15
+ beforeEach(abortEarly);
16
+ afterEach(abortEarly);
17
+ };
18
+
19
+ export default abortEarlySetup;
@@ -0,0 +1,34 @@
1
+ import * as config from '../../fixtures/accessibilityConfig.json';
2
+
3
+ function terminalLog(violations) {
4
+ const violationData = violations.map(
5
+ ({ id, impact, description, nodes }) => ({
6
+ elements: nodes.length,
7
+ id,
8
+ description,
9
+ impact,
10
+ })
11
+ );
12
+ violationData.forEach((violation) => {
13
+ cy.addContext(JSON.stringify(violation))
14
+ });
15
+ return null;
16
+ };
17
+
18
+ function checkAccessibility(cySelector = null) {
19
+ cy.wait(1000);
20
+ cy.injectAxe()
21
+ .then(() => {
22
+ if (cySelector === null) {
23
+ return cy.checkA11y(null, config, terminalLog);
24
+ } else {
25
+ cySelector.then(($element) => {
26
+ return cy.checkA11y($element.selector, config, terminalLog);
27
+ });
28
+ };
29
+ });
30
+ };
31
+
32
+ Cypress.Commands.add('checkAccessibility', (cySelector = null) => {
33
+ return checkAccessibility(cySelector);
34
+ });
@@ -0,0 +1,64 @@
1
+ import { uploadResponsePage } from "../../pages"
2
+ import { commonComponents } from "../../pages/components";
3
+
4
+ Cypress.Commands.add('verifyCSS', { prevSubject: true }, (subject, color, fontSize, fontWeight) => {
5
+ cy.wrap(subject)
6
+ .should('have.css', 'color', color)
7
+ .and('have.css', 'font-size', fontSize)
8
+ .and('have.css', 'font-weight', fontWeight);
9
+ return cy.wrap(subject);
10
+ });
11
+
12
+ Cypress.Commands.add('verifyTooltip', { prevSubject: true }, (subject, tooltipText, parameters) => {
13
+ cy.wrap(subject)
14
+ .trigger('mouseover', parameters);
15
+ commonComponents.tooltipText()
16
+ .should('have.text', tooltipText)
17
+ .and('be.visible');
18
+ cy.wrap(subject)
19
+ .trigger('mouseout', parameters);
20
+ commonComponents.tooltipText()
21
+ .should('not.exist');
22
+ });
23
+
24
+ Cypress.Commands.add('verifyInnerText', { prevSubject: true }, (subject, innerText) => {
25
+ cy.wrap(subject)
26
+ .should(($element) => {
27
+ expect($element.get(0).innerText).to.deep.eq(innerText);
28
+ });
29
+ return cy.wrap(subject);
30
+ });
31
+
32
+ Cypress.Commands.add('verifyPseudoClassBeforeProperty', { prevSubject: true }, (subject, property, value) => {
33
+ cy.wrap(subject)
34
+ .then(($element) => {
35
+ const win = $element[0].ownerDocument.defaultView
36
+ const CSSStyleDeclaration = win.getComputedStyle($element[0], 'before')
37
+ const CSSStyleDeclarationValue = CSSStyleDeclaration.getPropertyValue(property)
38
+ expect(CSSStyleDeclarationValue).to.deep.eq(value);
39
+ });
40
+ return cy.wrap(subject);
41
+ });
42
+
43
+ Cypress.Commands.add('verifyUploadFilePreviewDownload', (fileName) => {
44
+ cy.window().document().then(function (doc) {
45
+ doc.addEventListener('click', () => {
46
+ setTimeout(function () { doc.location.reload() }, 5000);
47
+ });
48
+ uploadResponsePage.uploadedFileWrapper()
49
+ .eq(0)
50
+ .within(() => {
51
+ uploadResponsePage.uploadedFileLink()
52
+ .click();
53
+ });
54
+ return cy.verifyDownload(fileName);
55
+ });
56
+ });
57
+
58
+ Cypress.Commands.add('verifyInnerHTML', { prevSubject: true }, (subject, innerHTML) => {
59
+ cy.wrap(subject)
60
+ .then(($element) => {
61
+ expect($element.get(0).innerHTML).to.deep.eq(innerHTML);
62
+ });
63
+ return cy.wrap(subject);
64
+ });
@@ -0,0 +1,13 @@
1
+ const LOCAL_STORAGE_MEMORY = {};
2
+
3
+ Cypress.Commands.add('saveLocalStorage', () => {
4
+ Object.keys(localStorage).forEach((key) => {
5
+ LOCAL_STORAGE_MEMORY[key] = localStorage[key];
6
+ });
7
+ });
8
+
9
+ Cypress.Commands.add('restoreLocalStorage', () => {
10
+ Object.keys(LOCAL_STORAGE_MEMORY).forEach((key) => {
11
+ localStorage.setItem(key, LOCAL_STORAGE_MEMORY[key]);
12
+ });
13
+ });