1

I'm writing Qunit tests to test An Ember model, but having a hard time testing computed properties that have a relation dependency (the computed property triggers another model's computed property).

The model that am testing (CoffeeScript):

Customer = DS.Model.extend
  firstName:      DS.attr('string')
  lastName:       DS.attr('string')
  phones:         DS.attr('embedded-list')
phone: (->
    @get('phones.firstObject.number')
  ).property('phones.firstObject.number')

fullName: (->
    [@get('lastName'), @get('firstName')].join(' ') )
  ).property('firstName','lastName')

The meeting Model:

Meeting = DS.Model.extend
  customers: DS.hasMany('customer')

  startAt:   DS.attr('isodate')
  status:    DS.attr()
  objective: DS.attr()

 customerPhones: (->
    phones = []
    @get('customers').forEach (c) ->
      c.get('phones').forEach (ph) ->
        phones.push(ph.number)
    phones
  ).property('customers.@each.phones')


  firstCustomer: (->
    @get('customers.firstObject')
  ).property('customers.firstObject')

 firstCustomerFullName: (->
    @get('firstCustomer.fullName')
  ).property('firstCustomer.fullName')

Now, testing customerPhones, and firstCustomerFullName is giving me a real hard time...

My test looks as follows:

`import { test, moduleForModel } from 'ember-qunit';`

moduleForModel('meeting', 'App.Meeting',{
   needs: ['model:customer']
   setup: ->
     Ember.run do (t = @)->
       ->
        customer = t.store().createRecord 'customer', firstName: 'John', lastName: 'Smith', phones:[]
        customer.get('phones').addObject(Ember.Object.create({tag: 'home', number: '111222333'}))
        customer.get('phones').addObject(Ember.Object.create({tag: 'work', number: '444555666'}))

        t.subject().set('customers.content', Ember.ArrayProxy.create({content: []}));
        t.subject().get('customers.content').pushObject(customer)    
 teardown: ->
  },(container, context) ->
      container.register 'store:main', DS.Store
      container.register 'adapter:application', DS.FixtureAdapter
      context.__setup_properties__.store = -> container.lookup('store:main')
)

test "it's a DS.Model", -> ok(@subject())

test "attributes: can be created with valid values", ->
  meeting = @subject({objective: 'Follow up'})
  Ember.run ->
    equal(meeting.get('objective', 'Follow up'))


test "properties: firstCustomer & firstCustomerFullName & firstCustomerPhone", ->
  meeting = @subject()
  Ember.run ->
    equal(meeting.get('firstCustomer.fullName'),  'Smith John')
    equal(meeting.get('firstCustomer.phone'),     '111222333')

Now, I used some techniques in this test, that I found in an answer here on Stack Overflow, but I can't seem to find it now.

That worked perfectly few days ago, now (it seems nonsense I know) whenever I run the test, it errors:

Assertion Failed: You cannot add 'meeting' records to this relationship (only 'meeting' allowed)

I don't know where the error is, nor how to fix it. Spent all the day monkeying around, No outcome.

How can I resolve this?

Mogsdad
  • 44,709
  • 21
  • 151
  • 275
Mawaheb
  • 822
  • 10
  • 21

2 Answers2

2

Okay, what I have so far is too much for a comment, so I'm going to do a WIP Answer.

  • I removed most of the run loops, they are only necessary for async processes.

  • I changed some of your computed properties to computed.alias properties

i.e.

phone: (->
  @get('phones.firstObject.number')
).property('phones.firstObject.number')

to

phone: Ember.computed.alias('phones.firstObject.number')
  • I ripped out most of the setup, Ember Data eagerly loads the store on its own and will use fixture ids etc without specifying it. (this part can be put back it, it just isn't necessary in this context).

i.e.

  },(container, context) ->
  container.register 'store:main', DS.Store
  container.register 'adapter:application', DS.FixtureAdapter
  context.__setup_properties__.store = -> container.lookup('store:main')
  • And I apologize in advance, I'm not a fan of coffeescript, so I put it all in js. Now the question is, if you're still seeing any issues we may need to find out what versions of Ember, ED, and Ember Qunit you are using.

http://emberjs.jsbin.com/OxIDiVU/625/edit

Community
  • 1
  • 1
Kingpin2k
  • 47,277
  • 10
  • 78
  • 96
  • hank you VERY much for having the time to read and answer my question, I really appreciate it. The test are still showing the same error, But actually, I noticed 2 things: 1- If I click "Rerun" that appears beside the test name, in order to run the test alone e.g localhost:4200/tests?testNumber=4 instead of localhost:4200/tests, It passes without problems! 2- Even though there is ONLY 1 equal inside a test, And even though am specifing expect(1), when I run all the tests e.g http://localhost:4200/tests it complains saying: `Expected 1 assertions, but 2 were run`. – Mawaheb Jun 09 '14 at 19:39
  • 1
    yeah, errors will toss an additionally assertion. I'm going to keep looking into how to cause it to crash in the jsbin, I'd guess it would be something to do with setup/teardown – Kingpin2k Jun 09 '14 at 20:58
  • Thank you very much, I've been monkeying around it endlessly, Something I noticed is, Not only the tests that exercise the relation fail, but they cause all other tests to fail as well, Saying :` Assertion Failed: You cannot add 'meeting' records to this relationship (only 'meeting' allowed)`!! That applies for the dead simple `it's a DS.Model` test! – Mawaheb Jun 09 '14 at 21:43
  • which version of Ember Data are you using? – Kingpin2k Jun 09 '14 at 21:47
  • `Ember-data @version 1.0.0-beta.8.2a68c63a` `Ember @version 1.6.0-beta.5` – Mawaheb Jun 09 '14 at 21:59
1

I found this question looking for 'how to unit test a computed property that uses a hasMany'.

Here is a simple example of how I did it (thanks to Kitler):

Fridge Model:

foods: DS.hasMany('food', {async: true}),

inDateFoods: Ember.computed('foods.@each.{ignoreEndDate,endDate}', function() {
  let foods = this.get('foods');
  let now = moment();
  return foods.filter(f => f.get(ignoreEndDate) || moment(c.get('endDate')).isAfter(now));
})

So say we now want to test inDateFoods in a unit test? Then do this in your fridge model test file:

import Ember from 'ember';
import { moduleForModel, test } from 'ember-qunit';
import Fridge from '../../../models/fridge';

Fridge.reopen({
  foods: Ember.computed(() => [])
});

moduleForModel('fridge', 'Unit | Model | fridge', {
  // Specify the other units that are required for this test.
  needs: ['model:food']
});

test('filters correctly', function(assert) {
  assert.expect(1);
  let model = this.subject();
  model.pushObject(Ember.Object.create({foods: [{id: 1, ignoreEndDate: false, endDate: '2050-03-08T00:00:00'});

  assert.equal(model.get('inDateFoods.length'), 1);
});

They key here is to reopen your model to remove the has many, and push the object after doing this.subject. Before doing the reopen we were getting the error All elements of a hasMany relationship must be instances of DS.Model, you passed [[object Object]] error.

Adam Knights
  • 2,141
  • 1
  • 25
  • 48