-
Notifications
You must be signed in to change notification settings - Fork 3.3k
/
Copy pathmocha+8.0.1.dev.patch
85 lines (85 loc) · 5.02 KB
/
mocha+8.0.1.dev.patch
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
diff --git a/node_modules/mocha/assets/growl/error.png b/node_modules/mocha/assets/growl/error.png
deleted file mode 100644
index a07a1ba..0000000
Binary files a/node_modules/mocha/assets/growl/error.png and /dev/null differ
diff --git a/node_modules/mocha/assets/growl/ok.png b/node_modules/mocha/assets/growl/ok.png
deleted file mode 100644
index b3623a5..0000000
Binary files a/node_modules/mocha/assets/growl/ok.png and /dev/null differ
diff --git a/node_modules/mocha/lib/runner.js b/node_modules/mocha/lib/runner.js
index 22e7bb9..9143aa3 100644
--- a/node_modules/mocha/lib/runner.js
+++ b/node_modules/mocha/lib/runner.js
@@ -758,9 +758,42 @@ Runner.prototype.runTests = function(suite, fn) {
}
self.emit(constants.EVENT_TEST_END, test);
return self.hookUp(HOOK_TYPE_AFTER_EACH, next);
- } else if (err) {
+ } else if (err || test.hasAttemptPassed) {
+ if(test.hasAttemptPassed){
+ // Currently, to get passing attempts to rerun in mocha,
+ // we signal to mocha that we MIGHT need to retry a passed test attempt.
+ // If the test is run and there are no errors present, we assume a
+ // passed test attempt(set in ./driver/src/cypress/runner.ts)
+ test.state = STATE_PASSED
+ } else {
+ // Otherwise, we can assume the test attempt failed as 'err' would have to be present here.
+ test.state = STATE_FAILED
+ }
+ // Evaluate if the test should continue based on 'calculateTestStatus'.
+ // This is a custom method added by Cypress in ./driver/src/cypress/mocha.ts
+ var testStatusInfo = test.calculateTestStatus()
+
+ if(!testStatusInfo.shouldAttemptsContinue){
+ // If the test has met the exit condition, we need to grab the metadata from
+ // 'calculateTestStatus' in order to display and interpret the test outerStatus correctly.
+ test._cypressTestStatusInfo = testStatusInfo
+
+ if(testStatusInfo.attempts > 1) {
+ // If the test has been run AT LEAST twice (i.e. we are retrying), and the exit condition is met,
+ // modify mocha '_retries' to be the max retries made in order to possibly short circuit a suite
+ // if a hook has failed on every attempt (which we may not know at this stage of the test run).
+
+ // We will need the original retries to 'reset' the possible retries
+ // if the test attempt passes and fits the exit condition, BUT an 'afterEach' hook fails.
+ // In this case, we need to know how many retries we can reapply to satisfy the config.
+ test._maxRetries = test._retries
+ test._retries = test._currentRetry
+ }
+ }
+
var retry = test.currentRetry();
- if (retry < test.retries()) {
+ // requeue the test if we have retries and haven't satisfied our retry configuration.
+ if (retry < test.retries() && testStatusInfo.shouldAttemptsContinue) {
var clonedTest = test.clone();
clonedTest.currentRetry(retry + 1);
tests.unshift(clonedTest);
@@ -770,8 +803,25 @@ Runner.prototype.runTests = function(suite, fn) {
// Early return + hook trigger so that it doesn't
// increment the count wrong
return self.hookUp(HOOK_TYPE_AFTER_EACH, next);
- } else {
- self.fail(test, err);
+ } else if(testStatusInfo.outerStatus === STATE_FAILED) {
+ // However, if we have fit the exit condition and the outerStatus of the test is marked as 'failed'.
+
+ // We need to check the state of the last test attempt.
+ // In this case, if the strategy is "detect-flake-but-always-fail",
+ // has an outerStatus of 'failed', but the last test attempt passed, we still want to call the 'fail' hooks on the test, but keep
+ // the test attempt marked as passed.
+
+ // However, since the test might have afterEach/after hooks that mutate the state of the test
+ // (from passed to failed), the hooks might actually affect how many retries are actually run in order to satisfy the config.
+ // In this case, we want to delay failing as long as possible to make sure the test is settled, all attempts are run, and hooks
+ // can no longer retry. For this edge case specifically, the failing of the test in the runner lives in ./driver/src/cypress/runner.ts
+ if(test.state === STATE_FAILED){
+ self.fail(test, err)
+ }
+ } else if (testStatusInfo?.outerStatus === STATE_PASSED){
+ // There is no case where a test can 'pass' and the last test attempt be a failure,
+ // meaning we can assume a 'passed' outerStatus has a final passed test attempt.
+ self.emit(constants.EVENT_TEST_PASS, test);
}
self.emit(constants.EVENT_TEST_END, test);
return self.hookUp(HOOK_TYPE_AFTER_EACH, next);