text: import { moduleFor, AutobootApplicationTestCase, isIE11, runTask } 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';
  
  const originalInfo = getDebugFunction('info');
  const 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) {
      let presentInHelperContainer = Boolean(helperContainer[helper]);
      let presentInTestHelpers = Boolean(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();
      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) {
          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) {
          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) {
          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) {
          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
        ) {
          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.
          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 = {};
  
          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' };
  
          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;
          }
  
          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);
  
          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}}
            <div contenteditable="true"> </div>
          {{/index-wrapper}}'));
        `
          );
  
          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}}
        `
          );
  
          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}}`);
  
          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);
  
          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;
          }
  
          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"}}
        `
          );
  
          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"}}
          <div id="limited">
            {{input type="text" id="inside-scope" class="input"}}
          </div>
        `
          );
          this.addTemplate('index', `{{index-wrapper}}`);
  
          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}}`);
  
          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',
            `
          <div id="parent">
            {{input type="text" id="first" class="current"}}
          </div>
          {{input type="text" id="second" class="current"}}
        `
          );
  
          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',
            `
          <div id="parent">
            {{input type="text" id="first" focus-in=(action "wasFocused")}}
          </div>'
        `
          );
  
          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',
            `
          <input type="text" id="first"
              oninput={{action "oninputHandler"}}
              onchange={{action "onchangeHandler"}}>
        `
          );
  
          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',
            `
          <input type="text" id="first" class="in-test">
          <input type="text" id="second" class="in-test">
        `
          );
  
          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"}}
          <div id="limited">
            {{input type="text" id="inside-scope" class="input"}}
          </div>
        `
          );
          this.addTemplate('index', `{{index-wrapper}}`);
  
          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();
          runTask(() => {
            this.application.advanceReadiness();
          });
        }
  
        [`@test pauseTest pauses`](assert) {
          assert.expect(1);
          // overwrite info to suppress 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 suppress 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();
          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 });
              });
            });
          });
          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();
  
          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(() => {
                    return expectDeprecation(() => {
                      return this.transitionTo('user.edit');
                    }, /Calling transitionTo on a route is deprecated/);
                  });
                },
              })
            );
  
            this.application.setupForTesting();
          });
  
          this.application.injectTestHelpers();
          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(5);
  
          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();
          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');
        }
      }
    );
  }
  