From 7dfbc4878329d92c45fb887d47c98d797afae890 Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Wed, 25 Mar 2026 19:00:41 +0000 Subject: [PATCH 1/4] remove --- spec/helper.js | 2 - spec/support/CurrentSpecReporter.js | 66 ----------------------------- 2 files changed, 68 deletions(-) diff --git a/spec/helper.js b/spec/helper.js index 032bdd1dcb..2f28b463f9 100644 --- a/spec/helper.js +++ b/spec/helper.js @@ -25,8 +25,6 @@ if (dns.setDefaultResultOrder) { jasmine.DEFAULT_TIMEOUT_INTERVAL = process.env.PARSE_SERVER_TEST_TIMEOUT || 10000; jasmine.getEnv().addReporter(new CurrentSpecReporter()); jasmine.getEnv().addReporter(new SpecReporter()); -global.retryFlakyTests(); - global.on_db = (db, callback, elseCallback) => { if (process.env.PARSE_SERVER_TEST_DB == db) { return callback(); diff --git a/spec/support/CurrentSpecReporter.js b/spec/support/CurrentSpecReporter.js index e296d42503..3d38d216e6 100755 --- a/spec/support/CurrentSpecReporter.js +++ b/spec/support/CurrentSpecReporter.js @@ -4,21 +4,10 @@ const { performance } = require('perf_hooks'); global.currentSpec = null; -/** - * Names of tests that fail randomly and are considered flaky. These tests will be retried - * a number of times to reduce the chance of false negatives. The test name must be the same - * as the one displayed in the CI log test output. - */ -const flakyTests = []; - /** The minimum execution time in seconds for a test to be considered slow. */ const slowTestLimit = 2; -/** The number of times to retry a flaky test. */ -const retries = 5; - const timerMap = {}; -const retryMap = {}; const duplicates = []; class CurrentSpecReporter { specStarted(spec) { @@ -52,61 +41,6 @@ global.displayTestStats = function() { console.warn('Duplicate spec: ' + spec); }); console.log('\n'); - Object.keys(retryMap).forEach((spec) => { - console.warn(`Flaky test: ${spec} failed ${retryMap[spec]} times`); - }); - console.log('\n'); }; -global.retryFlakyTests = function() { - const originalSpecConstructor = jasmine.Spec; - - jasmine.Spec = function(attrs) { - const spec = new originalSpecConstructor(attrs); - const originalTestFn = spec.queueableFn.fn; - const runOriginalTest = () => { - if (originalTestFn.length == 0) { - // handle async testing - return originalTestFn(); - } else { - // handle done() callback - return new Promise((resolve) => { - originalTestFn(resolve); - }); - } - }; - spec.queueableFn.fn = async function() { - const isFlaky = flakyTests.includes(spec.result.fullName); - const runs = isFlaky ? retries : 1; - let exceptionCaught; - let returnValue; - - for (let i = 0; i < runs; ++i) { - spec.result.failedExpectations = []; - returnValue = undefined; - exceptionCaught = undefined; - try { - returnValue = await runOriginalTest(); - } catch (exception) { - exceptionCaught = exception; - } - const failed = !spec.markedPending && - (exceptionCaught || spec.result.failedExpectations.length != 0); - if (!failed) { - break; - } - if (isFlaky) { - retryMap[spec.result.fullName] = (retryMap[spec.result.fullName] || 0) + 1; - await global.afterEachFn(); - } - } - if (exceptionCaught) { - throw exceptionCaught; - } - return returnValue; - }; - return spec; - }; -} - module.exports = CurrentSpecReporter; From 58831cc43aa67708598b2ede402f4fffcd2da6cc Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Wed, 25 Mar 2026 19:29:17 +0000 Subject: [PATCH 2/4] fix --- spec/helper.js | 1 + spec/support/CurrentSpecReporter.js | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/spec/helper.js b/spec/helper.js index 2f28b463f9..fdfb9786c5 100644 --- a/spec/helper.js +++ b/spec/helper.js @@ -25,6 +25,7 @@ if (dns.setDefaultResultOrder) { jasmine.DEFAULT_TIMEOUT_INTERVAL = process.env.PARSE_SERVER_TEST_TIMEOUT || 10000; jasmine.getEnv().addReporter(new CurrentSpecReporter()); jasmine.getEnv().addReporter(new SpecReporter()); +global.normalizeAsyncTests(); global.on_db = (db, callback, elseCallback) => { if (process.env.PARSE_SERVER_TEST_DB == db) { return callback(); diff --git a/spec/support/CurrentSpecReporter.js b/spec/support/CurrentSpecReporter.js index 3d38d216e6..d1a7d8dad2 100755 --- a/spec/support/CurrentSpecReporter.js +++ b/spec/support/CurrentSpecReporter.js @@ -43,4 +43,27 @@ global.displayTestStats = function() { console.log('\n'); }; +/** + * Wraps test functions that use both `async` and a `done` callback, which Jasmine + * does not support. This converts `async (done) => { ... }` to a promise-based + * function so Jasmine does not throw: + * "An asynchronous before/it/after function was defined with the async keyword + * but also took a done callback." + */ +global.normalizeAsyncTests = function() { + const originalSpecConstructor = jasmine.Spec; + jasmine.Spec = function(attrs) { + const spec = new originalSpecConstructor(attrs); + const originalTestFn = spec.queueableFn.fn; + if (originalTestFn.length > 0) { + spec.queueableFn.fn = function() { + return new Promise((resolve) => { + originalTestFn(resolve); + }); + }; + } + return spec; + }; +}; + module.exports = CurrentSpecReporter; From c72eaa49af35a4ebf289503d11175dc84ed565ca Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Wed, 25 Mar 2026 20:26:50 +0000 Subject: [PATCH 3/4] fix jasmine 5 wrappers --- spec/support/CurrentSpecReporter.js | 43 +++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/spec/support/CurrentSpecReporter.js b/spec/support/CurrentSpecReporter.js index d1a7d8dad2..e40b293863 100755 --- a/spec/support/CurrentSpecReporter.js +++ b/spec/support/CurrentSpecReporter.js @@ -44,26 +44,53 @@ global.displayTestStats = function() { }; /** - * Wraps test functions that use both `async` and a `done` callback, which Jasmine + * Wraps test functions that use both `async` and a `done` callback, which Jasmine 5 * does not support. This converts `async (done) => { ... }` to a promise-based * function so Jasmine does not throw: * "An asynchronous before/it/after function was defined with the async keyword * but also took a done callback." */ global.normalizeAsyncTests = function() { - const originalSpecConstructor = jasmine.Spec; - jasmine.Spec = function(attrs) { - const spec = new originalSpecConstructor(attrs); - const originalTestFn = spec.queueableFn.fn; - if (originalTestFn.length > 0) { - spec.queueableFn.fn = function() { + function wrapDoneCallback(fn) { + if (fn.length > 0) { + return function() { return new Promise((resolve) => { - originalTestFn(resolve); + fn.call(this, resolve); }); }; } + return fn; + } + + // Wrap it() specs + const originalSpecConstructor = jasmine.Spec; + jasmine.Spec = function(attrs) { + const spec = new originalSpecConstructor(attrs); + spec.queueableFn.fn = wrapDoneCallback(spec.queueableFn.fn); return spec; }; + + // Wrap beforeEach/afterEach/beforeAll/afterAll + const originalBeforeEach = jasmine.Suite.prototype.beforeEach; + jasmine.Suite.prototype.beforeEach = function(fn) { + fn.fn = wrapDoneCallback(fn.fn); + return originalBeforeEach.call(this, fn); + }; + const originalAfterEach = jasmine.Suite.prototype.afterEach; + jasmine.Suite.prototype.afterEach = function(fn) { + fn.fn = wrapDoneCallback(fn.fn); + return originalAfterEach.call(this, fn); + }; + const originalBeforeAll = jasmine.Suite.prototype.beforeAll; + jasmine.Suite.prototype.beforeAll = function(fn) { + fn.fn = wrapDoneCallback(fn.fn); + return originalBeforeAll.call(this, fn); + }; + const originalAfterAll = jasmine.Suite.prototype.afterAll; + jasmine.Suite.prototype.afterAll = function(fn) { + fn.fn = wrapDoneCallback(fn.fn); + return originalAfterAll.call(this, fn); + }; }; module.exports = CurrentSpecReporter; From b80a15fbfadbd8eada4687425389d650b0b44cab Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Thu, 26 Mar 2026 00:04:23 +0000 Subject: [PATCH 4/4] Update CurrentSpecReporter.js --- spec/support/CurrentSpecReporter.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/spec/support/CurrentSpecReporter.js b/spec/support/CurrentSpecReporter.js index e40b293863..1638b78a77 100755 --- a/spec/support/CurrentSpecReporter.js +++ b/spec/support/CurrentSpecReporter.js @@ -44,11 +44,19 @@ global.displayTestStats = function() { }; /** - * Wraps test functions that use both `async` and a `done` callback, which Jasmine 5 - * does not support. This converts `async (done) => { ... }` to a promise-based - * function so Jasmine does not throw: + * Transitional compatibility shim for Jasmine 5. + * + * Jasmine 5 throws when a test or hook function uses both `async` and a `done` callback: * "An asynchronous before/it/after function was defined with the async keyword * but also took a done callback." + * + * Many existing tests use `async (done) => { ... done(); }`. This wrapper converts + * those to promise-based functions by intercepting the `done` callback and resolving + * a promise instead, so Jasmine sees a plain async function. + * + * To remove this shim, convert each file below so that tests and hooks use plain + * `async () => {}` without a `done` parameter, then remove the file from this list. + * Once the list is empty, delete this function and its call in `helper.js`. */ global.normalizeAsyncTests = function() { function wrapDoneCallback(fn) {