ember-pausable-test v0.4.1
ember-pausable-test
This library provides a set of tools to pause async behavior in your tests to make it easier to assert intermediate state.
Usage
Installation
ember install ember-pausable-test
Acceptance Test
Suppose that we had a maybe-slow-loading route that rendered a loading template, with a model hook that looks like:
import Route from '@ember/routing/route';
export default Route.extend({
model({ id }) {
return this.store.find('friends', id);
}
})And, an acceptance test that looked something like this:
it('shows a friend', async function(assert) {
visit('/friends/1');
// Where do we assert this!?!
// assert.ok(find('.loading-spinner').length, 'loading screen visible!');
await andThen(() => {});
assert.ok(find('.friend-name').text().trim(), 'Steve');
});If we were to uncomment the assert that checks for the loading spinner, it's possible that it has rendered by then; but not necessarily a guarantee. (This could lead to a flaky test!)
Instead, with this library, we can explicitly pause the model hook so we can test the loading state.
import Route from '@ember/routing/route';
import { pausable } from 'ember-pausable-test';
export default Route.extend({
model({ id }) {
const friend = this.store.find('friends', id);
return pausable(friend, 'friend-promise');
}
})And, in our test:
(note: You should always call reset() in the afterEach hook when using pauseOn)
import { pauseOn, reset } from 'ember-pausable-test/test-support';
moduleForAcceptance('Acceptance | friend', {
afterEach() {
reset();
}
});
it('shows a friend', async function(assert) {
const { resume, awaitPause } = pauseOn('friend-promise');
visit('/friends/1');
await awaitPause();
assert.ok(find('.loading-spinner').length, 'loading screen visible!');
resume();
await andThen(() => {});
assert.ok(find('.friend-name').text().trim(), 'Steve');
});With ember-concurrecncy
Let's imagine a component that, when it renders, it pushes items onto a list every second.
There are two things I'd like to think about when testing this component:
- I want to test each step of the state as it changes
- I want the test to run fast (no need to wait a second between each step)
The component may look something like this:
export default Component.extend({
didInsertElement() {
set(this, 'objects', A([]));
get(this, 'myTask').perform();
},
myTask: task(function *() {
const objects = get(this, 'objects');
const waitTime = testing ? 0 : 1000;
let idx = -1;
while (++idx < 5) {
objects.pushObject({ name: `Step ${idx}` });
yield timeout(waitTime);
}
})
});<ul>
{{#each objects as |object|}}
<li>{{object.name}}</li>
{{/each}}
</ul>By replacing the yield statement with...
yield pausable(timeout(waitTime), 'state-progressor');...we can setup our integration test like this:
import { pauseOn } from 'ember-pausable-test/test-support';
import wait from 'ember-test-helpers/wait';
test('it renders each of the steps', async function(assert) {
const { resume, awaitPause } = pauseOn('state-progressor');
this.render(hbs`{{state-progressor}}`);
await awaitPause();
assert.equal(this.$('ul > li').length, 1);
resume();
await awaitPause();
assert.equal(this.$('ul > li').length, 2);
resume();
await awaitPause();
assert.equal(this.$('ul > li').length, 3);
resume();
await awaitPause();
assert.equal(this.$('ul > li').length, 4);
resume();
await wait();
assert.equal(this.$('ul > li').length, 5);
});API
ember-pausable-test
pausable(yieldable: Any, tokenName: String)In a test environment and when apauseOnis registered with the giventokenName, this method will return a promise that resolves whenpauseOn(tokenName).resume()is called and resolves with theyieldable.In non-test environments, or when there is no
pauseOnregistered, this will return theyieldabledirectly.
ember-pausable-test/test-support
pauseOn(tokenName: String)This regsiters a pause to happen when a correspondingpausableis reached in the code.This method returns a
PauseToken.PauseTokenresume()This will resolve the promise that is pausing the promise chain.awaitPause()This returns a promise that will resolve the next time the correspondingpausable()block is hit.throwException()This will cause the paused promise to reject, instead of resolve.
Configuration
Experimental support for unwrappping/removing pausable() calls in non-test builds can be used by modifying your ember-cli-build.js file:
const app = new EmberApp({
'ember-pausable-test': {
strip: true
}
});Collaborating
Running
ember serve- Visit your app at http://localhost:4200.
Running Tests
yarn test(Runsember try:eachto test your addon against multiple Ember versions)ember testember test --server
Building
ember build
For more information on using ember-cli, visit https://ember-cli.com/.
Releasing
ember release {--minor, --major, --patch}