Skip to content

Instantly share code, notes, and snippets.

@caseywatts
Last active August 8, 2018 22:48
  • Star 8 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save caseywatts/7c01654f74fbe402dfaadfa144965adb 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
};
@dwickern
Copy link

dwickern commented Nov 3, 2017

@caseywatts
Copy link
Author

awesome @dwickern !!

@caseywatts
Copy link
Author

@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