Skip to content

Commit eea27af

Browse files
authored
ci: Remove feature to retry flaky tests (#10314)
1 parent 3ff8180 commit eea27af

File tree

2 files changed

+53
-62
lines changed

2 files changed

+53
-62
lines changed

spec/helper.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ if (dns.setDefaultResultOrder) {
2525
jasmine.DEFAULT_TIMEOUT_INTERVAL = process.env.PARSE_SERVER_TEST_TIMEOUT || 10000;
2626
jasmine.getEnv().addReporter(new CurrentSpecReporter());
2727
jasmine.getEnv().addReporter(new SpecReporter());
28-
global.retryFlakyTests();
29-
28+
global.normalizeAsyncTests();
3029
global.on_db = (db, callback, elseCallback) => {
3130
if (process.env.PARSE_SERVER_TEST_DB == db) {
3231
return callback();

spec/support/CurrentSpecReporter.js

Lines changed: 52 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,10 @@ const { performance } = require('perf_hooks');
44

55
global.currentSpec = null;
66

7-
/**
8-
* Names of tests that fail randomly and are considered flaky. These tests will be retried
9-
* a number of times to reduce the chance of false negatives. The test name must be the same
10-
* as the one displayed in the CI log test output.
11-
*/
12-
const flakyTests = [];
13-
147
/** The minimum execution time in seconds for a test to be considered slow. */
158
const slowTestLimit = 2;
169

17-
/** The number of times to retry a flaky test. */
18-
const retries = 5;
19-
2010
const timerMap = {};
21-
const retryMap = {};
2211
const duplicates = [];
2312
class CurrentSpecReporter {
2413
specStarted(spec) {
@@ -52,61 +41,64 @@ global.displayTestStats = function() {
5241
console.warn('Duplicate spec: ' + spec);
5342
});
5443
console.log('\n');
55-
Object.keys(retryMap).forEach((spec) => {
56-
console.warn(`Flaky test: ${spec} failed ${retryMap[spec]} times`);
57-
});
58-
console.log('\n');
5944
};
6045

61-
global.retryFlakyTests = function() {
62-
const originalSpecConstructor = jasmine.Spec;
63-
64-
jasmine.Spec = function(attrs) {
65-
const spec = new originalSpecConstructor(attrs);
66-
const originalTestFn = spec.queueableFn.fn;
67-
const runOriginalTest = () => {
68-
if (originalTestFn.length == 0) {
69-
// handle async testing
70-
return originalTestFn();
71-
} else {
72-
// handle done() callback
46+
/**
47+
* Transitional compatibility shim for Jasmine 5.
48+
*
49+
* Jasmine 5 throws when a test or hook function uses both `async` and a `done` callback:
50+
* "An asynchronous before/it/after function was defined with the async keyword
51+
* but also took a done callback."
52+
*
53+
* Many existing tests use `async (done) => { ... done(); }`. This wrapper converts
54+
* those to promise-based functions by intercepting the `done` callback and resolving
55+
* a promise instead, so Jasmine sees a plain async function.
56+
*
57+
* To remove this shim, convert each file below so that tests and hooks use plain
58+
* `async () => {}` without a `done` parameter, then remove the file from this list.
59+
* Once the list is empty, delete this function and its call in `helper.js`.
60+
*/
61+
global.normalizeAsyncTests = function() {
62+
function wrapDoneCallback(fn) {
63+
if (fn.length > 0) {
64+
return function() {
7365
return new Promise((resolve) => {
74-
originalTestFn(resolve);
66+
fn.call(this, resolve);
7567
});
76-
}
77-
};
78-
spec.queueableFn.fn = async function() {
79-
const isFlaky = flakyTests.includes(spec.result.fullName);
80-
const runs = isFlaky ? retries : 1;
81-
let exceptionCaught;
82-
let returnValue;
68+
};
69+
}
70+
return fn;
71+
}
8372

84-
for (let i = 0; i < runs; ++i) {
85-
spec.result.failedExpectations = [];
86-
returnValue = undefined;
87-
exceptionCaught = undefined;
88-
try {
89-
returnValue = await runOriginalTest();
90-
} catch (exception) {
91-
exceptionCaught = exception;
92-
}
93-
const failed = !spec.markedPending &&
94-
(exceptionCaught || spec.result.failedExpectations.length != 0);
95-
if (!failed) {
96-
break;
97-
}
98-
if (isFlaky) {
99-
retryMap[spec.result.fullName] = (retryMap[spec.result.fullName] || 0) + 1;
100-
await global.afterEachFn();
101-
}
102-
}
103-
if (exceptionCaught) {
104-
throw exceptionCaught;
105-
}
106-
return returnValue;
107-
};
73+
// Wrap it() specs
74+
const originalSpecConstructor = jasmine.Spec;
75+
jasmine.Spec = function(attrs) {
76+
const spec = new originalSpecConstructor(attrs);
77+
spec.queueableFn.fn = wrapDoneCallback(spec.queueableFn.fn);
10878
return spec;
10979
};
110-
}
80+
81+
// Wrap beforeEach/afterEach/beforeAll/afterAll
82+
const originalBeforeEach = jasmine.Suite.prototype.beforeEach;
83+
jasmine.Suite.prototype.beforeEach = function(fn) {
84+
fn.fn = wrapDoneCallback(fn.fn);
85+
return originalBeforeEach.call(this, fn);
86+
};
87+
const originalAfterEach = jasmine.Suite.prototype.afterEach;
88+
jasmine.Suite.prototype.afterEach = function(fn) {
89+
fn.fn = wrapDoneCallback(fn.fn);
90+
return originalAfterEach.call(this, fn);
91+
};
92+
const originalBeforeAll = jasmine.Suite.prototype.beforeAll;
93+
jasmine.Suite.prototype.beforeAll = function(fn) {
94+
fn.fn = wrapDoneCallback(fn.fn);
95+
return originalBeforeAll.call(this, fn);
96+
};
97+
const originalAfterAll = jasmine.Suite.prototype.afterAll;
98+
jasmine.Suite.prototype.afterAll = function(fn) {
99+
fn.fn = wrapDoneCallback(fn.fn);
100+
return originalAfterAll.call(this, fn);
101+
};
102+
};
111103

112104
module.exports = CurrentSpecReporter;

0 commit comments

Comments
 (0)