Skip to content

Commit

Permalink
[BUGFIX release] Ensure proxies have access to getOwner(this).
Browse files Browse the repository at this point in the history
Prior to this change, when in debug builds, any "proxy" (i.e. something
with `unknownProperty`) would _not_ have access to an `owner` object
via `getOwner(this)`. This is because of our association with the
`FACTORY_FOR` weakmap is only setup for the actual `CoreObject` instance
being created, but when `unknownProperty` exists we never expose the
"real" `CoreObject` instance and instead expose a native JS `Proxy` (so
that we can trap usage of `instance.foo` and properly error).

This fix ensures that the native proxy that is returned is also
associated with the factory, and can properly access `getOwner(this)` /
`._debugContainerKey` / etc.
  • Loading branch information
rwjblue committed Apr 11, 2018
1 parent 8b24b9c commit 645fbe9
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 3 deletions.
2 changes: 2 additions & 0 deletions packages/ember-runtime/lib/system/core_object.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ function makeCtor(base) {
assert(messageFor(receiver, property), value === undefined);
},
});

FACTORY_FOR.set(self, FACTORY_FOR.get(this));
}

let m = meta(self);
Expand Down
20 changes: 19 additions & 1 deletion packages/ember-runtime/tests/system/core_object_test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getOwner } from 'ember-utils';
import { getOwner, setOwner } from 'ember-utils';
import { get } from 'ember-metal';
import CoreObject from '../../lib/system/core_object';
import { moduleFor, AbstractTestCase } from 'internal-test-helpers';
Expand Down Expand Up @@ -74,5 +74,23 @@ moduleFor(
// should not trigger an assertion
getOwner(proxy);
}

['@test can use getOwner in a proxy init GH#16484'](assert) {
let owner = {};
let options = {};
setOwner(options, owner);

CoreObject.extend({
init() {
this._super(...arguments);
let localOwner = getOwner(this);

assert.equal(localOwner, owner, 'should be able to `getOwner` in init');
},
unknownProperty() {
return undefined;
},
}).create(options);
}
}
);
19 changes: 19 additions & 0 deletions packages/ember-runtime/tests/system/object/create_test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { getOwner, setOwner } from 'ember-utils';
import { computed, Mixin, observer } from 'ember-metal';
import { MANDATORY_SETTER } from 'ember/features';
import EmberObject from '../../../lib/system/object';
Expand Down Expand Up @@ -112,5 +113,23 @@ moduleFor(
let o = EmberObject.create(undefined);
assert.deepEqual(EmberObject.create(), o);
}

['@test can use getOwner in a proxy init GH#16484'](assert) {
let owner = {};
let options = {};
setOwner(options, owner);

EmberObject.extend({
init() {
this._super(...arguments);
let localOwner = getOwner(this);

assert.equal(localOwner, owner, 'should be able to `getOwner` in init');
},
unknownProperty() {
return undefined;
},
}).create(options);
}
}
);
30 changes: 28 additions & 2 deletions packages/ember/tests/service_injection_test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Controller } from 'ember-runtime';
import { getOwner } from 'ember-utils';
import { Controller, inject, Service, _ProxyMixin } from 'ember-runtime';
import { moduleFor, ApplicationTestCase } from 'internal-test-helpers';
import { inject, Service } from 'ember-runtime';
import { computed } from 'ember-metal';
import { EMBER_METAL_ES5_GETTERS, EMBER_MODULE_UNIFICATION } from 'ember/features';

Expand All @@ -23,6 +23,32 @@ moduleFor(
assert.ok(controller.get('myService') instanceof MyService);
});
}

['@test Service can be an object proxy and access owner in init GH#16484'](assert) {
let serviceOwner;

this.add(
'controller:application',
Controller.extend({
myService: inject.service('my-service'),
})
);
let MyService = Service.extend(_ProxyMixin, {
init() {
this._super(...arguments);

serviceOwner = getOwner(this);
},
});
this.add('service:my-service', MyService);
this.addTemplate('application', '');

this.visit('/').then(instance => {
let controller = this.applicationInstance.lookup('controller:application');
assert.ok(controller.get('myService') instanceof MyService);
assert.equal(serviceOwner, instance, 'should be able to `getOwner` in init');
});
}
}
);

Expand Down

0 comments on commit 645fbe9

Please sign in to comment.