3

Using this:

DEBUG: -------------------------------
DEBUG: Ember      : 1.5.1
DEBUG: Ember Data : 1.0.0-beta.7.f87cba88
DEBUG: Handlebars : 1.3.0
DEBUG: jQuery     : 1.10.2
DEBUG: -------------------------------

And testing using Ember-qunit.

So I'm trying to write a unit test for a computed property on my model. The computed property depends on data from a hasMany relationship.

So my model looks something like this:

App.User = DS.Model.extend({
  name: DS.attr('string'),
  roles: DS.hasMany('role'),

  isInstructor: function(){
    return this.hasRole('instructor');
  }.property('roles'),

  hasRole: function(role_name){
    var roles = this.get('roles');
    if(!Ember.isEmpty(roles)){
      return roles.any(function(role){
        return role.get('name') === role_name;
      });
    }
    return false;
  }
});

And my test looks something like this:

moduleForModel('user', 'Course Model', {
  needs: ['model:role']
});

test('isInstructor - user is an Instructor', function() {
  var user = this.subject({
    id: 1,
    name: 'Joe'
  });

  Ember.run(function(){
    user.set('roles.content', Ember.ArrayProxy.create({content: []}));
    var role = Ember.ObjectProxy.create({name: 'instructor'});
    user.get('roles.content').pushObject(role);
  });

  var value = user.get('isInstructor');
  equal(value, true, "expected true but was " + value);
});

When I try to pushObject I get this error:

Uncaught TypeError: undefined is not a function ember-data.prod.js?body=1:4284

The line in ember-data it is referencing is this:

var inverse = childType.inverseFor(this.firstRecordName);

Now I've tried a couple different things and still have had no luck.

To start I tried creating it all at once:

var user = this.subject({
  id: 1,
  name: 'Joe',
  roles: Ember.ArrayProxy.create({content: [Ember.ObjectProxy.create({name: 'instructor' })]})
});

But that doesn't work as it says:

Uncaught Error: Cannot set read-only property "roles" on object: <App.User:ember792:1>

So I tried setting the roles in an Ember.run loop later:

user.set('roles',
  Ember.ArrayProxy.create({
    content: [
      Ember.ObjectProxy.create({
        name: 'instructor'
      })
    ]
  })
);

And that gives the same read-only error.

So I tried setting the content at the same time as the roles:

user.set('roles.content',
  Ember.ArrayProxy.create({
    content: [
      Ember.Object.create({
        name: 'instructor'
      })
    ]
  })
);

And I'm getting the

Uncaught TypeError: undefined is not a function

So now I'm to the code I defined above:

user.set('roles.content', Ember.ArrayProxy.create({content: []}));
var role = Ember.ObjectProxy.create({name: 'instructor'});
user.get('roles.content').pushObject(role);

And getting the TypeError. I'm at a loss. I'm not sure what I'm doing wrong or if there is a bug.

Anyone smarter than I have a suggestion?

Here is a jsbin http://jsbin.com/bidus/1/

Thanks!

** UPDATE 1 **

Looking at what kingpin2k is saying in his answer, I looked at my ember source in my app. I am using the rubygem ember-source and so I have pretty close to the same source as the 'debug' version that @kingpin2k used. There are some extra functions in the ember-source version, but all the test helpers are still there.

So I started looking at my code. The error that pops up has to do with inverse relationships.

var inverse = childType.inverseFor(this.firstRecordName);

And looking at my jsbin, I failed to add that the role model has a belongsTo('user')

Here is a failing jsbin http://jsbin.com/bidus/2/ using the same ember sources that @kingpin2k used. It is failing because of that belongsTo relationship on the role model. I realized that shouldn't be there as I have no need of a role needing to know of a user. Thus I removed that relationship and all is green now.

Now I have a passing jsbin http://jsbin.com/bidus/3/ which is the same as what @kingpin2k did.

But it still begs the question as to why that belongsTo is making it barf. As far as I can tell it should be fine being in there. Maybe @kingpin2k you can shed some more light on this? I shouldn't have to add inverse to the model roles as ember is suppose to be able to figure that out on its own (and I did try adding it for kicks and giggles but the code still barfs). I'm inclined to think there is a bug in the ember-data source.

Community
  • 1
  • 1
bfcoder
  • 3,042
  • 2
  • 28
  • 35

1 Answers1

3

Honestly I think the main issue I see is that you're using a production version of ember, and that doesn't include the testing helpers, or the method setupForTesting.

Debug version of Ember

http://jsbin.com/tuvoleqo/1/edit

Cleaner version

test('isInstructor - user is an Instructor', function() {
  var user = this.subject({
    id: 1,
    name: 'Joe'
  });

  Ember.run(function(){
    user.get('roles').pushObject(Em.Object.create({name:'instructor'}));
  });

  var value = user.get('isInstructor');
  equal(value, true, "expected true but was " + value);
});

http://jsbin.com/tuvoleqo/2/edit

Kingpin2k
  • 47,277
  • 10
  • 78
  • 96
  • @kingpin2k Excuse my naive question, But, I really don't see how creating an arbitrary Ember object is testing the user roles, Is that the only way to do this test? isn't it better to create a 'Role' object instead? or it doesn't matter – Mawaheb Jun 05 '14 at 12:20
  • 2
    He isn't testing user roles, he's testing the `isInstructor` computed property. To be honest we probably should have mocked out the hasRoles method as well, it's a unit test, not an integration test. All we care is that when `hasRoles` returns true `isInstructor` returns true, and vice versa. In a separate unit test he could have tested `hasRoles`. Testing Ember Data itself isn't pointless, but it has an entire set of tests that cover how its innards work (not to say it's without issues, it is beta after all, but you aren't changing its code) – Kingpin2k Jun 05 '14 at 14:24
  • Oh i see, I asked because am having a similar situation, Based on his example, Say, That role has `ability` and `age` and a computed property `limitation` that simply concatenates the `ability+' '+age`, and User has `roleLimit` computed property that tigers the `limitation` property, For me, That sounds like integeration test, But bear with me, In Case I do want to test it, How am to do so! Your way won't work, I need to create a role object right? Well, Doing so from within qunit test is a nightmare ! Endless searching online, No luck – Mawaheb Jun 09 '14 at 13:43
  • Would you mind creating a question, and putting the code/test in it? I have a hard time following it without looking at the code, feel free to post the link in here and I'll take a look at it. – Kingpin2k Jun 09 '14 at 14:23
  • Thank you so much for listening and being Patient, I did create a question... Thanks in Advance http://stackoverflow.com/q/24123948/2166870 – Mawaheb Jun 09 '14 at 15:54