Upgrade to Pro — share decks privately, control downloads, hide ads and more …

CodeEurope 2017: Testing Against Time - Meaning...

CodeEurope 2017: Testing Against Time - Meaningful Testing in Ember Apps

Testing asynchronous and other time-dependent behaviour in JavaScript applications, following integration and acceptance test examples from an EmberJS application.
Presented at Code Europe 2017 in Krakow, Poland and Warsaw, Poland. Duration: 50min.

Jessy Jordan

December 07, 2017
Tweet

More Decks by Jessy Jordan

Other Decks in Technology

Transcript

  1. WHY DO WE TEST? ! $ App Health: ❓ !

    + > 6 months ❓ BUILDING WITHOUT TESTING ATTRACTS BUGS
  2. TESTING EMBER APPLICATIONS CONVENTION OVER CONFIGURATION + ember g component

    my-component installing component create app/components/my-component.js create app/templates/components/my-component.hbs create tests/integration/components/my-component-test.js A dummy test file for free on every module generated
  3. TESTING EMBER APPLICATIONS CONVENTION OVER CONFIGURATION + ember g component

    my-component // tests/integration/components/my-component-test.js // … test('it renders', function(assert) { // Set any properties with this.set('myProperty', 'value'); // Handle any actions with // this.on(‘myAction’, function(val) { ... }); this.render(hbs`{{my-component}}`); assert.equal(this.$().text().trim(), ''); });
  4. TESTING EMBER APPLICATIONS A MORE FUNCTIONAL APPROACH TO TEST SETUP

    Simplified Ember Testing API RFC (Request for Comments): https://github.com/emberjs/rfcs/blob/master/text/0232-simplify-qunit-testing-api.md import { module, test } from 'qunit'; import { setupRenderingTest } from ‘ember-qunit'; import { render } from ‘ember-test-helpers'; import hbs from 'htmlbars-inline-precompile'; module('x-foo', function(hooks) { setupRenderingTest(hooks); hooks.beforeEach(function() { // custom setup here }); test('renders', async function(assert) { assert.expect(1); await render(hbs`{{pretty-color name="red"}}`); assert.equal(this.$('.color-name').text(), 'red'); }); });
  5. TESTING EMBER APPLICATIONS A FUNCTIONAL APPROACH TO TEST SETUP Simplified

    Ember Testing API RFC (Request for Comments): https://github.com/emberjs/rfcs/blob/master/text/0232-simplify-qunit-testing-api.md import { module, test } from 'qunit'; import { setupRenderingTest } from ‘ember-qunit'; import { render } from ‘ember-test-helpers'; import hbs from 'htmlbars-inline-precompile'; module('x-foo', function(hooks) { setupRenderingTest(hooks); hooks.beforeEach(function() { // custom setup here }); test('renders', async function(assert) { assert.expect(1); await render(hbs`{{pretty-color name="red"}}`); assert.equal(this.$('.color-name').text(), 'red'); }); });
  6. TESTING EMBER APPLICATIONS A FUNCTIONAL APPROACH TO TEST SETUP Simplified

    Ember Testing API RFC (Request for Comments): https://github.com/emberjs/rfcs/blob/master/text/0232-simplify-qunit-testing-api.md import { module, test } from 'qunit'; import { setupRenderingTest } from ‘ember-qunit'; import { render } from ‘ember-test-helpers'; import hbs from 'htmlbars-inline-precompile'; module('x-foo', function(hooks) { setupRenderingTest(hooks); hooks.beforeEach(function() { // custom setup here }); test('renders', async function(assert) { assert.expect(1); await render(hbs`{{pretty-color name="red"}}`); assert.equal(this.$('.color-name').text(), 'red'); }); });
  7. TESTING EMBER APPLICATIONS A FUNCTIONAL APPROACH TO TEST SETUP Simplified

    Ember Testing API RFC (Request for Comments): https://github.com/emberjs/rfcs/blob/master/text/0232-simplify-qunit-testing-api.md import { module, test } from 'qunit'; import { setupRenderingTest } from ‘ember-qunit'; import { render } from ‘ember-test-helpers'; import hbs from 'htmlbars-inline-precompile'; module('x-foo', function(hooks) { setupRenderingTest(hooks); hooks.beforeEach(function() { // custom setup here }); test('renders', async function(assert) { assert.expect(1); await render(hbs`{{pretty-color name="red"}}`); assert.equal(this.$('.color-name').text(), 'red'); }); });
  8. TESTING EMBER APPLICATIONS A FUNCTIONAL APPROACH TO TEST SETUP Simplified

    Ember Testing API RFC (Request for Comments): https://github.com/emberjs/rfcs/blob/master/text/0232-simplify-qunit-testing-api.md import { module, test } from 'qunit'; import { setupRenderingTest } from ‘ember-qunit'; import { render } from ‘ember-test-helpers'; import hbs from 'htmlbars-inline-precompile'; module('x-foo', function(hooks) { setupRenderingTest(hooks); hooks.beforeEach(function() { // custom setup here }); test('renders', async function(assert) { assert.expect(1); await render(hbs`{{pretty-color name="red"}}`); assert.equal(this.$('.color-name').text(), 'red'); }); });
  9. TESTING EMBER APPLICATIONS A FUNCTIONAL APPROACH TO TEST SETUP Simplified

    Ember Testing API RFC (Request for Comments): https://github.com/emberjs/rfcs/blob/master/text/0232-simplify-qunit-testing-api.md import { module, test } from 'qunit'; import { setupRenderingTest } from ‘ember-qunit'; import { render } from ‘ember-test-helpers'; import hbs from 'htmlbars-inline-precompile'; module('x-foo', function(hooks) { setupRenderingTest(hooks); hooks.beforeEach(function() { // custom setup here }); test('renders', async function(assert) { assert.expect(1); await render(hbs`{{pretty-color name="red"}}`); assert.equal(this.$('.color-name').text(), 'red'); }); });
  10. TESTING EMBER APPLICATIONS A FUNCTIONAL APPROACH TO TEST SETUP Simplified

    Ember Testing API RFC (Request for Comments): https://github.com/emberjs/rfcs/blob/master/text/0232-simplify-qunit-testing-api.md import { module, test } from 'qunit'; import { setupRenderingTest } from ‘ember-qunit'; import { render } from ‘ember-test-helpers'; import hbs from 'htmlbars-inline-precompile'; module('x-foo', function(hooks) { setupRenderingTest(hooks); hooks.beforeEach(function() { // custom setup here }); test('renders', async function(assert) { assert.expect(1); await render(hbs`{{pretty-color name="red"}}`); assert.equal(this.$('.color-name').text(), 'red'); }); });
  11. TESTING EMBER APPLICATIONS A FUNCTIONAL APPROACH TO TEST SETUP Simplified

    Ember Testing API RFC (Request for Comments): https://github.com/emberjs/rfcs/blob/master/text/0232-simplify-qunit-testing-api.md import { module, test } from 'qunit'; import { setupRenderingTest } from ‘ember-qunit'; import { render } from ‘ember-test-helpers'; import hbs from 'htmlbars-inline-precompile'; module('x-foo', function(hooks) { setupRenderingTest(hooks); hooks.beforeEach(function() { // custom setup here }); test('renders', async function(assert) { assert.expect(1); await render(hbs`{{pretty-color name="red"}}`); assert.equal(this.$('.color-name').text(), 'red'); }); });
  12. WAITING FOR ASYNCHRONOUS OPERATIONS TESTING ROUTE TRANSITIONS export default Route.extend({

    model() { const store = this.get('store'); const repoFetches = this.get('reposList').map((repo) => { return store.findRecord('github-org', repo); }); return all(repoFetches); }, });
  13. WAITING FOR ASYNCHRONOUS OPERATIONS ASYNC ACCEPTANCE TEST HELPERS: VISIT export

    default function visit(app, url) { let router = app.__container__.lookup('router:main'); app.boot().then(() => { router.location.setURL(url); // ... }); // teardown work return app.testHelpers.wait(); }
  14. WAITING FOR ASYNCHRONOUS OPERATIONS ASYNC ACCEPTANCE TEST HELPERS: VISIT export

    default function visit(app, url) { let router = app.__container__.lookup('router:main'); app.boot().then(() => { router.location.setURL(url); // ... }); // teardown work return app.testHelpers.wait(); }
  15. WAITING FOR ASYNCHRONOUS OPERATIONS test('visiting /overview', function(assert) { visit('overview'); andThen(function()

    { assert.equal(currentURL(), '/overview'); }); }); returns a Promise which fulfills once all async operations have resolved
  16. WAITING FOR ASYNCHRONOUS OPERATIONS test('visiting /overview', function(assert) { visit('overview'); andThen(function()

    { assert.equal(currentURL(), '/overview'); }); }); waits for all previously initiated Promises to resolve
  17. WAITING FOR ASYNCHRONOUS OPERATIONS visit() click() fillIn() keyEvent() triggerEvent() export

    default function visit(app, url){ // … return app.testHelpers.wait(); } BUILT-IN ASYNCHRONOUS HELPERS FOR ACCEPTANCE TESTING
  18. WAITING FOR ASYNCHRONOUS OPERATIONS ANY TIMERS || ANY SCHEDULED ITEMS

    IN RUN LOOP? ANY PENDING REQUESTS? ANY OTHER PENDING WAITERS? repeat each 10 ms wait()
  19. WAITING FOR ASYNCHRONOUS OPERATIONS TESTING ASYNC USER INTERACTIONS import Component

    from '@ember/component'; import { debounce } from '@ember/runloop'; export default Component.extend({ pull: null, actions: { loadComments(pull) { this.set('isLoadingComments', true); debounce(this, this.loadComments, pull, 800); }, }, });
  20. WAITING FOR ASYNCHRONOUS OPERATIONS TESTING ASYNC USER INTERACTIONS import Component

    from '@ember/component'; import { debounce } from '@ember/runloop'; export default Component.extend({ pull: null, comments: null, loadComments(pull) { const commentsUrl = pull.get('commentsUrl'); return this.get(‘request’).fetch(commentsUrl).then((comments) => { this.set('comments', comments); this.set('isLoadingComments', false); }); }, actions: { loadComments(pull) { this.set('isLoadingComments', true); debounce(this, this.loadComments, pull, 800); }, }, });
  21. WAITING FOR ASYNCHRONOUS OPERATIONS TESTING ASYNC USER INTERACTIONS import Component

    from '@ember/component'; import { debounce } from '@ember/runloop'; export default Component.extend({ pull: null, comments: null, loadComments(pull) { const commentsUrl = pull.get('commentsUrl'); return this.get(‘request’).fetch(commentsUrl).then((comments) => { this.set('comments', comments); this.set('isLoadingComments', false); }); }, actions: { loadComments(pull) { this.set('isLoadingComments', true); debounce(this, this.loadComments, pull, 800); }, }, });
  22. WAITING FOR ASYNCHRONOUS OPERATIONS TESTING ASYNC USER INTERACTIONS import Service

    from '@ember/service'; export default Service.extend({ fetch(url) { // ajax request for urls }, });
  23. WAITING FOR ASYNCHRONOUS OPERATIONS module('news-item', function(hooks) { setupRenderingTest(hooks); test(‘loading comments

    via user interaction', async function(assert) { // ember install ember-data-factory-guy this.set('pull', make('github-pull')); await this.render(hbs`{{news-item pull=pull repo=repo}}`); $(‘[data-test-load-comments]').click(); assert.equal($('[data-test-num-of-comments]').text(), `2`, 'displays comments’); } });
  24. WAITING FOR ASYNCHRONOUS OPERATIONS module('news-item', function(hooks) { setupRenderingTest(hooks); test(‘loading comments

    via user interaction', async function(assert) { // ember install ember-data-factory-guy this.set('pull', make('github-pull')); await this.render(hbs`{{news-item pull=pull repo=repo}}`); $(‘[data-test-load-comments]').click(); assert.equal($('[data-test-num-of-comments]').text(), `2`, 'displays comments’); } });
  25. WAITING FOR ASYNCHRONOUS OPERATIONS module(‘news-item‘, function(hooks) { setupRenderingTest(hooks); hooks.beforeEach(function() {

    this.register('service:request', Service.extend({ fetch: td.function(), }); }); test('loading comments via user interaction', async function(assert) { const pull = make(‘github-pull') this.set('pull', pull); this.set('comments', makeList('github-comment', 2)); const commentsUrl = 'https://api.github.com/repos/user1/repository/pulls/1/comments'; td.when(this.get(‘request’).fetch(commentsUrl)) .thenResolve(this.comments); await render(hbs`{{news-item pull=pull repo=repo}}`); $(‘[data-test-load-comments]').click(); assert.equal($(‘[data-test-num-of-comments]’).text().trim(), `2`, 'displays comments'); }); });
  26. WAITING FOR ASYNCHRONOUS OPERATIONS module(‘news-item‘, function(hooks) { setupRenderingTest(hooks); hooks.beforeEach(function() {

    this.register('service:request', Service.extend({ fetch: td.function(), }); }); test('loading comments via user interaction', async function(assert) { const pull = make(‘github-pull') this.set('pull', pull); this.set('comments', makeList('github-comment', 2)); const commentsUrl = 'https://api.github.com/repos/user1/repository/pulls/1/comments'; td.when(this.get(‘request’).fetch(commentsUrl)) .thenResolve(this.comments); await render(hbs`{{news-item pull=pull repo=repo}}`); $(‘[data-test-load-comments]').click(); assert.equal($(‘[data-test-num-of-comments]’).text().trim(), `2`, 'displays comments'); }); });
  27. WAITING FOR ASYNCHRONOUS OPERATIONS module(‘news-item‘, function(hooks) { setupRenderingTest(hooks); hooks.beforeEach(function() {

    this.register('service:request', Service.extend({ fetch: td.function(), }); }); test('loading comments via user interaction', async function(assert) { const pull = make(‘github-pull') this.set('pull', pull); this.set('comments', makeList('github-comment', 2)); const commentsUrl = 'https://api.github.com/repos/user1/repository/pulls/1/comments'; td.when(this.get(‘request’).fetch(commentsUrl)) .thenResolve(this.comments); await render(hbs`{{news-item pull=pull repo=repo}}`); $(‘[data-test-load-comments]').click(); assert.equal($(‘[data-test-num-of-comments]’).text().trim(), `2`, 'displays comments'); }); });
  28. WAITING FOR ASYNCHRONOUS OPERATIONS app/services/request.js tests/integration/components/news-item-test.js import Service from '@ember/component';

    export default Service.extend({ fetch(url) { // ajax request for urls }, }); const requestStub = Service.extend({ fetch: td.function(); });
  29. WAITING FOR ASYNCHRONOUS OPERATIONS const requestStub = Service.extend({ fetch: td.function();

    }); td.when(this.get(‘requestStub’) .fetch(commentsUrl)) .thenResolve(this.comments); loadComments(pull) { const commentsUrl = pull.get('commentsUrl'); return this.get(‘request’) .fetch(commentsUrl) .then((comments) => { this.set('comments', comments); this.set('isLoadingComments', false); }); }, app/components/news-item.js tests/integration/components/news-item-test.js
  30. WAITING FOR ASYNCHRONOUS OPERATIONS test('loading comments via user interaction', async

    function(assert) { const pull = make(‘github-pull') this.set('pull', pull); this.set('comments', makeList('github-comment', 2)); const commentsUrl = 'https://api.github.com/repos/user1/repository/pulls/1/comments'; td.when(this.get(‘request’) .fetch(commentsUrl)) .thenResolve(this.comments); await render(hbs`{{news-item pull=pull repo=repo}}`); $(‘[data-test-load-comments]’).click(); assert.equal($('[data-test-num-of-comments]').text(), `2`, 'displays comments'); });
  31. WAITING FOR ASYNCHRONOUS OPERATIONS import { wait } from 'ember-test-helpers/wait';

    test('loading comments via user interaction', async function(assert) { const pull = make(‘github-pull') this.set('pull', pull); this.set('comments', makeList('github-comment', 2)); const commentsUrl = 'https://api.github.com/repos/user1/repository/pulls/1/comments'; td.when(this.get(‘request’).fetch(commentsUrl)) .thenResolve(this.comments); await render(hbs`{{news-item pull=pull repo=repo}}`); $('[data-test-load-comments]').click(); return wait().then(() => { assert.equal($('[data-test-num-of-comments]').text(), `2`, 'displays comments'); }); });
  32. WAITING FOR ASYNCHRONOUS OPERATIONS import { wait } from 'ember-test-helpers/wait';

    test('loading comments via user interaction', await function(assert) { const pull = make(‘github-pull') this.set('pull', pull); this.set('comments', makeList('github-comment', 2)); const commentsUrl = 'https://api.github.com/repos/user1/repository/pulls/1/comments'; td.when(this.get(‘request’).fetch(commentsUrl)) .thenResolve(this.comments); await render(hbs`{{news-item pull=pull repo=repo}}`); $('[data-test-load-comments]').click(); return wait().then(() => { assert.equal($('[data-test-num-of-comments]').text(), `2`, 'displays comments'); }); });
  33. WAITING FOR ASYNCHRONOUS OPERATIONS await fillIn() await click() await keyEvent()

    await triggerEvent() await focus() await blur() await tap() EMBER-NATIVE-DOM-HELPERS & AWAIT / ASYNC SUITABLE FOR BOTH YOUR ACCEPTANCE & INTEGRATION TESTS
  34. WAITING FOR ASYNCHRONOUS OPERATIONS import { click } from 'ember-native-dom-helpers';

    test('loading comments via user interaction', async function(assert) { this.set('pull', make('github-pull')); this.set('comments', makeList('github-comment', 2)); const commentsUrl = 'https://api.github.com/repos/user1/repository/pulls/1/comments'; td.when(this.get(‘request’).fetch(commentsUrl)) .thenResolve(this.comments); await render(hbs`{{news-item pull=pull repo=repo}}`); await click(‘[data-test-load-comments]’); assert.equal($('[data-test-num-of-comments]').text(), `2`, 'displays comments'); });
  35. WAITING FOR ASYNCHRONOUS OPERATIONS HANDLING ASYNC BEHAVIOUR WITH EMBER-CONCURRENCY Alex

    Matchneer: ember-concurrency: the solution to so many problems you never knew you had: https://emberway.io/ember-concurrency-the-solution-to-so-many-problems-you-never-knew-you-had-cce6d7731ba9
  36. WAITING FOR ASYNCHRONOUS OPERATIONS export default Component.extend({ //… reloadComments: task(function

    * () { const commentsUrl = this.get('pull.commentsUrl'); const comments = yield this.get(‘request’) .fetch(this.get(‘pull.commentsUrl’)); this.set('comments', comments); }).drop(), }); GENERATOR FUNCTIONS WITH EMBER-CONCURRENCY
  37. WAITING FOR ASYNCHRONOUS OPERATIONS export default Component.extend({ startReloading: task(function *(){

    while(true) { this.get(‘reloadComments').perform(); yield timeout(50000); }, reloadComments: task(function * () { const commentsUrl = this.get('pull.commentsUrl'); const comments = yield this.get(‘request’) .fetch(this.get(‘pull.commentsUrl’)); this.set('comments', comments); }).drop(), });
  38. WAITING FOR ASYNCHRONOUS OPERATIONS td.when(this.get(‘request’) .fetch(commentsUrl)) .thenResolve(this.comments); await this.render(hbs`{{news-item pull=pull

    repo=repo}}`); return wait().then(() => { assert.equal(find('[data-test-num-of-comments]').textContent.trim(), `2`, 'displays comments'); });
  39. WAITING FOR ASYNCHRONOUS OPERATIONS await render(hbs`{{news-item pull=pull repo=repo}}`); later(() =>

    { run.cancelTimers(); }, 500); return wait().then(() => { assert.equal(find('[data-test-num-of-comments]').textContent.trim(), `2`, 'displays comments'); });
  40. WAITING FOR ASYNCHRONOUS OPERATIONS await render(hbs`{{news-item pull=pull repo=repo}}`); later(() =>

    { run.cancelTimers(); }, 500); return wait().then(() => { assert.equal(find('[data-test-num-of-comments]').textContent.trim(), `2`, 'displays comments'); });
  41. WAITING FOR ASYNCHRONOUS OPERATIONS await render(hbs`{{news-item pull=pull repo=repo}}`); later(() =>

    { run.cancelTimers(); }, 500); return wait().then(() => { assert.equal(find('[data-test-num-of-comments]').textContent.trim(), `2`, 'displays comments'); });
  42. WAITING FOR ASYNCHRONOUS OPERATIONS await render(hbs`{{news-item pull=pull repo=repo}}`); later(() =>

    { run.cancelTimers(); }, 500); return wait().then(() => { assert.equal(find('[data-test-num-of-comments]').textContent.trim(), `2`, 'displays comments'); });
  43. WAITING FOR ASYNCHRONOUS OPERATIONS await render(hbs`{{news-item pull=pull repo=repo}}`); later(() =>

    { run.cancelTimers(); }, 500000); return wait().then(() => { assert.equal(find('[data-test-num-of-comments]').textContent.trim(), `2`, 'displays comments'); });
  44. WAITING FOR ASYNCHRONOUS OPERATIONS const TIMEOUT_INTERVAL = Ember.testing ? 1

    : 500000; //… startReloading: task(function *(){ while(true) { yield timeout(TIMEOUT_INTERVAL); this.get(‘reloadComments').perform(); } }
  45. WAITING FOR ASYNCHRONOUS OPERATIONS await render(hbs`{{news-item pull=pull repo=repo}}`); later(() =>

    { run.cancelTimers(); }, 500000); return wait().then(() => { assert.equal(find('[data-test-num-of-comments]').textContent.trim(), `2`, 'displays comments'); });
  46. WAITING FOR ASYNCHRONOUS OPERATIONS await render(hbs`{{news-item pull=pull repo=repo}}`); later(() =>

    { run.cancelTimers(); }, 50); return wait().then(() => { assert.equal(find('[data-test-num-of-comments]').textContent.trim(), `2`, 'displays comments'); });
  47. await render(hbs`{{news-item pull=pull repo=repo}}`); later(() => { run.cancelTimers(); }, 50);

    return wait().then(() => { assert.equal(find('[data-test-num-of-comments]').textContent.trim(), `2`, 'displays comments'); });
  48. WAITING FOR ASYNCHRONOUS OPERATIONS FURTHER READING Ember Concurrency Docs on

    Testing: https://ember-concurrency.com/#/docs/testing-debugging Ember Testing Unificationn RFC: https://github.com/emberjs/rfcs/pull/119
  49. WAITING FOR ASYNCHRONOUS OPERATIONS test('the overview page doesn\'t stress me

    out with release date disclaimers', function(assert) { visit('/overview'); andThen(function() { assert.notOk(find('[data-test-is-thursday-disclaimer]'), 'doesn\'t display Thu disclaimer'); assert.notOk(find('[data-test-is-friday-disclaimer]'), 'doesn\'t display Fri disclaimer'); }); });
  50. WAITING FOR ASYNCHRONOUS OPERATIONS test('the overview page doesn\'t stress me

    out with release date disclaimers', function(assert) { visit('/overview'); andThen(function() { assert.notOk(find('[data-test-is-thursday-disclaimer]'), 'doesn\'t display Thu disclaimer'); assert.notOk(find('[data-test-is-friday-disclaimer]'), 'doesn\'t display Fri disclaimer'); }); });
  51. WAITING FOR ASYNCHRONOUS OPERATIONS moduleForAcceptance('Acceptance | overview', { beforeEach() Timecop.install();

    Timecop.travel(new Date(2017, 9, 11, 11, 45)); }, afterEach(){ Timecop.uninstall(); } }); EMBER INSTALL EMBER-CLI-TIMECOP
  52. WAITING FOR ASYNCHRONOUS OPERATIONS test('the overview page doesn\'t stress me

    out with release date disclaimers', function(assert) { visit('/overview'); andThen(function() { assert.notOk(find('[data-test-is-thursday-disclaimer]'), 'doesn\'t display Thursday disclaimer'); assert.notOk(find('[data-test-is-friday-disclaimer]'), 'doesn\'t display Friday disclaimer'); }); }); moduleForAcceptance('Acceptance | overview', { beforeEach() Timecop.install(); Timecop.travel(new Date(2017, 9, 11, 11, 45)); // is a Wednesday: 11.10.2017 }, afterEach(){ Timecop.uninstall(); } });
  53. WAITING FOR ASYNCHRONOUS OPERATIONS test('the overview page doesn\'t stress me

    out with release date disclaimers', function(assert) { visit('/overview'); andThen(function() { assert.notOk(find('[data-test-is-thursday-disclaimer]'), 'doesn\'t display Thursday disclaimer'); assert.notOk(find('[data-test-is-friday-disclaimer]'), 'doesn\'t display Friday disclaimer'); }); }); moduleForAcceptance('Acceptance | overview', { beforeEach() Timecop.install(); Timecop.travel(new Date(2017, 9, 11, 11, 45)); // is a Wednesday: 11.10.2017 }, afterEach(){ Timecop.uninstall(); } });
  54. WAITING FOR ASYNCHRONOUS OPERATIONS test('the overview page doesn\'t stress me

    out with release date disclaimers', function(assert) { visit('/overview'); andThen(function() { assert.notOk(find('[data-test-is-thursday-disclaimer]'), 'doesn\'t display Thursday disclaimer'); assert.notOk(find('[data-test-is-friday-disclaimer]'), 'doesn\'t display Friday disclaimer'); }); }); moduleForAcceptance('Acceptance | overview', { beforeEach() Timecop.install(); Timecop.travel(new Date(2017, 9, 11, 11, 45)); // is a Wednesday: 11.10.2017 }, afterEach(){ Timecop.uninstall(); } });
  55. WAITING FOR ASYNCHRONOUS OPERATIONS test('the overview page doesn\'t stress me

    out with release date disclaimers', function(assert) { visit('/overview'); andThen(function() { assert.notOk(find('[data-test-is-thursday-disclaimer]'), 'doesn\'t display Thursday disclaimer'); assert.notOk(find('[data-test-is-friday-disclaimer]'), 'doesn\'t display Friday disclaimer'); }); }); moduleForAcceptance('Acceptance | overview', { beforeEach() Timecop.install(); Timecop.travel(new Date(2017, 9, 11, 11, 45)); // is a Wednesday: 11.10.2017 }, afterEach(){ Timecop.uninstall(); } });
  56. WAITING FOR ASYNCHRONOUS OPERATIONS test('the overview page…oh no, it’s Friday’,

    function(assert) { Timecop.travel(new Date(2017, 9, 13, 16, 20)); // is a Friday visit('/overview'); andThen(function() { assert.notOk(find('[data-test-is-thursday-disclaimer]'), 'doesn\'t display Thursday disclaimer'); assert.ok(find('[data-test-is-friday-disclaimer]'), ‘the newsletter has to get out - oh no!’); }); });
  57. WAITING FOR ASYNCHRONOUS OPERATIONS test('the overview page…oh no, it’s Friday’,

    function(assert) { Timecop.travel(new Date(2017, 9, 13, 16, 20)); // is a Friday visit('/overview'); andThen(function() { assert.notOk(find('[data-test-is-thursday-disclaimer]'), 'doesn\'t display Thursday disclaimer'); assert.ok(find('[data-test-is-friday-disclaimer]'), ‘the newsletter has to get out - oh no!’); }); });
  58. WAITING FOR ASYNCHRONOUS OPERATIONS test('the overview page…oh no, it’s Friday’,

    function(assert) { Timecop.travel(new Date(2017, 9, 13, 16, 20)); // is a Friday visit('/overview'); andThen(function() { assert.notOk(find('[data-test-is-thursday-disclaimer]'), 'doesn\'t display Thursday disclaimer'); assert.ok(find('[data-test-is-friday-disclaimer]'), ‘the newsletter has to get out - oh no!’); }); });
  59. WAITING FOR ASYNCHRONOUS OPERATIONS test('the overview page…oh no, it’s Friday’,

    function(assert) { Timecop.travel(new Date(2017, 9, 13, 16, 20)); // is a Friday visit('/overview'); andThen(function() { assert.notOk(find('[data-test-is-thursday-disclaimer]'), 'doesn\'t display Thursday disclaimer'); assert.ok(find('[data-test-is-friday-disclaimer]'), ‘the newsletter has to get out - oh no!’); }); });