Search code examples
javascripttestingember.jsasync-awaitember-octane

Ember Octane: Unit testing async action on controller


Having the following controller and tests:

app/controllers/application.js

import Controller from '@ember/controller';
import { action } from '@ember/object';

export default class ApplicationController extends Controller {
  flag = false;

  @action
  raiseFlag() {
    this.flag = true;
  }

  @action
  async raiseFlagAsync() {
    await new Promise(resolve => setTimeout(resolve, 1000));
    this.flag = true;
  }
}

tests/unit/controllers/application-test.js

import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';

module('Unit | Controller | application', function(hooks) {
  setupTest(hooks);

  test('it raises flag', function(assert) {
    let controller = this.owner.lookup('controller:application');
    assert.equal(controller.flag, false);
    controller.send('raiseFlag');
    assert.equal(controller.flag, true);
  });

  test('it raises flag asyncronously', async function(assert) {
    let controller = this.owner.lookup('controller:application');
    assert.equal(controller.flag, false);
    await controller.send('raiseFlagAsync');
    assert.equal(controller.flag, true);
  });
});

The first test case passes. The second test case fails (the async one)

What is the ember-octane way of waiting for the async action?


Solution

  • The trick here is to not use send! Generally I would use send only if you need to bubble actions in the route chain. Its a bit a old concept and it has no return value. So await controller.send will not work.

    You should just invoke the action directly:

    test('it raises flag asyncronously', async function(assert) {
      let controller = this.owner.lookup('controller:application');
      assert.equal(controller.flag, false);
      await controller.raiseFlagAsync();
      assert.equal(controller.flag, true);
    });