import { moduleFor, AutobootApplicationTestCase, isIE11 } from 'internal-test-helpers'; import { Route } from '@ember/-internals/routing'; import Controller from '@ember/controller'; import { RSVP } from '@ember/-internals/runtime'; import { later } from '@ember/runloop'; import { Component } from '@ember/-internals/glimmer'; import { jQueryDisabled, jQuery } from '@ember/-internals/views'; import Test from '../lib/test'; import setupForTesting from '../lib/setup_for_testing'; import { pendingRequests, incrementPendingRequests, decrementPendingRequests, clearPendingRequests, } from '../lib/test/pending_requests'; import { setAdapter, getAdapter } from '../lib/test/adapter'; import { registerWaiter, unregisterWaiter } from '../lib/test/waiters'; import { getDebugFunction, setDebugFunction } from '@ember/debug'; var originalInfo = getDebugFunction('info'); var noop = function() {}; function registerHelper() { Test.registerHelper('LeakyMcLeakLeak', () => {}); } function assertHelpers(assert, application, helperContainer, expected) { if (!helperContainer) { helperContainer = window; } if (expected === undefined) { expected = true; } function checkHelperPresent(helper, expected) { var presentInHelperContainer = !!helperContainer[helper]; var presentInTestHelpers = !!application.testHelpers[helper]; assert.ok( presentInHelperContainer === expected, "Expected '" + helper + "' to be present in the helper container (defaults to window)." ); assert.ok( presentInTestHelpers === expected, "Expected '" + helper + "' to be present in App.testHelpers." ); } checkHelperPresent('visit', expected); checkHelperPresent('click', expected); checkHelperPresent('keyEvent', expected); checkHelperPresent('fillIn', expected); checkHelperPresent('wait', expected); checkHelperPresent('triggerEvent', expected); } function assertNoHelpers(assert, application, helperContainer) { assertHelpers(assert, application, helperContainer, false); } class HelpersTestCase extends AutobootApplicationTestCase { constructor() { super(); this._originalAdapter = getAdapter(); } teardown() { setAdapter(this._originalAdapter); document.removeEventListener('ajaxSend', incrementPendingRequests); document.removeEventListener('ajaxComplete', decrementPendingRequests); clearPendingRequests(); if (this.application) { this.application.removeTestHelpers(); } super.teardown(); } } class HelpersApplicationTestCase extends HelpersTestCase { constructor() { super(); this.runTask(() => { this.createApplication(); this.application.setupForTesting(); this.application.injectTestHelpers(); }); } } if (!jQueryDisabled) { moduleFor( 'ember-testing: Helper setup', class extends HelpersTestCase { [`@test Ember.Application#injectTestHelpers/#removeTestHelper`](assert) { this.runTask(() => { this.createApplication(); }); assertNoHelpers(assert, this.application); registerHelper(); this.application.injectTestHelpers(); assertHelpers(assert, this.application); assert.ok(Test.Promise.prototype.LeakyMcLeakLeak, 'helper in question SHOULD be present'); this.application.removeTestHelpers(); assertNoHelpers(assert, this.application); assert.equal( Test.Promise.prototype.LeakyMcLeakLeak, undefined, 'should NOT leak test promise extensions' ); } [`@test Ember.Application#setupForTesting`](assert) { this.runTask(() => { this.createApplication(); this.application.setupForTesting(); }); let routerInstance = this.applicationInstance.lookup('router:main'); assert.equal(routerInstance.location, 'none'); } [`@test Ember.Application.setupForTesting sets the application to 'testing'`](assert) { this.runTask(() => { this.createApplication(); this.application.setupForTesting(); }); assert.equal(this.application.testing, true, 'Application instance is set to testing.'); } [`@test Ember.Application.setupForTesting leaves the system in a deferred state.`](assert) { this.runTask(() => { this.createApplication(); this.application.setupForTesting(); }); assert.equal( this.application._readinessDeferrals, 1, 'App is in deferred state after setupForTesting.' ); } [`@test App.reset() after Application.setupForTesting leaves the system in a deferred state.`]( assert ) { this.runTask(() => { this.createApplication(); this.application.setupForTesting(); }); assert.equal( this.application._readinessDeferrals, 1, 'App is in deferred state after setupForTesting.' ); this.application.reset(); assert.equal( this.application._readinessDeferrals, 1, 'App is in deferred state after setupForTesting.' ); } [`@test Ember.Application#injectTestHelpers calls callbacks registered with onInjectHelpers`]( assert ) { let injected = 0; Test.onInjectHelpers(() => { injected++; }); // bind(this) so Babel doesn't leak _this // into the context onInjectHelpers. this.runTask( function() { this.createApplication(); this.application.setupForTesting(); }.bind(this) ); assert.equal(injected, 0, 'onInjectHelpers are not called before injectTestHelpers'); this.application.injectTestHelpers(); assert.equal(injected, 1, 'onInjectHelpers are called after injectTestHelpers'); } [`@test Ember.Application#injectTestHelpers adds helpers to provided object.`](assert) { let helpers = {}; this.runTask(() => { this.createApplication(); this.application.setupForTesting(); }); this.application.injectTestHelpers(helpers); assertHelpers(assert, this.application, helpers); this.application.removeTestHelpers(); assertNoHelpers(assert, this.application, helpers); } [`@test Ember.Application#removeTestHelpers resets the helperContainer\'s original values`]( assert ) { let helpers = { visit: 'snazzleflabber' }; this.runTask(() => { this.createApplication(); this.application.setupForTesting(); }); this.application.injectTestHelpers(helpers); assert.notEqual(helpers.visit, 'snazzleflabber', 'helper added to container'); this.application.removeTestHelpers(); assert.equal(helpers.visit, 'snazzleflabber', 'original value added back to container'); } } ); moduleFor( 'ember-testing: Helper methods', class extends HelpersApplicationTestCase { [`@test 'wait' respects registerWaiters`](assert) { assert.expect(3); let counter = 0; function waiter() { return ++counter > 2; } let other = 0; function otherWaiter() { return ++other > 2; } this.runTask(() => { this.application.advanceReadiness(); }); registerWaiter(waiter); registerWaiter(otherWaiter); let { application: { testHelpers } } = this; return testHelpers .wait() .then(() => { assert.equal(waiter(), true, 'should not resolve until our waiter is ready'); unregisterWaiter(waiter); counter = 0; return testHelpers.wait(); }) .then(() => { assert.equal(counter, 0, 'unregistered waiter was not checked'); assert.equal(otherWaiter(), true, 'other waiter is still registered'); }) .finally(() => { unregisterWaiter(otherWaiter); }); } [`@test 'visit' advances readiness.`](assert) { assert.expect(2); assert.equal( this.application._readinessDeferrals, 1, 'App is in deferred state after setupForTesting.' ); return this.application.testHelpers.visit('/').then(() => { assert.equal( this.application._readinessDeferrals, 0, `App's readiness was advanced by visit.` ); }); } [`@test 'wait' helper can be passed a resolution value`](assert) { assert.expect(4); this.runTask(() => { this.application.advanceReadiness(); }); let promiseObjectValue = {}; let objectValue = {}; let { application: { testHelpers } } = this; return testHelpers .wait('text') .then(val => { assert.equal(val, 'text', 'can resolve to a string'); return testHelpers.wait(1); }) .then(val => { assert.equal(val, 1, 'can resolve to an integer'); return testHelpers.wait(objectValue); }) .then(val => { assert.equal(val, objectValue, 'can resolve to an object'); return testHelpers.wait(RSVP.resolve(promiseObjectValue)); }) .then(val => { assert.equal(val, promiseObjectValue, 'can resolve to a promise resolution value'); }); } [`@test 'click' triggers appropriate events in order`](assert) { assert.expect(5); this.add( 'component:index-wrapper', Component.extend({ classNames: 'index-wrapper', didInsertElement() { let wrapper = document.querySelector('.index-wrapper'); wrapper.addEventListener('mousedown', e => events.push(e.type)); wrapper.addEventListener('mouseup', e => events.push(e.type)); wrapper.addEventListener('click', e => events.push(e.type)); wrapper.addEventListener('focusin', e => { // IE11 _sometimes_ triggers focusin **twice** in a row // (we believe this is when it is under higher load) // // the goal here is to only push a single focusin when running on // IE11 if (isIE11) { if (events[events.length - 1] !== 'focusin') { events.push(e.type); } } else { events.push(e.type); } }); }, }) ); this.add( 'component:x-checkbox', Component.extend({ tagName: 'input', attributeBindings: ['type'], type: 'checkbox', click() { events.push('click:' + this.get('checked')); }, change() { events.push('change:' + this.get('checked')); }, }) ); this.addTemplate( 'index', ` {{#index-wrapper}} {{input type="text"}} {{x-checkbox type="checkbox"}} {{textarea}}
{{/index-wrapper}}')); ` ); this.runTask(() => { this.application.advanceReadiness(); }); let events; let { application: { testHelpers } } = this; return testHelpers .wait() .then(() => { events = []; return testHelpers.click('.index-wrapper'); }) .then(() => { assert.deepEqual(events, ['mousedown', 'mouseup', 'click'], 'fires events in order'); }) .then(() => { events = []; return testHelpers.click('.index-wrapper input[type=text]'); }) .then(() => { assert.deepEqual( events, ['mousedown', 'focusin', 'mouseup', 'click'], 'fires focus events on inputs' ); }) .then(() => { events = []; return testHelpers.click('.index-wrapper textarea'); }) .then(() => { assert.deepEqual( events, ['mousedown', 'focusin', 'mouseup', 'click'], 'fires focus events on textareas' ); }) .then(() => { events = []; return testHelpers.click('.index-wrapper div'); }) .then(() => { assert.deepEqual( events, ['mousedown', 'focusin', 'mouseup', 'click'], 'fires focus events on contenteditable' ); }) .then(() => { events = []; return testHelpers.click('.index-wrapper input[type=checkbox]'); }) .then(() => { // i.e. mousedown, mouseup, change:true, click, click:true // Firefox differs so we can't assert the exact ordering here. // See https://bugzilla.mozilla.org/show_bug.cgi?id=843554. assert.equal(events.length, 5, 'fires click and change on checkboxes'); }); } [`@test 'click' triggers native events with simulated X/Y coordinates`](assert) { assert.expect(15); this.add( 'component:index-wrapper', Component.extend({ classNames: 'index-wrapper', didInsertElement() { let pushEvent = e => events.push(e); this.element.addEventListener('mousedown', pushEvent); this.element.addEventListener('mouseup', pushEvent); this.element.addEventListener('click', pushEvent); }, }) ); this.addTemplate( 'index', ` {{#index-wrapper}}some text{{/index-wrapper}} ` ); this.runTask(() => { this.application.advanceReadiness(); }); let events; let { application: { testHelpers: { wait, click } } } = this; return wait() .then(() => { events = []; return click('.index-wrapper'); }) .then(() => { events.forEach(e => { assert.ok(e instanceof window.Event, 'The event is an instance of MouseEvent'); assert.ok(typeof e.screenX === 'number', 'screenX is correct'); assert.ok(typeof e.screenY === 'number', 'screenY is correct'); assert.ok(typeof e.clientX === 'number', 'clientX is correct'); assert.ok(typeof e.clientY === 'number', 'clientY is correct'); }); }); } [`@test 'triggerEvent' with mouseenter triggers native events with simulated X/Y coordinates`]( assert ) { assert.expect(5); let evt; this.add( 'component:index-wrapper', Component.extend({ classNames: 'index-wrapper', didInsertElement() { this.element.addEventListener('mouseenter', e => (evt = e)); }, }) ); this.addTemplate('index', `{{#index-wrapper}}some text{{/index-wrapper}}`); this.runTask(() => { this.application.advanceReadiness(); }); let { application: { testHelpers: { wait, triggerEvent } } } = this; return wait() .then(() => { return triggerEvent('.index-wrapper', 'mouseenter'); }) .then(() => { assert.ok(evt instanceof window.Event, 'The event is an instance of MouseEvent'); assert.ok(typeof evt.screenX === 'number', 'screenX is correct'); assert.ok(typeof evt.screenY === 'number', 'screenY is correct'); assert.ok(typeof evt.clientX === 'number', 'clientX is correct'); assert.ok(typeof evt.clientY === 'number', 'clientY is correct'); }); } [`@test 'wait' waits for outstanding timers`](assert) { assert.expect(1); this.runTask(() => { this.application.advanceReadiness(); }); let waitDone = false; later(() => { waitDone = true; }, 20); return this.application.testHelpers.wait().then(() => { assert.equal(waitDone, true, 'should wait for the timer to be fired.'); }); } [`@test 'wait' respects registerWaiters with optional context`](assert) { assert.expect(3); let obj = { counter: 0, ready() { return ++this.counter > 2; }, }; let other = 0; function otherWaiter() { return ++other > 2; } this.runTask(() => { this.application.advanceReadiness(); }); registerWaiter(obj, obj.ready); registerWaiter(otherWaiter); let { application: { testHelpers: { wait } } } = this; return wait() .then(() => { assert.equal(obj.ready(), true, 'should not resolve until our waiter is ready'); unregisterWaiter(obj, obj.ready); obj.counter = 0; return wait(); }) .then(() => { assert.equal(obj.counter, 0, 'the unregistered waiter should still be at 0'); assert.equal(otherWaiter(), true, 'other waiter should still be registered'); }) .finally(() => { unregisterWaiter(otherWaiter); }); } [`@test 'wait' does not error if routing has not begun`](assert) { assert.expect(1); return this.application.testHelpers.wait().then(() => { assert.ok(true, 'should not error without `visit`'); }); } [`@test 'triggerEvent' accepts an optional options hash without context`](assert) { assert.expect(3); let event; this.add( 'component:index-wrapper', Component.extend({ didInsertElement() { let domElem = document.querySelector('.input'); domElem.addEventListener('change', e => (event = e)); domElem.addEventListener('keydown', e => (event = e)); }, }) ); this.addTemplate('index', `{{index-wrapper}}`); this.addTemplate( 'components/index-wrapper', ` {{input type="text" id="scope" class="input"}} ` ); this.runTask(() => { this.application.advanceReadiness(); }); let { application: { testHelpers: { wait, triggerEvent } } } = this; return wait() .then(() => { return triggerEvent('.input', 'keydown', { keyCode: 13 }); }) .then(() => { assert.equal(event.keyCode, 13, 'options were passed'); assert.equal(event.type, 'keydown', 'correct event was triggered'); assert.equal( event.target.getAttribute('id'), 'scope', 'triggered on the correct element' ); }); } [`@test 'triggerEvent' can limit searching for a selector to a scope`](assert) { assert.expect(2); let event; this.add( 'component:index-wrapper', Component.extend({ didInsertElement() { let firstInput = document.querySelector('.input'); firstInput.addEventListener('blur', e => (event = e)); firstInput.addEventListener('change', e => (event = e)); let secondInput = document.querySelector('#limited .input'); secondInput.addEventListener('blur', e => (event = e)); secondInput.addEventListener('change', e => (event = e)); }, }) ); this.addTemplate( 'components/index-wrapper', ` {{input type="text" id="outside-scope" class="input"}}
{{input type="text" id="inside-scope" class="input"}}
` ); this.addTemplate('index', `{{index-wrapper}}`); this.runTask(() => { this.application.advanceReadiness(); }); let { application: { testHelpers: { wait, triggerEvent } } } = this; return wait() .then(() => { return triggerEvent('.input', '#limited', 'blur'); }) .then(() => { assert.equal(event.type, 'blur', 'correct event was triggered'); assert.equal( event.target.getAttribute('id'), 'inside-scope', 'triggered on the correct element' ); }); } [`@test 'triggerEvent' can be used to trigger arbitrary events`](assert) { assert.expect(2); let event; this.add( 'component:index-wrapper', Component.extend({ didInsertElement() { let foo = document.getElementById('foo'); foo.addEventListener('blur', e => (event = e)); foo.addEventListener('change', e => (event = e)); }, }) ); this.addTemplate( 'components/index-wrapper', ` {{input type="text" id="foo"}} ` ); this.addTemplate('index', `{{index-wrapper}}`); this.runTask(() => { this.application.advanceReadiness(); }); let { application: { testHelpers: { wait, triggerEvent } } } = this; return wait() .then(() => { return triggerEvent('#foo', 'blur'); }) .then(() => { assert.equal(event.type, 'blur', 'correct event was triggered'); assert.equal( event.target.getAttribute('id'), 'foo', 'triggered on the correct element' ); }); } [`@test 'fillIn' takes context into consideration`](assert) { assert.expect(2); this.addTemplate( 'index', `
{{input type="text" id="first" class="current"}}
{{input type="text" id="second" class="current"}} ` ); this.runTask(() => { this.application.advanceReadiness(); }); let { application: { testHelpers: { visit, fillIn, andThen, find } } } = this; visit('/'); fillIn('.current', '#parent', 'current value'); return andThen(() => { assert.equal(find('#first')[0].value, 'current value'); assert.equal(find('#second')[0].value, ''); }); } [`@test 'fillIn' focuses on the element`](assert) { let wasFocused = false; this.add( 'controller:index', Controller.extend({ actions: { wasFocused() { wasFocused = true; }, }, }) ); this.addTemplate( 'index', `
{{input type="text" id="first" focus-in=(action "wasFocused")}}
' ` ); this.runTask(() => { this.application.advanceReadiness(); }); let { application: { testHelpers: { visit, fillIn, andThen, find, wait } } } = this; visit('/'); fillIn('#first', 'current value'); andThen(() => { assert.ok(wasFocused, 'focusIn event was triggered'); assert.equal(find('#first')[0].value, 'current value'); }); return wait(); } [`@test 'fillIn' fires 'input' and 'change' events in the proper order`](assert) { assert.expect(1); let events = []; this.add( 'controller:index', Controller.extend({ actions: { oninputHandler(e) { events.push(e.type); }, onchangeHandler(e) { events.push(e.type); }, }, }) ); this.addTemplate( 'index', ` ` ); this.runTask(() => { this.application.advanceReadiness(); }); let { application: { testHelpers: { visit, fillIn, andThen, wait } } } = this; visit('/'); fillIn('#first', 'current value'); andThen(() => { assert.deepEqual( events, ['input', 'change'], '`input` and `change` events are fired in the proper order' ); }); return wait(); } [`@test 'fillIn' only sets the value in the first matched element`](assert) { this.addTemplate( 'index', ` ` ); this.runTask(() => { this.application.advanceReadiness(); }); let { application: { testHelpers: { visit, fillIn, find, andThen, wait } } } = this; visit('/'); fillIn('input.in-test', 'new value'); andThen(() => { assert.equal(find('#first')[0].value, 'new value'); assert.equal(find('#second')[0].value, ''); }); return wait(); } [`@test 'triggerEvent' accepts an optional options hash and context`](assert) { assert.expect(3); let event; this.add( 'component:index-wrapper', Component.extend({ didInsertElement() { let firstInput = document.querySelector('.input'); firstInput.addEventListener('keydown', e => (event = e), false); firstInput.addEventListener('change', e => (event = e), false); let secondInput = document.querySelector('#limited .input'); secondInput.addEventListener('keydown', e => (event = e), false); secondInput.addEventListener('change', e => (event = e), false); }, }) ); this.addTemplate( 'components/index-wrapper', ` {{input type="text" id="outside-scope" class="input"}}
{{input type="text" id="inside-scope" class="input"}}
` ); this.addTemplate('index', `{{index-wrapper}}`); this.runTask(() => { this.application.advanceReadiness(); }); let { application: { testHelpers: { wait, triggerEvent } } } = this; return wait() .then(() => { return triggerEvent('.input', '#limited', 'keydown', { keyCode: 13, }); }) .then(() => { assert.equal(event.keyCode, 13, 'options were passed'); assert.equal(event.type, 'keydown', 'correct event was triggered'); assert.equal( event.target.getAttribute('id'), 'inside-scope', 'triggered on the correct element' ); }); } } ); moduleFor( 'ember-testing: debugging helpers', class extends HelpersApplicationTestCase { afterEach() { super.afterEach(); setDebugFunction('info', originalInfo); } constructor() { super(); this.runTask(() => { this.application.advanceReadiness(); }); } [`@test pauseTest pauses`](assert) { assert.expect(1); // overwrite info to supress the console output (see https://github.com/emberjs/ember.js/issues/16391) setDebugFunction('info', noop); let { andThen, pauseTest } = this.application.testHelpers; andThen(() => { Test.adapter.asyncStart = () => { assert.ok(true, 'Async start should be called after waiting for other helpers'); }; }); pauseTest(); } [`@test resumeTest resumes paused tests`](assert) { assert.expect(1); // overwrite info to supress the console output (see https://github.com/emberjs/ember.js/issues/16391) setDebugFunction('info', noop); let { application: { testHelpers: { pauseTest, resumeTest } } } = this; later(() => resumeTest(), 20); return pauseTest().then(() => { assert.ok(true, 'pauseTest promise was resolved'); }); } [`@test resumeTest throws if nothing to resume`](assert) { assert.expect(1); assert.throws(() => { this.application.testHelpers.resumeTest(); }, /Testing has not been paused. There is nothing to resume./); } } ); moduleFor( 'ember-testing: routing helpers', class extends HelpersTestCase { constructor() { super(); this.runTask(() => { this.createApplication(); this.application.setupForTesting(); this.application.injectTestHelpers(); this.router.map(function() { this.route('posts', { resetNamespace: true }, function() { this.route('new'); this.route('edit', { resetNamespace: true }); }); }); }); this.runTask(() => { this.application.advanceReadiness(); }); } [`@test currentRouteName for '/'`](assert) { assert.expect(3); let { application: { testHelpers } } = this; return testHelpers.visit('/').then(() => { assert.equal(testHelpers.currentRouteName(), 'index', `should equal 'index'.`); assert.equal(testHelpers.currentPath(), 'index', `should equal 'index'.`); assert.equal(testHelpers.currentURL(), '/', `should equal '/'.`); }); } [`@test currentRouteName for '/posts'`](assert) { assert.expect(3); let { application: { testHelpers } } = this; return testHelpers.visit('/posts').then(() => { assert.equal( testHelpers.currentRouteName(), 'posts.index', `should equal 'posts.index'.` ); assert.equal(testHelpers.currentPath(), 'posts.index', `should equal 'posts.index'.`); assert.equal(testHelpers.currentURL(), '/posts', `should equal '/posts'.`); }); } [`@test currentRouteName for '/posts/new'`](assert) { assert.expect(3); let { application: { testHelpers } } = this; return testHelpers.visit('/posts/new').then(() => { assert.equal(testHelpers.currentRouteName(), 'posts.new', `should equal 'posts.new'.`); assert.equal(testHelpers.currentPath(), 'posts.new', `should equal 'posts.new'.`); assert.equal(testHelpers.currentURL(), '/posts/new', `should equal '/posts/new'.`); }); } [`@test currentRouteName for '/posts/edit'`](assert) { assert.expect(3); let { application: { testHelpers } } = this; return testHelpers.visit('/posts/edit').then(() => { assert.equal(testHelpers.currentRouteName(), 'edit', `should equal 'edit'.`); assert.equal(testHelpers.currentPath(), 'posts.edit', `should equal 'posts.edit'.`); assert.equal(testHelpers.currentURL(), '/posts/edit', `should equal '/posts/edit'.`); }); } } ); moduleFor( 'ember-testing: pendingRequests', class extends HelpersApplicationTestCase { trigger(type, xhr) { jQuery(document).trigger(type, xhr); } [`@test pendingRequests is maintained for ajaxSend and ajaxComplete events`](assert) { let done = assert.async(); assert.equal(pendingRequests(), 0); let xhr = { some: 'xhr' }; this.trigger('ajaxSend', xhr); assert.equal(pendingRequests(), 1, 'Ember.Test.pendingRequests was incremented'); this.trigger('ajaxComplete', xhr); setTimeout(function() { assert.equal(pendingRequests(), 0, 'Ember.Test.pendingRequests was decremented'); done(); }, 0); } [`@test pendingRequests is ignores ajaxComplete events from past setupForTesting calls`]( assert ) { assert.equal(pendingRequests(), 0); let xhr = { some: 'xhr' }; this.trigger('ajaxSend', xhr); assert.equal(pendingRequests(), 1, 'Ember.Test.pendingRequests was incremented'); setupForTesting(); assert.equal(pendingRequests(), 0, 'Ember.Test.pendingRequests was reset'); let altXhr = { some: 'more xhr' }; this.trigger('ajaxSend', altXhr); assert.equal(pendingRequests(), 1, 'Ember.Test.pendingRequests was incremented'); this.trigger('ajaxComplete', xhr); assert.equal( pendingRequests(), 1, 'Ember.Test.pendingRequests is not impressed with your unexpected complete' ); } [`@test pendingRequests is reset by setupForTesting`](assert) { incrementPendingRequests(); setupForTesting(); assert.equal(pendingRequests(), 0, 'pendingRequests is reset'); } } ); moduleFor( 'ember-testing: async router', class extends HelpersTestCase { constructor() { super(); this.runTask(() => { this.createApplication(); this.router.map(function() { this.route('user', { resetNamespace: true }, function() { this.route('profile'); this.route('edit'); }); }); // Emulate a long-running unscheduled async operation. let resolveLater = () => new RSVP.Promise(resolve => { /* * The wait() helper has a 10ms tick. We should resolve() after * at least one tick to test whether wait() held off while the * async router was still loading. 20ms should be enough. */ later(resolve, { firstName: 'Tom' }, 20); }); this.add( 'route:user', Route.extend({ model() { return resolveLater(); }, }) ); this.add( 'route:user.profile', Route.extend({ beforeModel() { return resolveLater().then(() => this.transitionTo('user.edit')); }, }) ); this.application.setupForTesting(); }); this.application.injectTestHelpers(); this.runTask(() => { this.application.advanceReadiness(); }); } [`@test currentRouteName for '/user'`](assert) { assert.expect(4); let { application: { testHelpers } } = this; return testHelpers.visit('/user').then(() => { assert.equal(testHelpers.currentRouteName(), 'user.index', `should equal 'user.index'.`); assert.equal(testHelpers.currentPath(), 'user.index', `should equal 'user.index'.`); assert.equal(testHelpers.currentURL(), '/user', `should equal '/user'.`); let userRoute = this.applicationInstance.lookup('route:user'); assert.equal(userRoute.get('controller.model.firstName'), 'Tom', `should equal 'Tom'.`); }); } [`@test currentRouteName for '/user/profile'`](assert) { assert.expect(4); let { application: { testHelpers } } = this; return testHelpers.visit('/user/profile').then(() => { assert.equal(testHelpers.currentRouteName(), 'user.edit', `should equal 'user.edit'.`); assert.equal(testHelpers.currentPath(), 'user.edit', `should equal 'user.edit'.`); assert.equal(testHelpers.currentURL(), '/user/edit', `should equal '/user/edit'.`); let userRoute = this.applicationInstance.lookup('route:user'); assert.equal(userRoute.get('controller.model.firstName'), 'Tom', `should equal 'Tom'.`); }); } } ); moduleFor( 'ember-testing: can override built-in helpers', class extends HelpersTestCase { constructor() { super(); this.runTask(() => { this.createApplication(); this.application.setupForTesting(); }); this._originalVisitHelper = Test._helpers.visit; this._originalFindHelper = Test._helpers.find; } teardown() { Test._helpers.visit = this._originalVisitHelper; Test._helpers.find = this._originalFindHelper; super.teardown(); } [`@test can override visit helper`](assert) { assert.expect(1); Test.registerHelper('visit', () => { assert.ok(true, 'custom visit helper was called'); }); this.application.injectTestHelpers(); return this.application.testHelpers.visit(); } [`@test can override find helper`](assert) { assert.expect(1); Test.registerHelper('find', () => { assert.ok(true, 'custom find helper was called'); return ['not empty array']; }); this.application.injectTestHelpers(); return this.application.testHelpers.findWithAssert('.who-cares'); } } ); }