diff --git a/package/server.js b/package/server.js index 8439af4..d709daa 100644 --- a/package/server.js +++ b/package/server.js @@ -204,7 +204,14 @@ function clientTests() { } // Before Meteor calls the `start` function, app tests will be parsed and loaded by Mocha -function start() { +async function start() { + // Wait for all Meteor.startup() callbacks (including async ones) to complete. + // In Meteor 3.x, async startup callbacks and top-level await can cause the + // startup queue to still be draining when the test driver's start() is called. + // Adding a callback at the end of the queue ensures it runs after all prior + // callbacks have finished. See: https://github.com/Meteor-Community-Packages/meteor-mocha/issues/176 + await new Promise(resolve => Meteor.startup(resolve)); + const args = setArgs(); runnerOptions = args.runnerOptions; coverageOptions = args.coverageOptions; diff --git a/tests/dummy_app/server/async-startup.tests.js b/tests/dummy_app/server/async-startup.tests.js new file mode 100644 index 0000000..04fee7b --- /dev/null +++ b/tests/dummy_app/server/async-startup.tests.js @@ -0,0 +1,21 @@ +/* eslint-env mocha */ +import { Meteor } from 'meteor/meteor'; +import assert from 'assert'; + +// Simulate async startup work (e.g. ensuring MongoDB indices, initializing +// collections). Without the fix in server.js, mocha.run() can fire before +// this callback completes, causing the test below to fail. +let startupCompleted = false; + +Meteor.startup(async () => { + await new Promise(resolve => setTimeout(resolve, 50)); + startupCompleted = true; +}); + +describe('async Meteor.startup()', function () { + it('should complete before tests run', function () { + assert.strictEqual(startupCompleted, true, + 'Async Meteor.startup() callback did not complete before tests ran. ' + + 'See https://github.com/Meteor-Community-Packages/meteor-mocha/issues/176'); + }); +});