0

I am using Sinon with Ember.js Concurrency Tasks and am trying to stub the task in a test.

The code looks something like this:

component .ts file:

import Component from '@glimmer/component';
import { TaskGenerator, TaskInstance } from 'ember-concurrency';
import { task } from 'ember-concurrency-decorators';
import { taskFor } from 'ember-concurrency-ts';

export default class Container extends Component<Args> {

    @task *myTask(): TaskGenerator<Data> {
        const response: Data = yield json('someURL'); //json() returns a JSON object from a request to someURL
        return response;
    }

    get task(): TaskInstance<Data> | null {
        const task = taskFor(this.myTask);
        return task.last ? task.last : task.perform();
    }

    @action
    someMethod(): void {
        const task = taskFor(this.myTask);
        task.perform();
    }
}

relevant test from component test file:

...
module('Integration | Component | container', function(hooks){
    test('some test', async function(this: Context, assert) {
    await render(hbs`
        <Container @someMethod={{@someArgument}} as |c| >
            // some code that uses c
        </Container>
    `);
}

How would I stub the myTask task? I would essentially like to have it so that I am able to manually control the response that comes out of myTask so an HTTP response doesn't have to be made in the test.

Andrew Zaw
  • 754
  • 1
  • 9
  • 16

3 Answers3

2

I would extend the component in your test file with your mocked task overriding the real one.

class TestContainer extends Container {
  @task *myTask(): TaskGenerator<Data> {
    return someMockData;
  }
}

// ...

hooks.beforeEach(function() {
  this.owner.register('component:container', TestContainer);
});
Gaurav
  • 12,662
  • 2
  • 36
  • 34
  • This answers the question you asked, but if your real purpose is to mock a network response, see @jrjohnson 's answer – Gaurav Dec 23 '20 at 19:18
1

I'm not aware of any way to mock a single task in a component for testing. When the network is involved I reach for ember-cli-mirage which is built on pretender. Mirage is very good when working with ember-data models and can also be used to handle mocking any network request. If you're not using ember-data you may want to just use pretender or investigate the non-framework Mirage.js.

By mocking the network and returning canned data you will have the same control over your tests while testing the component as is. I really like this approach and have found it to be very reliable and stable for several years.

jrjohnson
  • 2,401
  • 17
  • 23
0

I do have tasks stubbing with sinon in my project. It's built a bit differently from the setup you have but perhaps you might get some inspiration.

So I have this task in my component

  @(task(function* () {
      yield this.exportxls.asXls.perform(someArg);
  })) downloadXls;

and this asXls method is in the service

  @(task(function* (mapping) {
    // ...
  }).drop()) asXls;

and then in my integration test I do the stub like this

    this.owner.register('service:exportxls', Service.extend({
      init() {
        this._super(...arguments);
        this.set('asXls', {
          perform: sinon.stub()
        });
      }
    }));

after that I can do usual checks

    assert.ok(exportService.asXls.perform.calledOnce);
Dharman
  • 30,962
  • 25
  • 85
  • 135
Andrey Stukalin
  • 5,328
  • 2
  • 31
  • 50