cypress-voice-plugin 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.js +149 -141
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -15,7 +15,14 @@ if (
15
15
  addStyles();
16
16
  });
17
17
 
18
- Cypress.on("test:after:run", (config, test) => {
18
+ // Used when user navigates away from current spec within the test runner
19
+ // Stops the voice from continuing
20
+ Cypress.on("window:unload", () => {
21
+ const voice = window.speechSynthesis;
22
+ voice.cancel();
23
+ });
24
+
25
+ Cypress.on("test:after:run", (_, test) => {
19
26
  // Additional context of test index
20
27
  // To account for loops where there is one test per describe and suite names may stay
21
28
  // And to account for both specs with multiple suites or only one suite
@@ -26,16 +33,6 @@ if (
26
33
 
27
34
  // Checking the current test index is either equal to the last index of the suite or the test context
28
35
  const currentTestIsLast = lastTestIndex === testNumber;
29
-
30
- // Checks within the document for a failure state
31
- const failed = window.top?.document.querySelector(".runnable-failed");
32
- // Checks within the document for a retried state to determine if retry occurred
33
- const retried = window.top?.document.querySelector(".runnable-retried");
34
- // Checks within the document for a passed state
35
- const passed = window.top?.document.querySelector(".runnable-passed");
36
- // Checks within the document for a skipped state
37
- const skipped = window.top?.document.querySelector(".runnable-pending");
38
-
39
36
  // Rate toggle for speed of spoken text
40
37
  const rate = window.top?.document.querySelector("#rate");
41
38
 
@@ -45,18 +42,26 @@ if (
45
42
  // Volume toggle for volume of spoken text
46
43
  const volume = window.top?.document.querySelector("#volume");
47
44
 
48
- const failedTests = window.top?.document.querySelectorAll(
49
- ".test.runnable-failed"
50
- ).length;
51
- const retriedTests = window.top?.document.querySelectorAll(
52
- ".test.runnable-passed.runnable-retried"
53
- ).length;
54
- const passedTests = window.top?.document.querySelectorAll(
55
- ".test.runnable-passed"
56
- ).length;
57
- const skippedTests = window.top?.document.querySelectorAll(
58
- ".test.runnable-pending"
59
- ).length;
45
+ // Logic involved with waiting for the restart button to appear
46
+ // This signals the Cypress Test Runner has completed it's current run
47
+ function waitForElement(selector, callback) {
48
+ const observer = new MutationObserver((mutations, observer) => {
49
+ const element = window.top?.document.querySelector(selector);
50
+ if (element) {
51
+ observer.disconnect();
52
+ callback(element);
53
+ }
54
+ });
55
+
56
+ observer.observe(window.top?.document.body, {
57
+ childList: true,
58
+ subtree: true,
59
+ });
60
+ }
61
+ // Checks within the document for a failure state
62
+ const failed = window.top?.document.querySelector(".runnable-failed");
63
+ // Checks within the document for a retried state to determine if retry occurred
64
+ const retried = window.top?.document.querySelector(".runnable-retried");
60
65
 
61
66
  // Check test result count for passed, failed, skipped, retried
62
67
  // If count is 1, use singular
@@ -69,7 +74,7 @@ if (
69
74
  // Only return seconds if minutes are less than or equal to 0
70
75
  function specTime() {
71
76
  const specTime = window.top?.document.querySelector(
72
- '[data-cy="spec-duration"]'
77
+ '[data-cy="spec-duration"]',
73
78
  )?.textContent;
74
79
  const specSec = specTime?.slice(-2);
75
80
  const specMin = specTime?.slice(0, 2);
@@ -137,33 +142,42 @@ if (
137
142
  }
138
143
  }
139
144
 
140
- // Checking if retries are set in config
141
- // If so, check the config object for the current retry number, the configured number of retries, and if current test failed
142
- // If return true, do not allow the voice to activate
143
- function checkRetry() {
144
- if (
145
- config.retries > 0 &&
146
- config.retries !== config.currentRetry &&
147
- config.state === "failed"
148
- ) {
149
- return true;
145
+ // Retrieve count of passed, failed, retried, and skipped tests
146
+ function retrieveTestStats() {
147
+ let failedTests = window.top?.document
148
+ .querySelector(".failed")
149
+ .innerText.replace("Failed:\n", "");
150
+
151
+ const retriedTests = window.top?.document.querySelectorAll(
152
+ ".test.runnable-passed.runnable-retried",
153
+ ).length;
154
+
155
+ let passedTests = window.top?.document
156
+ .querySelector(".passed")
157
+ .innerText.replace("Passed:\n", "");
158
+
159
+ let skippedTests = window.top?.document
160
+ .querySelector(".pending")
161
+ .innerText.replace("Pending:\n", "");
162
+
163
+ if (passedTests === "--") {
164
+ passedTests = 0;
150
165
  } else {
151
- return false;
166
+ passedTests = parseInt(passedTests);
152
167
  }
153
- }
154
168
 
155
- // Checking if all tests are skipped in spec file
156
- // If so, announce that all spec tests are skipped
157
- function checkSkipped() {
158
- if (skipped && !failed && !passed) {
159
- return true;
169
+ if (failedTests === "--") {
170
+ failedTests = 0;
160
171
  } else {
161
- return false;
172
+ failedTests = parseInt(failedTests);
173
+ }
174
+
175
+ if (skippedTests === "--") {
176
+ skippedTests = 0;
177
+ } else {
178
+ skippedTests = parseInt(skippedTests);
162
179
  }
163
- }
164
180
 
165
- // Retrieve count of passed, failed, retried, and skipped tests
166
- function retrieveTestStats() {
167
181
  const stats = [
168
182
  `${passedTests - retriedTests}` +
169
183
  pluralizeWord(" test", " tests", `${passedTests - retriedTests}`) +
@@ -183,102 +197,96 @@ if (
183
197
  return `${filteredStats.toString()}`;
184
198
  }
185
199
 
186
- // Checking if the index of current test matches the total length of tests in the spec
187
- // Checking if we are awaiting retries on final spec
188
- if (currentTestIsLast && checkSkipped() === true) {
189
- const message = new SpeechSynthesisUtterance(
190
- "All Spec tests are skipped."
191
- );
192
- message.rate = rate.value;
193
- message.pitch = pitch.value;
194
- message.volume = volume.value;
195
- speechSynthesis.speak(message);
196
- }
197
-
198
- // Before executing speechSynthesis, ensure we don't have any remaining tests to run
199
- // Determine which environment variables were set and speak appropriate message
200
- if (checkRetry() === false && checkSkipped() === false) {
201
- // Announce spec run result and/or total time based on provided environment variable(s)
202
- if (
203
- Cypress.env("voiceResultType") === "simple" &&
204
- !Cypress.env("voiceTime")
205
- ) {
206
- const message = new SpeechSynthesisUtterance(
207
- `Spec ${
208
- failed ? "failed." : retried ? "passed with retries." : "passed."
209
- }`
210
- );
211
- message.rate = rate.value;
212
- message.pitch = pitch.value;
213
- message.volume = volume.value;
214
- speechSynthesis.speak(message);
215
- } else if (
216
- Cypress.env("voiceTime") &&
217
- !(Cypress.env("voiceResultType") === "simple") &&
218
- !(Cypress.env("voiceResultType") === "detailed")
219
- ) {
220
- const message = new SpeechSynthesisUtterance(
221
- "Total time: " + specTime()
222
- );
223
- message.rate = rate.value;
224
- message.pitch = pitch.value;
225
- message.volume = volume.value;
226
- speechSynthesis.speak(message);
227
- } else if (
228
- Cypress.env("voiceResultType") === "detailed" &&
229
- !Cypress.env("voiceTime")
230
- ) {
231
- const message = new SpeechSynthesisUtterance(
232
- `Spec ${
233
- failed
234
- ? "failed: " + retrieveTestStats()
235
- : retried
236
- ? "passed with retries: " + retrieveTestStats()
237
- : "passed: " + retrieveTestStats()
238
- }`
239
- );
240
- message.rate = rate.value;
241
- message.pitch = pitch.value;
242
- message.volume = volume.value;
243
- speechSynthesis.speak(message);
244
- } else if (
245
- Cypress.env("voiceResultType") === "simple" &&
246
- Cypress.env("voiceTime")
247
- ) {
248
- const message = new SpeechSynthesisUtterance(
249
- `Spec ${
250
- failed
251
- ? "failed. Total time: " + specTime()
252
- : retried
253
- ? "passed with retries. Total time: " + specTime()
254
- : "passed. Total time: " + specTime()
255
- }`
256
- );
257
- message.rate = rate.value;
258
- message.pitch = pitch.value;
259
- message.volume = volume.value;
260
- speechSynthesis.speak(message);
261
- } else if (
262
- Cypress.env("voiceResultType") === "detailed" &&
263
- Cypress.env("voiceTime")
264
- ) {
265
- const message = new SpeechSynthesisUtterance(
266
- `Spec ${
267
- failed
268
- ? "failed: " + retrieveTestStats() + " Total time: " + specTime()
269
- : retried
270
- ? "passed with retries: " +
271
- retrieveTestStats() +
272
- ". Total time: " +
273
- specTime()
274
- : "passed: " + retrieveTestStats() + " Total time: " + specTime()
275
- }`
276
- );
277
- message.rate = rate.value;
278
- message.pitch = pitch.value;
279
- message.volume = volume.value;
280
- speechSynthesis.speak(message);
281
- }
200
+ if (currentTestIsLast) {
201
+ waitForElement(".restart", () => {
202
+ // Announce spec run result and/or total time based on provided environment variable(s)
203
+ if (
204
+ Cypress.env("voiceResultType") === "simple" &&
205
+ !Cypress.env("voiceTime")
206
+ ) {
207
+ const message = new SpeechSynthesisUtterance(
208
+ `Spec ${
209
+ failed ? "failed." : retried ? "passed with retries." : "passed."
210
+ }`,
211
+ );
212
+ message.rate = rate.value;
213
+ message.pitch = pitch.value;
214
+ message.volume = volume.value;
215
+ speechSynthesis.speak(message);
216
+ } else if (
217
+ Cypress.env("voiceTime") &&
218
+ !(Cypress.env("voiceResultType") === "simple") &&
219
+ !(Cypress.env("voiceResultType") === "detailed")
220
+ ) {
221
+ const message = new SpeechSynthesisUtterance(
222
+ "Total time: " + specTime(),
223
+ );
224
+ message.rate = rate.value;
225
+ message.pitch = pitch.value;
226
+ message.volume = volume.value;
227
+ speechSynthesis.speak(message);
228
+ } else if (
229
+ Cypress.env("voiceResultType") === "detailed" &&
230
+ !Cypress.env("voiceTime")
231
+ ) {
232
+ const message = new SpeechSynthesisUtterance(
233
+ `Spec ${
234
+ failed
235
+ ? "failed: " + retrieveTestStats()
236
+ : retried
237
+ ? "passed with retries: " + retrieveTestStats()
238
+ : "passed: " + retrieveTestStats()
239
+ }`,
240
+ );
241
+ message.rate = rate.value;
242
+ message.pitch = pitch.value;
243
+ message.volume = volume.value;
244
+ speechSynthesis.speak(message);
245
+ } else if (
246
+ Cypress.env("voiceResultType") === "simple" &&
247
+ Cypress.env("voiceTime")
248
+ ) {
249
+ const message = new SpeechSynthesisUtterance(
250
+ `Spec ${
251
+ failed
252
+ ? "failed. Total time: " + specTime()
253
+ : retried
254
+ ? "passed with retries. Total time: " + specTime()
255
+ : "passed. Total time: " + specTime()
256
+ }`,
257
+ );
258
+ message.rate = rate.value;
259
+ message.pitch = pitch.value;
260
+ message.volume = volume.value;
261
+ speechSynthesis.speak(message);
262
+ } else if (
263
+ Cypress.env("voiceResultType") === "detailed" &&
264
+ Cypress.env("voiceTime")
265
+ ) {
266
+ const message = new SpeechSynthesisUtterance(
267
+ `Spec ${
268
+ failed
269
+ ? "failed: " +
270
+ retrieveTestStats() +
271
+ " Total time: " +
272
+ specTime()
273
+ : retried
274
+ ? "passed with retries: " +
275
+ retrieveTestStats() +
276
+ ". Total time: " +
277
+ specTime()
278
+ : "passed: " +
279
+ retrieveTestStats() +
280
+ " Total time: " +
281
+ specTime()
282
+ }`,
283
+ );
284
+ message.rate = rate.value;
285
+ message.pitch = pitch.value;
286
+ message.volume = volume.value;
287
+ speechSynthesis.speak(message);
288
+ }
289
+ });
282
290
  }
283
291
  });
284
292
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cypress-voice-plugin",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Voice plugin for the Cypress Test Runner",
5
5
  "main": "./index.js",
6
6
  "scripts": {