From a10408117f4892a24634d76754a13545326e1e8b Mon Sep 17 00:00:00 2001 From: Steve Calvert Date: Thu, 9 May 2019 15:59:43 -0700 Subject: [PATCH] Converting signature in TestWaiter.beginAsync to take a Token --- .eslintrc.js | 6 - README.md | 90 +++++++++++++- addon/build-waiter.ts | 2 +- addon/noop-test-waiter.ts | 8 +- addon/test-waiter.ts | 35 ++++-- addon/types/index.ts | 7 +- addon/wait-for-promise.ts | 2 +- ember-cli-build.js | 17 ++- package.json | 7 +- tests/index.html | 7 -- tests/test-helper.js | 33 +----- tests/unit/test-waiter-test.ts | 85 +++++++++++++- tests/unit/waiter-manager-noop-test.ts | 5 +- vendor/shims/qunit.js | 18 --- yarn.lock | 156 ++++++++++++++++++++----- 15 files changed, 350 insertions(+), 128 deletions(-) delete mode 100644 vendor/shims/qunit.js diff --git a/.eslintrc.js b/.eslintrc.js index 7167a2e6..0093029d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -44,11 +44,5 @@ module.exports = { // add your custom rules and overrides for node files here }), }, - { - files: ['tests/**/*.[jt]s'], - env: { - qunit: true, - }, - }, ], }; diff --git a/README.md b/README.md index ce92932b..b2cdbb25 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # ember-test-waiters This addon provides APIs to allow [@ember/test-helpers](https://github.com/emberjs/ember-test-helpers/) to play nicely -with other asynchronous events, such as an application that is waiting for a CSS transition or an IndexDB transaction. +with other asynchronous operations, such as an application that is waiting for a CSS transition or an IndexDB transaction. The async helpers inside `@ember/test-helpers` return promises (i.e. `click`, `andThen`, `visit`, etc). Waiters run periodically after each helper has executed until a predetermined condition is met. After the waiters finish, the next async helper is executed and the process repeats. @@ -29,7 +29,10 @@ ember install ember-test-waiters ### buildWaiter function -The `buildWaiter` function is, in most cases, all you will need to wait for async operations to complete before continuing tests. +The `buildWaiter` function is, in most cases, all you will need to wait for async operations to complete before continuing tests. It returns a waiter instance +that provides a number of methods. The key methods that allow you to control async behavior are `beginAsync` and `endAsync`, which are expected to be called as +a pair to _begin_ waiting and _end_ waiting respectively. The `beginAsync` method returns a `token`, which uniquely identifies that async operation. To mark the +async operation as complete, call `endAsync`, passing in the `token` that was returned from the prior `beginAsync` call. ```js import Component from '@ember/component'; @@ -39,18 +42,97 @@ let waiter = buildWaiter('friend-waiter'); export default class Friendz extends Component { didInsertElement() { - waiter.beginAsync(this); + let token = waiter.beginAsync(); + + someAsyncWork() + .then(() => { + //... some work + }) + .finally(() => { + waiter.endAsync(token); + }); + } +} +``` + +#### Custom Tokens + +The `beginAsync` method also can receive a custom token, if you need to specifically define a token to represent your async operation. _Note_ - due to the nature of +async operations, it's impossible to guarantee which order the `endAsync` calls will run. If you are making multiple `beginAsync`/`endAsync` calls wiithin a single +class or function, _you need to ensure the uniqueness of each async operation by ensuring the uniqueness of the tokens you provide_. + +The following code _will not_ guarantee uniqueness, as the two `endAsync` calls _may_ be called in succession: + +```js +import Component from '@ember/component'; +import { buildWaiter } from 'ember-test-waiters'; + +let waiter = buildWaiter('friend-waiter'); + +export default class Friendz extends Component { + didInsertElement() { + let token = waiter.beginAsync(this); someAsyncWork().then(() => { waiter.endAsync(this); }); } + + action: { + someAction() { + let token = waiter.beginAsync(this); + + someOtherAsync() + .then(() => { + //... some work + }) + .finally(() => { + waiter.endAsync(this); + }); + } + } +} +``` + +The following code _will_ guarantee uniqueness, as the two `endAsync` calls _may_ be called in succession, but have unique tokens: + +```js +import Component from '@ember/component'; +import { buildWaiter } from 'ember-test-waiters'; + +let waiter = buildWaiter('friend-waiter'); + +export default class Friendz extends Component { + didInsertElement() { + let token = 'fist async'; + waiter.beginAsync(token); // if a token is provided, `beginAsync` wil simply return it + + someAsyncWork().then(() => { + waiter.endAsync(token); + }); + } + + action: { + someAction() { + let token = 'second async'; + waiter.beginAsync(token); + + someOtherAsync() + .then(() => { + //... some work + }) + .finally(() => { + waiter.endAsync(token); + }); + } + } } ``` ### waitForPromise function -This addon also provides a `waitForPromise` function, which can be used to wrap a promise to register it with the test waiter system. +This addon also provides a `waitForPromise` function, which can be used to wrap a promise to register it with the test waiter system. _Note_: the +`waitForPromise` function will ensure that `endAsync` is called correctly in the `finally` call of your promise. ```js import Component from '@ember/component'; diff --git a/addon/build-waiter.ts b/addon/build-waiter.ts index 49b7d4ba..62088054 100644 --- a/addon/build-waiter.ts +++ b/addon/build-waiter.ts @@ -29,7 +29,7 @@ import NoopTestWaiter from './noop-test-waiter'; * } * } */ -export default function buildWaiter(name: string): ITestWaiter { +export default function buildWaiter(name: string): ITestWaiter { if (DEBUG) { return new TestWaiter(name); } diff --git a/addon/noop-test-waiter.ts b/addon/noop-test-waiter.ts index cbaac190..5473d55e 100644 --- a/addon/noop-test-waiter.ts +++ b/addon/noop-test-waiter.ts @@ -1,4 +1,4 @@ -import { ITestWaiter } from './types'; +import { ITestWaiter, Token } from './types'; /** * A class providing a production, noop replacement for the {TestWaiter} class. @@ -6,13 +6,15 @@ import { ITestWaiter } from './types'; * @public * @class TestWaiter */ -export default class NoopTestWaiter implements ITestWaiter { +export default class NoopTestWaiter implements ITestWaiter { name: string; constructor(name: string) { this.name = name; } - beginAsync(): void {} + beginAsync(): Token { + return this; + } endAsync(): void {} diff --git a/addon/test-waiter.ts b/addon/test-waiter.ts index 4a7e9490..7c663a74 100644 --- a/addon/test-waiter.ts +++ b/addon/test-waiter.ts @@ -1,25 +1,34 @@ -import { ITestWaiter, WaiterName, ITestWaiterDebugInfo } from './types'; +import { ITestWaiter, WaiterName, ITestWaiterDebugInfo, Token } from './types'; import { register } from './waiter-manager'; +let token: number = 0; + +function getNextToken(): number { + return token++; +} + /** * A class providing creation, registration and async waiting functionality. * * @public * @class TestWaiter */ -export default class TestWaiter implements ITestWaiter { +export default class TestWaiter implements ITestWaiter { public name: WaiterName; + public nextToken: () => T; private isRegistered = false; - items = new Map(); + items = new Map(); /** * @public * @constructor * @param name {WaiterName} the name of the test waiter */ - constructor(name: WaiterName) { + constructor(name: WaiterName, nextToken?: () => T) { this.name = name; + // @ts-ignore + this.nextToken = nextToken || getNextToken; } /** @@ -50,17 +59,23 @@ export default class TestWaiter implements ITestWaiter { * @param item {T} The item to register for waiting * @param label {string} An optional label to identify the item */ - beginAsync(item: T, label?: string) { + beginAsync(token: T = this.nextToken(), label?: string) { this.register(); + if (this.items.has(token)) { + throw new Error(`beginAsync called for ${token} but it is already pending.`); + } + let error = new Error(); - this.items.set(item, { + this.items.set(token, { get stack() { return error.stack; }, label, }); + + return token; } /** @@ -72,12 +87,12 @@ export default class TestWaiter implements ITestWaiter { * @method endAsync * @param item {T} The item to that was registered for waiting */ - endAsync(item: T) { - if (!this.items.has(item)) { - throw new Error(`endAsync called for ${item} but item is not currently pending.`); + endAsync(token: T) { + if (!this.items.has(token)) { + throw new Error(`endAsync called for ${token} but it is not currently pending.`); } - this.items.delete(item); + this.items.delete(token); } /** diff --git a/addon/types/index.ts b/addon/types/index.ts index 79d7897d..213dca46 100644 --- a/addon/types/index.ts +++ b/addon/types/index.ts @@ -1,4 +1,5 @@ export type WaiterName = string; +export type Token = unknown; export interface IWaiter { name: WaiterName; @@ -6,9 +7,9 @@ export interface IWaiter { debugInfo(): unknown; } -export interface ITestWaiter extends IWaiter { - beginAsync(item: T, label?: string): void; - endAsync(item: T): void; +export interface ITestWaiter extends IWaiter { + beginAsync(token?: T, label?: string): T; + endAsync(token: T): void; } export interface ITestWaiterDebugInfo { diff --git a/addon/wait-for-promise.ts b/addon/wait-for-promise.ts index cbc869c6..1a405195 100644 --- a/addon/wait-for-promise.ts +++ b/addon/wait-for-promise.ts @@ -1,7 +1,7 @@ import { DEBUG } from '@glimmer/env'; import TestWaiter from './test-waiter'; -const PROMISE_WAITER = new TestWaiter('promise-waiter'); +const PROMISE_WAITER = new TestWaiter>('promise-waiter'); /** A convenient utility function to simplify waiting for a promise. diff --git a/ember-cli-build.js b/ember-cli-build.js index bb0def87..dc5a39e1 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -3,17 +3,16 @@ const EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); module.exports = function(defaults) { - let app = new EmberAddon(defaults, {}); - - app.import('node_modules/qunit/qunit/qunit.js', { - type: 'test', - }); - - app.import('node_modules/qunit/qunit/qunit.css', { - type: 'test', + let app = new EmberAddon(defaults, { + // Add options here }); - app.import('vendor/shims/qunit.js', { type: 'test' }); + /* + This build file specifies the options for the dummy test app of this + addon, located in `/tests/dummy` + This build file does *not* influence how the addon or the app using it + behave. You most likely want to be modifying `./index.js` or app's build file + */ return app.toTree(); }; diff --git a/package.json b/package.json index dab338e6..0011c20f 100644 --- a/package.json +++ b/package.json @@ -31,10 +31,11 @@ "@ember/optional-features": "^0.6.3", "@glimmer/env": "^0.1.7", "@types/ember": "^3.0.29", + "@types/ember-qunit": "^3.4.5", "@types/ember-test-helpers": "^1.0.4", "@types/ember-testing-helpers": "^0.0.3", "@types/ember__test-helpers": "^0.7.7", - "@types/qunit": "^2.9.0", + "@types/qunit": "^2.5.4", "@types/rsvp": "^4.0.2", "@typescript-eslint/eslint-plugin": "^1.4.2", "@typescript-eslint/parser": "^1.4.2", @@ -45,13 +46,13 @@ "ember-cli-htmlbars-inline-precompile": "^1.0.3", "ember-cli-inject-live-reload": "^1.8.2", "ember-cli-sri": "^2.1.1", - "ember-cli-test-loader": "^2.2.0", "ember-cli-typescript": "^1.5.0", "ember-cli-uglify": "^2.1.0", "ember-disable-prototype-extensions": "^1.1.3", "ember-export-application-global": "^2.0.0", "ember-load-initializers": "^1.1.0", "ember-maybe-import-regenerator": "^0.1.6", + "ember-qunit": "^3.4.1", "ember-resolver": "^5.0.1", "ember-source": "~3.7.0", "ember-source-channel-url": "^1.1.0", @@ -63,7 +64,7 @@ "eslint-plugin-prettier": "^3.0.1", "loader.js": "^4.7.0", "prettier": "^1.16.4", - "qunit": "^2.9.2", + "qunit-dom": "^0.8.0", "typescript": "^3.3.3333" }, "engines": { diff --git a/tests/index.html b/tests/index.html index efa55899..5209b852 100644 --- a/tests/index.html +++ b/tests/index.html @@ -21,13 +21,6 @@ {{content-for "body"}} {{content-for "test-body"}} -
-
- -
-
-
- diff --git a/tests/test-helper.js b/tests/test-helper.js index 6cb55e33..0382a848 100644 --- a/tests/test-helper.js +++ b/tests/test-helper.js @@ -1,29 +1,8 @@ -import QUnit from 'qunit'; -import AbstractTestLoader from 'ember-cli-test-loader/test-support/index'; +import Application from '../app'; +import config from '../config/environment'; +import { setApplication } from '@ember/test-helpers'; +import { start } from 'ember-qunit'; -let moduleLoadFailures = []; +setApplication(Application.create(config.APP)); -QUnit.done(function() { - if (moduleLoadFailures.length) { - throw new Error('\n' + moduleLoadFailures.join('\n')); - } -}); - -class TestLoader extends AbstractTestLoader { - moduleLoadFailure(moduleName, error) { - moduleLoadFailures.push(error); - - QUnit.module('TestLoader Failures'); - QUnit.test(moduleName + ': could not be loaded', function() { - throw error; - }); - } -} - -new TestLoader().loadModules(); - -QUnit.testDone(function() { - let testElementContainer = document.getElementById('ember-testing-container'); - let testElementReset = testElementContainer.outerHTML; - testElementContainer.innerHTML = testElementReset; -}); +start(); diff --git a/tests/unit/test-waiter-test.ts b/tests/unit/test-waiter-test.ts index f65bef93..3c88c74d 100644 --- a/tests/unit/test-waiter-test.ts +++ b/tests/unit/test-waiter-test.ts @@ -3,7 +3,7 @@ import { Promise } from 'rsvp'; import { TestWaiter, _reset, getWaiters, getPendingWaiterState } from 'ember-test-waiters'; import MockStableError, { overrideError, resetError } from './utils/mock-stable-error'; -module('test-waiter', function(hooks) { +module('test-waiter', function(hooks: NestedHooks) { hooks.afterEach(function() { _reset(); resetError(); @@ -16,7 +16,30 @@ module('test-waiter', function(hooks) { assert.equal(waiter.name, name); }); - test('test waiters automatically register when beginAsync is invoked', function(assert) { + test('test waiters return a token from beginAsync when no token provided', function(assert) { + let waiter = new TestWaiter('my-waiter'); + + let token = waiter.beginAsync(); + + assert.ok(typeof token === 'number', 'A token was returned from beginAsync'); + }); + + test('test waiters automatically register when beginAsync is invoked when no token provied', function(assert) { + let waiter = new TestWaiter('my-waiter'); + + let token = waiter.beginAsync(); + + let registeredWaiters = getWaiters(); + + assert.equal(registeredWaiters[0], waiter, 'The waiter is registered'); + assert.deepEqual( + (registeredWaiters[0]).items.keys().next().value, + token, + 'Waiter item is in items' + ); + }); + + test('test waiters automatically register when beginAsync is invoked using a custom token', function(assert) { let waiter = new TestWaiter('my-waiter'); let waiterItem = {}; @@ -26,7 +49,7 @@ module('test-waiter', function(hooks) { assert.equal(registeredWaiters[0], waiter, 'The waiter is registered'); assert.deepEqual( - (>registeredWaiters[0]).items.keys().next().value, + (registeredWaiters[0]).items.keys().next().value, {}, 'Waiter item is in items' ); @@ -34,16 +57,39 @@ module('test-waiter', function(hooks) { test('test waiters removes item from items map when endAsync is invoked', function(assert) { let waiter = new TestWaiter('my-waiter'); + + let token = waiter.beginAsync(); + waiter.endAsync(token); + let registeredWaiters = getWaiters(); + + assert.equal((registeredWaiters[0]).items.size, 0); + }); + + test('test waiters removes item from items map when endAsync is invoked using a custom token', function(assert) { + let waiter = new TestWaiter('my-waiter'); let waiterItem = {}; waiter.beginAsync(waiterItem); waiter.endAsync(waiterItem); let registeredWaiters = getWaiters(); - assert.equal((>registeredWaiters[0]).items.size, 0); + assert.equal((registeredWaiters[0]).items.size, 0); }); test('endAsync will throw if a prior call to beginAsync with the same waiter item did not occur', function(assert) { + let waiter = new TestWaiter('my-waiter'); + let token = 0; + + assert.throws( + () => { + waiter.endAsync(token); + }, + Error, + /endAsync called for [object Object] but item is not currently pending./ + ); + }); + + test('endAsync will throw if a prior call to beginAsync with the same waiter item did not occur using custom token', function(assert) { let waiter = new TestWaiter('my-waiter'); let waiterItem = {}; @@ -56,6 +102,37 @@ module('test-waiter', function(hooks) { ); }); + test('endAsync will throw if endAsync called twice in a row with the same token', function(assert) { + let waiter = new TestWaiter('my-waiter'); + let token = waiter.beginAsync(); + + waiter.endAsync(token); + + assert.throws( + () => { + waiter.endAsync(token); + }, + Error, + /endAsync called for [object Object] but item is not currently pending./ + ); + }); + + test('endAsync will throw if endAsync called twice in a row with the same token using custom token', function(assert) { + let waiter = new TestWaiter('my-waiter'); + let waiterItem = {}; + + waiter.beginAsync(waiterItem); + waiter.endAsync(waiterItem); + + assert.throws( + () => { + waiter.endAsync(waiterItem); + }, + Error, + /endAsync called for [object Object] but item is not currently pending./ + ); + }); + test('waitUntil returns the correct value if the waiter should wait', function(assert) { let waiter = new TestWaiter('my-waiter'); let waiterItem = {}; diff --git a/tests/unit/waiter-manager-noop-test.ts b/tests/unit/waiter-manager-noop-test.ts index 0ddd1e68..2bf6688f 100644 --- a/tests/unit/waiter-manager-noop-test.ts +++ b/tests/unit/waiter-manager-noop-test.ts @@ -26,12 +26,11 @@ if (!DEBUG) { test('a NoopTestWaiter always returns true from waitUntil', function(assert) { let waiter = buildWaiter('first'); - let waiterItem = {}; assert.ok(waiter.waitUntil(), 'waitUntil returns true'); - waiter.beginAsync(waiterItem); + let token = waiter.beginAsync(); assert.ok(waiter.waitUntil(), 'waitUntil returns true'); - waiter.endAsync(waiterItem); + waiter.endAsync(token); assert.ok(waiter.waitUntil(), 'waitUntil returns true'); }); }); diff --git a/vendor/shims/qunit.js b/vendor/shims/qunit.js deleted file mode 100644 index f680cd71..00000000 --- a/vendor/shims/qunit.js +++ /dev/null @@ -1,18 +0,0 @@ -/* globals define, self */ - -(function() { - function vendorModule() { - 'use strict'; - - return { - default: self.QUnit, - module: self.QUnit.module, - test: self.QUnit.test, - todo: self.QUnit.todo, - skip: self.QUnit.skip, - __esModule: true, - }; - } - - define('qunit', [], vendorModule); -})(); diff --git a/yarn.lock b/yarn.lock index 1b899e66..20c014d7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -972,6 +972,16 @@ silent-error "^1.1.0" util.promisify "^1.0.0" +"@ember/test-helpers@^0.7.26": + version "0.7.27" + resolved "https://registry.yarnpkg.com/@ember/test-helpers/-/test-helpers-0.7.27.tgz#c622cabd0cbb95b34efc1e1b6274ab5a14edc138" + integrity sha512-AQESk0FTFxRY6GyZ8PharR4SC7Fju0rXqNkfNYIntAjzefZ8xEqEM4iXDj5h7gAvfx/8dA69AQ9+p7ubc+KvJg== + dependencies: + broccoli-funnel "^2.0.1" + ember-assign-polyfill "~2.4.0" + ember-cli-babel "^6.12.0" + ember-cli-htmlbars-inline-precompile "^1.0.0" + "@glimmer/di@^0.2.0": version "0.2.1" resolved "https://registry.yarnpkg.com/@glimmer/di/-/di-0.2.1.tgz#5286b6b32040232b751138f6d006130c728d4b3d" @@ -994,7 +1004,15 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== -"@types/ember-test-helpers@^1.0.4": +"@types/ember-qunit@^3.4.5": + version "3.4.6" + resolved "https://registry.yarnpkg.com/@types/ember-qunit/-/ember-qunit-3.4.6.tgz#b09ae84192c16fbd1da0d1be26fa02b67691250d" + integrity sha512-ARB2JDNV3qzrZ94fC+YdV9jT9hYAXP8pXcqAVzVEYVL5/upSxKcYZjiCSScpKzXikN8yieIGNqSGArhQrcdzFA== + dependencies: + "@types/ember" "*" + "@types/ember-test-helpers" "*" + +"@types/ember-test-helpers@*", "@types/ember-test-helpers@^1.0.4": version "1.0.5" resolved "https://registry.yarnpkg.com/@types/ember-test-helpers/-/ember-test-helpers-1.0.5.tgz#b0a8a3b9386ddf372eef11ba95487be806674ca2" integrity sha512-LewaqxBqUDxT40Lb8M7r0pDlF78b5O87mQRK+8GqrreK/s3MSX/BXgxi5hbWF3TPJ57iX3G4S2TNO8z8soXYdA== @@ -1174,10 +1192,10 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== -"@types/qunit@^2.9.0": - version "2.9.0" - resolved "https://registry.yarnpkg.com/@types/qunit/-/qunit-2.9.0.tgz#0b3fcbe2b92f067856adac82ba3afbc66d8835ac" - integrity sha512-Hx34HZmTJKRay+x3sFdEK62I8Z8YSWYg+rAlNr4M+AbwvNUJYxTTmWEH4a8B9ZN+Fl61awFrw+oRicWLFVugvQ== +"@types/qunit@^2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@types/qunit/-/qunit-2.5.4.tgz#0518940acc6013259a8619a1ec34ce0e4ff8d1c4" + integrity sha512-VHi2lEd4/zp8OOouf43JXGJJ5ZxHvdLL1dU0Yakp6Iy73SjpuXl7yjwAwmh1qhTv8krDgHteSwaySr++uXX9YQ== "@types/rsvp@*", "@types/rsvp@^4.0.2": version "4.0.2" @@ -3085,6 +3103,11 @@ commander@~2.17.1: resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== +common-tags@^1.4.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" + integrity sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw== + component-bind@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" @@ -3605,7 +3628,15 @@ electron-to-chromium@^1.3.122, electron-to-chromium@^1.3.47: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.124.tgz#861fc0148748a11b3e5ccebdf8b795ff513fa11f" integrity sha512-glecGr/kFdfeXUHOHAWvGcXrxNU+1wSO/t5B23tT1dtlvYB26GY8aHzZSWD7HqhqC800Lr+w/hQul6C5AF542w== -ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.16.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.1: +ember-assign-polyfill@~2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/ember-assign-polyfill/-/ember-assign-polyfill-2.4.0.tgz#acb00466f7d674b3e6b030acfe255b3b1f6472e1" + integrity sha512-0SnGQb9CenRqbZdIa1KFsEjT+1ijGWfAbCSaDbg5uVa5l6HPdppuTzOXK6sfEQMsd2nbrp27QWFy7W5VX6l4Ag== + dependencies: + ember-cli-babel "^6.6.0" + ember-cli-version-checker "^2.0.0" + +ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.12.0, ember-cli-babel@^6.16.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2: version "6.18.0" resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.18.0.tgz#3f6435fd275172edeff2b634ee7b29ce74318957" integrity sha512-7ceC8joNYxY2wES16iIBlbPSxwKDBhYwC8drU3ZEvuPDMwVv1KzxCNu1fvxyFEBWhwaRNTUxSCsEVoTd9nosGA== @@ -3675,7 +3706,7 @@ ember-cli-get-component-path-option@^1.0.0: resolved "https://registry.yarnpkg.com/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" integrity sha1-DXtZVVni+QUKvtgE8djv8bCLx3E= -ember-cli-htmlbars-inline-precompile@^1.0.3: +ember-cli-htmlbars-inline-precompile@^1.0.0, ember-cli-htmlbars-inline-precompile@^1.0.3: version "1.0.5" resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-1.0.5.tgz#312e050c9e3dd301c55fb399fd706296cd0b1d6a" integrity sha512-/CNEqPxroIcbY6qejrt704ZaghHLCntZKYLizFfJ2esirXoJx6fuYKBY1YyJ8GOgjfbHHKjBZuK4vFFJpkGqkQ== @@ -3819,7 +3850,7 @@ ember-cli-valid-component-name@^1.0.0: dependencies: silent-error "^1.0.0" -ember-cli-version-checker@^2.1.0, ember-cli-version-checker@^2.1.2: +ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0, ember-cli-version-checker@^2.1.2: version "2.2.0" resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-2.2.0.tgz#47771b731fe0962705e27c8199a9e3825709f3b3" integrity sha512-G+KtYIVlSOWGcNaTFHk76xR4GdzDLzAS4uxZUKdASuFX0KJE43C6DaqL+y3VTpUFLI2FIkAS6HZ4I1YBi+S3hg== @@ -3960,6 +3991,19 @@ ember-maybe-import-regenerator@^0.1.6: ember-cli-babel "^6.0.0-beta.4" regenerator-runtime "^0.9.5" +ember-qunit@^3.4.1: + version "3.5.3" + resolved "https://registry.yarnpkg.com/ember-qunit/-/ember-qunit-3.5.3.tgz#bfd0bff8298c78c77e870cca43fe0826e78a0d09" + integrity sha512-FmXsI1bGsZ5th25x4KEle2fLCVURTptsQODfBt+Pg8tk9rX7y79cqny91PrhtkhE+giZ8p029tnq94SdpJ4ojg== + dependencies: + "@ember/test-helpers" "^0.7.26" + broccoli-funnel "^2.0.1" + broccoli-merge-trees "^2.0.0" + common-tags "^1.4.0" + ember-cli-babel "^6.8.2" + ember-cli-test-loader "^2.2.0" + qunit "~2.6.0" + ember-resolver@^5.0.1: version "5.1.3" resolved "https://registry.yarnpkg.com/ember-resolver/-/ember-resolver-5.1.3.tgz#d2a5a856d53911552c022649cdc7b0408a7908ae" @@ -4336,6 +4380,13 @@ events-to-array@^1.0.1: resolved "https://registry.yarnpkg.com/events-to-array/-/events-to-array-1.1.2.tgz#2d41f563e1fe400ed4962fe1a4d5c6a7539df7f6" integrity sha1-LUH1Y+H+QA7Uli/hpNXGp1Od9/Y= +exec-sh@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.2.tgz#2a5e7ffcbd7d0ba2755bdecb16e5a427dfbdec36" + integrity sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw== + dependencies: + merge "^1.2.0" + exec-sh@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.2.tgz#6738de2eb7c8e671d0366aea0b0db8c6f7d7391b" @@ -4367,6 +4418,11 @@ execa@^1.0.0: signal-exit "^3.0.0" strip-eof "^1.0.0" +exists-stat@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/exists-stat/-/exists-stat-1.0.0.tgz#0660e3525a2e89d9e446129440c272edfa24b529" + integrity sha1-BmDjUlouidnkRhKUQMJy7foktSk= + exists-sync@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.4.tgz#9744c2c428cc03b01060db454d4b12f0ef3c8879" @@ -4635,7 +4691,7 @@ find-yarn-workspace-root@^1.1.0: fs-extra "^4.0.3" micromatch "^3.1.4" -findup-sync@^2.0.0: +findup-sync@2.0.0, findup-sync@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" integrity sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw= @@ -4812,7 +4868,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@^1.2.7: +fsevents@^1.2.3, fsevents@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.7.tgz#4851b664a3783e52003b3c66eb0eee1074933aa4" integrity sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw== @@ -6664,6 +6720,11 @@ merge-trees@^2.0.0: fs-updater "^1.0.4" heimdalljs "^0.2.5" +merge@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" + integrity sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ== + methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" @@ -6725,7 +6786,7 @@ mimic-response@^1.0.0: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== -"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4: +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== @@ -6935,11 +6996,6 @@ node-releases@^1.1.13: dependencies: semver "^5.3.0" -node-watch@0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/node-watch/-/node-watch-0.6.0.tgz#ab0703b60cd270783698e57a428faa0010ed8fd0" - integrity sha512-XAgTL05z75ptd7JSVejH1a2Dm1zmXYhuDr9l230Qk6Z7/7GPcnAs/UyJJ4ggsXSvWil8iOzwQLW0zuGUvHpG8g== - nopt@^3.0.6: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" @@ -7396,7 +7452,7 @@ path-key@^2.0.0, path-key@^2.0.1: resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= -path-parse@^1.0.6: +path-parse@^1.0.5, path-parse@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== @@ -7639,16 +7695,26 @@ quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quick-temp@^0.1.8: rimraf "^2.5.4" underscore.string "~3.3.4" -qunit@^2.9.2: - version "2.9.2" - resolved "https://registry.yarnpkg.com/qunit/-/qunit-2.9.2.tgz#97919440c9c0ae838bcd3c33a2ee42f35c5ef4a0" - integrity sha512-wTOYHnioWHcx5wa85Wl15IE7D6zTZe2CQlsodS14yj7s2FZ3MviRnQluspBZsueIDEO7doiuzKlv05yfky1R7w== +qunit-dom@^0.8.0: + version "0.8.4" + resolved "https://registry.yarnpkg.com/qunit-dom/-/qunit-dom-0.8.4.tgz#8b75a73040df1735280fc2fab4c6a1a7f518488b" + integrity sha512-Ab2wCPQP2G2XdbIwhlUHMp3ROHh4XnqmK0ogHlpxwVIv+cXbW3/L6F9ucCThAMkjqCaxwZQQR+LaUHaaMxDCmw== + dependencies: + broccoli-funnel "^2.0.0" + broccoli-merge-trees "^3.0.1" + +qunit@~2.6.0: + version "2.6.2" + resolved "https://registry.yarnpkg.com/qunit/-/qunit-2.6.2.tgz#551210c5cf857258a4fe39a7fe15d9e14dfef22c" + integrity sha512-PHbKulmd4rrDhFto7iHicIstDTX7oMRvAcI7loHstvU8J7AOGwzcchONmy+EG4KU8HDk0K90o7vO0GhlYyKlOg== dependencies: commander "2.12.2" + exists-stat "1.0.0" + findup-sync "2.0.0" js-reporters "1.2.1" - minimatch "3.0.4" - node-watch "0.6.0" - resolve "1.9.0" + resolve "1.5.0" + sane "^2.5.2" + walk-sync "0.3.2" range-parser@~1.2.0: version "1.2.0" @@ -8114,12 +8180,12 @@ resolve@1.1.7: resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= -resolve@1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.9.0.tgz#a14c6fdfa8f92a7df1d996cb7105fa744658ea06" - integrity sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ== +resolve@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" + integrity sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw== dependencies: - path-parse "^1.0.6" + path-parse "^1.0.5" resolve@^1.1.3, resolve@^1.1.6, resolve@^1.10.0, resolve@^1.3.2, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.6.0, resolve@^1.8.1: version "1.10.0" @@ -8218,6 +8284,22 @@ safe-regex@^1.1.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +sane@^2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/sane/-/sane-2.5.2.tgz#b4dc1861c21b427e929507a3e751e2a2cb8ab3fa" + integrity sha1-tNwYYcIbQn6SlQej51HiosuKs/o= + dependencies: + anymatch "^2.0.0" + capture-exit "^1.2.0" + exec-sh "^0.2.0" + fb-watchman "^2.0.0" + micromatch "^3.1.4" + minimist "^1.1.1" + walker "~1.0.5" + watch "~0.18.0" + optionalDependencies: + fsevents "^1.2.3" + sane@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/sane/-/sane-4.0.3.tgz#e878c3f19e25cc57fbb734602f48f8a97818b181" @@ -9441,6 +9523,14 @@ vue-template-compiler@^2.5.16: de-indent "^1.0.2" he "^1.1.0" +walk-sync@0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.2.tgz#4827280afc42d0e035367c4a4e31eeac0d136f75" + integrity sha512-FMB5VqpLqOCcqrzA9okZFc0wq0Qbmdm396qJxvQZhDpyu0W95G9JCmp74tx7iyYnyOcBtUuKJsgIKAqjozvmmQ== + dependencies: + ensure-posix-path "^1.0.0" + matcher-collection "^1.0.0" + walk-sync@^0.2.5: version "0.2.7" resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" @@ -9484,6 +9574,14 @@ watch-detector@^0.1.0: semver "^5.4.1" silent-error "^1.1.0" +watch@~0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" + integrity sha1-KAlUdsbffJDJYxOJkMClQj60uYY= + dependencies: + exec-sh "^0.2.0" + minimist "^1.2.0" + wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"