Skip to content

Commit cd7a54b

Browse files
committed
More robust handling in setup-onerror
Resolves an issue where Ember.onerror could get cached too soon. Fixes #993
1 parent 3d267cd commit cd7a54b

File tree

4 files changed

+91
-23
lines changed

4 files changed

+91
-23
lines changed

addon-test-support/@ember/test-helpers/setup-context.ts

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { setOwner } from '@ember/application';
55

66
import buildOwner, { Owner } from './build-owner';
77
import { _setupAJAXHooks, _teardownAJAXHooks } from './settled';
8+
import { _prepareOnerror } from './setup-onerror';
89
import Ember from 'ember';
910
import { assert } from '@ember/debug';
1011
import global from './global';
@@ -180,6 +181,8 @@ export default function setupContext(
180181

181182
registerDestructor(context, cleanup);
182183

184+
_prepareOnerror(context);
185+
183186
return Promise.resolve()
184187
.then(() => {
185188
let application = getApplication();

addon-test-support/@ember/test-helpers/setup-onerror.ts

+43-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import Ember from 'ember';
2+
import { BaseContext, getContext } from './setup-context';
23

3-
const ORIGINAL_EMBER_ONERROR: (error: Error) => void | undefined = Ember.onerror;
4+
let cachedOnerror: Map<BaseContext, ((error: Error) => void) | undefined> = new Map();
45

56
/**
67
* Sets the `Ember.onerror` function for tests. This value is intended to be reset after
@@ -21,10 +22,24 @@ const ORIGINAL_EMBER_ONERROR: (error: Error) => void | undefined = Ember.onerror
2122
* });
2223
*/
2324
export default function setupOnerror(onError?: (error: Error) => void): void {
25+
let context = getContext();
26+
27+
if (!context) {
28+
throw new Error('Must setup test context before calling setupOnerror');
29+
}
30+
31+
if (!cachedOnerror.has(context)) {
32+
throw new Error(
33+
'_cacheOriginalOnerror must be called before setupOnerror. Normally, this will happen as part of your test harness.'
34+
);
35+
}
36+
2437
if (typeof onError !== 'function') {
25-
onError = ORIGINAL_EMBER_ONERROR;
38+
onError = cachedOnerror.get(context);
2639
}
2740

41+
// @ts-ignore types are incorrect and don't allow undefined.
42+
// See https://github.com/DefinitelyTyped/DefinitelyTyped/pull/51383
2843
Ember.onerror = onError;
2944
}
3045

@@ -42,3 +57,29 @@ export default function setupOnerror(onError?: (error: Error) => void): void {
4257
* })
4358
*/
4459
export const resetOnerror: Function = setupOnerror;
60+
61+
/**
62+
* Caches the current value of Ember.onerror. When `setupOnerror` is called without a value
63+
* or when `resetOnerror` is called the value will be set to what was cached here.
64+
*
65+
* @private
66+
* @param {BaseContext} context the text context
67+
*/
68+
export function _prepareOnerror(context: BaseContext) {
69+
if (cachedOnerror.has(context)) {
70+
throw new Error('_prepareOnerror should only be called once per-context');
71+
}
72+
73+
cachedOnerror.set(context, Ember.onerror);
74+
}
75+
76+
/**
77+
* Removes the cached value of Ember.onerror.
78+
*
79+
* @private
80+
* @param {BaseContext} context the text context
81+
*/
82+
export function _cleanupOnerror(context: BaseContext) {
83+
resetOnerror();
84+
cachedOnerror.delete(context);
85+
}

addon-test-support/@ember/test-helpers/teardown-context.ts

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { TestContext } from './setup-context';
22
import { Promise } from './-utils';
33
import settled from './settled';
4+
import { _cleanupOnerror } from './setup-onerror';
45
import { destroy } from '@ember/destroyable';
56

67
/**
@@ -29,6 +30,8 @@ export default function teardownContext(
2930

3031
return Promise.resolve()
3132
.then(() => {
33+
_cleanupOnerror(context);
34+
3235
destroy(context);
3336
})
3437
.finally(() => {
+42-21
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,67 @@
11
import Ember from 'ember';
22
import { module, test } from 'qunit';
33
import hasEmberVersion from '@ember/test-helpers/has-ember-version';
4+
import { setupContext, teardownContext } from '@ember/test-helpers';
45
import { setupOnerror, resetOnerror } from '@ember/test-helpers';
56

67
module('setupOnerror', function (hooks) {
7-
hooks.afterEach(function () {
8-
resetOnerror();
8+
let context;
9+
10+
hooks.beforeEach(function () {
11+
context = {};
12+
});
13+
14+
hooks.afterEach(async function () {
15+
if (context.owner) {
16+
await teardownContext(context);
17+
}
918
});
1019

1120
if (hasEmberVersion(2, 4)) {
12-
test('Ember.onerror is undefined by default', function (assert) {
13-
assert.expect(1);
21+
module('with context set', function (hooks) {
22+
hooks.beforeEach(async function () {
23+
await setupContext(context);
24+
});
1425

15-
assert.equal(Ember.onerror, undefined);
16-
});
26+
test('Ember.onerror is undefined by default', function (assert) {
27+
assert.expect(1);
1728

18-
test('Ember.onerror is setup correctly', async function (assert) {
19-
assert.expect(2);
29+
assert.equal(Ember.onerror, undefined);
30+
});
2031

21-
let onerror = err => err;
32+
test('Ember.onerror is setup correctly', async function (assert) {
33+
assert.expect(2);
2234

23-
assert.equal(Ember.onerror, undefined);
35+
let onerror = err => err;
2436

25-
setupOnerror(onerror);
37+
assert.equal(Ember.onerror, undefined);
2638

27-
assert.equal(Ember.onerror, onerror);
28-
});
39+
setupOnerror(onerror);
40+
41+
assert.equal(Ember.onerror, onerror);
42+
});
2943

30-
test('Ember.onerror is reset correctly', async function (assert) {
31-
assert.expect(3);
44+
test('Ember.onerror is reset correctly', async function (assert) {
45+
assert.expect(3);
3246

33-
let onerror = err => err;
47+
let onerror = err => err;
3448

35-
assert.equal(Ember.onerror, undefined);
49+
assert.equal(Ember.onerror, undefined);
3650

37-
setupOnerror(onerror);
51+
setupOnerror(onerror);
3852

39-
assert.equal(Ember.onerror, onerror);
53+
assert.equal(Ember.onerror, onerror);
4054

41-
resetOnerror();
55+
resetOnerror();
56+
57+
assert.equal(Ember.onerror, undefined);
58+
});
59+
});
4260

43-
assert.equal(Ember.onerror, undefined);
61+
test('it raises an error without context', function (assert) {
62+
assert.throws(() => {
63+
setupOnerror();
64+
}, /Must setup test context before calling setupOnerror/);
4465
});
4566
}
4667
});

0 commit comments

Comments
 (0)