2

This is an Ember component that will need this at some point:

export default Component.extend({ filteredSubs: computed.filter('model.subs', function() { // this will always return true in development http://localhost:4200/dummy // but will always return false in test because 'this' becomes undefined return this; }) }); 

Dummy has a one-to-many relationship to Sub:

export default Model.extend({ subs: hasMany('sub') }); export default Model.extend({ dummy: belongsTo('dummy') }); 

This test fails but shouldn't:

test('it renders', function(assert) { let dummy = server.create('dummy'); server.create('sub', { dummy }); this.set('dummy', dummy); this.render(hbs`{{show-dummy model=dummy}}`); assert.equal(this.$().text().trim(), 'Hi! There are 1 sub-dummies'); }); 

not ok 13 Chrome 63.0 - Integration | Component | show dummy: it renders

actual: Hi! There are 0 sub-dummies

expected: Hi! There are 1 sub-dummies

1 Answer 1

3
+50

Your problem comes from an unfortune sequense of falsy assumptions.

The first assumption of you is that this inside a Ember.computed.filter should be the corresponding object. I'm not 100% sure this is documented behaviour, and personally wouldnt rely on it. If you need full access to this I would go with a simple Ember.computed.

However your primary mistake is in your test. And this also explains why you only have this problem in testing. Your directly using a mirage model as model for your component:

let dummy = server.create('dummy'); server.create('sub', { dummy }); this.set('dummy', dummy); this.render(hbs`{{show-dummy model=dummy}}`); 

Here you assume that the result of server.create, a mirage model, is in some ways similar to a ember-data model. It is not! In fact, a mirage model is not even an ember object! So you can't use .get or .set on it, or anything you defined on your model, and definitly should not use it ever as an model für component testing. Instead you should use mirage as data-source for your ember-data models.

The question why this is undefined if your model is a mirage model leads to this line in ember-cli-mirage:

filter(f) { let filteredModels = this.models.filter(f); return new Collection(this.modelName, filteredModels); } 

where the this-context gets lost. Basically mirage is overriding the .filter function on their custom array-like structure, and doesnt ensure to keep the this-context.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for that @Lux. I'm now using filteredSubs: computed('dummy.subs', function() { return this.get('dummy.subs').filter(s => s); }) instead. Whether .filter should keep the context for this or not is now being discussed on the ember-cli-mirage issue github.com/samselikoff/ember-cli-mirage/issues/1256
Also @Lux what's your recommendation to "fake" data as part of a component test? Most people use Mirage's server.create but I have to agree that it's sometimes acting weirdly, as you mentioned we don't always have access to .get or .set. Ty!
I dont think thats common. server.create is common to produce test data, but you always should wrap them with real ember-data models! store.push might be what you're looking for.
You are right. I found this answer to be the best way to “mock objects” inside component integration tests, as compared to Mirage’s server.create or Ember’s EmberObject.create which would not work with objects that contain relationships

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.