Giter VIP home page Giter VIP logo

ember-concurrency-test-waiter's Introduction

ember-concurrency-test-waiter

Easily instrument your ember-concurrency tasks to cause @ember/test-helpers' settled() method to wait for any running instances of those tasks to complete before proceeding.

Motivation

Ember's async-aware test infrastructure will wait for several specific types of asynchronous operations (currently route transitions, AJAX requests and run loop actions/timers), but has no easy centralized way of tracking other asynchronous operations, such as waiting for callbacks from the FileReader API, waiting for an image to load in an <img> tag, etc.

ember-concurrency provides a very nice mechanism for wrapping these (and any other) asynchronous operations into tasks, and this addon adds support for easily telling the Ember testing framework to treat running instances of certain tasks as test-blocking asynchronous operations.

Installation

ember install ember-concurrency-test-waiter

Usage

Import ember-concurrency-test-waiter's withTestWaiter method into your application code and then use it to wrap any tasks that you want to block asynchronous test helpers:

// components/my-component.js
import Component from '@ember/component';
import { task } from 'ember-concurrency';
import withTestWaiter from 'ember-concurrency-test-waiter/with-test-waiter';
import doSomethingAsync from '../utils/do-something-async';

export default Component.extend({
  myTask: withTestWaiter(task(function*() {
    return yield doSomethingAsync();
  }))
});

Alternatively, you can call ember-concurrency-test-waiter's defineModifier method somewhere early in the boot process, such as app.js or an initializer, and then use it as a task modifier:

// app.js
import defineModifier from 'ember-concurrency-test-waiter/define-modifier';

defineModifier();

// remainder of app.js...
// components/my-component.js
import Component from '@ember/component';
import { task } from 'ember-concurrency';
import doSomethingAsync from '../utils/do-something-async';

export default Component.extend({
  myTask: task(function*() {
    return yield doSomethingAsync();
  }).withTestWaiter()
});

If you're using @task decorator provided by ember-concurrency-decorators, then use the task modifier like this:

// app.js
import defineModifier from 'ember-concurrency-test-waiter/define-modifier';

defineModifier();

// remainder of app.js...
// components/my-component.js
import Component from '@ember/component';
import { task } from 'ember-concurrency-decorators';
import doSomethingAsync from '../utils/do-something-async';

export default class MyComponent extends Component {
  @task({
    withTestWaiter: true
  })
  myTask = function*() {
    return yield doSomethingAsync();
  }
}

Why?

Here is a full example if how this addon could be useful to you. Suppose you want to test a component that is handed the URL of an image and displays its dimensions. Your component needs to load the image into an <img> tag and wait for a callback indicating that it's loaded so the dimensions can be read. But in your unit test, there's no good way to wait for that load to complete other than polling on a timer or something. Use ember-concurrency-test-waiter!

// app/app.js
import defineModifier from 'ember-concurrency-test-waiter/define-modifier';

defineModifier();

// remainder of app.js...
// app/components/image-size.js

import $ from 'jquery';
import Component from '@ember/component';
import { Promise } from 'rsvp';
import { run } from '@ember/runloop';
import { task } from 'ember-concurrency';

export default Component.extend({
  src: null,
  dimensions: null,

  init() {
    this._super(...arguments);
    this.get('computeDimensions').perform(this.get('src'));
  },

  computeDimensions: task(function*(src) {
    let img = yield new Promise((resolve, reject) => {
      let $img = $('<img>');
      $img.load(function() {
        run(() => resolve(this));
      });
      $img.error(run(reject));
      $img.attr('src', src);
    });
    this.set('dimensions', { width: img.width, height: img.height });
  }).restartable().withTestWaiter()
});
{{! app/templates/components/image-size.hbs }}
{{#if dimensions}}
  dimensions: {{dimensions.width}}x{{dimensions.height}}
{{else}}
  loading...
{{/if}}
// tests/integration/components/image-size.js

import { A } from '@ember/array';
import { run } from '@ember/runloop';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit'
import hbs from 'htmlbars-inline-precompile';
import { render, settled } from '@ember/test-helpers';

module('image-size', 'Integration | Component | image-size', function(hooks) {
  setupRenderingTest(hooks);

  test('it works', async function(assert) {
    assert.expect(2);

    await render(hbs`{{image-size src="assets/test-image.jpg"}}`);

    assert.dom(this.element).hasText('loading...');
    await settled(); // yay!
    assert.dom(this.element).hasText("200x350");
  });
});

Using the older test API

The mechanism that ember-concurrency-test-waiter uses to hook into the settled method also works for the old test framework -- moduleForAcceptance tests will automatically wait for withTestWaiter() tasks, and in unit tests (moduleForComponent, etc.), the wait() method (imported from ember-test-helpers) will wait for withTestWaiter() tasks.

ember-concurrency-test-waiter's People

Contributors

musaffa avatar ember-tomster avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.