I've run into some strange behavior here and wanted to see if anybody knew why it occurs. I've written a simple Ember QUnit test and want to share some data between each test, just to reduce clutter.
import Ember from 'ember'
import { moduleFor, test } from 'ember-qunit';
let create = Ember.Object.create;
let shared = create({});
shared.stardardData1 = create({ id: 1 });
shared.stardardData2 = create({ id: 2 });
moduleFor('controller:foo', 'description', {
beforeEach() { ... }
afterEach() { ... }
}
test('should do things', function () {
let myGroup = [shared.standardData1, shared.standardData2];
}
A couple things here:
this._initProperties is not a function
moduleFor
and the test
let a = 1
in the beforeEach
, but can't seem to reference them in the test itselfI noticed that the QUnit docs say that they've eliminated globals. Could that be playing a role in this? https://qunitjs.com/upgrade-guide-2.x/
PS: It would be nice to have something that set up the module just once instead of every time
Here's the stacktrace:
Promise rejected before should do things: this._initProperties is not a function Source: TypeError: this._initProperties is not a function at create (http://localhost:7357/assets/vendor.js:46461:14) at Object.beforeEach (http://localhost:7357/assets/tests.js:185:20) at http://localhost:7357/assets/test-support.js:6586:31 at tryCatch (http://localhost:7357/assets/vendor.js:61631:14) at invokeCallback (http://localhost:7357/assets/vendor.js:61646:15) at publish (http://localhost:7357/assets/vendor.js:61614:9) at http://localhost:7357/assets/vendor.js:41408:7 at invoke (http://localhost:7357/assets/vendor.js:11120:16) at Object.flush (http://localhost:7357/assets/vendor.js:11184:11) at Object.flush (http://localhost:7357/assets/vendor.js:10992:17)
Actually I think this might not have to do with the globals. I've also added (was not included before) let create = Ember.Object.create
just to save some typing (and wrapped the above objects with the call create(object)
. Getting rid of that and using the long form seems to get rid of this error though ...
The last part of your question is the actual problem.
When you do
let create = Ember.Object.create
You extract the function create
from the Ember.Object
and create a new reference to it, as a plain function.
As per JS binding rules, when you call a function as a plain function, this
inside of it binds to the global object (or undefined
in strict mode). On the other hand, when you call a function as a method on an object (i.e. calling it directly on Ember.Object
) would bind this
to that object.
That's why this
is undefined within create
and hence this._initProperties
is not a function.
Here's a demo of what is happening:
// an object with a method
var obj = {
getThis: function() {
return this;
}
};
// an extracted reference to the method
var extractedGetThis = obj.getThis;
// this binds to the object
console.log(
obj.getThis() === obj // true
);
// this binds globally
console.log(
extractedGetThis() === window // true
);