Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
2 changes: 1 addition & 1 deletion apps/repl/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
"ember-load-initializers": "^3.0.1",
"ember-page-title": "^9.0.3",
"ember-qunit": "^9.0.4",
"ember-source": "7.3.0-alpha.2",
"ember-source": "file:ember-source-7.3.0-alpha.1.all-optimizations+c09efdc8.tgz",
"ember-template-lint": "^7.9.3",
"eslint": "^9.39.1",
"execa": "^9.6.1",
Expand Down
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,14 @@
"kolay>ember-repl": "^8.0.0",
"side-channel": "npm:@nolyfill/side-channel@^1",
"string.prototype.matchall": "npm:@nolyfill/string.prototype.matchall@^1",
"string.prototype.trimend": "npm:@nolyfill/string.prototype.trimend@^1"
"string.prototype.trimend": "npm:@nolyfill/string.prototype.trimend@^1",
"ember-source": "file:./apps/repl/ember-source-7.3.0-alpha.1.all-optimizations+c09efdc8.tgz"
},
"patchedDependencies": {
"browserslist-generator": "patches/browserslist-generator.patch"
"browserslist-generator": "patches/browserslist-generator.patch",
"ember-qunit@9.0.4": "patches/ember-qunit@9.0.4.patch",
"@ember/test-helpers@5.4.1": "patches/@ember__test-helpers@5.4.1.patch",
"@ember/test-waiters@4.1.2": "patches/@ember__test-waiters@4.1.2.patch"
},
"_ember-repl": "workspace:*",
"_repl-sdk": "workspace:*"
Expand Down
127 changes: 127 additions & 0 deletions patches/@ember__test-helpers@5.4.1.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
diff --git a/dist/-internal/debug-info.js b/dist/-internal/debug-info.js
index 45733a399fc957c2b01109ce9fb37172dfd7d721..ae723167fdbd88e189c47edb9d9a0a3c9d69e5d5 100644
--- a/dist/-internal/debug-info.js
+++ b/dist/-internal/debug-info.js
@@ -1,4 +1,3 @@
-import { _backburner } from '@ember/runloop';
import { debugInfoHelpers } from './debug-info-helpers.js';
import { getPendingWaiterState } from '@ember/test-waiters';

@@ -22,7 +21,7 @@ const SCHEDULED_AUTORUN = 'Scheduled autorun';
* @returns {boolean} True if `getDebugInfo` is present in backburner, otherwise false.
*/
function backburnerDebugInfoAvailable() {
- return typeof _backburner.getDebugInfo === 'function';
+ return false;
}

/**
@@ -33,7 +32,7 @@ function backburnerDebugInfoAvailable() {
* @returns {MaybeDebugInfo | null} Backburner debugInfo or, if the getDebugInfo method is not present, null
*/
function getDebugInfo() {
- return _backburner.DEBUG === true && backburnerDebugInfoAvailable() ? _backburner.getDebugInfo() : null;
+ return null;
}

/**
diff --git a/dist/setup-context-BSrEM03X.js b/dist/setup-context-BSrEM03X.js
index 0f688234691707c6ee3a1b0326efdd0edb1ea5cb..f406633b247c60925088b14db67ce6e87f0a93ae 100644
--- a/dist/setup-context-BSrEM03X.js
+++ b/dist/setup-context-BSrEM03X.js
@@ -1,4 +1,5 @@
-import { _backburner, run } from '@ember/runloop';
+import { run } from '@ember/runloop';
+import { _onRenderSettledChange as _emberOnRenderSettledChange, renderSettled as _emberRenderSettled } from '@ember/renderer';
import { set, setProperties, get, getProperties } from '@ember/object';
import { setOwner } from '@ember/application';
import buildOwner from './build-owner.js';
@@ -16,7 +17,23 @@ import { getDeprecationsForContext, getDeprecationsDuringCallbackForContext } fr
import { getWarningsForContext, getWarningsDuringCallbackForContext } from './-internal/warnings.js';
import hasEmberVersion from './has-ember-version.js';
import { runHooks } from './helper-hooks.js';
-import { hasPendingWaiters } from '@ember/test-waiters';
+import { buildWaiter, hasPendingWaiters, waitersSettled } from '@ember/test-waiters';
+
+// Rendering reports its pending/complete edges; bridging them into a
+// test waiter folds rendering into the same settledness protocol as
+// every other async source, so isSettled needs no render clause and a
+// stuck render is named in test-waiter debug output.
+const _emberRenderWaiter = buildWaiter('@ember/test-helpers:render');
+let _emberRenderWaiterToken = null;
+_emberOnRenderSettledChange((pending) => {
+ if (pending) {
+ _emberRenderWaiterToken ??= _emberRenderWaiter.beginAsync();
+ } else if (_emberRenderWaiterToken !== null) {
+ const token = _emberRenderWaiterToken;
+ _emberRenderWaiterToken = null;
+ _emberRenderWaiter.endAsync(token);
+ }
+});
import { TestDebugInfo } from './-internal/debug-info.js';

const CAN_USE_ROUTER_EVENTS = hasEmberVersion(3, 6);
@@ -330,15 +347,16 @@ function _setupAJAXHooks() {
@returns {Object} object with properties for each of the metrics used to determine settledness
*/
function getSettledState() {
- const hasPendingTimers = _backburner.hasTimers();
- const hasRunLoop = Boolean(_backburner.currentInstance);
+ const hasPendingTimers = false;
+ const hasRunLoop = false;
const hasPendingLegacyWaiters = checkWaiters();
const hasPendingTestWaiters = hasPendingWaiters();
const pendingRequestCount = pendingRequests();
const hasPendingRequests = pendingRequestCount > 0;
// TODO: Ideally we'd have a function in Ember itself that can synchronously identify whether
// or not there are any pending render operations, but this will have to suffice for now
- const isRenderPending = !!hasRunLoop;
+ // counted via the render waiter above; a second clause would double-count
+ const isRenderPending = false;
return {
hasPendingTimers,
hasRunLoop,
@@ -390,10 +408,31 @@ function isSettled() {
@public
@returns {Promise<void>} resolves when settled
*/
-function settled() {
- return waitUntil(isSettled, {
- timeout: Infinity
- }).then(() => {});
+async function settled() {
+ // Settledness is awaited, not polled: rendering resolves
+ // renderSettled() when it completes, waiters resolve waitersSettled()
+ // on the endAsync that empties the last one. The fallback tick covers
+ // only sources that cannot announce completion (pull-only Waiter
+ // implementations, legacy waiters, request counters).
+ //
+ // Quiet is confirmed FROM A MACROTASK: already-queued task sources
+ // (worker messages, zero-delay timers) may register waiters or dirty
+ // state, and a microtask-context observation would win the race
+ // against them and settle early. And the loop re-checks, because
+ // finishing pending work can start more of it.
+ for (;;) {
+ // 50ms, not 10: the fallback has to LOSE to a frame-paced render
+ // tick, or it decides the race and costs an extra pass (measured
+ // 30 of 117 iterations at 10ms; 1 of 92 at 50ms).
+ await Promise.race([
+ Promise.all([_emberRenderSettled(), waitersSettled()]),
+ new Promise(resolve => setTimeout(resolve, 50)),
+ ]);
+ await new Promise(resolve => setTimeout(resolve, 0));
+ if (isSettled()) {
+ return;
+ }
+ }
}

const cachedOnerror = new Map();
@@ -777,7 +816,6 @@ function setupContext(base, options = {}) {
setContext(context);
const testMetadata = getTestMetadata(context);
testMetadata.setupTypes.push('setupContext');
- _backburner.DEBUG = true;
_prepareOnerror(context);
return Promise.resolve().then(() => {
const application = getApplication();
66 changes: 66 additions & 0 deletions patches/@ember__test-waiters@4.1.2.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
diff --git a/dist/index.js b/dist/index.js
index a661111916b73fd2e7d7c8b3574737ebd35ee098..9a10991584651a89c2c594eaf58348a715beb55d 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -105,6 +105,26 @@ function hasPendingWaiters() {
return state.pending > 0;
}

+// A promise carrying its own resolver, so pending collections hold
+// nothing but promises.
+function _resolvablePromise() {
+ let resolve;
+ const promise = new Promise(r => (resolve = r));
+ promise.resolve = resolve;
+ return promise;
+}
+
+// Compose waiter completion from the operations' own promises.
+const NEVER = new Promise(() => {});
+function waitersSettled() {
+ const settled = [];
+ for (const waiter of getWaiters()) {
+ if (typeof waiter.settled === 'function') settled.push(waiter.settled());
+ else if (!waiter.waitUntil()) return NEVER;
+ }
+ return Promise.all(settled);
+}
+
const WAITER_NAME_PATTERN = /^[^:]*:?.*/;
let WAITER_NAMES = macroCondition(isDevelopingApp()) ? new Set() : undefined;
function _resetWaiterNames() {
@@ -138,6 +158,7 @@ class TestWaiterImpl {
},
label
});
+ (this.pendingPromises ??= new Map()).set(token, _resolvablePromise());
return token;
}
endAsync(token) {
@@ -151,10 +172,19 @@ class TestWaiterImpl {
// Mark when a waiter operation has completed so we can distinguish
// whether endAsync is being called before a prior beginAsync call above.
this._getCompletedOperations(token).set(token, true);
+ const pending = this.pendingPromises?.get(token);
+ if (pending !== undefined) {
+ this.pendingPromises.delete(token);
+ pending.resolve();
+ }
}
waitUntil() {
return this.items.size === 0;
}
+ settled() {
+ if (this.pendingPromises === undefined) return Promise.resolve();
+ return Promise.all(this.pendingPromises.values());
+ }
debugInfo() {
const result = [];
this.items.forEach(value => {
@@ -445,5 +475,5 @@ async function waitForFetch(fetchPromise) {
});
}

-export { _reset, _resetWaiterNames, buildWaiter, getPendingWaiterState, getWaiters, hasPendingWaiters, register, unregister, waitFor, waitForFetch, waitForPromise };
+export { _reset, _resetWaiterNames, buildWaiter, getPendingWaiterState, getWaiters, hasPendingWaiters, register, unregister, waitFor, waitForFetch, waitForPromise, waitersSettled };
//# sourceMappingURL=index.js.map
20 changes: 20 additions & 0 deletions patches/ember-qunit@9.0.4.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
diff --git a/dist/index.js b/dist/index.js
index 6f1b3ebc90b6e359554e890c89e313cf7943be8f..a8c61a735388155100a25b386408db37d73d0a8d 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -4,7 +4,6 @@ import { setAdapter } from 'ember-testing/lib/test/adapter';
import Adapter from './adapter.js';
export { nonTestDoneCallback } from './adapter.js';
import './qunit-configuration.js';
-import { _backburner } from '@ember/runloop';
import { getTestMetadata, setupContext, teardownContext, setupRenderingContext, setupApplicationContext, validateErrorHandler, resetOnerror } from '@ember/test-helpers';
import * as QUnit from 'qunit';
import { installTestNotIsolatedHook } from './test-isolation-validation.js';
@@ -141,7 +140,6 @@ function setupResetOnerror() {
}
function setupTestIsolationValidation(delay) {
waitForSettled = false;
- _backburner.DEBUG = true;
QUnit.on('testStart', () => installTestNotIsolatedHook(delay));
}

Loading
Loading