11

According to the blog-post for ember-data version 1.0.0-beta.16 the store can now be used as a service:

TweetComposerComponent = Ember.Component.extend({
  store: Ember.inject.service()      
});

However, I can't figure out how to do qunit unit tests on such a component. I've tried the following:

moduleForComponent('tweet-composer', {
  needs: ['service:store']
});

and:

moduleForComponent('tweet-composer', {
  needs: ['store:main']
});

And when I do the former I get an error Attempting to register an unknown factory: 'service:store' and if I do the latter then store is undefined.

Thoughts?

(I'm writing a ember-cli style app).

Update:

It seems there's an open issue for this in the ember-test-helpers repo.

While I'm waiting for this fix, I cooked up a helper that can work as a stop-gap measure (coffeescript):

`import TestModuleForComponent from 'ember-test-helpers/test-module-for-component'`
`import { createModule } from 'ember-qunit/qunit-module'`

# This assumes the last argument, the callbacks, is present, although it
# does support the description being an optional argument.
moduleForStoreComponent = ->
  args = Array.prototype.slice.call arguments
  callbacks = args[args.length-1]
  # Wrap the original beforeEach callback in a modified version that
  # also sets up the store for the test container.
  originalSetup = callbacks.beforeEach
  callbacks.beforeEach = ->
    DS._setupContainer(@container)
    originalSetup.call(@) if originalSetup
  callbacks.store = ->
    @container.lookup('store:main')
  args.unshift TestModuleForComponent
  createModule.apply @, args

`export default moduleForStoreComponent`
Kevin Bullaughey
  • 2,556
  • 25
  • 37

1 Answers1

13

A unit test is a place where everything works perfectly except the code/component/unit that you are testing.

So, even the store should be assumed to be working perfectly (0 errors/bugs).

Something like this should work in your test:

moduleForComponent('tweet-composer', {
    beforeEach: function() {
        this.subject({
            store: {/*empty object*/}
        });
    }
});

If parts of your tests depend on data retrieved from the store, you can do something like:

this.subject({
    store: {
        find: function() {
          var mockedModel = Ember.Object.create({/*empty*/});
          return mockedModel;
        }
    }
});

This is to preserve the status of "unit test", if you start including and registering other objects from your app you 'll be actually writing integration tests.

Note:

In general, looking up models directly in a component is an anti-pattern, and you should prefer to pass in any model you need in the template that included the component.

http://discuss.emberjs.com/t/should-ember-components-load-data/4218/2?u=givanse

givanse
  • 14,503
  • 8
  • 51
  • 75
  • Acceptance tests are excruciatingly slow. I prefer to only use them if I am testing many aspects of the application. If I am testing exactly two pieces, it makes a lot more sense just to instantiate those two pieces and test them together, but in isolation of the rest of the app. – Kevin Bullaughey Apr 21 '15 at 00:58
  • 1
    I am aware of the thread you mention, and I appreciate the advice, but I am in the camp that feels there are certain limited, appropriate uses to enable store access inside certain components. In particular, when the state represented in the component is not derived from the URL, but rather an intrinsic and isolated aspect of the component, it can make sense to isolate this state in the component and not pollute all the routes that feature the component with the logic required to instantiate the models and update them as state internal to the component changes. – Kevin Bullaughey Apr 21 '15 at 01:03
  • Agreed, you have a good point there. Even then, in this type of test (your component), what you are testing is the component's logic not the store. So it doesn't really matter where the data is coming from. What the test needs to do is verify that different pieces of data trigger the correct events and result in expected outputs. – givanse Apr 21 '15 at 18:56
  • 2
    Yeah, although I'm using `http-mocks` for my model fixtures, and it's nice to be able to test a component in conjunction with realistic mock data that's centrally located and not distributed across all my hundreds of test files. I realize this means it's not really a "unit test" per se but it's the granularity of testing that I find most useful. I appreciate your answer and will up-vote it because I learned something about how to stub using `subject`, but I'm still holding out for another answer that lets me do what I desire. – Kevin Bullaughey Apr 22 '15 at 16:09