Skip to content

Instantly share code, notes, and snippets.

@jamesarosen
Last active August 29, 2015 14:21
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jamesarosen/a0e7639ad403925e78f5 to your computer and use it in GitHub Desktop.
Save jamesarosen/a0e7639ad403925e78f5 to your computer and use it in GitHub Desktop.
Upgrading to ember-qunit 0.3.2

Recently, I upgraded from ember-qunit 0.3.1 to 0.3.2. The main reason I wanted to upgrade was to take advantage of a new way of writing component tests.

Previously, there was no way to test how the component was actually used. A component test could instantiate a component and poke at its internals, but that isn't how we use components. We use them declaratively in templates. The old style also meant it was difficult to test block templates and impossible to test block parameters.

I really wanted the new test style, but it wasn't easy to get there. The following are my upgrade notes.

Gotcha: moduleForComponent Requires Three Arguments

Many of my old component tests looked like

moduleForComponent('foo-bar');

That breaks in the latest version because there is no default third argument. Instead, for an old-style unit test, just change the above to

moduleForComponent('foo-bar', 'FooBarComponent', {
  integration: false
});

Gotcha: Model-Integration Tests Are Broken

Previously, I had

moduleForModel('user', 'User#hasRole', {
  integration: true
});

just so I wouldn't have to declare a long needs list in the test. (user has relationships to lots of other models in the system.)

That breaks in ember-qunit 0.3.2, but the workaround is pretty easy:

moduleForModel('user', 'User#hasRole', {
  integration: true,

  beforeEach: function() {
    DS._setupContainer(this.container);
  }
});

See emberjs/ember-test-helpers#46 for more information.

Prefer Acceptance, Then Integration Tests for Components

In general, I prefer using the Acceptance-test style: visit('/billing');, click(findButton('Save')), etc. I always reach for that test first.

I find it hard to write those tests for general-purpose components. You could test just one instance in your app, but that might not cover the component's whole API. Or you could try to test them all, but you'll get lots of redundancy. I converted most of the tests for general-purpose components into the new integration: true style.

This new style does away with this.subject(attributes) in favor of this.render(template). Note that the template is outside the component and must include the use of the component itself. The context outside the component is the test itself. You can call this.set in your test to set up variables and bindings will work. And this.$() is a selector scoped to the template rendered by this.render().

Overall, I find it to be a good compromise -- easy to get some isolation around the component, yet the tests look more like real-world code and behavior.

One of my tests looks like

moduleForComponent('credit-card', 'CreditCardComponent', {
  integration: true,

  beforeEach: function() {
    this.set('fakeStripe', { createToken: sinon.stub() });
    this.set('card', { lastFourDigits: '4416' });

    this.render(`
{{credit-card stripe=fakeStripe card=card}}
`);
  }
});

test('shows the last four digits', function(assert) {
  assert.equal(this.$('.last-four').text(), '4416');
});

test('saving requests a token from Stripe', function(assert) {
  Ember.run(() => { this.$('.save').click(); });

  assert.ok(this.get('fakeStripe').createToken.calledOnce);
});
@rwjblue
Copy link

rwjblue commented May 18, 2015

  • The single argument version of moduleForComponent was fixed in ember-qunit@0.3.3.
  • Model integration tests were fixed in ember-qunit@0.4.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment