Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Protect context properties and methods from overwriting #349

Merged
merged 2 commits into from
Mar 26, 2018
Merged
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
53 changes: 34 additions & 19 deletions addon-test-support/@ember/test-helpers/setup-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,31 +167,46 @@ export default function(context, options = {}) {
return buildOwner(getApplication(), getResolver());
})
.then(owner => {
context.owner = owner;
Object.defineProperty(context, 'owner', {
value: owner,
writable: false,
});

context.set = function(key, value) {
let ret = run(function() {
return set(context, key, value);
});
Object.defineProperty(context, 'set', {
value(key, value) {
let ret = run(function() {
return set(context, key, value);
});

return ret;
};
return ret;
},
writable: false,
});

context.setProperties = function(hash) {
let ret = run(function() {
return setProperties(context, hash);
});
Object.defineProperty(context, 'setProperties', {
value(hash) {
let ret = run(function() {
return setProperties(context, hash);
});

return ret;
};
return ret;
},
writable: false,
});

context.get = function(key) {
return get(context, key);
};
Object.defineProperty(context, 'get', {
value(key) {
return get(context, key);
},
writable: false,
});

context.getProperties = function(...args) {
return getProperties(context, args);
};
Object.defineProperty(context, 'getProperties', {
value(...args) {
return getProperties(context, args);
},
writable: false,
});

let resume;
context.resumeTest = function resumeTest() {
Expand Down
36 changes: 21 additions & 15 deletions addon-test-support/@ember/test-helpers/setup-rendering-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,11 +154,14 @@ export default function setupRenderingContext(context) {
// these methods being placed on the context itself will be deprecated in
// a future version (no giant rush) to remove some confusion about which
// is the "right" way to things...
context.render = render;
context.clearRender = clearRender;
Object.defineProperty(context, 'render', { value: render, writable: false });
Object.defineProperty(context, 'clearRender', {
value: clearRender,
writable: false,
});

if (global.jQuery) {
context.$ = jQuerySelector;
Object.defineProperty(context, '$', { value: jQuerySelector, writable: false });
}

// When the host app uses `setApplication` (instead of `setResolver`) the event dispatcher has
Expand Down Expand Up @@ -190,18 +193,21 @@ export default function setupRenderingContext(context) {
});
})
.then(() => {
// ensure the element is based on the wrapping toplevel view
// Ember still wraps the main application template with a
// normal tagged view
//
// In older Ember versions (2.4) the element itself is not stable,
// and therefore we cannot update the `this.element` until after the
// rendering is completed
if (EmberENV._APPLICATION_TEMPLATE_WRAPPER !== false) {
context.element = getRootElement().querySelector('.ember-view');
} else {
context.element = getRootElement();
}
Object.defineProperty(context, 'element', {
// ensure the element is based on the wrapping toplevel view
// Ember still wraps the main application template with a
// normal tagged view
//
// In older Ember versions (2.4) the element itself is not stable,
// and therefore we cannot update the `this.element` until after the
// rendering is completed
value:
EmberENV._APPLICATION_TEMPLATE_WRAPPER !== false
? getRootElement().querySelector('.ember-view')
: getRootElement(),

writable: false,
});

return context;
});
Expand Down
15 changes: 15 additions & 0 deletions tests/unit/setup-context-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ module('setupContext', function(hooks) {
setResolver(resolver);
});

function overwriteTest(context, key) {
test(`throws an error when trying to overwrite this.${key}`, function(assert) {
assert.throws(() => {
context[key] = null;
}, TypeError);
});
}

function setupContextTests() {
module('without options', function(hooks) {
hooks.beforeEach(function() {
Expand All @@ -60,6 +68,8 @@ module('setupContext', function(hooks) {
}
});

overwriteTest(context, 'owner');

test('it uses the default resolver if no override specified', function(assert) {
let { owner } = context;
let instance = owner.lookup('service:foo');
Expand Down Expand Up @@ -104,6 +114,11 @@ module('setupContext', function(hooks) {
);
});

overwriteTest(context, 'set');
overwriteTest(context, 'setProperties');
overwriteTest(context, 'get');
overwriteTest(context, 'getProperties');

test('it calls setContext with the provided context', function(assert) {
assert.equal(getContext(), context);
});
Expand Down
13 changes: 13 additions & 0 deletions tests/unit/setup-rendering-context-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ module('setupRenderingContext', function(hooks) {
setResolver(resolver);
});

function overwriteTest(key) {
test(`throws an error when trying to overwrite this.${key}`, function(assert) {
assert.throws(() => {
this[key] = null;
}, TypeError);
});
}

function setupRenderingContextTests(hooks) {
hooks.beforeEach(async function() {
setResolverRegistry({
Expand Down Expand Up @@ -72,6 +80,8 @@ module('setupRenderingContext', function(hooks) {
});
}

overwriteTest('element');

test('render can be used multiple times', async function(assert) {
await this.render(hbs`<p>Hello!</p>`);
assert.equal(this.element.textContent, 'Hello!');
Expand Down Expand Up @@ -108,6 +118,9 @@ module('setupRenderingContext', function(hooks) {
assert.strictEqual(this.element, originalElement, 'this.element is stable');
});

overwriteTest('render');
overwriteTest('clearRender');

(hasjQuery() ? test : skip)('this.$ is exposed when jQuery is present', async function(assert) {
await this.render(hbs`<p>Hello!</p>`);

Expand Down