shane shane - 1 year ago 70
Javascript Question

Qunit _initProperties is not a function

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:

  • I'm getting an error
    this._initProperties is not a function

    • The error goes away when I remove the shared stuff

    • The error persists if I add the shared stuff between the
      and the

  • I want to be able to share variables defined in either the beforeEach or globally

  • I've tried doing something like
    let a = 1
    in the
    , but can't seem to reference them in the test itself

I noticed that the QUnit docs say that they've eliminated globals. Could that be playing a role in this?

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

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
. Getting rid of that and using the long form seems to get rid of this error though ...

Answer Source

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
  obj.getThis() === obj // true

// this binds globally
  extractedGetThis() === window // true