diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ba8cebedb..986f7383c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,7 +43,8 @@ jobs: - name: lint run: yarn lint - id: set-matrix - run: echo "::set-output name=matrix::$(node ./test-packages/support/suite-setup-util.js --matrix)" + working-directory: test-packages/support + run: echo "::set-output name=matrix::$(node ./suite-setup-util.js --matrix)" test: needs: ['preflight'] diff --git a/package.json b/package.json index 0c3b39b46..ccfb429cf 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "compile": "tsc", "lint": "eslint . --cache", "prepare": "tsc", - "test": "node ./test-packages/support/suite-setup-util.js --emit && jest" + "test": "cd tests/scenarios && yarn test" }, "jest": { "projects": [ diff --git a/packages/router/config/ember-try.js b/packages/router/config/ember-try.js deleted file mode 100644 index 53e2a4721..000000000 --- a/packages/router/config/ember-try.js +++ /dev/null @@ -1,90 +0,0 @@ -'use strict'; - -const getChannelURL = require('ember-source-channel-url'); - -module.exports = async function () { - return { - useYarn: true, - scenarios: [ - { - name: 'ember-lts-3.16', - npm: { - devDependencies: { - 'ember-source': '~3.16.0', - }, - }, - }, - { - name: 'ember-lts-3.20', - npm: { - devDependencies: { - 'ember-source': '~3.20.5', - }, - }, - }, - { - name: 'ember-lts-3.24', - npm: { - devDependencies: { - 'ember-source': '~3.24.3', - }, - }, - }, - { - name: 'ember-release', - npm: { - devDependencies: { - 'ember-source': await getChannelURL('release'), - }, - }, - }, - { - name: 'ember-beta', - npm: { - devDependencies: { - 'ember-source': await getChannelURL('beta'), - }, - }, - }, - { - name: 'ember-canary', - npm: { - devDependencies: { - 'ember-source': await getChannelURL('canary'), - }, - }, - }, - { - name: 'ember-default-with-jquery', - env: { - EMBER_OPTIONAL_FEATURES: JSON.stringify({ - 'jquery-integration': true, - }), - }, - npm: { - devDependencies: { - '@ember/jquery': '^1.1.0', - }, - }, - }, - { - name: 'ember-classic', - env: { - EMBER_OPTIONAL_FEATURES: JSON.stringify({ - 'application-template-wrapper': true, - 'default-async-observers': false, - 'template-only-glimmer-components': false, - }), - }, - npm: { - devDependencies: { - 'ember-source': '~3.28.0', - }, - ember: { - edition: 'classic', - }, - }, - }, - ], - }; -}; diff --git a/packages/router/package.json b/packages/router/package.json index 17b6d9ea3..1362a28f0 100644 --- a/packages/router/package.json +++ b/packages/router/package.json @@ -66,7 +66,6 @@ "ember-source": "~3.28.0", "ember-source-channel-url": "^3.0.0", "ember-template-lint": "^3.6.0", - "ember-try": "^1.4.0", "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-ember": "^10.5.4", diff --git a/packages/router/testem.js b/packages/router/testem.js index 442829a1a..aa5f6a7a8 100644 --- a/packages/router/testem.js +++ b/packages/router/testem.js @@ -1,2 +1,2 @@ -const { testemConfig } = require('@embroider/test-support/suite-setup-util'); +const { testemConfig } = require('@embroider/test-support/testem-config'); module.exports = testemConfig(); diff --git a/packages/util/config/ember-try.js b/packages/util/config/ember-try.js deleted file mode 100644 index 9534f6aa9..000000000 --- a/packages/util/config/ember-try.js +++ /dev/null @@ -1,80 +0,0 @@ -'use strict'; - -const getChannelURL = require('ember-source-channel-url'); - -module.exports = async function () { - return { - useYarn: true, - scenarios: [ - { - // this is the first release with co-located templates. - name: 'ember-3.13', - npm: { - devDependencies: { - 'ember-source': '~3.13.0', - }, - }, - }, - { - name: 'ember-lts-3.16', - npm: { - devDependencies: { - 'ember-source': '~3.16.0', - }, - }, - }, - { - name: 'ember-lts-3.20', - npm: { - devDependencies: { - 'ember-source': '~3.20.5', - }, - }, - }, - { - name: 'ember-lts-3.24', - npm: { - devDependencies: { - 'ember-source': '~3.24.0', - }, - }, - }, - { - name: 'ember-release', - npm: { - devDependencies: { - 'ember-source': await getChannelURL('release'), - }, - }, - }, - { - name: 'ember-default-with-jquery', - env: { - EMBER_OPTIONAL_FEATURES: JSON.stringify({ - 'jquery-integration': true, - }), - }, - npm: { - devDependencies: { - '@ember/jquery': '^2.0.0', - }, - }, - }, - { - name: 'ember-classic', - env: { - EMBER_OPTIONAL_FEATURES: JSON.stringify({ - 'application-template-wrapper': true, - 'default-async-observers': false, - 'template-only-glimmer-components': false, - }), - }, - npm: { - ember: { - edition: 'classic', - }, - }, - }, - ], - }; -}; diff --git a/packages/util/package.json b/packages/util/package.json index 8b18d7382..0f1d427b6 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -68,7 +68,6 @@ "ember-source": "~3.26", "ember-source-channel-url": "^3.0.0", "ember-template-lint": "^2.18.1", - "ember-try": "^1.4.0", "eslint": "^7.20.0", "eslint-config-prettier": "^7.2.0", "eslint-plugin-ember": "^10.2.0", diff --git a/packages/util/testem.js b/packages/util/testem.js index 442829a1a..aa5f6a7a8 100644 --- a/packages/util/testem.js +++ b/packages/util/testem.js @@ -1,2 +1,2 @@ -const { testemConfig } = require('@embroider/test-support/suite-setup-util'); +const { testemConfig } = require('@embroider/test-support/testem-config'); module.exports = testemConfig(); diff --git a/test-packages/jest.config.js b/test-packages/jest.config.js deleted file mode 100644 index 207554e2f..000000000 --- a/test-packages/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - testEnvironment: 'node', - testMatch: ['/dynamic_suites/*.test.js'], -}; diff --git a/test-packages/sample-transforms/config/ember-try.js b/test-packages/sample-transforms/config/ember-try.js deleted file mode 100644 index ff9546792..000000000 --- a/test-packages/sample-transforms/config/ember-try.js +++ /dev/null @@ -1,84 +0,0 @@ -'use strict'; - -const getChannelURL = require('ember-source-channel-url'); - -module.exports = function() { - return Promise.all([ - getChannelURL('release'), - getChannelURL('beta'), - getChannelURL('canary') - ]).then((urls) => { - return { - useYarn: true, - scenarios: [ - { - name: 'ember-lts-2.18', - env: { - EMBER_OPTIONAL_FEATURES: JSON.stringify({ 'jquery-integration': true }) - }, - npm: { - devDependencies: { - '@ember/jquery': '^2.0.0', - 'ember-source': '~2.18.0' - } - } - }, - { - name: 'ember-lts-3.4', - npm: { - devDependencies: { - 'ember-source': '~3.4.0' - } - } - }, - { - name: 'ember-release', - npm: { - devDependencies: { - 'ember-source': urls[0] - } - } - }, - { - name: 'ember-beta', - npm: { - devDependencies: { - 'ember-source': urls[1] - } - } - }, - { - name: 'ember-canary', - npm: { - devDependencies: { - 'ember-source': urls[2] - } - } - }, - // The default `.travis.yml` runs this scenario via `yarn test`, - // not via `ember try`. It's still included here so that running - // `ember try:each` manually or from a customized CI config will run it - // along with all the other scenarios. - { - name: 'ember-default', - npm: { - devDependencies: {} - } - }, - { - name: 'ember-default-with-jquery', - env: { - EMBER_OPTIONAL_FEATURES: JSON.stringify({ - 'jquery-integration': true - }) - }, - npm: { - devDependencies: { - '@ember/jquery': '^2.0.0' - } - } - } - ] - }; - }); -}; diff --git a/test-packages/sample-transforms/package.json b/test-packages/sample-transforms/package.json index 38059c92a..6bed11e36 100644 --- a/test-packages/sample-transforms/package.json +++ b/test-packages/sample-transforms/package.json @@ -44,7 +44,6 @@ "ember-source": "~3.26", "ember-source-channel-url": "^1.1.0", "ember-template-lint": "^3.6.0", - "ember-try": "^1.0.0", "eslint-plugin-ember": "^7.0.0", "eslint-plugin-node": "^9.0.1", "loader.js": "^4.7.0", diff --git a/test-packages/sample-transforms/testem.js b/test-packages/sample-transforms/testem.js index 442829a1a..aa5f6a7a8 100644 --- a/test-packages/sample-transforms/testem.js +++ b/test-packages/sample-transforms/testem.js @@ -1,2 +1,2 @@ -const { testemConfig } = require('@embroider/test-support/suite-setup-util'); +const { testemConfig } = require('@embroider/test-support/testem-config'); module.exports = testemConfig(); diff --git a/test-packages/support/suite-setup-util.ts b/test-packages/support/suite-setup-util.ts index 9a5cdff76..47565f705 100644 --- a/test-packages/support/suite-setup-util.ts +++ b/test-packages/support/suite-setup-util.ts @@ -1,135 +1,38 @@ -import { tmpdir } from '@embroider/shared-internals'; -import { basename, join, relative, resolve } from 'path'; -import { readdirSync, statSync, unlinkSync, writeFileSync } from 'fs-extra'; +import { relative, resolve } from 'path'; import execa from 'execa'; -// we sometimes run our various Ember app's test suites in parallel, and -// unfortunately the shared persistent caching underneath various broccoli -// plugins is not parallel-safe. So we give each suite a separate TMPDIR to run -// within. -export function separateTemp(name = `separate${Math.floor(Math.random() * 100000)}`): string { - return join(tmpdir, name); -} - -export function testemConfig() { - return { - test_page: 'tests/index.html?hidepassed', - disable_watching: true, - launch_in_ci: ['Chrome'], - launch_in_dev: ['Chrome'], - browser_start_timeout: 90, - browser_args: { - Chrome: { - ci: [ - // --no-sandbox is needed when running Chrome inside a container - process.env.CI ? '--no-sandbox' : null, - '--headless', - '--disable-dev-shm-usage', - '--disable-software-rasterizer', - '--mute-audio', - '--remote-debugging-port=0', - '--window-size=1440,900', - `--crash-dumps-dir=${process.env.TMPDIR}`, - ].filter(Boolean), - }, - }, - }; -} - -function expandDirs(relativeToHere: string): string[] { - let dir = resolve(__dirname, relativeToHere); - return readdirSync(dir) - .map(d => resolve(dir, d)) - .filter(d => statSync(d).isDirectory()); -} - -// these are all the separate test suites we want to run. As opposed to jest -// node tests, which run all together in a single jest run. -export async function allSuites({ includeEmberTry } = { includeEmberTry: true }) { - let packageDirs = [...expandDirs('..'), ...expandDirs('../../packages')]; - let suites = []; - for (let dir of packageDirs) { - let pkg = require(join(dir, 'package.json')); - if (pkg.scripts) { - for (let [name, command] of Object.entries(pkg.scripts as { [k: string]: string })) { - let m = /^test:(.*)/.exec(name); - if (m) { - if (command === 'ember try:each') { - if (includeEmberTry) { - // expand out all the ember-try scenarios as separate suites - let scenarios = require(join(dir, 'config/ember-try.js')); - for (let scenario of (await scenarios()).scenarios) { - suites.push({ - name: `${pkg.name} ${scenario.name}`, - command: 'yarn', - args: ['ember', 'try:one', scenario.name], - dir, - }); - } - } - } else { - suites.push({ - name: `${pkg.name} ${m[1]}`, - command: 'yarn', - args: [name], - dir, - }); - } - } - } - } - } - - // while we convert over from test-packages to test-scenarios here we merge both together - let { stdout } = await execa('scenario-tester', ['list', '--require', 'ts-node/register', '--files', '*-test.ts'], { - cwd: resolve(__dirname, '..', '..', 'tests', 'scenarios'), - preferLocal: true, - }); - - let testScenarios = stdout.split('\n'); - testScenarios.forEach(scenario => { - suites.push({ - name: scenario, - command: 'yarn', - args: ['test', '--filter', scenario], - dir: resolve(__dirname, '..', '..', 'tests', 'scenarios'), - }); - }); - - return suites; -} - function relativeToEmbroiderRoot(absolutePath: string): string { let embroiderRoot = resolve(__dirname, '../..'); - return relative(embroiderRoot, absolutePath); } -export async function githubMatrix() { - let suites = await allSuites(); +async function githubMatrix() { + let dir = resolve(__dirname, '..', '..', 'tests', 'scenarios'); + let { stdout } = await execa( + 'scenario-tester', + ['list', '--require', 'ts-node/register', '--files', '*-test.ts', '--matrix', 'yarn test --filter %s:'], + { + cwd: dir, + preferLocal: true, + } + ); - // add the node tests, which we don't consider a "suite" - suites.unshift({ - name: 'node', - command: 'yarn', - args: ['jest', '--forceExit'], - dir: resolve(__dirname, '..', '..'), - }); + let { include: suites } = JSON.parse(stdout) as { include: { name: string; command: string }[]; name: string[] }; let include = [ ...suites.map(s => ({ name: `${s.name} ubuntu`, os: 'ubuntu', - command: `${s.command} ${s.args.join(' ')}`, - dir: s.dir, + command: s.command, + dir, })), ...suites .filter(s => s.name !== 'node') // TODO: node tests do not work under windows yet .map(s => ({ name: `${s.name} windows`, os: 'windows', - command: `${s.command} ${s.args.join(' ')}`, - dir: relativeToEmbroiderRoot(s.dir), + command: s.command, + dir: relativeToEmbroiderRoot(dir), })), ]; @@ -139,65 +42,13 @@ export async function githubMatrix() { }; } -export async function emitDynamicSuites() { - let target = resolve(__dirname, 'dynamic_suites'); - for (let file of readdirSync(target)) { - if (file !== '.gitkeep') { - unlinkSync(resolve(target, file)); - } - } - - // we don't emit the ember try scenarios here because they can't be - // parallelized (they all mess with the monorepo-wide yarn state). - let suites = await allSuites({ includeEmberTry: false }); - - let jestSuites = new Map(); - for (let suite of suites) { - let assignedSuite = suite.name.replace(/^@[^/]+\//, '').replace(/[ /]/g, '_'); - let list = jestSuites.get(assignedSuite); - if (!list) { - list = []; - jestSuites.set(assignedSuite, list); - } - list.push(suite); - } - - for (let [dir, list] of jestSuites) { - let tests = [`const execa = require('execa');`, `const { separateTemp } = require('../suite-setup-util');`]; - for (let suite of list) { - tests.push(` - test("${suite.name}", async function() { - jest.setTimeout(300000); - await execa("${suite.command}", ${JSON.stringify(suite.args)}, { - cwd: "${suite.dir}", - env: { - TMPDIR: separateTemp() - } - }); - }); - `); - } - writeFileSync(join(target, `${basename(dir)}.test.js`), tests.join('\n'), 'utf8'); - } -} - async function main() { try { - if (process.argv.includes('--list')) { - const result = await allSuites(); - - process.stdout.write(JSON.stringify(result, null, 2) + '\n'); - } - if (process.argv.includes('--matrix')) { const result = await githubMatrix(); process.stdout.write(JSON.stringify(result)); } - - if (process.argv.includes('--emit')) { - await emitDynamicSuites(); - } } catch (error) { console.error(error); process.exitCode = -1; diff --git a/test-packages/support/testem-config.ts b/test-packages/support/testem-config.ts new file mode 100644 index 000000000..9ba831481 --- /dev/null +++ b/test-packages/support/testem-config.ts @@ -0,0 +1,24 @@ +export function testemConfig() { + return { + test_page: 'tests/index.html?hidepassed', + disable_watching: true, + launch_in_ci: ['Chrome'], + launch_in_dev: ['Chrome'], + browser_start_timeout: 90, + browser_args: { + Chrome: { + ci: [ + // --no-sandbox is needed when running Chrome inside a container + process.env.CI ? '--no-sandbox' : null, + '--headless', + '--disable-dev-shm-usage', + '--disable-software-rasterizer', + '--mute-audio', + '--remote-debugging-port=0', + '--window-size=1440,900', + `--crash-dumps-dir=${process.env.TMPDIR}`, + ].filter(Boolean), + }, + }, + }; +} diff --git a/tests/scenarios/jest-suites-test.ts b/tests/scenarios/jest-suites-test.ts new file mode 100644 index 000000000..3b50cfe9f --- /dev/null +++ b/tests/scenarios/jest-suites-test.ts @@ -0,0 +1,15 @@ +import QUnit from 'qunit'; +import { resolve } from 'path'; +import { PreparedApp } from 'scenario-tester'; + +const { module: Qmodule, test } = QUnit; + +// this is the bridge between our older Jest-based node tests and our newer +// scenario-tester powered tests +Qmodule('node', function () { + test('run node tests', async function (assert) { + let app = new PreparedApp(resolve(__dirname, '..', '..')); + let result = await app.execute('yarn jest --forceExit'); + assert.equal(result.exitCode, 0, result.output); + }); +}); diff --git a/tests/scenarios/macro-test.ts b/tests/scenarios/macro-test.ts index a97b114e0..12c2c5501 100644 --- a/tests/scenarios/macro-test.ts +++ b/tests/scenarios/macro-test.ts @@ -1,4 +1,4 @@ -import { appScenarios, appReleaseScenario, dummyAppScenarios, baseAddon } from './scenarios'; +import { appScenarios, dummyAppScenarios, baseAddon } from './scenarios'; import { PreparedApp, Project } from 'scenario-tester'; import QUnit from 'qunit'; import merge from 'lodash/merge'; @@ -70,7 +70,8 @@ appScenarios }); }); -appReleaseScenario +appScenarios + .only('release') .map('macro-babel-cache-busting', project => { scenarioSetup(project); }) diff --git a/tests/scenarios/package.json b/tests/scenarios/package.json index b0e5642e0..ec7d913b3 100644 --- a/tests/scenarios/package.json +++ b/tests/scenarios/package.json @@ -24,6 +24,8 @@ "@ember/string": "^1.0.0", "@embroider/macros": "1.2.0", "@embroider/addon-shim": "1.2.0", + "@embroider/router": "1.2.0", + "@embroider/util": "1.2.0", "bootstrap": "^4.3.1", "broccoli-funnel": "^3.0.5", "broccoli-merge-trees": "^3.0.2", diff --git a/tests/scenarios/router-test.ts b/tests/scenarios/router-test.ts new file mode 100644 index 000000000..7cb0d499e --- /dev/null +++ b/tests/scenarios/router-test.ts @@ -0,0 +1,21 @@ +import { supportMatrix } from './scenarios'; +import { PreparedApp, Scenarios } from 'scenario-tester'; +import QUnit from 'qunit'; +import { dirname } from 'path'; + +const { module: Qmodule, test } = QUnit; + +supportMatrix(Scenarios.fromDir(dirname(require.resolve('@embroider/router/package.json')))) + .map('router', () => {}) + .forEachScenario(scenario => { + Qmodule(scenario.name, function (hooks) { + let app: PreparedApp; + hooks.before(async () => { + app = await scenario.prepare(); + }); + test(`yarn test:ember`, async function (assert) { + let result = await app.execute('yarn test:ember'); + assert.equal(result.exitCode, 0, result.output); + }); + }); + }); diff --git a/tests/scenarios/scenarios.ts b/tests/scenarios/scenarios.ts index cb8868a4f..ace5bf440 100644 --- a/tests/scenarios/scenarios.ts +++ b/tests/scenarios/scenarios.ts @@ -54,10 +54,6 @@ export function supportMatrix(scenarios: Scenarios) { }); } -export function onlyRunRelease(scenarios: Scenarios) { - return scenarios.expand({ release }); -} - export function baseAddon(as: 'dummy-app' | 'dependency' = 'dependency') { return Project.fromDir( dirname(require.resolve('../addon-template/package.json')), @@ -71,4 +67,3 @@ export function baseApp() { export const appScenarios = supportMatrix(Scenarios.fromProject(baseApp)); export const dummyAppScenarios = supportMatrix(Scenarios.fromProject(() => baseAddon('dummy-app'))); -export const appReleaseScenario = onlyRunRelease(Scenarios.fromProject(baseApp)); diff --git a/tests/scenarios/stage1-test.ts b/tests/scenarios/stage1-test.ts index b1042a855..5e363dd53 100644 --- a/tests/scenarios/stage1-test.ts +++ b/tests/scenarios/stage1-test.ts @@ -3,13 +3,14 @@ import { join } from 'path'; import merge from 'lodash/merge'; import fs from 'fs-extra'; import { loadFromFixtureData } from './helpers'; -import { appReleaseScenario, dummyAppScenarios, baseAddon } from './scenarios'; +import { dummyAppScenarios, baseAddon, appScenarios } from './scenarios'; import { PreparedApp } from 'scenario-tester'; import QUnit from 'qunit'; const { module: Qmodule, test } = QUnit; -appReleaseScenario - .map('stage-1', project => { +appScenarios + .only('release') + .map('stage-1-max-compat', project => { let addon = baseAddon(); merge(addon.files, loadFromFixtureData('hello-world-addon')); @@ -24,7 +25,7 @@ appReleaseScenario merge(project.files, loadFromFixtureData('basic-in-repo-addon')); }) .forEachScenario(async scenario => { - Qmodule(`${scenario.name} max compatibility`, function (hooks) { + Qmodule(`${scenario.name}`, function (hooks) { let app: PreparedApp; let workspaceDir: string; @@ -129,7 +130,8 @@ appReleaseScenario }); }); -appReleaseScenario +appScenarios + .only('release') .map('stage-1-inline-hbs', project => { let addon = baseAddon(); @@ -158,7 +160,7 @@ appReleaseScenario project.addDependency(addon); }) .forEachScenario(async scenario => { - Qmodule(`${scenario.name} inline hbs, ember-cli-htmlbars@3`, function (hooks) { + Qmodule(`${scenario.name}`, function (hooks) { let app: PreparedApp; let workspaceDir: string; @@ -188,7 +190,8 @@ appReleaseScenario }); }); -appReleaseScenario +appScenarios + .only('release') .map('stage-1-problematic-addon-zoo', project => { let addon = baseAddon(); @@ -348,7 +351,7 @@ appReleaseScenario merge(project.files, loadFromFixtureData('blacklisted-addon-build-options')); }) .forEachScenario(async scenario => { - Qmodule(`${scenario.name} problematic addon zoo`, function (hooks) { + Qmodule(`${scenario.name}`, function (hooks) { let app: PreparedApp; let workspaceDir: string; @@ -427,7 +430,7 @@ dummyAppScenarios }); }) .forEachScenario(async scenario => { - Qmodule(`${scenario.name} addon dummy app`, function (hooks) { + Qmodule(`${scenario.name}`, function (hooks) { let app: PreparedApp; let workspaceDir: string; diff --git a/tests/scenarios/util-test.ts b/tests/scenarios/util-test.ts new file mode 100644 index 000000000..2d16e8e40 --- /dev/null +++ b/tests/scenarios/util-test.ts @@ -0,0 +1,27 @@ +import { supportMatrix } from './scenarios'; +import { PreparedApp, Scenarios } from 'scenario-tester'; +import QUnit from 'qunit'; +import { dirname } from 'path'; + +const { module: Qmodule, test } = QUnit; + +supportMatrix(Scenarios.fromDir(dirname(require.resolve('@embroider/util/package.json')))) + .map('util', () => {}) + .forEachScenario(scenario => { + Qmodule(scenario.name, function (hooks) { + let app: PreparedApp; + hooks.before(async () => { + app = await scenario.prepare(); + }); + + test(`yarn test:ember`, async function (assert) { + let result = await app.execute('yarn test:ember'); + assert.equal(result.exitCode, 0, result.output); + }); + + test(`yarn test:classic`, async function (assert) { + let result = await app.execute('yarn test:classic'); + assert.equal(result.exitCode, 0, result.output); + }); + }); + }); diff --git a/yarn.lock b/yarn.lock index 73d7781a8..eef38ba44 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8724,7 +8724,7 @@ ember-try-config@^3.0.0: rsvp "^4.8.1" semver "^5.5.0" -ember-try@^1.0.0, ember-try@^1.4.0: +ember-try@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ember-try/-/ember-try-1.4.0.tgz#be15965bd1727c27a65a78c4c8392f03763cc565" integrity sha512-o0SoCH4K8umCf8etphla8FDygKfQGkwY+w47wEuYFVKaESrOZaK63ObnAK7DTKkjJU74Fss2abf+r+pAWpX43g==