ember.jsember-dataember-qunit

Ember integration test + mocking model with relationships + ember-deferred-content add-on


I am using the {{deferred-content}} component within my component's template, hooked into a model object's asset relationship. Here is a stripped-down version of what I'm trying to do:

{{#unless showUploadForm}}
  {{#deferred-content contentBlock.asset as |d|}}
    {{#d.fulfilled as |asset|}}
      {{#if asset.asset.isProcessing}}
        {{! Show processing message here }}
      {{/if}}
    {{/d.fulfilled}}
  {{/deferred-content}}
{{/unless}

The showUploadForm computed property is of interest:

showUploadForm: computed('contentBlock.asset', 'isReplacing', function() {
  console.log(this.get('contentBlock.asset.id'));
  return this.get('isReplacing') || isBlank(this.get('contentBlock.asset.id'));
})

This all works wonderfully from my application in development mode and production mode, all hooked into the API and such.

Then we enter Trouble Town when I try to write an integration test:

test('it displays processing message when asset is loaded in with processing status', function(assert) {
  let deferred = RSVP.defer();

  this.set('contentBlock', Ember.Object.create({
    asset: deferred.promise
  }));

  this.render(hbs`{{asset-editor contentBlock=contentBlock}}`);

  // This is likely the big fat problem. I don't know what to put here.
  deferred.resolve(Ember.Object.create({
    id: 'the-id',
    asset: {
      isProcessing: true
    }
  }));

  let done = assert.async();

  return wait().then(() => {
    // Stuff I'm asserting is here. It fails because the
    // `showUploadForm` computed property is returning `true`.
    done();
  });
});

The interesting part is in the computed property that I share above. In development/production, I get an id. In testing, I get undefined.

I am certain that this problem is because of how Ember Data is handling the promise and the object that it "unpacks" after resolution of the data that it receives. The problem is that I don't know how to mock this in my integration test.

Is there anything in particular that I can set when calling deferred.resolve to force the application to treat the value as a model's relationship?

Bonus: For giggles, I hooked Ember Mirage into the test, queried the store service to get the contentBlock (both with the related data side-loaded and then later not), and set that as contentBlock on the testing context. I got similar results.


Solution

  • I ultimately got this working with an acceptance test instead of an integration test. This doesn't sit 100% well with me because the component tests look incomplete since I can't test much of the functionality in that context.

    That said, this problem is also challenging me to consider breaking the component down into smaller components so some of the specialized logic can be isolated and tested more easily. Then I can test the individual components' functionality without worrying as much about how the data was loaded (directly vs. asynchronously through a relationship, etc.).

    The acceptance test does allow me to test the overall integration of all of these little components, so it will be nice to have around, event after breaking it all down further.