Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
/* globals Promise */
import RSVP from 'rsvp';
import hasEmberVersion from './has-ember-version';
export class _Promise extends RSVP.Promise {}
const ORIGINAL_RSVP_ASYNC: Function = RSVP.configure('async');
/*
Long ago in a galaxy far far away, Ember forced RSVP.Promise to "resolve" on the Ember.run loop.
At the time, this was meant to help ease pain with folks receiving the dreaded "auto-run" assertion
during their tests, and to help ensure that promise resolution was coelesced to avoid "thrashing"
of the DOM. Unfortunately, the result of this configuration is that code like the following behaves
differently if using native `Promise` vs `RSVP.Promise`:
```js
console.log('first');
Ember.run(() => Promise.resolve().then(() => console.log('second')));
console.log('third');
When Promise
is the native promise that will log 'first', 'third', 'second'
, but when Promise
is an RSVP.Promise
that will log 'first', 'second', 'third'
. The fact that RSVP.Promise
s can
be truthy. This is due to the fact that Ember has configured `RSVP` to resolve all promises in the run
loop. What that means practically is this:
1. all checks within `waitUntil` (used by `settled()` internally) are completed and we are "settled"
2. `waitUntil` resolves the promise that it returned (to signify that the world is "settled")
3. resolving the promise (since it is an `RSVP.Promise` and Ember has configured RSVP.Promise) creates
a new Ember.run loop in order to resolve
4. the presence of that new run loop means that we are no longer "settled"
5. `isSettled()` returns false ðŸ˜ðŸ˜ðŸ˜ðŸ˜ðŸ˜ðŸ˜ðŸ˜ðŸ˜ðŸ˜
This custom `RSVP.configure('async`, ...)` below provides a way to prevent the promises that are returned
from `settled` from causing this "loop" and instead "just use normal Promise semantics".
😩😫🙀
*/
RSVP.configure('async', (callback: any, promise: any) => {
if (promise instanceof _Promise) {
// @ts-ignore - avoid erroring about useless `Promise !== RSVP.Promise` comparison
// (this handles when folks have polyfilled via Promise = Ember.RSVP.Promise)
if (typeof Promise !== 'undefined' && Promise !== RSVP.Promise) {
// use real native promise semantics whenever possible
Promise.resolve().then(() => callback(promise));
} else {
// fallback to using RSVP's natural `asap` (**not** the fake
// one configured by Ember...)
RSVP.asap(callback, promise);
}
} else {
// fall back to the normal Ember behavior
ORIGINAL_RSVP_ASYNC(callback, promise);
}
});
QUnit.begin(() => {
RSVP.configure('onerror', reason => {
// only print error messages if they're exceptions;
// otherwise, let a future turn of the event loop
// handle the error.
if (reason && reason instanceof Error) {
throw reason;
}
});
// Prevent all tests involving serialization to require a container
DS.JSONSerializer.reopen({
transformFor(attributeType) {
return this._super(attributeType, true) || transforms[attributeType];
}
});
});
QUnit.begin(() => {
RSVP.configure('onerror', reason => {
// only print error messages if they're exceptions;
// otherwise, let a future turn of the event loop
// handle the error.
if (reason && reason instanceof Error) {
throw reason;
}
});
// Prevent all tests involving serialization to require a container
// TODO kill the need for this
DS.JSONSerializer.reopen({
transformFor(attributeType) {
return this._super(attributeType, true) || transforms[attributeType];
},
});
});
session.userColorSchemeId =
parseInt(setupData.userColorSchemeId, 10) || null;
session.userDarkSchemeId = parseInt(setupData.userDarkSchemeId, 10) || -1;
let iconList = setupData.svgIconList;
if (isDevelopment() && iconList) {
setIconList(
typeof iconList === "string" ? JSON.parse(iconList) : iconList
);
}
if (setupData.s3BaseUrl) {
setupS3CDN(setupData.s3BaseUrl, setupData.s3Cdn);
}
RSVP.configure("onerror", function (e) {
// Ignore TransitionAborted exceptions that bubble up
if (e && e.message === "TransitionAborted") {
return;
}
if (!isProduction()) {
/* eslint-disable no-console */
if (e) {
if (e.message || e.stack) {
console.log(e.message);
console.log(e.stack);
} else {
console.log("Uncaught promise: ", e);
}
} else {
console.log("A promise failed but was not caught.");
export function _setupPromiseListeners() {
if (!hasEmberVersion(1, 7)) {
originalAsync = RSVP.configure('async');
RSVP.configure('async', function(callback, promise) {
run.backburner.schedule('actions', () => {
callback(promise);
});
});
}
}
export function _teardownPromiseListeners() {
if (!hasEmberVersion(1, 7)) {
RSVP.configure('async', originalAsync);
}
}
beforeEach: function() {
configure('async', customAsync);
bb.begin();
if (options.setup) {
options.setup.apply(this, arguments);
}
},
afterEach: function() {
import * as RSVP from 'rsvp';
import { backburner, _rsvpErrorQueue } from '@ember/runloop';
import { getDispatchOverride } from '@ember/-internals/error-handling';
import { assert } from '@ember/debug';
RSVP.configure('async', (callback, promise) => {
backburner.schedule('actions', null, callback, promise);
});
RSVP.configure('after', cb => {
backburner.schedule(_rsvpErrorQueue, null, cb);
});
RSVP.on('error', onerrorDefault);
export function onerrorDefault(reason) {
let error = errorFor(reason);
if (error) {
let overrideDispatch = getDispatchOverride();
if (overrideDispatch) {
overrideDispatch(error);
} else {
import * as RSVP from 'rsvp';
import { backburner, _rsvpErrorQueue } from '@ember/runloop';
import { getDispatchOverride } from '@ember/-internals/error-handling';
import { assert } from '@ember/debug';
RSVP.configure('async', (callback, promise) => {
backburner.schedule('actions', null, callback, promise);
});
RSVP.configure('after', cb => {
backburner.schedule(_rsvpErrorQueue, null, cb);
});
RSVP.on('error', onerrorDefault);
export function onerrorDefault(reason) {
let error = errorFor(reason);
if (error) {
let overrideDispatch = getDispatchOverride();
if (overrideDispatch) {
overrideDispatch(error);
} else {
throw error;
}
}
}