Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
async/await in ember tests

You can use async/await in your Ember testing suite, today! This blog post explains the situation pretty thoroughly. Also check out this blog post.

It's great in tests, but not quite useful for app code yet.

There are three ways we can get it to work. If you try async/await without any of these changes, you will get the error regeneratorRuntime is not defined.

Method Size ※ app code test code
includePolyfill: true 30kb yes yes
ember-maybe-import-regenerator 2kb yes yes
targets.js (see below) 0kb no yes

※ size in prod (gzipped). Determined by doing ember build -p before and after making the change.

targets.js method

This method adds nothing to the production payload. You can configure just the test environment browser target to use the latest chrome. Add the targets.js (below) to your app

Since this does not let you use async/await in your app code, you may want to restrict usage in app code somehow. Is there an eslint rule that would work for this? If so we could enable in tests/eslintrc.js but not ./eslintrc.js.

Although maybe 2kb is small enough you'd rather use ember-maybe-import-regenerator :)

References

Test Code

before

"sawtooth" pattern (better than pyramid of doom, but still not ideal)

it('can create a new plan', function() {
  fillIn(PRICE_INPUT, '10.00');
  click(ADD_PLAN);
  andThen(() => {
    expect(server.db.plans[0].price_cents).to.equal(1000);
  });
});

after

so smooth~

basically no need for andThen ever again

it('can create a new plan', async function() {
  await fillIn(PRICE_INPUT, '10.00');
  await click(ADD_PLAN);
  expect(server.db.plans[0].price_cents).to.equal(1000);
});

App Code

Not actually useful in app code yet! See this RFC.

before

"sawtooth" pattern (better than pyramid of doom, but still not ideal)

actions: {
  savePlan() {
    this.get('plan').save().then((plan) => {
      this.get('flashMessages').success(`Plan "${plan.get('name')}" created.`);
      this.get('goToEdit')(plan.get('id'));
    });
  }
}

after

so smooth~

In my testing save() did work, so it must not require an Ember.run(). However, in my testing ember-data relationship calls didn't work, and deleteRecord didn't either. These must need an Ember.run().

actions: {
  async savePlan() {
    const plan = await this.get('plan').save();
    this.get('flashMessages').success(`Plan "${plan.get('name')}" created.`);
    this.get('goToEdit')(plan.get('id'));
  }
}
// config/targets.js
let browsers;
if (process.env.EMBER_ENV === 'test') {
browsers = [ 'last 1 Chrome versions' ];
} else {
browsers = ['> 3%'];
}
module.exports = {
browsers
};
@dwickern

This comment has been minimized.

Copy link

dwickern commented Nov 3, 2017

@caseywatts

This comment has been minimized.

Copy link
Owner Author

caseywatts commented Nov 17, 2017

awesome @dwickern !!

@caseywatts

This comment has been minimized.

Copy link
Owner Author

caseywatts commented Dec 21, 2017

@chuckcarpenter suggested that maybe the testem.js config could accomplish the same thing as targets.js. That seems plausible!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.