Skip to content

Instantly share code, notes, and snippets.

@villander
Forked from caseywatts/0 README.md
Created November 10, 2017 11:58
Show Gist options
  • Save villander/7c6e0f7fdb344569c51c1d14eee65c5a to your computer and use it in GitHub Desktop.
Save villander/7c6e0f7fdb344569c51c1d14eee65c5a to your computer and use it in GitHub Desktop.
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
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment