diff --git a/.eslintrc.js b/.eslintrc.js index 16cb435e80c..8afddfde403 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -2,15 +2,18 @@ module.exports = { root: true, extends: [ 'eslint:recommended', + 'prettier', ], plugins: [ - "ember-internal" + 'ember-internal', + 'prettier', ], rules: { 'semi': 'error', 'no-unused-vars': 'error', 'no-useless-escape': 'off', // TODO: bring this back + 'prettier/prettier': 'error', }, overrides: [ @@ -23,7 +26,7 @@ module.exports = { }, globals: { - // A safe subset of "browser:true": + // A safe subset of 'browser:true': 'window': true, 'document': true, 'setTimeout': true, diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 00000000000..978b4d511ea --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,7 @@ +'use strict'; + +module.exports = { + singleQuote: true, + trailingComma: 'es5', + printWidth: 100, +}; diff --git a/bin/build-for-publishing.js b/bin/build-for-publishing.js index d40ba3ec457..9e7e16fb44e 100755 --- a/bin/build-for-publishing.js +++ b/bin/build-for-publishing.js @@ -26,7 +26,9 @@ function updatePackageJSONVersion() { pkg._versionPreviouslyCalculated = true; pkg._originalVersion = pkg.version; pkg.version = VERSION; - fs.writeFileSync(packageJSONPath, JSON.stringify(pkg, null, 2), { encoding: 'utf-8' }); + fs.writeFileSync(packageJSONPath, JSON.stringify(pkg, null, 2), { + encoding: 'utf-8' + }); } /* @@ -43,11 +45,12 @@ function updateDocumentationVersion() { let contents = fs.readFileSync(docsPath, { encoding: 'utf-8' }); let docs = JSON.parse(contents); docs.project.version = VERSION; - fs.writeFileSync(docsPath, JSON.stringify(docs, null, 2), { encoding: 'utf-8' }); + fs.writeFileSync(docsPath, JSON.stringify(docs, null, 2), { + encoding: 'utf-8' + }); } -Promise - .resolve() +Promise.resolve() .then(() => { updatePackageJSONVersion(); // ensures that we tag this correctly @@ -69,9 +72,13 @@ Promise version: VERSION, buildType: process.env.BUILD_TYPE, SHA: process.env.TRAVIS_COMMIT, - assetPath: `/${process.env.BUILD_TYPE}/shas/${process.env.TRAVIS_COMMIT}.tgz`, + assetPath: `/${process.env.BUILD_TYPE}/shas/${ + process.env.TRAVIS_COMMIT + }.tgz` }; - fs.writeFileSync('build-metadata.json', JSON.stringify(metadata, null, 2), { encoding: 'utf-8' }); + fs.writeFileSync('build-metadata.json', JSON.stringify(metadata, null, 2), { + encoding: 'utf-8' + }); // using npm pack here because `yarn pack` does not honor the `package.json`'s `files` // property properly, and therefore the tarball generated is quite large (~7MB). @@ -80,7 +87,7 @@ Promise .then( // eslint-disable-next-line () => console.log('build-for-publishing completed succesfully!'), - (error) => { + error => { // eslint-disable-next-line console.error(error); // eslint-disable-next-line diff --git a/bin/feature-flag-yuidoc-filter.js b/bin/feature-flag-yuidoc-filter.js index 21b2f8db08e..3bc1803914d 100755 --- a/bin/feature-flag-yuidoc-filter.js +++ b/bin/feature-flag-yuidoc-filter.js @@ -49,7 +49,7 @@ function updateClassReferencesInNamespaces(data) { } } -module.exports = function (data) { +module.exports = function(data) { var featuresToFilter = gatherFeatures(); data.classes = gatherClassesToDocument(data, featuresToFilter); updateClassReferencesInNamespaces(data); diff --git a/bin/publish_to_s3.js b/bin/publish_to_s3.js index a850d146f6f..c15b5084ba6 100755 --- a/bin/publish_to_s3.js +++ b/bin/publish_to_s3.js @@ -1,4 +1,3 @@ - // To invoke this from the commandline you need the following to env vars to exist: // // S3_BUCKET_NAME @@ -14,17 +13,23 @@ // ./bin/publish_to_s3.js // ``` var S3Publisher = require('ember-publisher'); -var configPath = require('path').join(__dirname, '../config/s3ProjectConfig.js'); +var configPath = require('path').join( + __dirname, + '../config/s3ProjectConfig.js' +); var publisher = new S3Publisher({ projectConfigPath: configPath }); publisher.currentBranch = function() { - return process.env.BUILD_TYPE || { - master: 'canary', - beta: 'beta', - release: 'release', - 'lts-2-4': 'lts-2-4', - }[this.CURRENT_BRANCH]; + return ( + process.env.BUILD_TYPE || + { + master: 'canary', + beta: 'beta', + release: 'release', + 'lts-2-4': 'lts-2-4' + }[this.CURRENT_BRANCH] + ); }; publisher.publish(); diff --git a/bin/run-browserstack-tests.js b/bin/run-browserstack-tests.js index bdfeb389ca2..a2d18fa622f 100755 --- a/bin/run-browserstack-tests.js +++ b/bin/run-browserstack-tests.js @@ -1,7 +1,6 @@ - /* eslint-disable no-console */ -var RSVP = require('rsvp'); +var RSVP = require('rsvp'); var spawn = require('child_process').spawn; function run(command, _args) { @@ -36,13 +35,21 @@ function run(command, _args) { RSVP.resolve() .then(function() { - return run('./node_modules/.bin/ember', [ 'browserstack:connect' ]); + return run('./node_modules/.bin/ember', ['browserstack:connect']); }) .then(function() { // Calling testem directly here instead of `ember test` so that // we do not have to do a double build (by the time this is run // we have already ran `ember build`). - return run('./node_modules/.bin/testem', [ 'ci', '-f', 'testem.dist.js', '--host', '127.0.0.1', '--port', '7774' ]); + return run('./node_modules/.bin/testem', [ + 'ci', + '-f', + 'testem.dist.js', + '--host', + '127.0.0.1', + '--port', + '7774' + ]); }) .finally(function() { var promise = RSVP.resolve(); @@ -57,7 +64,8 @@ RSVP.resolve() console.log('error'); console.log(error); process.exit(1); - }).then(function() { + }) + .then(function() { console.log('success'); process.exit(0); }); diff --git a/bin/run-tests.js b/bin/run-tests.js index d4ee132ba3d..edb2eb53bef 100755 --- a/bin/run-tests.js +++ b/bin/run-tests.js @@ -3,7 +3,7 @@ 'use strict'; var execa = require('execa'); -var RSVP = require('rsvp'); +var RSVP = require('rsvp'); var execFile = require('child_process').execFile; var chalk = require('chalk'); var FEATURES = require('../broccoli/features'); @@ -16,7 +16,7 @@ var http = require('http'); var serveStatic = require('serve-static'); // Serve up public/ftp folder. -var serve = serveStatic('./dist/', { 'index': ['index.html', 'index.htm'] }); +var serve = serveStatic('./dist/', { index: ['index.html', 'index.htm'] }); // Create server. var server = http.createServer(function(req, res) { @@ -36,7 +36,7 @@ function run(queryString) { } function runInBrowser(url, retries, resolve, reject) { - var result = {output: [], errors: [], code: null}; + var result = { output: [], errors: [], code: null }; console.log('Running Chrome headless: ' + url); @@ -71,7 +71,7 @@ function runInBrowser(url, retries, resolve, reject) { var testsFailed = 0; var currentTestAssertions = []; - QUnit.log(function (details) { + QUnit.log(function(details) { var response; // Ignore passing assertions @@ -86,7 +86,11 @@ function runInBrowser(url, retries, resolve, reject) { response += ', '; } - response += 'expected: ' + details.expected + ', but was: ' + details.actual; + response += + 'expected: ' + + details.expected + + ', but was: ' + + details.actual; } if (details.source) { @@ -96,10 +100,10 @@ function runInBrowser(url, retries, resolve, reject) { currentTestAssertions.push('Failed assertion: ' + response); }); - QUnit.testDone(function (result) { + QUnit.testDone(function(result) { var i, - len, - name = ''; + len, + name = ''; if (result.module) { name += result.module + ': '; @@ -122,13 +126,24 @@ function runInBrowser(url, retries, resolve, reject) { currentTestAssertions.length = 0; }); - QUnit.done(function (result) { - console.log('\n' + 'Took ' + result.runtime + 'ms to run ' + testsTotal + ' tests. ' + testsPassed + ' passed, ' + testsFailed + ' failed.'); + QUnit.done(function(result) { + console.log( + '\n' + + 'Took ' + + result.runtime + + 'ms to run ' + + testsTotal + + ' tests. ' + + testsPassed + + ' passed, ' + + testsFailed + + ' failed.' + ); if (typeof window.callPhantom === 'function') { window.callPhantom({ - 'name': 'QUnit.done', - 'data': result + name: 'QUnit.done', + data: result }); } }); @@ -141,7 +156,9 @@ function runInBrowser(url, retries, resolve, reject) { var failed = !result || !result.total || result.failed; if (!result.total) { - console.error('No tests were executed. Are you loading tests asynchronously?'); + console.error( + 'No tests were executed. Are you loading tests asynchronously?' + ); } var code = failed ? 1 : 0; @@ -153,11 +170,15 @@ function runInBrowser(url, retries, resolve, reject) { console.log(chalk.red('Browser crashed with exit code ' + code)); if (retries > 1) { - console.log(chalk.yellow('Retrying... ¯\_(ツ)_/¯')); + console.log(chalk.yellow('Retrying... ¯_(ツ)_/¯')); runInBrowser(url, retries - 1, resolve, reject); } else { console.log(chalk.red('Giving up! (╯°□°)╯︵ ┻━┻')); - console.log(chalk.yellow('This might be a known issue with Chrome headless, skipping for now')); + console.log( + chalk.yellow( + 'This might be a known issue with Chrome headless, skipping for now' + ) + ); resolve(result); } } else { @@ -180,7 +201,9 @@ function generateEachPackageTests() { var packages = getPackages(features); Object.keys(packages).forEach(function(packageName) { - if (packages[packageName].skipTests) { return; } + if (packages[packageName].skipTests) { + return; + } testFunctions.push(function() { return run('package=' + packageName); @@ -196,7 +219,6 @@ function generateEachPackageTests() { testFunctions.push(function() { return run('package=' + packageName + '&enableoptionalfeatures=true'); }); - }); } @@ -253,19 +275,13 @@ function runChecker(bin, args) { function codeQualityChecks() { var checkers = [ - runChecker('node', [ - require.resolve('typescript/bin/tsc'), - '--noEmit' - ]), + runChecker('node', [require.resolve('typescript/bin/tsc'), '--noEmit']), runChecker('node', [ require.resolve('tslint/bin/tslint'), '-p', 'tsconfig.json' ]), - runChecker('node', [ - require.resolve('eslint/bin/eslint'), - '.' - ]) + runChecker('node', [require.resolve('eslint/bin/eslint'), '.']) ]; return RSVP.Promise.all(checkers).then(function(results) { results.forEach(result => { @@ -276,7 +292,7 @@ function codeQualityChecks() { } }); if (!results.every(result => result.ok)) { - throw new Error("Some quality checks failed"); + throw new Error('Some quality checks failed'); } }); } @@ -293,7 +309,6 @@ function runAndExit() { }); } - switch (process.env.TEST_SUITE) { case 'built-tests': console.log('suite: built-tests'); diff --git a/bin/run-travis-browser-tests.js b/bin/run-travis-browser-tests.js index f0aa0b0a064..d2d17b74b01 100755 --- a/bin/run-travis-browser-tests.js +++ b/bin/run-travis-browser-tests.js @@ -1,7 +1,6 @@ - /* eslint-disable no-console */ -var RSVP = require('rsvp'); +var RSVP = require('rsvp'); var spawn = require('child_process').spawn; function run(command, _args) { @@ -35,13 +34,18 @@ function run(command, _args) { }); } - RSVP.resolve() .then(function() { return run('./node_modules/.bin/testem', ['launchers']); }) .then(function() { - return run('./node_modules/.bin/testem', ['ci', '--file', 'testem.travis-browsers.js', '--port', '7000']); + return run('./node_modules/.bin/testem', [ + 'ci', + '--file', + 'testem.travis-browsers.js', + '--port', + '7000' + ]); }) .catch(function(error) { console.error(error.stack); diff --git a/bin/yarn-link-glimmer.js b/bin/yarn-link-glimmer.js index e2fb46005c8..72daa167167 100755 --- a/bin/yarn-link-glimmer.js +++ b/bin/yarn-link-glimmer.js @@ -1,8 +1,16 @@ -"use strict"; -const child_process = require("child_process"); +'use strict'; +const child_process = require('child_process'); -const yarnConfig = JSON.parse(JSON.parse(require('child_process').execSync('yarn --json config current', { encoding: 'utf8' })).data); -const linkedModules = yarnConfig.linkedModules.filter((m) => m.startsWith('@glimmer/')); +const yarnConfig = JSON.parse( + JSON.parse( + require('child_process').execSync('yarn --json config current', { + encoding: 'utf8' + }) + ).data +); +const linkedModules = yarnConfig.linkedModules.filter(m => + m.startsWith('@glimmer/') +); linkedModules.forEach(mod => { child_process.execSync(`yarn link "${mod}"`); diff --git a/bin/yarn-unlink-glimmer.js b/bin/yarn-unlink-glimmer.js index 5fcc8ebeda4..cdd161bb1c0 100755 --- a/bin/yarn-unlink-glimmer.js +++ b/bin/yarn-unlink-glimmer.js @@ -1,8 +1,16 @@ -"use strict"; -const child_process = require("child_process"); +'use strict'; +const child_process = require('child_process'); -const yarnConfig = JSON.parse(JSON.parse(require('child_process').execSync('yarn --json config current', { encoding: 'utf8' })).data); -const linkedModules = yarnConfig.linkedModules.filter((m) => m.startsWith('@glimmer/')); +const yarnConfig = JSON.parse( + JSON.parse( + require('child_process').execSync('yarn --json config current', { + encoding: 'utf8' + }) + ).data +); +const linkedModules = yarnConfig.linkedModules.filter(m => + m.startsWith('@glimmer/') +); linkedModules.forEach(mod => { child_process.execSync(`yarn unlink "${mod}"`); diff --git a/blueprints/-addon-import.js b/blueprints/-addon-import.js index ed89ae9891d..d950ca1d8f3 100644 --- a/blueprints/-addon-import.js +++ b/blueprints/-addon-import.js @@ -1,8 +1,8 @@ 'use strict'; -var stringUtil = require('ember-cli-string-utils'); -var path = require('path'); -var inflector = require('inflection'); +var stringUtil = require('ember-cli-string-utils'); +var path = require('path'); +var inflector = require('inflection'); module.exports = { description: 'Generates an import wrapper.', @@ -25,15 +25,25 @@ module.exports = { }, locals: function(options) { - var addonRawName = options.inRepoAddon ? options.inRepoAddon : options.project.name(); - var addonName = stringUtil.dasherize(addonRawName); - var fileName = stringUtil.dasherize(options.entity.name); - var blueprintName = options.originBlueprintName; - var modulePathSegments = [addonName, inflector.pluralize(options.originBlueprintName), fileName]; + var addonRawName = options.inRepoAddon + ? options.inRepoAddon + : options.project.name(); + var addonName = stringUtil.dasherize(addonRawName); + var fileName = stringUtil.dasherize(options.entity.name); + var blueprintName = options.originBlueprintName; + var modulePathSegments = [ + addonName, + inflector.pluralize(options.originBlueprintName), + fileName + ]; if (blueprintName.match(/-addon/)) { blueprintName = blueprintName.substr(0, blueprintName.indexOf('-addon')); - modulePathSegments = [addonName, inflector.pluralize(blueprintName), fileName]; + modulePathSegments = [ + addonName, + inflector.pluralize(blueprintName), + fileName + ]; } return { diff --git a/blueprints/acceptance-test/index.js b/blueprints/acceptance-test/index.js index 36dad5e966d..db6cd7619a5 100644 --- a/blueprints/acceptance-test/index.js +++ b/blueprints/acceptance-test/index.js @@ -14,13 +14,21 @@ module.exports = useTestFrameworkDetector({ let testFolderRoot = stringUtils.dasherize(options.project.name()); if (options.project.isEmberCLIAddon()) { - testFolderRoot = pathUtil.getRelativeParentPath(options.entity.name, -1, false); + testFolderRoot = pathUtil.getRelativeParentPath( + options.entity.name, + -1, + false + ); } - let destroyAppExists = - fs.existsSync(path.join(this.project.root, '/tests/helpers/destroy-app.js')); + let destroyAppExists = fs.existsSync( + path.join(this.project.root, '/tests/helpers/destroy-app.js') + ); - let friendlyTestName = ['Acceptance', stringUtils.dasherize(options.entity.name).replace(/[-]/g,' ')].join(' | '); + let friendlyTestName = [ + 'Acceptance', + stringUtils.dasherize(options.entity.name).replace(/[-]/g, ' ') + ].join(' | '); return { testFolderRoot: testFolderRoot, diff --git a/blueprints/component-addon/index.js b/blueprints/component-addon/index.js index 82da2928edc..3386da0ac77 100644 --- a/blueprints/component-addon/index.js +++ b/blueprints/component-addon/index.js @@ -13,7 +13,11 @@ module.exports = { return { __path__: function(options) { if (options.pod) { - return path.join(options.podPath, options.locals.path, options.dasherizedModuleName); + return path.join( + options.podPath, + options.locals.path, + options.dasherizedModuleName + ); } return 'components'; }, @@ -39,13 +43,17 @@ module.exports = { }, locals: function(options) { - let addonRawName = options.inRepoAddon ? options.inRepoAddon : options.project.name(); - let addonName = stringUtil.dasherize(addonRawName); - let fileName = stringUtil.dasherize(options.entity.name); - let importPathName = [addonName, 'components', fileName].join('/'); + let addonRawName = options.inRepoAddon + ? options.inRepoAddon + : options.project.name(); + let addonName = stringUtil.dasherize(addonRawName); + let fileName = stringUtil.dasherize(options.entity.name); + let importPathName = [addonName, 'components', fileName].join('/'); if (options.pod) { - importPathName = [addonName, 'components', fileName, 'component'].join('/'); + importPathName = [addonName, 'components', fileName, 'component'].join( + '/' + ); } return { diff --git a/blueprints/component-test/index.js b/blueprints/component-test/index.js index c26019056f6..d3f8a17aab8 100644 --- a/blueprints/component-test/index.js +++ b/blueprints/component-test/index.js @@ -6,7 +6,8 @@ const isPackageMissing = require('ember-cli-is-package-missing'); const getPathOption = require('ember-cli-get-component-path-option'); const useTestFrameworkDetector = require('../test-framework-detector'); -const isModuleUnificationProject = require('../module-unification').isModuleUnificationProject; +const isModuleUnificationProject = require('../module-unification') + .isModuleUnificationProject; module.exports = useTestFrameworkDetector({ description: 'Generates a component integration or unit test.', @@ -17,10 +18,10 @@ module.exports = useTestFrameworkDetector({ type: ['integration', 'unit'], default: 'integration', aliases: [ - { 'i': 'integration' }, - { 'u': 'unit' }, - { 'integration': 'integration' }, - { 'unit': 'unit' } + { i: 'integration' }, + { u: 'unit' }, + { integration: 'integration' }, + { unit: 'unit' } ] } ], @@ -39,14 +40,14 @@ module.exports = useTestFrameworkDetector({ }, __testType__(options) { if (options.locals.testType === 'unit') { - throw 'The --unit flag isn\'t supported within a module unification app'; + throw "The --unit flag isn't supported within a module unification app"; } return ''; }, __path__(options) { if (options.pod) { - throw 'Pods aren\'t supported within a module unification app'; + throw "Pods aren't supported within a module unification app"; } return path.join('ui', 'components', options.dasherizedModuleName); } @@ -61,7 +62,11 @@ module.exports = useTestFrameworkDetector({ }, __path__(options) { if (options.pod) { - return path.join(options.podPath, options.locals.path, options.dasherizedModuleName); + return path.join( + options.podPath, + options.locals.path, + options.dasherizedModuleName + ); } return 'components'; } @@ -77,11 +82,13 @@ module.exports = useTestFrameworkDetector({ let friendlyTestDescription = [ testType === 'unit' ? 'Unit' : 'Integration', 'Component', - dasherizedModuleName, + dasherizedModuleName ].join(' | '); if (options.pod && options.path !== 'components' && options.path !== '') { - componentPathName = [options.path, dasherizedModuleName].filter(Boolean).join('/'); + componentPathName = [options.path, dasherizedModuleName] + .filter(Boolean) + .join('/'); } else if (isModuleUnificationProject(this.project)) { if (options.inRepoAddon) { componentPathName = `${options.inRepoAddon}::${dasherizedModuleName}`; @@ -99,7 +106,11 @@ module.exports = useTestFrameworkDetector({ }, afterInstall: function(options) { - if (!options.dryRun && options.testType === 'integration' && isPackageMissing(this, 'ember-cli-htmlbars-inline-precompile')) { + if ( + !options.dryRun && + options.testType === 'integration' && + isPackageMissing(this, 'ember-cli-htmlbars-inline-precompile') + ) { return this.addPackagesToProject([ { name: 'ember-cli-htmlbars-inline-precompile', target: '^0.3.1' } ]); diff --git a/blueprints/component/index.js b/blueprints/component/index.js index 203c542100d..0da7e32a69a 100644 --- a/blueprints/component/index.js +++ b/blueprints/component/index.js @@ -6,7 +6,8 @@ const pathUtil = require('ember-cli-path-utils'); const validComponentName = require('ember-cli-valid-component-name'); const getPathOption = require('ember-cli-get-component-path-option'); const normalizeEntityName = require('ember-cli-normalize-entity-name'); -const isModuleUnificationProject = require('../module-unification').isModuleUnificationProject; +const isModuleUnificationProject = require('../module-unification') + .isModuleUnificationProject; module.exports = { description: 'Generates a component. Name must contain a hyphen.', @@ -16,9 +17,7 @@ module.exports = { name: 'path', type: String, default: 'components', - aliases: [ - { 'no-path': '' } - ] + aliases: [{ 'no-path': '' }] } ], @@ -46,20 +45,28 @@ module.exports = { }, __path__(options) { return path.join('ui', 'components', options.dasherizedModuleName); - }, + } }; } else { return { __path__: function(options) { if (options.pod) { - return path.join(options.podPath, options.locals.path, options.dasherizedModuleName); + return path.join( + options.podPath, + options.locals.path, + options.dasherizedModuleName + ); } else { return 'components'; } }, __templatepath__: function(options) { if (options.pod) { - return path.join(options.podPath, options.locals.path, options.dasherizedModuleName); + return path.join( + options.podPath, + options.locals.path, + options.dasherizedModuleName + ); } return 'templates/components'; }, @@ -80,21 +87,25 @@ module.exports = { }, locals: function(options) { - let templatePath = ''; + let templatePath = ''; let importTemplate = ''; - let contents = ''; + let contents = ''; // if we're in an addon, build import statement - if (options.project.isEmberCLIAddon() || options.inRepoAddon && !options.inDummy) { + if ( + options.project.isEmberCLIAddon() || + (options.inRepoAddon && !options.inDummy) + ) { if (options.pod) { - templatePath = './template'; + templatePath = './template'; } else { - templatePath = pathUtil.getRelativeParentPath(options.entity.name) + - 'templates/components/' + stringUtil.dasherize(options.entity.name); - + templatePath = + pathUtil.getRelativeParentPath(options.entity.name) + + 'templates/components/' + + stringUtil.dasherize(options.entity.name); } - importTemplate = 'import layout from \'' + templatePath + '\';\n'; - contents = '\n layout'; + importTemplate = "import layout from '" + templatePath + "';\n"; + contents = '\n layout'; } return { diff --git a/blueprints/controller-test/index.js b/blueprints/controller-test/index.js index f3adbf0d8a1..e6c7c3cbe01 100644 --- a/blueprints/controller-test/index.js +++ b/blueprints/controller-test/index.js @@ -11,7 +11,11 @@ module.exports = useTestFrameworkDetector({ let controllerPathName = dasherizedModuleName; return { controllerPathName: controllerPathName, - friendlyTestDescription: ['Unit', 'Controller', dasherizedModuleName].join(' | ') + friendlyTestDescription: [ + 'Unit', + 'Controller', + dasherizedModuleName + ].join(' | ') }; } }); diff --git a/blueprints/helper-test/index.js b/blueprints/helper-test/index.js index 560f89f23c3..6d755147f78 100644 --- a/blueprints/helper-test/index.js +++ b/blueprints/helper-test/index.js @@ -14,10 +14,10 @@ module.exports = useTestFrameworkDetector({ type: ['integration', 'unit'], default: 'integration', aliases: [ - { 'i': 'integration' }, - { 'u': 'unit' }, - { 'integration': 'integration' }, - { 'unit': 'unit' } + { i: 'integration' }, + { u: 'unit' }, + { integration: 'integration' }, + { unit: 'unit' } ] } ], @@ -33,17 +33,25 @@ module.exports = useTestFrameworkDetector({ locals: function(options) { let testType = options.testType || 'integration'; let testName = testType === 'integration' ? 'Integration' : 'Unit'; - let friendlyTestName = [testName, 'Helper', options.entity.name].join(' | '); + let friendlyTestName = [testName, 'Helper', options.entity.name].join( + ' | ' + ); return { friendlyTestName: friendlyTestName, - dasherizedModulePrefix: stringUtils.dasherize(options.project.config().modulePrefix), + dasherizedModulePrefix: stringUtils.dasherize( + options.project.config().modulePrefix + ), testType: testType }; }, afterInstall: function(options) { - if (!options.dryRun && options.testType === 'integration' && isPackageMissing(this, 'ember-cli-htmlbars-inline-precompile')) { + if ( + !options.dryRun && + options.testType === 'integration' && + isPackageMissing(this, 'ember-cli-htmlbars-inline-precompile') + ) { return this.addPackagesToProject([ { name: 'ember-cli-htmlbars-inline-precompile', target: '^0.3.1' } ]); diff --git a/blueprints/initializer-test/index.js b/blueprints/initializer-test/index.js index 0750bc0f30b..c4410f6c23d 100644 --- a/blueprints/initializer-test/index.js +++ b/blueprints/initializer-test/index.js @@ -10,9 +10,15 @@ module.exports = useTestFrameworkDetector({ description: 'Generates an initializer unit test.', locals: function(options) { return { - friendlyTestName: ['Unit', 'Initializer', options.entity.name].join(' | '), - dasherizedModulePrefix: stringUtils.dasherize(options.project.config().modulePrefix), - destroyAppExists: fs.existsSync(path.join(this.project.root, '/tests/helpers/destroy-app.js')) + friendlyTestName: ['Unit', 'Initializer', options.entity.name].join( + ' | ' + ), + dasherizedModulePrefix: stringUtils.dasherize( + options.project.config().modulePrefix + ), + destroyAppExists: fs.existsSync( + path.join(this.project.root, '/tests/helpers/destroy-app.js') + ) }; } }); diff --git a/blueprints/instance-initializer-test/index.js b/blueprints/instance-initializer-test/index.js index 3899d692666..3b5c3086423 100644 --- a/blueprints/instance-initializer-test/index.js +++ b/blueprints/instance-initializer-test/index.js @@ -10,9 +10,17 @@ module.exports = useTestFrameworkDetector({ description: 'Generates an instance initializer unit test.', locals: function(options) { return { - friendlyTestName: ['Unit', 'Instance Initializer', options.entity.name].join(' | '), - dasherizedModulePrefix: stringUtils.dasherize(options.project.config().modulePrefix), - destroyAppExists: fs.existsSync(path.join(this.project.root, '/tests/helpers/destroy-app.js')) + friendlyTestName: [ + 'Unit', + 'Instance Initializer', + options.entity.name + ].join(' | '), + dasherizedModulePrefix: stringUtils.dasherize( + options.project.config().modulePrefix + ), + destroyAppExists: fs.existsSync( + path.join(this.project.root, '/tests/helpers/destroy-app.js') + ) }; } }); diff --git a/blueprints/mixin-test/index.js b/blueprints/mixin-test/index.js index 146587f3953..df0dc09d194 100644 --- a/blueprints/mixin-test/index.js +++ b/blueprints/mixin-test/index.js @@ -6,7 +6,9 @@ module.exports = useTestFrameworkDetector({ description: 'Generates a mixin unit test.', locals: function(options) { return { - projectName: options.inRepoAddon ? options.inRepoAddon : options.project.name(), + projectName: options.inRepoAddon + ? options.inRepoAddon + : options.project.name(), friendlyTestName: ['Unit', 'Mixin', options.entity.name].join(' | ') }; } diff --git a/blueprints/route-addon/index.js b/blueprints/route-addon/index.js index 7cb062215d9..6e794435d32 100644 --- a/blueprints/route-addon/index.js +++ b/blueprints/route-addon/index.js @@ -21,7 +21,7 @@ module.exports = { } return options.dasherizedModuleName; }, - __name__: function (options) { + __name__: function(options) { if (options.pod) { return 'route'; } @@ -45,14 +45,18 @@ module.exports = { }; }, - locals: function (options) { + locals: function(options) { let locals = {}; - let addonRawName = options.inRepoAddon ? options.inRepoAddon : options.project.name(); + let addonRawName = options.inRepoAddon + ? options.inRepoAddon + : options.project.name(); let addonName = stringUtil.dasherize(addonRawName); let fileName = stringUtil.dasherize(options.entity.name); - ['route', 'template'].forEach(function (blueprint) { - let pathName = [addonName, inflector.pluralize(blueprint), fileName].join('/'); + ['route', 'template'].forEach(function(blueprint) { + let pathName = [addonName, inflector.pluralize(blueprint), fileName].join( + '/' + ); if (options.pod) { pathName = [addonName, fileName, blueprint].join('/'); diff --git a/blueprints/route-test/index.js b/blueprints/route-test/index.js index e633fde0140..268895d0ebf 100644 --- a/blueprints/route-test/index.js +++ b/blueprints/route-test/index.js @@ -16,7 +16,7 @@ module.exports = useTestFrameworkDetector({ fileMapTokens: function() { return { - __test__: function (options) { + __test__: function(options) { let moduleName = options.locals.moduleName; if (options.pod) { @@ -42,8 +42,10 @@ module.exports = useTestFrameworkDetector({ } return { - friendlyTestDescription: ['Unit', 'Route', options.entity.name].join(' | '), + friendlyTestDescription: ['Unit', 'Route', options.entity.name].join( + ' | ' + ), moduleName: stringUtil.dasherize(moduleName) }; - }, + } }); diff --git a/blueprints/route/index.js b/blueprints/route/index.js index d5a74d00b15..28fd3eb3ff3 100644 --- a/blueprints/route/index.js +++ b/blueprints/route/index.js @@ -7,7 +7,8 @@ const stringUtil = require('ember-cli-string-utils'); const EmberRouterGenerator = require('ember-router-generator'); module.exports = { - description: 'Generates a route and a template, and registers the route with the router.', + description: + 'Generates a route and a template, and registers the route with the router.', availableOptions: [ { @@ -28,7 +29,7 @@ module.exports = { fileMapTokens: function() { return { - __name__: function (options) { + __name__: function(options) { if (options.pod) { return 'route'; } @@ -94,9 +95,15 @@ module.exports = { let entityTouchesRouter = this.shouldEntityTouchRouter(name); let isDummy = !!options.dummy; let isAddon = !!options.project.isEmberCLIAddon(); - let isAddonDummyOrApp = (isDummy === isAddon); - - return (entityTouchesRouter && isAddonDummyOrApp && !options.dryRun && !options.inRepoAddon && !options.skipRouter); + let isAddonDummyOrApp = isDummy === isAddon; + + return ( + entityTouchesRouter && + isAddonDummyOrApp && + !options.dryRun && + !options.inRepoAddon && + !options.skipRouter + ); }, afterInstall: function(options) { @@ -128,7 +135,12 @@ function findRouter(options) { let routerPathParts = [options.project.root]; if (options.dummy && options.project.isEmberCLIAddon()) { - routerPathParts = routerPathParts.concat(['tests', 'dummy', 'app', 'router.js']); + routerPathParts = routerPathParts.concat([ + 'tests', + 'dummy', + 'app', + 'router.js' + ]); } else { routerPathParts = routerPathParts.concat(['app', 'router.js']); } diff --git a/blueprints/service-test/index.js b/blueprints/service-test/index.js index e5bb9d2a598..844307cda2b 100644 --- a/blueprints/service-test/index.js +++ b/blueprints/service-test/index.js @@ -6,7 +6,9 @@ module.exports = useTestFrameworkDetector({ description: 'Generates a service unit test.', locals: function(options) { return { - friendlyTestDescription: ['Unit', 'Service', options.entity.name].join(' | ') + friendlyTestDescription: ['Unit', 'Service', options.entity.name].join( + ' | ' + ) }; - }, + } }); diff --git a/blueprints/test-framework-detector.js b/blueprints/test-framework-detector.js index c4fef5cabb9..ce46022345d 100644 --- a/blueprints/test-framework-detector.js +++ b/blueprints/test-framework-detector.js @@ -15,28 +15,30 @@ module.exports = function(blueprint) { let dependencies = this.project.dependencies(); if ('ember-qunit' in dependencies) { type = 'qunit-rfc-232'; - } else if ('ember-cli-qunit' in dependencies) { let checker = new VersionChecker(this.project); - if (fs.existsSync(this.path + '/qunit-rfc-232-files') && checker.for('ember-cli-qunit', 'npm').gte('4.2.0')) { + if ( + fs.existsSync(this.path + '/qunit-rfc-232-files') && + checker.for('ember-cli-qunit', 'npm').gte('4.2.0') + ) { type = 'qunit-rfc-232'; } else { type = 'qunit'; } - } else if ('ember-mocha' in dependencies) { type = 'mocha-0.12'; - } else if ('ember-cli-mocha' in dependencies) { let checker = new VersionChecker(this.project); - if (fs.existsSync(this.path + '/mocha-0.12-files') && checker.for('ember-cli-mocha', 'npm').gte('0.12.0')) { + if ( + fs.existsSync(this.path + '/mocha-0.12-files') && + checker.for('ember-cli-mocha', 'npm').gte('0.12.0') + ) { type = 'mocha-0.12'; } else { type = 'mocha'; } - } else { - this.ui.writeLine('Couldn\'t determine test style - using QUnit'); + this.ui.writeLine("Couldn't determine test style - using QUnit"); type = 'qunit'; } diff --git a/blueprints/util-test/index.js b/blueprints/util-test/index.js index f2b031d9d60..6fb39fd0403 100644 --- a/blueprints/util-test/index.js +++ b/blueprints/util-test/index.js @@ -9,7 +9,9 @@ module.exports = useTestFrameworkDetector({ locals: function(options) { return { friendlyTestName: ['Unit', 'Utility', options.entity.name].join(' | '), - dasherizedModulePrefix: stringUtils.dasherize(options.project.config().modulePrefix) + dasherizedModulePrefix: stringUtils.dasherize( + options.project.config().modulePrefix + ) }; } }); diff --git a/broccoli/features.js b/broccoli/features.js index e1e69a7d230..0728fe91493 100644 --- a/broccoli/features.js +++ b/broccoli/features.js @@ -31,7 +31,7 @@ function getFeatures(isDebug) { function toConst(features) { let consted = {}; - Object.keys(features).forEach((feature) => { + Object.keys(features).forEach(feature => { consted[feature.toUpperCase().replace(/-/g, '_')] = features[feature]; }); diff --git a/broccoli/find-lib.js b/broccoli/find-lib.js index 14fd444fd76..044032c9927 100644 --- a/broccoli/find-lib.js +++ b/broccoli/find-lib.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const findPackage = require('./find-package'); diff --git a/broccoli/find-package.js b/broccoli/find-package.js index 8ce6e61ef1d..b25117a7b15 100644 --- a/broccoli/find-package.js +++ b/broccoli/find-package.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const fs = require('fs'); const path = require('path'); const resolve = require('resolve'); @@ -51,8 +51,7 @@ class PackageInfo { return { dir: parsed.dir, base: parsed.base, - path: resolved, + path: resolved }; } - } diff --git a/broccoli/funnel-lib.js b/broccoli/funnel-lib.js index 6a191bc77ec..b62094c28e4 100644 --- a/broccoli/funnel-lib.js +++ b/broccoli/funnel-lib.js @@ -1,10 +1,9 @@ -"use strict"; +'use strict'; const Funnel = require('broccoli-funnel'); const findLib = require('./find-lib'); module.exports = function funnelLib(name) { - let libPath, options; if (arguments.length > 2) { libPath = arguments[1]; @@ -13,6 +12,5 @@ module.exports = function funnelLib(name) { options = arguments[1]; } - return new Funnel(findLib(name, libPath), options); }; diff --git a/broccoli/glimmer-template-compiler.js b/broccoli/glimmer-template-compiler.js index 8123b8cfee6..897a6fa826a 100644 --- a/broccoli/glimmer-template-compiler.js +++ b/broccoli/glimmer-template-compiler.js @@ -5,7 +5,7 @@ const { stripIndent } = require('common-tags'); GlimmerTemplatePrecompiler.prototype = Object.create(Filter.prototype); -function GlimmerTemplatePrecompiler (inputTree, options) { +function GlimmerTemplatePrecompiler(inputTree, options) { if (!(this instanceof GlimmerTemplatePrecompiler)) { return new GlimmerTemplatePrecompiler(inputTree, options); } @@ -26,8 +26,13 @@ GlimmerTemplatePrecompiler.prototype.baseDir = function() { return __dirname; }; -GlimmerTemplatePrecompiler.prototype.processString = function(content, relativePath) { - var compiled = this.precompile(content, { meta: { moduleName: relativePath } }); +GlimmerTemplatePrecompiler.prototype.processString = function( + content, + relativePath +) { + var compiled = this.precompile(content, { + meta: { moduleName: relativePath } + }); return stripIndent` import template from '../template'; export default template(${compiled}); diff --git a/broccoli/minify.js b/broccoli/minify.js index 64615b31072..7b0a6f9636b 100644 --- a/broccoli/minify.js +++ b/broccoli/minify.js @@ -4,23 +4,23 @@ const Uglify = require('broccoli-uglify-sourcemap'); module.exports = function _minify(tree) { let options = { - enabled: true, + enabled: true, - uglify: { - compress: { - // this is adversely affects heuristics for IIFE eval - 'negate_iife': false, - // limit sequences because of memory issues during parsing - sequences: 0, - }, - mangle: { - safari10: true - }, - output: { - // no difference in size and much easier to debug - semicolons: false, - }, + uglify: { + compress: { + // this is adversely affects heuristics for IIFE eval + negate_iife: false, + // limit sequences because of memory issues during parsing + sequences: 0 + }, + mangle: { + safari10: true + }, + output: { + // no difference in size and much easier to debug + semicolons: false } + } }; return new Uglify(tree, options); diff --git a/broccoli/packages.js b/broccoli/packages.js index 3fd11b5a380..f1c706f4d75 100644 --- a/broccoli/packages.js +++ b/broccoli/packages.js @@ -82,20 +82,31 @@ module.exports.emberTypescriptPkgES = function emberTypescriptPkg(name) { `${name}:templates-output` ); - let nonTypeScriptContents = new Funnel(debuggedCompiledTemplatesAndTypeScript, { - srcDir: 'packages', - exclude: ["**/*.ts"], - }); + let nonTypeScriptContents = new Funnel( + debuggedCompiledTemplatesAndTypeScript, + { + srcDir: 'packages', + exclude: ['**/*.ts'] + } + ); let typescriptContents = new Funnel(debuggedCompiledTemplatesAndTypeScript, { - include: ["**/*.ts"], + include: ['**/*.ts'] }); - let typescriptCompiled = typescript(debugTree(typescriptContents, `${name}:ts:input`)); + let typescriptCompiled = typescript( + debugTree(typescriptContents, `${name}:ts:input`) + ); - let debuggedCompiledTypescript = debugTree(typescriptCompiled, `${name}:ts:output`); + let debuggedCompiledTypescript = debugTree( + typescriptCompiled, + `${name}:ts:output` + ); - let mergedFinalOutput = new MergeTrees([nonTypeScriptContents, debuggedCompiledTypescript], { overwrite: true }); + let mergedFinalOutput = new MergeTrees( + [nonTypeScriptContents, debuggedCompiledTypescript], + { overwrite: true } + ); return debugTree(mergedFinalOutput, `${name}:output`); }; diff --git a/broccoli/test-index-html.js b/broccoli/test-index-html.js index 96143a5c039..be7ce04ba04 100644 --- a/broccoli/test-index-html.js +++ b/broccoli/test-index-html.js @@ -12,13 +12,16 @@ module.exports = function testIndexHTML() { }); index = new StringReplace(index, { files: ['tests/index.html'], - patterns: [{ - match: /\{\{DEV_FEATURES\}\}/g, - replacement: JSON.stringify(FEATURES.DEBUG) - }, { - match: /\{\{PROD_FEATURES\}\}/g, - replacement: JSON.stringify(FEATURES.RELEASE) - }], + patterns: [ + { + match: /\{\{DEV_FEATURES\}\}/g, + replacement: JSON.stringify(FEATURES.DEBUG) + }, + { + match: /\{\{PROD_FEATURES\}\}/g, + replacement: JSON.stringify(FEATURES.RELEASE) + } + ] }); index._annotation = 'tests/index.html FEATURES'; return index; diff --git a/broccoli/to-es5.js b/broccoli/to-es5.js index b4c0f1e390d..b101ed3e8f0 100644 --- a/broccoli/to-es5.js +++ b/broccoli/to-es5.js @@ -9,41 +9,50 @@ const stripClassCallCheck = require('./transforms/strip-class-call-check'); const resolveModuleSource = require('amd-name-resolver').moduleResolve; module.exports = function toES5(tree, _options) { - let options = Object.assign({ - environment: 'developement' - }, _options); + let options = Object.assign( + { + environment: 'developement' + }, + _options + ); options.moduleIds = true; options.resolveModuleSource = resolveModuleSource; options.sourceMap = true; options.plugins = [ injectBabelHelpers, - ['debug-macros', { - debugTools: { - source: 'ember-debug', - assertPredicateIndex: 1 - }, - envFlags: { - source: 'ember-env-flags', - flags: { DEBUG: options.environment !== 'production' } - }, - features: { - name: 'ember', - source: 'ember/features', - flags: options.environment === 'production' ? toConst(RELEASE) : toConst(DEBUG) - }, - externalizeHelpers: { - module: true + [ + 'debug-macros', + { + debugTools: { + source: 'ember-debug', + assertPredicateIndex: 1 + }, + envFlags: { + source: 'ember-env-flags', + flags: { DEBUG: options.environment !== 'production' } + }, + features: { + name: 'ember', + source: 'ember/features', + flags: + options.environment === 'production' + ? toConst(RELEASE) + : toConst(DEBUG) + }, + externalizeHelpers: { + module: true + } } - }], - ['transform-es2015-template-literals', {loose: true}], + ], + ['transform-es2015-template-literals', { loose: true }], ['transform-es2015-literals'], ['transform-es2015-arrow-functions'], - ['transform-es2015-destructuring', {loose: true}], - ['transform-es2015-spread', {loose: true}], + ['transform-es2015-destructuring', { loose: true }], + ['transform-es2015-spread', { loose: true }], ['transform-es2015-parameters'], - ['transform-es2015-computed-properties', {loose: true}], + ['transform-es2015-computed-properties', { loose: true }], ['transform-es2015-shorthand-properties'], - ['transform-es2015-block-scoping', { 'throwIfClosureRequired': true }], + ['transform-es2015-block-scoping', { throwIfClosureRequired: true }], ['check-es2015-constants'], ['transform-es2015-classes', { loose: true }], ['transform-proto-to-assign'], diff --git a/broccoli/to-named-amd.js b/broccoli/to-named-amd.js index ba11134712d..956b084a93a 100644 --- a/broccoli/to-named-amd.js +++ b/broccoli/to-named-amd.js @@ -10,11 +10,11 @@ module.exports = function processModulesOnly(tree, annotation) { // in both browser and node-land injectNodeGlobals, ['transform-es2015-modules-amd', { loose: true, noInterop: true }], - enifed, + enifed ], moduleIds: true, resolveModuleSource, - annotation, + annotation }; return new Babel(tree, options); diff --git a/broccoli/transforms/inject-babel-helpers.js b/broccoli/transforms/inject-babel-helpers.js index fe7245edcf8..ca286130bfb 100644 --- a/broccoli/transforms/inject-babel-helpers.js +++ b/broccoli/transforms/inject-babel-helpers.js @@ -3,7 +3,7 @@ function injectBabelHelpers() { return { pre(file) { - file.set('helperGenerator', function (name) { + file.set('helperGenerator', function(name) { if (name === 'extends') { return file.addImport('ember-utils', 'assign', name); } diff --git a/broccoli/transforms/inject-node-globals.js b/broccoli/transforms/inject-node-globals.js index e4ad508b3ff..a0c1ffc1481 100644 --- a/broccoli/transforms/inject-node-globals.js +++ b/broccoli/transforms/inject-node-globals.js @@ -11,28 +11,32 @@ function injectNodeGlobals({ types: t }) { moduleId = path.scope.globals.module; if (requireId || moduleId) { - let specifiers = []; - let source = t.stringLiteral(this.file.resolveModuleSource('node-module')); + let source = t.stringLiteral( + this.file.resolveModuleSource('node-module') + ); if (requireId) { delete path.scope.globals.require; - specifiers.push(t.importSpecifier(requireId, t.identifier('require'))); + specifiers.push( + t.importSpecifier(requireId, t.identifier('require')) + ); } if (moduleId) { delete path.scope.globals.module; - specifiers.push(t.importSpecifier(moduleId, t.identifier('module'))); + specifiers.push( + t.importSpecifier(moduleId, t.identifier('module')) + ); } importDecl = t.importDeclaration(specifiers, source); path.unshiftContainer('body', importDecl); } - }, exit(path) { if (requireId) { - path.scope.rename("require"); + path.scope.rename('require'); } } }, diff --git a/broccoli/transforms/strip-class-call-check.js b/broccoli/transforms/strip-class-call-check.js index 8c8f629c654..5949576a837 100644 --- a/broccoli/transforms/strip-class-call-check.js +++ b/broccoli/transforms/strip-class-call-check.js @@ -9,7 +9,9 @@ function stripClassCallCheck({ traverse }) { enter(path, state) { let [amd] = path.get('body'); - if (!amd) { return; } + if (!amd) { + return; + } let [, deps, callBack] = amd.get('expression.arguments'); let params = callBack.get('params'); @@ -25,7 +27,9 @@ function stripClassCallCheck({ traverse }) { } }, exit(path) { - if (!this.binding) { return; } + if (!this.binding) { + return; + } traverse.clearCache(); path.scope.crawl(); @@ -44,18 +48,26 @@ function stripClassCallCheck({ traverse }) { CallExpression(path) { let callee = path.get('callee'); - if (!this.binding) { return; } + if (!this.binding) { + return; + } if (callee.isSequenceExpression()) { let [, member] = callee.get('expressions'); - if (member.node.object.name === this.binding.node.name && member.node.property.name.indexOf('classCallCheck') > -1) { + if ( + member.node.object.name === this.binding.node.name && + member.node.property.name.indexOf('classCallCheck') > -1 + ) { path.remove(); } } if (callee.isMemberExpression()) { - if (callee.node.object.name === this.binding.node.name && callee.node.property.name.indexOf('classCallCheck') > -1) { + if ( + callee.node.object.name === this.binding.node.name && + callee.node.property.name.indexOf('classCallCheck') > -1 + ) { path.remove(); } } diff --git a/config/s3ProjectConfig.js b/config/s3ProjectConfig.js index 15014598206..74f4e6b37ea 100644 --- a/config/s3ProjectConfig.js +++ b/config/s3ProjectConfig.js @@ -4,10 +4,10 @@ const semver = require('semver'); function fileMap(revision, tag, date) { let filesToPublish = { - "../docs/data.json": fileObject( - "ember-docs", - ".json", - "application/json", + '../docs/data.json': fileObject( + 'ember-docs', + '.json', + 'application/json', revision, tag, date @@ -20,71 +20,58 @@ function fileMap(revision, tag, date) { filesToPublish[`../ember-source-${sanitizedVersion}.tgz`] = { contentType: 'application/x-gzip', destinations: { - 'alpha': [ - `alpha/daily/${date}.tgz`, - `alpha/shas/${revision}.tgz`, - ], - 'canary': [ - `canary/daily/${date}.tgz`, - `canary/shas/${revision}.tgz`, - ], - 'beta': [ - `beta/daily/${date}.tgz`, - `beta/shas/${revision}.tgz`, - ], - 'release': [ - `release/daily/${date}.tgz`, - `release/shas/${revision}.tgz`, - ], + alpha: [`alpha/daily/${date}.tgz`, `alpha/shas/${revision}.tgz`], + canary: [`canary/daily/${date}.tgz`, `canary/shas/${revision}.tgz`], + beta: [`beta/daily/${date}.tgz`, `beta/shas/${revision}.tgz`], + release: [`release/daily/${date}.tgz`, `release/shas/${revision}.tgz`] } }; filesToPublish['../build-metadata.json'] = { contentType: 'application/json', destinations: { - 'alpha': [ - 'alpha.json', - ], - 'canary': [ - 'canary.json', - ], - 'beta': [ - 'beta.json', - ], - 'release': [ - 'release.json', - ], + alpha: ['alpha.json'], + canary: ['canary.json'], + beta: ['beta.json'], + release: ['release.json'] } }; return filesToPublish; } -function fileObject(baseName, extension, contentType, currentRevision, tag, date) { - var fullName = "/" + baseName + extension; - var obj = { +function fileObject( + baseName, + extension, + contentType, + currentRevision, + tag, + date +) { + var fullName = '/' + baseName + extension; + var obj = { contentType: contentType, destinations: { alpha: [ - "alpha" + fullName, - "alpha/daily/" + date + fullName, - "alpha/shas/" + currentRevision + fullName + 'alpha' + fullName, + 'alpha/daily/' + date + fullName, + 'alpha/shas/' + currentRevision + fullName ], canary: [ - "latest" + fullName, - "canary" + fullName, - "canary/daily/" + date + fullName, - "canary/shas/" + currentRevision + fullName + 'latest' + fullName, + 'canary' + fullName, + 'canary/daily/' + date + fullName, + 'canary/shas/' + currentRevision + fullName ], release: [ - "stable" + fullName, - "release" + fullName, - "release/daily/" + date + fullName, - "release/shas/" + currentRevision + fullName + 'stable' + fullName, + 'release' + fullName, + 'release/daily/' + date + fullName, + 'release/shas/' + currentRevision + fullName ], beta: [ - "beta" + fullName, - "beta/daily/" + date + fullName, - "beta/shas/" + currentRevision + fullName + 'beta' + fullName, + 'beta/daily/' + date + fullName, + 'beta/shas/' + currentRevision + fullName ], wildcard: [] } @@ -92,7 +79,7 @@ function fileObject(baseName, extension, contentType, currentRevision, tag, date if (tag) { for (var key in obj.destinations) { - obj.destinations[key].push("tags/" + tag + fullName); + obj.destinations[key].push('tags/' + tag + fullName); } } diff --git a/d8-app.js b/d8-app.js index 797ad91c2b9..1bb224f41ba 100644 --- a/d8-app.js +++ b/d8-app.js @@ -6,11 +6,20 @@ var Router = Ember.Router.extend({ rootURL: '/' }); Router.map(function() { - this.route('my-route', { path: '/my-route' }, function () { - }); + this.route('my-route', { path: '/my-route' }, function() {}); +}); +Ember.TEMPLATES['index'] = Ember.HTMLBars.template({ + id: null, + block: + '{"statements":[["text","index"]],"locals":[],"named":[],"yields":[],"blocks":[],"hasPartials":false}', + meta: {} +}); +Ember.TEMPLATES['my-route/index'] = Ember.HTMLBars.template({ + id: null, + block: + '{"statements":[["text","my-route"]],"locals":[],"named":[],"yields":[],"blocks":[],"hasPartials":false}', + meta: {} }); -Ember.TEMPLATES['index'] = Ember.HTMLBars.template({"id":null,"block":"{\"statements\":[[\"text\",\"index\"]],\"locals\":[],\"named\":[],\"yields\":[],\"blocks\":[],\"hasPartials\":false}","meta":{}}); -Ember.TEMPLATES['my-route/index'] = Ember.HTMLBars.template({"id":null,"block":"{\"statements\":[[\"text\",\"my-route\"]],\"locals\":[],\"named\":[],\"yields\":[],\"blocks\":[],\"hasPartials\":false}","meta":{}}); var App = Ember.Application.extend({ Router: Router, autoboot: false @@ -24,16 +33,21 @@ var options = { rootElement: doc.body, shouldRender: true }; -app.visit('/', options).then(function (instance) { - print(serializer.serialize(doc.body)); - var router = instance.lookup('router:main'); - return router.transitionTo('/my-route'); -}).then(function () { - return new Ember.RSVP.Promise(function (resolve) { - Ember.run.schedule('afterRender', resolve); +app + .visit('/', options) + .then(function(instance) { + print(serializer.serialize(doc.body)); + var router = instance.lookup('router:main'); + return router.transitionTo('/my-route'); + }) + .then(function() { + return new Ember.RSVP.Promise(function(resolve) { + Ember.run.schedule('afterRender', resolve); + }); + }) + .then(function() { + print(serializer.serialize(doc.body)); + }) + .catch(function(err) { + print(err.stack); }); -}).then(function () { - print(serializer.serialize(doc.body)); -}).catch(function (err) { - print(err.stack); -}); diff --git a/d8-runner.js b/d8-runner.js index b7b495b5bf7..ee050800584 100644 --- a/d8-runner.js +++ b/d8-runner.js @@ -54,7 +54,9 @@ global.console = { global.setTimeout = function(callback) { // good enough - Promise.resolve().then(callback).catch(e => print('error' + e)); + Promise.resolve() + .then(callback) + .catch(e => print('error' + e)); }; loadFile('./node_modules/simple-dom/dist/simple-dom.js'); @@ -68,7 +70,6 @@ loadFile('./dist/ember.prod.js'); // prod build === no asserts and dev related c // loadFile('/dist/ember.min.js'); // prod build + minified // loadFile('/dist/ember.debug.js'); // debug build === asserts and stuff, has perf issues - // do what you want // try running `d8 d8-runner.js d8-app.js` diff --git a/ember-cli-build.js b/ember-cli-build.js index b9311ee70dd..f13523b216d 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -69,19 +69,23 @@ module.exports = function() { emberPkgES('ember-utils'), emberPkgES('ember-views'), emberPkgES('ember'), - ...dependenciesES({ includeGlimmerCompiler: true }), + ...dependenciesES({ includeGlimmerCompiler: true }) ]); let es = new Funnel(combinedES, { - destDir: 'es', + destDir: 'es' }); - let esMin = minify(new Funnel(combinedES, { - destDir: 'es-min', - })); + let esMin = minify( + new Funnel(combinedES, { + destDir: 'es-min' + }) + ); let emberTestsES = buildEmberTestsES(); - let pkgAndTestES = new MergeTrees([combinedES, ...emberTestsES], { overwrite: true }); + let pkgAndTestES = new MergeTrees([combinedES, ...emberTestsES], { + overwrite: true + }); let pkgAndTestESInAMD = toNamedAMD(pkgAndTestES); let emberEnvFlagsDebug = toNamedAMD(buildEmberEnvFlagsES({ DEBUG: true })); @@ -102,8 +106,12 @@ module.exports = function() { let emberDebug = emberPkgES('ember-debug'); let emberDebugES5 = toES5(emberDebug, { annotation: 'ember-debug' }); let emberTemplateCompiler = emberPkgES('ember-template-compiler'); - let emberTemplateCompilerES5 = toES5(emberTemplateCompiler, { annotation: 'ember-template-compiler' }); - let babelDebugHelpersES5 = toES5(babelHelpers('debug'), { annotation: 'babel helpers debug' }); + let emberTemplateCompilerES5 = toES5(emberTemplateCompiler, { + annotation: 'ember-template-compiler' + }); + let babelDebugHelpersES5 = toES5(babelHelpers('debug'), { + annotation: 'babel helpers debug' + }); let inlineParser = toES5(handlebarsES(), { annotation: 'handlebars' }); let tokenizer = toES5(simpleHTMLTokenizerES(), { annotation: 'tokenizer' }); let rsvp = toES5(rsvpES(), { annotation: 'rsvp' }); @@ -112,10 +120,14 @@ module.exports = function() { include: ['**/*.js'] }); let emberMetalES5 = rollupEmberMetal(emberMetal); - let emberConsole = emberPkgES('ember-console', SHOULD_ROLLUP, ['ember-environment']); + let emberConsole = emberPkgES('ember-console', SHOULD_ROLLUP, [ + 'ember-environment' + ]); let emberConsoleES5 = toES5(emberConsole, { annotation: 'ember-console' }); let emberEnvironment = emberPkgES('ember-environment', SHOULD_ROLLUP); - let emberEnvironmentES5 = toES5(emberEnvironment, { annotation: 'ember-environment' }); + let emberEnvironmentES5 = toES5(emberEnvironment, { + annotation: 'ember-environment' + }); let emberUtils = emberPkgES('ember-utils', SHOULD_ROLLUP); let emberUtilsES5 = toES5(emberUtils, { annotation: 'ember-utils' }); let container = emberPkgES('container', SHOULD_ROLLUP, [ @@ -141,7 +153,7 @@ module.exports = function() { loader, nodeModule, license, - babelDebugHelpersES5, + babelDebugHelpersES5 ]); let emberDebugBase = [ @@ -172,7 +184,7 @@ module.exports = function() { emberTestingES5, babelDebugHelpersES5, inlineParser, - debugFeatures, + debugFeatures ]); emberDebugBundle = concatBundle(emberDebugBundle, { @@ -319,7 +331,9 @@ module.exports = function() { hasBootstrap: false }); - let emberProdMinRename = rename(emberProdBundle, { 'ember.prod.js': 'ember.min.js' }); + let emberProdMinRename = rename(emberProdBundle, { + 'ember.prod.js': 'ember.min.js' + }); let emberMinBundle = minify(emberProdMinRename); trees.push( @@ -417,7 +431,7 @@ function emberES() { emberPkgES('ember-application'), emberPkgES('ember-runtime'), emberPkgES('ember-extension-support'), - emberPkgES('ember-routing'), + emberPkgES('ember-routing') ]; } diff --git a/lib/index.js b/lib/index.js index 0088c133b0f..ba26d7b13fa 100644 --- a/lib/index.js +++ b/lib/index.js @@ -10,16 +10,22 @@ var absolutePaths = {}; function add(paths, name, path) { Object.defineProperty(paths, name, { configurable: false, - get: function() { return path; } + get: function() { + return path; + } }); } -add(paths, 'prod', 'vendor/ember/ember.prod.js'); +add(paths, 'prod', 'vendor/ember/ember.prod.js'); add(paths, 'debug', 'vendor/ember/ember.debug.js'); add(paths, 'testing', 'vendor/ember/ember-testing.js'); add(paths, 'jquery', 'vendor/ember/jquery/jquery.js'); -add(absolutePaths, 'templateCompiler', path.join(__dirname, '..', 'dist', 'ember-template-compiler.js')); +add( + absolutePaths, + 'templateCompiler', + path.join(__dirname, '..', 'dist', 'ember-template-compiler.js') +); module.exports = { init: function() { @@ -27,7 +33,9 @@ module.exports = { if ('ember' in this.project.bowerDependencies()) { // TODO: move this to a throw soon. - this.ui.writeWarnLine('Ember.js is now provided by node_module `ember-source`, please remove it from bower'); + this.ui.writeWarnLine( + 'Ember.js is now provided by node_module `ember-source`, please remove it from bower' + ); } // resets `this.root` to the correct location by default ember-cli @@ -46,14 +54,16 @@ module.exports = { var jqueryPath; try { - jqueryPath = path.dirname(resolve.sync('jquery/package.json', { basedir: this.project.root })); + jqueryPath = path.dirname( + resolve.sync('jquery/package.json', { basedir: this.project.root }) + ); } catch (error) { jqueryPath = path.dirname(require.resolve('jquery/package.json')); } var jquery = new Funnel(jqueryPath + '/dist', { destDir: 'ember/jquery', - files: [ 'jquery.js' ] + files: ['jquery.js'] }); var emberFiles = [ diff --git a/lib/packages.js b/lib/packages.js index c2edcb5d0bf..f98cd4c819e 100644 --- a/lib/packages.js +++ b/lib/packages.js @@ -1,25 +1,69 @@ module.exports = function() { var packages = { - 'container': { trees: null, requirements: ['ember-utils'], isTypeScript: true, vendorRequirements: ['@glimmer/di'], requiresJQuery: false }, - 'ember-environment': { trees: null, requirements: [], skipTests: true, requiresJQuery: false }, - 'ember-utils': { trees: null, requirements: [], requiresJQuery: false }, - 'ember-console': { trees: null, requirements: [], skipTests: true, requiresJQuery: false }, - 'ember-metal': { trees: null, requirements: ['ember-environment', 'ember-utils'], vendorRequirements: ['backburner'], requiresJQuery: false }, - 'ember-debug': { trees: null, requirements: [], requiresJQuery: false }, - 'ember-runtime': { trees: null, vendorRequirements: ['rsvp'], requirements: ['container', 'ember-environment', 'ember-console', 'ember-metal'], requiresJQuery: false }, - 'ember-views': { trees: null, requirements: ['ember-runtime'], skipTests: true }, - 'ember-extension-support': { trees: null, requirements: ['ember-application'], requiresJQuery: false }, - 'ember-testing': { - trees: null, + container: { + trees: null, + requirements: ['ember-utils'], + isTypeScript: true, + vendorRequirements: ['@glimmer/di'], + requiresJQuery: false + }, + 'ember-environment': { + trees: null, + requirements: [], + skipTests: true, + requiresJQuery: false + }, + 'ember-utils': { trees: null, requirements: [], requiresJQuery: false }, + 'ember-console': { + trees: null, + requirements: [], + skipTests: true, + requiresJQuery: false + }, + 'ember-metal': { + trees: null, + requirements: ['ember-environment', 'ember-utils'], + vendorRequirements: ['backburner'], + requiresJQuery: false + }, + 'ember-debug': { trees: null, requirements: [], requiresJQuery: false }, + 'ember-runtime': { + trees: null, + vendorRequirements: ['rsvp'], + requirements: [ + 'container', + 'ember-environment', + 'ember-console', + 'ember-metal' + ], + requiresJQuery: false + }, + 'ember-views': { + trees: null, + requirements: ['ember-runtime'], + skipTests: true + }, + 'ember-extension-support': { + trees: null, + requirements: ['ember-application'], + requiresJQuery: false + }, + 'ember-testing': { + trees: null, requiresJQuery: false, - requirements: ['ember-application', 'ember-routing'], - testing: true + requirements: ['ember-application', 'ember-routing'], + testing: true }, 'ember-template-compiler': { trees: null, templateCompilerOnly: true, requiresJQuery: false, - requirements: ['container', 'ember-metal', 'ember-environment', 'ember-console'], + requirements: [ + 'container', + 'ember-metal', + 'ember-environment', + 'ember-console' + ], templateCompilerVendor: [ 'simple-html-tokenizer', 'backburner', @@ -30,18 +74,27 @@ module.exports = function() { '@glimmer/reference', '@glimmer/runtime', 'handlebars' - ], + ] + }, + 'ember-routing': { + trees: null, + vendorRequirements: ['router', 'route-recognizer'], + requirements: ['ember-runtime', 'ember-views'], + requiresJQuery: false + }, + 'ember-application': { + trees: null, + vendorRequirements: ['dag-map'], + requirements: ['ember-routing'], + requiresJQuery: false }, - 'ember-routing': { trees: null, vendorRequirements: ['router', 'route-recognizer'], - requirements: ['ember-runtime', 'ember-views'], requiresJQuery: false }, - 'ember-application': { trees: null, vendorRequirements: ['dag-map'], requirements: ['ember-routing'], requiresJQuery: false }, - 'ember': { trees: null, requirements: ['ember-application'] }, - 'internal-test-helpers': { trees: null, requiresJQuery: false }, + ember: { trees: null, requirements: ['ember-application'] }, + 'internal-test-helpers': { trees: null, requiresJQuery: false }, - 'ember-glimmer': { + 'ember-glimmer': { trees: null, requiresJQuery: false, - requirements: ['container', 'ember-metal', 'ember-routing' ], + requirements: ['container', 'ember-metal', 'ember-routing'], hasTemplates: true, vendorRequirements: [ '@glimmer/runtime', @@ -50,7 +103,7 @@ module.exports = function() { '@glimmer/wire-format', '@glimmer/node' ], - testingVendorRequirements: [], + testingVendorRequirements: [] } }; diff --git a/node-tests/blueprints/acceptance-test-test.js b/node-tests/blueprints/acceptance-test-test.js index 157fcdc38b8..aad3c39b62f 100644 --- a/node-tests/blueprints/acceptance-test-test.js +++ b/node-tests/blueprints/acceptance-test-test.js @@ -22,8 +22,9 @@ describe('Blueprint: acceptance-test', function() { it('acceptance-test foo', function() { return emberGenerateDestroy(['acceptance-test', 'foo'], _file => { - expect(_file('tests/acceptance/foo-test.js')) - .to.equal(fixture('acceptance-test/default.js')); + expect(_file('tests/acceptance/foo-test.js')).to.equal( + fixture('acceptance-test/default.js') + ); }); }); @@ -34,8 +35,9 @@ describe('Blueprint: acceptance-test', function() { it('acceptance-test foo', function() { return emberGenerateDestroy(['acceptance-test', 'foo'], _file => { - expect(_file('tests/acceptance/foo-test.js')) - .to.equal(fixture('acceptance-test/qunit-rfc268.js')); + expect(_file('tests/acceptance/foo-test.js')).to.equal( + fixture('acceptance-test/qunit-rfc268.js') + ); }); }); }); @@ -50,14 +52,14 @@ describe('Blueprint: acceptance-test', function() { it('acceptance-test foo', function() { return emberGenerateDestroy(['acceptance-test', 'foo'], _file => { - expect(_file('tests/acceptance/foo-test.js')) - .to.equal(fixture('acceptance-test/mocha.js')); + expect(_file('tests/acceptance/foo-test.js')).to.equal( + fixture('acceptance-test/mocha.js') + ); }); }); }); }); - describe('in addon', function() { beforeEach(function() { return emberNew({ target: 'addon' }); @@ -65,21 +67,21 @@ describe('Blueprint: acceptance-test', function() { it('acceptance-test foo', function() { return emberGenerateDestroy(['acceptance-test', 'foo'], _file => { - expect(_file('tests/acceptance/foo-test.js')) - .to.equal(fixture('acceptance-test/addon-default.js')); + expect(_file('tests/acceptance/foo-test.js')).to.equal( + fixture('acceptance-test/addon-default.js') + ); - expect(_file('app/acceptance-tests/foo.js')) - .to.not.exist; + expect(_file('app/acceptance-tests/foo.js')).to.not.exist; }); }); it('acceptance-test foo/bar', function() { return emberGenerateDestroy(['acceptance-test', 'foo/bar'], _file => { - expect(_file('tests/acceptance/foo/bar-test.js')) - .to.equal(fixture('acceptance-test/addon-nested.js')); + expect(_file('tests/acceptance/foo/bar-test.js')).to.equal( + fixture('acceptance-test/addon-nested.js') + ); - expect(_file('app/acceptance-tests/foo/bar.js')) - .to.not.exist; + expect(_file('app/acceptance-tests/foo/bar.js')).to.not.exist; }); }); @@ -90,8 +92,9 @@ describe('Blueprint: acceptance-test', function() { it('acceptance-test foo', function() { return emberGenerateDestroy(['acceptance-test', 'foo'], _file => { - expect(_file('tests/acceptance/foo-test.js')) - .to.equal(fixture('acceptance-test/qunit-rfc268.js')); + expect(_file('tests/acceptance/foo-test.js')).to.equal( + fixture('acceptance-test/qunit-rfc268.js') + ); }); }); }); diff --git a/node-tests/blueprints/component-addon-test.js b/node-tests/blueprints/component-addon-test.js index c96c6cc3f69..8d980e6a88a 100644 --- a/node-tests/blueprints/component-addon-test.js +++ b/node-tests/blueprints/component-addon-test.js @@ -18,8 +18,9 @@ describe('Blueprint: component-addon', function() { it('component-addon foo-bar', function() { return emberGenerateDestroy(['component-addon', 'foo-bar'], _file => { - expect(_file('app/components/foo-bar.js')) - .to.contain("export { default } from 'my-addon/components/foo-bar';"); + expect(_file('app/components/foo-bar.js')).to.contain( + "export { default } from 'my-addon/components/foo-bar';" + ); }); }); }); diff --git a/node-tests/blueprints/component-test-test.js b/node-tests/blueprints/component-test-test.js index 14777bb5e3c..c0509fd9a9e 100644 --- a/node-tests/blueprints/component-test-test.js +++ b/node-tests/blueprints/component-test-test.js @@ -16,11 +16,13 @@ const generateFakePackageManifest = require('../helpers/generate-fake-package-ma const fixture = require('../helpers/fixture'); function expectError(promise, expectedErrorText) { - return promise.then(() => { - throw 'the command should raise an exception'; - }).catch(error => { - expect(error).to.equal(expectedErrorText); - }); + return promise + .then(() => { + throw 'the command should raise an exception'; + }) + .catch(error => { + expect(error).to.equal(expectedErrorText); + }); } describe('Blueprint: component-test', function() { @@ -33,30 +35,39 @@ describe('Blueprint: component-test', function() { it('component-test x-foo', function() { return emberGenerateDestroy(['component-test', 'x-foo'], _file => { - expect(_file('tests/integration/components/x-foo-test.js')) - .to.equal(fixture('component-test/default.js')); + expect(_file('tests/integration/components/x-foo-test.js')).to.equal( + fixture('component-test/default.js') + ); }); }); it('component-test x-foo --unit', function() { - return emberGenerateDestroy(['component-test', 'x-foo', '--unit'], _file => { - expect(_file('tests/unit/components/x-foo-test.js')) - .to.equal(fixture('component-test/unit.js')); - }); + return emberGenerateDestroy( + ['component-test', 'x-foo', '--unit'], + _file => { + expect(_file('tests/unit/components/x-foo-test.js')).to.equal( + fixture('component-test/unit.js') + ); + } + ); }); describe('with usePods=true', function() { beforeEach(function() { - fs.writeFileSync('.ember-cli', `{ + fs.writeFileSync( + '.ember-cli', + `{ "disableAnalytics": false, "usePods": true - }`); + }` + ); }); it('component-test x-foo', function() { return emberGenerateDestroy(['component-test', 'x-foo'], _file => { - expect(_file('tests/integration/components/x-foo/component-test.js')) - .to.equal(fixture('component-test/default.js')); + expect( + _file('tests/integration/components/x-foo/component-test.js') + ).to.equal(fixture('component-test/default.js')); }); }); }); @@ -68,16 +79,21 @@ describe('Blueprint: component-test', function() { it('component-test x-foo', function() { return emberGenerateDestroy(['component-test', 'x-foo'], _file => { - expect(_file('tests/integration/components/x-foo-test.js')) - .to.equal(fixture('component-test/rfc232.js')); + expect(_file('tests/integration/components/x-foo-test.js')).to.equal( + fixture('component-test/rfc232.js') + ); }); }); it('component-test x-foo --unit', function() { - return emberGenerateDestroy(['component-test', 'x-foo', '--unit'], _file => { - expect(_file('tests/unit/components/x-foo-test.js')) - .to.equal(fixture('component-test/rfc232-unit.js')); - }); + return emberGenerateDestroy( + ['component-test', 'x-foo', '--unit'], + _file => { + expect(_file('tests/unit/components/x-foo-test.js')).to.equal( + fixture('component-test/rfc232-unit.js') + ); + } + ); }); }); @@ -92,16 +108,21 @@ describe('Blueprint: component-test', function() { it('component-test x-foo', function() { return emberGenerateDestroy(['component-test', 'x-foo'], _file => { - expect(_file('tests/integration/components/x-foo-test.js')) - .to.equal(fixture('component-test/mocha.js')); + expect(_file('tests/integration/components/x-foo-test.js')).to.equal( + fixture('component-test/mocha.js') + ); }); }); it('component-test x-foo --unit', function() { - return emberGenerateDestroy(['component-test', 'x-foo', '--unit'], _file => { - expect(_file('tests/unit/components/x-foo-test.js')) - .to.equal(fixture('component-test/mocha-unit.js')); - }); + return emberGenerateDestroy( + ['component-test', 'x-foo', '--unit'], + _file => { + expect(_file('tests/unit/components/x-foo-test.js')).to.equal( + fixture('component-test/mocha-unit.js') + ); + } + ); }); }); @@ -116,16 +137,21 @@ describe('Blueprint: component-test', function() { it('component-test x-foo', function() { return emberGenerateDestroy(['component-test', 'x-foo'], _file => { - expect(_file('tests/integration/components/x-foo-test.js')) - .to.equal(fixture('component-test/mocha-0.12.js')); + expect(_file('tests/integration/components/x-foo-test.js')).to.equal( + fixture('component-test/mocha-0.12.js') + ); }); }); it('component-test x-foo --unit', function() { - return emberGenerateDestroy(['component-test', 'x-foo', '--unit'], _file => { - expect(_file('tests/unit/components/x-foo-test.js')) - .to.equal(fixture('component-test/mocha-0.12-unit.js')); - }); + return emberGenerateDestroy( + ['component-test', 'x-foo', '--unit'], + _file => { + expect(_file('tests/unit/components/x-foo-test.js')).to.equal( + fixture('component-test/mocha-0.12-unit.js') + ); + } + ); }); }); }); @@ -137,31 +163,39 @@ describe('Blueprint: component-test', function() { it('component-test x-foo', function() { return emberGenerateDestroy(['component-test', 'x-foo'], _file => { - expect(_file('src/ui/components/x-foo/component-test.js')) - .to.equal(fixture('component-test/default.js')); + expect(_file('src/ui/components/x-foo/component-test.js')).to.equal( + fixture('component-test/default.js') + ); }); }); it('component-test x-foo --unit', function() { - return emberGenerate(['component-test', 'x-foo', '--unit']).then(() => { - throw 'the command should raise an exception'; - }).catch(error => { - expect(error).to.equal('The --unit flag isn\'t supported within a module unification app'); - }); + return emberGenerate(['component-test', 'x-foo', '--unit']) + .then(() => { + throw 'the command should raise an exception'; + }) + .catch(error => { + expect(error).to.equal( + "The --unit flag isn't supported within a module unification app" + ); + }); }); describe('with usePods=true', function() { beforeEach(function() { - fs.writeFileSync('.ember-cli', `{ + fs.writeFileSync( + '.ember-cli', + `{ "disableAnalytics": false, "usePods": true - }`); + }` + ); }); it('component-test x-foo', function() { return expectError( emberGenerate(['component-test', 'x-foo']), - 'Pods aren\'t supported within a module unification app' + "Pods aren't supported within a module unification app" ); }); }); @@ -173,15 +207,16 @@ describe('Blueprint: component-test', function() { it('component-test x-foo', function() { return emberGenerateDestroy(['component-test', 'x-foo'], _file => { - expect(_file('src/ui/components/x-foo/component-test.js')) - .to.equal(fixture('component-test/rfc232.js')); + expect(_file('src/ui/components/x-foo/component-test.js')).to.equal( + fixture('component-test/rfc232.js') + ); }); }); it('component-test x-foo --unit', function() { return expectError( emberGenerate(['component-test', 'x-foo', '--unit']), - 'The --unit flag isn\'t supported within a module unification app' + "The --unit flag isn't supported within a module unification app" ); }); }); @@ -197,15 +232,16 @@ describe('Blueprint: component-test', function() { it('component-test x-foo', function() { return emberGenerateDestroy(['component-test', 'x-foo'], _file => { - expect(_file('src/ui/components/x-foo/component-test.js')) - .to.equal(fixture('component-test/mocha.js')); + expect(_file('src/ui/components/x-foo/component-test.js')).to.equal( + fixture('component-test/mocha.js') + ); }); }); it('component-test x-foo --unit', function() { return expectError( emberGenerate(['component-test', 'x-foo', '--unit']), - 'The --unit flag isn\'t supported within a module unification app' + "The --unit flag isn't supported within a module unification app" ); }); }); @@ -221,15 +257,16 @@ describe('Blueprint: component-test', function() { it('component-test x-foo', function() { return emberGenerateDestroy(['component-test', 'x-foo'], _file => { - expect(_file('src/ui/components/x-foo/component-test.js')) - .to.equal(fixture('component-test/mocha-0.12.js')); + expect(_file('src/ui/components/x-foo/component-test.js')).to.equal( + fixture('component-test/mocha-0.12.js') + ); }); }); it('component-test x-foo --unit', function() { return expectError( emberGenerate(['component-test', 'x-foo', '--unit']), - 'The --unit flag isn\'t supported within a module unification app' + "The --unit flag isn't supported within a module unification app" ); }); }); @@ -242,32 +279,38 @@ describe('Blueprint: component-test', function() { it('component-test x-foo', function() { return emberGenerateDestroy(['component-test', 'x-foo'], _file => { - expect(_file('tests/integration/components/x-foo-test.js')) - .to.equal(fixture('component-test/default.js')); + expect(_file('tests/integration/components/x-foo-test.js')).to.equal( + fixture('component-test/default.js') + ); - expect(_file('app/component-test/x-foo.js')) - .to.not.exist; + expect(_file('app/component-test/x-foo.js')).to.not.exist; }); }); it('component-test x-foo --unit', function() { - return emberGenerateDestroy(['component-test', 'x-foo', '--unit'], _file => { - expect(_file('tests/unit/components/x-foo-test.js')) - .to.equal(fixture('component-test/unit.js')); - - expect(_file('app/component-test/x-foo.js')) - .to.not.exist; - }); + return emberGenerateDestroy( + ['component-test', 'x-foo', '--unit'], + _file => { + expect(_file('tests/unit/components/x-foo-test.js')).to.equal( + fixture('component-test/unit.js') + ); + + expect(_file('app/component-test/x-foo.js')).to.not.exist; + } + ); }); it('component-test x-foo --dummy', function() { - return emberGenerateDestroy(['component-test', 'x-foo', '--dummy'], _file => { - expect(_file('tests/integration/components/x-foo-test.js')) - .to.equal(fixture('component-test/default.js')); - - expect(_file('app/component-test/x-foo.js')) - .to.not.exist; - }); + return emberGenerateDestroy( + ['component-test', 'x-foo', '--dummy'], + _file => { + expect(_file('tests/integration/components/x-foo-test.js')).to.equal( + fixture('component-test/default.js') + ); + + expect(_file('app/component-test/x-foo.js')).to.not.exist; + } + ); }); }); @@ -277,17 +320,25 @@ describe('Blueprint: component-test', function() { }); it('component-test x-foo --in-repo-addon=my-addon', function() { - return emberGenerateDestroy(['component-test', 'x-foo', '--in-repo-addon=my-addon'], _file => { - expect(_file('tests/integration/components/x-foo-test.js')) - .to.equal(fixture('component-test/default.js')); - }); + return emberGenerateDestroy( + ['component-test', 'x-foo', '--in-repo-addon=my-addon'], + _file => { + expect(_file('tests/integration/components/x-foo-test.js')).to.equal( + fixture('component-test/default.js') + ); + } + ); }); it('component-test x-foo --in-repo-addon=my-addon --unit', function() { - return emberGenerateDestroy(['component-test', 'x-foo', '--in-repo-addon=my-addon', '--unit'], _file => { - expect(_file('tests/unit/components/x-foo-test.js')) - .to.equal(fixture('component-test/unit.js')); - }); + return emberGenerateDestroy( + ['component-test', 'x-foo', '--in-repo-addon=my-addon', '--unit'], + _file => { + expect(_file('tests/unit/components/x-foo-test.js')).to.equal( + fixture('component-test/unit.js') + ); + } + ); }); }); }); diff --git a/node-tests/blueprints/component-test.js b/node-tests/blueprints/component-test.js index f81c1e790c5..d8252b6f170 100644 --- a/node-tests/blueprints/component-test.js +++ b/node-tests/blueprints/component-test.js @@ -20,20 +20,22 @@ describe('Blueprint: component', function() { it('component x-foo', function() { return emberGenerateDestroy(['component', 'x-foo'], _file => { - expect(_file('app/components/x-foo.js')).to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); + expect(_file('app/components/x-foo.js')) + .to.contain("import Component from '@ember/component';") + .to.contain('export default Component.extend({') + .to.contain('});'); - expect(_file('app/templates/components/x-foo.hbs')) - .to.equal("{{yield}}"); + expect(_file('app/templates/components/x-foo.hbs')).to.equal( + '{{yield}}' + ); expect(_file('tests/integration/components/x-foo-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") .to.contain("import hbs from 'htmlbars-inline-precompile';") .to.contain("moduleForComponent('x-foo'") - .to.contain("integration: true") - .to.contain("{{x-foo}}") - .to.contain("{{#x-foo}}"); + .to.contain('integration: true') + .to.contain('{{x-foo}}') + .to.contain('{{#x-foo}}'); }); }); @@ -41,198 +43,240 @@ describe('Blueprint: component', function() { return emberGenerateDestroy(['component', 'foo/x-foo'], _file => { expect(_file('app/components/foo/x-foo.js')) .to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); + .to.contain('export default Component.extend({') + .to.contain('});'); - expect(_file('app/templates/components/foo/x-foo.hbs')) - .to.equal("{{yield}}"); + expect(_file('app/templates/components/foo/x-foo.hbs')).to.equal( + '{{yield}}' + ); expect(_file('tests/integration/components/foo/x-foo-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") .to.contain("import hbs from 'htmlbars-inline-precompile';") .to.contain("moduleForComponent('foo/x-foo'") - .to.contain("integration: true") - .to.contain("{{foo/x-foo}}") - .to.contain("{{#foo/x-foo}}"); + .to.contain('integration: true') + .to.contain('{{foo/x-foo}}') + .to.contain('{{#foo/x-foo}}'); }); }); it('component x-foo --path foo', function() { - return emberGenerateDestroy(['component', 'x-foo', '--path', 'foo'], _file => { - expect(_file('app/components/x-foo.js')) - .to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); + return emberGenerateDestroy( + ['component', 'x-foo', '--path', 'foo'], + _file => { + expect(_file('app/components/x-foo.js')) + .to.contain("import Component from '@ember/component';") + .to.contain('export default Component.extend({') + .to.contain('});'); - expect(_file('app/templates/components/x-foo.hbs')) - .to.equal("{{yield}}"); + expect(_file('app/templates/components/x-foo.hbs')).to.equal( + '{{yield}}' + ); - expect(_file('tests/integration/components/x-foo-test.js')) - .to.contain("import { moduleForComponent, test } from 'ember-qunit';") - .to.contain("import hbs from 'htmlbars-inline-precompile';") - .to.contain("moduleForComponent('x-foo'") - .to.contain("integration: true") - .to.contain("{{x-foo}}") - .to.contain("{{#x-foo}}"); - }); + expect(_file('tests/integration/components/x-foo-test.js')) + .to.contain( + "import { moduleForComponent, test } from 'ember-qunit';" + ) + .to.contain("import hbs from 'htmlbars-inline-precompile';") + .to.contain("moduleForComponent('x-foo'") + .to.contain('integration: true') + .to.contain('{{x-foo}}') + .to.contain('{{#x-foo}}'); + } + ); }); it('component x-foo --pod', function() { return emberGenerateDestroy(['component', 'x-foo', '--pod'], _file => { expect(_file('app/components/x-foo/component.js')) .to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); + .to.contain('export default Component.extend({') + .to.contain('});'); - expect(_file('app/components/x-foo/template.hbs')) - .to.equal("{{yield}}"); + expect(_file('app/components/x-foo/template.hbs')).to.equal( + '{{yield}}' + ); expect(_file('tests/integration/components/x-foo/component-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") .to.contain("import hbs from 'htmlbars-inline-precompile';") .to.contain("moduleForComponent('x-foo'") - .to.contain("integration: true"); + .to.contain('integration: true'); }); }); it('component foo/x-foo --pod', function() { - return emberGenerateDestroy(['component', 'foo/x-foo', '--pod'], _file => { - expect(_file('app/components/foo/x-foo/component.js')) - .to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); - - expect(_file('app/components/foo/x-foo/template.hbs')) - .to.equal("{{yield}}"); - - expect(_file('tests/integration/components/foo/x-foo/component-test.js')) - .to.contain("import { moduleForComponent, test } from 'ember-qunit';") - .to.contain("import hbs from 'htmlbars-inline-precompile';") - .to.contain("moduleForComponent('foo/x-foo'") - .to.contain("integration: true") - .to.contain("{{foo/x-foo}}") - .to.contain("{{#foo/x-foo}}"); - }); + return emberGenerateDestroy( + ['component', 'foo/x-foo', '--pod'], + _file => { + expect(_file('app/components/foo/x-foo/component.js')) + .to.contain("import Component from '@ember/component';") + .to.contain('export default Component.extend({') + .to.contain('});'); + + expect(_file('app/components/foo/x-foo/template.hbs')).to.equal( + '{{yield}}' + ); + + expect( + _file('tests/integration/components/foo/x-foo/component-test.js') + ) + .to.contain( + "import { moduleForComponent, test } from 'ember-qunit';" + ) + .to.contain("import hbs from 'htmlbars-inline-precompile';") + .to.contain("moduleForComponent('foo/x-foo'") + .to.contain('integration: true') + .to.contain('{{foo/x-foo}}') + .to.contain('{{#foo/x-foo}}'); + } + ); }); it('component x-foo --pod --path bar', function() { - return emberGenerateDestroy(['component', 'x-foo', '--pod', '--path', 'bar'], _file => { - expect(_file('app/bar/x-foo/component.js')) - .to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); + return emberGenerateDestroy( + ['component', 'x-foo', '--pod', '--path', 'bar'], + _file => { + expect(_file('app/bar/x-foo/component.js')) + .to.contain("import Component from '@ember/component';") + .to.contain('export default Component.extend({') + .to.contain('});'); - expect(_file('app/bar/x-foo/template.hbs')) - .to.equal("{{yield}}"); + expect(_file('app/bar/x-foo/template.hbs')).to.equal('{{yield}}'); - expect(_file('tests/integration/bar/x-foo/component-test.js')) - .to.contain("import { moduleForComponent, test } from 'ember-qunit';") - .to.contain("import hbs from 'htmlbars-inline-precompile';") - .to.contain("moduleForComponent('bar/x-foo'") - .to.contain("integration: true") - .to.contain("{{bar/x-foo}}") - .to.contain("{{#bar/x-foo}}"); - }); + expect(_file('tests/integration/bar/x-foo/component-test.js')) + .to.contain( + "import { moduleForComponent, test } from 'ember-qunit';" + ) + .to.contain("import hbs from 'htmlbars-inline-precompile';") + .to.contain("moduleForComponent('bar/x-foo'") + .to.contain('integration: true') + .to.contain('{{bar/x-foo}}') + .to.contain('{{#bar/x-foo}}'); + } + ); }); it('component foo/x-foo --pod --path bar', function() { - return emberGenerateDestroy(['component', 'foo/x-foo', '--pod', '--path', 'bar'], _file => { - expect(_file('app/bar/foo/x-foo/component.js')) - .to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); + return emberGenerateDestroy( + ['component', 'foo/x-foo', '--pod', '--path', 'bar'], + _file => { + expect(_file('app/bar/foo/x-foo/component.js')) + .to.contain("import Component from '@ember/component';") + .to.contain('export default Component.extend({') + .to.contain('});'); - expect(_file('app/bar/foo/x-foo/template.hbs')) - .to.equal("{{yield}}"); + expect(_file('app/bar/foo/x-foo/template.hbs')).to.equal('{{yield}}'); - expect(_file('tests/integration/bar/foo/x-foo/component-test.js')) - .to.contain("import { moduleForComponent, test } from 'ember-qunit';") - .to.contain("import hbs from 'htmlbars-inline-precompile';") - .to.contain("moduleForComponent('bar/foo/x-foo'") - .to.contain("integration: true") - .to.contain("{{bar/foo/x-foo}}") - .to.contain("{{#bar/foo/x-foo}}"); - }); + expect(_file('tests/integration/bar/foo/x-foo/component-test.js')) + .to.contain( + "import { moduleForComponent, test } from 'ember-qunit';" + ) + .to.contain("import hbs from 'htmlbars-inline-precompile';") + .to.contain("moduleForComponent('bar/foo/x-foo'") + .to.contain('integration: true') + .to.contain('{{bar/foo/x-foo}}') + .to.contain('{{#bar/foo/x-foo}}'); + } + ); }); it('component x-foo --pod --path bar/baz', function() { - return emberGenerateDestroy(['component', 'x-foo', '--pod', '--path', 'bar/baz'], _file => { - expect(_file('app/bar/baz/x-foo/component.js')) - .to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); + return emberGenerateDestroy( + ['component', 'x-foo', '--pod', '--path', 'bar/baz'], + _file => { + expect(_file('app/bar/baz/x-foo/component.js')) + .to.contain("import Component from '@ember/component';") + .to.contain('export default Component.extend({') + .to.contain('});'); - expect(_file('app/bar/baz/x-foo/template.hbs')) - .to.equal("{{yield}}"); + expect(_file('app/bar/baz/x-foo/template.hbs')).to.equal('{{yield}}'); - expect(_file('tests/integration/bar/baz/x-foo/component-test.js')) - .to.contain("import { moduleForComponent, test } from 'ember-qunit';") - .to.contain("import hbs from 'htmlbars-inline-precompile';") - .to.contain("moduleForComponent('bar/baz/x-foo'") - .to.contain("integration: true") - .to.contain("{{bar/baz/x-foo}}") - .to.contain("{{#bar/baz/x-foo}}"); - }); + expect(_file('tests/integration/bar/baz/x-foo/component-test.js')) + .to.contain( + "import { moduleForComponent, test } from 'ember-qunit';" + ) + .to.contain("import hbs from 'htmlbars-inline-precompile';") + .to.contain("moduleForComponent('bar/baz/x-foo'") + .to.contain('integration: true') + .to.contain('{{bar/baz/x-foo}}') + .to.contain('{{#bar/baz/x-foo}}'); + } + ); }); it('component foo/x-foo --pod --path bar/baz', function() { - return emberGenerateDestroy(['component', 'foo/x-foo', '--pod', '--path', 'bar/baz'], _file => { - expect(_file('app/bar/baz/foo/x-foo/component.js')) - .to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); + return emberGenerateDestroy( + ['component', 'foo/x-foo', '--pod', '--path', 'bar/baz'], + _file => { + expect(_file('app/bar/baz/foo/x-foo/component.js')) + .to.contain("import Component from '@ember/component';") + .to.contain('export default Component.extend({') + .to.contain('});'); - expect(_file('app/bar/baz/foo/x-foo/template.hbs')) - .to.equal("{{yield}}"); + expect(_file('app/bar/baz/foo/x-foo/template.hbs')).to.equal( + '{{yield}}' + ); - expect(_file('tests/integration/bar/baz/foo/x-foo/component-test.js')) - .to.contain("import { moduleForComponent, test } from 'ember-qunit';") - .to.contain("import hbs from 'htmlbars-inline-precompile';") - .to.contain("moduleForComponent('bar/baz/foo/x-foo'") - .to.contain("integration: true") - .to.contain("{{bar/baz/foo/x-foo}}") - .to.contain("{{#bar/baz/foo/x-foo}}"); - }); + expect(_file('tests/integration/bar/baz/foo/x-foo/component-test.js')) + .to.contain( + "import { moduleForComponent, test } from 'ember-qunit';" + ) + .to.contain("import hbs from 'htmlbars-inline-precompile';") + .to.contain("moduleForComponent('bar/baz/foo/x-foo'") + .to.contain('integration: true') + .to.contain('{{bar/baz/foo/x-foo}}') + .to.contain('{{#bar/baz/foo/x-foo}}'); + } + ); }); it('component x-foo --pod -no-path', function() { - return emberGenerateDestroy(['component', 'x-foo', '--pod', '-no-path'], _file => { - expect(_file('app/x-foo/component.js')) - .to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); + return emberGenerateDestroy( + ['component', 'x-foo', '--pod', '-no-path'], + _file => { + expect(_file('app/x-foo/component.js')) + .to.contain("import Component from '@ember/component';") + .to.contain('export default Component.extend({') + .to.contain('});'); - expect(_file('app/x-foo/template.hbs')) - .to.equal("{{yield}}"); + expect(_file('app/x-foo/template.hbs')).to.equal('{{yield}}'); - expect(_file('tests/integration/x-foo/component-test.js')) - .to.contain("import { moduleForComponent, test } from 'ember-qunit';") - .to.contain("import hbs from 'htmlbars-inline-precompile';") - .to.contain("moduleForComponent('x-foo'") - .to.contain("integration: true") - .to.contain("{{x-foo}}") - .to.contain("{{#x-foo}}"); - }); + expect(_file('tests/integration/x-foo/component-test.js')) + .to.contain( + "import { moduleForComponent, test } from 'ember-qunit';" + ) + .to.contain("import hbs from 'htmlbars-inline-precompile';") + .to.contain("moduleForComponent('x-foo'") + .to.contain('integration: true') + .to.contain('{{x-foo}}') + .to.contain('{{#x-foo}}'); + } + ); }); it('component foo/x-foo --pod -no-path', function() { - return emberGenerateDestroy(['component', 'foo/x-foo', '--pod', '-no-path'], _file => { - expect(_file('app/foo/x-foo/component.js')) - .to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); + return emberGenerateDestroy( + ['component', 'foo/x-foo', '--pod', '-no-path'], + _file => { + expect(_file('app/foo/x-foo/component.js')) + .to.contain("import Component from '@ember/component';") + .to.contain('export default Component.extend({') + .to.contain('});'); - expect(_file('app/foo/x-foo/template.hbs')) - .to.equal("{{yield}}"); + expect(_file('app/foo/x-foo/template.hbs')).to.equal('{{yield}}'); - expect(_file('tests/integration/foo/x-foo/component-test.js')) - .to.contain("import { moduleForComponent, test } from 'ember-qunit';") - .to.contain("import hbs from 'htmlbars-inline-precompile';") - .to.contain("moduleForComponent('foo/x-foo'") - .to.contain("integration: true") - .to.contain("{{foo/x-foo}}") - .to.contain("{{#foo/x-foo}}"); - }); + expect(_file('tests/integration/foo/x-foo/component-test.js')) + .to.contain( + "import { moduleForComponent, test } from 'ember-qunit';" + ) + .to.contain("import hbs from 'htmlbars-inline-precompile';") + .to.contain("moduleForComponent('foo/x-foo'") + .to.contain('integration: true') + .to.contain('{{foo/x-foo}}') + .to.contain('{{#foo/x-foo}}'); + } + ); }); describe('with podModulePrefix', function() { @@ -244,159 +288,216 @@ describe('Blueprint: component', function() { return emberGenerateDestroy(['component', 'x-foo', '--pod'], _file => { expect(_file('app/pods/components/x-foo/component.js')) .to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); - - expect(_file('app/pods/components/x-foo/template.hbs')) - .to.equal("{{yield}}"); - - expect(_file('tests/integration/pods/components/x-foo/component-test.js')) - .to.contain("import { moduleForComponent, test } from 'ember-qunit';") + .to.contain('export default Component.extend({') + .to.contain('});'); + + expect(_file('app/pods/components/x-foo/template.hbs')).to.equal( + '{{yield}}' + ); + + expect( + _file('tests/integration/pods/components/x-foo/component-test.js') + ) + .to.contain( + "import { moduleForComponent, test } from 'ember-qunit';" + ) .to.contain("import hbs from 'htmlbars-inline-precompile';") .to.contain("moduleForComponent('x-foo'") - .to.contain("integration: true") - .to.contain("{{x-foo}}") - .to.contain("{{#x-foo}}"); + .to.contain('integration: true') + .to.contain('{{x-foo}}') + .to.contain('{{#x-foo}}'); }); }); it('component foo/x-foo --pod', function() { - return emberGenerateDestroy(['component', 'foo/x-foo', '--pod'], _file => { - expect(_file('app/pods/components/foo/x-foo/component.js')) - .to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); - - expect(_file('app/pods/components/foo/x-foo/template.hbs')) - .to.equal("{{yield}}"); - - expect(_file('tests/integration/pods/components/foo/x-foo/component-test.js')) - .to.contain("import { moduleForComponent, test } from 'ember-qunit';") - .to.contain("import hbs from 'htmlbars-inline-precompile';") - .to.contain("moduleForComponent('foo/x-foo'") - .to.contain("integration: true") - .to.contain("{{foo/x-foo}}") - .to.contain("{{#foo/x-foo}}"); - }); + return emberGenerateDestroy( + ['component', 'foo/x-foo', '--pod'], + _file => { + expect(_file('app/pods/components/foo/x-foo/component.js')) + .to.contain("import Component from '@ember/component';") + .to.contain('export default Component.extend({') + .to.contain('});'); + + expect( + _file('app/pods/components/foo/x-foo/template.hbs') + ).to.equal('{{yield}}'); + + expect( + _file( + 'tests/integration/pods/components/foo/x-foo/component-test.js' + ) + ) + .to.contain( + "import { moduleForComponent, test } from 'ember-qunit';" + ) + .to.contain("import hbs from 'htmlbars-inline-precompile';") + .to.contain("moduleForComponent('foo/x-foo'") + .to.contain('integration: true') + .to.contain('{{foo/x-foo}}') + .to.contain('{{#foo/x-foo}}'); + } + ); }); it('component x-foo --pod --path bar', function() { - return emberGenerateDestroy(['component', 'x-foo', '--pod', '--path', 'bar'], _file => { - expect(_file('app/pods/bar/x-foo/component.js')) - .to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); - - expect(_file('app/pods/bar/x-foo/template.hbs')) - .to.equal("{{yield}}"); - - expect(_file('tests/integration/pods/bar/x-foo/component-test.js')) - .to.contain("import { moduleForComponent, test } from 'ember-qunit';") - .to.contain("import hbs from 'htmlbars-inline-precompile';") - .to.contain("moduleForComponent('bar/x-foo'") - .to.contain("integration: true") - .to.contain("{{bar/x-foo}}") - .to.contain("{{#bar/x-foo}}"); - }); + return emberGenerateDestroy( + ['component', 'x-foo', '--pod', '--path', 'bar'], + _file => { + expect(_file('app/pods/bar/x-foo/component.js')) + .to.contain("import Component from '@ember/component';") + .to.contain('export default Component.extend({') + .to.contain('});'); + + expect(_file('app/pods/bar/x-foo/template.hbs')).to.equal( + '{{yield}}' + ); + + expect(_file('tests/integration/pods/bar/x-foo/component-test.js')) + .to.contain( + "import { moduleForComponent, test } from 'ember-qunit';" + ) + .to.contain("import hbs from 'htmlbars-inline-precompile';") + .to.contain("moduleForComponent('bar/x-foo'") + .to.contain('integration: true') + .to.contain('{{bar/x-foo}}') + .to.contain('{{#bar/x-foo}}'); + } + ); }); it('component foo/x-foo --pod --path bar', function() { - return emberGenerateDestroy(['component', 'foo/x-foo', '--pod', '--path', 'bar'], _file => { - expect(_file('app/pods/bar/foo/x-foo/component.js')) - .to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); - - expect(_file('app/pods/bar/foo/x-foo/template.hbs')) - .to.equal("{{yield}}"); - - expect(_file('tests/integration/pods/bar/foo/x-foo/component-test.js')) - .to.contain("import { moduleForComponent, test } from 'ember-qunit';") - .to.contain("moduleForComponent('bar/foo/x-foo'") - .to.contain("integration: true") - .to.contain("{{bar/foo/x-foo}}") - .to.contain("{{#bar/foo/x-foo}}"); - }); + return emberGenerateDestroy( + ['component', 'foo/x-foo', '--pod', '--path', 'bar'], + _file => { + expect(_file('app/pods/bar/foo/x-foo/component.js')) + .to.contain("import Component from '@ember/component';") + .to.contain('export default Component.extend({') + .to.contain('});'); + + expect(_file('app/pods/bar/foo/x-foo/template.hbs')).to.equal( + '{{yield}}' + ); + + expect( + _file('tests/integration/pods/bar/foo/x-foo/component-test.js') + ) + .to.contain( + "import { moduleForComponent, test } from 'ember-qunit';" + ) + .to.contain("moduleForComponent('bar/foo/x-foo'") + .to.contain('integration: true') + .to.contain('{{bar/foo/x-foo}}') + .to.contain('{{#bar/foo/x-foo}}'); + } + ); }); it('component x-foo --pod --path bar/baz', function() { - return emberGenerateDestroy(['component', 'x-foo', '--pod', '--path', 'bar/baz'], _file => { - expect(_file('app/pods/bar/baz/x-foo/component.js')) - .to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); - - expect(_file('app/pods/bar/baz/x-foo/template.hbs')) - .to.equal("{{yield}}"); - - expect(_file('tests/integration/pods/bar/baz/x-foo/component-test.js')) - .to.contain("import { moduleForComponent, test } from 'ember-qunit';") - .to.contain("import hbs from 'htmlbars-inline-precompile';") - .to.contain("moduleForComponent('bar/baz/x-foo'") - .to.contain("integration: true") - .to.contain("{{bar/baz/x-foo}}") - .to.contain("{{#bar/baz/x-foo}}"); - }); + return emberGenerateDestroy( + ['component', 'x-foo', '--pod', '--path', 'bar/baz'], + _file => { + expect(_file('app/pods/bar/baz/x-foo/component.js')) + .to.contain("import Component from '@ember/component';") + .to.contain('export default Component.extend({') + .to.contain('});'); + + expect(_file('app/pods/bar/baz/x-foo/template.hbs')).to.equal( + '{{yield}}' + ); + + expect( + _file('tests/integration/pods/bar/baz/x-foo/component-test.js') + ) + .to.contain( + "import { moduleForComponent, test } from 'ember-qunit';" + ) + .to.contain("import hbs from 'htmlbars-inline-precompile';") + .to.contain("moduleForComponent('bar/baz/x-foo'") + .to.contain('integration: true') + .to.contain('{{bar/baz/x-foo}}') + .to.contain('{{#bar/baz/x-foo}}'); + } + ); }); it('component foo/x-foo --pod --path bar/baz', function() { - return emberGenerateDestroy(['component', 'foo/x-foo', '--pod', '--path', 'bar/baz'], _file => { - expect(_file('app/pods/bar/baz/foo/x-foo/component.js')) - .to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); - - expect(_file('app/pods/bar/baz/foo/x-foo/template.hbs')) - .to.equal("{{yield}}"); - - expect(_file('tests/integration/pods/bar/baz/foo/x-foo/component-test.js')) - .to.contain("import { moduleForComponent, test } from 'ember-qunit';") - .to.contain("import hbs from 'htmlbars-inline-precompile';") - .to.contain("moduleForComponent('bar/baz/foo/x-foo'") - .to.contain("integration: true") - .to.contain("{{bar/baz/foo/x-foo}}") - .to.contain("{{#bar/baz/foo/x-foo}}"); - }); + return emberGenerateDestroy( + ['component', 'foo/x-foo', '--pod', '--path', 'bar/baz'], + _file => { + expect(_file('app/pods/bar/baz/foo/x-foo/component.js')) + .to.contain("import Component from '@ember/component';") + .to.contain('export default Component.extend({') + .to.contain('});'); + + expect(_file('app/pods/bar/baz/foo/x-foo/template.hbs')).to.equal( + '{{yield}}' + ); + + expect( + _file( + 'tests/integration/pods/bar/baz/foo/x-foo/component-test.js' + ) + ) + .to.contain( + "import { moduleForComponent, test } from 'ember-qunit';" + ) + .to.contain("import hbs from 'htmlbars-inline-precompile';") + .to.contain("moduleForComponent('bar/baz/foo/x-foo'") + .to.contain('integration: true') + .to.contain('{{bar/baz/foo/x-foo}}') + .to.contain('{{#bar/baz/foo/x-foo}}'); + } + ); }); it('component x-foo --pod -no-path', function() { - return emberGenerateDestroy(['component', 'x-foo', '--pod', '-no-path'], _file => { - expect(_file('app/pods/x-foo/component.js')) - .to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); - - expect(_file('app/pods/x-foo/template.hbs')) - .to.equal("{{yield}}"); - - expect(_file('tests/integration/pods/x-foo/component-test.js')) - .to.contain("import { moduleForComponent, test } from 'ember-qunit';") - .to.contain("import hbs from 'htmlbars-inline-precompile';") - .to.contain("moduleForComponent('x-foo'") - .to.contain("integration: true") - .to.contain("{{x-foo}}") - .to.contain("{{#x-foo}}"); - }); + return emberGenerateDestroy( + ['component', 'x-foo', '--pod', '-no-path'], + _file => { + expect(_file('app/pods/x-foo/component.js')) + .to.contain("import Component from '@ember/component';") + .to.contain('export default Component.extend({') + .to.contain('});'); + + expect(_file('app/pods/x-foo/template.hbs')).to.equal('{{yield}}'); + + expect(_file('tests/integration/pods/x-foo/component-test.js')) + .to.contain( + "import { moduleForComponent, test } from 'ember-qunit';" + ) + .to.contain("import hbs from 'htmlbars-inline-precompile';") + .to.contain("moduleForComponent('x-foo'") + .to.contain('integration: true') + .to.contain('{{x-foo}}') + .to.contain('{{#x-foo}}'); + } + ); }); it('component foo/x-foo --pod -no-path', function() { - return emberGenerateDestroy(['component', 'foo/x-foo', '--pod', '-no-path'], _file => { - expect(_file('app/pods/foo/x-foo/component.js')) - .to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); - - expect(_file('app/pods/foo/x-foo/template.hbs')) - .to.equal("{{yield}}"); - - expect(_file('tests/integration/pods/foo/x-foo/component-test.js')) - .to.contain("import { moduleForComponent, test } from 'ember-qunit';") - .to.contain("import hbs from 'htmlbars-inline-precompile';") - .to.contain("moduleForComponent('foo/x-foo'") - .to.contain("integration: true") - .to.contain("{{foo/x-foo}}") - .to.contain("{{#foo/x-foo}}"); - }); + return emberGenerateDestroy( + ['component', 'foo/x-foo', '--pod', '-no-path'], + _file => { + expect(_file('app/pods/foo/x-foo/component.js')) + .to.contain("import Component from '@ember/component';") + .to.contain('export default Component.extend({') + .to.contain('});'); + + expect(_file('app/pods/foo/x-foo/template.hbs')).to.equal( + '{{yield}}' + ); + + expect(_file('tests/integration/pods/foo/x-foo/component-test.js')) + .to.contain( + "import { moduleForComponent, test } from 'ember-qunit';" + ) + .to.contain("import hbs from 'htmlbars-inline-precompile';") + .to.contain("moduleForComponent('foo/x-foo'") + .to.contain('integration: true') + .to.contain('{{foo/x-foo}}') + .to.contain('{{#foo/x-foo}}'); + } + ); }); }); }); @@ -408,39 +509,43 @@ describe('Blueprint: component', function() { it('component x-foo', function() { return emberGenerateDestroy(['component', 'x-foo'], _file => { - expect(_file('src/ui/components/x-foo/component.js')).to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); + expect(_file('src/ui/components/x-foo/component.js')) + .to.contain("import Component from '@ember/component';") + .to.contain('export default Component.extend({') + .to.contain('});'); - expect(_file('src/ui/components/x-foo/template.hbs')) - .to.equal("{{yield}}"); + expect(_file('src/ui/components/x-foo/template.hbs')).to.equal( + '{{yield}}' + ); expect(_file('src/ui/components/x-foo/component-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") .to.contain("import hbs from 'htmlbars-inline-precompile';") .to.contain("moduleForComponent('x-foo'") - .to.contain("integration: true") - .to.contain("{{x-foo}}") - .to.contain("{{#x-foo}}"); + .to.contain('integration: true') + .to.contain('{{x-foo}}') + .to.contain('{{#x-foo}}'); }); }); it('component foo/x-foo', function() { return emberGenerateDestroy(['component', 'x-foo/x-bar'], _file => { - expect(_file('src/ui/components/x-foo/x-bar/component.js')).to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); + expect(_file('src/ui/components/x-foo/x-bar/component.js')) + .to.contain("import Component from '@ember/component';") + .to.contain('export default Component.extend({') + .to.contain('});'); - expect(_file('src/ui/components/x-foo/x-bar/template.hbs')) - .to.equal("{{yield}}"); + expect(_file('src/ui/components/x-foo/x-bar/template.hbs')).to.equal( + '{{yield}}' + ); expect(_file('src/ui/components/x-foo/x-bar/component-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") .to.contain("import hbs from 'htmlbars-inline-precompile';") .to.contain("moduleForComponent('x-foo/x-bar'") - .to.contain("integration: true") - .to.contain("{{x-foo/x-bar}}") - .to.contain("{{#x-foo/x-bar}}"); + .to.contain('integration: true') + .to.contain('{{x-foo/x-bar}}') + .to.contain('{{#x-foo/x-bar}}'); }); }); }); @@ -455,23 +560,25 @@ describe('Blueprint: component', function() { expect(_file('addon/components/x-foo.js')) .to.contain("import Component from '@ember/component';") .to.contain("import layout from '../templates/components/x-foo';") - .to.contain("export default Component.extend({") - .to.contain("layout") - .to.contain("});"); + .to.contain('export default Component.extend({') + .to.contain('layout') + .to.contain('});'); - expect(_file('addon/templates/components/x-foo.hbs')) - .to.equal("{{yield}}"); + expect(_file('addon/templates/components/x-foo.hbs')).to.equal( + '{{yield}}' + ); - expect(_file('app/components/x-foo.js')) - .to.contain("export { default } from 'my-addon/components/x-foo';"); + expect(_file('app/components/x-foo.js')).to.contain( + "export { default } from 'my-addon/components/x-foo';" + ); expect(_file('tests/integration/components/x-foo-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") .to.contain("import hbs from 'htmlbars-inline-precompile';") .to.contain("moduleForComponent('x-foo'") - .to.contain("integration: true") - .to.contain("{{x-foo}}") - .to.contain("{{#x-foo}}"); + .to.contain('integration: true') + .to.contain('{{x-foo}}') + .to.contain('{{#x-foo}}'); }); }); @@ -479,24 +586,28 @@ describe('Blueprint: component', function() { return emberGenerateDestroy(['component', 'nested/x-foo'], _file => { expect(_file('addon/components/nested/x-foo.js')) .to.contain("import Component from '@ember/component';") - .to.contain("import layout from '../../templates/components/nested/x-foo';") - .to.contain("export default Component.extend({") - .to.contain("layout") - .to.contain("});"); + .to.contain( + "import layout from '../../templates/components/nested/x-foo';" + ) + .to.contain('export default Component.extend({') + .to.contain('layout') + .to.contain('});'); - expect(_file('addon/templates/components/nested/x-foo.hbs')) - .to.equal("{{yield}}"); + expect(_file('addon/templates/components/nested/x-foo.hbs')).to.equal( + '{{yield}}' + ); - expect(_file('app/components/nested/x-foo.js')) - .to.contain("export { default } from 'my-addon/components/nested/x-foo';"); + expect(_file('app/components/nested/x-foo.js')).to.contain( + "export { default } from 'my-addon/components/nested/x-foo';" + ); expect(_file('tests/integration/components/nested/x-foo-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") .to.contain("import hbs from 'htmlbars-inline-precompile';") .to.contain("moduleForComponent('nested/x-foo'") - .to.contain("integration: true") - .to.contain("{{nested/x-foo}}") - .to.contain("{{#nested/x-foo}}"); + .to.contain('integration: true') + .to.contain('{{nested/x-foo}}') + .to.contain('{{#nested/x-foo}}'); }); }); @@ -504,36 +615,38 @@ describe('Blueprint: component', function() { return emberGenerateDestroy(['component', 'x-foo', '--dummy'], _file => { expect(_file('tests/dummy/app/components/x-foo.js')) .to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); + .to.contain('export default Component.extend({') + .to.contain('});'); - expect(_file('tests/dummy/app/templates/components/x-foo.hbs')) - .to.equal("{{yield}}"); + expect( + _file('tests/dummy/app/templates/components/x-foo.hbs') + ).to.equal('{{yield}}'); - expect(_file('app/components/x-foo.js')) - .to.not.exist; + expect(_file('app/components/x-foo.js')).to.not.exist; - expect(_file('tests/unit/components/x-foo-test.js')) - .to.not.exist; + expect(_file('tests/unit/components/x-foo-test.js')).to.not.exist; }); }); it('component nested/x-foo --dummy', function() { - return emberGenerateDestroy(['component', 'nested/x-foo', '--dummy'], _file => { - expect(_file('tests/dummy/app/components/nested/x-foo.js')) - .to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); + return emberGenerateDestroy( + ['component', 'nested/x-foo', '--dummy'], + _file => { + expect(_file('tests/dummy/app/components/nested/x-foo.js')) + .to.contain("import Component from '@ember/component';") + .to.contain('export default Component.extend({') + .to.contain('});'); - expect(_file('tests/dummy/app/templates/components/nested/x-foo.hbs')) - .to.equal("{{yield}}"); + expect( + _file('tests/dummy/app/templates/components/nested/x-foo.hbs') + ).to.equal('{{yield}}'); - expect(_file('app/components/nested/x-foo.js')) - .to.not.exist; + expect(_file('app/components/nested/x-foo.js')).to.not.exist; - expect(_file('tests/unit/components/nested/x-foo-test.js')) - .to.not.exist; - }); + expect(_file('tests/unit/components/nested/x-foo-test.js')).to.not + .exist; + } + ); }); it('component x-foo --pod', function() { @@ -541,20 +654,22 @@ describe('Blueprint: component', function() { expect(_file('addon/components/x-foo/component.js')) .to.contain("import Component from '@ember/component';") .to.contain("import layout from './template';") - .to.contain("export default Component.extend({") - .to.contain("layout") - .to.contain("});"); + .to.contain('export default Component.extend({') + .to.contain('layout') + .to.contain('});'); - expect(_file('addon/components/x-foo/template.hbs')) - .to.equal("{{yield}}"); + expect(_file('addon/components/x-foo/template.hbs')).to.equal( + '{{yield}}' + ); - expect(_file('app/components/x-foo/component.js')) - .to.contain("export { default } from 'my-addon/components/x-foo/component';"); + expect(_file('app/components/x-foo/component.js')).to.contain( + "export { default } from 'my-addon/components/x-foo/component';" + ); expect(_file('tests/integration/components/x-foo/component-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") .to.contain("moduleForComponent('x-foo'") - .to.contain("integration: true"); + .to.contain('integration: true'); }); }); }); @@ -566,41 +681,45 @@ describe('Blueprint: component', function() { it('component x-foo', function() { return emberGenerateDestroy(['component', 'x-foo'], _file => { - expect(_file('src/ui/components/x-foo/component.js')).to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); + expect(_file('src/ui/components/x-foo/component.js')) + .to.contain("import Component from '@ember/component';") + .to.contain('export default Component.extend({') + .to.contain('});'); - expect(_file('src/ui/components/x-foo/template.hbs')) - .to.equal("{{yield}}"); + expect(_file('src/ui/components/x-foo/template.hbs')).to.equal( + '{{yield}}' + ); - expect(_file('src/ui/components/x-foo/component-test.js')) - .to.contain("import { moduleForComponent, test } from 'ember-qunit';") - .to.contain("import hbs from 'htmlbars-inline-precompile';") - .to.contain("moduleForComponent('my-addon::x-foo'") - .to.contain("integration: true") - .to.contain("{{my-addon::x-foo}}") - .to.contain("{{#my-addon::x-foo}}") - .to.contain("{{/my-addon::x-foo}}"); + expect(_file('src/ui/components/x-foo/component-test.js')) + .to.contain("import { moduleForComponent, test } from 'ember-qunit';") + .to.contain("import hbs from 'htmlbars-inline-precompile';") + .to.contain("moduleForComponent('my-addon::x-foo'") + .to.contain('integration: true') + .to.contain('{{my-addon::x-foo}}') + .to.contain('{{#my-addon::x-foo}}') + .to.contain('{{/my-addon::x-foo}}'); }); }); it('component nested/x-foo', function() { return emberGenerateDestroy(['component', 'x-foo/x-bar'], _file => { - expect(_file('src/ui/components/x-foo/x-bar/component.js')).to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); + expect(_file('src/ui/components/x-foo/x-bar/component.js')) + .to.contain("import Component from '@ember/component';") + .to.contain('export default Component.extend({') + .to.contain('});'); - expect(_file('src/ui/components/x-foo/x-bar/template.hbs')) - .to.equal("{{yield}}"); + expect(_file('src/ui/components/x-foo/x-bar/template.hbs')).to.equal( + '{{yield}}' + ); - expect(_file('src/ui/components/x-foo/x-bar/component-test.js')) - .to.contain("import { moduleForComponent, test } from 'ember-qunit';") - .to.contain("import hbs from 'htmlbars-inline-precompile';") - .to.contain("moduleForComponent('my-addon::x-foo/x-bar'") - .to.contain("integration: true") - .to.contain("{{my-addon::x-foo/x-bar}}") - .to.contain("{{#my-addon::x-foo/x-bar}}") - .to.contain("{{/my-addon::x-foo/x-bar}}"); + expect(_file('src/ui/components/x-foo/x-bar/component-test.js')) + .to.contain("import { moduleForComponent, test } from 'ember-qunit';") + .to.contain("import hbs from 'htmlbars-inline-precompile';") + .to.contain("moduleForComponent('my-addon::x-foo/x-bar'") + .to.contain('integration: true') + .to.contain('{{my-addon::x-foo/x-bar}}') + .to.contain('{{#my-addon::x-foo/x-bar}}') + .to.contain('{{/my-addon::x-foo/x-bar}}'); }); }); @@ -608,36 +727,41 @@ describe('Blueprint: component', function() { return emberGenerateDestroy(['component', 'x-foo', '--dummy'], _file => { expect(_file('tests/dummy/src/ui/components/x-foo/component.js')) .to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); + .to.contain('export default Component.extend({') + .to.contain('});'); - expect(_file('tests/dummy/src/ui/components/x-foo/template.hbs')) - .to.equal("{{yield}}"); + expect( + _file('tests/dummy/src/ui/components/x-foo/template.hbs') + ).to.equal('{{yield}}'); - expect(_file('src/ui/components/x-foo/component.js')) - .to.not.exist; + expect(_file('src/ui/components/x-foo/component.js')).to.not.exist; - expect(_file('src/ui/components/x-foo/component-test.js')) - .to.not.exist; + expect(_file('src/ui/components/x-foo/component-test.js')).to.not.exist; }); }); it('component nested/x-foo --dummy', function() { - return emberGenerateDestroy(['component', 'x-foo/x-bar', '--dummy'], _file => { - expect(_file('tests/dummy/src/ui/components/x-foo/x-bar/component.js')) - .to.contain("import Component from '@ember/component';") - .to.contain("export default Component.extend({") - .to.contain("});"); + return emberGenerateDestroy( + ['component', 'x-foo/x-bar', '--dummy'], + _file => { + expect( + _file('tests/dummy/src/ui/components/x-foo/x-bar/component.js') + ) + .to.contain("import Component from '@ember/component';") + .to.contain('export default Component.extend({') + .to.contain('});'); - expect(_file('tests/dummy/src/ui/components/x-foo/x-bar/template.hbs')) - .to.equal("{{yield}}"); + expect( + _file('tests/dummy/src/ui/components/x-foo/x-bar/template.hbs') + ).to.equal('{{yield}}'); - expect(_file('src/ui/components/x-foo/x-bar/component.js')) - .to.not.exist; + expect(_file('src/ui/components/x-foo/x-bar/component.js')).to.not + .exist; - expect(_file('src/ui/components/x-foo/x-bar/component-test.js')) - .to.not.exist; - }); + expect(_file('src/ui/components/x-foo/x-bar/component-test.js')).to + .not.exist; + } + ); }); }); @@ -647,120 +771,172 @@ describe('Blueprint: component', function() { }); it('component x-foo --in-repo-addon=my-addon', function() { - return emberGenerateDestroy(['component', 'x-foo', '--in-repo-addon=my-addon'], _file => { - expect(_file('lib/my-addon/addon/components/x-foo.js')) - .to.contain("import Component from '@ember/component';") - .to.contain("import layout from '../templates/components/x-foo';") - .to.contain("export default Component.extend({") - .to.contain("layout") - .to.contain("});"); - - expect(_file('lib/my-addon/addon/templates/components/x-foo.hbs')) - .to.equal("{{yield}}"); - - expect(_file('lib/my-addon/app/components/x-foo.js')) - .to.contain("export { default } from 'my-addon/components/x-foo';"); - - expect(_file('tests/integration/components/x-foo-test.js')) - .to.contain("import { moduleForComponent, test } from 'ember-qunit';") - .to.contain("import hbs from 'htmlbars-inline-precompile';") - .to.contain("moduleForComponent('x-foo'") - .to.contain("integration: true") - .to.contain("{{x-foo}}") - .to.contain("{{#x-foo}}"); - }); + return emberGenerateDestroy( + ['component', 'x-foo', '--in-repo-addon=my-addon'], + _file => { + expect(_file('lib/my-addon/addon/components/x-foo.js')) + .to.contain("import Component from '@ember/component';") + .to.contain("import layout from '../templates/components/x-foo';") + .to.contain('export default Component.extend({') + .to.contain('layout') + .to.contain('});'); + + expect( + _file('lib/my-addon/addon/templates/components/x-foo.hbs') + ).to.equal('{{yield}}'); + + expect(_file('lib/my-addon/app/components/x-foo.js')).to.contain( + "export { default } from 'my-addon/components/x-foo';" + ); + + expect(_file('tests/integration/components/x-foo-test.js')) + .to.contain( + "import { moduleForComponent, test } from 'ember-qunit';" + ) + .to.contain("import hbs from 'htmlbars-inline-precompile';") + .to.contain("moduleForComponent('x-foo'") + .to.contain('integration: true') + .to.contain('{{x-foo}}') + .to.contain('{{#x-foo}}'); + } + ); }); it('component nested/x-foo --in-repo-addon=my-addon', function() { - return emberGenerateDestroy(['component', 'nested/x-foo', '--in-repo-addon=my-addon'], _file => { - expect(_file('lib/my-addon/addon/components/nested/x-foo.js')) - .to.contain("import Component from '@ember/component';") - .to.contain("import layout from '../../templates/components/nested/x-foo';") - .to.contain("export default Component.extend({") - .to.contain("layout") - .to.contain("});"); - - expect(_file('lib/my-addon/addon/templates/components/nested/x-foo.hbs')) - .to.equal("{{yield}}"); - - expect(_file('lib/my-addon/app/components/nested/x-foo.js')) - .to.contain("export { default } from 'my-addon/components/nested/x-foo';"); - - expect(_file('tests/integration/components/nested/x-foo-test.js')) - .to.contain("import { moduleForComponent, test } from 'ember-qunit';") - .to.contain("import hbs from 'htmlbars-inline-precompile';") - .to.contain("moduleForComponent('nested/x-foo'") - .to.contain("integration: true"); - }); + return emberGenerateDestroy( + ['component', 'nested/x-foo', '--in-repo-addon=my-addon'], + _file => { + expect(_file('lib/my-addon/addon/components/nested/x-foo.js')) + .to.contain("import Component from '@ember/component';") + .to.contain( + "import layout from '../../templates/components/nested/x-foo';" + ) + .to.contain('export default Component.extend({') + .to.contain('layout') + .to.contain('});'); + + expect( + _file('lib/my-addon/addon/templates/components/nested/x-foo.hbs') + ).to.equal('{{yield}}'); + + expect( + _file('lib/my-addon/app/components/nested/x-foo.js') + ).to.contain( + "export { default } from 'my-addon/components/nested/x-foo';" + ); + + expect(_file('tests/integration/components/nested/x-foo-test.js')) + .to.contain( + "import { moduleForComponent, test } from 'ember-qunit';" + ) + .to.contain("import hbs from 'htmlbars-inline-precompile';") + .to.contain("moduleForComponent('nested/x-foo'") + .to.contain('integration: true'); + } + ); }); it('component x-foo --in-repo-addon=my-addon --pod', function() { - return emberGenerateDestroy(['component', 'x-foo', '--in-repo-addon=my-addon', '--pod'], _file => { - expect(_file('lib/my-addon/addon/components/x-foo/component.js')) - .to.contain("import Component from '@ember/component';") - .to.contain("import layout from './template';") - .to.contain("export default Component.extend({") - .to.contain("layout") - .to.contain("});"); - - expect(_file('lib/my-addon/addon/components/x-foo/template.hbs')) - .to.equal("{{yield}}"); - - expect(_file('lib/my-addon/app/components/x-foo/component.js')) - .to.contain("export { default } from 'my-addon/components/x-foo/component';"); - - expect(_file('tests/integration/components/x-foo/component-test.js')) - .to.contain("import { moduleForComponent, test } from 'ember-qunit';") - .to.contain("moduleForComponent('x-foo'") - .to.contain("integration: true"); - }); + return emberGenerateDestroy( + ['component', 'x-foo', '--in-repo-addon=my-addon', '--pod'], + _file => { + expect(_file('lib/my-addon/addon/components/x-foo/component.js')) + .to.contain("import Component from '@ember/component';") + .to.contain("import layout from './template';") + .to.contain('export default Component.extend({') + .to.contain('layout') + .to.contain('});'); + + expect( + _file('lib/my-addon/addon/components/x-foo/template.hbs') + ).to.equal('{{yield}}'); + + expect( + _file('lib/my-addon/app/components/x-foo/component.js') + ).to.contain( + "export { default } from 'my-addon/components/x-foo/component';" + ); + + expect(_file('tests/integration/components/x-foo/component-test.js')) + .to.contain( + "import { moduleForComponent, test } from 'ember-qunit';" + ) + .to.contain("moduleForComponent('x-foo'") + .to.contain('integration: true'); + } + ); }); it('component nested/x-foo --in-repo-addon=my-addon --pod', function() { - return emberGenerateDestroy(['component', 'nested/x-foo', '--in-repo-addon=my-addon', '--pod'], _file => { - expect(_file('lib/my-addon/addon/components/nested/x-foo/component.js')) - .to.contain("import Component from '@ember/component';") - .to.contain("import layout from './template';") - .to.contain("export default Component.extend({") - .to.contain("layout") - .to.contain("});"); - - expect(_file('lib/my-addon/addon/components/nested/x-foo/template.hbs')) - .to.equal("{{yield}}"); - - expect(_file('lib/my-addon/app/components/nested/x-foo/component.js')) - .to.contain("export { default } from 'my-addon/components/nested/x-foo/component';"); - - expect(_file('tests/integration/components/nested/x-foo/component-test.js')) - .to.contain("import { moduleForComponent, test } from 'ember-qunit';") - .to.contain("moduleForComponent('nested/x-foo'") - .to.contain("integration: true"); - }); + return emberGenerateDestroy( + ['component', 'nested/x-foo', '--in-repo-addon=my-addon', '--pod'], + _file => { + expect( + _file('lib/my-addon/addon/components/nested/x-foo/component.js') + ) + .to.contain("import Component from '@ember/component';") + .to.contain("import layout from './template';") + .to.contain('export default Component.extend({') + .to.contain('layout') + .to.contain('});'); + + expect( + _file('lib/my-addon/addon/components/nested/x-foo/template.hbs') + ).to.equal('{{yield}}'); + + expect( + _file('lib/my-addon/app/components/nested/x-foo/component.js') + ).to.contain( + "export { default } from 'my-addon/components/nested/x-foo/component';" + ); + + expect( + _file('tests/integration/components/nested/x-foo/component-test.js') + ) + .to.contain( + "import { moduleForComponent, test } from 'ember-qunit';" + ) + .to.contain("moduleForComponent('nested/x-foo'") + .to.contain('integration: true'); + } + ); }); }); describe('in in-repo-addon - module unification', function() { beforeEach(function() { - return emberNew({ target: 'in-repo-addon' }).then(() => fs.ensureDirSync('src')); + return emberNew({ target: 'in-repo-addon' }).then(() => + fs.ensureDirSync('src') + ); }); it('component x-foo --in-repo-addon=my-addon', function() { - return emberGenerateDestroy(['component', 'x-foo', '--in-repo-addon=my-addon'], _file => { - expect(_file('packages/my-addon/src/ui/components/x-foo/component.js')) - .to.contain("export default Component.extend({") - .to.contain("});"); - - expect(_file('packages/my-addon/src/ui/components/x-foo/template.hbs')) - .to.equal("{{yield}}"); - - expect(_file('packages/my-addon/src/ui/components/x-foo/component-test.js')) - .to.contain("import { moduleForComponent, test } from 'ember-qunit';") - .to.contain("import hbs from 'htmlbars-inline-precompile';") - .to.contain("moduleForComponent('my-addon::x-foo'") - .to.contain("integration: true") - .to.contain("{{#my-addon::x-foo}}") - .to.contain("{{my-addon::x-foo}}"); - }); + return emberGenerateDestroy( + ['component', 'x-foo', '--in-repo-addon=my-addon'], + _file => { + expect( + _file('packages/my-addon/src/ui/components/x-foo/component.js') + ) + .to.contain('export default Component.extend({') + .to.contain('});'); + + expect( + _file('packages/my-addon/src/ui/components/x-foo/template.hbs') + ).to.equal('{{yield}}'); + + expect( + _file('packages/my-addon/src/ui/components/x-foo/component-test.js') + ) + .to.contain( + "import { moduleForComponent, test } from 'ember-qunit';" + ) + .to.contain("import hbs from 'htmlbars-inline-precompile';") + .to.contain("moduleForComponent('my-addon::x-foo'") + .to.contain('integration: true') + .to.contain('{{#my-addon::x-foo}}') + .to.contain('{{my-addon::x-foo}}'); + } + ); }); }); }); diff --git a/node-tests/blueprints/controller-test-test.js b/node-tests/blueprints/controller-test-test.js index 8b64927e9f3..e32b9d75e18 100644 --- a/node-tests/blueprints/controller-test-test.js +++ b/node-tests/blueprints/controller-test-test.js @@ -22,8 +22,9 @@ describe('Blueprint: controller-test', function() { it('controller-test foo', function() { return emberGenerateDestroy(['controller-test', 'foo'], _file => { - expect(_file('tests/unit/controllers/foo-test.js')) - .to.equal(fixture('controller-test/default.js')); + expect(_file('tests/unit/controllers/foo-test.js')).to.equal( + fixture('controller-test/default.js') + ); }); }); @@ -34,8 +35,9 @@ describe('Blueprint: controller-test', function() { it('controller-test foo', function() { return emberGenerateDestroy(['controller-test', 'foo'], _file => { - expect(_file('tests/unit/controllers/foo-test.js')) - .to.equal(fixture('controller-test/rfc232.js')); + expect(_file('tests/unit/controllers/foo-test.js')).to.equal( + fixture('controller-test/rfc232.js') + ); }); }); }); @@ -51,8 +53,9 @@ describe('Blueprint: controller-test', function() { it('controller-test foo for mocha', function() { return emberGenerateDestroy(['controller-test', 'foo'], _file => { - expect(_file('tests/unit/controllers/foo-test.js')) - .to.equal(fixture('controller-test/mocha.js')); + expect(_file('tests/unit/controllers/foo-test.js')).to.equal( + fixture('controller-test/mocha.js') + ); }); }); }); @@ -68,8 +71,9 @@ describe('Blueprint: controller-test', function() { it('controller-test foo', function() { return emberGenerateDestroy(['controller-test', 'foo'], _file => { - expect(_file('tests/unit/controllers/foo-test.js')) - .to.equal(fixture('controller-test/mocha-0.12.js')); + expect(_file('tests/unit/controllers/foo-test.js')).to.equal( + fixture('controller-test/mocha-0.12.js') + ); }); }); }); @@ -82,8 +86,9 @@ describe('Blueprint: controller-test', function() { it('controller-test foo', function() { return emberGenerateDestroy(['controller-test', 'foo'], _file => { - expect(_file('tests/unit/controllers/foo-test.js')) - .to.equal(fixture('controller-test/default.js')); + expect(_file('tests/unit/controllers/foo-test.js')).to.equal( + fixture('controller-test/default.js') + ); }); }); }); diff --git a/node-tests/blueprints/controller-test.js b/node-tests/blueprints/controller-test.js index feaf48ca413..d7474de4cdd 100644 --- a/node-tests/blueprints/controller-test.js +++ b/node-tests/blueprints/controller-test.js @@ -21,7 +21,7 @@ describe('Blueprint: controller', function() { return emberGenerateDestroy(['controller', 'foo'], _file => { expect(_file('app/controllers/foo.js')) .to.contain("import Controller from '@ember/controller';") - .to.contain("export default Controller.extend({\n});"); + .to.contain('export default Controller.extend({\n});'); expect(_file('tests/unit/controllers/foo-test.js')) .to.contain("import { moduleFor, test } from 'ember-qunit';") @@ -33,7 +33,7 @@ describe('Blueprint: controller', function() { return emberGenerateDestroy(['controller', 'foo/bar'], _file => { expect(_file('app/controllers/foo/bar.js')) .to.contain("import Controller from '@ember/controller';") - .to.contain("export default Controller.extend({\n});"); + .to.contain('export default Controller.extend({\n});'); expect(_file('tests/unit/controllers/foo/bar-test.js')) .to.contain("import { moduleFor, test } from 'ember-qunit';") @@ -45,7 +45,7 @@ describe('Blueprint: controller', function() { return emberGenerateDestroy(['controller', 'foo', '--pod'], _file => { expect(_file('app/foo/controller.js')) .to.contain("import Controller from '@ember/controller';") - .to.contain("export default Controller.extend({\n});"); + .to.contain('export default Controller.extend({\n});'); expect(_file('tests/unit/foo/controller-test.js')) .to.contain("import { moduleFor, test } from 'ember-qunit';") @@ -57,7 +57,7 @@ describe('Blueprint: controller', function() { return emberGenerateDestroy(['controller', 'foo/bar', '--pod'], _file => { expect(_file('app/foo/bar/controller.js')) .to.contain("import Controller from '@ember/controller';") - .to.contain("export default Controller.extend({\n});"); + .to.contain('export default Controller.extend({\n});'); expect(_file('tests/unit/foo/bar/controller-test.js')) .to.contain("import { moduleFor, test } from 'ember-qunit';") @@ -74,7 +74,7 @@ describe('Blueprint: controller', function() { return emberGenerateDestroy(['controller', 'foo', '--pod'], _file => { expect(_file('app/pods/foo/controller.js')) .to.contain("import Controller from '@ember/controller';") - .to.contain("export default Controller.extend({\n});"); + .to.contain('export default Controller.extend({\n});'); expect(_file('tests/unit/pods/foo/controller-test.js')) .to.contain("import { moduleFor, test } from 'ember-qunit';") @@ -83,15 +83,18 @@ describe('Blueprint: controller', function() { }); it('controller foo/bar --pod podModulePrefix', function() { - return emberGenerateDestroy(['controller', 'foo/bar', '--pod'], _file => { - expect(_file('app/pods/foo/bar/controller.js')) - .to.contain("import Controller from '@ember/controller';") - .to.contain("export default Controller.extend({\n});"); - - expect(_file('tests/unit/pods/foo/bar/controller-test.js')) - .to.contain("import { moduleFor, test } from 'ember-qunit';") - .to.contain("moduleFor('controller:foo/bar'"); - }); + return emberGenerateDestroy( + ['controller', 'foo/bar', '--pod'], + _file => { + expect(_file('app/pods/foo/bar/controller.js')) + .to.contain("import Controller from '@ember/controller';") + .to.contain('export default Controller.extend({\n});'); + + expect(_file('tests/unit/pods/foo/bar/controller-test.js')) + .to.contain("import { moduleFor, test } from 'ember-qunit';") + .to.contain("moduleFor('controller:foo/bar'"); + } + ); }); }); }); @@ -105,10 +108,11 @@ describe('Blueprint: controller', function() { return emberGenerateDestroy(['controller', 'foo'], _file => { expect(_file('addon/controllers/foo.js')) .to.contain("import Controller from '@ember/controller';") - .to.contain("export default Controller.extend({\n});"); + .to.contain('export default Controller.extend({\n});'); - expect(_file('app/controllers/foo.js')) - .to.contain("export { default } from 'my-addon/controllers/foo';"); + expect(_file('app/controllers/foo.js')).to.contain( + "export { default } from 'my-addon/controllers/foo';" + ); expect(_file('tests/unit/controllers/foo-test.js')) .to.contain("import { moduleFor, test } from 'ember-qunit';") @@ -120,10 +124,11 @@ describe('Blueprint: controller', function() { return emberGenerateDestroy(['controller', 'foo/bar'], _file => { expect(_file('addon/controllers/foo/bar.js')) .to.contain("import Controller from '@ember/controller';") - .to.contain("export default Controller.extend({\n});"); + .to.contain('export default Controller.extend({\n});'); - expect(_file('app/controllers/foo/bar.js')) - .to.contain("export { default } from 'my-addon/controllers/foo/bar';"); + expect(_file('app/controllers/foo/bar.js')).to.contain( + "export { default } from 'my-addon/controllers/foo/bar';" + ); expect(_file('tests/unit/controllers/foo/bar-test.js')) .to.contain("import { moduleFor, test } from 'ember-qunit';") @@ -135,28 +140,27 @@ describe('Blueprint: controller', function() { return emberGenerateDestroy(['controller', 'foo', '--dummy'], _file => { expect(_file('tests/dummy/app/controllers/foo.js')) .to.contain("import Controller from '@ember/controller';") - .to.contain("export default Controller.extend({\n});"); + .to.contain('export default Controller.extend({\n});'); - expect(_file('app/controllers/foo-test.js')) - .to.not.exist; + expect(_file('app/controllers/foo-test.js')).to.not.exist; - expect(_file('tests/unit/controllers/foo-test.js')) - .to.not.exist; + expect(_file('tests/unit/controllers/foo-test.js')).to.not.exist; }); }); it('controller foo/bar --dummy', function() { - return emberGenerateDestroy(['controller', 'foo/bar', '--dummy'], _file => { - expect(_file('tests/dummy/app/controllers/foo/bar.js')) - .to.contain("import Controller from '@ember/controller';") - .to.contain("export default Controller.extend({\n});"); + return emberGenerateDestroy( + ['controller', 'foo/bar', '--dummy'], + _file => { + expect(_file('tests/dummy/app/controllers/foo/bar.js')) + .to.contain("import Controller from '@ember/controller';") + .to.contain('export default Controller.extend({\n});'); - expect(_file('app/controllers/foo/bar.js')) - .to.not.exist; + expect(_file('app/controllers/foo/bar.js')).to.not.exist; - expect(_file('tests/unit/controllers/foo/bar-test.js')) - .to.not.exist; - }); + expect(_file('tests/unit/controllers/foo/bar-test.js')).to.not.exist; + } + ); }); }); @@ -166,33 +170,41 @@ describe('Blueprint: controller', function() { }); it('controller foo --in-repo-addon=my-addon', function() { - return emberGenerateDestroy(['controller', 'foo', '--in-repo-addon=my-addon'], _file => { - expect(_file('lib/my-addon/addon/controllers/foo.js')) - .to.contain("import Controller from '@ember/controller';") - .to.contain("export default Controller.extend({\n});"); + return emberGenerateDestroy( + ['controller', 'foo', '--in-repo-addon=my-addon'], + _file => { + expect(_file('lib/my-addon/addon/controllers/foo.js')) + .to.contain("import Controller from '@ember/controller';") + .to.contain('export default Controller.extend({\n});'); - expect(_file('lib/my-addon/app/controllers/foo.js')) - .to.contain("export { default } from 'my-addon/controllers/foo';"); + expect(_file('lib/my-addon/app/controllers/foo.js')).to.contain( + "export { default } from 'my-addon/controllers/foo';" + ); - expect(_file('tests/unit/controllers/foo-test.js')) - .to.contain("import { moduleFor, test } from 'ember-qunit';") - .to.contain("moduleFor('controller:foo'"); - }); + expect(_file('tests/unit/controllers/foo-test.js')) + .to.contain("import { moduleFor, test } from 'ember-qunit';") + .to.contain("moduleFor('controller:foo'"); + } + ); }); it('controller foo/bar --in-repo-addon=my-addon', function() { - return emberGenerateDestroy(['controller', 'foo/bar', '--in-repo-addon=my-addon'], _file => { - expect(_file('lib/my-addon/addon/controllers/foo/bar.js')) - .to.contain("import Controller from '@ember/controller';") - .to.contain("export default Controller.extend({\n});"); + return emberGenerateDestroy( + ['controller', 'foo/bar', '--in-repo-addon=my-addon'], + _file => { + expect(_file('lib/my-addon/addon/controllers/foo/bar.js')) + .to.contain("import Controller from '@ember/controller';") + .to.contain('export default Controller.extend({\n});'); - expect(_file('lib/my-addon/app/controllers/foo/bar.js')) - .to.contain("export { default } from 'my-addon/controllers/foo/bar';"); + expect(_file('lib/my-addon/app/controllers/foo/bar.js')).to.contain( + "export { default } from 'my-addon/controllers/foo/bar';" + ); - expect(_file('tests/unit/controllers/foo/bar-test.js')) - .to.contain("import { moduleFor, test } from 'ember-qunit';") - .to.contain("moduleFor('controller:foo/bar'"); - }); + expect(_file('tests/unit/controllers/foo/bar-test.js')) + .to.contain("import { moduleFor, test } from 'ember-qunit';") + .to.contain("moduleFor('controller:foo/bar'"); + } + ); }); }); }); diff --git a/node-tests/blueprints/helper-addon-test.js b/node-tests/blueprints/helper-addon-test.js index b74a6319b87..4a0b9a13805 100644 --- a/node-tests/blueprints/helper-addon-test.js +++ b/node-tests/blueprints/helper-addon-test.js @@ -20,16 +20,21 @@ describe('Blueprint: helper-addon', function() { it('helper-addon foo/bar-baz', function() { return emberGenerateDestroy(['helper-addon', 'foo/bar-baz'], _file => { - expect(_file('app/helpers/foo/bar-baz.js')) - .to.equal(fixture('helper-addon.js')); + expect(_file('app/helpers/foo/bar-baz.js')).to.equal( + fixture('helper-addon.js') + ); }); }); it('helper-addon foo/bar-baz --pod', function() { - return emberGenerateDestroy(['helper-addon', 'foo/bar-baz', '--pod'], _file => { - expect(_file('app/helpers/foo/bar-baz.js')) - .to.equal(fixture('helper-addon.js')); - }); + return emberGenerateDestroy( + ['helper-addon', 'foo/bar-baz', '--pod'], + _file => { + expect(_file('app/helpers/foo/bar-baz.js')).to.equal( + fixture('helper-addon.js') + ); + } + ); }); }); }); diff --git a/node-tests/blueprints/helper-test-test.js b/node-tests/blueprints/helper-test-test.js index 0eeebbf5da0..03c72805142 100644 --- a/node-tests/blueprints/helper-test-test.js +++ b/node-tests/blueprints/helper-test-test.js @@ -22,16 +22,21 @@ describe('Blueprint: helper-test', function() { it('helper-test foo/bar-baz', function() { return emberGenerateDestroy(['helper-test', 'foo/bar-baz'], _file => { - expect(_file('tests/integration/helpers/foo/bar-baz-test.js')) - .to.equal(fixture('helper-test/integration.js')); + expect(_file('tests/integration/helpers/foo/bar-baz-test.js')).to.equal( + fixture('helper-test/integration.js') + ); }); }); it('helper-test foo/bar-baz --integration', function() { - return emberGenerateDestroy(['helper-test', 'foo/bar-baz', '--integration'], _file => { - expect(_file('tests/integration/helpers/foo/bar-baz-test.js')) - .to.equal(fixture('helper-test/integration.js')); - }); + return emberGenerateDestroy( + ['helper-test', 'foo/bar-baz', '--integration'], + _file => { + expect( + _file('tests/integration/helpers/foo/bar-baz-test.js') + ).to.equal(fixture('helper-test/integration.js')); + } + ); }); describe('with ember-cli-qunit@4.2.0', function() { @@ -41,16 +46,21 @@ describe('Blueprint: helper-test', function() { it('helper-test foo/bar-baz', function() { return emberGenerateDestroy(['helper-test', 'foo/bar-baz'], _file => { - expect(_file('tests/integration/helpers/foo/bar-baz-test.js')) - .to.equal(fixture('helper-test/rfc232.js')); + expect( + _file('tests/integration/helpers/foo/bar-baz-test.js') + ).to.equal(fixture('helper-test/rfc232.js')); }); }); it('helper-test foo/bar-baz --unit', function() { - return emberGenerateDestroy(['helper-test', 'foo/bar-baz', '--unit'], _file => { - expect(_file('tests/unit/helpers/foo/bar-baz-test.js')) - .to.equal(fixture('helper-test/rfc232-unit.js')); - }); + return emberGenerateDestroy( + ['helper-test', 'foo/bar-baz', '--unit'], + _file => { + expect(_file('tests/unit/helpers/foo/bar-baz-test.js')).to.equal( + fixture('helper-test/rfc232-unit.js') + ); + } + ); }); }); @@ -65,16 +75,21 @@ describe('Blueprint: helper-test', function() { it('helper-test foo/bar-baz --integration', function() { return emberGenerateDestroy(['helper-test', 'foo/bar-baz'], _file => { - expect(_file('tests/integration/helpers/foo/bar-baz-test.js')) - .to.equal(fixture('helper-test/mocha.js')); + expect( + _file('tests/integration/helpers/foo/bar-baz-test.js') + ).to.equal(fixture('helper-test/mocha.js')); }); }); it('helper-test foo/bar-baz --unit', function() { - return emberGenerateDestroy(['helper-test', 'foo/bar-baz', '--unit'], _file => { - expect(_file('tests/unit/helpers/foo/bar-baz-test.js')) - .to.equal(fixture('helper-test/mocha-unit.js')); - }); + return emberGenerateDestroy( + ['helper-test', 'foo/bar-baz', '--unit'], + _file => { + expect(_file('tests/unit/helpers/foo/bar-baz-test.js')).to.equal( + fixture('helper-test/mocha-unit.js') + ); + } + ); }); }); @@ -89,16 +104,21 @@ describe('Blueprint: helper-test', function() { it('helper-test foo/bar-baz for mocha', function() { return emberGenerateDestroy(['helper-test', 'foo/bar-baz'], _file => { - expect(_file('tests/integration/helpers/foo/bar-baz-test.js')) - .to.equal(fixture('helper-test/mocha-0.12.js')); + expect( + _file('tests/integration/helpers/foo/bar-baz-test.js') + ).to.equal(fixture('helper-test/mocha-0.12.js')); }); }); it('helper-test foo/bar-baz for mocha --unit', function() { - return emberGenerateDestroy(['helper-test', 'foo/bar-baz', '--unit'], _file => { - expect(_file('tests/unit/helpers/foo/bar-baz-test.js')) - .to.equal(fixture('helper-test/mocha-0.12-unit.js')); - }); + return emberGenerateDestroy( + ['helper-test', 'foo/bar-baz', '--unit'], + _file => { + expect(_file('tests/unit/helpers/foo/bar-baz-test.js')).to.equal( + fixture('helper-test/mocha-0.12-unit.js') + ); + } + ); }); }); }); @@ -110,8 +130,9 @@ describe('Blueprint: helper-test', function() { it('helper-test foo/bar-baz', function() { return emberGenerateDestroy(['helper-test', 'foo/bar-baz'], _file => { - expect(_file('tests/integration/helpers/foo/bar-baz-test.js')) - .to.equal(fixture('helper-test/integration.js')); + expect(_file('tests/integration/helpers/foo/bar-baz-test.js')).to.equal( + fixture('helper-test/integration.js') + ); }); }); }); diff --git a/node-tests/blueprints/helper-test.js b/node-tests/blueprints/helper-test.js index 3b785533f9f..ec12fdc6fee 100644 --- a/node-tests/blueprints/helper-test.js +++ b/node-tests/blueprints/helper-test.js @@ -21,37 +21,48 @@ describe('Blueprint: helper', function() { it('helper foo/bar-baz', function() { return emberGenerateDestroy(['helper', 'foo/bar-baz'], _file => { - expect(_file('app/helpers/foo/bar-baz.js')) - .to.equal(fixture('helper.js')); - expect(_file('tests/integration/helpers/foo/bar-baz-test.js')) - .to.equal(fixture('helper-test/integration.js')); + expect(_file('app/helpers/foo/bar-baz.js')).to.equal( + fixture('helper.js') + ); + expect(_file('tests/integration/helpers/foo/bar-baz-test.js')).to.equal( + fixture('helper-test/integration.js') + ); }); }); it('helper foo/bar-baz unit', function() { - return emberGenerateDestroy(['helper', '--test-type=unit', 'foo/bar-baz'], _file => { - expect(_file('app/helpers/foo/bar-baz.js')) - .to.equal(fixture('helper.js')); - expect(_file('tests/unit/helpers/foo/bar-baz-test.js')) - .to.equal(fixture('helper-test/unit.js')); - }); + return emberGenerateDestroy( + ['helper', '--test-type=unit', 'foo/bar-baz'], + _file => { + expect(_file('app/helpers/foo/bar-baz.js')).to.equal( + fixture('helper.js') + ); + expect(_file('tests/unit/helpers/foo/bar-baz-test.js')).to.equal( + fixture('helper-test/unit.js') + ); + } + ); }); it('helper foo/bar-baz --pod', function() { return emberGenerateDestroy(['helper', 'foo/bar-baz', '--pod'], _file => { - expect(_file('app/helpers/foo/bar-baz.js')) - .to.equal(fixture('helper.js')); - expect(_file('tests/integration/helpers/foo/bar-baz-test.js')) - .to.equal(fixture('helper-test/integration.js')); + expect(_file('app/helpers/foo/bar-baz.js')).to.equal( + fixture('helper.js') + ); + expect(_file('tests/integration/helpers/foo/bar-baz-test.js')).to.equal( + fixture('helper-test/integration.js') + ); }); }); it('helper foo/bar-baz --pod', function() { return emberGenerateDestroy(['helper', 'foo/bar-baz', '--pod'], _file => { - expect(_file('app/helpers/foo/bar-baz.js')) - .to.equal(fixture('helper.js')); - expect(_file('tests/integration/helpers/foo/bar-baz-test.js')) - .to.equal(fixture('helper-test/integration.js')); + expect(_file('app/helpers/foo/bar-baz.js')).to.equal( + fixture('helper.js') + ); + expect(_file('tests/integration/helpers/foo/bar-baz-test.js')).to.equal( + fixture('helper-test/integration.js') + ); }); }); @@ -61,21 +72,31 @@ describe('Blueprint: helper', function() { }); it('helper foo/bar-baz --pod', function() { - return emberGenerateDestroy(['helper', 'foo/bar-baz', '--pod'], _file => { - expect(_file('app/helpers/foo/bar-baz.js')) - .to.equal(fixture('helper.js')); - expect(_file('tests/integration/helpers/foo/bar-baz-test.js')) - .to.equal(fixture('helper-test/integration.js')); - }); + return emberGenerateDestroy( + ['helper', 'foo/bar-baz', '--pod'], + _file => { + expect(_file('app/helpers/foo/bar-baz.js')).to.equal( + fixture('helper.js') + ); + expect( + _file('tests/integration/helpers/foo/bar-baz-test.js') + ).to.equal(fixture('helper-test/integration.js')); + } + ); }); it('helper foo/bar-baz --pod', function() { - return emberGenerateDestroy(['helper', 'foo/bar-baz', '--pod'], _file => { - expect(_file('app/helpers/foo/bar-baz.js')) - .to.equal(fixture('helper.js')); - expect(_file('tests/integration/helpers/foo/bar-baz-test.js')) - .to.equal(fixture('helper-test/integration.js')); - }); + return emberGenerateDestroy( + ['helper', 'foo/bar-baz', '--pod'], + _file => { + expect(_file('app/helpers/foo/bar-baz.js')).to.equal( + fixture('helper.js') + ); + expect( + _file('tests/integration/helpers/foo/bar-baz-test.js') + ).to.equal(fixture('helper-test/integration.js')); + } + ); }); }); }); @@ -87,35 +108,44 @@ describe('Blueprint: helper', function() { it('helper foo/bar-baz', function() { return emberGenerateDestroy(['helper', 'foo/bar-baz'], _file => { - expect(_file('addon/helpers/foo/bar-baz.js')) - .to.equal(fixture('helper.js')); - expect(_file('app/helpers/foo/bar-baz.js')) - .to.equal(fixture('helper-addon.js')); - expect(_file('tests/integration/helpers/foo/bar-baz-test.js')) - .to.equal(fixture('helper-test/integration.js')); + expect(_file('addon/helpers/foo/bar-baz.js')).to.equal( + fixture('helper.js') + ); + expect(_file('app/helpers/foo/bar-baz.js')).to.equal( + fixture('helper-addon.js') + ); + expect(_file('tests/integration/helpers/foo/bar-baz-test.js')).to.equal( + fixture('helper-test/integration.js') + ); }); }); it('helper foo/bar-baz', function() { return emberGenerateDestroy(['helper', 'foo/bar-baz'], _file => { - expect(_file('addon/helpers/foo/bar-baz.js')) - .to.equal(fixture('helper.js')); - expect(_file('app/helpers/foo/bar-baz.js')) - .to.equal(fixture('helper-addon.js')); - expect(_file('tests/integration/helpers/foo/bar-baz-test.js')) - .to.equal(fixture('helper-test/integration.js')); + expect(_file('addon/helpers/foo/bar-baz.js')).to.equal( + fixture('helper.js') + ); + expect(_file('app/helpers/foo/bar-baz.js')).to.equal( + fixture('helper-addon.js') + ); + expect(_file('tests/integration/helpers/foo/bar-baz-test.js')).to.equal( + fixture('helper-test/integration.js') + ); }); }); it('helper foo/bar-baz --dummy', function() { - return emberGenerateDestroy(['helper', 'foo/bar-baz', '--dummy'], _file => { - expect(_file('tests/dummy/app/helpers/foo/bar-baz.js')) - .to.equal(fixture('helper.js')); - expect(_file('app/helpers/foo/bar-baz.js')) - .to.not.exist; - expect(_file('tests/integration/helpers/foo/bar-baz-test.js')) - .to.not.exist; - }); + return emberGenerateDestroy( + ['helper', 'foo/bar-baz', '--dummy'], + _file => { + expect(_file('tests/dummy/app/helpers/foo/bar-baz.js')).to.equal( + fixture('helper.js') + ); + expect(_file('app/helpers/foo/bar-baz.js')).to.not.exist; + expect(_file('tests/integration/helpers/foo/bar-baz-test.js')).to.not + .exist; + } + ); }); }); @@ -125,14 +155,20 @@ describe('Blueprint: helper', function() { }); it('helper foo/bar-baz --in-repo-addon=my-addon', function() { - return emberGenerateDestroy(['helper', 'foo/bar-baz', '--in-repo-addon=my-addon'], _file => { - expect(_file('lib/my-addon/addon/helpers/foo/bar-baz.js')) - .to.equal(fixture('helper.js')); - expect(_file('lib/my-addon/app/helpers/foo/bar-baz.js')) - .to.equal(fixture('helper-addon.js')); - expect(_file('tests/integration/helpers/foo/bar-baz-test.js')) - .to.equal(fixture('helper-test/integration.js')); - }); + return emberGenerateDestroy( + ['helper', 'foo/bar-baz', '--in-repo-addon=my-addon'], + _file => { + expect(_file('lib/my-addon/addon/helpers/foo/bar-baz.js')).to.equal( + fixture('helper.js') + ); + expect(_file('lib/my-addon/app/helpers/foo/bar-baz.js')).to.equal( + fixture('helper-addon.js') + ); + expect( + _file('tests/integration/helpers/foo/bar-baz-test.js') + ).to.equal(fixture('helper-test/integration.js')); + } + ); }); }); }); diff --git a/node-tests/blueprints/initializer-addon-test.js b/node-tests/blueprints/initializer-addon-test.js index c6816cc6450..07e1d95c939 100644 --- a/node-tests/blueprints/initializer-addon-test.js +++ b/node-tests/blueprints/initializer-addon-test.js @@ -18,16 +18,21 @@ describe('Blueprint: initializer-addon', function() { it('initializer-addon foo', function() { return emberGenerateDestroy(['initializer-addon', 'foo'], _file => { - expect(_file('app/initializers/foo.js')) - .to.contain("export { default, initialize } from 'my-addon/initializers/foo';"); + expect(_file('app/initializers/foo.js')).to.contain( + "export { default, initialize } from 'my-addon/initializers/foo';" + ); }); }); it('initializer-addon foo --pod', function() { - return emberGenerateDestroy(['initializer-addon', 'foo', '--pod'], _file => { - expect(_file('app/initializers/foo.js')) - .to.contain("export { default, initialize } from 'my-addon/initializers/foo';"); - }); + return emberGenerateDestroy( + ['initializer-addon', 'foo', '--pod'], + _file => { + expect(_file('app/initializers/foo.js')).to.contain( + "export { default, initialize } from 'my-addon/initializers/foo';" + ); + } + ); }); }); }); diff --git a/node-tests/blueprints/initializer-test-test.js b/node-tests/blueprints/initializer-test-test.js index 0e4ab834bd6..bd12e00139a 100644 --- a/node-tests/blueprints/initializer-test-test.js +++ b/node-tests/blueprints/initializer-test-test.js @@ -22,8 +22,9 @@ describe('Blueprint: initializer-test', function() { it('initializer-test foo', function() { return emberGenerateDestroy(['initializer-test', 'foo'], _file => { - expect(_file('tests/unit/initializers/foo-test.js')) - .to.equal(fixture('initializer-test/default.js')); + expect(_file('tests/unit/initializers/foo-test.js')).to.equal( + fixture('initializer-test/default.js') + ); }); }); @@ -34,8 +35,9 @@ describe('Blueprint: initializer-test', function() { it('initializer-test foo', function() { return emberGenerateDestroy(['initializer-test', 'foo'], _file => { - expect(_file('tests/unit/initializers/foo-test.js')) - .to.equal(fixture('initializer-test/rfc232.js')); + expect(_file('tests/unit/initializers/foo-test.js')).to.equal( + fixture('initializer-test/rfc232.js') + ); }); }); }); @@ -50,8 +52,9 @@ describe('Blueprint: initializer-test', function() { it('initializer-test foo', function() { return emberGenerateDestroy(['initializer-test', 'foo'], _file => { - expect(_file('tests/unit/initializers/foo-test.js')) - .to.equal(fixture('initializer-test/mocha.js')); + expect(_file('tests/unit/initializers/foo-test.js')).to.equal( + fixture('initializer-test/mocha.js') + ); }); }); }); @@ -64,8 +67,9 @@ describe('Blueprint: initializer-test', function() { it('initializer-test foo', function() { return emberGenerateDestroy(['initializer-test', 'foo'], _file => { - expect(_file('tests/unit/initializers/foo-test.js')) - .to.equal(fixture('initializer-test/dummy.js')); + expect(_file('tests/unit/initializers/foo-test.js')).to.equal( + fixture('initializer-test/dummy.js') + ); }); }); }); diff --git a/node-tests/blueprints/initializer-test.js b/node-tests/blueprints/initializer-test.js index 60546bbd6f7..d72afff73d8 100644 --- a/node-tests/blueprints/initializer-test.js +++ b/node-tests/blueprints/initializer-test.js @@ -19,60 +19,69 @@ describe('Blueprint: initializer', function() { it('initializer foo', function() { return emberGenerateDestroy(['initializer', 'foo'], _file => { - expect(_file('app/initializers/foo.js')) - .to.contain("export function initialize(/* application */) {\n" + - " // application.inject('route', 'foo', 'service:foo');\n" + - "}\n" + - "\n" + - "export default {\n" + - " initialize\n" + - "};"); - - expect(_file('tests/unit/initializers/foo-test.js')) - .to.contain("import { initialize } from 'my-app/initializers/foo';"); + expect(_file('app/initializers/foo.js')).to.contain( + 'export function initialize(/* application */) {\n' + + " // application.inject('route', 'foo', 'service:foo');\n" + + '}\n' + + '\n' + + 'export default {\n' + + ' initialize\n' + + '};' + ); + + expect(_file('tests/unit/initializers/foo-test.js')).to.contain( + "import { initialize } from 'my-app/initializers/foo';" + ); }); }); it('initializer foo/bar', function() { return emberGenerateDestroy(['initializer', 'foo/bar'], _file => { - expect(_file('app/initializers/foo/bar.js')) - .to.contain("export function initialize(/* application */) {\n" + - " // application.inject('route', 'foo', 'service:foo');\n" + - "}\n" + - "\n" + - "export default {\n" + - " initialize\n" + - "};"); - - expect(_file('tests/unit/initializers/foo/bar-test.js')) - .to.contain("import { initialize } from 'my-app/initializers/foo/bar';"); + expect(_file('app/initializers/foo/bar.js')).to.contain( + 'export function initialize(/* application */) {\n' + + " // application.inject('route', 'foo', 'service:foo');\n" + + '}\n' + + '\n' + + 'export default {\n' + + ' initialize\n' + + '};' + ); + + expect(_file('tests/unit/initializers/foo/bar-test.js')).to.contain( + "import { initialize } from 'my-app/initializers/foo/bar';" + ); }); }); it('initializer foo --pod', function() { return emberGenerateDestroy(['initializer', 'foo', '--pod'], _file => { - expect(_file('app/initializers/foo.js')) - .to.contain("export function initialize(/* application */) {\n" + - " // application.inject('route', 'foo', 'service:foo');\n" + - "}\n" + - "\n" + - "export default {\n" + - " initialize\n" + - "};"); + expect(_file('app/initializers/foo.js')).to.contain( + 'export function initialize(/* application */) {\n' + + " // application.inject('route', 'foo', 'service:foo');\n" + + '}\n' + + '\n' + + 'export default {\n' + + ' initialize\n' + + '};' + ); }); }); it('initializer foo/bar --pod', function() { - return emberGenerateDestroy(['initializer', 'foo/bar', '--pod'], _file => { - expect(_file('app/initializers/foo/bar.js')) - .to.contain("export function initialize(/* application */) {\n" + - " // application.inject('route', 'foo', 'service:foo');\n" + - "}\n" + - "\n" + - "export default {\n" + - " initialize\n" + - "};"); - }); + return emberGenerateDestroy( + ['initializer', 'foo/bar', '--pod'], + _file => { + expect(_file('app/initializers/foo/bar.js')).to.contain( + 'export function initialize(/* application */) {\n' + + " // application.inject('route', 'foo', 'service:foo');\n" + + '}\n' + + '\n' + + 'export default {\n' + + ' initialize\n' + + '};' + ); + } + ); }); describe('with podModulePrefix', function() { @@ -82,28 +91,33 @@ describe('Blueprint: initializer', function() { it('initializer foo --pod', function() { return emberGenerateDestroy(['initializer', 'foo', '--pod'], _file => { - expect(_file('app/initializers/foo.js')) - .to.contain("export function initialize(/* application */) {\n" + - " // application.inject('route', 'foo', 'service:foo');\n" + - "}\n" + - "\n" + - "export default {\n" + - " initialize\n" + - "};"); + expect(_file('app/initializers/foo.js')).to.contain( + 'export function initialize(/* application */) {\n' + + " // application.inject('route', 'foo', 'service:foo');\n" + + '}\n' + + '\n' + + 'export default {\n' + + ' initialize\n' + + '};' + ); }); }); it('initializer foo/bar --pod', function() { - return emberGenerateDestroy(['initializer', 'foo/bar', '--pod'], _file => { - expect(_file('app/initializers/foo/bar.js')) - .to.contain("export function initialize(/* application */) {\n" + - " // application.inject('route', 'foo', 'service:foo');\n" + - "}\n" + - "\n" + - "export default {\n" + - " initialize\n" + - "};"); - }); + return emberGenerateDestroy( + ['initializer', 'foo/bar', '--pod'], + _file => { + expect(_file('app/initializers/foo/bar.js')).to.contain( + 'export function initialize(/* application */) {\n' + + " // application.inject('route', 'foo', 'service:foo');\n" + + '}\n' + + '\n' + + 'export default {\n' + + ' initialize\n' + + '};' + ); + } + ); }); }); }); @@ -115,78 +129,81 @@ describe('Blueprint: initializer', function() { it('initializer foo', function() { return emberGenerateDestroy(['initializer', 'foo'], _file => { - expect(_file('addon/initializers/foo.js')) - .to.contain("export function initialize(/* application */) {\n" + - " // application.inject('route', 'foo', 'service:foo');\n" + - "}\n" + - "\n" + - "export default {\n" + - " initialize\n" + - "};"); - - expect(_file('app/initializers/foo.js')) - .to.contain("export { default, initialize } from 'my-addon/initializers/foo';"); - - expect(_file('tests/unit/initializers/foo-test.js')) - .to.exist; + expect(_file('addon/initializers/foo.js')).to.contain( + 'export function initialize(/* application */) {\n' + + " // application.inject('route', 'foo', 'service:foo');\n" + + '}\n' + + '\n' + + 'export default {\n' + + ' initialize\n' + + '};' + ); + + expect(_file('app/initializers/foo.js')).to.contain( + "export { default, initialize } from 'my-addon/initializers/foo';" + ); + + expect(_file('tests/unit/initializers/foo-test.js')).to.exist; }); }); it('initializer foo/bar', function() { return emberGenerateDestroy(['initializer', 'foo/bar'], _file => { - expect(_file('addon/initializers/foo/bar.js')) - .to.contain("export function initialize(/* application */) {\n" + - " // application.inject('route', 'foo', 'service:foo');\n" + - "}\n" + - "\n" + - "export default {\n" + - " initialize\n" + - "};"); - - expect(_file('app/initializers/foo/bar.js')) - .to.contain("export { default, initialize } from 'my-addon/initializers/foo/bar';"); - - expect(_file('tests/unit/initializers/foo/bar-test.js')) - .to.exist; + expect(_file('addon/initializers/foo/bar.js')).to.contain( + 'export function initialize(/* application */) {\n' + + " // application.inject('route', 'foo', 'service:foo');\n" + + '}\n' + + '\n' + + 'export default {\n' + + ' initialize\n' + + '};' + ); + + expect(_file('app/initializers/foo/bar.js')).to.contain( + "export { default, initialize } from 'my-addon/initializers/foo/bar';" + ); + + expect(_file('tests/unit/initializers/foo/bar-test.js')).to.exist; }); }); it('initializer foo --dumy', function() { return emberGenerateDestroy(['initializer', 'foo', '--dummy'], _file => { - expect(_file('tests/dummy/app/initializers/foo.js')) - .to.contain("export function initialize(/* application */) {\n" + - " // application.inject('route', 'foo', 'service:foo');\n" + - "}\n" + - "\n" + - "export default {\n" + - " initialize\n" + - "};"); - - expect(_file('app/initializers/foo.js')) - .to.not.exist; - - expect(_file('tests/unit/initializers/foo-test.js')) - .to.not.exist; + expect(_file('tests/dummy/app/initializers/foo.js')).to.contain( + 'export function initialize(/* application */) {\n' + + " // application.inject('route', 'foo', 'service:foo');\n" + + '}\n' + + '\n' + + 'export default {\n' + + ' initialize\n' + + '};' + ); + + expect(_file('app/initializers/foo.js')).to.not.exist; + + expect(_file('tests/unit/initializers/foo-test.js')).to.not.exist; }); }); it('initializer foo/bar --dummy', function() { - return emberGenerateDestroy(['initializer', 'foo/bar', '--dummy'], _file => { - expect(_file('tests/dummy/app/initializers/foo/bar.js')) - .to.contain("export function initialize(/* application */) {\n" + - " // application.inject('route', 'foo', 'service:foo');\n" + - "}\n" + - "\n" + - "export default {\n" + - " initialize\n" + - "};"); - - expect(_file('app/initializers/foo/bar.js')) - .to.not.exist; - - expect(_file('tests/unit/initializers/foo/bar-test.js')) - .to.not.exist; - }); + return emberGenerateDestroy( + ['initializer', 'foo/bar', '--dummy'], + _file => { + expect(_file('tests/dummy/app/initializers/foo/bar.js')).to.contain( + 'export function initialize(/* application */) {\n' + + " // application.inject('route', 'foo', 'service:foo');\n" + + '}\n' + + '\n' + + 'export default {\n' + + ' initialize\n' + + '};' + ); + + expect(_file('app/initializers/foo/bar.js')).to.not.exist; + + expect(_file('tests/unit/initializers/foo/bar-test.js')).to.not.exist; + } + ); }); it('initializer-test foo', function() { @@ -194,11 +211,10 @@ describe('Blueprint: initializer', function() { expect(_file('tests/unit/initializers/foo-test.js')) .to.contain("import { initialize } from 'dummy/initializers/foo';") .to.contain("module('Unit | Initializer | foo'") - .to.contain("application = Application.create();") - .to.contain("initialize(this.application);"); + .to.contain('application = Application.create();') + .to.contain('initialize(this.application);'); }); }); - }); describe('in in-repo-addon', function() { @@ -207,41 +223,51 @@ describe('Blueprint: initializer', function() { }); it('initializer foo --in-repo-addon=my-addon', function() { - return emberGenerateDestroy(['initializer', 'foo', '--in-repo-addon=my-addon'], _file => { - expect(_file('lib/my-addon/addon/initializers/foo.js')) - .to.contain("export function initialize(/* application */) {\n" + - " // application.inject('route', 'foo', 'service:foo');\n" + - "}\n" + - "\n" + - "export default {\n" + - " initialize\n" + - "};"); - - expect(_file('lib/my-addon/app/initializers/foo.js')) - .to.contain("export { default, initialize } from 'my-addon/initializers/foo';"); - - expect(_file('tests/unit/initializers/foo-test.js')) - .to.exist; - }); + return emberGenerateDestroy( + ['initializer', 'foo', '--in-repo-addon=my-addon'], + _file => { + expect(_file('lib/my-addon/addon/initializers/foo.js')).to.contain( + 'export function initialize(/* application */) {\n' + + " // application.inject('route', 'foo', 'service:foo');\n" + + '}\n' + + '\n' + + 'export default {\n' + + ' initialize\n' + + '};' + ); + + expect(_file('lib/my-addon/app/initializers/foo.js')).to.contain( + "export { default, initialize } from 'my-addon/initializers/foo';" + ); + + expect(_file('tests/unit/initializers/foo-test.js')).to.exist; + } + ); }); it('initializer foo/bar --in-repo-addon=my-addon', function() { - return emberGenerateDestroy(['initializer', 'foo/bar', '--in-repo-addon=my-addon'], _file => { - expect(_file('lib/my-addon/addon/initializers/foo/bar.js')) - .to.contain("export function initialize(/* application */) {\n" + - " // application.inject('route', 'foo', 'service:foo');\n" + - "}\n" + - "\n" + - "export default {\n" + - " initialize\n" + - "};"); - - expect(_file('lib/my-addon/app/initializers/foo/bar.js')) - .to.contain("export { default, initialize } from 'my-addon/initializers/foo/bar';"); - - expect(_file('tests/unit/initializers/foo/bar-test.js')) - .to.exist; - }); + return emberGenerateDestroy( + ['initializer', 'foo/bar', '--in-repo-addon=my-addon'], + _file => { + expect( + _file('lib/my-addon/addon/initializers/foo/bar.js') + ).to.contain( + 'export function initialize(/* application */) {\n' + + " // application.inject('route', 'foo', 'service:foo');\n" + + '}\n' + + '\n' + + 'export default {\n' + + ' initialize\n' + + '};' + ); + + expect(_file('lib/my-addon/app/initializers/foo/bar.js')).to.contain( + "export { default, initialize } from 'my-addon/initializers/foo/bar';" + ); + + expect(_file('tests/unit/initializers/foo/bar-test.js')).to.exist; + } + ); }); }); }); diff --git a/node-tests/blueprints/instance-initializer-addon-test.js b/node-tests/blueprints/instance-initializer-addon-test.js index 7df68363b6c..f32a8484852 100644 --- a/node-tests/blueprints/instance-initializer-addon-test.js +++ b/node-tests/blueprints/instance-initializer-addon-test.js @@ -17,17 +17,25 @@ describe('Blueprint: instance-initializer-addon', function() { }); it('instance-initializer-addon foo', function() { - return emberGenerateDestroy(['instance-initializer-addon', 'foo'], _file => { - expect(_file('app/instance-initializers/foo.js')) - .to.contain("export { default, initialize } from 'my-addon/instance-initializers/foo';"); - }); + return emberGenerateDestroy( + ['instance-initializer-addon', 'foo'], + _file => { + expect(_file('app/instance-initializers/foo.js')).to.contain( + "export { default, initialize } from 'my-addon/instance-initializers/foo';" + ); + } + ); }); it('instance-initializer-addon foo --pod', function() { - return emberGenerateDestroy(['instance-initializer-addon', 'foo', '--pod'], _file => { - expect(_file('app/instance-initializers/foo.js')) - .to.contain("export { default, initialize } from 'my-addon/instance-initializers/foo';"); - }); + return emberGenerateDestroy( + ['instance-initializer-addon', 'foo', '--pod'], + _file => { + expect(_file('app/instance-initializers/foo.js')).to.contain( + "export { default, initialize } from 'my-addon/instance-initializers/foo';" + ); + } + ); }); }); }); diff --git a/node-tests/blueprints/instance-initializer-test-test.js b/node-tests/blueprints/instance-initializer-test-test.js index 01c31cbeaab..da3d5f5d013 100644 --- a/node-tests/blueprints/instance-initializer-test-test.js +++ b/node-tests/blueprints/instance-initializer-test-test.js @@ -21,10 +21,14 @@ describe('Blueprint: instance-initializer-test', function() { }); it('instance-initializer-test foo', function() { - return emberGenerateDestroy(['instance-initializer-test', 'foo'], _file => { - expect(_file('tests/unit/instance-initializers/foo-test.js')) - .to.equal(fixture('instance-initializer-test/default.js')); - }); + return emberGenerateDestroy( + ['instance-initializer-test', 'foo'], + _file => { + expect( + _file('tests/unit/instance-initializers/foo-test.js') + ).to.equal(fixture('instance-initializer-test/default.js')); + } + ); }); describe('with ember-cli-qunit@4.2.0', function() { @@ -33,10 +37,14 @@ describe('Blueprint: instance-initializer-test', function() { }); it('instance-initializer-test foo', function() { - return emberGenerateDestroy(['instance-initializer-test', 'foo'], _file => { - expect(_file('tests/unit/instance-initializers/foo-test.js')) - .to.equal(fixture('instance-initializer-test/rfc232.js')); - }); + return emberGenerateDestroy( + ['instance-initializer-test', 'foo'], + _file => { + expect( + _file('tests/unit/instance-initializers/foo-test.js') + ).to.equal(fixture('instance-initializer-test/rfc232.js')); + } + ); }); }); @@ -49,10 +57,14 @@ describe('Blueprint: instance-initializer-test', function() { }); it('instance-initializer-test foo for mocha', function() { - return emberGenerateDestroy(['instance-initializer-test', 'foo'], _file => { - expect(_file('tests/unit/instance-initializers/foo-test.js')) - .to.equal(fixture('instance-initializer-test/mocha.js')); - }); + return emberGenerateDestroy( + ['instance-initializer-test', 'foo'], + _file => { + expect( + _file('tests/unit/instance-initializers/foo-test.js') + ).to.equal(fixture('instance-initializer-test/mocha.js')); + } + ); }); }); }); @@ -63,10 +75,14 @@ describe('Blueprint: instance-initializer-test', function() { }); it('instance-initializer-test foo', function() { - return emberGenerateDestroy(['instance-initializer-test', 'foo'], _file => { - expect(_file('tests/unit/instance-initializers/foo-test.js')) - .to.equal(fixture('instance-initializer-test/dummy.js')); - }); + return emberGenerateDestroy( + ['instance-initializer-test', 'foo'], + _file => { + expect( + _file('tests/unit/instance-initializers/foo-test.js') + ).to.equal(fixture('instance-initializer-test/dummy.js')); + } + ); }); }); }); diff --git a/node-tests/blueprints/instance-initializer-test.js b/node-tests/blueprints/instance-initializer-test.js index ef6bc2f5cdc..44deab80e17 100644 --- a/node-tests/blueprints/instance-initializer-test.js +++ b/node-tests/blueprints/instance-initializer-test.js @@ -19,60 +19,79 @@ describe('Blueprint: instance-initializer', function() { it('instance-initializer foo', function() { return emberGenerateDestroy(['instance-initializer', 'foo'], _file => { - expect(_file('app/instance-initializers/foo.js')) - .to.contain("export function initialize(/* appInstance */) {\n" + - " // appInstance.inject('route', 'foo', 'service:foo');\n" + - "}\n" + - "\n" + - "export default {\n" + - " initialize\n" + - "};"); - - expect(_file('tests/unit/instance-initializers/foo-test.js')) - .to.contain("import { initialize } from 'my-app/instance-initializers/foo';"); + expect(_file('app/instance-initializers/foo.js')).to.contain( + 'export function initialize(/* appInstance */) {\n' + + " // appInstance.inject('route', 'foo', 'service:foo');\n" + + '}\n' + + '\n' + + 'export default {\n' + + ' initialize\n' + + '};' + ); + + expect( + _file('tests/unit/instance-initializers/foo-test.js') + ).to.contain( + "import { initialize } from 'my-app/instance-initializers/foo';" + ); }); }); it('instance-initializer foo/bar', function() { - return emberGenerateDestroy(['instance-initializer', 'foo/bar'], _file => { - expect(_file('app/instance-initializers/foo/bar.js')) - .to.contain("export function initialize(/* appInstance */) {\n" + - " // appInstance.inject('route', 'foo', 'service:foo');\n" + - "}\n" + - "\n" + - "export default {\n" + - " initialize\n" + - "};"); - - expect(_file('tests/unit/instance-initializers/foo/bar-test.js')) - .to.contain("import { initialize } from 'my-app/instance-initializers/foo/bar';"); - }); + return emberGenerateDestroy( + ['instance-initializer', 'foo/bar'], + _file => { + expect(_file('app/instance-initializers/foo/bar.js')).to.contain( + 'export function initialize(/* appInstance */) {\n' + + " // appInstance.inject('route', 'foo', 'service:foo');\n" + + '}\n' + + '\n' + + 'export default {\n' + + ' initialize\n' + + '};' + ); + + expect( + _file('tests/unit/instance-initializers/foo/bar-test.js') + ).to.contain( + "import { initialize } from 'my-app/instance-initializers/foo/bar';" + ); + } + ); }); it('instance-initializer foo --pod', function() { - return emberGenerateDestroy(['instance-initializer', 'foo', '--pod'], _file => { - expect(_file('app/instance-initializers/foo.js')) - .to.contain("export function initialize(/* appInstance */) {\n" + - " // appInstance.inject('route', 'foo', 'service:foo');\n" + - "}\n" + - "\n" + - "export default {\n" + - " initialize\n" + - "};"); - }); + return emberGenerateDestroy( + ['instance-initializer', 'foo', '--pod'], + _file => { + expect(_file('app/instance-initializers/foo.js')).to.contain( + 'export function initialize(/* appInstance */) {\n' + + " // appInstance.inject('route', 'foo', 'service:foo');\n" + + '}\n' + + '\n' + + 'export default {\n' + + ' initialize\n' + + '};' + ); + } + ); }); it('instance-initializer foo/bar --pod', function() { - return emberGenerateDestroy(['instance-initializer', 'foo/bar', '--pod'], _file => { - expect(_file('app/instance-initializers/foo/bar.js')) - .to.contain("export function initialize(/* appInstance */) {\n" + - " // appInstance.inject('route', 'foo', 'service:foo');\n" + - "}\n" + - "\n" + - "export default {\n" + - " initialize\n" + - "};"); - }); + return emberGenerateDestroy( + ['instance-initializer', 'foo/bar', '--pod'], + _file => { + expect(_file('app/instance-initializers/foo/bar.js')).to.contain( + 'export function initialize(/* appInstance */) {\n' + + " // appInstance.inject('route', 'foo', 'service:foo');\n" + + '}\n' + + '\n' + + 'export default {\n' + + ' initialize\n' + + '};' + ); + } + ); }); describe('with podModulePrefix', function() { @@ -81,29 +100,37 @@ describe('Blueprint: instance-initializer', function() { }); it('instance-initializer foo --pod', function() { - return emberGenerateDestroy(['instance-initializer', 'foo', '--pod'], _file => { - expect(_file('app/instance-initializers/foo.js')) - .to.contain("export function initialize(/* appInstance */) {\n" + - " // appInstance.inject('route', 'foo', 'service:foo');\n" + - "}\n" + - "\n" + - "export default {\n" + - " initialize\n" + - "};"); - }); + return emberGenerateDestroy( + ['instance-initializer', 'foo', '--pod'], + _file => { + expect(_file('app/instance-initializers/foo.js')).to.contain( + 'export function initialize(/* appInstance */) {\n' + + " // appInstance.inject('route', 'foo', 'service:foo');\n" + + '}\n' + + '\n' + + 'export default {\n' + + ' initialize\n' + + '};' + ); + } + ); }); it('instance-initializer foo/bar --pod', function() { - return emberGenerateDestroy(['instance-initializer', 'foo/bar', '--pod'], _file => { - expect(_file('app/instance-initializers/foo/bar.js')) - .to.contain("export function initialize(/* appInstance */) {\n" + - " // appInstance.inject('route', 'foo', 'service:foo');\n" + - "}\n" + - "\n" + - "export default {\n" + - " initialize\n" + - "};"); - }); + return emberGenerateDestroy( + ['instance-initializer', 'foo/bar', '--pod'], + _file => { + expect(_file('app/instance-initializers/foo/bar.js')).to.contain( + 'export function initialize(/* appInstance */) {\n' + + " // appInstance.inject('route', 'foo', 'service:foo');\n" + + '}\n' + + '\n' + + 'export default {\n' + + ' initialize\n' + + '};' + ); + } + ); }); }); }); @@ -115,76 +142,93 @@ describe('Blueprint: instance-initializer', function() { it('instance-initializer foo', function() { return emberGenerateDestroy(['instance-initializer', 'foo'], _file => { - expect(_file('addon/instance-initializers/foo.js')) - .to.contain("export function initialize(/* appInstance */) {\n" + - " // appInstance.inject('route', 'foo', 'service:foo');\n" + - "}\n" + - "\n" + - "export default {\n" + - " initialize\n" + - "};"); - - expect(_file('app/instance-initializers/foo.js')) - .to.contain("export { default, initialize } from 'my-addon/instance-initializers/foo';"); + expect(_file('addon/instance-initializers/foo.js')).to.contain( + 'export function initialize(/* appInstance */) {\n' + + " // appInstance.inject('route', 'foo', 'service:foo');\n" + + '}\n' + + '\n' + + 'export default {\n' + + ' initialize\n' + + '};' + ); + + expect(_file('app/instance-initializers/foo.js')).to.contain( + "export { default, initialize } from 'my-addon/instance-initializers/foo';" + ); expect(_file('tests/unit/instance-initializers/foo-test.js')); }); }); it('instance-initializer foo/bar', function() { - return emberGenerateDestroy(['instance-initializer', 'foo/bar'], _file => { - expect(_file('addon/instance-initializers/foo/bar.js')) - .to.contain("export function initialize(/* appInstance */) {\n" + - " // appInstance.inject('route', 'foo', 'service:foo');\n" + - "}\n" + - "\n" + - "export default {\n" + - " initialize\n" + - "};"); - - expect(_file('app/instance-initializers/foo/bar.js')) - .to.contain("export { default, initialize } from 'my-addon/instance-initializers/foo/bar';"); - - expect(_file('tests/unit/instance-initializers/foo/bar-test.js')); - }); + return emberGenerateDestroy( + ['instance-initializer', 'foo/bar'], + _file => { + expect(_file('addon/instance-initializers/foo/bar.js')).to.contain( + 'export function initialize(/* appInstance */) {\n' + + " // appInstance.inject('route', 'foo', 'service:foo');\n" + + '}\n' + + '\n' + + 'export default {\n' + + ' initialize\n' + + '};' + ); + + expect(_file('app/instance-initializers/foo/bar.js')).to.contain( + "export { default, initialize } from 'my-addon/instance-initializers/foo/bar';" + ); + + expect(_file('tests/unit/instance-initializers/foo/bar-test.js')); + } + ); }); it('instance-initializer foo --dummy', function() { - return emberGenerateDestroy(['instance-initializer', 'foo', '--dummy'], _file => { - expect(_file('tests/dummy/app/instance-initializers/foo.js')) - .to.contain("export function initialize(/* appInstance */) {\n" + - " // appInstance.inject('route', 'foo', 'service:foo');\n" + - "}\n" + - "\n" + - "export default {\n" + - " initialize\n" + - "};"); - - expect(_file('app/instance-initializers/foo.js')) - .to.not.exist; - - expect(_file('tests/unit/instance-initializers/foo-test.js')) - .to.not.exist; - }); + return emberGenerateDestroy( + ['instance-initializer', 'foo', '--dummy'], + _file => { + expect( + _file('tests/dummy/app/instance-initializers/foo.js') + ).to.contain( + 'export function initialize(/* appInstance */) {\n' + + " // appInstance.inject('route', 'foo', 'service:foo');\n" + + '}\n' + + '\n' + + 'export default {\n' + + ' initialize\n' + + '};' + ); + + expect(_file('app/instance-initializers/foo.js')).to.not.exist; + + expect(_file('tests/unit/instance-initializers/foo-test.js')).to.not + .exist; + } + ); }); it('instance-initializer foo/bar --dummy', function() { - return emberGenerateDestroy(['instance-initializer', 'foo/bar', '--dummy'], _file => { - expect(_file('tests/dummy/app/instance-initializers/foo/bar.js')) - .to.contain("export function initialize(/* appInstance */) {\n" + - " // appInstance.inject('route', 'foo', 'service:foo');\n" + - "}\n" + - "\n" + - "export default {\n" + - " initialize\n" + - "};"); - - expect(_file('app/instance-initializers/foo/bar.js')) - .to.not.exist; - - expect(_file('tests/unit/instance-initializers/foo/bar-test.js')) - .to.not.exist; - }); + return emberGenerateDestroy( + ['instance-initializer', 'foo/bar', '--dummy'], + _file => { + expect( + _file('tests/dummy/app/instance-initializers/foo/bar.js') + ).to.contain( + 'export function initialize(/* appInstance */) {\n' + + " // appInstance.inject('route', 'foo', 'service:foo');\n" + + '}\n' + + '\n' + + 'export default {\n' + + ' initialize\n' + + '};' + ); + + expect(_file('app/instance-initializers/foo/bar.js')).to.not.exist; + + expect(_file('tests/unit/instance-initializers/foo/bar-test.js')).to + .not.exist; + } + ); }); }); @@ -194,41 +238,59 @@ describe('Blueprint: instance-initializer', function() { }); it('instance-initializer foo --in-repo-addon=my-addon', function() { - return emberGenerateDestroy(['instance-initializer', 'foo', '--in-repo-addon=my-addon'], _file => { - expect(_file('lib/my-addon/addon/instance-initializers/foo.js')) - .to.contain("export function initialize(/* appInstance */) {\n" + - " // appInstance.inject('route', 'foo', 'service:foo');\n" + - "}\n" + - "\n" + - "export default {\n" + - " initialize\n" + - "};"); - - expect(_file('lib/my-addon/app/instance-initializers/foo.js')) - .to.contain("export { default, initialize } from 'my-addon/instance-initializers/foo';"); - - expect(_file('tests/unit/instance-initializers/foo-test.js')) - .to.exist; - }); + return emberGenerateDestroy( + ['instance-initializer', 'foo', '--in-repo-addon=my-addon'], + _file => { + expect( + _file('lib/my-addon/addon/instance-initializers/foo.js') + ).to.contain( + 'export function initialize(/* appInstance */) {\n' + + " // appInstance.inject('route', 'foo', 'service:foo');\n" + + '}\n' + + '\n' + + 'export default {\n' + + ' initialize\n' + + '};' + ); + + expect( + _file('lib/my-addon/app/instance-initializers/foo.js') + ).to.contain( + "export { default, initialize } from 'my-addon/instance-initializers/foo';" + ); + + expect(_file('tests/unit/instance-initializers/foo-test.js')).to + .exist; + } + ); }); it('instance-initializer foo/bar --in-repo-addon=my-addon', function() { - return emberGenerateDestroy(['instance-initializer', 'foo/bar', '--in-repo-addon=my-addon'], _file => { - expect(_file('lib/my-addon/addon/instance-initializers/foo/bar.js')) - .to.contain("export function initialize(/* appInstance */) {\n" + - " // appInstance.inject('route', 'foo', 'service:foo');\n" + - "}\n" + - "\n" + - "export default {\n" + - " initialize\n" + - "};"); - - expect(_file('lib/my-addon/app/instance-initializers/foo/bar.js')) - .to.contain("export { default, initialize } from 'my-addon/instance-initializers/foo/bar';"); - - expect(_file('tests/unit/instance-initializers/foo/bar-test.js')) - .to.exist; - }); + return emberGenerateDestroy( + ['instance-initializer', 'foo/bar', '--in-repo-addon=my-addon'], + _file => { + expect( + _file('lib/my-addon/addon/instance-initializers/foo/bar.js') + ).to.contain( + 'export function initialize(/* appInstance */) {\n' + + " // appInstance.inject('route', 'foo', 'service:foo');\n" + + '}\n' + + '\n' + + 'export default {\n' + + ' initialize\n' + + '};' + ); + + expect( + _file('lib/my-addon/app/instance-initializers/foo/bar.js') + ).to.contain( + "export { default, initialize } from 'my-addon/instance-initializers/foo/bar';" + ); + + expect(_file('tests/unit/instance-initializers/foo/bar-test.js')).to + .exist; + } + ); }); }); }); diff --git a/node-tests/blueprints/mixin-test-test.js b/node-tests/blueprints/mixin-test-test.js index be0bbbb28ac..82dc66f1dcf 100644 --- a/node-tests/blueprints/mixin-test-test.js +++ b/node-tests/blueprints/mixin-test-test.js @@ -22,8 +22,9 @@ describe('Blueprint: mixin-test', function() { it('mixin-test foo', function() { return emberGenerateDestroy(['mixin-test', 'foo'], _file => { - expect(_file('tests/unit/mixins/foo-test.js')) - .to.equal(fixture('mixin-test/default.js')); + expect(_file('tests/unit/mixins/foo-test.js')).to.equal( + fixture('mixin-test/default.js') + ); }); }); @@ -37,8 +38,9 @@ describe('Blueprint: mixin-test', function() { it('mixin-test foo', function() { return emberGenerateDestroy(['mixin-test', 'foo'], _file => { - expect(_file('tests/unit/mixins/foo-test.js')) - .to.equal(fixture('mixin-test/mocha.js')); + expect(_file('tests/unit/mixins/foo-test.js')).to.equal( + fixture('mixin-test/mocha.js') + ); }); }); }); @@ -50,8 +52,9 @@ describe('Blueprint: mixin-test', function() { it('mixin-test foo', function() { return emberGenerateDestroy(['mixin-test', 'foo'], _file => { - expect(_file('tests/unit/mixins/foo-test.js')) - .to.equal(fixture('mixin-test/rfc232.js')); + expect(_file('tests/unit/mixins/foo-test.js')).to.equal( + fixture('mixin-test/rfc232.js') + ); }); }); }); @@ -64,8 +67,9 @@ describe('Blueprint: mixin-test', function() { it('mixin-test foo', function() { return emberGenerateDestroy(['mixin-test', 'foo'], _file => { - expect(_file('tests/unit/mixins/foo-test.js')) - .to.equal(fixture('mixin-test/addon.js')); + expect(_file('tests/unit/mixins/foo-test.js')).to.equal( + fixture('mixin-test/addon.js') + ); }); }); }); diff --git a/node-tests/blueprints/mixin-test.js b/node-tests/blueprints/mixin-test.js index 228c7f39c2d..4f5a887d4f8 100644 --- a/node-tests/blueprints/mixin-test.js +++ b/node-tests/blueprints/mixin-test.js @@ -20,58 +20,64 @@ describe('Blueprint: mixin', function() { it('mixin foo', function() { return emberGenerateDestroy(['mixin', 'foo'], _file => { expect(_file('app/mixins/foo.js')) - .to.contain('import Mixin from \'@ember/object/mixin\';') + .to.contain("import Mixin from '@ember/object/mixin';") .to.contain('export default Mixin.create({\n});'); - expect(_file('tests/unit/mixins/foo-test.js')) - .to.contain("import FooMixin from 'my-app/mixins/foo';"); + expect(_file('tests/unit/mixins/foo-test.js')).to.contain( + "import FooMixin from 'my-app/mixins/foo';" + ); }); }); it('mixin foo/bar', function() { return emberGenerateDestroy(['mixin', 'foo/bar'], _file => { expect(_file('app/mixins/foo/bar.js')) - .to.contain('import Mixin from \'@ember/object/mixin\';') + .to.contain("import Mixin from '@ember/object/mixin';") .to.contain('export default Mixin.create({\n});'); - expect(_file('tests/unit/mixins/foo/bar-test.js')) - .to.contain("import FooBarMixin from 'my-app/mixins/foo/bar';"); + expect(_file('tests/unit/mixins/foo/bar-test.js')).to.contain( + "import FooBarMixin from 'my-app/mixins/foo/bar';" + ); }); }); it('mixin foo/bar/baz', function() { return emberGenerateDestroy(['mixin', 'foo/bar/baz'], _file => { - expect(_file('tests/unit/mixins/foo/bar/baz-test.js')) - .to.contain("import FooBarBazMixin from 'my-app/mixins/foo/bar/baz';"); + expect(_file('tests/unit/mixins/foo/bar/baz-test.js')).to.contain( + "import FooBarBazMixin from 'my-app/mixins/foo/bar/baz';" + ); }); }); it('mixin foo --pod', function() { return emberGenerateDestroy(['mixin', 'foo', '--pod'], _file => { expect(_file('app/mixins/foo.js')) - .to.contain('import Mixin from \'@ember/object/mixin\';') + .to.contain("import Mixin from '@ember/object/mixin';") .to.contain('export default Mixin.create({\n});'); - expect(_file('tests/unit/mixins/foo-test.js')) - .to.contain("import FooMixin from 'my-app/mixins/foo';"); + expect(_file('tests/unit/mixins/foo-test.js')).to.contain( + "import FooMixin from 'my-app/mixins/foo';" + ); }); }); it('mixin foo/bar --pod', function() { return emberGenerateDestroy(['mixin', 'foo/bar', '--pod'], _file => { expect(_file('app/mixins/foo/bar.js')) - .to.contain('import Mixin from \'@ember/object/mixin\';') + .to.contain("import Mixin from '@ember/object/mixin';") .to.contain('export default Mixin.create({\n});'); - expect(_file('tests/unit/mixins/foo/bar-test.js')) - .to.contain("import FooBarMixin from 'my-app/mixins/foo/bar';"); + expect(_file('tests/unit/mixins/foo/bar-test.js')).to.contain( + "import FooBarMixin from 'my-app/mixins/foo/bar';" + ); }); }); it('mixin foo/bar/baz --pod', function() { return emberGenerateDestroy(['mixin', 'foo/bar/baz', '--pod'], _file => { - expect(_file('tests/unit/mixins/foo/bar/baz-test.js')) - .to.contain("import FooBarBazMixin from 'my-app/mixins/foo/bar/baz';"); + expect(_file('tests/unit/mixins/foo/bar/baz-test.js')).to.contain( + "import FooBarBazMixin from 'my-app/mixins/foo/bar/baz';" + ); }); }); @@ -83,22 +89,24 @@ describe('Blueprint: mixin', function() { it('mixin foo --pod', function() { return emberGenerateDestroy(['mixin', 'foo', '--pod'], _file => { expect(_file('app/mixins/foo.js')) - .to.contain('import Mixin from \'@ember/object/mixin\';') + .to.contain("import Mixin from '@ember/object/mixin';") .to.contain('export default Mixin.create({\n});'); - expect(_file('tests/unit/mixins/foo-test.js')) - .to.contain("import FooMixin from 'my-app/mixins/foo';"); + expect(_file('tests/unit/mixins/foo-test.js')).to.contain( + "import FooMixin from 'my-app/mixins/foo';" + ); }); }); it('mixin foo/bar --pod', function() { return emberGenerateDestroy(['mixin', 'foo/bar', '--pod'], _file => { expect(_file('app/mixins/foo/bar.js')) - .to.contain('import Mixin from \'@ember/object/mixin\';') + .to.contain("import Mixin from '@ember/object/mixin';") .to.contain('export default Mixin.create({\n});'); - expect(_file('tests/unit/mixins/foo/bar-test.js')) - .to.contain("import FooBarMixin from 'my-app/mixins/foo/bar';"); + expect(_file('tests/unit/mixins/foo/bar-test.js')).to.contain( + "import FooBarMixin from 'my-app/mixins/foo/bar';" + ); }); }); }); @@ -112,42 +120,42 @@ describe('Blueprint: mixin', function() { it('mixin foo', function() { return emberGenerateDestroy(['mixin', 'foo'], _file => { expect(_file('addon/mixins/foo.js')) - .to.contain('import Mixin from \'@ember/object/mixin\';') + .to.contain("import Mixin from '@ember/object/mixin';") .to.contain('export default Mixin.create({\n});'); - expect(_file('tests/unit/mixins/foo-test.js')) - .to.contain("import FooMixin from 'my-addon/mixins/foo';"); + expect(_file('tests/unit/mixins/foo-test.js')).to.contain( + "import FooMixin from 'my-addon/mixins/foo';" + ); - expect(_file('app/mixins/foo.js')) - .to.not.exist; + expect(_file('app/mixins/foo.js')).to.not.exist; }); }); it('mixin foo/bar', function() { return emberGenerateDestroy(['mixin', 'foo/bar'], _file => { expect(_file('addon/mixins/foo/bar.js')) - .to.contain('import Mixin from \'@ember/object/mixin\';') + .to.contain("import Mixin from '@ember/object/mixin';") .to.contain('export default Mixin.create({\n});'); - expect(_file('tests/unit/mixins/foo/bar-test.js')) - .to.contain("import FooBarMixin from 'my-addon/mixins/foo/bar';"); + expect(_file('tests/unit/mixins/foo/bar-test.js')).to.contain( + "import FooBarMixin from 'my-addon/mixins/foo/bar';" + ); - expect(_file('app/mixins/foo/bar.js')) - .to.not.exist; + expect(_file('app/mixins/foo/bar.js')).to.not.exist; }); }); it('mixin foo/bar/baz', function() { return emberGenerateDestroy(['mixin', 'foo/bar/baz'], _file => { expect(_file('addon/mixins/foo/bar/baz.js')) - .to.contain('import Mixin from \'@ember/object/mixin\';') + .to.contain("import Mixin from '@ember/object/mixin';") .to.contain('export default Mixin.create({\n});'); - expect(_file('tests/unit/mixins/foo/bar/baz-test.js')) - .to.contain("import FooBarBazMixin from 'my-addon/mixins/foo/bar/baz';"); + expect(_file('tests/unit/mixins/foo/bar/baz-test.js')).to.contain( + "import FooBarBazMixin from 'my-addon/mixins/foo/bar/baz';" + ); - expect(_file('app/mixins/foo/bar/baz.js')) - .to.not.exist; + expect(_file('app/mixins/foo/bar/baz.js')).to.not.exist; }); }); }); @@ -158,32 +166,44 @@ describe('Blueprint: mixin', function() { }); it('mixin foo --in-repo-addon=my-addon', function() { - return emberGenerateDestroy(['mixin', 'foo', '--in-repo-addon=my-addon'], _file => { - expect(_file('lib/my-addon/addon/mixins/foo.js')) - .to.contain('import Mixin from \'@ember/object/mixin\';') - .to.contain('export default Mixin.create({\n});'); + return emberGenerateDestroy( + ['mixin', 'foo', '--in-repo-addon=my-addon'], + _file => { + expect(_file('lib/my-addon/addon/mixins/foo.js')) + .to.contain("import Mixin from '@ember/object/mixin';") + .to.contain('export default Mixin.create({\n});'); - expect(_file('tests/unit/mixins/foo-test.js')) - .to.contain("import FooMixin from 'my-addon/mixins/foo';"); - }); + expect(_file('tests/unit/mixins/foo-test.js')).to.contain( + "import FooMixin from 'my-addon/mixins/foo';" + ); + } + ); }); it('mixin foo/bar --in-repo-addon=my-addon', function() { - return emberGenerateDestroy(['mixin', 'foo/bar', '--in-repo-addon=my-addon'], _file => { - expect(_file('lib/my-addon/addon/mixins/foo/bar.js')) - .to.contain('import Mixin from \'@ember/object/mixin\';') - .to.contain('export default Mixin.create({\n});'); + return emberGenerateDestroy( + ['mixin', 'foo/bar', '--in-repo-addon=my-addon'], + _file => { + expect(_file('lib/my-addon/addon/mixins/foo/bar.js')) + .to.contain("import Mixin from '@ember/object/mixin';") + .to.contain('export default Mixin.create({\n});'); - expect(_file('tests/unit/mixins/foo/bar-test.js')) - .to.contain("import FooBarMixin from 'my-addon/mixins/foo/bar';"); - }); + expect(_file('tests/unit/mixins/foo/bar-test.js')).to.contain( + "import FooBarMixin from 'my-addon/mixins/foo/bar';" + ); + } + ); }); it('mixin foo/bar/baz --in-repo-addon=my-addon', function() { - return emberGenerateDestroy(['mixin', 'foo/bar/baz', '--in-repo-addon=my-addon'], _file => { - expect(_file('tests/unit/mixins/foo/bar/baz-test.js')) - .to.contain("import FooBarBazMixin from 'my-addon/mixins/foo/bar/baz';"); - }); + return emberGenerateDestroy( + ['mixin', 'foo/bar/baz', '--in-repo-addon=my-addon'], + _file => { + expect(_file('tests/unit/mixins/foo/bar/baz-test.js')).to.contain( + "import FooBarBazMixin from 'my-addon/mixins/foo/bar/baz';" + ); + } + ); }); }); }); diff --git a/node-tests/blueprints/route-addon-test.js b/node-tests/blueprints/route-addon-test.js index 8a47272bc5e..3086d38e797 100644 --- a/node-tests/blueprints/route-addon-test.js +++ b/node-tests/blueprints/route-addon-test.js @@ -18,11 +18,13 @@ describe('Blueprint: route-addon', function() { it('route-addon foo', function() { return emberGenerateDestroy(['route-addon', 'foo'], _file => { - expect(_file('app/routes/foo.js')) - .to.contain("export { default } from 'my-addon/routes/foo';"); + expect(_file('app/routes/foo.js')).to.contain( + "export { default } from 'my-addon/routes/foo';" + ); - expect(_file('app/templates/foo.js')) - .to.contain("export { default } from 'my-addon/templates/foo';"); + expect(_file('app/templates/foo.js')).to.contain( + "export { default } from 'my-addon/templates/foo';" + ); }); }); }); diff --git a/node-tests/blueprints/route-test-test.js b/node-tests/blueprints/route-test-test.js index ef64f0484ec..e316ac08c86 100644 --- a/node-tests/blueprints/route-test-test.js +++ b/node-tests/blueprints/route-test-test.js @@ -21,9 +21,10 @@ describe('Blueprint: route-test', function() { }); it('route-test foo', function() { - return emberGenerateDestroy(['route-test', 'foo'], (_file) => { - expect(_file('tests/unit/routes/foo-test.js')) - .to.equal(fixture('route-test/default.js')); + return emberGenerateDestroy(['route-test', 'foo'], _file => { + expect(_file('tests/unit/routes/foo-test.js')).to.equal( + fixture('route-test/default.js') + ); }); }); @@ -33,9 +34,10 @@ describe('Blueprint: route-test', function() { }); it('route-test foo', function() { - return emberGenerateDestroy(['route-test', 'foo'], (_file) => { - expect(_file('tests/unit/routes/foo-test.js')) - .to.equal(fixture('route-test/rfc232.js')); + return emberGenerateDestroy(['route-test', 'foo'], _file => { + expect(_file('tests/unit/routes/foo-test.js')).to.equal( + fixture('route-test/rfc232.js') + ); }); }); }); @@ -50,9 +52,10 @@ describe('Blueprint: route-test', function() { }); it('route-test foo', function() { - return emberGenerateDestroy(['route-test', 'foo'], (_file) => { - expect(_file('tests/unit/routes/foo-test.js')) - .to.equal(fixture('route-test/mocha.js')); + return emberGenerateDestroy(['route-test', 'foo'], _file => { + expect(_file('tests/unit/routes/foo-test.js')).to.equal( + fixture('route-test/mocha.js') + ); }); }); }); @@ -67,9 +70,10 @@ describe('Blueprint: route-test', function() { }); it('route-test foo', function() { - return emberGenerateDestroy(['route-test', 'foo'], (_file) => { - expect(_file('tests/unit/routes/foo-test.js')) - .to.equal(fixture('route-test/mocha-0.12.js')); + return emberGenerateDestroy(['route-test', 'foo'], _file => { + expect(_file('tests/unit/routes/foo-test.js')).to.equal( + fixture('route-test/mocha-0.12.js') + ); }); }); }); @@ -81,9 +85,10 @@ describe('Blueprint: route-test', function() { }); it('route-test foo', function() { - return emberGenerateDestroy(['route-test', 'foo'], (_file) => { - expect(_file('tests/unit/routes/foo-test.js')) - .to.equal(fixture('route-test/default.js')); + return emberGenerateDestroy(['route-test', 'foo'], _file => { + expect(_file('tests/unit/routes/foo-test.js')).to.equal( + fixture('route-test/default.js') + ); }); }); }); diff --git a/node-tests/blueprints/route-test.js b/node-tests/blueprints/route-test.js index 8d5db973853..e96c2476a90 100644 --- a/node-tests/blueprints/route-test.js +++ b/node-tests/blueprints/route-test.js @@ -22,186 +22,193 @@ describe('Blueprint: route', function() { }); it('route foo', function() { - return emberGenerateDestroy(['route', 'foo'], (_file) => { - expect(_file('app/routes/foo.js')) - .to.contain('import Route from \'@ember/routing/route\';') - .to.contain('export default Route.extend({\n});'); + return emberGenerateDestroy(['route', 'foo'], _file => { + expect(_file('app/routes/foo.js')) + .to.contain("import Route from '@ember/routing/route';") + .to.contain('export default Route.extend({\n});'); - expect(_file('app/templates/foo.hbs')) - .to.equal('{{outlet}}'); + expect(_file('app/templates/foo.hbs')).to.equal('{{outlet}}'); - expect(_file('tests/unit/routes/foo-test.js')) - .to.contain('import { moduleFor, test } from \'ember-qunit\';') - .to.contain('moduleFor(\'route:foo\''); - - expect(file('app/router.js')) - .to.contain('this.route(\'foo\')'); + expect(_file('tests/unit/routes/foo-test.js')) + .to.contain("import { moduleFor, test } from 'ember-qunit';") + .to.contain("moduleFor('route:foo'"); - }).then(() => { - expect(file('app/router.js')) - .to.not.contain('this.route(\'foo\')'); - }); + expect(file('app/router.js')).to.contain("this.route('foo')"); + }).then(() => { + expect(file('app/router.js')).to.not.contain("this.route('foo')"); + }); }); it('route foo --skip-router', function() { - return emberGenerateDestroy(['route', 'foo', '--skip-router'], (_file) => { + return emberGenerateDestroy(['route', 'foo', '--skip-router'], _file => { expect(_file('app/routes/foo.js')).to.exist; expect(_file('app/templates/foo.hbs')).to.exist; expect(_file('tests/unit/routes/foo-test.js')).to.exist; - expect(file('app/router.js')).to.not.contain('this.route(\'foo\')'); + expect(file('app/router.js')).to.not.contain("this.route('foo')"); }).then(() => { - expect(file('app/router.js')).to.not.contain('this.route(\'foo\')'); + expect(file('app/router.js')).to.not.contain("this.route('foo')"); }); }); it('route foo --path=:foo_id/show', function() { - return emberGenerateDestroy(['route', 'foo', '--path=:foo_id/show'], (_file) => { - expect(_file('app/routes/foo.js')) - .to.contain('import Route from \'@ember/routing/route\';') - .to.contain('export default Route.extend({\n});'); - - expect(_file('app/templates/foo.hbs')) - .to.equal('{{outlet}}'); + return emberGenerateDestroy( + ['route', 'foo', '--path=:foo_id/show'], + _file => { + expect(_file('app/routes/foo.js')) + .to.contain("import Route from '@ember/routing/route';") + .to.contain('export default Route.extend({\n});'); - expect(_file('tests/unit/routes/foo-test.js')) - .to.contain('import { moduleFor, test } from \'ember-qunit\';') - .to.contain('moduleFor(\'route:foo\''); + expect(_file('app/templates/foo.hbs')).to.equal('{{outlet}}'); - expect(file('app/router.js')) - .to.contain('this.route(\'foo\', {') - .to.contain('path: \':foo_id/show\'') - .to.contain('});'); + expect(_file('tests/unit/routes/foo-test.js')) + .to.contain("import { moduleFor, test } from 'ember-qunit';") + .to.contain("moduleFor('route:foo'"); - }).then(() => { + expect(file('app/router.js')) + .to.contain("this.route('foo', {") + .to.contain("path: ':foo_id/show'") + .to.contain('});'); + } + ).then(() => { expect(file('app/router.js')) - .to.not.contain('this.route(\'foo\'') - .to.not.contain('path: \':foo_id/show\''); + .to.not.contain("this.route('foo'") + .to.not.contain("path: ':foo_id/show'"); }); }); it('route parent/child --reset-namespace', function() { - return emberGenerateDestroy(['route', 'parent/child', '--reset-namespace'], (_file) => { - expect(_file('app/routes/child.js')) - .to.contain('import Route from \'@ember/routing/route\';') - .to.contain('export default Route.extend({\n});'); + return emberGenerateDestroy( + ['route', 'parent/child', '--reset-namespace'], + _file => { + expect(_file('app/routes/child.js')) + .to.contain("import Route from '@ember/routing/route';") + .to.contain('export default Route.extend({\n});'); - expect(_file('app/templates/child.hbs')) - .to.equal('{{outlet}}'); + expect(_file('app/templates/child.hbs')).to.equal('{{outlet}}'); - expect(_file('tests/unit/routes/child-test.js')) - .to.contain('import { moduleFor, test } from \'ember-qunit\';') - .to.contain('moduleFor(\'route:child\''); + expect(_file('tests/unit/routes/child-test.js')) + .to.contain("import { moduleFor, test } from 'ember-qunit';") + .to.contain("moduleFor('route:child'"); - expect(file('app/router.js')) - .to.contain('this.route(\'parent\', {') - .to.contain('this.route(\'child\', {') - .to.contain('resetNamespace: true') - .to.contain('});'); - }); + expect(file('app/router.js')) + .to.contain("this.route('parent', {") + .to.contain("this.route('child', {") + .to.contain('resetNamespace: true') + .to.contain('});'); + } + ); }); it('route parent/child --reset-namespace --pod', function() { - return emberGenerateDestroy(['route', 'parent/child', '--reset-namespace', '--pod'], (_file) => { - expect(_file('app/child/route.js')) - .to.contain('import Route from \'@ember/routing/route\';') - .to.contain('export default Route.extend({\n});'); + return emberGenerateDestroy( + ['route', 'parent/child', '--reset-namespace', '--pod'], + _file => { + expect(_file('app/child/route.js')) + .to.contain("import Route from '@ember/routing/route';") + .to.contain('export default Route.extend({\n});'); - expect(_file('app/child/template.hbs')) - .to.equal('{{outlet}}'); + expect(_file('app/child/template.hbs')).to.equal('{{outlet}}'); - expect(_file('tests/unit/child/route-test.js')) - .to.contain('import { moduleFor, test } from \'ember-qunit\';') - .to.contain('moduleFor(\'route:child\''); + expect(_file('tests/unit/child/route-test.js')) + .to.contain("import { moduleFor, test } from 'ember-qunit';") + .to.contain("moduleFor('route:child'"); - expect(file('app/router.js')) - .to.contain('this.route(\'parent\', {') - .to.contain('this.route(\'child\', {') - .to.contain('resetNamespace: true') - .to.contain('});'); - }); + expect(file('app/router.js')) + .to.contain("this.route('parent', {") + .to.contain("this.route('child', {") + .to.contain('resetNamespace: true') + .to.contain('});'); + } + ); }); it('route index', function() { - return emberGenerateDestroy(['route', 'index'], (_file) => { + return emberGenerateDestroy(['route', 'index'], _file => { expect(_file('app/routes/index.js')).to.exist; expect(_file('app/templates/index.hbs')).to.exist; expect(_file('tests/unit/routes/index-test.js')).to.exist; - expect(file('app/router.js')).to.not.contain('this.route(\'index\')'); + expect(file('app/router.js')).to.not.contain("this.route('index')"); }).then(() => { - expect(file('app/router.js')).to.not.contain('this.route(\'index\')'); + expect(file('app/router.js')).to.not.contain("this.route('index')"); }); }); it('route application', function() { fs.removeSync('app/templates/application.hbs'); return emberGenerate(['route', 'application']).then(() => { - expect(file('app/router.js')).to.not.contain('this.route(\'application\')'); + expect(file('app/router.js')).to.not.contain( + "this.route('application')" + ); }); }); it('route basic', function() { - return emberGenerateDestroy(['route', 'basic'], (_file) => { + return emberGenerateDestroy(['route', 'basic'], _file => { expect(_file('app/routes/basic.js')).to.exist; - expect(file('app/router.js')).to.not.contain('this.route(\'basic\')'); + expect(file('app/router.js')).to.not.contain("this.route('basic')"); }).then(() => { - expect(file('app/router.js')).to.not.contain('this.route(\'basic\')'); + expect(file('app/router.js')).to.not.contain("this.route('basic')"); }); }); - it('route foo --pod', function() { - return emberGenerateDestroy(['route', 'foo', '--pod'], (_file) => { + return emberGenerateDestroy(['route', 'foo', '--pod'], _file => { expect(_file('app/foo/route.js')) - .to.contain('import Route from \'@ember/routing/route\';') + .to.contain("import Route from '@ember/routing/route';") .to.contain('export default Route.extend({\n});'); - expect(_file('app/foo/template.hbs')) - .to.equal('{{outlet}}'); + expect(_file('app/foo/template.hbs')).to.equal('{{outlet}}'); expect(_file('tests/unit/foo/route-test.js')) - .to.contain('import { moduleFor, test } from \'ember-qunit\';') - .to.contain('moduleFor(\'route:foo\''); - - expect(file('app/router.js')) - .to.contain('this.route(\'foo\')'); + .to.contain("import { moduleFor, test } from 'ember-qunit';") + .to.contain("moduleFor('route:foo'"); + expect(file('app/router.js')).to.contain("this.route('foo')"); }).then(() => { - expect(file('app/router.js')) - .to.not.contain('this.route(\'foo\')'); + expect(file('app/router.js')).to.not.contain("this.route('foo')"); }); }); it('route foo --pod with --path', function() { return emberGenerate(['route', 'foo', '--pod', '--path=:foo_id/show']) - .then(() => expect(file('app/router.js')) - .to.contain('this.route(\'foo\', {') - .to.contain('path: \':foo_id/show\'') - .to.contain('});')) - - .then(() => emberDestroy(['route', 'foo', '--pod', '--path=:foo_id/show'])) - .then(() => expect(file('app/router.js')) - .to.not.contain('this.route(\'foo\', {') - .to.not.contain('path: \':foo_id/show\'')); + .then(() => + expect(file('app/router.js')) + .to.contain("this.route('foo', {") + .to.contain("path: ':foo_id/show'") + .to.contain('});') + ) + + .then(() => + emberDestroy(['route', 'foo', '--pod', '--path=:foo_id/show']) + ) + .then(() => + expect(file('app/router.js')) + .to.not.contain("this.route('foo', {") + .to.not.contain("path: ':foo_id/show'") + ); }); it('route index --pod', function() { - return emberGenerate(['route', 'index', '--pod']) - .then(() => expect(file('app/router.js')) - .to.not.contain('this.route(\'index\')')); + return emberGenerate(['route', 'index', '--pod']).then(() => + expect(file('app/router.js')).to.not.contain("this.route('index')") + ); }); it('route application --pod', function() { return emberGenerate(['route', 'application', '--pod']) .then(() => expect(file('app/application/route.js')).to.exist) .then(() => expect(file('app/application/template.hbs')).to.exist) - .then(() => expect(file('app/router.js')).to.not.contain('this.route(\'application\')')); + .then(() => + expect(file('app/router.js')).to.not.contain( + "this.route('application')" + ) + ); }); it('route basic --pod', function() { - return emberGenerateDestroy(['route', 'basic', '--pod'], (_file) => { + return emberGenerateDestroy(['route', 'basic', '--pod'], _file => { expect(_file('app/basic/route.js')).to.exist; - expect(file('app/router.js')) - .to.not.contain('this.route(\'index\')'); + expect(file('app/router.js')).to.not.contain("this.route('index')"); }); }); @@ -211,24 +218,20 @@ describe('Blueprint: route', function() { }); it('route foo --pod', function() { - return emberGenerateDestroy(['route', 'foo', '--pod'], (_file) => { + return emberGenerateDestroy(['route', 'foo', '--pod'], _file => { expect(_file('app/pods/foo/route.js')) - .to.contain('import Route from \'@ember/routing/route\';') + .to.contain("import Route from '@ember/routing/route';") .to.contain('export default Route.extend({\n});'); - expect(_file('app/pods/foo/template.hbs')) - .to.equal('{{outlet}}'); + expect(_file('app/pods/foo/template.hbs')).to.equal('{{outlet}}'); expect(_file('tests/unit/pods/foo/route-test.js')) - .to.contain('import { moduleFor, test } from \'ember-qunit\';') - .to.contain('moduleFor(\'route:foo\''); - - expect(file('app/router.js')) - .to.contain('this.route(\'foo\')'); + .to.contain("import { moduleFor, test } from 'ember-qunit';") + .to.contain("moduleFor('route:foo'"); + expect(file('app/router.js')).to.contain("this.route('foo')"); }).then(() => { - expect(file('app/router.js')) - .to.not.contain('this.route(\'foo\')'); + expect(file('app/router.js')).to.not.contain("this.route('foo')"); }); }); }); @@ -240,124 +243,132 @@ describe('Blueprint: route', function() { }); it('route foo', function() { - return emberGenerateDestroy(['route', 'foo'], (_file) => { + return emberGenerateDestroy(['route', 'foo'], _file => { expect(_file('addon/routes/foo.js')) - .to.contain('import Route from \'@ember/routing/route\';') + .to.contain("import Route from '@ember/routing/route';") .to.contain('export default Route.extend({\n});'); - expect(_file('addon/templates/foo.hbs')) - .to.equal('{{outlet}}'); + expect(_file('addon/templates/foo.hbs')).to.equal('{{outlet}}'); - expect(_file('app/routes/foo.js')) - .to.contain('export { default } from \'my-addon/routes/foo\';'); + expect(_file('app/routes/foo.js')).to.contain( + "export { default } from 'my-addon/routes/foo';" + ); - expect(_file('app/templates/foo.js')) - .to.contain('export { default } from \'my-addon/templates/foo\';'); + expect(_file('app/templates/foo.js')).to.contain( + "export { default } from 'my-addon/templates/foo';" + ); expect(_file('tests/unit/routes/foo-test.js')) - .to.contain('import { moduleFor, test } from \'ember-qunit\';') - .to.contain('moduleFor(\'route:foo\''); - - expect(file('tests/dummy/app/router.js')) - .to.not.contain('this.route(\'foo\')'); + .to.contain("import { moduleFor, test } from 'ember-qunit';") + .to.contain("moduleFor('route:foo'"); + expect(file('tests/dummy/app/router.js')).to.not.contain( + "this.route('foo')" + ); }).then(() => { - expect(file('tests/dummy/app/router.js')) - .to.not.contain('this.route(\'foo\')'); + expect(file('tests/dummy/app/router.js')).to.not.contain( + "this.route('foo')" + ); }); }); it('route foo/bar', function() { - return emberGenerateDestroy(['route', 'foo/bar'], (_file) => { + return emberGenerateDestroy(['route', 'foo/bar'], _file => { expect(_file('addon/routes/foo/bar.js')) - .to.contain('import Route from \'@ember/routing/route\';') + .to.contain("import Route from '@ember/routing/route';") .to.contain('export default Route.extend({\n});'); - expect(_file('addon/templates/foo/bar.hbs')) - .to.equal('{{outlet}}'); + expect(_file('addon/templates/foo/bar.hbs')).to.equal('{{outlet}}'); - expect(_file('app/routes/foo/bar.js')) - .to.contain('export { default } from \'my-addon/routes/foo/bar\';'); + expect(_file('app/routes/foo/bar.js')).to.contain( + "export { default } from 'my-addon/routes/foo/bar';" + ); - expect(_file('app/templates/foo/bar.js')) - .to.contain('export { default } from \'my-addon/templates/foo/bar\';'); + expect(_file('app/templates/foo/bar.js')).to.contain( + "export { default } from 'my-addon/templates/foo/bar';" + ); expect(_file('tests/unit/routes/foo/bar-test.js')) - .to.contain('import { moduleFor, test } from \'ember-qunit\';') - .to.contain('moduleFor(\'route:foo/bar\''); - - expect(file('tests/dummy/app/router.js')) - .to.not.contain('this.route(\'bar\')'); + .to.contain("import { moduleFor, test } from 'ember-qunit';") + .to.contain("moduleFor('route:foo/bar'"); + expect(file('tests/dummy/app/router.js')).to.not.contain( + "this.route('bar')" + ); }).then(() => { - expect(file('tests/dummy/app/router.js')) - .to.not.contain('this.route(\'bar\')'); + expect(file('tests/dummy/app/router.js')).to.not.contain( + "this.route('bar')" + ); }); }); it('route foo --dummy', function() { - return emberGenerateDestroy(['route', 'foo', '--dummy'], (_file) => { + return emberGenerateDestroy(['route', 'foo', '--dummy'], _file => { expect(_file('tests/dummy/app/routes/foo.js')) - .to.contain('import Route from \'@ember/routing/route\';') + .to.contain("import Route from '@ember/routing/route';") .to.contain('export default Route.extend({\n});'); - expect(_file('tests/dummy/app/templates/foo.hbs')) - .to.equal('{{outlet}}'); + expect(_file('tests/dummy/app/templates/foo.hbs')).to.equal( + '{{outlet}}' + ); expect(_file('app/routes/foo.js')).to.not.exist; expect(_file('app/templates/foo.hbs')).to.not.exist; expect(_file('tests/unit/routes/foo-test.js')).to.not.exist; - expect(file('tests/dummy/app/router.js')) - .to.contain('this.route(\'foo\')'); - + expect(file('tests/dummy/app/router.js')).to.contain( + "this.route('foo')" + ); }).then(() => { - expect(file('tests/dummy/app/router.js')) - .to.not.contain('this.route(\'foo\')'); + expect(file('tests/dummy/app/router.js')).to.not.contain( + "this.route('foo')" + ); }); }); it('route foo/bar --dummy', function() { - return emberGenerateDestroy(['route', 'foo/bar', '--dummy'], (_file) => { + return emberGenerateDestroy(['route', 'foo/bar', '--dummy'], _file => { expect(_file('tests/dummy/app/routes/foo/bar.js')) - .to.contain('import Route from \'@ember/routing/route\';') + .to.contain("import Route from '@ember/routing/route';") .to.contain('export default Route.extend({\n});'); - expect(_file('tests/dummy/app/templates/foo/bar.hbs')) - .to.equal('{{outlet}}'); + expect(_file('tests/dummy/app/templates/foo/bar.hbs')).to.equal( + '{{outlet}}' + ); expect(_file('app/routes/foo/bar.js')).to.not.exist; expect(_file('app/templates/foo/bar.hbs')).to.not.exist; expect(_file('tests/unit/routes/foo/bar-test.js')).to.not.exist; expect(file('tests/dummy/app/router.js')) - .to.contain('this.route(\'foo\', function() {') - .to.contain('this.route(\'bar\')'); - + .to.contain("this.route('foo', function() {") + .to.contain("this.route('bar')"); }).then(() => { - expect(file('tests/dummy/app/router.js')) - .to.not.contain('this.route(\'bar\')'); + expect(file('tests/dummy/app/router.js')).to.not.contain( + "this.route('bar')" + ); }); }); it('route foo --pod', function() { - return emberGenerateDestroy(['route', 'foo', '--pod'], (_file) => { + return emberGenerateDestroy(['route', 'foo', '--pod'], _file => { expect(_file('addon/foo/route.js')) - .to.contain('import Route from \'@ember/routing/route\';') + .to.contain("import Route from '@ember/routing/route';") .to.contain('export default Route.extend({\n});'); - expect(_file('addon/foo/template.hbs')) - .to.equal('{{outlet}}'); + expect(_file('addon/foo/template.hbs')).to.equal('{{outlet}}'); - expect(_file('app/foo/route.js')) - .to.contain('export { default } from \'my-addon/foo/route\';'); + expect(_file('app/foo/route.js')).to.contain( + "export { default } from 'my-addon/foo/route';" + ); - expect(_file('app/foo/template.js')) - .to.contain('export { default } from \'my-addon/foo/template\';'); + expect(_file('app/foo/template.js')).to.contain( + "export { default } from 'my-addon/foo/template';" + ); expect(_file('tests/unit/foo/route-test.js')) - .to.contain('import { moduleFor, test } from \'ember-qunit\';') - .to.contain('moduleFor(\'route:foo\''); + .to.contain("import { moduleFor, test } from 'ember-qunit';") + .to.contain("moduleFor('route:foo'"); }); }); }); @@ -368,45 +379,57 @@ describe('Blueprint: route', function() { }); it('route foo --in-repo-addon=my-addon', function() { - return emberGenerateDestroy(['route', 'foo', '--in-repo-addon=my-addon'], (_file) => { - expect(_file('lib/my-addon/addon/routes/foo.js')) - .to.contain('import Route from \'@ember/routing/route\';') - .to.contain('export default Route.extend({\n});'); + return emberGenerateDestroy( + ['route', 'foo', '--in-repo-addon=my-addon'], + _file => { + expect(_file('lib/my-addon/addon/routes/foo.js')) + .to.contain("import Route from '@ember/routing/route';") + .to.contain('export default Route.extend({\n});'); - expect(_file('lib/my-addon/addon/templates/foo.hbs')) - .to.equal('{{outlet}}'); + expect(_file('lib/my-addon/addon/templates/foo.hbs')).to.equal( + '{{outlet}}' + ); - expect(_file('lib/my-addon/app/routes/foo.js')) - .to.contain('export { default } from \'my-addon/routes/foo\';'); + expect(_file('lib/my-addon/app/routes/foo.js')).to.contain( + "export { default } from 'my-addon/routes/foo';" + ); - expect(_file('lib/my-addon/app/templates/foo.js')) - .to.contain('export { default } from \'my-addon/templates/foo\';'); + expect(_file('lib/my-addon/app/templates/foo.js')).to.contain( + "export { default } from 'my-addon/templates/foo';" + ); - expect(_file('tests/unit/routes/foo-test.js')) - .to.contain('import { moduleFor, test } from \'ember-qunit\';') - .to.contain('moduleFor(\'route:foo\''); - }); + expect(_file('tests/unit/routes/foo-test.js')) + .to.contain("import { moduleFor, test } from 'ember-qunit';") + .to.contain("moduleFor('route:foo'"); + } + ); }); it('route foo/bar --in-repo-addon=my-addon', function() { - return emberGenerateDestroy(['route', 'foo/bar', '--in-repo-addon=my-addon'], (_file) => { - expect(_file('lib/my-addon/addon/routes/foo/bar.js')) - .to.contain('import Route from \'@ember/routing/route\';') - .to.contain('export default Route.extend({\n});'); + return emberGenerateDestroy( + ['route', 'foo/bar', '--in-repo-addon=my-addon'], + _file => { + expect(_file('lib/my-addon/addon/routes/foo/bar.js')) + .to.contain("import Route from '@ember/routing/route';") + .to.contain('export default Route.extend({\n});'); - expect(_file('lib/my-addon/addon/templates/foo/bar.hbs')) - .to.equal('{{outlet}}'); + expect(_file('lib/my-addon/addon/templates/foo/bar.hbs')).to.equal( + '{{outlet}}' + ); - expect(_file('lib/my-addon/app/routes/foo/bar.js')) - .to.contain('export { default } from \'my-addon/routes/foo/bar\';'); + expect(_file('lib/my-addon/app/routes/foo/bar.js')).to.contain( + "export { default } from 'my-addon/routes/foo/bar';" + ); - expect(_file('lib/my-addon/app/templates/foo/bar.js')) - .to.contain('export { default } from \'my-addon/templates/foo/bar\';'); + expect(_file('lib/my-addon/app/templates/foo/bar.js')).to.contain( + "export { default } from 'my-addon/templates/foo/bar';" + ); - expect(_file('tests/unit/routes/foo/bar-test.js')) - .to.contain('import { moduleFor, test } from \'ember-qunit\';') - .to.contain('moduleFor(\'route:foo/bar\''); - }); + expect(_file('tests/unit/routes/foo/bar-test.js')) + .to.contain("import { moduleFor, test } from 'ember-qunit';") + .to.contain("moduleFor('route:foo/bar'"); + } + ); }); }); }); diff --git a/node-tests/blueprints/service-test-test.js b/node-tests/blueprints/service-test-test.js index 8e02665d4ff..8f8386ebabd 100644 --- a/node-tests/blueprints/service-test-test.js +++ b/node-tests/blueprints/service-test-test.js @@ -22,8 +22,9 @@ describe('Blueprint: service-test', function() { it('service-test foo', function() { return emberGenerateDestroy(['service-test', 'foo'], _file => { - expect(_file('tests/unit/services/foo-test.js')) - .to.equal(fixture('service-test/default.js')); + expect(_file('tests/unit/services/foo-test.js')).to.equal( + fixture('service-test/default.js') + ); }); }); @@ -38,15 +39,17 @@ describe('Blueprint: service-test', function() { it('service-test foo', function() { return emberGenerateDestroy(['service-test', 'foo'], _file => { - expect(_file('tests/unit/services/foo-test.js')) - .to.equal(fixture('service-test/mocha.js')); + expect(_file('tests/unit/services/foo-test.js')).to.equal( + fixture('service-test/mocha.js') + ); }); }); it('service-test foo --pod', function() { return emberGenerateDestroy(['service-test', 'foo', '--pod'], _file => { - expect(_file('tests/unit/foo/service-test.js')) - .to.equal(fixture('service-test/mocha.js')); + expect(_file('tests/unit/foo/service-test.js')).to.equal( + fixture('service-test/mocha.js') + ); }); }); }); @@ -62,15 +65,17 @@ describe('Blueprint: service-test', function() { it('service-test foo', function() { return emberGenerateDestroy(['service-test', 'foo'], _file => { - expect(_file('tests/unit/services/foo-test.js')) - .to.equal(fixture('service-test/mocha-0.12.js')); + expect(_file('tests/unit/services/foo-test.js')).to.equal( + fixture('service-test/mocha-0.12.js') + ); }); }); it('service-test foo --pod', function() { return emberGenerateDestroy(['service-test', 'foo', '--pod'], _file => { - expect(_file('tests/unit/foo/service-test.js')) - .to.equal(fixture('service-test/mocha-0.12.js')); + expect(_file('tests/unit/foo/service-test.js')).to.equal( + fixture('service-test/mocha-0.12.js') + ); }); }); }); @@ -82,8 +87,9 @@ describe('Blueprint: service-test', function() { it('service-test foo', function() { return emberGenerateDestroy(['service-test', 'foo'], _file => { - expect(_file('tests/unit/services/foo-test.js')) - .to.equal(fixture('service-test/rfc232.js')); + expect(_file('tests/unit/services/foo-test.js')).to.equal( + fixture('service-test/rfc232.js') + ); }); }); }); @@ -96,11 +102,11 @@ describe('Blueprint: service-test', function() { it('service-test foo', function() { return emberGenerateDestroy(['service-test', 'foo'], _file => { - expect(_file('tests/unit/services/foo-test.js')) - .to.equal(fixture('service-test/default.js')); + expect(_file('tests/unit/services/foo-test.js')).to.equal( + fixture('service-test/default.js') + ); - expect(_file('app/service-test/foo.js')) - .to.not.exist; + expect(_file('app/service-test/foo.js')).to.not.exist; }); }); }); diff --git a/node-tests/blueprints/service-test.js b/node-tests/blueprints/service-test.js index 9bb13709e6f..fa8bb2e750d 100644 --- a/node-tests/blueprints/service-test.js +++ b/node-tests/blueprints/service-test.js @@ -107,8 +107,9 @@ describe('Blueprint: service', function() { .to.contain("import Service from '@ember/service';") .to.contain('export default Service.extend({\n});'); - expect(_file('app/services/foo.js')) - .to.contain("export { default } from 'my-addon/services/foo';"); + expect(_file('app/services/foo.js')).to.contain( + "export { default } from 'my-addon/services/foo';" + ); expect(_file('tests/unit/services/foo-test.js')) .to.contain("import { moduleFor, test } from 'ember-qunit';") @@ -122,8 +123,9 @@ describe('Blueprint: service', function() { .to.contain("import Service from '@ember/service';") .to.contain('export default Service.extend({\n});'); - expect(_file('app/services/foo/bar.js')) - .to.contain("export { default } from 'my-addon/services/foo/bar';"); + expect(_file('app/services/foo/bar.js')).to.contain( + "export { default } from 'my-addon/services/foo/bar';" + ); expect(_file('tests/unit/services/foo/bar-test.js')) .to.contain("import { moduleFor, test } from 'ember-qunit';") diff --git a/node-tests/blueprints/template-test.js b/node-tests/blueprints/template-test.js index f01a9ff8cb8..4bc62023bcc 100644 --- a/node-tests/blueprints/template-test.js +++ b/node-tests/blueprints/template-test.js @@ -105,15 +105,23 @@ describe('Blueprint: template', function() { }); it('template foo --in-repo-addon=my-addon', function() { - return emberGenerateDestroy(['template', 'foo', '--in-repo-addon=my-addon'], _file => { - expect(_file('lib/my-addon/addon/templates/foo.hbs')).to.equal(''); - }); + return emberGenerateDestroy( + ['template', 'foo', '--in-repo-addon=my-addon'], + _file => { + expect(_file('lib/my-addon/addon/templates/foo.hbs')).to.equal(''); + } + ); }); it('template foo/bar --in-repo-addon=my-addon', function() { - return emberGenerateDestroy(['template', 'foo/bar', '--in-repo-addon=my-addon'], _file => { - expect(_file('lib/my-addon/addon/templates/foo/bar.hbs')).to.equal(''); - }); + return emberGenerateDestroy( + ['template', 'foo/bar', '--in-repo-addon=my-addon'], + _file => { + expect(_file('lib/my-addon/addon/templates/foo/bar.hbs')).to.equal( + '' + ); + } + ); }); }); }); diff --git a/node-tests/blueprints/util-test-test.js b/node-tests/blueprints/util-test-test.js index 68eb9d4b5b9..538e1a5fe90 100644 --- a/node-tests/blueprints/util-test-test.js +++ b/node-tests/blueprints/util-test-test.js @@ -22,8 +22,9 @@ describe('Blueprint: util-test', function() { it('util-test foo-bar', function() { return emberGenerateDestroy(['util-test', 'foo-bar'], _file => { - expect(_file('tests/unit/utils/foo-bar-test.js')) - .to.equal(fixture('util-test/default.js')); + expect(_file('tests/unit/utils/foo-bar-test.js')).to.equal( + fixture('util-test/default.js') + ); }); }); @@ -34,8 +35,9 @@ describe('Blueprint: util-test', function() { it('util-test foo-bar', function() { return emberGenerateDestroy(['util-test', 'foo-bar'], _file => { - expect(_file('tests/unit/utils/foo-bar-test.js')) - .to.equal(fixture('util-test/rfc232.js')); + expect(_file('tests/unit/utils/foo-bar-test.js')).to.equal( + fixture('util-test/rfc232.js') + ); }); }); }); @@ -50,8 +52,9 @@ describe('Blueprint: util-test', function() { it('util-test foo-bar', function() { return emberGenerateDestroy(['util-test', 'foo-bar'], _file => { - expect(_file('tests/unit/utils/foo-bar-test.js')) - .to.equal(fixture('util-test/mocha.js')); + expect(_file('tests/unit/utils/foo-bar-test.js')).to.equal( + fixture('util-test/mocha.js') + ); }); }); }); @@ -64,8 +67,9 @@ describe('Blueprint: util-test', function() { it('util-test foo-bar', function() { return emberGenerateDestroy(['util-test', 'foo-bar'], _file => { - expect(_file('tests/unit/utils/foo-bar-test.js')) - .to.equal(fixture('util-test/dummy.js')); + expect(_file('tests/unit/utils/foo-bar-test.js')).to.equal( + fixture('util-test/dummy.js') + ); }); }); }); diff --git a/node-tests/blueprints/util-test.js b/node-tests/blueprints/util-test.js index f722f6dff46..7e65ed87e03 100644 --- a/node-tests/blueprints/util-test.js +++ b/node-tests/blueprints/util-test.js @@ -19,49 +19,49 @@ describe('Blueprint: util', function() { it('util foo-bar', function() { return emberGenerateDestroy(['util', 'foo-bar'], _file => { - expect(_file('app/utils/foo-bar.js')) - .to.contain('export default function fooBar() {\n' + - ' return true;\n' + - '}'); + expect(_file('app/utils/foo-bar.js')).to.contain( + 'export default function fooBar() {\n' + ' return true;\n' + '}' + ); - expect(_file('tests/unit/utils/foo-bar-test.js')) - .to.contain("import fooBar from 'my-app/utils/foo-bar';"); + expect(_file('tests/unit/utils/foo-bar-test.js')).to.contain( + "import fooBar from 'my-app/utils/foo-bar';" + ); }); }); it('util foo-bar/baz', function() { return emberGenerateDestroy(['util', 'foo/bar-baz'], _file => { - expect(_file('app/utils/foo/bar-baz.js')) - .to.contain('export default function fooBarBaz() {\n' + - ' return true;\n' + - '}'); + expect(_file('app/utils/foo/bar-baz.js')).to.contain( + 'export default function fooBarBaz() {\n' + ' return true;\n' + '}' + ); - expect(_file('tests/unit/utils/foo/bar-baz-test.js')) - .to.contain("import fooBarBaz from 'my-app/utils/foo/bar-baz';"); + expect(_file('tests/unit/utils/foo/bar-baz-test.js')).to.contain( + "import fooBarBaz from 'my-app/utils/foo/bar-baz';" + ); }); }); it('util foo-bar --pod', function() { return emberGenerateDestroy(['util', 'foo-bar', '--pod'], _file => { - expect(_file('app/utils/foo-bar.js')) - .to.contain('export default function fooBar() {\n' + - ' return true;\n' + - '}'); + expect(_file('app/utils/foo-bar.js')).to.contain( + 'export default function fooBar() {\n' + ' return true;\n' + '}' + ); - expect(_file('tests/unit/utils/foo-bar-test.js')) - .to.contain("import fooBar from 'my-app/utils/foo-bar';"); + expect(_file('tests/unit/utils/foo-bar-test.js')).to.contain( + "import fooBar from 'my-app/utils/foo-bar';" + ); }); }); it('util foo-bar/baz --pod', function() { return emberGenerateDestroy(['util', 'foo/bar-baz', '--pod'], _file => { - expect(_file('app/utils/foo/bar-baz.js')) - .to.contain('export default function fooBarBaz() {\n' + - ' return true;\n' + - '}'); + expect(_file('app/utils/foo/bar-baz.js')).to.contain( + 'export default function fooBarBaz() {\n' + ' return true;\n' + '}' + ); - expect(_file('tests/unit/utils/foo/bar-baz-test.js')) - .to.contain("import fooBarBaz from 'my-app/utils/foo/bar-baz';"); + expect(_file('tests/unit/utils/foo/bar-baz-test.js')).to.contain( + "import fooBarBaz from 'my-app/utils/foo/bar-baz';" + ); }); }); @@ -72,13 +72,13 @@ describe('Blueprint: util', function() { it('util foo-bar --pod', function() { return emberGenerateDestroy(['util', 'foo-bar', '--pod'], _file => { - expect(_file('app/utils/foo-bar.js')) - .to.contain('export default function fooBar() {\n' + - ' return true;\n' + - '}'); + expect(_file('app/utils/foo-bar.js')).to.contain( + 'export default function fooBar() {\n' + ' return true;\n' + '}' + ); - expect(_file('tests/unit/utils/foo-bar-test.js')) - .to.contain("import fooBar from 'my-app/utils/foo-bar';"); + expect(_file('tests/unit/utils/foo-bar-test.js')).to.contain( + "import fooBar from 'my-app/utils/foo-bar';" + ); }); }); }); @@ -91,31 +91,33 @@ describe('Blueprint: util', function() { it('util foo-bar', function() { return emberGenerateDestroy(['util', 'foo-bar'], _file => { - expect(_file('addon/utils/foo-bar.js')) - .to.contain('export default function fooBar() {\n' + - ' return true;\n' + - '}'); + expect(_file('addon/utils/foo-bar.js')).to.contain( + 'export default function fooBar() {\n' + ' return true;\n' + '}' + ); - expect(_file('app/utils/foo-bar.js')) - .to.contain("export { default } from 'my-addon/utils/foo-bar';"); + expect(_file('app/utils/foo-bar.js')).to.contain( + "export { default } from 'my-addon/utils/foo-bar';" + ); - expect(_file('tests/unit/utils/foo-bar-test.js')) - .to.contain("import fooBar from 'dummy/utils/foo-bar';"); + expect(_file('tests/unit/utils/foo-bar-test.js')).to.contain( + "import fooBar from 'dummy/utils/foo-bar';" + ); }); }); it('util foo-bar/baz', function() { return emberGenerateDestroy(['util', 'foo/bar-baz'], _file => { - expect(_file('addon/utils/foo/bar-baz.js')) - .to.contain('export default function fooBarBaz() {\n' + - ' return true;\n' + - '}'); + expect(_file('addon/utils/foo/bar-baz.js')).to.contain( + 'export default function fooBarBaz() {\n' + ' return true;\n' + '}' + ); - expect(_file('app/utils/foo/bar-baz.js')) - .to.contain("export { default } from 'my-addon/utils/foo/bar-baz';"); + expect(_file('app/utils/foo/bar-baz.js')).to.contain( + "export { default } from 'my-addon/utils/foo/bar-baz';" + ); - expect(_file('tests/unit/utils/foo/bar-baz-test.js')) - .to.contain("import fooBarBaz from 'dummy/utils/foo/bar-baz';"); + expect(_file('tests/unit/utils/foo/bar-baz-test.js')).to.contain( + "import fooBarBaz from 'dummy/utils/foo/bar-baz';" + ); }); }); }); diff --git a/node-tests/helpers/generate-fake-package-manifest.js b/node-tests/helpers/generate-fake-package-manifest.js index d6f92f1f5a9..5705ecfb96d 100644 --- a/node-tests/helpers/generate-fake-package-manifest.js +++ b/node-tests/helpers/generate-fake-package-manifest.js @@ -7,7 +7,10 @@ module.exports = function generateFakePackageManifest(name, version) { if (!fs.existsSync('node_modules/' + name)) { fs.mkdirSync('node_modules/' + name); } - fs.writeFileSync('node_modules/' + name + '/package.json', JSON.stringify({ - version: version, - })); + fs.writeFileSync( + 'node_modules/' + name + '/package.json', + JSON.stringify({ + version: version + }) + ); }; diff --git a/package.json b/package.json index 4fd7bdc3276..2a977eb5a93 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "start": "ember serve", "pretest": "ember build", "lint": "TEST_SUITE=code-quality node bin/run-tests.js", + "lint:fix": "eslint --fix .", "test": "node bin/run-tests.js", "test:blueprints": "node node-tests/nodetest-runner.js", "test:node": "qunit tests/**/*-test.js", @@ -113,8 +114,10 @@ "ember-cli-yuidoc": "^0.8.8", "ember-publisher": "0.0.7", "eslint": "^4.9.1", + "eslint-config-prettier": "^2.9.0", "eslint-plugin-ember-internal": "^1.1.1", "eslint-plugin-node": "^6.0.1", + "eslint-plugin-prettier": "^2.6.0", "execa": "^0.10.0", "express": "^4.16.2", "finalhandler": "^1.0.2", @@ -125,6 +128,7 @@ "html-differ": "^1.3.4", "lodash.uniq": "^4.5.0", "mocha": "^5.0.0", + "prettier": "1.11.1", "puppeteer": "^0.13.0", "qunit": "^2.5.0", "route-recognizer": "^0.3.3", diff --git a/packages/container/lib/container.js b/packages/container/lib/container.js index 8c14a08e528..e09276931db 100644 --- a/packages/container/lib/container.js +++ b/packages/container/lib/container.js @@ -10,7 +10,6 @@ import { HAS_NATIVE_PROXY } from 'ember-utils'; - /** A container used to instantiate and cache objects. @@ -26,9 +25,9 @@ import { */ export default class Container { constructor(registry, options = {}) { - this.registry = registry; - this.owner = options.owner || null; - this.cache = dictionary(options.cache || null); + this.registry = registry; + this.owner = options.owner || null; + this.cache = dictionary(options.cache || null); this.factoryManagerCache = dictionary(options.factoryManagerCache || null); this.isDestroyed = false; @@ -89,7 +88,10 @@ export default class Container { @return {any} */ lookup(fullName, options) { - assert('fullName must be a proper full name', this.registry.isValidFullName(fullName)); + assert( + 'fullName must be a proper full name', + this.registry.isValidFullName(fullName) + ); return lookup(this, this.registry.normalize(fullName), options); } @@ -145,7 +147,10 @@ export default class Container { factoryFor(fullName, options = {}) { let normalizedName = this.registry.normalize(fullName); - assert('fullName must be a proper full name', this.registry.isValidFullName(normalizedName)); + assert( + 'fullName must be a proper full name', + this.registry.isValidFullName(normalizedName) + ); assert( 'EMBER_MODULE_UNIFICATION must be enabled to pass a namespace option to factoryFor', EMBER_MODULE_UNIFICATION || !options.namespace @@ -169,7 +174,9 @@ function wrapManagerInDeprecationProxy(manager) { if (HAS_NATIVE_PROXY) { let validator = { set(obj, prop) { - throw new Error(`You attempted to set "${prop}" on a factory manager created by container#factoryFor. A factory manager is a read-only construct.`); + throw new Error( + `You attempted to set "${prop}" on a factory manager created by container#factoryFor. A factory manager is a read-only construct.` + ); } }; @@ -224,11 +231,12 @@ function lookup(container, fullName, options = {}) { return instantiateFactory(container, normalizedName, fullName, options); } - function factoryFor(container, normalizedName, fullName) { let cached = container.factoryManagerCache[normalizedName]; - if (cached !== undefined) { return cached; } + if (cached !== undefined) { + return cached; + } let factory = container.registry.resolve(normalizedName); @@ -240,7 +248,12 @@ function factoryFor(container, normalizedName, fullName) { factory._onLookup(fullName); // What should this pass? fullname or the normalized key? } - let manager = new FactoryManager(container, factory, fullName, normalizedName); + let manager = new FactoryManager( + container, + factory, + fullName, + normalizedName + ); if (DEBUG) { manager = wrapManagerInDeprecationProxy(manager); @@ -251,19 +264,37 @@ function factoryFor(container, normalizedName, fullName) { } function isSingletonClass(container, fullName, { instantiate, singleton }) { - return singleton !== false && !instantiate && isSingleton(container, fullName) && !isInstantiatable(container, fullName); + return ( + singleton !== false && + !instantiate && + isSingleton(container, fullName) && + !isInstantiatable(container, fullName) + ); } function isSingletonInstance(container, fullName, { instantiate, singleton }) { - return singleton !== false && instantiate !== false && isSingleton(container, fullName) && isInstantiatable(container, fullName); + return ( + singleton !== false && + instantiate !== false && + isSingleton(container, fullName) && + isInstantiatable(container, fullName) + ); } function isFactoryClass(container, fullname, { instantiate, singleton }) { - return instantiate === false && (singleton === false || !isSingleton(container, fullname)) && !isInstantiatable(container, fullname); + return ( + instantiate === false && + (singleton === false || !isSingleton(container, fullname)) && + !isInstantiatable(container, fullname) + ); } function isFactoryInstance(container, fullName, { instantiate, singleton }) { - return instantiate !== false && (singleton !== false || isSingleton(container, fullName)) && isInstantiatable(container, fullName); + return ( + instantiate !== false && + (singleton !== false || isSingleton(container, fullName)) && + isInstantiatable(container, fullName) + ); } function instantiateFactory(container, normalizedName, fullName, options) { @@ -276,7 +307,7 @@ function instantiateFactory(container, normalizedName, fullName, options) { // SomeClass { singleton: true, instantiate: true } | { singleton: true } | { instantiate: true } | {} // By default majority of objects fall into this case if (isSingletonInstance(container, fullName, options)) { - return container.cache[normalizedName] = factoryManager.create(); + return (container.cache[normalizedName] = factoryManager.create()); } // SomeClass { singleton: false, instantiate: true } @@ -285,7 +316,10 @@ function instantiateFactory(container, normalizedName, fullName, options) { } // SomeClass { singleton: true, instantiate: false } | { instantiate: false } | { singleton: false, instantiation: false } - if (isSingletonClass(container, fullName, options) || isFactoryClass(container, fullName, options)) { + if ( + isSingletonClass(container, fullName, options) || + isFactoryClass(container, fullName, options) + ) { return factoryManager.class; } @@ -303,7 +337,7 @@ function processInjections(container, injections, result) { } for (let i = 0; i < injections.length; i++) { - let {property, specifier, source} = injections[i]; + let { property, specifier, source } = injections[i]; if (source) { hash[property] = lookup(container, specifier, { source }); @@ -320,7 +354,7 @@ function processInjections(container, injections, result) { function buildInjections(container, typeInjections, injections) { let result = { injections: undefined, - isDyanmic: false, + isDyanmic: false }; if (typeInjections !== undefined) { @@ -393,7 +427,10 @@ class FactoryManager { toString() { if (this.madeToString === undefined) { - this.madeToString = this.container.registry.makeToString(this.class, this.fullName); + this.madeToString = this.container.registry.makeToString( + this.class, + this.fullName + ); } return this.madeToString; @@ -402,7 +439,10 @@ class FactoryManager { create(options) { let injectionsCache = this.injections; if (injectionsCache === undefined) { - let { injections, isDynamic } = injectionsFor(this.container, this.normalizedName); + let { injections, isDynamic } = injectionsFor( + this.container, + this.normalizedName + ); injectionsCache = injections; if (!isDynamic) { this.injections = injections; @@ -418,9 +458,15 @@ class FactoryManager { let lazyInjections; let validationCache = this.container.validationCache; // Ensure that all lazy injections are valid at instantiation time - if (!validationCache[this.fullName] && this.class && typeof this.class._lazyInjections === 'function') { + if ( + !validationCache[this.fullName] && + this.class && + typeof this.class._lazyInjections === 'function' + ) { lazyInjections = this.class._lazyInjections(); - lazyInjections = this.container.registry.normalizeInjectionsHash(lazyInjections); + lazyInjections = this.container.registry.normalizeInjectionsHash( + lazyInjections + ); this.container.registry.validateInjections(lazyInjections); } @@ -429,7 +475,12 @@ class FactoryManager { } if (!this.class.create) { - throw new Error(`Failed to create an instance of '${this.normalizedName}'. Most likely an improperly defined class or` + ` an invalid module export.`); + throw new Error( + `Failed to create an instance of '${ + this.normalizedName + }'. Most likely an improperly defined class or` + + ` an invalid module export.` + ); } // required to allow access to things like diff --git a/packages/container/lib/index.js b/packages/container/lib/index.js index 06d441265b2..36e0aca59d7 100644 --- a/packages/container/lib/index.js +++ b/packages/container/lib/index.js @@ -6,7 +6,4 @@ The public API, specified on the application namespace should be considered the */ export { default as Registry, privatize } from './registry'; -export { - default as Container, - FACTORY_FOR, -} from './container'; +export { default as Container, FACTORY_FOR } from './container'; diff --git a/packages/container/lib/registry.js b/packages/container/lib/registry.js index 664b1698fa4..cff11459cb0 100644 --- a/packages/container/lib/registry.js +++ b/packages/container/lib/registry.js @@ -5,7 +5,8 @@ import { DEBUG } from 'ember-env-flags'; import { ENV } from 'ember-environment'; const VALID_FULL_NAME_REGEXP = /^[^:]+:[^:]+$/; -const missingResolverFunctionsDeprecation = 'Passing a `resolver` function into a Registry is deprecated. Please pass in a Resolver object with a `resolve` method.'; +const missingResolverFunctionsDeprecation = + 'Passing a `resolver` function into a Registry is deprecated. Please pass in a Resolver object with a `resolve` method.'; /** A registry used to store factory and option information keyed @@ -32,22 +33,25 @@ export default class Registry { ); } - if (typeof this.resolver === 'function' && ENV._ENABLE_RESOLVER_FUNCTION_SUPPORT === true) { + if ( + typeof this.resolver === 'function' && + ENV._ENABLE_RESOLVER_FUNCTION_SUPPORT === true + ) { deprecateResolverFunction(this); } this.registrations = dictionary(options.registrations || null); - this._typeInjections = dictionary(null); - this._injections = dictionary(null); + this._typeInjections = dictionary(null); + this._injections = dictionary(null); - this._localLookupCache = Object.create(null); - this._normalizeCache = dictionary(null); - this._resolveCache = dictionary(null); - this._failSet = new Set(); + this._localLookupCache = Object.create(null); + this._normalizeCache = dictionary(null); + this._resolveCache = dictionary(null); + this._failSet = new Set(); - this._options = dictionary(null); - this._typeOptions = dictionary(null); + this._options = dictionary(null); + this._typeOptions = dictionary(null); } /** @@ -146,11 +150,20 @@ export default class Registry { @param {Object} options */ register(fullName, factory, options = {}) { - assert('fullName must be a proper full name', this.isValidFullName(fullName)); - assert(`Attempting to register an unknown factory: '${fullName}'`, factory !== undefined); + assert( + 'fullName must be a proper full name', + this.isValidFullName(fullName) + ); + assert( + `Attempting to register an unknown factory: '${fullName}'`, + factory !== undefined + ); let normalizedName = this.normalize(fullName); - assert(`Cannot re-register: '${fullName}', as it has already been resolved.`, !this._resolveCache[normalizedName]); + assert( + `Cannot re-register: '${fullName}', as it has already been resolved.`, + !this._resolveCache[normalizedName] + ); this._failSet.delete(normalizedName); this.registrations[normalizedName] = factory; @@ -175,7 +188,10 @@ export default class Registry { @param {String} fullName */ unregister(fullName) { - assert('fullName must be a proper full name', this.isValidFullName(fullName)); + assert( + 'fullName must be a proper full name', + this.isValidFullName(fullName) + ); let normalizedName = this.normalize(fullName); @@ -280,9 +296,10 @@ export default class Registry { @return {string} normalized fullName */ normalize(fullName) { - return this._normalizeCache[fullName] || ( - (this._normalizeCache[fullName] = this.normalizeFullName(fullName)) - ); + return ( + this._normalizeCache[fullName] || + (this._normalizeCache[fullName] = this.normalizeFullName(fullName)) + ); } /** @@ -441,13 +458,19 @@ export default class Registry { @param {String} fullName */ typeInjection(type, property, fullName) { - assert('fullName must be a proper full name', this.isValidFullName(fullName)); + assert( + 'fullName must be a proper full name', + this.isValidFullName(fullName) + ); let fullNameType = fullName.split(':')[0]; - assert(`Cannot inject a '${fullName}' on other ${type}(s).`, fullNameType !== type); + assert( + `Cannot inject a '${fullName}' on other ${type}(s).`, + fullNameType !== type + ); - let injections = this._typeInjections[type] || - (this._typeInjections[type] = []); + let injections = + this._typeInjections[type] || (this._typeInjections[type] = []); injections.push({ property, specifier: fullName }); } @@ -499,7 +522,10 @@ export default class Registry { @param {String} injectionName */ injection(fullName, property, injectionName) { - assert(`Invalid injectionName, expected: 'type:name' got: ${injectionName}`, this.isValidFullName(injectionName)); + assert( + `Invalid injectionName, expected: 'type:name' got: ${injectionName}`, + this.isValidFullName(injectionName) + ); let normalizedInjectionName = this.normalize(injectionName); @@ -507,11 +533,15 @@ export default class Registry { return this.typeInjection(fullName, property, normalizedInjectionName); } - assert('fullName must be a proper full name', this.isValidFullName(fullName)); + assert( + 'fullName must be a proper full name', + this.isValidFullName(fullName) + ); let normalizedName = this.normalize(fullName); - let injections = this._injections[normalizedName] || - (this._injections[normalizedName] = []); + let injections = + this._injections[normalizedName] || + (this._injections[normalizedName] = []); injections.push({ property, specifier: normalizedInjectionName }); } @@ -555,7 +585,10 @@ export default class Registry { let fallbackInjections = this.fallback.getInjections(fullName); if (fallbackInjections !== undefined) { - injections = injections === undefined ? fallbackInjections : injections.concat(fallbackInjections); + injections = + injections === undefined + ? fallbackInjections + : injections.concat(fallbackInjections); } } @@ -568,7 +601,10 @@ export default class Registry { let fallbackInjections = this.fallback.getTypeInjections(type); if (fallbackInjections !== undefined) { - injections = injections === undefined ? fallbackInjections : injections.concat(fallbackInjections); + injections = + injections === undefined + ? fallbackInjections + : injections.concat(fallbackInjections); } } @@ -595,13 +631,24 @@ export default class Registry { */ expandLocalLookup(fullName, options) { if (this.resolver !== null && this.resolver.expandLocalLookup) { - assert('fullName must be a proper full name', this.isValidFullName(fullName)); - assert('options.source must be a proper full name', !options.source || this.isValidFullName(options.source)); + assert( + 'fullName must be a proper full name', + this.isValidFullName(fullName) + ); + assert( + 'options.source must be a proper full name', + !options.source || this.isValidFullName(options.source) + ); let normalizedFullName = this.normalize(fullName); let normalizedSource = this.normalize(options.source); - return expandLocalLookup(this, normalizedFullName, normalizedSource, options.namespace); + return expandLocalLookup( + this, + normalizedFullName, + normalizedSource, + options.namespace + ); } else if (this.fallback !== null) { return this.fallback.expandLocalLookup(fullName, options); } else { @@ -611,11 +658,12 @@ export default class Registry { } function deprecateResolverFunction(registry) { - deprecate( - missingResolverFunctionsDeprecation, - false, - { id: 'ember-application.registry-resolver-as-function', until: '3.0.0', url: 'https://emberjs.com/deprecations/v2.x#toc_registry-resolver-as-function' } - ); + deprecate(missingResolverFunctionsDeprecation, false, { + id: 'ember-application.registry-resolver-as-function', + until: '3.0.0', + url: + 'https://emberjs.com/deprecations/v2.x#toc_registry-resolver-as-function' + }); registry.resolver = { resolve: registry.resolver }; } @@ -626,7 +674,10 @@ if (DEBUG) { for (let key in hash) { if (hash.hasOwnProperty(key)) { let { specifier, source, namespace } = hash[key]; - assert(`Expected a proper full name, given '${specifier}'`, this.isValidFullName(specifier)); + assert( + `Expected a proper full name, given '${specifier}'`, + this.isValidFullName(specifier) + ); injections.push({ property: key, @@ -641,17 +692,27 @@ if (DEBUG) { }; Registry.prototype.validateInjections = function(injections) { - if (!injections) { return; } + if (!injections) { + return; + } for (let i = 0; i < injections.length; i++) { - let {specifier, source, namespace} = injections[i]; + let { specifier, source, namespace } = injections[i]; - assert(`Attempting to inject an unknown injection: '${specifier}'`, this.has(specifier, {source, namespace})); + assert( + `Attempting to inject an unknown injection: '${specifier}'`, + this.has(specifier, { source, namespace }) + ); } }; } -function expandLocalLookup(registry, normalizedName, normalizedSource, namespace) { +function expandLocalLookup( + registry, + normalizedName, + normalizedSource, + namespace +) { let cache = registry._localLookupCache; let normalizedNameCache = cache[normalizedName]; @@ -663,11 +724,17 @@ function expandLocalLookup(registry, normalizedName, normalizedSource, namespace let cached = normalizedNameCache[cacheKey]; - if (cached !== undefined) { return cached; } + if (cached !== undefined) { + return cached; + } - let expanded = registry.resolver.expandLocalLookup(normalizedName, normalizedSource, namespace); + let expanded = registry.resolver.expandLocalLookup( + normalizedName, + normalizedSource, + namespace + ); - return normalizedNameCache[cacheKey] = expanded; + return (normalizedNameCache[cacheKey] = expanded); } function resolve(registry, _normalizedName, options) { @@ -682,8 +749,12 @@ function resolve(registry, _normalizedName, options) { } let cached = registry._resolveCache[normalizedName]; - if (cached !== undefined) { return cached; } - if (registry._failSet.has(normalizedName)) { return; } + if (cached !== undefined) { + return cached; + } + if (registry._failSet.has(normalizedName)) { + return; + } let resolved; @@ -713,8 +784,12 @@ const privateSuffix = `${Math.random()}${Date.now()}`.replace('.', ''); export function privatize([fullName]) { let name = privateNames[fullName]; - if (name) { return name; } + if (name) { + return name; + } let [type, rawName] = fullName.split(':'); - return privateNames[fullName] = intern(`${type}:${rawName}-${privateSuffix}`); + return (privateNames[fullName] = intern( + `${type}:${rawName}-${privateSuffix}` + )); } diff --git a/packages/container/tests/container_test.js b/packages/container/tests/container_test.js index a8dd24460df..9c8aa332255 100644 --- a/packages/container/tests/container_test.js +++ b/packages/container/tests/container_test.js @@ -3,749 +3,909 @@ import { EMBER_MODULE_UNIFICATION } from 'ember/features'; import { Registry } from '..'; import { factory, moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('Container', class extends AbstractTestCase { - ['@test A registered factory returns the same instance each time'](assert) { - let registry = new Registry(); - let container = registry.container(); - let PostController = factory(); - - registry.register('controller:post', PostController); - - let postController = container.lookup('controller:post'); - - assert.ok(postController instanceof PostController, 'The lookup is an instance of the factory'); - - assert.equal(postController, container.lookup('controller:post')); - } - - ['@test uses create time injections if factory has no extend'](assert) { - let registry = new Registry(); - let container = registry.container(); - let AppleController = factory(); - let PostController = factory(); - - PostController.extend = undefined; // remove extend - - registry.register('controller:apple', AppleController); - registry.register('controller:post', PostController); - registry.injection('controller:post', 'apple', 'controller:apple'); +moduleFor( + 'Container', + class extends AbstractTestCase { + ['@test A registered factory returns the same instance each time'](assert) { + let registry = new Registry(); + let container = registry.container(); + let PostController = factory(); - let postController = container.lookup('controller:post'); + registry.register('controller:post', PostController); - assert.ok(postController.apple instanceof AppleController, 'instance receives an apple of instance AppleController'); - } + let postController = container.lookup('controller:post'); - ['@test A registered factory returns a fresh instance if singleton: false is passed as an option'](assert) { - let registry = new Registry(); - let container = registry.container(); - let PostController = factory(); + assert.ok( + postController instanceof PostController, + 'The lookup is an instance of the factory' + ); - registry.register('controller:post', PostController); + assert.equal(postController, container.lookup('controller:post')); + } - let postController1 = container.lookup('controller:post'); - let postController2 = container.lookup('controller:post', { singleton: false }); - let postController3 = container.lookup('controller:post', { singleton: false }); - let postController4 = container.lookup('controller:post'); + ['@test uses create time injections if factory has no extend'](assert) { + let registry = new Registry(); + let container = registry.container(); + let AppleController = factory(); + let PostController = factory(); - assert.equal(postController1.toString(), postController4.toString(), 'Singleton factories looked up normally return the same value'); - assert.notEqual(postController1.toString(), postController2.toString(), 'Singleton factories are not equal to factories looked up with singleton: false'); - assert.notEqual(postController2.toString(), postController3.toString(), 'Two factories looked up with singleton: false are not equal'); - assert.notEqual(postController3.toString(), postController4.toString(), 'A singleton factory looked up after a factory called with singleton: false is not equal'); + PostController.extend = undefined; // remove extend - assert.ok(postController1 instanceof PostController, 'All instances are instances of the registered factory'); - assert.ok(postController2 instanceof PostController, 'All instances are instances of the registered factory'); - assert.ok(postController3 instanceof PostController, 'All instances are instances of the registered factory'); - assert.ok(postController4 instanceof PostController, 'All instances are instances of the registered factory'); - } + registry.register('controller:apple', AppleController); + registry.register('controller:post', PostController); + registry.injection('controller:post', 'apple', 'controller:apple'); - ['@test A factory type with a registered injection\'s instances receive that injection'](assert) { - let registry = new Registry(); - let container = registry.container(); - let PostController = factory(); - let Store = factory(); + let postController = container.lookup('controller:post'); - registry.register('controller:post', PostController); - registry.register('store:main', Store); + assert.ok( + postController.apple instanceof AppleController, + 'instance receives an apple of instance AppleController' + ); + } - registry.typeInjection('controller', 'store', 'store:main'); + ['@test A registered factory returns a fresh instance if singleton: false is passed as an option']( + assert + ) { + let registry = new Registry(); + let container = registry.container(); + let PostController = factory(); + + registry.register('controller:post', PostController); + + let postController1 = container.lookup('controller:post'); + let postController2 = container.lookup('controller:post', { + singleton: false + }); + let postController3 = container.lookup('controller:post', { + singleton: false + }); + let postController4 = container.lookup('controller:post'); + + assert.equal( + postController1.toString(), + postController4.toString(), + 'Singleton factories looked up normally return the same value' + ); + assert.notEqual( + postController1.toString(), + postController2.toString(), + 'Singleton factories are not equal to factories looked up with singleton: false' + ); + assert.notEqual( + postController2.toString(), + postController3.toString(), + 'Two factories looked up with singleton: false are not equal' + ); + assert.notEqual( + postController3.toString(), + postController4.toString(), + 'A singleton factory looked up after a factory called with singleton: false is not equal' + ); + + assert.ok( + postController1 instanceof PostController, + 'All instances are instances of the registered factory' + ); + assert.ok( + postController2 instanceof PostController, + 'All instances are instances of the registered factory' + ); + assert.ok( + postController3 instanceof PostController, + 'All instances are instances of the registered factory' + ); + assert.ok( + postController4 instanceof PostController, + 'All instances are instances of the registered factory' + ); + } - let postController = container.lookup('controller:post'); - let store = container.lookup('store:main'); + ["@test A factory type with a registered injection's instances receive that injection"]( + assert + ) { + let registry = new Registry(); + let container = registry.container(); + let PostController = factory(); + let Store = factory(); - assert.equal(postController.store, store); - } + registry.register('controller:post', PostController); + registry.register('store:main', Store); - ['@test An individual factory with a registered injection receives the injection'](assert) { - let registry = new Registry(); - let container = registry.container(); - let PostController = factory(); - let Store = factory(); + registry.typeInjection('controller', 'store', 'store:main'); - registry.register('controller:post', PostController); - registry.register('store:main', Store); + let postController = container.lookup('controller:post'); + let store = container.lookup('store:main'); - registry.injection('controller:post', 'store', 'store:main'); + assert.equal(postController.store, store); + } - let postController = container.lookup('controller:post'); - let store = container.lookup('store:main'); + ['@test An individual factory with a registered injection receives the injection']( + assert + ) { + let registry = new Registry(); + let container = registry.container(); + let PostController = factory(); + let Store = factory(); - assert.equal(postController.store, store, 'has the correct store injected'); - } + registry.register('controller:post', PostController); + registry.register('store:main', Store); - ['@test A factory with both type and individual injections'](assert) { - let registry = new Registry(); - let container = registry.container(); - let PostController = factory(); - let Store = factory(); - let Router = factory(); + registry.injection('controller:post', 'store', 'store:main'); - registry.register('controller:post', PostController); - registry.register('store:main', Store); - registry.register('router:main', Router); + let postController = container.lookup('controller:post'); + let store = container.lookup('store:main'); - registry.injection('controller:post', 'store', 'store:main'); - registry.typeInjection('controller', 'router', 'router:main'); + assert.equal( + postController.store, + store, + 'has the correct store injected' + ); + } - let postController = container.lookup('controller:post'); - let store = container.lookup('store:main'); - let router = container.lookup('router:main'); + ['@test A factory with both type and individual injections'](assert) { + let registry = new Registry(); + let container = registry.container(); + let PostController = factory(); + let Store = factory(); + let Router = factory(); - assert.equal(postController.store, store); - assert.equal(postController.router, router); - } + registry.register('controller:post', PostController); + registry.register('store:main', Store); + registry.register('router:main', Router); - ['@test A non-singleton instance is never cached'](assert) { - let registry = new Registry(); - let container = registry.container(); - let PostView = factory(); + registry.injection('controller:post', 'store', 'store:main'); + registry.typeInjection('controller', 'router', 'router:main'); - registry.register('view:post', PostView, { singleton: false }); + let postController = container.lookup('controller:post'); + let store = container.lookup('store:main'); + let router = container.lookup('router:main'); - let postView1 = container.lookup('view:post'); - let postView2 = container.lookup('view:post'); + assert.equal(postController.store, store); + assert.equal(postController.router, router); + } - assert.ok(postView1 !== postView2, 'Non-singletons are not cached'); - } + ['@test A non-singleton instance is never cached'](assert) { + let registry = new Registry(); + let container = registry.container(); + let PostView = factory(); - ['@test A non-instantiated property is not instantiated'](assert) { - let registry = new Registry(); - let container = registry.container(); + registry.register('view:post', PostView, { singleton: false }); - let template = function() {}; - registry.register('template:foo', template, { instantiate: false }); - assert.equal(container.lookup('template:foo'), template); - } + let postView1 = container.lookup('view:post'); + let postView2 = container.lookup('view:post'); - ['@test A failed lookup returns undefined'](assert) { - let registry = new Registry(); - let container = registry.container(); + assert.ok(postView1 !== postView2, 'Non-singletons are not cached'); + } - assert.equal(container.lookup('doesnot:exist'), undefined); - } + ['@test A non-instantiated property is not instantiated'](assert) { + let registry = new Registry(); + let container = registry.container(); - ['@test An invalid factory throws an error'](assert) { - let registry = new Registry(); - let container = registry.container(); + let template = function() {}; + registry.register('template:foo', template, { instantiate: false }); + assert.equal(container.lookup('template:foo'), template); + } - registry.register('controller:foo', {}); + ['@test A failed lookup returns undefined'](assert) { + let registry = new Registry(); + let container = registry.container(); - assert.throws(() => { - container.lookup('controller:foo'); - }, /Failed to create an instance of \'controller:foo\'/); - } + assert.equal(container.lookup('doesnot:exist'), undefined); + } - ['@test Injecting a failed lookup raises an error'](assert) { - let registry = new Registry(); - let container = registry.container(); + ['@test An invalid factory throws an error'](assert) { + let registry = new Registry(); + let container = registry.container(); - let fooInstance = {}; - let fooFactory = {}; + registry.register('controller:foo', {}); + assert.throws(() => { + container.lookup('controller:foo'); + }, /Failed to create an instance of \'controller:foo\'/); + } - let Foo = { - create() { return fooInstance; }, - extend() { return fooFactory; } - }; + ['@test Injecting a failed lookup raises an error'](assert) { + let registry = new Registry(); + let container = registry.container(); - registry.register('model:foo', Foo); - registry.injection('model:foo', 'store', 'store:main'); + let fooInstance = {}; + let fooFactory = {}; - assert.throws(() => { - container.lookup('model:foo'); - }); - } + let Foo = { + create() { + return fooInstance; + }, + extend() { + return fooFactory; + } + }; - ['@test Injecting a falsy value does not raise an error'](assert) { - let registry = new Registry(); - let container = registry.container(); - let ApplicationController = factory(); + registry.register('model:foo', Foo); + registry.injection('model:foo', 'store', 'store:main'); - registry.register('controller:application', ApplicationController); - registry.register('user:current', null, { instantiate: false }); - registry.injection('controller:application', 'currentUser', 'user:current'); + assert.throws(() => { + container.lookup('model:foo'); + }); + } - assert.strictEqual(container.lookup('controller:application').currentUser, null); - } + ['@test Injecting a falsy value does not raise an error'](assert) { + let registry = new Registry(); + let container = registry.container(); + let ApplicationController = factory(); + + registry.register('controller:application', ApplicationController); + registry.register('user:current', null, { instantiate: false }); + registry.injection( + 'controller:application', + 'currentUser', + 'user:current' + ); + + assert.strictEqual( + container.lookup('controller:application').currentUser, + null + ); + } - ['@test The container returns same value each time even if the value is falsy'](assert) { - let registry = new Registry(); - let container = registry.container(); + ['@test The container returns same value each time even if the value is falsy']( + assert + ) { + let registry = new Registry(); + let container = registry.container(); - registry.register('falsy:value', null, { instantiate: false }); + registry.register('falsy:value', null, { instantiate: false }); - assert.strictEqual(container.lookup('falsy:value'), container.lookup('falsy:value')); - } + assert.strictEqual( + container.lookup('falsy:value'), + container.lookup('falsy:value') + ); + } - ['@test Destroying the container destroys any cached singletons'](assert) { - let registry = new Registry(); - let container = registry.container(); - let PostController = factory(); - let PostView = factory(); - let template = function() {}; + ['@test Destroying the container destroys any cached singletons'](assert) { + let registry = new Registry(); + let container = registry.container(); + let PostController = factory(); + let PostView = factory(); + let template = function() {}; - registry.register('controller:post', PostController); - registry.register('view:post', PostView, { singleton: false }); - registry.register('template:post', template, { instantiate: false }); + registry.register('controller:post', PostController); + registry.register('view:post', PostView, { singleton: false }); + registry.register('template:post', template, { instantiate: false }); - registry.injection('controller:post', 'postView', 'view:post'); + registry.injection('controller:post', 'postView', 'view:post'); - let postController = container.lookup('controller:post'); - let postView = postController.postView; + let postController = container.lookup('controller:post'); + let postView = postController.postView; - assert.ok(postView instanceof PostView, 'The non-singleton was injected'); + assert.ok(postView instanceof PostView, 'The non-singleton was injected'); - container.destroy(); + container.destroy(); - assert.ok(postController.isDestroyed, 'Singletons are destroyed'); - assert.ok(!postView.isDestroyed, 'Non-singletons are not destroyed'); - } + assert.ok(postController.isDestroyed, 'Singletons are destroyed'); + assert.ok(!postView.isDestroyed, 'Non-singletons are not destroyed'); + } - ['@test The container can use a registry hook to resolve factories lazily'](assert) { - let registry = new Registry(); - let container = registry.container(); - let PostController = factory(); + ['@test The container can use a registry hook to resolve factories lazily']( + assert + ) { + let registry = new Registry(); + let container = registry.container(); + let PostController = factory(); - registry.resolver = { - resolve(fullName) { - if (fullName === 'controller:post') { - return PostController; + registry.resolver = { + resolve(fullName) { + if (fullName === 'controller:post') { + return PostController; + } } - } - }; + }; - let postController = container.lookup('controller:post'); + let postController = container.lookup('controller:post'); - assert.ok(postController instanceof PostController, 'The correct factory was provided'); - } + assert.ok( + postController instanceof PostController, + 'The correct factory was provided' + ); + } - ['@test The container normalizes names before resolving'](assert) { - let registry = new Registry(); - let container = registry.container(); - let PostController = factory(); + ['@test The container normalizes names before resolving'](assert) { + let registry = new Registry(); + let container = registry.container(); + let PostController = factory(); - registry.normalizeFullName = function() { - return 'controller:post'; - }; + registry.normalizeFullName = function() { + return 'controller:post'; + }; - registry.register('controller:post', PostController); - let postController = container.lookup('controller:normalized'); + registry.register('controller:post', PostController); + let postController = container.lookup('controller:normalized'); - assert.ok(postController instanceof PostController, 'Normalizes the name before resolving'); - } + assert.ok( + postController instanceof PostController, + 'Normalizes the name before resolving' + ); + } - ['@test The container normalizes names when looking factory up'](assert) { - let registry = new Registry(); - let container = registry.container(); - let PostController = factory(); + ['@test The container normalizes names when looking factory up'](assert) { + let registry = new Registry(); + let container = registry.container(); + let PostController = factory(); - registry.normalizeFullName = function() { - return 'controller:post'; - }; + registry.normalizeFullName = function() { + return 'controller:post'; + }; - registry.register('controller:post', PostController); - let fact = container.factoryFor('controller:normalized'); + registry.register('controller:post', PostController); + let fact = container.factoryFor('controller:normalized'); - let factInstance = fact.create(); - assert.ok(factInstance instanceof PostController, 'Normalizes the name'); - } + let factInstance = fact.create(); + assert.ok(factInstance instanceof PostController, 'Normalizes the name'); + } - ['@test Options can be registered that should be applied to a given factory'](assert) { - let registry = new Registry(); - let container = registry.container(); - let PostView = factory(); + ['@test Options can be registered that should be applied to a given factory']( + assert + ) { + let registry = new Registry(); + let container = registry.container(); + let PostView = factory(); - registry.resolver = { - resolve(fullName) { - if (fullName === 'view:post') { - return PostView; + registry.resolver = { + resolve(fullName) { + if (fullName === 'view:post') { + return PostView; + } } - } - }; + }; - registry.options('view:post', { instantiate: true, singleton: false }); + registry.options('view:post', { instantiate: true, singleton: false }); - let postView1 = container.lookup('view:post'); - let postView2 = container.lookup('view:post'); + let postView1 = container.lookup('view:post'); + let postView2 = container.lookup('view:post'); - assert.ok(postView1 instanceof PostView, 'The correct factory was provided'); - assert.ok(postView2 instanceof PostView, 'The correct factory was provided'); + assert.ok( + postView1 instanceof PostView, + 'The correct factory was provided' + ); + assert.ok( + postView2 instanceof PostView, + 'The correct factory was provided' + ); - assert.ok(postView1 !== postView2, 'The two lookups are different'); - } + assert.ok(postView1 !== postView2, 'The two lookups are different'); + } - ['@test Options can be registered that should be applied to all factories for a given type'](assert) { - let registry = new Registry(); - let container = registry.container(); - let PostView = factory(); + ['@test Options can be registered that should be applied to all factories for a given type']( + assert + ) { + let registry = new Registry(); + let container = registry.container(); + let PostView = factory(); - registry.resolver = { - resolve(fullName) { - if (fullName === 'view:post') { - return PostView; + registry.resolver = { + resolve(fullName) { + if (fullName === 'view:post') { + return PostView; + } } - } - }; - - registry.optionsForType('view', { singleton: false }); - - let postView1 = container.lookup('view:post'); - let postView2 = container.lookup('view:post'); - - assert.ok(postView1 instanceof PostView, 'The correct factory was provided'); - assert.ok(postView2 instanceof PostView, 'The correct factory was provided'); - - assert.ok(postView1 !== postView2, 'The two lookups are different'); - } + }; - ['@test An injected non-singleton instance is never cached'](assert) { - let registry = new Registry(); - let container = registry.container(); - let PostView = factory(); - let PostViewHelper = factory(); + registry.optionsForType('view', { singleton: false }); - registry.register('view:post', PostView, { singleton: false }); - registry.register('view_helper:post', PostViewHelper, { singleton: false }); - registry.injection('view:post', 'viewHelper', 'view_helper:post'); + let postView1 = container.lookup('view:post'); + let postView2 = container.lookup('view:post'); - let postView1 = container.lookup('view:post'); - let postView2 = container.lookup('view:post'); + assert.ok( + postView1 instanceof PostView, + 'The correct factory was provided' + ); + assert.ok( + postView2 instanceof PostView, + 'The correct factory was provided' + ); - assert.ok(postView1.viewHelper !== postView2.viewHelper, 'Injected non-singletons are not cached'); - } + assert.ok(postView1 !== postView2, 'The two lookups are different'); + } - ['@test Factory resolves are cached'](assert) { - let registry = new Registry(); - let container = registry.container(); - let PostController = factory(); - let resolveWasCalled = []; - registry.resolve = function(fullName) { - resolveWasCalled.push(fullName); - return PostController; - }; - - assert.deepEqual(resolveWasCalled, []); - container.factoryFor('controller:post'); - assert.deepEqual(resolveWasCalled, ['controller:post']); - - container.factoryFor('controller:post'); - assert.deepEqual(resolveWasCalled, ['controller:post']); - } + ['@test An injected non-singleton instance is never cached'](assert) { + let registry = new Registry(); + let container = registry.container(); + let PostView = factory(); + let PostViewHelper = factory(); + + registry.register('view:post', PostView, { singleton: false }); + registry.register('view_helper:post', PostViewHelper, { + singleton: false + }); + registry.injection('view:post', 'viewHelper', 'view_helper:post'); + + let postView1 = container.lookup('view:post'); + let postView2 = container.lookup('view:post'); + + assert.ok( + postView1.viewHelper !== postView2.viewHelper, + 'Injected non-singletons are not cached' + ); + } - ['@test factory for non extendables (MODEL) resolves are cached'](assert) { - let registry = new Registry(); - let container = registry.container(); - let PostController = factory(); - let resolveWasCalled = []; - registry.resolve = function(fullName) { - resolveWasCalled.push(fullName); - return PostController; - }; - - assert.deepEqual(resolveWasCalled, []); - container.factoryFor('model:post'); - assert.deepEqual(resolveWasCalled, ['model:post']); - - container.factoryFor('model:post'); - assert.deepEqual(resolveWasCalled, ['model:post']); - } + ['@test Factory resolves are cached'](assert) { + let registry = new Registry(); + let container = registry.container(); + let PostController = factory(); + let resolveWasCalled = []; + registry.resolve = function(fullName) { + resolveWasCalled.push(fullName); + return PostController; + }; - ['@test factory for non extendables resolves are cached'](assert) { - let registry = new Registry(); - let container = registry.container(); - let PostController = {}; - let resolveWasCalled = []; + assert.deepEqual(resolveWasCalled, []); + container.factoryFor('controller:post'); + assert.deepEqual(resolveWasCalled, ['controller:post']); - registry.resolve = function(fullName) { - resolveWasCalled.push(fullName); - return PostController; - }; + container.factoryFor('controller:post'); + assert.deepEqual(resolveWasCalled, ['controller:post']); + } - assert.deepEqual(resolveWasCalled, []); - container.factoryFor('foo:post'); - assert.deepEqual(resolveWasCalled, ['foo:post']); + ['@test factory for non extendables (MODEL) resolves are cached'](assert) { + let registry = new Registry(); + let container = registry.container(); + let PostController = factory(); + let resolveWasCalled = []; + registry.resolve = function(fullName) { + resolveWasCalled.push(fullName); + return PostController; + }; - container.factoryFor('foo:post'); - assert.deepEqual(resolveWasCalled, ['foo:post']); - } + assert.deepEqual(resolveWasCalled, []); + container.factoryFor('model:post'); + assert.deepEqual(resolveWasCalled, ['model:post']); - [`@test A factory's lazy injections are validated when first instantiated`](assert) { - let registry = new Registry(); - let container = registry.container(); - let Apple = factory(); - let Orange = factory(); - - Apple.reopenClass({ - _lazyInjections() { - return [ - {specifier: 'orange:main'}, - {specifier: 'banana:main'} - ]; - } - }); + container.factoryFor('model:post'); + assert.deepEqual(resolveWasCalled, ['model:post']); + } - registry.register('apple:main', Apple); - registry.register('orange:main', Orange); + ['@test factory for non extendables resolves are cached'](assert) { + let registry = new Registry(); + let container = registry.container(); + let PostController = {}; + let resolveWasCalled = []; - assert.throws(() => { - container.lookup('apple:main'); - }, /Attempting to inject an unknown injection: 'banana:main'/); - } + registry.resolve = function(fullName) { + resolveWasCalled.push(fullName); + return PostController; + }; - ['@test Lazy injection validations are cached'](assert) { - assert.expect(1); + assert.deepEqual(resolveWasCalled, []); + container.factoryFor('foo:post'); + assert.deepEqual(resolveWasCalled, ['foo:post']); - let registry = new Registry(); - let container = registry.container(); - let Apple = factory(); - let Orange = factory(); + container.factoryFor('foo:post'); + assert.deepEqual(resolveWasCalled, ['foo:post']); + } - Apple.reopenClass({ - _lazyInjections: () => { - assert.ok(true, 'should call lazy injection method'); - return [ - {specifier: 'orange:main'} - ]; - } - }); + [`@test A factory's lazy injections are validated when first instantiated`]( + assert + ) { + let registry = new Registry(); + let container = registry.container(); + let Apple = factory(); + let Orange = factory(); - registry.register('apple:main', Apple); - registry.register('orange:main', Orange); + Apple.reopenClass({ + _lazyInjections() { + return [{ specifier: 'orange:main' }, { specifier: 'banana:main' }]; + } + }); - container.lookup('apple:main'); - container.lookup('apple:main'); - } + registry.register('apple:main', Apple); + registry.register('orange:main', Orange); - ['@test An object with its owner pre-set should be returned from ownerInjection'](assert) { - let owner = { }; - let registry = new Registry(); - let container = registry.container({ owner }); + assert.throws(() => { + container.lookup('apple:main'); + }, /Attempting to inject an unknown injection: 'banana:main'/); + } - let result = container.ownerInjection(); + ['@test Lazy injection validations are cached'](assert) { + assert.expect(1); - assert.equal(result[OWNER], owner, 'owner is properly included'); - } + let registry = new Registry(); + let container = registry.container(); + let Apple = factory(); + let Orange = factory(); - ['@test lookup passes options through to expandlocallookup'](assert) { - let registry = new Registry(); - let container = registry.container(); - let PostController = factory(); + Apple.reopenClass({ + _lazyInjections: () => { + assert.ok(true, 'should call lazy injection method'); + return [{ specifier: 'orange:main' }]; + } + }); - registry.register('controller:post', PostController); - registry.expandLocalLookup = (fullName, options) => { - assert.ok(true, 'expandLocalLookup was called'); - assert.equal(fullName, 'foo:bar'); - assert.deepEqual(options, { source: 'baz:qux' }); + registry.register('apple:main', Apple); + registry.register('orange:main', Orange); - return 'controller:post'; - }; + container.lookup('apple:main'); + container.lookup('apple:main'); + } - let PostControllerLookupResult = container.lookup('foo:bar', { source: 'baz:qux' }); + ['@test An object with its owner pre-set should be returned from ownerInjection']( + assert + ) { + let owner = {}; + let registry = new Registry(); + let container = registry.container({ owner }); - assert.ok(PostControllerLookupResult instanceof PostController); - } + let result = container.ownerInjection(); - ['@test #factoryFor class is registered class'](assert) { - let registry = new Registry(); - let container = registry.container(); + assert.equal(result[OWNER], owner, 'owner is properly included'); + } - let Component = factory(); - registry.register('component:foo-bar', Component); + ['@test lookup passes options through to expandlocallookup'](assert) { + let registry = new Registry(); + let container = registry.container(); + let PostController = factory(); - let factoryManager = container.factoryFor('component:foo-bar'); - assert.deepEqual(factoryManager.class, Component, 'No double extend'); - } + registry.register('controller:post', PostController); + registry.expandLocalLookup = (fullName, options) => { + assert.ok(true, 'expandLocalLookup was called'); + assert.equal(fullName, 'foo:bar'); + assert.deepEqual(options, { source: 'baz:qux' }); - ['@test #factoryFor must supply a fullname']() { - let registry = new Registry(); - let container = registry.container(); - expectAssertion(() => { - container.factoryFor('chad-bar'); - }, /fullName must be a proper full name/); - } + return 'controller:post'; + }; - ['@test #factoryFor returns a factory manager'](assert) { - let registry = new Registry(); - let container = registry.container(); + let PostControllerLookupResult = container.lookup('foo:bar', { + source: 'baz:qux' + }); - let Component = factory(); - registry.register('component:foo-bar', Component); + assert.ok(PostControllerLookupResult instanceof PostController); + } - let factoryManager = container.factoryFor('component:foo-bar'); - assert.ok(factoryManager.create); - assert.ok(factoryManager.class); - } + ['@test #factoryFor class is registered class'](assert) { + let registry = new Registry(); + let container = registry.container(); - ['@test #factoryFor returns a cached factory manager for the same type'](assert) { - let registry = new Registry(); - let container = registry.container(); + let Component = factory(); + registry.register('component:foo-bar', Component); - let Component = factory(); - registry.register('component:foo-bar', Component); - registry.register('component:baz-bar', Component); + let factoryManager = container.factoryFor('component:foo-bar'); + assert.deepEqual(factoryManager.class, Component, 'No double extend'); + } - let factoryManager1 = container.factoryFor('component:foo-bar'); - let factoryManager2 = container.factoryFor('component:foo-bar'); - let factoryManager3 = container.factoryFor('component:baz-bar'); + ['@test #factoryFor must supply a fullname']() { + let registry = new Registry(); + let container = registry.container(); + expectAssertion(() => { + container.factoryFor('chad-bar'); + }, /fullName must be a proper full name/); + } - assert.equal(factoryManager1, factoryManager2, 'cache hit'); - assert.notEqual(factoryManager1, factoryManager3, 'cache miss'); - } + ['@test #factoryFor returns a factory manager'](assert) { + let registry = new Registry(); + let container = registry.container(); - ['@test #factoryFor class returns the factory function'](assert) { - let registry = new Registry(); - let container = registry.container(); + let Component = factory(); + registry.register('component:foo-bar', Component); - let Component = factory(); - registry.register('component:foo-bar', Component); + let factoryManager = container.factoryFor('component:foo-bar'); + assert.ok(factoryManager.create); + assert.ok(factoryManager.class); + } - let factoryManager = container.factoryFor('component:foo-bar'); - assert.deepEqual(factoryManager.class, Component, 'No double extend'); - } + ['@test #factoryFor returns a cached factory manager for the same type']( + assert + ) { + let registry = new Registry(); + let container = registry.container(); - ['@test #factoryFor instance have a common parent'](assert) { - let registry = new Registry(); - let container = registry.container(); + let Component = factory(); + registry.register('component:foo-bar', Component); + registry.register('component:baz-bar', Component); - let Component = factory(); - registry.register('component:foo-bar', Component); + let factoryManager1 = container.factoryFor('component:foo-bar'); + let factoryManager2 = container.factoryFor('component:foo-bar'); + let factoryManager3 = container.factoryFor('component:baz-bar'); - let factoryManager1 = container.factoryFor('component:foo-bar'); - let factoryManager2 = container.factoryFor('component:foo-bar'); - let instance1 = factoryManager1.create({ foo: 'foo' }); - let instance2 = factoryManager2.create({ bar: 'bar' }); + assert.equal(factoryManager1, factoryManager2, 'cache hit'); + assert.notEqual(factoryManager1, factoryManager3, 'cache miss'); + } - assert.deepEqual(instance1.constructor, instance2.constructor); - } + ['@test #factoryFor class returns the factory function'](assert) { + let registry = new Registry(); + let container = registry.container(); - ['@test can properly reset cache'](assert) { - let registry = new Registry(); - let container = registry.container(); + let Component = factory(); + registry.register('component:foo-bar', Component); - let Component = factory(); - registry.register('component:foo-bar', Component); + let factoryManager = container.factoryFor('component:foo-bar'); + assert.deepEqual(factoryManager.class, Component, 'No double extend'); + } - let factory1 = container.factoryFor('component:foo-bar'); - let factory2 = container.factoryFor('component:foo-bar'); + ['@test #factoryFor instance have a common parent'](assert) { + let registry = new Registry(); + let container = registry.container(); - let instance1 = container.lookup('component:foo-bar'); - let instance2 = container.lookup('component:foo-bar'); + let Component = factory(); + registry.register('component:foo-bar', Component); - assert.equal(instance1, instance2); - assert.equal(factory1, factory2); + let factoryManager1 = container.factoryFor('component:foo-bar'); + let factoryManager2 = container.factoryFor('component:foo-bar'); + let instance1 = factoryManager1.create({ foo: 'foo' }); + let instance2 = factoryManager2.create({ bar: 'bar' }); - container.reset(); + assert.deepEqual(instance1.constructor, instance2.constructor); + } - let factory3 = container.factoryFor('component:foo-bar'); - let instance3 = container.lookup('component:foo-bar'); + ['@test can properly reset cache'](assert) { + let registry = new Registry(); + let container = registry.container(); - assert.notEqual(instance1, instance3); - assert.notEqual(factory1, factory3); - } + let Component = factory(); + registry.register('component:foo-bar', Component); - ['@test #factoryFor created instances come with instance injections'](assert) { - let registry = new Registry(); - let container = registry.container(); + let factory1 = container.factoryFor('component:foo-bar'); + let factory2 = container.factoryFor('component:foo-bar'); - let Component = factory(); - let Ajax = factory(); - registry.register('component:foo-bar', Component); - registry.register('util:ajax', Ajax); - registry.injection('component:foo-bar', 'ajax', 'util:ajax'); + let instance1 = container.lookup('component:foo-bar'); + let instance2 = container.lookup('component:foo-bar'); - let componentFactory = container.factoryFor('component:foo-bar'); - let component = componentFactory.create(); + assert.equal(instance1, instance2); + assert.equal(factory1, factory2); - assert.ok(component.ajax); - assert.ok(component.ajax instanceof Ajax); - } + container.reset(); - ['@test #factoryFor options passed to create clobber injections'](assert) { - let registry = new Registry(); - let container = registry.container(); + let factory3 = container.factoryFor('component:foo-bar'); + let instance3 = container.lookup('component:foo-bar'); - let Component = factory(); - let Ajax = factory(); - registry.register('component:foo-bar', Component); - registry.register('util:ajax', Ajax); - registry.injection('component:foo-bar', 'ajax', 'util:ajax'); + assert.notEqual(instance1, instance3); + assert.notEqual(factory1, factory3); + } - let componentFactory = container.factoryFor('component:foo-bar'); - let instrance = componentFactory.create({ ajax: 'fetch' }); + ['@test #factoryFor created instances come with instance injections']( + assert + ) { + let registry = new Registry(); + let container = registry.container(); - assert.equal(instrance.ajax, 'fetch'); - } + let Component = factory(); + let Ajax = factory(); + registry.register('component:foo-bar', Component); + registry.register('util:ajax', Ajax); + registry.injection('component:foo-bar', 'ajax', 'util:ajax'); - ['@test #factoryFor does not add properties to the object being instantiated when _initFactory is present'](assert) { - let registry = new Registry(); - let container = registry.container(); + let componentFactory = container.factoryFor('component:foo-bar'); + let component = componentFactory.create(); - class Component { - static _initFactory() {} - static create(options) { - let instance = new this(); - assign(instance, options); - return instance; - } + assert.ok(component.ajax); + assert.ok(component.ajax instanceof Ajax); } - registry.register('component:foo-bar', Component); - let componentFactory = container.factoryFor('component:foo-bar'); - let instance = componentFactory.create(); + ['@test #factoryFor options passed to create clobber injections'](assert) { + let registry = new Registry(); + let container = registry.container(); - // note: _guid and isDestroyed are being set in the `factory` constructor - // not via registry/container shenanigans - assert.deepEqual(Object.keys(instance), []); - } + let Component = factory(); + let Ajax = factory(); + registry.register('component:foo-bar', Component); + registry.register('util:ajax', Ajax); + registry.injection('component:foo-bar', 'ajax', 'util:ajax'); - // this is skipped until templates and the glimmer environment do not require `OWNER` to be - // passed in as constructor args - ['@skip #factoryFor does not add properties to the object being instantiated'](assert) { - let registry = new Registry(); - let container = registry.container(); - - class Component { - static create(options) { - let instance = new this(); - assign(instance, options); - return instance; - } - } - registry.register('component:foo-bar', Component); + let componentFactory = container.factoryFor('component:foo-bar'); + let instrance = componentFactory.create({ ajax: 'fetch' }); - let componentFactory = container.factoryFor('component:foo-bar'); - let instance = componentFactory.create(); + assert.equal(instrance.ajax, 'fetch'); + } - // note: _guid and isDestroyed are being set in the `factory` constructor - // not via registry/container shenanigans - assert.deepEqual(Object.keys(instance), []); - } -}); + ['@test #factoryFor does not add properties to the object being instantiated when _initFactory is present']( + assert + ) { + let registry = new Registry(); + let container = registry.container(); -if (EMBER_MODULE_UNIFICATION) { - moduleFor('Container module unification', class extends AbstractTestCase { - ['@test The container can expand and resolve a source to factoryFor'](assert) { - let PrivateComponent = factory(); - let lookup = 'component:my-input'; - let expectedSource = 'template:routes/application'; - let registry = new Registry(); - let resolveCount = 0; - let expandedKey = 'boom, special expanded key'; - registry.expandLocalLookup = (specifier, options) => { - this.assert.strictEqual(specifier, lookup, 'specifier is expanded'); - this.assert.strictEqual(options.source, expectedSource, 'source is expanded'); - return expandedKey; - }; - registry.resolve = function(fullName) { - resolveCount++; - if (fullName === expandedKey) { - return PrivateComponent; + class Component { + static _initFactory() {} + static create(options) { + let instance = new this(); + assign(instance, options); + return instance; } - }; + } + registry.register('component:foo-bar', Component); - let container = registry.container(); + let componentFactory = container.factoryFor('component:foo-bar'); + let instance = componentFactory.create(); - assert.strictEqual(container.factoryFor(lookup, { source: expectedSource }).class, PrivateComponent, 'The correct factory was provided'); - assert.strictEqual(container.factoryFor(lookup, { source: expectedSource }).class, PrivateComponent, 'The correct factory was provided again'); - assert.equal(resolveCount, 1, 'resolve called only once and a cached factory was returned the second time'); + // note: _guid and isDestroyed are being set in the `factory` constructor + // not via registry/container shenanigans + assert.deepEqual(Object.keys(instance), []); } - ['@test The container can expand and resolve a source to lookup']() { - let PrivateComponent = factory(); - let lookup = 'component:my-input'; - let expectedSource = 'template:routes/application'; + // this is skipped until templates and the glimmer environment do not require `OWNER` to be + // passed in as constructor args + ['@skip #factoryFor does not add properties to the object being instantiated']( + assert + ) { let registry = new Registry(); - let expandedKey = 'boom, special expanded key'; - registry.expandLocalLookup = (specifier, options) => { - this.assert.strictEqual(specifier, lookup, 'specifier is expanded'); - this.assert.strictEqual(options.source, expectedSource, 'source is expanded'); - return expandedKey; - }; - registry.resolve = function(fullName) { - if (fullName === expandedKey) { - return PrivateComponent; - } - }; - let container = registry.container(); - let result = container.lookup(lookup, { source: expectedSource }); - this.assert.ok(result instanceof PrivateComponent, 'The correct factory was provided'); - - this.assert.ok(container.cache[expandedKey] instanceof PrivateComponent, - 'The correct factory was stored in the cache with the correct key which includes the source.'); - } - - ['@test The container can expand and resolve a namespace to factoryFor'](assert) { - let PrivateComponent = factory(); - let lookup = 'component:my-input'; - let expectedNamespace = 'my-addon'; - let registry = new Registry(); - let resolveCount = 0; - let expandedKey = 'boom, special expanded key'; - registry.expandLocalLookup = (specifier, options) => { - this.assert.strictEqual(specifier, lookup, 'specifier is expanded'); - this.assert.strictEqual(options.namespace, expectedNamespace, 'namespace is expanded'); - return expandedKey; - }; - registry.resolve = function(fullName) { - resolveCount++; - if (fullName === expandedKey) { - return PrivateComponent; + class Component { + static create(options) { + let instance = new this(); + assign(instance, options); + return instance; } - }; + } + registry.register('component:foo-bar', Component); - let container = registry.container(); + let componentFactory = container.factoryFor('component:foo-bar'); + let instance = componentFactory.create(); - assert.strictEqual(container.factoryFor(lookup, { namespace: expectedNamespace }).class, PrivateComponent, 'The correct factory was provided'); - assert.strictEqual(container.factoryFor(lookup, { namespace: expectedNamespace }).class, PrivateComponent, 'The correct factory was provided again'); - assert.equal(resolveCount, 1, 'resolve called only once and a cached factory was returned the second time'); + // note: _guid and isDestroyed are being set in the `factory` constructor + // not via registry/container shenanigans + assert.deepEqual(Object.keys(instance), []); } + } +); - ['@test The container can expand and resolve a namespace to lookup']() { - let PrivateComponent = factory(); - let lookup = 'component:my-input'; - let expectedNamespace = 'my-addon'; - let registry = new Registry(); - let expandedKey = 'boom, special expanded key'; - registry.expandLocalLookup = (specifier, options) => { - this.assert.strictEqual(specifier, lookup, 'specifier is expanded'); - this.assert.strictEqual(options.namespace, expectedNamespace, 'namespace is expanded'); - return expandedKey; - }; - registry.resolve = function(fullName) { - if (fullName === expandedKey) { - return PrivateComponent; - } - }; +if (EMBER_MODULE_UNIFICATION) { + moduleFor( + 'Container module unification', + class extends AbstractTestCase { + ['@test The container can expand and resolve a source to factoryFor']( + assert + ) { + let PrivateComponent = factory(); + let lookup = 'component:my-input'; + let expectedSource = 'template:routes/application'; + let registry = new Registry(); + let resolveCount = 0; + let expandedKey = 'boom, special expanded key'; + registry.expandLocalLookup = (specifier, options) => { + this.assert.strictEqual(specifier, lookup, 'specifier is expanded'); + this.assert.strictEqual( + options.source, + expectedSource, + 'source is expanded' + ); + return expandedKey; + }; + registry.resolve = function(fullName) { + resolveCount++; + if (fullName === expandedKey) { + return PrivateComponent; + } + }; + + let container = registry.container(); + + assert.strictEqual( + container.factoryFor(lookup, { source: expectedSource }).class, + PrivateComponent, + 'The correct factory was provided' + ); + assert.strictEqual( + container.factoryFor(lookup, { source: expectedSource }).class, + PrivateComponent, + 'The correct factory was provided again' + ); + assert.equal( + resolveCount, + 1, + 'resolve called only once and a cached factory was returned the second time' + ); + } - let container = registry.container(); + ['@test The container can expand and resolve a source to lookup']() { + let PrivateComponent = factory(); + let lookup = 'component:my-input'; + let expectedSource = 'template:routes/application'; + let registry = new Registry(); + let expandedKey = 'boom, special expanded key'; + registry.expandLocalLookup = (specifier, options) => { + this.assert.strictEqual(specifier, lookup, 'specifier is expanded'); + this.assert.strictEqual( + options.source, + expectedSource, + 'source is expanded' + ); + return expandedKey; + }; + registry.resolve = function(fullName) { + if (fullName === expandedKey) { + return PrivateComponent; + } + }; + + let container = registry.container(); + + let result = container.lookup(lookup, { source: expectedSource }); + this.assert.ok( + result instanceof PrivateComponent, + 'The correct factory was provided' + ); + + this.assert.ok( + container.cache[expandedKey] instanceof PrivateComponent, + 'The correct factory was stored in the cache with the correct key which includes the source.' + ); + } - let result = container.lookup(lookup, { namespace: expectedNamespace }); - this.assert.ok(result instanceof PrivateComponent, 'The correct factory was provided'); + ['@test The container can expand and resolve a namespace to factoryFor']( + assert + ) { + let PrivateComponent = factory(); + let lookup = 'component:my-input'; + let expectedNamespace = 'my-addon'; + let registry = new Registry(); + let resolveCount = 0; + let expandedKey = 'boom, special expanded key'; + registry.expandLocalLookup = (specifier, options) => { + this.assert.strictEqual(specifier, lookup, 'specifier is expanded'); + this.assert.strictEqual( + options.namespace, + expectedNamespace, + 'namespace is expanded' + ); + return expandedKey; + }; + registry.resolve = function(fullName) { + resolveCount++; + if (fullName === expandedKey) { + return PrivateComponent; + } + }; + + let container = registry.container(); + + assert.strictEqual( + container.factoryFor(lookup, { namespace: expectedNamespace }).class, + PrivateComponent, + 'The correct factory was provided' + ); + assert.strictEqual( + container.factoryFor(lookup, { namespace: expectedNamespace }).class, + PrivateComponent, + 'The correct factory was provided again' + ); + assert.equal( + resolveCount, + 1, + 'resolve called only once and a cached factory was returned the second time' + ); + } - this.assert.ok(container.cache[expandedKey] instanceof PrivateComponent, - 'The correct factory was stored in the cache with the correct key which includes the source.'); + ['@test The container can expand and resolve a namespace to lookup']() { + let PrivateComponent = factory(); + let lookup = 'component:my-input'; + let expectedNamespace = 'my-addon'; + let registry = new Registry(); + let expandedKey = 'boom, special expanded key'; + registry.expandLocalLookup = (specifier, options) => { + this.assert.strictEqual(specifier, lookup, 'specifier is expanded'); + this.assert.strictEqual( + options.namespace, + expectedNamespace, + 'namespace is expanded' + ); + return expandedKey; + }; + registry.resolve = function(fullName) { + if (fullName === expandedKey) { + return PrivateComponent; + } + }; + + let container = registry.container(); + + let result = container.lookup(lookup, { namespace: expectedNamespace }); + this.assert.ok( + result instanceof PrivateComponent, + 'The correct factory was provided' + ); + + this.assert.ok( + container.cache[expandedKey] instanceof PrivateComponent, + 'The correct factory was stored in the cache with the correct key which includes the source.' + ); + } } - }); - + ); } diff --git a/packages/container/tests/owner_test.js b/packages/container/tests/owner_test.js index 5c08e749d4f..903d81792e9 100644 --- a/packages/container/tests/owner_test.js +++ b/packages/container/tests/owner_test.js @@ -1,17 +1,26 @@ import { getOwner, setOwner, OWNER } from 'ember-utils'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('Owner', class extends AbstractTestCase { - ['@test An owner can be set with `setOwner` and retrieved with `getOwner`'](assert) { - let owner = {}; - let obj = {}; +moduleFor( + 'Owner', + class extends AbstractTestCase { + ['@test An owner can be set with `setOwner` and retrieved with `getOwner`']( + assert + ) { + let owner = {}; + let obj = {}; - assert.strictEqual(getOwner(obj), undefined, 'owner has not been set'); + assert.strictEqual(getOwner(obj), undefined, 'owner has not been set'); - setOwner(obj, owner); + setOwner(obj, owner); - assert.strictEqual(getOwner(obj), owner, 'owner has been set'); + assert.strictEqual(getOwner(obj), owner, 'owner has been set'); - assert.strictEqual(obj[OWNER], owner, 'owner has been set to the OWNER symbol'); + assert.strictEqual( + obj[OWNER], + owner, + 'owner has been set to the OWNER symbol' + ); + } } -}); +); diff --git a/packages/container/tests/registry_test.js b/packages/container/tests/registry_test.js index 2d842db7f25..f7859ce19f9 100644 --- a/packages/container/tests/registry_test.js +++ b/packages/container/tests/registry_test.js @@ -8,805 +8,1007 @@ import { import { EMBER_MODULE_UNIFICATION } from 'ember/features'; import { ENV } from 'ember-environment'; -moduleFor('Registry', class extends AbstractTestCase{ - constructor() { - super(); - - this.originalResolverFunctionSupport = ENV._ENABLE_RESOLVER_FUNCTION_SUPPORT; - ENV._ENABLE_RESOLVER_FUNCTION_SUPPORT = true; - } +moduleFor( + 'Registry', + class extends AbstractTestCase { + constructor() { + super(); + + this.originalResolverFunctionSupport = + ENV._ENABLE_RESOLVER_FUNCTION_SUPPORT; + ENV._ENABLE_RESOLVER_FUNCTION_SUPPORT = true; + } - teardown() { - ENV._ENABLE_RESOLVER_FUNCTION_SUPPORT = this.originalResolverFunctionSupport; - } + teardown() { + ENV._ENABLE_RESOLVER_FUNCTION_SUPPORT = this.originalResolverFunctionSupport; + } - ['@test A registered factory is returned from resolve'](assert) { - let registry = new Registry(); - let PostController = factory(); + ['@test A registered factory is returned from resolve'](assert) { + let registry = new Registry(); + let PostController = factory(); - registry.register('controller:post', PostController); + registry.register('controller:post', PostController); - let PostControllerFactory = registry.resolve('controller:post'); + let PostControllerFactory = registry.resolve('controller:post'); - assert.ok(PostControllerFactory, 'factory is returned'); - assert.ok(PostControllerFactory.create() instanceof PostController, 'The return of factory.create is an instance of PostController'); - } + assert.ok(PostControllerFactory, 'factory is returned'); + assert.ok( + PostControllerFactory.create() instanceof PostController, + 'The return of factory.create is an instance of PostController' + ); + } - ['@test The registered factory returned from resolve is the same factory each time'](assert) { - let registry = new Registry(); - let PostController = factory(); + ['@test The registered factory returned from resolve is the same factory each time']( + assert + ) { + let registry = new Registry(); + let PostController = factory(); - registry.register('controller:post', PostController); + registry.register('controller:post', PostController); - assert.deepEqual(registry.resolve('controller:post'), registry.resolve('controller:post'), 'The return of resolve is always the same'); - } + assert.deepEqual( + registry.resolve('controller:post'), + registry.resolve('controller:post'), + 'The return of resolve is always the same' + ); + } - ['@test The registered value returned from resolve is the same value each time even if the value is falsy'](assert) { - let registry = new Registry(); + ['@test The registered value returned from resolve is the same value each time even if the value is falsy']( + assert + ) { + let registry = new Registry(); - registry.register('falsy:value', null, { instantiate: false }); + registry.register('falsy:value', null, { instantiate: false }); - assert.strictEqual(registry.resolve('falsy:value'), registry.resolve('falsy:value'), 'The return of resolve is always the same'); - } + assert.strictEqual( + registry.resolve('falsy:value'), + registry.resolve('falsy:value'), + 'The return of resolve is always the same' + ); + } - ['@test The value returned from resolver is the same value as the original value even if the value is falsy'](assert) { - let resolver = { - resolve(fullName) { - if (fullName === 'falsy:value') { - return null; + ['@test The value returned from resolver is the same value as the original value even if the value is falsy']( + assert + ) { + let resolver = { + resolve(fullName) { + if (fullName === 'falsy:value') { + return null; + } } - } - }; - let registry = new Registry({ resolver }); + }; + let registry = new Registry({ resolver }); - assert.strictEqual(registry.resolve('falsy:value'), null); - } + assert.strictEqual(registry.resolve('falsy:value'), null); + } - ['@test A registered factory returns true for `has` if an item is registered'](assert) { - let registry = new Registry(); - let PostController = factory(); + ['@test A registered factory returns true for `has` if an item is registered']( + assert + ) { + let registry = new Registry(); + let PostController = factory(); - registry.register('controller:post', PostController); + registry.register('controller:post', PostController); - assert.equal(registry.has('controller:post'), true, 'The `has` method returned true for registered factories'); - assert.equal(registry.has('controller:posts'), false, 'The `has` method returned false for unregistered factories'); - } + assert.equal( + registry.has('controller:post'), + true, + 'The `has` method returned true for registered factories' + ); + assert.equal( + registry.has('controller:posts'), + false, + 'The `has` method returned false for unregistered factories' + ); + } - ['@test Throw exception when trying to inject `type:thing` on all type(s)']() { - let registry = new Registry(); - let PostController = factory(); + ['@test Throw exception when trying to inject `type:thing` on all type(s)']() { + let registry = new Registry(); + let PostController = factory(); - registry.register('controller:post', PostController); + registry.register('controller:post', PostController); - expectAssertion(() => { - registry.typeInjection('controller', 'injected', 'controller:post'); - }, /Cannot inject a 'controller:post' on other controller\(s\)\./); - } + expectAssertion(() => { + registry.typeInjection('controller', 'injected', 'controller:post'); + }, /Cannot inject a 'controller:post' on other controller\(s\)\./); + } - ['@test The registry can take a hook to resolve factories lazily'](assert) { - let PostController = factory(); - let resolver = { - resolve(fullName) { - if (fullName === 'controller:post') { - return PostController; + ['@test The registry can take a hook to resolve factories lazily'](assert) { + let PostController = factory(); + let resolver = { + resolve(fullName) { + if (fullName === 'controller:post') { + return PostController; + } } - } - }; - let registry = new Registry({ resolver }); + }; + let registry = new Registry({ resolver }); - assert.strictEqual(registry.resolve('controller:post'), PostController, 'The correct factory was provided'); - } + assert.strictEqual( + registry.resolve('controller:post'), + PostController, + 'The correct factory was provided' + ); + } - ['@test The registry respects the resolver hook for `has`'](assert) { - let PostController = factory(); - let resolver = { - resolve(fullName) { - if (fullName === 'controller:post') { - return PostController; + ['@test The registry respects the resolver hook for `has`'](assert) { + let PostController = factory(); + let resolver = { + resolve(fullName) { + if (fullName === 'controller:post') { + return PostController; + } } - } - }; - let registry = new Registry({ resolver }); - - assert.ok(registry.has('controller:post'), 'the `has` method uses the resolver hook'); - } - - ['@test The registry normalizes names when resolving'](assert) { - let registry = new Registry(); - let PostController = factory(); - - registry.normalizeFullName = function() { - return 'controller:post'; - }; - - registry.register('controller:post', PostController); - let type = registry.resolve('controller:normalized'); - - assert.strictEqual(type, PostController, 'Normalizes the name when resolving'); - } - - ['@test The registry normalizes names when checking if the factory is registered'](assert) { - let registry = new Registry(); - let PostController = factory(); - - registry.normalizeFullName = function(fullName) { - return fullName === 'controller:normalized' ? 'controller:post' : fullName; - }; + }; + let registry = new Registry({ resolver }); - registry.register('controller:post', PostController); - let isPresent = registry.has('controller:normalized'); + assert.ok( + registry.has('controller:post'), + 'the `has` method uses the resolver hook' + ); + } - assert.equal(isPresent, true, 'Normalizes the name when checking if the factory or instance is present'); - } + ['@test The registry normalizes names when resolving'](assert) { + let registry = new Registry(); + let PostController = factory(); - ['@test The registry normalizes names when injecting'](assert) { - let registry = new Registry(); - let PostController = factory(); - let user = { name: 'Stef' }; + registry.normalizeFullName = function() { + return 'controller:post'; + }; - registry.normalize = function() { - return 'controller:post'; - }; + registry.register('controller:post', PostController); + let type = registry.resolve('controller:normalized'); - registry.register('controller:post', PostController); - registry.register('user:post', user, { instantiate: false }); - registry.injection('controller:post', 'user', 'controller:normalized'); + assert.strictEqual( + type, + PostController, + 'Normalizes the name when resolving' + ); + } - assert.deepEqual(registry.resolve('controller:post'), user, 'Normalizes the name when injecting'); - } + ['@test The registry normalizes names when checking if the factory is registered']( + assert + ) { + let registry = new Registry(); + let PostController = factory(); + + registry.normalizeFullName = function(fullName) { + return fullName === 'controller:normalized' + ? 'controller:post' + : fullName; + }; + + registry.register('controller:post', PostController); + let isPresent = registry.has('controller:normalized'); + + assert.equal( + isPresent, + true, + 'Normalizes the name when checking if the factory or instance is present' + ); + } - ['@test cannot register an `undefined` factory'](assert) { - let registry = new Registry(); + ['@test The registry normalizes names when injecting'](assert) { + let registry = new Registry(); + let PostController = factory(); + let user = { name: 'Stef' }; - assert.throws(() => { - registry.register('controller:apple', undefined); - }, ''); - } + registry.normalize = function() { + return 'controller:post'; + }; - ['@test can re-register a factory'](assert) { - let registry = new Registry(); - let FirstApple = factory('first'); - let SecondApple = factory('second'); + registry.register('controller:post', PostController); + registry.register('user:post', user, { instantiate: false }); + registry.injection('controller:post', 'user', 'controller:normalized'); - registry.register('controller:apple', FirstApple); - registry.register('controller:apple', SecondApple); + assert.deepEqual( + registry.resolve('controller:post'), + user, + 'Normalizes the name when injecting' + ); + } - assert.ok(registry.resolve('controller:apple').create() instanceof SecondApple); - } + ['@test cannot register an `undefined` factory'](assert) { + let registry = new Registry(); - ['@test cannot re-register a factory if it has been resolved'](assert) { - let registry = new Registry(); - let FirstApple = factory('first'); - let SecondApple = factory('second'); + assert.throws(() => { + registry.register('controller:apple', undefined); + }, ''); + } - registry.register('controller:apple', FirstApple); - assert.strictEqual(registry.resolve('controller:apple'), FirstApple); + ['@test can re-register a factory'](assert) { + let registry = new Registry(); + let FirstApple = factory('first'); + let SecondApple = factory('second'); - expectAssertion(function() { + registry.register('controller:apple', FirstApple); registry.register('controller:apple', SecondApple); - }, /Cannot re-register: 'controller:apple', as it has already been resolved\./); - - assert.strictEqual(registry.resolve('controller:apple'), FirstApple); - } - ['@test registry.has should not accidentally cause injections on that factory to be run. (Mitigate merely on observing)'](assert) { - assert.expect(1); - - let registry = new Registry(); - let FirstApple = factory('first'); - let SecondApple = factory('second'); - - SecondApple.extend = function() { - assert.ok(false, 'should not extend or touch the injected model, merely to inspect existence of another'); - }; - - registry.register('controller:apple', FirstApple); - registry.register('controller:second-apple', SecondApple); - registry.injection('controller:apple', 'badApple', 'controller:second-apple'); - - assert.ok(registry.has('controller:apple')); - } - - ['@test registry.has should not error for invalid fullNames'](assert) { - let registry = new Registry(); + assert.ok( + registry.resolve('controller:apple').create() instanceof SecondApple + ); + } - assert.ok(!registry.has('foo:bar:baz')); - } + ['@test cannot re-register a factory if it has been resolved'](assert) { + let registry = new Registry(); + let FirstApple = factory('first'); + let SecondApple = factory('second'); - ['@test once resolved, always return the same result'](assert) { - let registry = new Registry(); + registry.register('controller:apple', FirstApple); + assert.strictEqual(registry.resolve('controller:apple'), FirstApple); - registry.resolver = { - resolve() { - return 'bar'; - } - }; + expectAssertion(function() { + registry.register('controller:apple', SecondApple); + }, /Cannot re-register: 'controller:apple', as it has already been resolved\./); - let Bar = registry.resolve('models:bar'); + assert.strictEqual(registry.resolve('controller:apple'), FirstApple); + } - registry.resolver = { - resolve() { - return 'not bar'; - } - }; + ['@test registry.has should not accidentally cause injections on that factory to be run. (Mitigate merely on observing)']( + assert + ) { + assert.expect(1); + + let registry = new Registry(); + let FirstApple = factory('first'); + let SecondApple = factory('second'); + + SecondApple.extend = function() { + assert.ok( + false, + 'should not extend or touch the injected model, merely to inspect existence of another' + ); + }; + + registry.register('controller:apple', FirstApple); + registry.register('controller:second-apple', SecondApple); + registry.injection( + 'controller:apple', + 'badApple', + 'controller:second-apple' + ); - assert.equal(registry.resolve('models:bar'), Bar); - } + assert.ok(registry.has('controller:apple')); + } - ['@test factory resolves are cached'](assert) { - let registry = new Registry(); - let PostController = factory(); - let resolveWasCalled = []; + ['@test registry.has should not error for invalid fullNames'](assert) { + let registry = new Registry(); - registry.resolver = { - resolve(fullName) { - resolveWasCalled.push(fullName); - return PostController; - } - }; + assert.ok(!registry.has('foo:bar:baz')); + } - assert.deepEqual(resolveWasCalled, []); - registry.resolve('controller:post'); - assert.deepEqual(resolveWasCalled, ['controller:post']); + ['@test once resolved, always return the same result'](assert) { + let registry = new Registry(); - registry.resolve('controller:post'); - assert.deepEqual(resolveWasCalled, ['controller:post']); - } + registry.resolver = { + resolve() { + return 'bar'; + } + }; - ['@test factory for non extendables (MODEL) resolves are cached'](assert) { - let registry = new Registry(); - let PostController = factory(); - let resolveWasCalled = []; + let Bar = registry.resolve('models:bar'); - registry.resolver = { - resolve(fullName) { - resolveWasCalled.push(fullName); - return PostController; - } - }; + registry.resolver = { + resolve() { + return 'not bar'; + } + }; - assert.deepEqual(resolveWasCalled, []); - registry.resolve('model:post'); - assert.deepEqual(resolveWasCalled, ['model:post']); + assert.equal(registry.resolve('models:bar'), Bar); + } - registry.resolve('model:post'); - assert.deepEqual(resolveWasCalled, ['model:post']); - } + ['@test factory resolves are cached'](assert) { + let registry = new Registry(); + let PostController = factory(); + let resolveWasCalled = []; - ['@test factory for non extendables resolves are cached'](assert) { - let registry = new Registry(); - let PostController = {}; - let resolveWasCalled = []; + registry.resolver = { + resolve(fullName) { + resolveWasCalled.push(fullName); + return PostController; + } + }; - registry.resolver = { - resolve(fullName) { - resolveWasCalled.push(fullName); - return PostController; - } - }; + assert.deepEqual(resolveWasCalled, []); + registry.resolve('controller:post'); + assert.deepEqual(resolveWasCalled, ['controller:post']); - assert.deepEqual(resolveWasCalled, []); - registry.resolve('foo:post'); - assert.deepEqual(resolveWasCalled, ['foo:post']); + registry.resolve('controller:post'); + assert.deepEqual(resolveWasCalled, ['controller:post']); + } - registry.resolve('foo:post'); - assert.deepEqual(resolveWasCalled, ['foo:post']); - } + ['@test factory for non extendables (MODEL) resolves are cached'](assert) { + let registry = new Registry(); + let PostController = factory(); + let resolveWasCalled = []; - ['@test registry.container creates a container'](assert) { - let registry = new Registry(); - let PostController = factory(); - registry.register('controller:post', PostController); + registry.resolver = { + resolve(fullName) { + resolveWasCalled.push(fullName); + return PostController; + } + }; - let container = registry.container(); - let postController = container.lookup('controller:post'); + assert.deepEqual(resolveWasCalled, []); + registry.resolve('model:post'); + assert.deepEqual(resolveWasCalled, ['model:post']); - assert.ok(postController instanceof PostController, 'The lookup is an instance of the registered factory'); - } + registry.resolve('model:post'); + assert.deepEqual(resolveWasCalled, ['model:post']); + } - ['@test `describe` will be handled by the resolver, then by the fallback registry, if available'](assert) { - let fallback = { - describe(fullName) { - return `${fullName}-fallback`; - } - }; + ['@test factory for non extendables resolves are cached'](assert) { + let registry = new Registry(); + let PostController = {}; + let resolveWasCalled = []; - let resolver = { - lookupDescription(fullName) { - return `${fullName}-resolver`; - } - }; + registry.resolver = { + resolve(fullName) { + resolveWasCalled.push(fullName); + return PostController; + } + }; - let registry = new Registry({ fallback, resolver }); + assert.deepEqual(resolveWasCalled, []); + registry.resolve('foo:post'); + assert.deepEqual(resolveWasCalled, ['foo:post']); - assert.equal(registry.describe('controller:post'), 'controller:post-resolver', '`describe` handled by the resolver first.'); + registry.resolve('foo:post'); + assert.deepEqual(resolveWasCalled, ['foo:post']); + } - registry.resolver = null; + ['@test registry.container creates a container'](assert) { + let registry = new Registry(); + let PostController = factory(); + registry.register('controller:post', PostController); - assert.equal(registry.describe('controller:post'), 'controller:post-fallback', '`describe` handled by fallback registry next.'); + let container = registry.container(); + let postController = container.lookup('controller:post'); - registry.fallback = null; + assert.ok( + postController instanceof PostController, + 'The lookup is an instance of the registered factory' + ); + } - assert.equal(registry.describe('controller:post'), 'controller:post', '`describe` by default returns argument.'); - } + ['@test `describe` will be handled by the resolver, then by the fallback registry, if available']( + assert + ) { + let fallback = { + describe(fullName) { + return `${fullName}-fallback`; + } + }; - ['@test `normalizeFullName` will be handled by the resolver, then by the fallback registry, if available'](assert) { - let fallback = { - normalizeFullName(fullName) { - return `${fullName}-fallback`; - } - }; + let resolver = { + lookupDescription(fullName) { + return `${fullName}-resolver`; + } + }; - let resolver = { - normalize(fullName) { - return `${fullName}-resolver`; - } - }; + let registry = new Registry({ fallback, resolver }); - let registry = new Registry({ fallback, resolver }); + assert.equal( + registry.describe('controller:post'), + 'controller:post-resolver', + '`describe` handled by the resolver first.' + ); - assert.equal(registry.normalizeFullName('controller:post'), 'controller:post-resolver', '`normalizeFullName` handled by the resolver first.'); + registry.resolver = null; - registry.resolver = null; + assert.equal( + registry.describe('controller:post'), + 'controller:post-fallback', + '`describe` handled by fallback registry next.' + ); - assert.equal(registry.normalizeFullName('controller:post'), 'controller:post-fallback', '`normalizeFullName` handled by fallback registry next.'); + registry.fallback = null; - registry.fallback = null; + assert.equal( + registry.describe('controller:post'), + 'controller:post', + '`describe` by default returns argument.' + ); + } - assert.equal(registry.normalizeFullName('controller:post'), 'controller:post', '`normalizeFullName` by default returns argument.'); - } + ['@test `normalizeFullName` will be handled by the resolver, then by the fallback registry, if available']( + assert + ) { + let fallback = { + normalizeFullName(fullName) { + return `${fullName}-fallback`; + } + }; - ['@test `makeToString` will be handled by the resolver, then by the fallback registry, if available'](assert) { - let fallback = { - makeToString(fullName) { - return `${fullName}-fallback`; - } - }; + let resolver = { + normalize(fullName) { + return `${fullName}-resolver`; + } + }; - let resolver = { - makeToString(fullName) { - return `${fullName}-resolver`; - } - }; + let registry = new Registry({ fallback, resolver }); - let registry = new Registry({ fallback, resolver }); + assert.equal( + registry.normalizeFullName('controller:post'), + 'controller:post-resolver', + '`normalizeFullName` handled by the resolver first.' + ); - assert.equal(registry.makeToString('controller:post'), 'controller:post-resolver', '`makeToString` handled by the resolver first.'); + registry.resolver = null; - registry.resolver = null; + assert.equal( + registry.normalizeFullName('controller:post'), + 'controller:post-fallback', + '`normalizeFullName` handled by fallback registry next.' + ); - assert.equal(registry.makeToString('controller:post'), 'controller:post-fallback', '`makeToString` handled by fallback registry next.'); + registry.fallback = null; - registry.fallback = null; + assert.equal( + registry.normalizeFullName('controller:post'), + 'controller:post', + '`normalizeFullName` by default returns argument.' + ); + } - assert.equal(registry.makeToString('controller:post'), 'controller:post', '`makeToString` by default returns argument.'); - } + ['@test `makeToString` will be handled by the resolver, then by the fallback registry, if available']( + assert + ) { + let fallback = { + makeToString(fullName) { + return `${fullName}-fallback`; + } + }; - ['@test `resolve` can be handled by a fallback registry'](assert) { - let fallback = new Registry(); + let resolver = { + makeToString(fullName) { + return `${fullName}-resolver`; + } + }; - let registry = new Registry({ fallback: fallback }); - let PostController = factory(); + let registry = new Registry({ fallback, resolver }); - fallback.register('controller:post', PostController); + assert.equal( + registry.makeToString('controller:post'), + 'controller:post-resolver', + '`makeToString` handled by the resolver first.' + ); - let PostControllerFactory = registry.resolve('controller:post'); + registry.resolver = null; - assert.ok(PostControllerFactory, 'factory is returned'); - assert.ok(PostControllerFactory.create() instanceof PostController, 'The return of factory.create is an instance of PostController'); - } + assert.equal( + registry.makeToString('controller:post'), + 'controller:post-fallback', + '`makeToString` handled by fallback registry next.' + ); - ['@test `has` can be handled by a fallback registry'](assert) { - let fallback = new Registry(); + registry.fallback = null; - let registry = new Registry({ fallback: fallback }); - let PostController = factory(); + assert.equal( + registry.makeToString('controller:post'), + 'controller:post', + '`makeToString` by default returns argument.' + ); + } - fallback.register('controller:post', PostController); + ['@test `resolve` can be handled by a fallback registry'](assert) { + let fallback = new Registry(); - assert.equal(registry.has('controller:post'), true, 'Fallback registry is checked for registration'); - } + let registry = new Registry({ fallback: fallback }); + let PostController = factory(); - ['@test `getInjections` includes injections from a fallback registry'](assert) { - let fallback = new Registry(); - let registry = new Registry({ fallback: fallback }); + fallback.register('controller:post', PostController); - assert.strictEqual(registry.getInjections('model:user'), undefined, 'No injections in the primary registry'); + let PostControllerFactory = registry.resolve('controller:post'); - fallback.injection('model:user', 'post', 'model:post'); + assert.ok(PostControllerFactory, 'factory is returned'); + assert.ok( + PostControllerFactory.create() instanceof PostController, + 'The return of factory.create is an instance of PostController' + ); + } - assert.equal(registry.getInjections('model:user').length, 1, 'Injections from the fallback registry are merged'); - } + ['@test `has` can be handled by a fallback registry'](assert) { + let fallback = new Registry(); - ['@test `getTypeInjections` includes type injections from a fallback registry'](assert) { - let fallback = new Registry(); - let registry = new Registry({ fallback: fallback }); + let registry = new Registry({ fallback: fallback }); + let PostController = factory(); - assert.strictEqual(registry.getTypeInjections('model'), undefined, 'No injections in the primary registry'); + fallback.register('controller:post', PostController); - fallback.injection('model', 'source', 'source:main'); + assert.equal( + registry.has('controller:post'), + true, + 'Fallback registry is checked for registration' + ); + } - assert.equal(registry.getTypeInjections('model').length, 1, 'Injections from the fallback registry are merged'); - } + ['@test `getInjections` includes injections from a fallback registry']( + assert + ) { + let fallback = new Registry(); + let registry = new Registry({ fallback: fallback }); - ['@test `knownForType` contains keys for each item of a given type'](assert) { - let registry = new Registry(); + assert.strictEqual( + registry.getInjections('model:user'), + undefined, + 'No injections in the primary registry' + ); - registry.register('foo:bar-baz', 'baz'); - registry.register('foo:qux-fez', 'fez'); + fallback.injection('model:user', 'post', 'model:post'); - let found = registry.knownForType('foo'); + assert.equal( + registry.getInjections('model:user').length, + 1, + 'Injections from the fallback registry are merged' + ); + } - assert.deepEqual(found, { - 'foo:bar-baz': true, - 'foo:qux-fez': true - }); - } + ['@test `getTypeInjections` includes type injections from a fallback registry']( + assert + ) { + let fallback = new Registry(); + let registry = new Registry({ fallback: fallback }); - ['@test `knownForType` includes fallback registry results'](assert) { - let fallback = new Registry(); - let registry = new Registry({ fallback: fallback }); + assert.strictEqual( + registry.getTypeInjections('model'), + undefined, + 'No injections in the primary registry' + ); - registry.register('foo:bar-baz', 'baz'); - registry.register('foo:qux-fez', 'fez'); - fallback.register('foo:zurp-zorp', 'zorp'); + fallback.injection('model', 'source', 'source:main'); - let found = registry.knownForType('foo'); + assert.equal( + registry.getTypeInjections('model').length, + 1, + 'Injections from the fallback registry are merged' + ); + } - assert.deepEqual(found, { - 'foo:bar-baz': true, - 'foo:qux-fez': true, - 'foo:zurp-zorp': true - }); - } + ['@test `knownForType` contains keys for each item of a given type']( + assert + ) { + let registry = new Registry(); - ['@test `knownForType` is called on the resolver if present'](assert) { - assert.expect(3); + registry.register('foo:bar-baz', 'baz'); + registry.register('foo:qux-fez', 'fez'); - let resolver = { - knownForType(type) { - assert.ok(true, 'knownForType called on the resolver'); - assert.equal(type, 'foo', 'the type was passed through'); + let found = registry.knownForType('foo'); - return { 'foo:yorp': true }; - } - }; + assert.deepEqual(found, { + 'foo:bar-baz': true, + 'foo:qux-fez': true + }); + } - let registry = new Registry({ - resolver - }); - registry.register('foo:bar-baz', 'baz'); + ['@test `knownForType` includes fallback registry results'](assert) { + let fallback = new Registry(); + let registry = new Registry({ fallback: fallback }); - let found = registry.knownForType('foo'); + registry.register('foo:bar-baz', 'baz'); + registry.register('foo:qux-fez', 'fez'); + fallback.register('foo:zurp-zorp', 'zorp'); - assert.deepEqual(found, { - 'foo:yorp': true, - 'foo:bar-baz': true - }); - } + let found = registry.knownForType('foo'); - ['@test A registry created with `resolver` function instead of an object throws deprecation'](assert) { - assert.expect(2); + assert.deepEqual(found, { + 'foo:bar-baz': true, + 'foo:qux-fez': true, + 'foo:zurp-zorp': true + }); + } - ENV._ENABLE_RESOLVER_FUNCTION_SUPPORT = true; + ['@test `knownForType` is called on the resolver if present'](assert) { + assert.expect(3); - let registry; + let resolver = { + knownForType(type) { + assert.ok(true, 'knownForType called on the resolver'); + assert.equal(type, 'foo', 'the type was passed through'); - expectDeprecation(() => { - registry = new Registry({ - resolver(fullName) { - return `${fullName}-resolved`; + return { 'foo:yorp': true }; } - }); - }, 'Passing a `resolver` function into a Registry is deprecated. Please pass in a Resolver object with a `resolve` method.'); + }; - assert.equal(registry.resolve('foo:bar'), 'foo:bar-resolved', '`resolve` still calls the deprecated function'); - } - - ['@test A registry created with `resolver` function instead of an object throws assertion'](assert) { - assert.expect(1); + let registry = new Registry({ + resolver + }); + registry.register('foo:bar-baz', 'baz'); - ENV._ENABLE_RESOLVER_FUNCTION_SUPPORT = false; + let found = registry.knownForType('foo'); - expectAssertion(() => { - new Registry({ - resolver(fullName) { - return `${fullName}-resolved`; - } + assert.deepEqual(found, { + 'foo:yorp': true, + 'foo:bar-baz': true }); - }, /Passing a \`resolver\` function into a Registry is deprecated\. Please pass in a Resolver object with a \`resolve\` method\./); - } - - ['@test resolver.expandLocalLookup is not required'](assert) { - let registry = new Registry({ - resolver: { } - }); + } - let result = registry.expandLocalLookup('foo:bar', { - source: 'baz:qux' - }); + ['@test A registry created with `resolver` function instead of an object throws deprecation']( + assert + ) { + assert.expect(2); - assert.equal(result, null); - } + ENV._ENABLE_RESOLVER_FUNCTION_SUPPORT = true; - ['@test expandLocalLookup is called on the resolver if present'](assert) { - assert.expect(4); + let registry; - let resolver = { - expandLocalLookup: (targetFullName, sourceFullName) => { - assert.ok(true, 'expandLocalLookup is called on the resolver'); - assert.equal(targetFullName, 'foo:bar', 'the targetFullName was passed through'); - assert.equal(sourceFullName, 'baz:qux', 'the sourceFullName was passed through'); + expectDeprecation(() => { + registry = new Registry({ + resolver(fullName) { + return `${fullName}-resolved`; + } + }); + }, 'Passing a `resolver` function into a Registry is deprecated. Please pass in a Resolver object with a `resolve` method.'); - return 'foo:qux/bar'; - } - }; + assert.equal( + registry.resolve('foo:bar'), + 'foo:bar-resolved', + '`resolve` still calls the deprecated function' + ); + } - let registry = new Registry({ - resolver - }); + ['@test A registry created with `resolver` function instead of an object throws assertion']( + assert + ) { + assert.expect(1); - let result = registry.expandLocalLookup('foo:bar', { - source: 'baz:qux' - }); + ENV._ENABLE_RESOLVER_FUNCTION_SUPPORT = false; - assert.equal(result, 'foo:qux/bar'); - } + expectAssertion(() => { + new Registry({ + resolver(fullName) { + return `${fullName}-resolved`; + } + }); + }, /Passing a \`resolver\` function into a Registry is deprecated\. Please pass in a Resolver object with a \`resolve\` method\./); + } - ['@test `expandLocalLookup` is handled by the resolver, then by the fallback registry, if available'](assert) { - assert.expect(9); + ['@test resolver.expandLocalLookup is not required'](assert) { + let registry = new Registry({ + resolver: {} + }); - let fallbackResolver = { - expandLocalLookup: (targetFullName, sourceFullName) => { - assert.ok(true, 'expandLocalLookup is called on the fallback resolver'); - assert.equal(targetFullName, 'foo:bar', 'the targetFullName was passed through'); - assert.equal(sourceFullName, 'baz:qux', 'the sourceFullName was passed through'); + let result = registry.expandLocalLookup('foo:bar', { + source: 'baz:qux' + }); - return 'foo:qux/bar-fallback'; - } - }; + assert.equal(result, null); + } - let resolver = { - expandLocalLookup: (targetFullName, sourceFullName) => { - assert.ok(true, 'expandLocalLookup is called on the resolver'); - assert.equal(targetFullName, 'foo:bar', 'the targetFullName was passed through'); - assert.equal(sourceFullName, 'baz:qux', 'the sourceFullName was passed through'); + ['@test expandLocalLookup is called on the resolver if present'](assert) { + assert.expect(4); + + let resolver = { + expandLocalLookup: (targetFullName, sourceFullName) => { + assert.ok(true, 'expandLocalLookup is called on the resolver'); + assert.equal( + targetFullName, + 'foo:bar', + 'the targetFullName was passed through' + ); + assert.equal( + sourceFullName, + 'baz:qux', + 'the sourceFullName was passed through' + ); - return 'foo:qux/bar-resolver'; - } - }; + return 'foo:qux/bar'; + } + }; - let fallbackRegistry = new Registry({ - resolver: fallbackResolver - }); + let registry = new Registry({ + resolver + }); - let registry = new Registry({ - fallback: fallbackRegistry, - resolver - }); + let result = registry.expandLocalLookup('foo:bar', { + source: 'baz:qux' + }); - let result = registry.expandLocalLookup('foo:bar', { - source: 'baz:qux' - }); + assert.equal(result, 'foo:qux/bar'); + } - assert.equal(result, 'foo:qux/bar-resolver', 'handled by the resolver'); + ['@test `expandLocalLookup` is handled by the resolver, then by the fallback registry, if available']( + assert + ) { + assert.expect(9); + + let fallbackResolver = { + expandLocalLookup: (targetFullName, sourceFullName) => { + assert.ok( + true, + 'expandLocalLookup is called on the fallback resolver' + ); + assert.equal( + targetFullName, + 'foo:bar', + 'the targetFullName was passed through' + ); + assert.equal( + sourceFullName, + 'baz:qux', + 'the sourceFullName was passed through' + ); + + return 'foo:qux/bar-fallback'; + } + }; + + let resolver = { + expandLocalLookup: (targetFullName, sourceFullName) => { + assert.ok(true, 'expandLocalLookup is called on the resolver'); + assert.equal( + targetFullName, + 'foo:bar', + 'the targetFullName was passed through' + ); + assert.equal( + sourceFullName, + 'baz:qux', + 'the sourceFullName was passed through' + ); + + return 'foo:qux/bar-resolver'; + } + }; - registry.resolver = null; + let fallbackRegistry = new Registry({ + resolver: fallbackResolver + }); - result = registry.expandLocalLookup('foo:bar', { - source: 'baz:qux' - }); + let registry = new Registry({ + fallback: fallbackRegistry, + resolver + }); - assert.equal(result, 'foo:qux/bar-fallback', 'handled by the fallback registry'); + let result = registry.expandLocalLookup('foo:bar', { + source: 'baz:qux' + }); - registry.fallback = null; + assert.equal(result, 'foo:qux/bar-resolver', 'handled by the resolver'); - result = registry.expandLocalLookup('foo:bar', { - source: 'baz:qux' - }); + registry.resolver = null; - assert.equal(result, null, 'null is returned by default when no resolver or fallback registry is present'); - } + result = registry.expandLocalLookup('foo:bar', { + source: 'baz:qux' + }); - ['@test resolver.expandLocalLookup result is cached'](assert) { - assert.expect(3); - let result; + assert.equal( + result, + 'foo:qux/bar-fallback', + 'handled by the fallback registry' + ); - let resolver = { - expandLocalLookup: () => { - assert.ok(true, 'expandLocalLookup is called on the resolver'); + registry.fallback = null; - return 'foo:qux/bar'; - } - }; + result = registry.expandLocalLookup('foo:bar', { + source: 'baz:qux' + }); - let registry = new Registry({ - resolver - }); + assert.equal( + result, + null, + 'null is returned by default when no resolver or fallback registry is present' + ); + } - result = registry.expandLocalLookup('foo:bar', { - source: 'baz:qux' - }); + ['@test resolver.expandLocalLookup result is cached'](assert) { + assert.expect(3); + let result; - assert.equal(result, 'foo:qux/bar'); + let resolver = { + expandLocalLookup: () => { + assert.ok(true, 'expandLocalLookup is called on the resolver'); - result = registry.expandLocalLookup('foo:bar', { - source: 'baz:qux' - }); + return 'foo:qux/bar'; + } + }; - assert.equal(result, 'foo:qux/bar'); - } + let registry = new Registry({ + resolver + }); - ['@test resolver.expandLocalLookup cache is busted when any unregister is called'](assert) { - assert.expect(4); - let result; + result = registry.expandLocalLookup('foo:bar', { + source: 'baz:qux' + }); - let resolver = { - expandLocalLookup: () => { - assert.ok(true, 'expandLocalLookup is called on the resolver'); + assert.equal(result, 'foo:qux/bar'); - return 'foo:qux/bar'; - } - }; + result = registry.expandLocalLookup('foo:bar', { + source: 'baz:qux' + }); - let registry = new Registry({ - resolver - }); + assert.equal(result, 'foo:qux/bar'); + } - result = registry.expandLocalLookup('foo:bar', { - source: 'baz:qux' - }); + ['@test resolver.expandLocalLookup cache is busted when any unregister is called']( + assert + ) { + assert.expect(4); + let result; - assert.equal(result, 'foo:qux/bar'); + let resolver = { + expandLocalLookup: () => { + assert.ok(true, 'expandLocalLookup is called on the resolver'); - registry.unregister('foo:bar'); + return 'foo:qux/bar'; + } + }; - result = registry.expandLocalLookup('foo:bar', { - source: 'baz:qux' - }); + let registry = new Registry({ + resolver + }); - assert.equal(result, 'foo:qux/bar'); - } + result = registry.expandLocalLookup('foo:bar', { + source: 'baz:qux' + }); - ['@test resolve calls expandLocallookup when it receives options.source'](assert) { - assert.expect(3); + assert.equal(result, 'foo:qux/bar'); - let resolver = { - resolve() { }, - expandLocalLookup: (targetFullName, sourceFullName) => { - assert.ok(true, 'expandLocalLookup is called on the resolver'); - assert.equal(targetFullName, 'foo:bar', 'the targetFullName was passed through'); - assert.equal(sourceFullName, 'baz:qux', 'the sourceFullName was passed through'); + registry.unregister('foo:bar'); - return 'foo:qux/bar'; - } - }; + result = registry.expandLocalLookup('foo:bar', { + source: 'baz:qux' + }); - let registry = new Registry({ - resolver - }); + assert.equal(result, 'foo:qux/bar'); + } - registry.resolve('foo:bar', { - source: 'baz:qux' - }); - } + ['@test resolve calls expandLocallookup when it receives options.source']( + assert + ) { + assert.expect(3); + + let resolver = { + resolve() {}, + expandLocalLookup: (targetFullName, sourceFullName) => { + assert.ok(true, 'expandLocalLookup is called on the resolver'); + assert.equal( + targetFullName, + 'foo:bar', + 'the targetFullName was passed through' + ); + assert.equal( + sourceFullName, + 'baz:qux', + 'the sourceFullName was passed through' + ); - ['@test has uses expandLocalLookup'](assert) { - assert.expect(5); - let resolvedFullNames = []; - let result; + return 'foo:qux/bar'; + } + }; - let resolver = { - resolve(name) { - resolvedFullNames.push(name); - return 'yippie!'; - }, + let registry = new Registry({ + resolver + }); - expandLocalLookup: (targetFullName) => { - assert.ok(true, 'expandLocalLookup is called on the resolver'); + registry.resolve('foo:bar', { + source: 'baz:qux' + }); + } - if (targetFullName === 'foo:bar') { - return 'foo:qux/bar'; - } else { - return null; + ['@test has uses expandLocalLookup'](assert) { + assert.expect(5); + let resolvedFullNames = []; + let result; + + let resolver = { + resolve(name) { + resolvedFullNames.push(name); + return 'yippie!'; + }, + + expandLocalLookup: targetFullName => { + assert.ok(true, 'expandLocalLookup is called on the resolver'); + + if (targetFullName === 'foo:bar') { + return 'foo:qux/bar'; + } else { + return null; + } } - } - }; + }; - let registry = new Registry({ - resolver - }); + let registry = new Registry({ + resolver + }); - result = registry.has('foo:bar', { - source: 'baz:qux' - }); + result = registry.has('foo:bar', { + source: 'baz:qux' + }); - assert.ok(result, 'found foo:bar/qux'); + assert.ok(result, 'found foo:bar/qux'); - result = registry.has('foo:baz', { - source: 'baz:qux' - }); + result = registry.has('foo:baz', { + source: 'baz:qux' + }); - assert.ok(!result, 'foo:baz/qux not found'); + assert.ok(!result, 'foo:baz/qux not found'); - assert.deepEqual(['foo:qux/bar'], resolvedFullNames); + assert.deepEqual(['foo:qux/bar'], resolvedFullNames); + } } -}); +); -moduleFor('Registry privatize', class extends AbstractTestCase { - ['@test valid format'](assert) { - let privatized = privatize(['secret:factory']); - let matched = privatized.match(/^([^:]+):([^:]+)-(\d+)$/); +moduleFor( + 'Registry privatize', + class extends AbstractTestCase { + ['@test valid format'](assert) { + let privatized = privatize(['secret:factory']); + let matched = privatized.match(/^([^:]+):([^:]+)-(\d+)$/); - assert.ok(matched, 'privatized format was recognized'); - assert.equal(matched[1], 'secret'); - assert.equal(matched[2], 'factory'); - assert.ok(/^\d+$/.test(matched[3])); + assert.ok(matched, 'privatized format was recognized'); + assert.equal(matched[1], 'secret'); + assert.equal(matched[2], 'factory'); + assert.ok(/^\d+$/.test(matched[3])); + } } -}); +); if (EMBER_MODULE_UNIFICATION) { - moduleFor('Registry module unification', class extends AbstractTestCase { - ['@test The registry can pass a source to the resolver'](assert) { - let PrivateComponent = factory(); - let type = 'component'; - let name = 'my-input'; - let specifier = `${type}:${name}`; - let source = 'template:routes/application'; - - let resolver = new ModuleBasedTestResolver(); - resolver.add({specifier, source}, PrivateComponent); - let registry = new Registry({ resolver }); - - assert.strictEqual( - registry.resolve(specifier), - undefined, - 'Not returned when specifier not scoped' - ); - assert.strictEqual( - registry.resolve(specifier, { source }), - PrivateComponent, - 'The correct factory was provided' - ); - assert.strictEqual( - registry.resolve(specifier, { source }), - PrivateComponent, - 'The correct factory was provided again' - ); - } - - ['@test The registry can pass a namespace to the resolver'](assert) { - let PrivateComponent = factory(); - let type = 'component'; - let name = 'my-input'; - let specifier = `${type}:${name}`; - let source = 'template:routes/application'; - let namespace = 'my-addon'; - - let resolver = new ModuleBasedTestResolver(); - resolver.add({specifier, source, namespace}, PrivateComponent); - let registry = new Registry({ resolver }); + moduleFor( + 'Registry module unification', + class extends AbstractTestCase { + ['@test The registry can pass a source to the resolver'](assert) { + let PrivateComponent = factory(); + let type = 'component'; + let name = 'my-input'; + let specifier = `${type}:${name}`; + let source = 'template:routes/application'; + + let resolver = new ModuleBasedTestResolver(); + resolver.add({ specifier, source }, PrivateComponent); + let registry = new Registry({ resolver }); + + assert.strictEqual( + registry.resolve(specifier), + undefined, + 'Not returned when specifier not scoped' + ); + assert.strictEqual( + registry.resolve(specifier, { source }), + PrivateComponent, + 'The correct factory was provided' + ); + assert.strictEqual( + registry.resolve(specifier, { source }), + PrivateComponent, + 'The correct factory was provided again' + ); + } - assert.strictEqual( - registry.resolve(specifier), - undefined, - 'Not returned when specifier not scoped' - ); - assert.strictEqual( - registry.resolve(specifier, {source}), - undefined, - 'Not returned when specifier is missing namespace' - ); - assert.strictEqual( - registry.resolve(specifier, { source, namespace }), - PrivateComponent, - 'The correct factory was provided' - ); - assert.strictEqual( - registry.resolve(specifier, { source, namespace }), - PrivateComponent, - 'The correct factory was provided again' - ); + ['@test The registry can pass a namespace to the resolver'](assert) { + let PrivateComponent = factory(); + let type = 'component'; + let name = 'my-input'; + let specifier = `${type}:${name}`; + let source = 'template:routes/application'; + let namespace = 'my-addon'; + + let resolver = new ModuleBasedTestResolver(); + resolver.add({ specifier, source, namespace }, PrivateComponent); + let registry = new Registry({ resolver }); + + assert.strictEqual( + registry.resolve(specifier), + undefined, + 'Not returned when specifier not scoped' + ); + assert.strictEqual( + registry.resolve(specifier, { source }), + undefined, + 'Not returned when specifier is missing namespace' + ); + assert.strictEqual( + registry.resolve(specifier, { source, namespace }), + PrivateComponent, + 'The correct factory was provided' + ); + assert.strictEqual( + registry.resolve(specifier, { source, namespace }), + PrivateComponent, + 'The correct factory was provided again' + ); + } } - }); + ); } diff --git a/packages/ember-application/lib/index.js b/packages/ember-application/lib/index.js index 1f0efd26456..2cba30ca7dc 100644 --- a/packages/ember-application/lib/index.js +++ b/packages/ember-application/lib/index.js @@ -1,4 +1,3 @@ - export { default as Application } from './system/application'; export { default as ApplicationInstance } from './system/application-instance'; export { default as Resolver } from './system/resolver'; diff --git a/packages/ember-application/lib/system/application-instance.js b/packages/ember-application/lib/system/application-instance.js index 6ae1a745051..cbdc054b1e3 100644 --- a/packages/ember-application/lib/system/application-instance.js +++ b/packages/ember-application/lib/system/application-instance.js @@ -96,7 +96,9 @@ const ApplicationInstance = EngineInstance.extend({ @private */ _bootSync(options) { - if (this._booted) { return this; } + if (this._booted) { + return this; + } options = new BootOptions(options); @@ -171,7 +173,9 @@ const ApplicationInstance = EngineInstance.extend({ beyond the first call have no effect. */ setupRouter() { - if (this._didSetupRouter) { return; } + if (this._didSetupRouter) { + return; + } this._didSetupRouter = true; let router = get(this, 'router'); @@ -200,7 +204,11 @@ const ApplicationInstance = EngineInstance.extend({ let applicationCustomEvents = get(this.application, 'customEvents'); let instanceCustomEvents = get(this, 'customEvents'); - let customEvents = assign({}, applicationCustomEvents, instanceCustomEvents); + let customEvents = assign( + {}, + applicationCustomEvents, + instanceCustomEvents + ); dispatcher.setup(customEvents, this.rootElement); return dispatcher; @@ -248,11 +256,17 @@ const ApplicationInstance = EngineInstance.extend({ } }; - let handleTransitionReject = (error) => { + let handleTransitionReject = error => { if (error.error) { throw error.error; - } else if (error.name === 'TransitionAborted' && router._routerMicrolib.activeTransition) { - return router._routerMicrolib.activeTransition.then(handleTransitionResolve, handleTransitionReject); + } else if ( + error.name === 'TransitionAborted' && + router._routerMicrolib.activeTransition + ) { + return router._routerMicrolib.activeTransition.then( + handleTransitionResolve, + handleTransitionReject + ); } else if (error.name === 'TransitionAborted') { throw new Error(error.message); } else { @@ -266,7 +280,9 @@ const ApplicationInstance = EngineInstance.extend({ location.setURL(url); // getURL returns the set url with the rootURL stripped off - return router.handleURL(location.getURL()).then(handleTransitionResolve, handleTransitionReject); + return router + .handleURL(location.getURL()) + .then(handleTransitionResolve, handleTransitionReject); }, willDestroy() { @@ -287,8 +303,12 @@ ApplicationInstance.reopenClass({ options = new BootOptions(options); } - registry.register('-environment:main', options.toEnvironment(), { instantiate: false }); - registry.register('service:-document', options.document, { instantiate: false }); + registry.register('-environment:main', options.toEnvironment(), { + instantiate: false + }); + registry.register('service:-document', options.document, { + instantiate: false + }); this._super(registry, options); } @@ -343,7 +363,6 @@ class BootOptions { */ this.isInteractive = environment.hasDOM; // This default is overridable below - /** @property _renderMode @type string @@ -435,7 +454,7 @@ class BootOptions { if (options.document) { this.document = options.document; } else { - this.document = (typeof document !== 'undefined') ? document : null; + this.document = typeof document !== 'undefined' ? document : null; } /** diff --git a/packages/ember-application/lib/system/engine-instance.js b/packages/ember-application/lib/system/engine-instance.js index febc61d962a..3db5418da15 100644 --- a/packages/ember-application/lib/system/engine-instance.js +++ b/packages/ember-application/lib/system/engine-instance.js @@ -24,40 +24,43 @@ import { getEngineParent, setEngineParent } from './engine-parent'; @uses ContainerProxyMixin */ -const EngineInstance = EmberObject.extend(RegistryProxyMixin, ContainerProxyMixin, { - /** +const EngineInstance = EmberObject.extend( + RegistryProxyMixin, + ContainerProxyMixin, + { + /** The base `Engine` for which this is an instance. @property {Engine} engine @private */ - base: null, + base: null, - init() { - this._super(...arguments); + init() { + this._super(...arguments); - guidFor(this); + guidFor(this); - let base = this.base; + let base = this.base; - if (!base) { - base = this.application; - this.base = base; - } + if (!base) { + base = this.application; + this.base = base; + } - // Create a per-instance registry that will use the application's registry - // as a fallback for resolving registrations. - let registry = this.__registry__ = new Registry({ - fallback: base.__registry__ - }); + // Create a per-instance registry that will use the application's registry + // as a fallback for resolving registrations. + let registry = (this.__registry__ = new Registry({ + fallback: base.__registry__ + })); - // Create a per-instance container from the instance's registry - this.__container__ = registry.container({ owner: this }); + // Create a per-instance container from the instance's registry + this.__container__ = registry.container({ owner: this }); - this._booted = false; - }, + this._booted = false; + }, - /** + /** Initialize the `EngineInstance` and return a promise that resolves with the instance itself when the boot process is complete. @@ -70,15 +73,19 @@ const EngineInstance = EmberObject.extend(RegistryProxyMixin, ContainerProxyMixi @param options {Object} @return {Promise} */ - boot(options) { - if (this._bootPromise) { return this._bootPromise; } + boot(options) { + if (this._bootPromise) { + return this._bootPromise; + } - this._bootPromise = new RSVP.Promise(resolve => resolve(this._bootSync(options))); + this._bootPromise = new RSVP.Promise(resolve => + resolve(this._bootSync(options)) + ); - return this._bootPromise; - }, + return this._bootPromise; + }, - /** + /** Unfortunately, a lot of existing code assumes booting an instance is synchronous – specifically, a lot of tests assume the last call to `app.advanceReadiness()` or `app.reset()` will result in a new instance @@ -92,27 +99,32 @@ const EngineInstance = EmberObject.extend(RegistryProxyMixin, ContainerProxyMixi @private */ - _bootSync(options) { - if (this._booted) { return this; } + _bootSync(options) { + if (this._booted) { + return this; + } - assert('An engine instance\'s parent must be set via `setEngineParent(engine, parent)` prior to calling `engine.boot()`.', getEngineParent(this)); + assert( + "An engine instance's parent must be set via `setEngineParent(engine, parent)` prior to calling `engine.boot()`.", + getEngineParent(this) + ); - this.cloneParentDependencies(); + this.cloneParentDependencies(); - this.setupRegistry(options); + this.setupRegistry(options); - this.base.runInstanceInitializers(this); + this.base.runInstanceInitializers(this); - this._booted = true; + this._booted = true; - return this; - }, + return this; + }, - setupRegistry(options = this.__container__.lookup('-environment:main')) { - this.constructor.setupRegistry(this.__registry__, options); - }, + setupRegistry(options = this.__container__.lookup('-environment:main')) { + this.constructor.setupRegistry(this.__registry__, options); + }, - /** + /** Unregister a factory. Overrides `RegistryProxy#unregister` in order to clear any cached instances @@ -122,12 +134,12 @@ const EngineInstance = EmberObject.extend(RegistryProxyMixin, ContainerProxyMixi @method unregister @param {String} fullName */ - unregister(fullName) { - this.__container__.reset(fullName); - this._super(...arguments); - }, + unregister(fullName) { + this.__container__.reset(fullName); + this._super(...arguments); + }, - /** + /** Build a new `EngineInstance` that's a child of this instance. Engines must be registered by name with their parent engine @@ -139,59 +151,66 @@ const EngineInstance = EmberObject.extend(RegistryProxyMixin, ContainerProxyMixi @param options {Object} options provided to the engine instance. @return {EngineInstance,Error} */ - buildChildEngineInstance(name, options = {}) { - let Engine = this.lookup(`engine:${name}`); + buildChildEngineInstance(name, options = {}) { + let Engine = this.lookup(`engine:${name}`); - if (!Engine) { - throw new EmberError(`You attempted to mount the engine '${name}', but it is not registered with its parent.`); - } + if (!Engine) { + throw new EmberError( + `You attempted to mount the engine '${name}', but it is not registered with its parent.` + ); + } - let engineInstance = Engine.buildInstance(options); + let engineInstance = Engine.buildInstance(options); - setEngineParent(engineInstance, this); + setEngineParent(engineInstance, this); - return engineInstance; - }, + return engineInstance; + }, - /** + /** Clone dependencies shared between an engine instance and its parent. @private @method cloneParentDependencies */ - cloneParentDependencies() { - let parent = getEngineParent(this); - - let registrations = [ - 'route:basic', - 'service:-routing', - 'service:-glimmer-environment' - ]; - - registrations.forEach(key => this.register(key, parent.resolveRegistration(key))); - - let env = parent.lookup('-environment:main'); - this.register('-environment:main', env, { instantiate: false }); - - let singletons = [ - 'router:main', - P`-bucket-cache:main`, - '-view-registry:main', - `renderer:-${env.isInteractive ? 'dom' : 'inert'}`, - 'service:-document', - P`template-compiler:main`, - ]; - - if (env.isInteractive) { - singletons.push('event_dispatcher:main'); + cloneParentDependencies() { + let parent = getEngineParent(this); + + let registrations = [ + 'route:basic', + 'service:-routing', + 'service:-glimmer-environment' + ]; + + registrations.forEach(key => + this.register(key, parent.resolveRegistration(key)) + ); + + let env = parent.lookup('-environment:main'); + this.register('-environment:main', env, { instantiate: false }); + + let singletons = [ + 'router:main', + P`-bucket-cache:main`, + '-view-registry:main', + `renderer:-${env.isInteractive ? 'dom' : 'inert'}`, + 'service:-document', + P`template-compiler:main` + ]; + + if (env.isInteractive) { + singletons.push('event_dispatcher:main'); + } + + singletons.forEach(key => + this.register(key, parent.lookup(key), { instantiate: false }) + ); + + this.inject('view', '_environment', '-environment:main'); + this.inject('route', '_environment', '-environment:main'); } - - singletons.forEach(key => this.register(key, parent.lookup(key), { instantiate: false })); - - this.inject('view', '_environment', '-environment:main'); - this.inject('route', '_environment', '-environment:main'); } -}); +); EngineInstance.reopenClass({ /** @@ -202,7 +221,9 @@ EngineInstance.reopenClass({ */ setupRegistry(registry, options) { // when no options/environment is present, do nothing - if (!options) { return; } + if (!options) { + return; + } registry.injection('view', '_environment', '-environment:main'); registry.injection('route', '_environment', '-environment:main'); diff --git a/packages/ember-application/lib/system/engine.js b/packages/ember-application/lib/system/engine.js index c72132d6233..89c07fb2005 100644 --- a/packages/ember-application/lib/system/engine.js +++ b/packages/ember-application/lib/system/engine.js @@ -2,15 +2,8 @@ @module @ember/engine */ import { canInvoke } from 'ember-utils'; -import { - Namespace, - RegistryProxyMixin, - Controller -} from 'ember-runtime'; -import { - Registry, - privatize as P -} from 'container'; +import { Namespace, RegistryProxyMixin, Controller } from 'ember-runtime'; +import { Registry, privatize as P } from 'container'; import DAG from 'dag-map'; import { assert } from 'ember-debug'; import { get, set } from 'ember-metal'; @@ -96,7 +89,7 @@ const Engine = Namespace.extend(RegistryProxyMixin, { @return {Ember.Registry} the configured registry */ buildRegistry() { - let registry = this.__registry__ = this.constructor.buildRegistry(this); + let registry = (this.__registry__ = this.constructor.buildRegistry(this)); return registry; }, @@ -148,7 +141,12 @@ const Engine = Namespace.extend(RegistryProxyMixin, { for (let i = 0; i < initializers.length; i++) { initializer = initializersByName[initializers[i]]; - graph.add(initializer.name, initializer, initializer.before, initializer.after); + graph.add( + initializer.name, + initializer, + initializer.before, + initializer.after + ); } graph.topsort(cb); @@ -378,7 +376,10 @@ Engine.reopenClass({ @param instanceInitializer @public */ - instanceInitializer: buildInitializerMethod('instanceInitializers', 'instance initializer'), + instanceInitializer: buildInitializerMethod( + 'instanceInitializers', + 'instance initializer' + ), /** This creates a registry with the default Ember naming conventions. @@ -463,20 +464,32 @@ function resolverFor(namespace) { } function buildInitializerMethod(bucketName, humanName) { - return function (initializer) { + return function(initializer) { // If this is the first initializer being added to a subclass, we are going to reopen the class // to make sure we have a new `initializers` object, which extends from the parent class' using // prototypal inheritance. Without this, attempting to add initializers to the subclass would // pollute the parent class as well as other subclasses. - if (this.superclass[bucketName] !== undefined && this.superclass[bucketName] === this[bucketName]) { + if ( + this.superclass[bucketName] !== undefined && + this.superclass[bucketName] === this[bucketName] + ) { let attrs = {}; attrs[bucketName] = Object.create(this[bucketName]); this.reopenClass(attrs); } - assert(`The ${humanName} '${initializer.name}' has already been registered`, !this[bucketName][initializer.name]); - assert(`An ${humanName} cannot be registered without an initialize function`, canInvoke(initializer, 'initialize')); - assert(`An ${humanName} cannot be registered without a name property`, initializer.name !== undefined); + assert( + `The ${humanName} '${initializer.name}' has already been registered`, + !this[bucketName][initializer.name] + ); + assert( + `An ${humanName} cannot be registered without an initialize function`, + canInvoke(initializer, 'initialize') + ); + assert( + `An ${humanName} cannot be registered without a name property`, + initializer.name !== undefined + ); this[bucketName][initializer.name] = initializer; }; @@ -490,7 +503,11 @@ function commonSetupRegistry(registry) { registry.injection('view', '_viewRegistry', '-view-registry:main'); registry.injection('renderer', '_viewRegistry', '-view-registry:main'); - registry.injection('event_dispatcher:main', '_viewRegistry', '-view-registry:main'); + registry.injection( + 'event_dispatcher:main', + '_viewRegistry', + '-view-registry:main' + ); registry.injection('route', '_topLevelViewTemplate', 'template:-outlet'); @@ -510,9 +527,19 @@ function commonSetupRegistry(registry) { registry.injection('service:-routing', 'router', 'router:main'); // DEBUGGING - registry.register('resolver-for-debugging:main', registry.resolver, { instantiate: false }); - registry.injection('container-debug-adapter:main', 'resolver', 'resolver-for-debugging:main'); - registry.injection('data-adapter:main', 'containerDebugAdapter', 'container-debug-adapter:main'); + registry.register('resolver-for-debugging:main', registry.resolver, { + instantiate: false + }); + registry.injection( + 'container-debug-adapter:main', + 'resolver', + 'resolver-for-debugging:main' + ); + registry.injection( + 'data-adapter:main', + 'containerDebugAdapter', + 'container-debug-adapter:main' + ); // Custom resolver authors may want to register their own ContainerDebugAdapter with this key registry.register('container-debug-adapter:main', ContainerDebugAdapter); diff --git a/packages/ember-application/lib/utils/validate-type.js b/packages/ember-application/lib/utils/validate-type.js index 7adc9254ce2..6425a0c26c7 100644 --- a/packages/ember-application/lib/utils/validate-type.js +++ b/packages/ember-application/lib/utils/validate-type.js @@ -1,10 +1,10 @@ import { assert } from 'ember-debug'; const VALIDATED_TYPES = { - route: ['assert', 'isRouteFactory', 'Ember.Route'], + route: ['assert', 'isRouteFactory', 'Ember.Route'], component: ['deprecate', 'isComponentFactory', 'Ember.Component'], - view: ['deprecate', 'isViewFactory', 'Ember.View'], - service: ['deprecate', 'isServiceFactory', 'Ember.Service'] + view: ['deprecate', 'isViewFactory', 'Ember.View'], + service: ['deprecate', 'isServiceFactory', 'Ember.Service'] }; export default function validateType(resolvedType, parsedName) { @@ -18,7 +18,7 @@ export default function validateType(resolvedType, parsedName) { assert( `Expected ${parsedName.fullName} to resolve to an ${expectedType} but ` + - `instead it was ${resolvedType}.`, + `instead it was ${resolvedType}.`, !!resolvedType[factoryFlag] ); } diff --git a/packages/ember-application/tests/system/application_instance_test.js b/packages/ember-application/tests/system/application_instance_test.js index dcce72aeb1b..3eaae5dd94c 100644 --- a/packages/ember-application/tests/system/application_instance_test.js +++ b/packages/ember-application/tests/system/application_instance_test.js @@ -5,167 +5,207 @@ import { run } from 'ember-metal'; import { privatize as P } from 'container'; import { factory } from 'internal-test-helpers'; import { Object as EmberObject } from 'ember-runtime'; -import { - moduleFor, - AbstractTestCase as TestCase -} from 'internal-test-helpers'; +import { moduleFor, AbstractTestCase as TestCase } from 'internal-test-helpers'; import { getDebugFunction, setDebugFunction } from 'ember-debug'; const originalDebug = getDebugFunction('debug'); -const noop = function(){}; +const noop = function() {}; let application, appInstance; -moduleFor('ApplicationInstance', class extends TestCase { - constructor() { - setDebugFunction('debug', noop); - super(); +moduleFor( + 'ApplicationInstance', + class extends TestCase { + constructor() { + setDebugFunction('debug', noop); + super(); - document.getElementById('qunit-fixture').innerHTML = ` + document.getElementById('qunit-fixture').innerHTML = `
HI
HI
`; - application = run(() => Application.create({ rootElement: '#one', router: null })); - } - - teardown() { - setDebugFunction('debug', originalDebug); - if (appInstance) { - run(appInstance, 'destroy'); + application = run(() => + Application.create({ rootElement: '#one', router: null }) + ); } - if (application) { - run(application, 'destroy'); - } - - document.getElementById('qunit-fixture').innerHTML = ''; - } - - ['@test an application instance can be created based upon an application'](assert) { - appInstance = run(() => ApplicationInstance.create({ application })); - - assert.ok(appInstance, 'instance should be created'); - assert.equal(appInstance.application, application, 'application should be set to parent'); - } - - ['@test customEvents added to the application before setupEventDispatcher'](assert) { - assert.expect(1); + teardown() { + setDebugFunction('debug', originalDebug); + if (appInstance) { + run(appInstance, 'destroy'); + } - appInstance = run(() => ApplicationInstance.create({ application })); - appInstance.setupRegistry(); + if (application) { + run(application, 'destroy'); + } - application.customEvents = { - awesome: 'sauce' - }; - - let eventDispatcher = appInstance.lookup('event_dispatcher:main'); - eventDispatcher.setup = function(events) { - assert.equal(events.awesome, 'sauce'); - }; - - appInstance.setupEventDispatcher(); - } - - ['@test customEvents added to the application before setupEventDispatcher'](assert) { - assert.expect(1); + document.getElementById('qunit-fixture').innerHTML = ''; + } - appInstance = run(() => ApplicationInstance.create({ application })); - appInstance.setupRegistry(); + ['@test an application instance can be created based upon an application']( + assert + ) { + appInstance = run(() => ApplicationInstance.create({ application })); + + assert.ok(appInstance, 'instance should be created'); + assert.equal( + appInstance.application, + application, + 'application should be set to parent' + ); + } - application.customEvents = { - awesome: 'sauce' - }; + ['@test customEvents added to the application before setupEventDispatcher']( + assert + ) { + assert.expect(1); - let eventDispatcher = appInstance.lookup('event_dispatcher:main'); - eventDispatcher.setup = function(events) { - assert.equal(events.awesome, 'sauce'); - }; + appInstance = run(() => ApplicationInstance.create({ application })); + appInstance.setupRegistry(); - appInstance.setupEventDispatcher(); - } + application.customEvents = { + awesome: 'sauce' + }; - ['@test customEvents added to the application instance before setupEventDispatcher'](assert) { - assert.expect(1); + let eventDispatcher = appInstance.lookup('event_dispatcher:main'); + eventDispatcher.setup = function(events) { + assert.equal(events.awesome, 'sauce'); + }; - appInstance = run(() => ApplicationInstance.create({ application })); - appInstance.setupRegistry(); + appInstance.setupEventDispatcher(); + } - appInstance.customEvents = { - awesome: 'sauce' - }; + ['@test customEvents added to the application before setupEventDispatcher']( + assert + ) { + assert.expect(1); - let eventDispatcher = appInstance.lookup('event_dispatcher:main'); - eventDispatcher.setup = function(events) { - assert.equal(events.awesome, 'sauce'); - }; + appInstance = run(() => ApplicationInstance.create({ application })); + appInstance.setupRegistry(); - appInstance.setupEventDispatcher(); - } + application.customEvents = { + awesome: 'sauce' + }; - ['@test unregistering a factory clears all cached instances of that factory'](assert) { - assert.expect(5); + let eventDispatcher = appInstance.lookup('event_dispatcher:main'); + eventDispatcher.setup = function(events) { + assert.equal(events.awesome, 'sauce'); + }; - appInstance = run(() => ApplicationInstance.create({ application })); + appInstance.setupEventDispatcher(); + } - let PostController1 = factory(); - let PostController2 = factory(); + ['@test customEvents added to the application instance before setupEventDispatcher']( + assert + ) { + assert.expect(1); - appInstance.register('controller:post', PostController1); + appInstance = run(() => ApplicationInstance.create({ application })); + appInstance.setupRegistry(); - let postController1 = appInstance.lookup('controller:post'); - let postController1Factory = appInstance.factoryFor('controller:post'); - assert.ok(postController1 instanceof PostController1, 'precond - lookup creates instance'); - assert.equal(PostController1, postController1Factory.class, 'precond - factoryFor().class matches'); + appInstance.customEvents = { + awesome: 'sauce' + }; - appInstance.unregister('controller:post'); - appInstance.register('controller:post', PostController2); + let eventDispatcher = appInstance.lookup('event_dispatcher:main'); + eventDispatcher.setup = function(events) { + assert.equal(events.awesome, 'sauce'); + }; - let postController2 = appInstance.lookup('controller:post'); - let postController2Factory = appInstance.factoryFor('controller:post'); - assert.ok(postController2 instanceof PostController2, 'lookup creates instance'); - assert.equal(PostController2, postController2Factory.class, 'factoryFor().class matches'); + appInstance.setupEventDispatcher(); + } - assert.notStrictEqual(postController1, postController2, 'lookup creates a brand new instance, because the previous one was reset'); - } + ['@test unregistering a factory clears all cached instances of that factory']( + assert + ) { + assert.expect(5); + + appInstance = run(() => ApplicationInstance.create({ application })); + + let PostController1 = factory(); + let PostController2 = factory(); + + appInstance.register('controller:post', PostController1); + + let postController1 = appInstance.lookup('controller:post'); + let postController1Factory = appInstance.factoryFor('controller:post'); + assert.ok( + postController1 instanceof PostController1, + 'precond - lookup creates instance' + ); + assert.equal( + PostController1, + postController1Factory.class, + 'precond - factoryFor().class matches' + ); + + appInstance.unregister('controller:post'); + appInstance.register('controller:post', PostController2); + + let postController2 = appInstance.lookup('controller:post'); + let postController2Factory = appInstance.factoryFor('controller:post'); + assert.ok( + postController2 instanceof PostController2, + 'lookup creates instance' + ); + assert.equal( + PostController2, + postController2Factory.class, + 'factoryFor().class matches' + ); + + assert.notStrictEqual( + postController1, + postController2, + 'lookup creates a brand new instance, because the previous one was reset' + ); + } - ['@skip unregistering a factory clears caches with source of that factory'](assert) { - assert.expect(1); + ['@skip unregistering a factory clears caches with source of that factory']( + assert + ) { + assert.expect(1); - appInstance = run(() => ApplicationInstance.create({ application })); + appInstance = run(() => ApplicationInstance.create({ application })); - let PostController1 = factory(); - let PostController2 = factory(); + let PostController1 = factory(); + let PostController2 = factory(); - appInstance.register('controller:post', PostController1); + appInstance.register('controller:post', PostController1); - appInstance.lookup('controller:post'); - let postControllerLookupWithSource = appInstance.lookup('controller:post', {source: 'doesnt-even-matter'}); + appInstance.lookup('controller:post'); + let postControllerLookupWithSource = appInstance.lookup( + 'controller:post', + { source: 'doesnt-even-matter' } + ); - appInstance.unregister('controller:post'); - appInstance.register('controller:post', PostController2); + appInstance.unregister('controller:post'); + appInstance.register('controller:post', PostController2); - // The cache that is source-specific is not cleared - assert.ok( - postControllerLookupWithSource !== appInstance.lookup('controller:post', {source: 'doesnt-even-matter'}), - 'lookup with source creates a new instance' - ); - } + // The cache that is source-specific is not cleared + assert.ok( + postControllerLookupWithSource !== + appInstance.lookup('controller:post', { + source: 'doesnt-even-matter' + }), + 'lookup with source creates a new instance' + ); + } - ['@test can build and boot a registered engine'](assert) { - assert.expect(11); + ['@test can build and boot a registered engine'](assert) { + assert.expect(11); - let ChatEngine = Engine.extend(); - let chatEngineInstance; + let ChatEngine = Engine.extend(); + let chatEngineInstance; - application.register('engine:chat', ChatEngine); + application.register('engine:chat', ChatEngine); - run(() => { - appInstance = ApplicationInstance.create({ application }); - appInstance.setupRegistry(); - chatEngineInstance = appInstance.buildChildEngineInstance('chat'); - }); + run(() => { + appInstance = ApplicationInstance.create({ application }); + appInstance.setupRegistry(); + chatEngineInstance = appInstance.buildChildEngineInstance('chat'); + }); - return chatEngineInstance.boot() - .then(() => { + return chatEngineInstance.boot().then(() => { assert.ok(true, 'boot successful'); let registrations = [ @@ -178,7 +218,8 @@ moduleFor('ApplicationInstance', class extends TestCase { assert.strictEqual( chatEngineInstance.resolveRegistration(key), appInstance.resolveRegistration(key), - `Engine and parent app share registrations for '${key}'`); + `Engine and parent app share registrations for '${key}'` + ); }); let singletons = [ @@ -191,26 +232,32 @@ moduleFor('ApplicationInstance', class extends TestCase { ]; let env = appInstance.lookup('-environment:main'); - singletons.push(env.isInteractive ? 'renderer:-dom' : 'renderer:-inert'); + singletons.push( + env.isInteractive ? 'renderer:-dom' : 'renderer:-inert' + ); singletons.forEach(key => { assert.strictEqual( chatEngineInstance.lookup(key), appInstance.lookup(key), - `Engine and parent app share singleton '${key}'`); + `Engine and parent app share singleton '${key}'` + ); }); }); - } + } - ['@test can build a registry via ApplicationInstance.setupRegistry() -- simulates ember-test-helpers'](assert) { - let namespace = EmberObject.create({ - Resolver: { create: function() { } } - }); + ['@test can build a registry via ApplicationInstance.setupRegistry() -- simulates ember-test-helpers']( + assert + ) { + let namespace = EmberObject.create({ + Resolver: { create: function() {} } + }); - let registry = Application.buildRegistry(namespace); + let registry = Application.buildRegistry(namespace); - ApplicationInstance.setupRegistry(registry); + ApplicationInstance.setupRegistry(registry); - assert.equal(registry.resolve('service:-document'), document); + assert.equal(registry.resolve('service:-document'), document); + } } -}); +); diff --git a/packages/ember-application/tests/system/bootstrap-test.js b/packages/ember-application/tests/system/bootstrap-test.js index 7575b348d01..d37705487d1 100644 --- a/packages/ember-application/tests/system/bootstrap-test.js +++ b/packages/ember-application/tests/system/bootstrap-test.js @@ -4,25 +4,30 @@ import { DefaultResolverApplicationTestCase } from 'internal-test-helpers'; -moduleFor('Application with default resolver and autoboot', class extends DefaultResolverApplicationTestCase { - get fixture() { - return ` +moduleFor( + 'Application with default resolver and autoboot', + class extends DefaultResolverApplicationTestCase { + get fixture() { + return `
`; - } + } - get applicationOptions() { - return assign(super.applicationOptions, { - autoboot: true, - rootElement: '#app' - }); - } + get applicationOptions() { + return assign(super.applicationOptions, { + autoboot: true, + rootElement: '#app' + }); + } - ['@test templates in script tags are extracted at application creation'](assert) { - this.runTask(() => this.createApplication()); - assert.equal(document.getElementById('app').textContent, 'Hello World!'); + ['@test templates in script tags are extracted at application creation']( + assert + ) { + this.runTask(() => this.createApplication()); + assert.equal(document.getElementById('app').textContent, 'Hello World!'); + } } -}); +); diff --git a/packages/ember-application/tests/system/dependency_injection/custom_resolver_test.js b/packages/ember-application/tests/system/dependency_injection/custom_resolver_test.js index d4b26b8406e..54cd2402611 100644 --- a/packages/ember-application/tests/system/dependency_injection/custom_resolver_test.js +++ b/packages/ember-application/tests/system/dependency_injection/custom_resolver_test.js @@ -5,29 +5,31 @@ import { DefaultResolverApplicationTestCase } from 'internal-test-helpers'; -moduleFor('Application with extended default resolver and autoboot', class extends DefaultResolverApplicationTestCase { +moduleFor( + 'Application with extended default resolver and autoboot', + class extends DefaultResolverApplicationTestCase { + get applicationOptions() { + let applicationTemplate = this.compile(`

Fallback

`); - get applicationOptions() { - let applicationTemplate = this.compile(`

Fallback

`); - - let Resolver = DefaultResolver.extend({ - resolveTemplate(resolvable) { - if (resolvable.fullNameWithoutType === 'application') { - return applicationTemplate; - } else { - return this._super(resolvable); + let Resolver = DefaultResolver.extend({ + resolveTemplate(resolvable) { + if (resolvable.fullNameWithoutType === 'application') { + return applicationTemplate; + } else { + return this._super(resolvable); + } } - } - }); + }); - return assign(super.applicationOptions, { - Resolver, - autoboot: true - }); - } + return assign(super.applicationOptions, { + Resolver, + autoboot: true + }); + } - [`@test a resolver can be supplied to application`]() { - this.runTask(() => this.createApplication()); - this.assertText('Fallback'); + [`@test a resolver can be supplied to application`]() { + this.runTask(() => this.createApplication()); + this.assertText('Fallback'); + } } -}); +); diff --git a/packages/ember-application/tests/system/dependency_injection/normalization_test.js b/packages/ember-application/tests/system/dependency_injection/normalization_test.js index 0dff0bafb90..e5c4c75ec0a 100644 --- a/packages/ember-application/tests/system/dependency_injection/normalization_test.js +++ b/packages/ember-application/tests/system/dependency_injection/normalization_test.js @@ -1,54 +1,106 @@ import { run } from 'ember-metal'; import Application from '../../../system/application'; -import { - moduleFor, - AbstractTestCase as TestCase -} from 'internal-test-helpers'; - +import { moduleFor, AbstractTestCase as TestCase } from 'internal-test-helpers'; let application, registry; -moduleFor('Application Dependency Injection - normalize', class extends TestCase { - constructor() { - super(); +moduleFor( + 'Application Dependency Injection - normalize', + class extends TestCase { + constructor() { + super(); - application = run(Application, 'create'); - registry = application.__registry__; - } + application = run(Application, 'create'); + registry = application.__registry__; + } - teardown() { - run(application, 'destroy'); - } + teardown() { + run(application, 'destroy'); + } - ['@test normalization'](assert) { - assert.ok(registry.normalize, 'registry#normalize is present'); - - assert.equal(registry.normalize('foo:bar'), 'foo:bar'); - - assert.equal(registry.normalize('controller:posts'), 'controller:posts'); - assert.equal(registry.normalize('controller:posts_index'), 'controller:postsIndex'); - assert.equal(registry.normalize('controller:posts.index'), 'controller:postsIndex'); - assert.equal(registry.normalize('controller:posts-index'), 'controller:postsIndex'); - assert.equal(registry.normalize('controller:posts.post.index'), 'controller:postsPostIndex'); - assert.equal(registry.normalize('controller:posts_post.index'), 'controller:postsPostIndex'); - assert.equal(registry.normalize('controller:posts.post_index'), 'controller:postsPostIndex'); - assert.equal(registry.normalize('controller:posts.post-index'), 'controller:postsPostIndex'); - assert.equal(registry.normalize('controller:postsIndex'), 'controller:postsIndex'); - assert.equal(registry.normalize('controller:blogPosts.index'), 'controller:blogPostsIndex'); - assert.equal(registry.normalize('controller:blog/posts.index'), 'controller:blog/postsIndex'); - assert.equal(registry.normalize('controller:blog/posts-index'), 'controller:blog/postsIndex'); - assert.equal(registry.normalize('controller:blog/posts.post.index'), 'controller:blog/postsPostIndex'); - assert.equal(registry.normalize('controller:blog/posts_post.index'), 'controller:blog/postsPostIndex'); - assert.equal(registry.normalize('controller:blog/posts_post-index'), 'controller:blog/postsPostIndex'); - - assert.equal(registry.normalize('template:blog/posts_index'), 'template:blog/posts_index'); - } + ['@test normalization'](assert) { + assert.ok(registry.normalize, 'registry#normalize is present'); + + assert.equal(registry.normalize('foo:bar'), 'foo:bar'); + + assert.equal(registry.normalize('controller:posts'), 'controller:posts'); + assert.equal( + registry.normalize('controller:posts_index'), + 'controller:postsIndex' + ); + assert.equal( + registry.normalize('controller:posts.index'), + 'controller:postsIndex' + ); + assert.equal( + registry.normalize('controller:posts-index'), + 'controller:postsIndex' + ); + assert.equal( + registry.normalize('controller:posts.post.index'), + 'controller:postsPostIndex' + ); + assert.equal( + registry.normalize('controller:posts_post.index'), + 'controller:postsPostIndex' + ); + assert.equal( + registry.normalize('controller:posts.post_index'), + 'controller:postsPostIndex' + ); + assert.equal( + registry.normalize('controller:posts.post-index'), + 'controller:postsPostIndex' + ); + assert.equal( + registry.normalize('controller:postsIndex'), + 'controller:postsIndex' + ); + assert.equal( + registry.normalize('controller:blogPosts.index'), + 'controller:blogPostsIndex' + ); + assert.equal( + registry.normalize('controller:blog/posts.index'), + 'controller:blog/postsIndex' + ); + assert.equal( + registry.normalize('controller:blog/posts-index'), + 'controller:blog/postsIndex' + ); + assert.equal( + registry.normalize('controller:blog/posts.post.index'), + 'controller:blog/postsPostIndex' + ); + assert.equal( + registry.normalize('controller:blog/posts_post.index'), + 'controller:blog/postsPostIndex' + ); + assert.equal( + registry.normalize('controller:blog/posts_post-index'), + 'controller:blog/postsPostIndex' + ); + + assert.equal( + registry.normalize('template:blog/posts_index'), + 'template:blog/posts_index' + ); + } - ['@test normalization is indempotent'](assert) { - let examples = ['controller:posts', 'controller:posts.post.index', 'controller:blog/posts.post_index', 'template:foo_bar']; + ['@test normalization is indempotent'](assert) { + let examples = [ + 'controller:posts', + 'controller:posts.post.index', + 'controller:blog/posts.post_index', + 'template:foo_bar' + ]; - examples.forEach((example) => { - assert.equal(registry.normalize(registry.normalize(example)), registry.normalize(example)); - }); + examples.forEach(example => { + assert.equal( + registry.normalize(registry.normalize(example)), + registry.normalize(example) + ); + }); + } } -}); +); diff --git a/packages/ember-application/tests/system/dependency_injection/to_string_test.js b/packages/ember-application/tests/system/dependency_injection/to_string_test.js index 513c7bc3151..3a8d744c51e 100644 --- a/packages/ember-application/tests/system/dependency_injection/to_string_test.js +++ b/packages/ember-application/tests/system/dependency_injection/to_string_test.js @@ -7,57 +7,68 @@ import { DefaultResolverApplicationTestCase } from 'internal-test-helpers'; -moduleFor('Application Dependency Injection - DefaultResolver#toString', class extends DefaultResolverApplicationTestCase { - constructor() { - super(); - this.runTask(() => this.createApplication()); - this.application.Post = EmberObject.extend(); - } +moduleFor( + 'Application Dependency Injection - DefaultResolver#toString', + class extends DefaultResolverApplicationTestCase { + constructor() { + super(); + this.runTask(() => this.createApplication()); + this.application.Post = EmberObject.extend(); + } - beforeEach() { - return this.visit('/'); - } + beforeEach() { + return this.visit('/'); + } - ['@test factories'](assert) { - let PostFactory = this.applicationInstance.factoryFor('model:post').class; - assert.equal( - PostFactory.toString(), '.Post', - 'expecting the model to be post' - ); - } + ['@test factories'](assert) { + let PostFactory = this.applicationInstance.factoryFor('model:post').class; + assert.equal( + PostFactory.toString(), + '.Post', + 'expecting the model to be post' + ); + } - ['@test instances'](assert) { - let post = this.applicationInstance.lookup('model:post'); - let guid = guidFor(post); + ['@test instances'](assert) { + let post = this.applicationInstance.lookup('model:post'); + let guid = guidFor(post); - assert.equal(post.toString(), '<.Post:' + guid + '>', 'expecting the model to be post'); + assert.equal( + post.toString(), + '<.Post:' + guid + '>', + 'expecting the model to be post' + ); + } } -}); +); -moduleFor('Application Dependency Injection - Resolver#toString', class extends ApplicationTestCase { +moduleFor( + 'Application Dependency Injection - Resolver#toString', + class extends ApplicationTestCase { + beforeEach() { + return this.visit('/'); + } - beforeEach() { - return this.visit('/'); - } - - get applicationOptions() { - return assign(super.applicationOptions, { - Resolver: class extends ModuleBasedTestResolver { - makeToString(_, fullName) { - return fullName; + get applicationOptions() { + return assign(super.applicationOptions, { + Resolver: class extends ModuleBasedTestResolver { + makeToString(_, fullName) { + return fullName; + } } - } - }); - } + }); + } - ['@test toString called on a resolver'](assert) { - this.add('model:peter', EmberObject.extend()); + ['@test toString called on a resolver'](assert) { + this.add('model:peter', EmberObject.extend()); - let peter = this.applicationInstance.lookup('model:peter'); - let guid = guidFor(peter); - assert.equal( - peter.toString(), ``, - 'expecting the supermodel to be peter' - ); + let peter = this.applicationInstance.lookup('model:peter'); + let guid = guidFor(peter); + assert.equal( + peter.toString(), + ``, + 'expecting the supermodel to be peter' + ); + } } -}); +); diff --git a/packages/ember-application/tests/system/dependency_injection_test.js b/packages/ember-application/tests/system/dependency_injection_test.js index 3a898d0f20b..0103bb84d58 100644 --- a/packages/ember-application/tests/system/dependency_injection_test.js +++ b/packages/ember-application/tests/system/dependency_injection_test.js @@ -2,80 +2,100 @@ import { context } from 'ember-environment'; import { run } from 'ember-metal'; import { Object as EmberObject } from 'ember-runtime'; import Application from '../../system/application'; -import { - moduleFor, - AbstractTestCase as TestCase -} from 'internal-test-helpers'; - +import { moduleFor, AbstractTestCase as TestCase } from 'internal-test-helpers'; let EmberApplication = Application; let originalLookup = context.lookup; let registry, locator, application; -moduleFor('Application Dependency Injection', class extends TestCase { - constructor() { - super(); - - application = run(EmberApplication, 'create'); - - application.Person = EmberObject.extend({}); - application.Orange = EmberObject.extend({}); - application.Email = EmberObject.extend({}); - application.User = EmberObject.extend({}); - application.PostIndexController = EmberObject.extend({}); - - application.register('model:person', application.Person, { singleton: false }); - application.register('model:user', application.User, { singleton: false }); - application.register('fruit:favorite', application.Orange); - application.register('communication:main', application.Email, { singleton: false }); - application.register('controller:postIndex', application.PostIndexController, { singleton: true }); - - registry = application.__registry__; - locator = application.__container__; - - context.lookup = {}; - } - - teardown() { - run(application, 'destroy'); - application = locator = null; - context.lookup = originalLookup; - } - - ['@test container lookup is normalized'](assert) { - let dotNotationController = locator.lookup('controller:post.index'); - let camelCaseController = locator.lookup('controller:postIndex'); - - assert.ok(dotNotationController instanceof application.PostIndexController); - assert.ok(camelCaseController instanceof application.PostIndexController); - - assert.equal(dotNotationController, camelCaseController); - } - - ['@test registered entities can be looked up later'](assert) { - assert.equal(registry.resolve('model:person'), application.Person); - assert.equal(registry.resolve('model:user'), application.User); - assert.equal(registry.resolve('fruit:favorite'), application.Orange); - assert.equal(registry.resolve('communication:main'), application.Email); - assert.equal(registry.resolve('controller:postIndex'), application.PostIndexController); - - assert.equal(locator.lookup('fruit:favorite'), locator.lookup('fruit:favorite'), 'singleton lookup worked'); - assert.ok(locator.lookup('model:user') !== locator.lookup('model:user'), 'non-singleton lookup worked'); - } - - - ['@test injections'](assert) { - application.inject('model', 'fruit', 'fruit:favorite'); - application.inject('model:user', 'communication', 'communication:main'); - - let user = locator.lookup('model:user'); - let person = locator.lookup('model:person'); - let fruit = locator.lookup('fruit:favorite'); - - assert.equal(user.get('fruit'), fruit); - assert.equal(person.get('fruit'), fruit); - - assert.ok(application.Email.detectInstance(user.get('communication'))); +moduleFor( + 'Application Dependency Injection', + class extends TestCase { + constructor() { + super(); + + application = run(EmberApplication, 'create'); + + application.Person = EmberObject.extend({}); + application.Orange = EmberObject.extend({}); + application.Email = EmberObject.extend({}); + application.User = EmberObject.extend({}); + application.PostIndexController = EmberObject.extend({}); + + application.register('model:person', application.Person, { + singleton: false + }); + application.register('model:user', application.User, { + singleton: false + }); + application.register('fruit:favorite', application.Orange); + application.register('communication:main', application.Email, { + singleton: false + }); + application.register( + 'controller:postIndex', + application.PostIndexController, + { singleton: true } + ); + + registry = application.__registry__; + locator = application.__container__; + + context.lookup = {}; + } + + teardown() { + run(application, 'destroy'); + application = locator = null; + context.lookup = originalLookup; + } + + ['@test container lookup is normalized'](assert) { + let dotNotationController = locator.lookup('controller:post.index'); + let camelCaseController = locator.lookup('controller:postIndex'); + + assert.ok( + dotNotationController instanceof application.PostIndexController + ); + assert.ok(camelCaseController instanceof application.PostIndexController); + + assert.equal(dotNotationController, camelCaseController); + } + + ['@test registered entities can be looked up later'](assert) { + assert.equal(registry.resolve('model:person'), application.Person); + assert.equal(registry.resolve('model:user'), application.User); + assert.equal(registry.resolve('fruit:favorite'), application.Orange); + assert.equal(registry.resolve('communication:main'), application.Email); + assert.equal( + registry.resolve('controller:postIndex'), + application.PostIndexController + ); + + assert.equal( + locator.lookup('fruit:favorite'), + locator.lookup('fruit:favorite'), + 'singleton lookup worked' + ); + assert.ok( + locator.lookup('model:user') !== locator.lookup('model:user'), + 'non-singleton lookup worked' + ); + } + + ['@test injections'](assert) { + application.inject('model', 'fruit', 'fruit:favorite'); + application.inject('model:user', 'communication', 'communication:main'); + + let user = locator.lookup('model:user'); + let person = locator.lookup('model:person'); + let fruit = locator.lookup('fruit:favorite'); + + assert.equal(user.get('fruit'), fruit); + assert.equal(person.get('fruit'), fruit); + + assert.ok(application.Email.detectInstance(user.get('communication'))); + } } -}); +); diff --git a/packages/ember-application/tests/system/engine_initializers_test.js b/packages/ember-application/tests/system/engine_initializers_test.js index 8c2bbe1bd16..ebcbebcc04a 100644 --- a/packages/ember-application/tests/system/engine_initializers_test.js +++ b/packages/ember-application/tests/system/engine_initializers_test.js @@ -1,352 +1,412 @@ import { run } from 'ember-metal'; import Engine from '../../system/engine'; -import { - moduleFor, - AbstractTestCase as TestCase -} from 'internal-test-helpers'; +import { moduleFor, AbstractTestCase as TestCase } from 'internal-test-helpers'; let MyEngine, myEngine, myEngineInstance; -moduleFor('Engine initializers', class extends TestCase { - teardown() { - run(() => { - if (myEngineInstance) { - myEngineInstance.destroy(); - } - - if (myEngine) { - myEngine.destroy(); - } - }); - } +moduleFor( + 'Engine initializers', + class extends TestCase { + teardown() { + run(() => { + if (myEngineInstance) { + myEngineInstance.destroy(); + } + + if (myEngine) { + myEngine.destroy(); + } + }); + } - ['@test initializers require proper \'name\' and \'initialize\' properties']() { - MyEngine = Engine.extend(); + ["@test initializers require proper 'name' and 'initialize' properties"]() { + MyEngine = Engine.extend(); - expectAssertion(() => { - run(() => { - MyEngine.initializer({ name: 'initializer' }); + expectAssertion(() => { + run(() => { + MyEngine.initializer({ name: 'initializer' }); + }); }); - }); - expectAssertion(() => { - run(() => { - MyEngine.initializer({ initialize() {} }); + expectAssertion(() => { + run(() => { + MyEngine.initializer({ initialize() {} }); + }); }); - }); - } + } - ['@test initializers are passed an Engine'](assert) { - MyEngine = Engine.extend(); + ['@test initializers are passed an Engine'](assert) { + MyEngine = Engine.extend(); - MyEngine.initializer({ - name: 'initializer', - initialize(engine) { - assert.ok(engine instanceof Engine, 'initialize is passed an Engine'); - } - }); + MyEngine.initializer({ + name: 'initializer', + initialize(engine) { + assert.ok(engine instanceof Engine, 'initialize is passed an Engine'); + } + }); - myEngine = MyEngine.create(); - myEngineInstance = myEngine.buildInstance(); - } + myEngine = MyEngine.create(); + myEngineInstance = myEngine.buildInstance(); + } - ['@test initializers can be registered in a specified order'](assert) { - let order = []; - - MyEngine = Engine.extend(); - MyEngine.initializer({ - name: 'fourth', - after: 'third', - initialize() { - order.push('fourth'); - } - }); - - MyEngine.initializer({ - name: 'second', - after: 'first', - before: 'third', - initialize() { - order.push('second'); - } - }); - - MyEngine.initializer({ - name: 'fifth', - after: 'fourth', - before: 'sixth', - initialize() { - order.push('fifth'); - } - }); - - MyEngine.initializer({ - name: 'first', - before: 'second', - initialize() { - order.push('first'); - } - }); - - MyEngine.initializer({ - name: 'third', - initialize() { - order.push('third'); - } - }); - - MyEngine.initializer({ - name: 'sixth', - initialize() { - order.push('sixth'); - } - }); - - myEngine = MyEngine.create(); - myEngineInstance = myEngine.buildInstance(); - - assert.deepEqual(order, ['first', 'second', 'third', 'fourth', 'fifth', 'sixth']); - } + ['@test initializers can be registered in a specified order'](assert) { + let order = []; - ['@test initializers can be registered in a specified order as an array'](assert) { - let order = []; - - MyEngine = Engine.extend(); - - MyEngine.initializer({ - name: 'third', - initialize() { - order.push('third'); - } - }); - - MyEngine.initializer({ - name: 'second', - after: 'first', - before: ['third', 'fourth'], - initialize() { - order.push('second'); - } - }); - - MyEngine.initializer({ - name: 'fourth', - after: ['second', 'third'], - initialize() { - order.push('fourth'); - } - }); - - MyEngine.initializer({ - name: 'fifth', - after: 'fourth', - before: 'sixth', - initialize() { - order.push('fifth'); - } - }); - - MyEngine.initializer({ - name: 'first', - before: ['second'], - initialize() { - order.push('first'); - } - }); - - MyEngine.initializer({ - name: 'sixth', - initialize() { - order.push('sixth'); - } - }); - - myEngine = MyEngine.create(); - myEngineInstance = myEngine.buildInstance(); - - assert.deepEqual(order, ['first', 'second', 'third', 'fourth', 'fifth', 'sixth']); - } - - ['@test initializers can have multiple dependencies'](assert) { - let order = []; - - MyEngine = Engine.extend(); - - let a = { - name: 'a', - before: 'b', - initialize() { - order.push('a'); - } - }; - let b = { - name: 'b', - initialize() { - order.push('b'); - } - }; - let c = { - name: 'c', - after: 'b', - initialize() { - order.push('c'); - } - }; - let afterB = { - name: 'after b', - after: 'b', - initialize() { - order.push('after b'); - } - }; - let afterC = { - name: 'after c', - after: 'c', - initialize() { - order.push('after c'); - } - }; - - MyEngine.initializer(b); - MyEngine.initializer(a); - MyEngine.initializer(afterC); - MyEngine.initializer(afterB); - MyEngine.initializer(c); - - myEngine = MyEngine.create(); - myEngineInstance = myEngine.buildInstance(); - - assert.ok(order.indexOf(a.name) < order.indexOf(b.name), 'a < b'); - assert.ok(order.indexOf(b.name) < order.indexOf(c.name), 'b < c'); - assert.ok(order.indexOf(b.name) < order.indexOf(afterB.name), 'b < afterB'); - assert.ok(order.indexOf(c.name) < order.indexOf(afterC.name), 'c < afterC'); - } + MyEngine = Engine.extend(); + MyEngine.initializer({ + name: 'fourth', + after: 'third', + initialize() { + order.push('fourth'); + } + }); - ['@test initializers set on Engine subclasses are not shared between engines'](assert) { - let firstInitializerRunCount = 0; - let secondInitializerRunCount = 0; - let FirstEngine = Engine.extend(); + MyEngine.initializer({ + name: 'second', + after: 'first', + before: 'third', + initialize() { + order.push('second'); + } + }); - FirstEngine.initializer({ - name: 'first', - initialize() { - firstInitializerRunCount++; - } - }); + MyEngine.initializer({ + name: 'fifth', + after: 'fourth', + before: 'sixth', + initialize() { + order.push('fifth'); + } + }); - let SecondEngine = Engine.extend(); + MyEngine.initializer({ + name: 'first', + before: 'second', + initialize() { + order.push('first'); + } + }); - SecondEngine.initializer({ - name: 'second', - initialize() { - secondInitializerRunCount++; - } - }); + MyEngine.initializer({ + name: 'third', + initialize() { + order.push('third'); + } + }); - let firstEngine = FirstEngine.create(); - let firstEngineInstance = firstEngine.buildInstance(); + MyEngine.initializer({ + name: 'sixth', + initialize() { + order.push('sixth'); + } + }); - assert.equal(firstInitializerRunCount, 1, 'first initializer only was run'); - assert.equal(secondInitializerRunCount, 0, 'first initializer only was run'); + myEngine = MyEngine.create(); + myEngineInstance = myEngine.buildInstance(); + + assert.deepEqual(order, [ + 'first', + 'second', + 'third', + 'fourth', + 'fifth', + 'sixth' + ]); + } + + ['@test initializers can be registered in a specified order as an array']( + assert + ) { + let order = []; + + MyEngine = Engine.extend(); + + MyEngine.initializer({ + name: 'third', + initialize() { + order.push('third'); + } + }); - let secondEngine = SecondEngine.create(); - let secondEngineInstance = secondEngine.buildInstance(); + MyEngine.initializer({ + name: 'second', + after: 'first', + before: ['third', 'fourth'], + initialize() { + order.push('second'); + } + }); - assert.equal(firstInitializerRunCount, 1, 'second initializer only was run'); - assert.equal(secondInitializerRunCount, 1, 'second initializer only was run'); + MyEngine.initializer({ + name: 'fourth', + after: ['second', 'third'], + initialize() { + order.push('fourth'); + } + }); - run(function() { - firstEngineInstance.destroy(); - secondEngineInstance.destroy(); + MyEngine.initializer({ + name: 'fifth', + after: 'fourth', + before: 'sixth', + initialize() { + order.push('fifth'); + } + }); - firstEngine.destroy(); - secondEngine.destroy(); - }); - } + MyEngine.initializer({ + name: 'first', + before: ['second'], + initialize() { + order.push('first'); + } + }); - ['@test initializers are concatenated'](assert) { - let firstInitializerRunCount = 0; - let secondInitializerRunCount = 0; - let FirstEngine = Engine.extend(); + MyEngine.initializer({ + name: 'sixth', + initialize() { + order.push('sixth'); + } + }); - FirstEngine.initializer({ - name: 'first', - initialize() { - firstInitializerRunCount++; - } - }); + myEngine = MyEngine.create(); + myEngineInstance = myEngine.buildInstance(); + + assert.deepEqual(order, [ + 'first', + 'second', + 'third', + 'fourth', + 'fifth', + 'sixth' + ]); + } + + ['@test initializers can have multiple dependencies'](assert) { + let order = []; + + MyEngine = Engine.extend(); + + let a = { + name: 'a', + before: 'b', + initialize() { + order.push('a'); + } + }; + let b = { + name: 'b', + initialize() { + order.push('b'); + } + }; + let c = { + name: 'c', + after: 'b', + initialize() { + order.push('c'); + } + }; + let afterB = { + name: 'after b', + after: 'b', + initialize() { + order.push('after b'); + } + }; + let afterC = { + name: 'after c', + after: 'c', + initialize() { + order.push('after c'); + } + }; + + MyEngine.initializer(b); + MyEngine.initializer(a); + MyEngine.initializer(afterC); + MyEngine.initializer(afterB); + MyEngine.initializer(c); + + myEngine = MyEngine.create(); + myEngineInstance = myEngine.buildInstance(); + + assert.ok(order.indexOf(a.name) < order.indexOf(b.name), 'a < b'); + assert.ok(order.indexOf(b.name) < order.indexOf(c.name), 'b < c'); + assert.ok( + order.indexOf(b.name) < order.indexOf(afterB.name), + 'b < afterB' + ); + assert.ok( + order.indexOf(c.name) < order.indexOf(afterC.name), + 'c < afterC' + ); + } + + ['@test initializers set on Engine subclasses are not shared between engines']( + assert + ) { + let firstInitializerRunCount = 0; + let secondInitializerRunCount = 0; + let FirstEngine = Engine.extend(); - let SecondEngine = FirstEngine.extend(); + FirstEngine.initializer({ + name: 'first', + initialize() { + firstInitializerRunCount++; + } + }); - SecondEngine.initializer({ - name: 'second', - initialize() { - secondInitializerRunCount++; - } - }); + let SecondEngine = Engine.extend(); - let firstEngine = FirstEngine.create(); - let firstEngineInstance = firstEngine.buildInstance(); + SecondEngine.initializer({ + name: 'second', + initialize() { + secondInitializerRunCount++; + } + }); - assert.equal(firstInitializerRunCount, 1, 'first initializer only was run when base class created'); - assert.equal(secondInitializerRunCount, 0, 'second initializer was not run when first base class created'); - firstInitializerRunCount = 0; + let firstEngine = FirstEngine.create(); + let firstEngineInstance = firstEngine.buildInstance(); + + assert.equal( + firstInitializerRunCount, + 1, + 'first initializer only was run' + ); + assert.equal( + secondInitializerRunCount, + 0, + 'first initializer only was run' + ); + + let secondEngine = SecondEngine.create(); + let secondEngineInstance = secondEngine.buildInstance(); + + assert.equal( + firstInitializerRunCount, + 1, + 'second initializer only was run' + ); + assert.equal( + secondInitializerRunCount, + 1, + 'second initializer only was run' + ); + + run(function() { + firstEngineInstance.destroy(); + secondEngineInstance.destroy(); + + firstEngine.destroy(); + secondEngine.destroy(); + }); + } - let secondEngine = SecondEngine.create(); - let secondEngineInstance = secondEngine.buildInstance(); + ['@test initializers are concatenated'](assert) { + let firstInitializerRunCount = 0; + let secondInitializerRunCount = 0; + let FirstEngine = Engine.extend(); - assert.equal(firstInitializerRunCount, 1, 'first initializer was run when subclass created'); - assert.equal(secondInitializerRunCount, 1, 'second initializers was run when subclass created'); + FirstEngine.initializer({ + name: 'first', + initialize() { + firstInitializerRunCount++; + } + }); - run(function() { - firstEngineInstance.destroy(); - secondEngineInstance.destroy(); + let SecondEngine = FirstEngine.extend(); - firstEngine.destroy(); - secondEngine.destroy(); - }); - } + SecondEngine.initializer({ + name: 'second', + initialize() { + secondInitializerRunCount++; + } + }); - ['@test initializers are per-engine'](assert) { - assert.expect(2); + let firstEngine = FirstEngine.create(); + let firstEngineInstance = firstEngine.buildInstance(); + + assert.equal( + firstInitializerRunCount, + 1, + 'first initializer only was run when base class created' + ); + assert.equal( + secondInitializerRunCount, + 0, + 'second initializer was not run when first base class created' + ); + firstInitializerRunCount = 0; + + let secondEngine = SecondEngine.create(); + let secondEngineInstance = secondEngine.buildInstance(); + + assert.equal( + firstInitializerRunCount, + 1, + 'first initializer was run when subclass created' + ); + assert.equal( + secondInitializerRunCount, + 1, + 'second initializers was run when subclass created' + ); + + run(function() { + firstEngineInstance.destroy(); + secondEngineInstance.destroy(); + + firstEngine.destroy(); + secondEngine.destroy(); + }); + } - let FirstEngine = Engine.extend(); + ['@test initializers are per-engine'](assert) { + assert.expect(2); - FirstEngine.initializer({ - name: 'abc', - initialize() {} - }); + let FirstEngine = Engine.extend(); - expectAssertion(function() { FirstEngine.initializer({ name: 'abc', initialize() {} }); - }); - let SecondEngine = Engine.extend(); - SecondEngine.instanceInitializer({ - name: 'abc', - initialize() {} - }); + expectAssertion(function() { + FirstEngine.initializer({ + name: 'abc', + initialize() {} + }); + }); - assert.ok(true, 'Two engines can have initializers named the same.'); - } + let SecondEngine = Engine.extend(); + SecondEngine.instanceInitializer({ + name: 'abc', + initialize() {} + }); - ['@test initializers are executed in their own context'](assert) { - assert.expect(1); + assert.ok(true, 'Two engines can have initializers named the same.'); + } - MyEngine = Engine.extend(); + ['@test initializers are executed in their own context'](assert) { + assert.expect(1); - MyEngine.initializer({ - name: 'coolInitializer', - myProperty: 'cool', - initialize() { - assert.equal(this.myProperty, 'cool', 'should have access to its own context'); - } - }); + MyEngine = Engine.extend(); + + MyEngine.initializer({ + name: 'coolInitializer', + myProperty: 'cool', + initialize() { + assert.equal( + this.myProperty, + 'cool', + 'should have access to its own context' + ); + } + }); - myEngine = MyEngine.create(); - myEngineInstance = myEngine.buildInstance(); + myEngine = MyEngine.create(); + myEngineInstance = myEngine.buildInstance(); + } } -}); +); diff --git a/packages/ember-application/tests/system/engine_instance_initializers_test.js b/packages/ember-application/tests/system/engine_instance_initializers_test.js index a7853bf471e..e85cdef15d6 100644 --- a/packages/ember-application/tests/system/engine_instance_initializers_test.js +++ b/packages/ember-application/tests/system/engine_instance_initializers_test.js @@ -2,385 +2,454 @@ import { run } from 'ember-metal'; import Engine from '../../system/engine'; import EngineInstance from '../../system/engine-instance'; import { setEngineParent } from '../../system/engine-parent'; -import { - moduleFor, - AbstractTestCase as TestCase -} from 'internal-test-helpers'; +import { moduleFor, AbstractTestCase as TestCase } from 'internal-test-helpers'; let MyEngine, myEngine, myEngineInstance; function buildEngineInstance(EngineClass) { let engineInstance = EngineClass.buildInstance(); setEngineParent(engineInstance, { - lookup() { return {}; }, - resolveRegistration() { return {}; } + lookup() { + return {}; + }, + resolveRegistration() { + return {}; + } }); return engineInstance; } -moduleFor('Engine instance initializers', class extends TestCase { - teardown() { - run(() => { - if (myEngineInstance) { - myEngineInstance.destroy(); - } - - if (myEngine) { - myEngine.destroy(); - } - }); - } +moduleFor( + 'Engine instance initializers', + class extends TestCase { + teardown() { + run(() => { + if (myEngineInstance) { + myEngineInstance.destroy(); + } - ['@test initializers require proper \'name\' and \'initialize\' properties']() { - MyEngine = Engine.extend(); + if (myEngine) { + myEngine.destroy(); + } + }); + } - expectAssertion(() => { - run(() => { - MyEngine.instanceInitializer({ name: 'initializer' }); + ["@test initializers require proper 'name' and 'initialize' properties"]() { + MyEngine = Engine.extend(); + + expectAssertion(() => { + run(() => { + MyEngine.instanceInitializer({ name: 'initializer' }); + }); }); - }); - expectAssertion(() => { - run(() => { - MyEngine.instanceInitializer({ initialize() { } }); + expectAssertion(() => { + run(() => { + MyEngine.instanceInitializer({ initialize() {} }); + }); + }); + } + + ['@test initializers are passed an engine instance'](assert) { + MyEngine = Engine.extend(); + + MyEngine.instanceInitializer({ + name: 'initializer', + initialize(instance) { + assert.ok( + instance instanceof EngineInstance, + 'initialize is passed an engine instance' + ); + } }); - }); - } - ['@test initializers are passed an engine instance'](assert) { - MyEngine = Engine.extend(); + myEngine = MyEngine.create(); + myEngineInstance = buildEngineInstance(myEngine); + return myEngineInstance.boot(); + } - MyEngine.instanceInitializer({ - name: 'initializer', - initialize(instance) { - assert.ok(instance instanceof EngineInstance, 'initialize is passed an engine instance'); - } - }); + ['@test initializers can be registered in a specified order'](assert) { + let order = []; - myEngine = MyEngine.create(); - myEngineInstance = buildEngineInstance(myEngine); - return myEngineInstance.boot(); - } + MyEngine = Engine.extend(); - ['@test initializers can be registered in a specified order'](assert) { - let order = []; - - MyEngine = Engine.extend(); - - MyEngine.instanceInitializer({ - name: 'fourth', - after: 'third', - initialize() { - order.push('fourth'); - } - }); - - MyEngine.instanceInitializer({ - name: 'second', - after: 'first', - before: 'third', - initialize() { - order.push('second'); - } - }); - - MyEngine.instanceInitializer({ - name: 'fifth', - after: 'fourth', - before: 'sixth', - initialize() { - order.push('fifth'); - } - }); - - MyEngine.instanceInitializer({ - name: 'first', - before: 'second', - initialize() { - order.push('first'); - } - }); - - MyEngine.instanceInitializer({ - name: 'third', - initialize() { - order.push('third'); - } - }); - - MyEngine.instanceInitializer({ - name: 'sixth', - initialize() { - order.push('sixth'); - } - }); - - myEngine = MyEngine.create(); - myEngineInstance = buildEngineInstance(myEngine); - - return myEngineInstance.boot().then(() => { - assert.deepEqual(order, ['first', 'second', 'third', 'fourth', 'fifth', 'sixth']); - }); - } + MyEngine.instanceInitializer({ + name: 'fourth', + after: 'third', + initialize() { + order.push('fourth'); + } + }); - ['@test initializers can be registered in a specified order as an array'](assert) { - let order = []; - MyEngine = Engine.extend(); - - MyEngine.instanceInitializer({ - name: 'third', - initialize() { - order.push('third'); - } - }); - - MyEngine.instanceInitializer({ - name: 'second', - after: 'first', - before: ['third', 'fourth'], - initialize() { - order.push('second'); - } - }); - - MyEngine.instanceInitializer({ - name: 'fourth', - after: ['second', 'third'], - initialize() { - order.push('fourth'); - } - }); - - MyEngine.instanceInitializer({ - name: 'fifth', - after: 'fourth', - before: 'sixth', - initialize() { - order.push('fifth'); - } - }); - - MyEngine.instanceInitializer({ - name: 'first', - before: ['second'], - initialize() { - order.push('first'); - } - }); - - MyEngine.instanceInitializer({ - name: 'sixth', - initialize() { - order.push('sixth'); - } - }); - - myEngine = MyEngine.create(); - myEngineInstance = buildEngineInstance(myEngine); - - return myEngineInstance.boot().then(() => { - assert.deepEqual(order, ['first', 'second', 'third', 'fourth', 'fifth', 'sixth']); - }); - } + MyEngine.instanceInitializer({ + name: 'second', + after: 'first', + before: 'third', + initialize() { + order.push('second'); + } + }); - ['@test initializers can have multiple dependencies'](assert) { - let order = []; - - MyEngine = Engine.extend(); - - let a = { - name: 'a', - before: 'b', - initialize() { - order.push('a'); - } - }; - let b = { - name: 'b', - initialize() { - order.push('b'); - } - }; - let c = { - name: 'c', - after: 'b', - initialize() { - order.push('c'); - } - }; - let afterB = { - name: 'after b', - after: 'b', - initialize() { - order.push('after b'); - } - }; - let afterC = { - name: 'after c', - after: 'c', - initialize() { - order.push('after c'); - } - }; - - MyEngine.instanceInitializer(b); - MyEngine.instanceInitializer(a); - MyEngine.instanceInitializer(afterC); - MyEngine.instanceInitializer(afterB); - MyEngine.instanceInitializer(c); - - myEngine = MyEngine.create(); - myEngineInstance = buildEngineInstance(myEngine); - - return myEngineInstance.boot().then(() => { - assert.ok(order.indexOf(a.name) < order.indexOf(b.name), 'a < b'); - assert.ok(order.indexOf(b.name) < order.indexOf(c.name), 'b < c'); - assert.ok(order.indexOf(b.name) < order.indexOf(afterB.name), 'b < afterB'); - assert.ok(order.indexOf(c.name) < order.indexOf(afterC.name), 'c < afterC'); - }); - } + MyEngine.instanceInitializer({ + name: 'fifth', + after: 'fourth', + before: 'sixth', + initialize() { + order.push('fifth'); + } + }); - ['@test initializers set on Engine subclasses should not be shared between engines'](assert) { - let firstInitializerRunCount = 0; - let secondInitializerRunCount = 0; - let FirstEngine = Engine.extend(); - let firstEngine, firstEngineInstance; - - FirstEngine.instanceInitializer({ - name: 'first', - initialize() { - firstInitializerRunCount++; - } - }); - - let SecondEngine = Engine.extend(); - let secondEngine, secondEngineInstance; - - SecondEngine.instanceInitializer({ - name: 'second', - initialize() { - secondInitializerRunCount++; - } - }); - - firstEngine = FirstEngine.create(); - firstEngineInstance = buildEngineInstance(firstEngine); - - return firstEngineInstance.boot() - .then(() => { - assert.equal(firstInitializerRunCount, 1, 'first initializer only was run'); - assert.equal(secondInitializerRunCount, 0, 'first initializer only was run'); - - secondEngine = SecondEngine.create(); - secondEngineInstance = buildEngineInstance(secondEngine); - return secondEngineInstance.boot(); - }) - .then(() => { - assert.equal(firstInitializerRunCount, 1, 'second initializer only was run'); - assert.equal(secondInitializerRunCount, 1, 'second initializer only was run'); + MyEngine.instanceInitializer({ + name: 'first', + before: 'second', + initialize() { + order.push('first'); + } + }); - run(() => { - firstEngineInstance.destroy(); - secondEngineInstance.destroy(); + MyEngine.instanceInitializer({ + name: 'third', + initialize() { + order.push('third'); + } + }); - firstEngine.destroy(); - secondEngine.destroy(); - }); + MyEngine.instanceInitializer({ + name: 'sixth', + initialize() { + order.push('sixth'); + } }); - } - ['@test initializers are concatenated'](assert) { - let firstInitializerRunCount = 0; - let secondInitializerRunCount = 0; - let FirstEngine = Engine.extend(); - - FirstEngine.instanceInitializer({ - name: 'first', - initialize() { - firstInitializerRunCount++; - } - }); - - let SecondEngine = FirstEngine.extend(); - - SecondEngine.instanceInitializer({ - name: 'second', - initialize() { - secondInitializerRunCount++; - } - }); - - let firstEngine = FirstEngine.create(); - let firstEngineInstance = buildEngineInstance(firstEngine); - - let secondEngine, secondEngineInstance; - - return firstEngineInstance.boot() - .then(() => { - assert.equal(firstInitializerRunCount, 1, 'first initializer only was run when base class created'); - assert.equal(secondInitializerRunCount, 0, 'second initializer was not run when first base class created'); - firstInitializerRunCount = 0; - - secondEngine = SecondEngine.create(); - secondEngineInstance = buildEngineInstance(secondEngine); - return secondEngineInstance.boot(); - }) - .then(() => { - assert.equal(firstInitializerRunCount, 1, 'first initializer was run when subclass created'); - assert.equal(secondInitializerRunCount, 1, 'second initializers was run when subclass created'); + myEngine = MyEngine.create(); + myEngineInstance = buildEngineInstance(myEngine); + + return myEngineInstance.boot().then(() => { + assert.deepEqual(order, [ + 'first', + 'second', + 'third', + 'fourth', + 'fifth', + 'sixth' + ]); + }); + } + + ['@test initializers can be registered in a specified order as an array']( + assert + ) { + let order = []; + MyEngine = Engine.extend(); + + MyEngine.instanceInitializer({ + name: 'third', + initialize() { + order.push('third'); + } + }); - run(() => { - firstEngineInstance.destroy(); - secondEngineInstance.destroy(); + MyEngine.instanceInitializer({ + name: 'second', + after: 'first', + before: ['third', 'fourth'], + initialize() { + order.push('second'); + } + }); - firstEngine.destroy(); - secondEngine.destroy(); + MyEngine.instanceInitializer({ + name: 'fourth', + after: ['second', 'third'], + initialize() { + order.push('fourth'); + } + }); + + MyEngine.instanceInitializer({ + name: 'fifth', + after: 'fourth', + before: 'sixth', + initialize() { + order.push('fifth'); + } + }); + + MyEngine.instanceInitializer({ + name: 'first', + before: ['second'], + initialize() { + order.push('first'); + } + }); + + MyEngine.instanceInitializer({ + name: 'sixth', + initialize() { + order.push('sixth'); + } + }); + + myEngine = MyEngine.create(); + myEngineInstance = buildEngineInstance(myEngine); + + return myEngineInstance.boot().then(() => { + assert.deepEqual(order, [ + 'first', + 'second', + 'third', + 'fourth', + 'fifth', + 'sixth' + ]); + }); + } + + ['@test initializers can have multiple dependencies'](assert) { + let order = []; + + MyEngine = Engine.extend(); + + let a = { + name: 'a', + before: 'b', + initialize() { + order.push('a'); + } + }; + let b = { + name: 'b', + initialize() { + order.push('b'); + } + }; + let c = { + name: 'c', + after: 'b', + initialize() { + order.push('c'); + } + }; + let afterB = { + name: 'after b', + after: 'b', + initialize() { + order.push('after b'); + } + }; + let afterC = { + name: 'after c', + after: 'c', + initialize() { + order.push('after c'); + } + }; + + MyEngine.instanceInitializer(b); + MyEngine.instanceInitializer(a); + MyEngine.instanceInitializer(afterC); + MyEngine.instanceInitializer(afterB); + MyEngine.instanceInitializer(c); + + myEngine = MyEngine.create(); + myEngineInstance = buildEngineInstance(myEngine); + + return myEngineInstance.boot().then(() => { + assert.ok(order.indexOf(a.name) < order.indexOf(b.name), 'a < b'); + assert.ok(order.indexOf(b.name) < order.indexOf(c.name), 'b < c'); + assert.ok( + order.indexOf(b.name) < order.indexOf(afterB.name), + 'b < afterB' + ); + assert.ok( + order.indexOf(c.name) < order.indexOf(afterC.name), + 'c < afterC' + ); + }); + } + + ['@test initializers set on Engine subclasses should not be shared between engines']( + assert + ) { + let firstInitializerRunCount = 0; + let secondInitializerRunCount = 0; + let FirstEngine = Engine.extend(); + let firstEngine, firstEngineInstance; + + FirstEngine.instanceInitializer({ + name: 'first', + initialize() { + firstInitializerRunCount++; + } + }); + + let SecondEngine = Engine.extend(); + let secondEngine, secondEngineInstance; + + SecondEngine.instanceInitializer({ + name: 'second', + initialize() { + secondInitializerRunCount++; + } + }); + + firstEngine = FirstEngine.create(); + firstEngineInstance = buildEngineInstance(firstEngine); + + return firstEngineInstance + .boot() + .then(() => { + assert.equal( + firstInitializerRunCount, + 1, + 'first initializer only was run' + ); + assert.equal( + secondInitializerRunCount, + 0, + 'first initializer only was run' + ); + + secondEngine = SecondEngine.create(); + secondEngineInstance = buildEngineInstance(secondEngine); + return secondEngineInstance.boot(); + }) + .then(() => { + assert.equal( + firstInitializerRunCount, + 1, + 'second initializer only was run' + ); + assert.equal( + secondInitializerRunCount, + 1, + 'second initializer only was run' + ); + + run(() => { + firstEngineInstance.destroy(); + secondEngineInstance.destroy(); + + firstEngine.destroy(); + secondEngine.destroy(); + }); }); + } + + ['@test initializers are concatenated'](assert) { + let firstInitializerRunCount = 0; + let secondInitializerRunCount = 0; + let FirstEngine = Engine.extend(); + + FirstEngine.instanceInitializer({ + name: 'first', + initialize() { + firstInitializerRunCount++; + } }); - } - ['@test initializers are per-engine'](assert) { - assert.expect(2); + let SecondEngine = FirstEngine.extend(); + + SecondEngine.instanceInitializer({ + name: 'second', + initialize() { + secondInitializerRunCount++; + } + }); + + let firstEngine = FirstEngine.create(); + let firstEngineInstance = buildEngineInstance(firstEngine); + + let secondEngine, secondEngineInstance; + + return firstEngineInstance + .boot() + .then(() => { + assert.equal( + firstInitializerRunCount, + 1, + 'first initializer only was run when base class created' + ); + assert.equal( + secondInitializerRunCount, + 0, + 'second initializer was not run when first base class created' + ); + firstInitializerRunCount = 0; + + secondEngine = SecondEngine.create(); + secondEngineInstance = buildEngineInstance(secondEngine); + return secondEngineInstance.boot(); + }) + .then(() => { + assert.equal( + firstInitializerRunCount, + 1, + 'first initializer was run when subclass created' + ); + assert.equal( + secondInitializerRunCount, + 1, + 'second initializers was run when subclass created' + ); + + run(() => { + firstEngineInstance.destroy(); + secondEngineInstance.destroy(); + + firstEngine.destroy(); + secondEngine.destroy(); + }); + }); + } - let FirstEngine = Engine.extend(); + ['@test initializers are per-engine'](assert) { + assert.expect(2); - FirstEngine.instanceInitializer({ - name: 'abc', - initialize() { } - }); + let FirstEngine = Engine.extend(); - expectAssertion(() => { FirstEngine.instanceInitializer({ name: 'abc', - initialize() { } + initialize() {} }); - }); - let SecondEngine = Engine.extend(); - SecondEngine.instanceInitializer({ - name: 'abc', - initialize() { } - }); + expectAssertion(() => { + FirstEngine.instanceInitializer({ + name: 'abc', + initialize() {} + }); + }); - assert.ok(true, 'Two engines can have initializers named the same.'); - } + let SecondEngine = Engine.extend(); + SecondEngine.instanceInitializer({ + name: 'abc', + initialize() {} + }); + + assert.ok(true, 'Two engines can have initializers named the same.'); + } - ['@test initializers are executed in their own context'](assert) { - assert.expect(1); + ['@test initializers are executed in their own context'](assert) { + assert.expect(1); - let MyEngine = Engine.extend(); + let MyEngine = Engine.extend(); - MyEngine.instanceInitializer({ - name: 'coolInitializer', - myProperty: 'cool', - initialize() { - assert.equal(this.myProperty, 'cool', 'should have access to its own context'); - } - }); + MyEngine.instanceInitializer({ + name: 'coolInitializer', + myProperty: 'cool', + initialize() { + assert.equal( + this.myProperty, + 'cool', + 'should have access to its own context' + ); + } + }); - myEngine = MyEngine.create(); - myEngineInstance = buildEngineInstance(myEngine); + myEngine = MyEngine.create(); + myEngineInstance = buildEngineInstance(myEngine); - return myEngineInstance.boot(); + return myEngineInstance.boot(); + } } -}); +); diff --git a/packages/ember-application/tests/system/engine_instance_test.js b/packages/ember-application/tests/system/engine_instance_test.js index 14c41ce15ba..0ff200670a7 100644 --- a/packages/ember-application/tests/system/engine_instance_test.js +++ b/packages/ember-application/tests/system/engine_instance_test.js @@ -3,105 +3,119 @@ import EngineInstance from '../../system/engine-instance'; import { getEngineParent, setEngineParent } from '../../system/engine-parent'; import { run } from 'ember-metal'; import { factory } from 'internal-test-helpers'; -import { - moduleFor, - AbstractTestCase as TestCase -} from 'internal-test-helpers'; - +import { moduleFor, AbstractTestCase as TestCase } from 'internal-test-helpers'; let engine, engineInstance; -moduleFor('EngineInstance', class extends TestCase { - constructor() { - super(); - - run(() => { - engine = Engine.create({ router: null }); - }); - } +moduleFor( + 'EngineInstance', + class extends TestCase { + constructor() { + super(); - teardown() { - if (engineInstance) { - run(engineInstance, 'destroy'); + run(() => { + engine = Engine.create({ router: null }); + }); } - if (engine) { - run(engine, 'destroy'); + teardown() { + if (engineInstance) { + run(engineInstance, 'destroy'); + } + + if (engine) { + run(engine, 'destroy'); + } } - } - ['@test an engine instance can be created based upon a base engine'](assert) { - run(() => { - engineInstance = EngineInstance.create({ base: engine }); - }); + ['@test an engine instance can be created based upon a base engine']( + assert + ) { + run(() => { + engineInstance = EngineInstance.create({ base: engine }); + }); - assert.ok(engineInstance, 'instance should be created'); - assert.equal(engineInstance.base, engine, 'base should be set to engine'); - } + assert.ok(engineInstance, 'instance should be created'); + assert.equal(engineInstance.base, engine, 'base should be set to engine'); + } - ['@test unregistering a factory clears all cached instances of that factory'](assert) { - assert.expect(3); + ['@test unregistering a factory clears all cached instances of that factory']( + assert + ) { + assert.expect(3); - engineInstance = run(() => EngineInstance.create({ base: engine })); + engineInstance = run(() => EngineInstance.create({ base: engine })); - let PostComponent = factory(); + let PostComponent = factory(); - engineInstance.register('component:post', PostComponent); + engineInstance.register('component:post', PostComponent); - let postComponent1 = engineInstance.lookup('component:post'); - assert.ok(postComponent1, 'lookup creates instance'); + let postComponent1 = engineInstance.lookup('component:post'); + assert.ok(postComponent1, 'lookup creates instance'); - engineInstance.unregister('component:post'); - engineInstance.register('component:post', PostComponent); + engineInstance.unregister('component:post'); + engineInstance.register('component:post', PostComponent); - let postComponent2 = engineInstance.lookup('component:post'); - assert.ok(postComponent2, 'lookup creates instance'); + let postComponent2 = engineInstance.lookup('component:post'); + assert.ok(postComponent2, 'lookup creates instance'); - assert.notStrictEqual(postComponent1, postComponent2, 'lookup creates a brand new instance because previous one was reset'); - } + assert.notStrictEqual( + postComponent1, + postComponent2, + 'lookup creates a brand new instance because previous one was reset' + ); + } - ['@test can be booted when its parent has been set'](assert) { - assert.expect(3); + ['@test can be booted when its parent has been set'](assert) { + assert.expect(3); - engineInstance = run(() => EngineInstance.create({ base: engine })); + engineInstance = run(() => EngineInstance.create({ base: engine })); - expectAssertion(() => { - engineInstance._bootSync(); - }, 'An engine instance\'s parent must be set via `setEngineParent(engine, parent)` prior to calling `engine.boot()`.'); + expectAssertion(() => { + engineInstance._bootSync(); + }, "An engine instance's parent must be set via `setEngineParent(engine, parent)` prior to calling `engine.boot()`."); - setEngineParent(engineInstance, {}); + setEngineParent(engineInstance, {}); - // Stub `cloneParentDependencies`, the internals of which are tested along - // with application instances. - engineInstance.cloneParentDependencies = function() { - assert.ok(true, 'parent dependencies are cloned'); - }; + // Stub `cloneParentDependencies`, the internals of which are tested along + // with application instances. + engineInstance.cloneParentDependencies = function() { + assert.ok(true, 'parent dependencies are cloned'); + }; - return engineInstance.boot().then(() => { - assert.ok(true, 'boot successful'); - }); - } + return engineInstance.boot().then(() => { + assert.ok(true, 'boot successful'); + }); + } - ['@test can build a child instance of a registered engine'](assert) { - let ChatEngine = Engine.extend(); - let chatEngineInstance; + ['@test can build a child instance of a registered engine'](assert) { + let ChatEngine = Engine.extend(); + let chatEngineInstance; - engine.register('engine:chat', ChatEngine); + engine.register('engine:chat', ChatEngine); - run(() => { - engineInstance = EngineInstance.create({ base: engine }); + run(() => { + engineInstance = EngineInstance.create({ base: engine }); - // Try to build an unregistered engine. - assert.throws(() => { - engineInstance.buildChildEngineInstance('fake'); - }, `You attempted to mount the engine 'fake', but it is not registered with its parent.`); + // Try to build an unregistered engine. + assert.throws(() => { + engineInstance.buildChildEngineInstance('fake'); + }, `You attempted to mount the engine 'fake', but it is not registered with its parent.`); - // Build the `chat` engine, registered above. - chatEngineInstance = engineInstance.buildChildEngineInstance('chat'); - }); + // Build the `chat` engine, registered above. + chatEngineInstance = engineInstance.buildChildEngineInstance('chat'); + }); - assert.ok(chatEngineInstance, 'child engine instance successfully created'); + assert.ok( + chatEngineInstance, + 'child engine instance successfully created' + ); - assert.strictEqual(getEngineParent(chatEngineInstance), engineInstance, 'child engine instance is assigned the correct parent'); + assert.strictEqual( + getEngineParent(chatEngineInstance), + engineInstance, + 'child engine instance is assigned the correct parent' + ); + } } -}); +); diff --git a/packages/ember-application/tests/system/engine_parent_test.js b/packages/ember-application/tests/system/engine_parent_test.js index c5d2e18e897..c977a16f2e4 100644 --- a/packages/ember-application/tests/system/engine_parent_test.js +++ b/packages/ember-application/tests/system/engine_parent_test.js @@ -3,21 +3,35 @@ import { setEngineParent, ENGINE_PARENT } from '../../system/engine-parent'; -import { - moduleFor, - AbstractTestCase as TestCase -} from 'internal-test-helpers'; +import { moduleFor, AbstractTestCase as TestCase } from 'internal-test-helpers'; -moduleFor('EngineParent', class extends TestCase { - ['@test An engine\'s parent can be set with `setEngineParent` and retrieved with `getEngineParent`'](assert) { - let engine = {}; - let parent = {}; +moduleFor( + 'EngineParent', + class extends TestCase { + ["@test An engine's parent can be set with `setEngineParent` and retrieved with `getEngineParent`"]( + assert + ) { + let engine = {}; + let parent = {}; - assert.strictEqual(getEngineParent(engine), undefined, 'parent has not been set'); + assert.strictEqual( + getEngineParent(engine), + undefined, + 'parent has not been set' + ); - setEngineParent(engine, parent); + setEngineParent(engine, parent); - assert.strictEqual(getEngineParent(engine), parent, 'parent has been set'); - assert.strictEqual(engine[ENGINE_PARENT], parent, 'parent has been set to the ENGINE_PARENT symbol'); + assert.strictEqual( + getEngineParent(engine), + parent, + 'parent has been set' + ); + assert.strictEqual( + engine[ENGINE_PARENT], + parent, + 'parent has been set to the ENGINE_PARENT symbol' + ); + } } -}); +); diff --git a/packages/ember-application/tests/system/engine_test.js b/packages/ember-application/tests/system/engine_test.js index 9e6197ee34f..0d9315d8722 100644 --- a/packages/ember-application/tests/system/engine_test.js +++ b/packages/ember-application/tests/system/engine_test.js @@ -7,77 +7,174 @@ import { verifyInjection, verifyRegistration } from '../test-helpers/registry-check'; -import { - moduleFor, - AbstractTestCase as TestCase -} from 'internal-test-helpers'; - +import { moduleFor, AbstractTestCase as TestCase } from 'internal-test-helpers'; let engine; let originalLookup = context.lookup; let lookup; -moduleFor('Engine', class extends TestCase { - constructor() { - super(); +moduleFor( + 'Engine', + class extends TestCase { + constructor() { + super(); - lookup = context.lookup = {}; - engine = run(() => Engine.create()); - } + lookup = context.lookup = {}; + engine = run(() => Engine.create()); + } - teardown() { - context.lookup = originalLookup; - if (engine) { - run(engine, 'destroy'); + teardown() { + context.lookup = originalLookup; + if (engine) { + run(engine, 'destroy'); + } } - } - ['@test acts like a namespace'](assert) { - engine = run(() => lookup.TestEngine = Engine.create()); + ['@test acts like a namespace'](assert) { + engine = run(() => (lookup.TestEngine = Engine.create())); - engine.Foo = EmberObject.extend(); - assert.equal(engine.Foo.toString(), 'TestEngine.Foo', 'Classes pick up their parent namespace'); - } + engine.Foo = EmberObject.extend(); + assert.equal( + engine.Foo.toString(), + 'TestEngine.Foo', + 'Classes pick up their parent namespace' + ); + } - ['@test builds a registry'](assert) { - assert.strictEqual(engine.resolveRegistration('application:main'), engine, `application:main is registered`); - assert.deepEqual(engine.registeredOptionsForType('component'), { singleton: false }, `optionsForType 'component'`); - assert.deepEqual(engine.registeredOptionsForType('view'), { singleton: false }, `optionsForType 'view'`); - verifyRegistration(assert, engine, 'controller:basic'); - verifyInjection(assert, engine, 'view', '_viewRegistry', '-view-registry:main'); - verifyInjection(assert, engine, 'route', '_topLevelViewTemplate', 'template:-outlet'); - verifyInjection(assert, engine, 'view:-outlet', 'namespace', 'application:main'); + ['@test builds a registry'](assert) { + assert.strictEqual( + engine.resolveRegistration('application:main'), + engine, + `application:main is registered` + ); + assert.deepEqual( + engine.registeredOptionsForType('component'), + { singleton: false }, + `optionsForType 'component'` + ); + assert.deepEqual( + engine.registeredOptionsForType('view'), + { singleton: false }, + `optionsForType 'view'` + ); + verifyRegistration(assert, engine, 'controller:basic'); + verifyInjection( + assert, + engine, + 'view', + '_viewRegistry', + '-view-registry:main' + ); + verifyInjection( + assert, + engine, + 'route', + '_topLevelViewTemplate', + 'template:-outlet' + ); + verifyInjection( + assert, + engine, + 'view:-outlet', + 'namespace', + 'application:main' + ); - verifyInjection(assert, engine, 'controller', 'target', 'router:main'); - verifyInjection(assert, engine, 'controller', 'namespace', 'application:main'); + verifyInjection(assert, engine, 'controller', 'target', 'router:main'); + verifyInjection( + assert, + engine, + 'controller', + 'namespace', + 'application:main' + ); - verifyInjection(assert, engine, 'router', '_bucketCache', P`-bucket-cache:main`); - verifyInjection(assert, engine, 'route', '_bucketCache', P`-bucket-cache:main`); + verifyInjection( + assert, + engine, + 'router', + '_bucketCache', + P`-bucket-cache:main` + ); + verifyInjection( + assert, + engine, + 'route', + '_bucketCache', + P`-bucket-cache:main` + ); - verifyInjection(assert, engine, 'route', '_router', 'router:main'); + verifyInjection(assert, engine, 'route', '_router', 'router:main'); - verifyRegistration(assert, engine, 'component:-text-field'); - verifyRegistration(assert, engine, 'component:-text-area'); - verifyRegistration(assert, engine, 'component:-checkbox'); - verifyRegistration(assert, engine, 'component:link-to'); + verifyRegistration(assert, engine, 'component:-text-field'); + verifyRegistration(assert, engine, 'component:-text-area'); + verifyRegistration(assert, engine, 'component:-checkbox'); + verifyRegistration(assert, engine, 'component:link-to'); - verifyRegistration(assert, engine, 'service:-routing'); - verifyInjection(assert, engine, 'service:-routing', 'router', 'router:main'); + verifyRegistration(assert, engine, 'service:-routing'); + verifyInjection( + assert, + engine, + 'service:-routing', + 'router', + 'router:main' + ); - // DEBUGGING - verifyRegistration(assert, engine, 'resolver-for-debugging:main'); - verifyInjection(assert, engine, 'container-debug-adapter:main', 'resolver', 'resolver-for-debugging:main'); - verifyInjection(assert, engine, 'data-adapter:main', 'containerDebugAdapter', 'container-debug-adapter:main'); - verifyRegistration(assert, engine, 'container-debug-adapter:main'); - verifyRegistration(assert, engine, 'component-lookup:main'); + // DEBUGGING + verifyRegistration(assert, engine, 'resolver-for-debugging:main'); + verifyInjection( + assert, + engine, + 'container-debug-adapter:main', + 'resolver', + 'resolver-for-debugging:main' + ); + verifyInjection( + assert, + engine, + 'data-adapter:main', + 'containerDebugAdapter', + 'container-debug-adapter:main' + ); + verifyRegistration(assert, engine, 'container-debug-adapter:main'); + verifyRegistration(assert, engine, 'component-lookup:main'); - verifyInjection(assert, engine, 'service:-dom-changes', 'document', 'service:-document'); - verifyInjection(assert, engine, 'service:-dom-tree-construction', 'document', 'service:-document'); - verifyRegistration(assert, engine, 'view:-outlet'); - verifyRegistration(assert, engine, P`template:components/-default`); - verifyRegistration(assert, engine, 'template:-outlet'); - verifyInjection(assert, engine, 'view:-outlet', 'template', 'template:-outlet'); - verifyInjection(assert, engine, 'template', 'compiler', P`template-compiler:main`); - assert.deepEqual(engine.registeredOptionsForType('helper'), { instantiate: false }, `optionsForType 'helper'`); + verifyInjection( + assert, + engine, + 'service:-dom-changes', + 'document', + 'service:-document' + ); + verifyInjection( + assert, + engine, + 'service:-dom-tree-construction', + 'document', + 'service:-document' + ); + verifyRegistration(assert, engine, 'view:-outlet'); + verifyRegistration(assert, engine, P`template:components/-default`); + verifyRegistration(assert, engine, 'template:-outlet'); + verifyInjection( + assert, + engine, + 'view:-outlet', + 'template', + 'template:-outlet' + ); + verifyInjection( + assert, + engine, + 'template', + 'compiler', + P`template-compiler:main` + ); + assert.deepEqual( + engine.registeredOptionsForType('helper'), + { instantiate: false }, + `optionsForType 'helper'` + ); + } } -}); +); diff --git a/packages/ember-application/tests/system/initializers_test.js b/packages/ember-application/tests/system/initializers_test.js index 03aa35d4a4a..96c24d1b565 100644 --- a/packages/ember-application/tests/system/initializers_test.js +++ b/packages/ember-application/tests/system/initializers_test.js @@ -2,361 +2,447 @@ import { assign } from 'ember-utils'; import { moduleFor, AutobootApplicationTestCase } from 'internal-test-helpers'; import { Application } from 'ember-application'; -moduleFor('Application initializers', class extends AutobootApplicationTestCase { - get fixture() { - return `
ONE
+moduleFor( + 'Application initializers', + class extends AutobootApplicationTestCase { + get fixture() { + return `
ONE
TWO
`; - } - - get applicationOptions() { - return assign(super.applicationOptions, { - rootElement: '#one' - }); - } - - createSecondApplication(options, MyApplication = Application) { - let myOptions = assign(this.applicationOptions, { - rootElement: '#two' - }, options); - let secondApp = this.secondApp = MyApplication.create(myOptions); - return secondApp; - } - - teardown() { - super.teardown(); - - if (this.secondApp) { - this.runTask(() => this.secondApp.destroy()); } - } - - [`@test initializers require proper 'name' and 'initialize' properties`]() { - let MyApplication = Application.extend(); - expectAssertion(() => { - MyApplication.initializer({ name: 'initializer' }); - }); - - expectAssertion(() => { - MyApplication.initializer({ initialize() { } }); - }); - } + get applicationOptions() { + return assign(super.applicationOptions, { + rootElement: '#one' + }); + } - [`@test initializers that throw errors cause the boot promise to reject with the error`](assert) { - assert.expect(2); + createSecondApplication(options, MyApplication = Application) { + let myOptions = assign( + this.applicationOptions, + { + rootElement: '#two' + }, + options + ); + let secondApp = (this.secondApp = MyApplication.create(myOptions)); + return secondApp; + } - let MyApplication = Application.extend(); + teardown() { + super.teardown(); - MyApplication.initializer({ - name: 'initializer', - initialize() { throw new Error('boot failure'); } - }); + if (this.secondApp) { + this.runTask(() => this.secondApp.destroy()); + } + } - this.runTask(() => { - this.createApplication({ - autoboot: false - }, MyApplication); - }); + [`@test initializers require proper 'name' and 'initialize' properties`]() { + let MyApplication = Application.extend(); - let app = this.application; + expectAssertion(() => { + MyApplication.initializer({ name: 'initializer' }); + }); - try { - this.runTask(() => { - app.boot().then(() => { - assert.ok(false, 'The boot promise should not resolve when there is a boot error'); - }, error => { - assert.ok(error instanceof Error, 'The boot promise should reject with an error'); - assert.equal(error.message, 'boot failure'); - }); + expectAssertion(() => { + MyApplication.initializer({ initialize() {} }); }); - } catch (error) { - assert.ok(false, 'The boot method should not throw'); - throw error; } - } - [`@test initializers are passed an App`](assert) { - let MyApplication = Application.extend(); + [`@test initializers that throw errors cause the boot promise to reject with the error`]( + assert + ) { + assert.expect(2); - MyApplication.initializer({ - name: 'initializer', - initialize(App) { - assert.ok(App instanceof Application, 'initialize is passed an Application'); - } - }); - - this.runTask(() => this.createApplication({}, MyApplication)); - } + let MyApplication = Application.extend(); - [`@test initializers can be registered in a specified order`](assert) { - let order = []; - let MyApplication = Application.extend(); - - MyApplication.initializer({ - name: 'fourth', - after: 'third', - initialize() { - order.push('fourth'); - } - }); - - MyApplication.initializer({ - name: 'second', - after: 'first', - before: 'third', - initialize() { - order.push('second'); - } - }); - - MyApplication.initializer({ - name: 'fifth', - after: 'fourth', - before: 'sixth', - initialize() { - order.push('fifth'); - } - }); - - MyApplication.initializer({ - name: 'first', - before: 'second', - initialize() { - order.push('first'); - } - }); + MyApplication.initializer({ + name: 'initializer', + initialize() { + throw new Error('boot failure'); + } + }); - MyApplication.initializer({ - name: 'third', - initialize() { - order.push('third'); - } - }); + this.runTask(() => { + this.createApplication( + { + autoboot: false + }, + MyApplication + ); + }); - MyApplication.initializer({ - name: 'sixth', - initialize() { - order.push('sixth'); + let app = this.application; + + try { + this.runTask(() => { + app.boot().then( + () => { + assert.ok( + false, + 'The boot promise should not resolve when there is a boot error' + ); + }, + error => { + assert.ok( + error instanceof Error, + 'The boot promise should reject with an error' + ); + assert.equal(error.message, 'boot failure'); + } + ); + }); + } catch (error) { + assert.ok(false, 'The boot method should not throw'); + throw error; } - }); + } - this.runTask(() => this.createApplication({}, MyApplication)); + [`@test initializers are passed an App`](assert) { + let MyApplication = Application.extend(); + + MyApplication.initializer({ + name: 'initializer', + initialize(App) { + assert.ok( + App instanceof Application, + 'initialize is passed an Application' + ); + } + }); - assert.deepEqual(order, ['first', 'second', 'third', 'fourth', 'fifth', 'sixth']); - } + this.runTask(() => this.createApplication({}, MyApplication)); + } - [`@test initializers can be registered in a specified order as an array`](assert) { - let order = []; - let MyApplication = Application.extend(); + [`@test initializers can be registered in a specified order`](assert) { + let order = []; + let MyApplication = Application.extend(); - MyApplication.initializer({ - name: 'third', - initialize() { - order.push('third'); - } - }); - - MyApplication.initializer({ - name: 'second', - after: 'first', - before: ['third', 'fourth'], - initialize() { - order.push('second'); - } - }); + MyApplication.initializer({ + name: 'fourth', + after: 'third', + initialize() { + order.push('fourth'); + } + }); - MyApplication.initializer({ - name: 'fourth', - after: ['second', 'third'], - initialize() { - order.push('fourth'); - } - }); - - MyApplication.initializer({ - name: 'fifth', - after: 'fourth', - before: 'sixth', - initialize() { - order.push('fifth'); - } - }); + MyApplication.initializer({ + name: 'second', + after: 'first', + before: 'third', + initialize() { + order.push('second'); + } + }); - MyApplication.initializer({ - name: 'first', - before: ['second'], - initialize() { - order.push('first'); - } - }); + MyApplication.initializer({ + name: 'fifth', + after: 'fourth', + before: 'sixth', + initialize() { + order.push('fifth'); + } + }); - MyApplication.initializer({ - name: 'sixth', - initialize() { - order.push('sixth'); - } - }); + MyApplication.initializer({ + name: 'first', + before: 'second', + initialize() { + order.push('first'); + } + }); - this.runTask(() => this.createApplication({}, MyApplication)); + MyApplication.initializer({ + name: 'third', + initialize() { + order.push('third'); + } + }); - assert.deepEqual(order, ['first', 'second', 'third', 'fourth', 'fifth', 'sixth']); - } + MyApplication.initializer({ + name: 'sixth', + initialize() { + order.push('sixth'); + } + }); - [`@test initializers can have multiple dependencies`](assert) { - let order = []; - let MyApplication = Application.extend(); - let a = { - name: 'a', - before: 'b', - initialize() { - order.push('a'); - } - }; - let b = { - name: 'b', - initialize() { - order.push('b'); - } - }; - let c = { - name: 'c', - after: 'b', - initialize() { - order.push('c'); - } - }; - let afterB = { - name: 'after b', - after: 'b', - initialize() { - order.push('after b'); - } - }; - let afterC = { - name: 'after c', - after: 'c', - initialize() { - order.push('after c'); - } - }; + this.runTask(() => this.createApplication({}, MyApplication)); - MyApplication.initializer(b); - MyApplication.initializer(a); - MyApplication.initializer(afterC); - MyApplication.initializer(afterB); - MyApplication.initializer(c); + assert.deepEqual(order, [ + 'first', + 'second', + 'third', + 'fourth', + 'fifth', + 'sixth' + ]); + } - this.runTask(() => this.createApplication({}, MyApplication)); + [`@test initializers can be registered in a specified order as an array`]( + assert + ) { + let order = []; + let MyApplication = Application.extend(); + + MyApplication.initializer({ + name: 'third', + initialize() { + order.push('third'); + } + }); - assert.ok(order.indexOf(a.name) < order.indexOf(b.name), 'a < b'); - assert.ok(order.indexOf(b.name) < order.indexOf(c.name), 'b < c'); - assert.ok(order.indexOf(b.name) < order.indexOf(afterB.name), 'b < afterB'); - assert.ok(order.indexOf(c.name) < order.indexOf(afterC.name), 'c < afterC'); - } + MyApplication.initializer({ + name: 'second', + after: 'first', + before: ['third', 'fourth'], + initialize() { + order.push('second'); + } + }); - [`@test initializers set on Application subclasses are not shared between apps`](assert) { - let firstInitializerRunCount = 0; - let secondInitializerRunCount = 0; - let FirstApp = Application.extend(); + MyApplication.initializer({ + name: 'fourth', + after: ['second', 'third'], + initialize() { + order.push('fourth'); + } + }); - FirstApp.initializer({ - name: 'first', - initialize() { - firstInitializerRunCount++; - } - }); + MyApplication.initializer({ + name: 'fifth', + after: 'fourth', + before: 'sixth', + initialize() { + order.push('fifth'); + } + }); - let SecondApp = Application.extend(); + MyApplication.initializer({ + name: 'first', + before: ['second'], + initialize() { + order.push('first'); + } + }); - SecondApp.initializer({ - name: 'second', - initialize() { - secondInitializerRunCount++; - } - }); + MyApplication.initializer({ + name: 'sixth', + initialize() { + order.push('sixth'); + } + }); - this.runTask(() => this.createApplication({}, FirstApp)); + this.runTask(() => this.createApplication({}, MyApplication)); - assert.equal(firstInitializerRunCount, 1, 'first initializer only was run'); - assert.equal(secondInitializerRunCount, 0, 'first initializer only was run'); + assert.deepEqual(order, [ + 'first', + 'second', + 'third', + 'fourth', + 'fifth', + 'sixth' + ]); + } - this.runTask(() => this.createSecondApplication({}, SecondApp)); + [`@test initializers can have multiple dependencies`](assert) { + let order = []; + let MyApplication = Application.extend(); + let a = { + name: 'a', + before: 'b', + initialize() { + order.push('a'); + } + }; + let b = { + name: 'b', + initialize() { + order.push('b'); + } + }; + let c = { + name: 'c', + after: 'b', + initialize() { + order.push('c'); + } + }; + let afterB = { + name: 'after b', + after: 'b', + initialize() { + order.push('after b'); + } + }; + let afterC = { + name: 'after c', + after: 'c', + initialize() { + order.push('after c'); + } + }; + + MyApplication.initializer(b); + MyApplication.initializer(a); + MyApplication.initializer(afterC); + MyApplication.initializer(afterB); + MyApplication.initializer(c); + + this.runTask(() => this.createApplication({}, MyApplication)); + + assert.ok(order.indexOf(a.name) < order.indexOf(b.name), 'a < b'); + assert.ok(order.indexOf(b.name) < order.indexOf(c.name), 'b < c'); + assert.ok( + order.indexOf(b.name) < order.indexOf(afterB.name), + 'b < afterB' + ); + assert.ok( + order.indexOf(c.name) < order.indexOf(afterC.name), + 'c < afterC' + ); + } - assert.equal(firstInitializerRunCount, 1, 'second initializer only was run'); - assert.equal(secondInitializerRunCount, 1, 'second initializer only was run'); - } + [`@test initializers set on Application subclasses are not shared between apps`]( + assert + ) { + let firstInitializerRunCount = 0; + let secondInitializerRunCount = 0; + let FirstApp = Application.extend(); - [`@test initializers are concatenated`](assert) { - let firstInitializerRunCount = 0; - let secondInitializerRunCount = 0; - let FirstApp = Application.extend(); + FirstApp.initializer({ + name: 'first', + initialize() { + firstInitializerRunCount++; + } + }); - FirstApp.initializer({ - name: 'first', - initialize() { - firstInitializerRunCount++; - } - }); + let SecondApp = Application.extend(); - let SecondApp = FirstApp.extend(); - SecondApp.initializer({ - name: 'second', - initialize() { - secondInitializerRunCount++; - } - }); + SecondApp.initializer({ + name: 'second', + initialize() { + secondInitializerRunCount++; + } + }); - this.runTask(() => this.createApplication({}, FirstApp)); + this.runTask(() => this.createApplication({}, FirstApp)); + + assert.equal( + firstInitializerRunCount, + 1, + 'first initializer only was run' + ); + assert.equal( + secondInitializerRunCount, + 0, + 'first initializer only was run' + ); + + this.runTask(() => this.createSecondApplication({}, SecondApp)); + + assert.equal( + firstInitializerRunCount, + 1, + 'second initializer only was run' + ); + assert.equal( + secondInitializerRunCount, + 1, + 'second initializer only was run' + ); + } - assert.equal(firstInitializerRunCount, 1, 'first initializer only was run when base class created'); - assert.equal(secondInitializerRunCount, 0, 'first initializer only was run when base class created'); + [`@test initializers are concatenated`](assert) { + let firstInitializerRunCount = 0; + let secondInitializerRunCount = 0; + let FirstApp = Application.extend(); - firstInitializerRunCount = 0; - this.runTask(() => this.createSecondApplication({}, SecondApp)); + FirstApp.initializer({ + name: 'first', + initialize() { + firstInitializerRunCount++; + } + }); - assert.equal(firstInitializerRunCount, 1, 'first initializer was run when subclass created'); - assert.equal(secondInitializerRunCount, 1, 'second initializers was run when subclass created'); - } + let SecondApp = FirstApp.extend(); + SecondApp.initializer({ + name: 'second', + initialize() { + secondInitializerRunCount++; + } + }); - [`@test initializers are per-app`](assert) { - assert.expect(2); + this.runTask(() => this.createApplication({}, FirstApp)); + + assert.equal( + firstInitializerRunCount, + 1, + 'first initializer only was run when base class created' + ); + assert.equal( + secondInitializerRunCount, + 0, + 'first initializer only was run when base class created' + ); + + firstInitializerRunCount = 0; + this.runTask(() => this.createSecondApplication({}, SecondApp)); + + assert.equal( + firstInitializerRunCount, + 1, + 'first initializer was run when subclass created' + ); + assert.equal( + secondInitializerRunCount, + 1, + 'second initializers was run when subclass created' + ); + } - let FirstApp = Application.extend(); + [`@test initializers are per-app`](assert) { + assert.expect(2); - FirstApp.initializer({ - name: 'abc', - initialize() { } - }); + let FirstApp = Application.extend(); - expectAssertion(() => { FirstApp.initializer({ name: 'abc', - initialize() { } + initialize() {} }); - }); - let SecondApp = Application.extend(); - SecondApp.instanceInitializer({ - name: 'abc', - initialize() { } - }); + expectAssertion(() => { + FirstApp.initializer({ + name: 'abc', + initialize() {} + }); + }); - assert.ok(true, 'Two apps can have initializers named the same.'); - } + let SecondApp = Application.extend(); + SecondApp.instanceInitializer({ + name: 'abc', + initialize() {} + }); - [`@test initializers are executed in their own context`](assert) { - assert.expect(1); - let MyApplication = Application.extend(); + assert.ok(true, 'Two apps can have initializers named the same.'); + } - MyApplication.initializer({ - name: 'coolInitializer', - myProperty: 'cool', - initialize() { - assert.equal(this.myProperty, 'cool', 'should have access to its own context'); - } - }); + [`@test initializers are executed in their own context`](assert) { + assert.expect(1); + let MyApplication = Application.extend(); + + MyApplication.initializer({ + name: 'coolInitializer', + myProperty: 'cool', + initialize() { + assert.equal( + this.myProperty, + 'cool', + 'should have access to its own context' + ); + } + }); - this.runTask(() => this.createApplication({}, MyApplication)); + this.runTask(() => this.createApplication({}, MyApplication)); + } } -}); +); diff --git a/packages/ember-application/tests/system/instance_initializers_test.js b/packages/ember-application/tests/system/instance_initializers_test.js index 46a9c85a87d..5e8e5e1f9d7 100644 --- a/packages/ember-application/tests/system/instance_initializers_test.js +++ b/packages/ember-application/tests/system/instance_initializers_test.js @@ -2,371 +2,441 @@ import { assign } from 'ember-utils'; import { moduleFor, AutobootApplicationTestCase } from 'internal-test-helpers'; import { Application, ApplicationInstance } from 'ember-application'; -moduleFor('Application instance initializers', class extends AutobootApplicationTestCase { - get fixture() { - return `
ONE
+moduleFor( + 'Application instance initializers', + class extends AutobootApplicationTestCase { + get fixture() { + return `
ONE
TWO
`; - } - - get applicationOptions() { - return assign(super.applicationOptions, { - rootElement: '#one' - }); - } - - createSecondApplication(options, MyApplication=Application) { - let myOptions = assign(this.applicationOptions, { - rootElement: '#two' - }, options); - let secondApp = this.secondApp = MyApplication.create(myOptions); - return secondApp; - } - - teardown() { - super.teardown(); - - if (this.secondApp) { - this.runTask(() => this.secondApp.destroy()); } - } - - [`@test initializers require proper 'name' and 'initialize' properties`]() { - let MyApplication = Application.extend(); - expectAssertion(() => { - MyApplication.instanceInitializer({ name: 'initializer' }); - }); - - expectAssertion(() => { - MyApplication.instanceInitializer({ initialize() {} }); - }); + get applicationOptions() { + return assign(super.applicationOptions, { + rootElement: '#one' + }); + } - this.runTask(() => this.createApplication({}, MyApplication)); - } + createSecondApplication(options, MyApplication = Application) { + let myOptions = assign( + this.applicationOptions, + { + rootElement: '#two' + }, + options + ); + let secondApp = (this.secondApp = MyApplication.create(myOptions)); + return secondApp; + } - [`@test initializers are passed an app instance`](assert) { - let MyApplication = Application.extend(); + teardown() { + super.teardown(); - MyApplication.instanceInitializer({ - name: 'initializer', - initialize(instance) { - assert.ok(instance instanceof ApplicationInstance, 'initialize is passed an application instance'); + if (this.secondApp) { + this.runTask(() => this.secondApp.destroy()); } - }); - - this.runTask(() => this.createApplication({}, MyApplication)); - } + } - [`@test initializers can be registered in a specified order`](assert) { - let order = []; - let MyApplication = Application.extend(); + [`@test initializers require proper 'name' and 'initialize' properties`]() { + let MyApplication = Application.extend(); - MyApplication.instanceInitializer({ - name: 'fourth', - after: 'third', - initialize() { - order.push('fourth'); - } - }); - - MyApplication.instanceInitializer({ - name: 'second', - after: 'first', - before: 'third', - initialize() { - order.push('second'); - } - }); - - MyApplication.instanceInitializer({ - name: 'fifth', - after: 'fourth', - before: 'sixth', - initialize() { - order.push('fifth'); - } - }); - - MyApplication.instanceInitializer({ - name: 'first', - before: 'second', - initialize() { - order.push('first'); - } - }); + expectAssertion(() => { + MyApplication.instanceInitializer({ name: 'initializer' }); + }); - MyApplication.instanceInitializer({ - name: 'third', - initialize() { - order.push('third'); - } - }); + expectAssertion(() => { + MyApplication.instanceInitializer({ initialize() {} }); + }); - MyApplication.instanceInitializer({ - name: 'sixth', - initialize() { - order.push('sixth'); - } - }); + this.runTask(() => this.createApplication({}, MyApplication)); + } - this.runTask(() => this.createApplication({}, MyApplication)); + [`@test initializers are passed an app instance`](assert) { + let MyApplication = Application.extend(); + + MyApplication.instanceInitializer({ + name: 'initializer', + initialize(instance) { + assert.ok( + instance instanceof ApplicationInstance, + 'initialize is passed an application instance' + ); + } + }); - assert.deepEqual(order, ['first', 'second', 'third', 'fourth', 'fifth', 'sixth']); - } + this.runTask(() => this.createApplication({}, MyApplication)); + } - [`@test initializers can be registered in a specified order as an array`](assert) { - let order = []; - let MyApplication = Application.extend(); + [`@test initializers can be registered in a specified order`](assert) { + let order = []; + let MyApplication = Application.extend(); - MyApplication.instanceInitializer({ - name: 'third', - initialize() { - order.push('third'); - } - }); - - MyApplication.instanceInitializer({ - name: 'second', - after: 'first', - before: ['third', 'fourth'], - initialize() { - order.push('second'); - } - }); + MyApplication.instanceInitializer({ + name: 'fourth', + after: 'third', + initialize() { + order.push('fourth'); + } + }); - MyApplication.instanceInitializer({ - name: 'fourth', - after: ['second', 'third'], - initialize() { - order.push('fourth'); - } - }); - - MyApplication.instanceInitializer({ - name: 'fifth', - after: 'fourth', - before: 'sixth', - initialize() { - order.push('fifth'); - } - }); + MyApplication.instanceInitializer({ + name: 'second', + after: 'first', + before: 'third', + initialize() { + order.push('second'); + } + }); - MyApplication.instanceInitializer({ - name: 'first', - before: ['second'], - initialize() { - order.push('first'); - } - }); + MyApplication.instanceInitializer({ + name: 'fifth', + after: 'fourth', + before: 'sixth', + initialize() { + order.push('fifth'); + } + }); - MyApplication.instanceInitializer({ - name: 'sixth', - initialize() { - order.push('sixth'); - } - }); + MyApplication.instanceInitializer({ + name: 'first', + before: 'second', + initialize() { + order.push('first'); + } + }); - this.runTask(() => this.createApplication({}, MyApplication)); + MyApplication.instanceInitializer({ + name: 'third', + initialize() { + order.push('third'); + } + }); - assert.deepEqual(order, ['first', 'second', 'third', 'fourth', 'fifth', 'sixth']); - } + MyApplication.instanceInitializer({ + name: 'sixth', + initialize() { + order.push('sixth'); + } + }); - [`@test initializers can have multiple dependencies`](assert) { - let order = []; - let MyApplication = Application.extend(); - let a = { - name: 'a', - before: 'b', - initialize() { - order.push('a'); - } - }; - let b = { - name: 'b', - initialize() { - order.push('b'); - } - }; - let c = { - name: 'c', - after: 'b', - initialize() { - order.push('c'); - } - }; - let afterB = { - name: 'after b', - after: 'b', - initialize() { - order.push('after b'); - } - }; - let afterC = { - name: 'after c', - after: 'c', - initialize() { - order.push('after c'); - } - }; + this.runTask(() => this.createApplication({}, MyApplication)); - MyApplication.instanceInitializer(b); - MyApplication.instanceInitializer(a); - MyApplication.instanceInitializer(afterC); - MyApplication.instanceInitializer(afterB); - MyApplication.instanceInitializer(c); + assert.deepEqual(order, [ + 'first', + 'second', + 'third', + 'fourth', + 'fifth', + 'sixth' + ]); + } - this.runTask(() => this.createApplication({}, MyApplication)); + [`@test initializers can be registered in a specified order as an array`]( + assert + ) { + let order = []; + let MyApplication = Application.extend(); + + MyApplication.instanceInitializer({ + name: 'third', + initialize() { + order.push('third'); + } + }); - assert.ok(order.indexOf(a.name) < order.indexOf(b.name), 'a < b'); - assert.ok(order.indexOf(b.name) < order.indexOf(c.name), 'b < c'); - assert.ok(order.indexOf(b.name) < order.indexOf(afterB.name), 'b < afterB'); - assert.ok(order.indexOf(c.name) < order.indexOf(afterC.name), 'c < afterC'); - } + MyApplication.instanceInitializer({ + name: 'second', + after: 'first', + before: ['third', 'fourth'], + initialize() { + order.push('second'); + } + }); - [`@test initializers set on Application subclasses should not be shared between apps`](assert) { - let firstInitializerRunCount = 0; - let secondInitializerRunCount = 0; - let FirstApp = Application.extend(); + MyApplication.instanceInitializer({ + name: 'fourth', + after: ['second', 'third'], + initialize() { + order.push('fourth'); + } + }); - FirstApp.instanceInitializer({ - name: 'first', - initialize() { - firstInitializerRunCount++; - } - }); + MyApplication.instanceInitializer({ + name: 'fifth', + after: 'fourth', + before: 'sixth', + initialize() { + order.push('fifth'); + } + }); - let SecondApp = Application.extend(); - SecondApp.instanceInitializer({ - name: 'second', - initialize() { - secondInitializerRunCount++; - } - }); + MyApplication.instanceInitializer({ + name: 'first', + before: ['second'], + initialize() { + order.push('first'); + } + }); - this.runTask(() => this.createApplication({}, FirstApp)); + MyApplication.instanceInitializer({ + name: 'sixth', + initialize() { + order.push('sixth'); + } + }); - assert.equal(firstInitializerRunCount, 1, 'first initializer only was run'); - assert.equal(secondInitializerRunCount, 0, 'first initializer only was run'); + this.runTask(() => this.createApplication({}, MyApplication)); - this.runTask(() => this.createSecondApplication({}, SecondApp)); + assert.deepEqual(order, [ + 'first', + 'second', + 'third', + 'fourth', + 'fifth', + 'sixth' + ]); + } - assert.equal(firstInitializerRunCount, 1, 'second initializer only was run'); - assert.equal(secondInitializerRunCount, 1, 'second initializer only was run'); - } + [`@test initializers can have multiple dependencies`](assert) { + let order = []; + let MyApplication = Application.extend(); + let a = { + name: 'a', + before: 'b', + initialize() { + order.push('a'); + } + }; + let b = { + name: 'b', + initialize() { + order.push('b'); + } + }; + let c = { + name: 'c', + after: 'b', + initialize() { + order.push('c'); + } + }; + let afterB = { + name: 'after b', + after: 'b', + initialize() { + order.push('after b'); + } + }; + let afterC = { + name: 'after c', + after: 'c', + initialize() { + order.push('after c'); + } + }; + + MyApplication.instanceInitializer(b); + MyApplication.instanceInitializer(a); + MyApplication.instanceInitializer(afterC); + MyApplication.instanceInitializer(afterB); + MyApplication.instanceInitializer(c); + + this.runTask(() => this.createApplication({}, MyApplication)); + + assert.ok(order.indexOf(a.name) < order.indexOf(b.name), 'a < b'); + assert.ok(order.indexOf(b.name) < order.indexOf(c.name), 'b < c'); + assert.ok( + order.indexOf(b.name) < order.indexOf(afterB.name), + 'b < afterB' + ); + assert.ok( + order.indexOf(c.name) < order.indexOf(afterC.name), + 'c < afterC' + ); + } - [`@test initializers are concatenated`](assert) { - let firstInitializerRunCount = 0; - let secondInitializerRunCount = 0; - let FirstApp = Application.extend(); + [`@test initializers set on Application subclasses should not be shared between apps`]( + assert + ) { + let firstInitializerRunCount = 0; + let secondInitializerRunCount = 0; + let FirstApp = Application.extend(); - FirstApp.instanceInitializer({ - name: 'first', - initialize() { - firstInitializerRunCount++; - } - }); + FirstApp.instanceInitializer({ + name: 'first', + initialize() { + firstInitializerRunCount++; + } + }); - let SecondApp = FirstApp.extend(); - SecondApp.instanceInitializer({ - name: 'second', - initialize() { - secondInitializerRunCount++; - } - }); + let SecondApp = Application.extend(); + SecondApp.instanceInitializer({ + name: 'second', + initialize() { + secondInitializerRunCount++; + } + }); - this.runTask(() => this.createApplication({}, FirstApp)); + this.runTask(() => this.createApplication({}, FirstApp)); + + assert.equal( + firstInitializerRunCount, + 1, + 'first initializer only was run' + ); + assert.equal( + secondInitializerRunCount, + 0, + 'first initializer only was run' + ); + + this.runTask(() => this.createSecondApplication({}, SecondApp)); + + assert.equal( + firstInitializerRunCount, + 1, + 'second initializer only was run' + ); + assert.equal( + secondInitializerRunCount, + 1, + 'second initializer only was run' + ); + } - assert.equal(firstInitializerRunCount, 1, 'first initializer only was run when base class created'); - assert.equal(secondInitializerRunCount, 0, 'first initializer only was run when base class created'); + [`@test initializers are concatenated`](assert) { + let firstInitializerRunCount = 0; + let secondInitializerRunCount = 0; + let FirstApp = Application.extend(); - firstInitializerRunCount = 0; - this.runTask(() => this.createSecondApplication({}, SecondApp)); + FirstApp.instanceInitializer({ + name: 'first', + initialize() { + firstInitializerRunCount++; + } + }); - assert.equal(firstInitializerRunCount, 1, 'first initializer was run when subclass created'); - assert.equal(secondInitializerRunCount, 1, 'second initializers was run when subclass created'); - } + let SecondApp = FirstApp.extend(); + SecondApp.instanceInitializer({ + name: 'second', + initialize() { + secondInitializerRunCount++; + } + }); - [`@test initializers are per-app`](assert) { - assert.expect(2); + this.runTask(() => this.createApplication({}, FirstApp)); + + assert.equal( + firstInitializerRunCount, + 1, + 'first initializer only was run when base class created' + ); + assert.equal( + secondInitializerRunCount, + 0, + 'first initializer only was run when base class created' + ); + + firstInitializerRunCount = 0; + this.runTask(() => this.createSecondApplication({}, SecondApp)); + + assert.equal( + firstInitializerRunCount, + 1, + 'first initializer was run when subclass created' + ); + assert.equal( + secondInitializerRunCount, + 1, + 'second initializers was run when subclass created' + ); + } - let FirstApp = Application.extend(); - FirstApp.instanceInitializer({ - name: 'abc', - initialize() {} - }); + [`@test initializers are per-app`](assert) { + assert.expect(2); - expectAssertion(function() { + let FirstApp = Application.extend(); FirstApp.instanceInitializer({ name: 'abc', initialize() {} }); - }); - this.runTask(() => this.createApplication({}, FirstApp)); - - let SecondApp = Application.extend(); - SecondApp.instanceInitializer({ - name: 'abc', - initialize() {} - }); + expectAssertion(function() { + FirstApp.instanceInitializer({ + name: 'abc', + initialize() {} + }); + }); - this.runTask(() => this.createSecondApplication({}, SecondApp)); + this.runTask(() => this.createApplication({}, FirstApp)); - assert.ok(true, 'Two apps can have initializers named the same.'); - } + let SecondApp = Application.extend(); + SecondApp.instanceInitializer({ + name: 'abc', + initialize() {} + }); - [`@test initializers are run before ready hook`](assert) { - assert.expect(2); + this.runTask(() => this.createSecondApplication({}, SecondApp)); - let MyApplication = Application.extend({ - ready() { - assert.ok(true, 'ready is called'); - readyWasCalled = false; - } - }); - let readyWasCalled = false; + assert.ok(true, 'Two apps can have initializers named the same.'); + } - MyApplication.instanceInitializer({ - name: 'initializer', - initialize() { - assert.ok(!readyWasCalled, 'ready is not yet called'); - } - }); + [`@test initializers are run before ready hook`](assert) { + assert.expect(2); - this.runTask(() => this.createApplication({}, MyApplication)); - } + let MyApplication = Application.extend({ + ready() { + assert.ok(true, 'ready is called'); + readyWasCalled = false; + } + }); + let readyWasCalled = false; - [`@test initializers are executed in their own context`](assert) { - assert.expect(1); + MyApplication.instanceInitializer({ + name: 'initializer', + initialize() { + assert.ok(!readyWasCalled, 'ready is not yet called'); + } + }); - let MyApplication = Application.extend(); + this.runTask(() => this.createApplication({}, MyApplication)); + } - MyApplication.instanceInitializer({ - name: 'coolInitializer', - myProperty: 'cool', - initialize() { - assert.equal(this.myProperty, 'cool', 'should have access to its own context'); - } - }); + [`@test initializers are executed in their own context`](assert) { + assert.expect(1); + + let MyApplication = Application.extend(); + + MyApplication.instanceInitializer({ + name: 'coolInitializer', + myProperty: 'cool', + initialize() { + assert.equal( + this.myProperty, + 'cool', + 'should have access to its own context' + ); + } + }); - this.runTask(() => this.createApplication({}, MyApplication)); - } + this.runTask(() => this.createApplication({}, MyApplication)); + } - [`@test initializers get an instance on app reset`](assert) { - assert.expect(2); + [`@test initializers get an instance on app reset`](assert) { + assert.expect(2); - let MyApplication = Application.extend(); + let MyApplication = Application.extend(); - MyApplication.instanceInitializer({ - name: 'giveMeAnInstance', - initialize(instance) { - assert.ok(!!instance, 'Initializer got an instance'); - } - }); + MyApplication.instanceInitializer({ + name: 'giveMeAnInstance', + initialize(instance) { + assert.ok(!!instance, 'Initializer got an instance'); + } + }); - this.runTask(() => this.createApplication({}, MyApplication)); + this.runTask(() => this.createApplication({}, MyApplication)); - this.runTask(() => this.application.reset()); + this.runTask(() => this.application.reset()); + } } -}); +); diff --git a/packages/ember-application/tests/system/logging_test.js b/packages/ember-application/tests/system/logging_test.js index ae4ab536c06..d23f0d91d49 100644 --- a/packages/ember-application/tests/system/logging_test.js +++ b/packages/ember-application/tests/system/logging_test.js @@ -1,15 +1,11 @@ /*globals EmberDev */ -import { - moduleFor, - ApplicationTestCase -} from 'internal-test-helpers'; +import { moduleFor, ApplicationTestCase } from 'internal-test-helpers'; import { Controller } from 'ember-runtime'; import { Route } from 'ember-routing'; import { assign } from 'ember-utils'; - class LoggingApplicationTestCase extends ApplicationTestCase { constructor() { super(); @@ -19,13 +15,13 @@ class LoggingApplicationTestCase extends ApplicationTestCase { /* eslint-disable no-console */ this._originalLogger = console.info; - console.info = (_, {fullName}) => { + console.info = (_, { fullName }) => { if (!this.logs.hasOwnProperty(fullName)) { this.logs[fullName] = 0; } - /* eslint-ensable no-console */ - this.logs[fullName]++; - }; + /* eslint-ensable no-console */ + this.logs[fullName]++; + }; this.router.map(function() { this.route('posts', { resetNamespace: true }); @@ -40,117 +36,168 @@ class LoggingApplicationTestCase extends ApplicationTestCase { } } -moduleFor('Application with LOG_ACTIVE_GENERATION=true', class extends LoggingApplicationTestCase { - - get applicationOptions() { - return assign(super.applicationOptions, { - LOG_ACTIVE_GENERATION: true - }); - } - - ['@test log class generation if logging enabled'](assert) { - if (EmberDev && EmberDev.runningProdBuild) { - assert.ok(true, 'Logging does not occur in production builds'); - return; +moduleFor( + 'Application with LOG_ACTIVE_GENERATION=true', + class extends LoggingApplicationTestCase { + get applicationOptions() { + return assign(super.applicationOptions, { + LOG_ACTIVE_GENERATION: true + }); } - return this.visit('/posts').then(() => { - assert.equal(Object.keys(this.logs).length, 4, 'expected logs'); - }); - } + ['@test log class generation if logging enabled'](assert) { + if (EmberDev && EmberDev.runningProdBuild) { + assert.ok(true, 'Logging does not occur in production builds'); + return; + } - ['@test actively generated classes get logged'](assert) { - if (EmberDev && EmberDev.runningProdBuild) { - assert.ok(true, 'Logging does not occur in production builds'); - return; + return this.visit('/posts').then(() => { + assert.equal(Object.keys(this.logs).length, 4, 'expected logs'); + }); } - return this.visit('/posts').then(() => { - assert.equal(this.logs['controller:application'], 1, 'expected: ApplicationController was generated'); - assert.equal(this.logs['controller:posts'], 1, 'expected: PostsController was generated'); - - assert.equal(this.logs['route:application'], 1, 'expected: ApplicationRoute was generated'); - assert.equal(this.logs['route:posts'], 1, 'expected: PostsRoute was generated'); - }); - } - - ['@test predefined classes do not get logged'](assert) { - this.add('controller:application', Controller.extend()); - this.add('controller:posts', Controller.extend()); - this.add('route:application', Route.extend()); - this.add('route:posts', Route.extend()); - - return this.visit('/posts').then(() => { - assert.ok(!this.logs['controller:application'], 'did not expect: ApplicationController was generated'); - assert.ok(!this.logs['controller:posts'], 'did not expect: PostsController was generated'); - - assert.ok(!this.logs['route:application'], 'did not expect: ApplicationRoute was generated'); - assert.ok(!this.logs['route:posts'], 'did not expect: PostsRoute was generated'); - }); - } - -}); - -moduleFor('Application when LOG_ACTIVE_GENERATION=false', class extends LoggingApplicationTestCase { - - get applicationOptions() { - return assign(super.applicationOptions, { - LOG_ACTIVE_GENERATION: false - }); - } - - [`@test do NOT log class generation if logging disabled`](assert) { - return this.visit('/posts').then(() => { - assert.equal(Object.keys(this.logs).length, 0, 'expected logs'); - }); - } - -}); + ['@test actively generated classes get logged'](assert) { + if (EmberDev && EmberDev.runningProdBuild) { + assert.ok(true, 'Logging does not occur in production builds'); + return; + } -moduleFor('Application with LOG_VIEW_LOOKUPS=true', class extends LoggingApplicationTestCase { + return this.visit('/posts').then(() => { + assert.equal( + this.logs['controller:application'], + 1, + 'expected: ApplicationController was generated' + ); + assert.equal( + this.logs['controller:posts'], + 1, + 'expected: PostsController was generated' + ); + + assert.equal( + this.logs['route:application'], + 1, + 'expected: ApplicationRoute was generated' + ); + assert.equal( + this.logs['route:posts'], + 1, + 'expected: PostsRoute was generated' + ); + }); + } - get applicationOptions() { - return assign(super.applicationOptions, { - LOG_VIEW_LOOKUPS: true - }); + ['@test predefined classes do not get logged'](assert) { + this.add('controller:application', Controller.extend()); + this.add('controller:posts', Controller.extend()); + this.add('route:application', Route.extend()); + this.add('route:posts', Route.extend()); + + return this.visit('/posts').then(() => { + assert.ok( + !this.logs['controller:application'], + 'did not expect: ApplicationController was generated' + ); + assert.ok( + !this.logs['controller:posts'], + 'did not expect: PostsController was generated' + ); + + assert.ok( + !this.logs['route:application'], + 'did not expect: ApplicationRoute was generated' + ); + assert.ok( + !this.logs['route:posts'], + 'did not expect: PostsRoute was generated' + ); + }); + } } - - [`@test log when template and view are missing when flag is active`](assert) { - if (EmberDev && EmberDev.runningProdBuild) { - assert.ok(true, 'Logging does not occur in production builds'); - return; +); + +moduleFor( + 'Application when LOG_ACTIVE_GENERATION=false', + class extends LoggingApplicationTestCase { + get applicationOptions() { + return assign(super.applicationOptions, { + LOG_ACTIVE_GENERATION: false + }); } - this.addTemplate('application', '{{outlet}}'); - - return this.visit('/') - .then(() => this.visit('/posts')) - .then(() => { - assert.equal(this.logs['template:application'], undefined, 'expected: Should not log template:application since it exists.'); - assert.equal(this.logs['template:index'], 1, 'expected: Could not find "index" template or view.'); - assert.equal(this.logs['template:posts'], 1, 'expected: Could not find "posts" template or view.'); + [`@test do NOT log class generation if logging disabled`](assert) { + return this.visit('/posts').then(() => { + assert.equal(Object.keys(this.logs).length, 0, 'expected logs'); }); + } } +); + +moduleFor( + 'Application with LOG_VIEW_LOOKUPS=true', + class extends LoggingApplicationTestCase { + get applicationOptions() { + return assign(super.applicationOptions, { + LOG_VIEW_LOOKUPS: true + }); + } -}); - -moduleFor('Application with LOG_VIEW_LOOKUPS=false', class extends LoggingApplicationTestCase { + [`@test log when template and view are missing when flag is active`]( + assert + ) { + if (EmberDev && EmberDev.runningProdBuild) { + assert.ok(true, 'Logging does not occur in production builds'); + return; + } - get applicationOptions() { - return assign(super.applicationOptions, { - LOG_VIEW_LOOKUPS: false - }); + this.addTemplate('application', '{{outlet}}'); + + return this.visit('/') + .then(() => this.visit('/posts')) + .then(() => { + assert.equal( + this.logs['template:application'], + undefined, + 'expected: Should not log template:application since it exists.' + ); + assert.equal( + this.logs['template:index'], + 1, + 'expected: Could not find "index" template or view.' + ); + assert.equal( + this.logs['template:posts'], + 1, + 'expected: Could not find "posts" template or view.' + ); + }); + } } +); + +moduleFor( + 'Application with LOG_VIEW_LOOKUPS=false', + class extends LoggingApplicationTestCase { + get applicationOptions() { + return assign(super.applicationOptions, { + LOG_VIEW_LOOKUPS: false + }); + } - [`@test do not log when template and view are missing when flag is not true`](assert) { - return this.visit('/posts').then(() => { - assert.equal(Object.keys(this.logs).length, 0, 'expected no logs'); - }); - } + [`@test do not log when template and view are missing when flag is not true`]( + assert + ) { + return this.visit('/posts').then(() => { + assert.equal(Object.keys(this.logs).length, 0, 'expected no logs'); + }); + } - [`@test do not log which views are used with templates when flag is not true`](assert) { - return this.visit('/posts').then(() => { - assert.equal(Object.keys(this.logs).length, 0, 'expected no logs'); - }); + [`@test do not log which views are used with templates when flag is not true`]( + assert + ) { + return this.visit('/posts').then(() => { + assert.equal(Object.keys(this.logs).length, 0, 'expected no logs'); + }); + } } -}); +); diff --git a/packages/ember-application/tests/system/readiness_test.js b/packages/ember-application/tests/system/readiness_test.js index da7291e34ab..67f25b24a3f 100644 --- a/packages/ember-application/tests/system/readiness_test.js +++ b/packages/ember-application/tests/system/readiness_test.js @@ -1,7 +1,4 @@ -import { - moduleFor, - ApplicationTestCase -} from 'internal-test-helpers'; +import { moduleFor, ApplicationTestCase } from 'internal-test-helpers'; import { run } from 'ember-metal'; import EmberApplication from '../../system/application'; @@ -12,124 +9,149 @@ let readyWasCalled, domReady, readyCallbacks; // very well-defined semantics, and we want to confirm that a jQuery stub run // in a more minimal server environment that implements this behavior will be // sufficient for Ember's requirements. -moduleFor('Application readiness', class extends ApplicationTestCase { - constructor() { - super(); - - readyWasCalled = 0; - readyCallbacks = []; - - let jQueryInstance = { - ready(callback) { - readyCallbacks.push(callback); - if (jQuery.isReady) { - domReady(); +moduleFor( + 'Application readiness', + class extends ApplicationTestCase { + constructor() { + super(); + + readyWasCalled = 0; + readyCallbacks = []; + + let jQueryInstance = { + ready(callback) { + readyCallbacks.push(callback); + if (jQuery.isReady) { + domReady(); + } } - } - }; - - jQuery = function() { - return jQueryInstance; - }; - jQuery.isReady = false; - - let domReadyCalled = 0; - domReady = function() { - if (domReadyCalled !== 0) { return; } - domReadyCalled++; - for (let i = 0; i < readyCallbacks.length; i++) { - readyCallbacks[i](); - } - }; + }; - Application = EmberApplication.extend({ - $: jQuery, + jQuery = function() { + return jQueryInstance; + }; + jQuery.isReady = false; - ready() { - readyWasCalled++; - } - }); - } + let domReadyCalled = 0; + domReady = function() { + if (domReadyCalled !== 0) { + return; + } + domReadyCalled++; + for (let i = 0; i < readyCallbacks.length; i++) { + readyCallbacks[i](); + } + }; + + Application = EmberApplication.extend({ + $: jQuery, - teardown() { - if (application) { - run(() => application.destroy()); + ready() { + readyWasCalled++; + } + }); } - } - // These tests are confirming that if the callbacks passed into jQuery's ready hook is called - // synchronously during the application's initialization, we get the same behavior as if - // it was triggered after initialization. + teardown() { + if (application) { + run(() => application.destroy()); + } + } - ['@test Application\'s ready event is called right away if jQuery is already ready'](assert) { - jQuery.isReady = true; + // These tests are confirming that if the callbacks passed into jQuery's ready hook is called + // synchronously during the application's initialization, we get the same behavior as if + // it was triggered after initialization. - run(() => { - application = Application.create({ router: false }); + ["@test Application's ready event is called right away if jQuery is already ready"]( + assert + ) { + jQuery.isReady = true; - assert.equal(readyWasCalled, 0, 'ready is not called until later'); - }); + run(() => { + application = Application.create({ router: false }); - assert.equal(readyWasCalled, 1, 'ready was called'); + assert.equal(readyWasCalled, 0, 'ready is not called until later'); + }); - domReady(); + assert.equal(readyWasCalled, 1, 'ready was called'); - assert.equal(readyWasCalled, 1, 'application\'s ready was not called again'); - } + domReady(); - ['@test Application\'s ready event is called after the document becomes ready'](assert) { - run(() => { - application = Application.create({ router: false }); - }); + assert.equal( + readyWasCalled, + 1, + "application's ready was not called again" + ); + } - assert.equal(readyWasCalled, 0, 'ready wasn\'t called yet'); + ["@test Application's ready event is called after the document becomes ready"]( + assert + ) { + run(() => { + application = Application.create({ router: false }); + }); - domReady(); + assert.equal(readyWasCalled, 0, "ready wasn't called yet"); - assert.equal(readyWasCalled, 1, 'ready was called now that DOM is ready'); - } + domReady(); - ['@test Application\'s ready event can be deferred by other components'](assert) { - run(() => { - application = Application.create({ router: false }); - application.deferReadiness(); - }); + assert.equal(readyWasCalled, 1, 'ready was called now that DOM is ready'); + } - assert.equal(readyWasCalled, 0, 'ready wasn\'t called yet'); + ["@test Application's ready event can be deferred by other components"]( + assert + ) { + run(() => { + application = Application.create({ router: false }); + application.deferReadiness(); + }); - domReady(); + assert.equal(readyWasCalled, 0, "ready wasn't called yet"); - assert.equal(readyWasCalled, 0, 'ready wasn\'t called yet'); + domReady(); - run(() => { - application.advanceReadiness(); - assert.equal(readyWasCalled, 0); - }); + assert.equal(readyWasCalled, 0, "ready wasn't called yet"); - assert.equal(readyWasCalled, 1, 'ready was called now all readiness deferrals are advanced'); - } + run(() => { + application.advanceReadiness(); + assert.equal(readyWasCalled, 0); + }); + + assert.equal( + readyWasCalled, + 1, + 'ready was called now all readiness deferrals are advanced' + ); + } - ['@test Application\'s ready event can be deferred by other components'](assert) { - jQuery.isReady = false; + ["@test Application's ready event can be deferred by other components"]( + assert + ) { + jQuery.isReady = false; - run(() => { - application = Application.create({ router: false }); - application.deferReadiness(); - assert.equal(readyWasCalled, 0, 'ready wasn\'t called yet'); - }); + run(() => { + application = Application.create({ router: false }); + application.deferReadiness(); + assert.equal(readyWasCalled, 0, "ready wasn't called yet"); + }); - domReady(); + domReady(); - assert.equal(readyWasCalled, 0, 'ready wasn\'t called yet'); + assert.equal(readyWasCalled, 0, "ready wasn't called yet"); - run(() => { - application.advanceReadiness(); - }); + run(() => { + application.advanceReadiness(); + }); - assert.equal(readyWasCalled, 1, 'ready was called now all readiness deferrals are advanced'); + assert.equal( + readyWasCalled, + 1, + 'ready was called now all readiness deferrals are advanced' + ); - expectAssertion(() => { - application.deferReadiness(); - }); + expectAssertion(() => { + application.deferReadiness(); + }); + } } -}); +); diff --git a/packages/ember-application/tests/system/reset_test.js b/packages/ember-application/tests/system/reset_test.js index 927f5bb34c1..8d23916c5f1 100644 --- a/packages/ember-application/tests/system/reset_test.js +++ b/packages/ember-application/tests/system/reset_test.js @@ -3,155 +3,206 @@ import { Controller } from 'ember-runtime'; import { Router } from 'ember-routing'; import { moduleFor, AutobootApplicationTestCase } from 'internal-test-helpers'; -moduleFor('Application - resetting', class extends AutobootApplicationTestCase { - - ['@test Brings its own run-loop if not provided'](assert) { - assert.expect(0); - run(() => this.createApplication()); - this.application.reset(); - } - - ['@test Does not bring its own run loop if one is already provided'](assert) { - assert.expect(3); - - let didBecomeReady = false; - - run(() => this.createApplication()); - - run(() => { - this.application.ready = () => { - didBecomeReady = true; - }; - +moduleFor( + 'Application - resetting', + class extends AutobootApplicationTestCase { + ['@test Brings its own run-loop if not provided'](assert) { + assert.expect(0); + run(() => this.createApplication()); this.application.reset(); + } - this.application.deferReadiness(); - assert.ok(!didBecomeReady, 'app is not ready'); - }); - - assert.ok(!didBecomeReady, 'app is not ready'); - run(this.application, 'advanceReadiness'); - assert.ok(didBecomeReady, 'app is ready'); - } - - ['@test When an application is reset, new instances of controllers are generated'](assert) { - run(() => { - this.createApplication(); - this.add('controller:academic', Controller.extend()); - }); - - let firstController = this.applicationInstance.lookup('controller:academic'); - let secondController = this.applicationInstance.lookup('controller:academic'); - - this.application.reset(); - - let thirdController = this.applicationInstance.lookup('controller:academic'); + ['@test Does not bring its own run loop if one is already provided']( + assert + ) { + assert.expect(3); - assert.strictEqual(firstController, secondController, 'controllers looked up in succession should be the same instance'); + let didBecomeReady = false; - assert.ok(firstController.isDestroying, 'controllers are destroyed when their application is reset'); + run(() => this.createApplication()); - assert.notStrictEqual(firstController, thirdController, 'controllers looked up after the application is reset should not be the same instance'); - } - - ['@test When an application is reset, the eventDispatcher is destroyed and recreated'](assert) { - let eventDispatcherWasSetup = 0; - let eventDispatcherWasDestroyed = 0; - - let mockEventDispatcher = { - setup() { - eventDispatcherWasSetup++; - }, - destroy() { - eventDispatcherWasDestroyed++; - } - }; + run(() => { + this.application.ready = () => { + didBecomeReady = true; + }; - run(() => { - this.createApplication(); - this.add('event_dispatcher:main', {create: () => mockEventDispatcher}); + this.application.reset(); - assert.equal(eventDispatcherWasSetup, 0); - assert.equal(eventDispatcherWasDestroyed, 0); - }); + this.application.deferReadiness(); + assert.ok(!didBecomeReady, 'app is not ready'); + }); - assert.equal(eventDispatcherWasSetup, 1); - assert.equal(eventDispatcherWasDestroyed, 0); + assert.ok(!didBecomeReady, 'app is not ready'); + run(this.application, 'advanceReadiness'); + assert.ok(didBecomeReady, 'app is ready'); + } + + ['@test When an application is reset, new instances of controllers are generated']( + assert + ) { + run(() => { + this.createApplication(); + this.add('controller:academic', Controller.extend()); + }); - this.application.reset(); + let firstController = this.applicationInstance.lookup( + 'controller:academic' + ); + let secondController = this.applicationInstance.lookup( + 'controller:academic' + ); - assert.equal(eventDispatcherWasDestroyed, 1); - assert.equal(eventDispatcherWasSetup, 2, 'setup called after reset'); - } + this.application.reset(); - ['@test When an application is reset, the router URL is reset to `/`'](assert) { - run(() => { - this.createApplication(); + let thirdController = this.applicationInstance.lookup( + 'controller:academic' + ); + + assert.strictEqual( + firstController, + secondController, + 'controllers looked up in succession should be the same instance' + ); + + assert.ok( + firstController.isDestroying, + 'controllers are destroyed when their application is reset' + ); + + assert.notStrictEqual( + firstController, + thirdController, + 'controllers looked up after the application is reset should not be the same instance' + ); + } + + ['@test When an application is reset, the eventDispatcher is destroyed and recreated']( + assert + ) { + let eventDispatcherWasSetup = 0; + let eventDispatcherWasDestroyed = 0; + + let mockEventDispatcher = { + setup() { + eventDispatcherWasSetup++; + }, + destroy() { + eventDispatcherWasDestroyed++; + } + }; - this.add('router:main', Router.extend({ - location: 'none' - })); + run(() => { + this.createApplication(); + this.add('event_dispatcher:main', { + create: () => mockEventDispatcher + }); - this.router.map(function() { - this.route('one'); - this.route('two'); + assert.equal(eventDispatcherWasSetup, 0); + assert.equal(eventDispatcherWasDestroyed, 0); }); - }); - - let initialRouter, initialApplicationController; - return this.visit('/one') - .then(() => { - initialApplicationController = this.applicationInstance.lookup('controller:application'); - initialRouter = this.applicationInstance.lookup('router:main'); - let location = initialRouter.get('location'); - - assert.equal(location.getURL(), '/one'); - assert.equal(get(initialApplicationController, 'currentPath'), 'one'); - - this.application.reset(); - - return this.application._bootPromise; - }) - .then(() => { - let applicationController = this.applicationInstance.lookup('controller:application'); - assert.strictEqual(applicationController, undefined, 'application controller no longer exists'); - return this.visit('/one'); - }) - .then(() => { - let applicationController = this.applicationInstance.lookup('controller:application'); - let router = this.applicationInstance.lookup('router:main'); - let location = router.get('location'); + assert.equal(eventDispatcherWasSetup, 1); + assert.equal(eventDispatcherWasDestroyed, 0); - assert.notEqual(initialRouter, router, 'a different router instance was created'); - assert.notEqual(initialApplicationController, applicationController, 'a different application controller is created'); + this.application.reset(); - assert.equal(location.getURL(), '/one'); - assert.equal(get(applicationController, 'currentPath'), 'one'); + assert.equal(eventDispatcherWasDestroyed, 1); + assert.equal(eventDispatcherWasSetup, 2, 'setup called after reset'); + } + + ['@test When an application is reset, the router URL is reset to `/`']( + assert + ) { + run(() => { + this.createApplication(); + + this.add( + 'router:main', + Router.extend({ + location: 'none' + }) + ); + + this.router.map(function() { + this.route('one'); + this.route('two'); + }); }); - } - ['@test When an application with advance/deferReadiness is reset, the app does correctly become ready after reset'](assert) { - let readyCallCount = 0; - - run(() => { - this.createApplication({ - ready() { - readyCallCount++; - } + let initialRouter, initialApplicationController; + return this.visit('/one') + .then(() => { + initialApplicationController = this.applicationInstance.lookup( + 'controller:application' + ); + initialRouter = this.applicationInstance.lookup('router:main'); + let location = initialRouter.get('location'); + + assert.equal(location.getURL(), '/one'); + assert.equal(get(initialApplicationController, 'currentPath'), 'one'); + + this.application.reset(); + + return this.application._bootPromise; + }) + .then(() => { + let applicationController = this.applicationInstance.lookup( + 'controller:application' + ); + assert.strictEqual( + applicationController, + undefined, + 'application controller no longer exists' + ); + + return this.visit('/one'); + }) + .then(() => { + let applicationController = this.applicationInstance.lookup( + 'controller:application' + ); + let router = this.applicationInstance.lookup('router:main'); + let location = router.get('location'); + + assert.notEqual( + initialRouter, + router, + 'a different router instance was created' + ); + assert.notEqual( + initialApplicationController, + applicationController, + 'a different application controller is created' + ); + + assert.equal(location.getURL(), '/one'); + assert.equal(get(applicationController, 'currentPath'), 'one'); + }); + } + + ['@test When an application with advance/deferReadiness is reset, the app does correctly become ready after reset']( + assert + ) { + let readyCallCount = 0; + + run(() => { + this.createApplication({ + ready() { + readyCallCount++; + } + }); + + this.application.deferReadiness(); + assert.equal(readyCallCount, 0, 'ready has not yet been called'); }); - this.application.deferReadiness(); - assert.equal(readyCallCount, 0, 'ready has not yet been called'); - }); - - run(this.application, 'advanceReadiness'); + run(this.application, 'advanceReadiness'); - assert.equal(readyCallCount, 1, 'ready was called once'); + assert.equal(readyCallCount, 1, 'ready was called once'); - this.application.reset(); + this.application.reset(); - assert.equal(readyCallCount, 2, 'ready was called twice'); + assert.equal(readyCallCount, 2, 'ready was called twice'); + } } - -}); +); diff --git a/packages/ember-application/tests/system/visit_test.js b/packages/ember-application/tests/system/visit_test.js index 3e9a3396eaa..5225a126e1b 100644 --- a/packages/ember-application/tests/system/visit_test.js +++ b/packages/ember-application/tests/system/visit_test.js @@ -18,663 +18,813 @@ function expectAsyncError() { RSVP.off('error'); } -moduleFor('Application - visit()', class extends ApplicationTestCase { +moduleFor( + 'Application - visit()', + class extends ApplicationTestCase { + teardown() { + RSVP.on('error', onerrorDefault); + ENV._APPLICATION_TEMPLATE_WRAPPER = false; + super.teardown(); + } - teardown() { - RSVP.on('error', onerrorDefault); - ENV._APPLICATION_TEMPLATE_WRAPPER = false; - super.teardown(); - } + createApplication(options) { + return super.createApplication(options, Application.extend()); + } - createApplication(options) { - return super.createApplication(options, Application.extend()); - } + assertEmptyFixture(message) { + this.assert.strictEqual( + document.getElementById('qunit-fixture').children.length, + 0, + `there are no elements in the fixture element ${message ? message : ''}` + ); + } - assertEmptyFixture(message) { - this.assert.strictEqual( - document.getElementById('qunit-fixture').children.length, 0, - `there are no elements in the fixture element ${message ? message : ''}` - ); - } + [`@test does not add serialize-mode markers by default`](assert) { + let templateContent = '
Hi, Mom!
'; + this.addTemplate('index', templateContent); + let rootElement = document.createElement('div'); + + let bootOptions = { + isBrowser: false, + rootElement + }; + + ENV._APPLICATION_TEMPLATE_WRAPPER = false; + return this.visit('/', bootOptions).then(() => { + assert.equal( + rootElement.innerHTML, + templateContent, + 'without serialize flag renders as expected' + ); + }); + } - [`@test does not add serialize-mode markers by default`](assert) { - let templateContent = '
Hi, Mom!
'; - this.addTemplate('index', templateContent); - let rootElement = document.createElement('div'); + [`@test _renderMode: rehydration`](assert) { + assert.expect(2); - let bootOptions = { - isBrowser: false, - rootElement - }; + let indexTemplate = '
Hi, Mom!
'; + this.addTemplate('index', indexTemplate); + let rootElement = document.createElement('div'); - ENV._APPLICATION_TEMPLATE_WRAPPER = false; - return this.visit('/', bootOptions).then(()=> { - assert.equal(rootElement.innerHTML, templateContent, 'without serialize flag renders as expected'); - }); - } + let bootOptions = { + isBrowser: false, + rootElement, + _renderMode: 'serialize' + }; - [`@test _renderMode: rehydration`](assert) { - assert.expect(2); + ENV._APPLICATION_TEMPLATE_WRAPPER = false; - let indexTemplate = '
Hi, Mom!
'; - this.addTemplate('index', indexTemplate); - let rootElement = document.createElement('div'); + return this.visit('/', bootOptions) + .then(instance => { + assert.ok( + isSerializationFirstNode(instance.rootElement.firstChild), + 'glimmer-vm comment node was not found' + ); + }) + .then(() => { + return this.runTask(() => { + this.applicationInstance.destroy(); + this.applicationInstance = null; + }); + }) + .then(() => { + bootOptions = { + isBrowser: false, + rootElement, + _renderMode: 'rehydrate' + }; + + this.application.visit('/', bootOptions).then(instance => { + assert.equal( + instance.rootElement.innerHTML, + indexTemplate, + 'was not properly rehydrated' + ); + }); + }); + } - let bootOptions = { - isBrowser: false, - rootElement, - _renderMode: 'serialize' - }; + // This tests whether the application is "autobooted" by registering an + // instance initializer and asserting it never gets run. Since this is + // inherently testing that async behavior *doesn't* happen, we set a + // 500ms timeout to verify that when autoboot is set to false, the + // instance initializer that would normally get called on DOM ready + // does not fire. + [`@test Applications with autoboot set to false do not autoboot`](assert) { + function delay(time) { + return new RSVP.Promise(resolve => later(resolve, time)); + } - ENV._APPLICATION_TEMPLATE_WRAPPER = false; + let appBooted = 0; + let instanceBooted = 0; - return this.visit('/', bootOptions) - .then((instance) => { - assert.ok( - isSerializationFirstNode(instance.rootElement.firstChild), - 'glimmer-vm comment node was not found' - ); - }).then(() =>{ - return this.runTask(()=>{ - this.applicationInstance.destroy(); - this.applicationInstance = null; - }); - }).then(() => { - bootOptions = { - isBrowser: false, - rootElement, - _renderMode: 'rehydrate' - }; - - this.application.visit('/', bootOptions).then(instance => { - assert.equal( - instance.rootElement.innerHTML, - indexTemplate, - 'was not properly rehydrated' - ); - }); + this.application.initializer({ + name: 'assert-no-autoboot', + initialize() { + appBooted++; + } }); - } - - // This tests whether the application is "autobooted" by registering an - // instance initializer and asserting it never gets run. Since this is - // inherently testing that async behavior *doesn't* happen, we set a - // 500ms timeout to verify that when autoboot is set to false, the - // instance initializer that would normally get called on DOM ready - // does not fire. - [`@test Applications with autoboot set to false do not autoboot`](assert) { - function delay(time) { - return new RSVP.Promise(resolve => later(resolve, time)); - } - let appBooted = 0; - let instanceBooted = 0; + this.application.instanceInitializer({ + name: 'assert-no-autoboot', + initialize() { + instanceBooted++; + } + }); - this.application.initializer({ - name: 'assert-no-autoboot', - initialize() { - appBooted++; - } - }); + assert.ok(!this.applicationInstance, 'precond - no instance'); + assert.ok(appBooted === 0, 'precond - not booted'); + assert.ok(instanceBooted === 0, 'precond - not booted'); + + // Continue after 500ms + return delay(500) + .then(() => { + assert.ok(appBooted === 0, '500ms elapsed without app being booted'); + assert.ok( + instanceBooted === 0, + '500ms elapsed without instances being booted' + ); - this.application.instanceInitializer({ - name: 'assert-no-autoboot', - initialize() { - instanceBooted++; - } - }); - - assert.ok(!this.applicationInstance, 'precond - no instance'); - assert.ok(appBooted === 0, 'precond - not booted'); - assert.ok(instanceBooted === 0, 'precond - not booted'); - - // Continue after 500ms - return delay(500).then(() => { - assert.ok(appBooted === 0, '500ms elapsed without app being booted'); - assert.ok(instanceBooted === 0, '500ms elapsed without instances being booted'); - - return this.runTask(() => this.application.boot()); - }).then(() => { - assert.ok(appBooted === 1, 'app should boot when manually calling `app.boot()`'); - assert.ok(instanceBooted === 0, 'no instances should be booted automatically when manually calling `app.boot()'); - }); - } + return this.runTask(() => this.application.boot()); + }) + .then(() => { + assert.ok( + appBooted === 1, + 'app should boot when manually calling `app.boot()`' + ); + assert.ok( + instanceBooted === 0, + 'no instances should be booted automatically when manually calling `app.boot()' + ); + }); + } - [`@test calling visit() on an app without first calling boot() should boot the app`](assert) { - let appBooted = 0; - let instanceBooted = 0; + [`@test calling visit() on an app without first calling boot() should boot the app`]( + assert + ) { + let appBooted = 0; + let instanceBooted = 0; - this.application.initializer({ - name: 'assert-no-autoboot', - initialize() { - appBooted++; - } - }); + this.application.initializer({ + name: 'assert-no-autoboot', + initialize() { + appBooted++; + } + }); - this.application.instanceInitializer({ - name: 'assert-no-autoboot', - initialize() { - instanceBooted++; - } - }); + this.application.instanceInitializer({ + name: 'assert-no-autoboot', + initialize() { + instanceBooted++; + } + }); - return this.visit('/').then(() => { - assert.ok(appBooted === 1, 'the app should be booted`'); - assert.ok(instanceBooted === 1, 'an instances should be booted'); - }); - } + return this.visit('/').then(() => { + assert.ok(appBooted === 1, 'the app should be booted`'); + assert.ok(instanceBooted === 1, 'an instances should be booted'); + }); + } - [`@test calling visit() on an already booted app should not boot it again`](assert) { - let appBooted = 0; - let instanceBooted = 0; + [`@test calling visit() on an already booted app should not boot it again`]( + assert + ) { + let appBooted = 0; + let instanceBooted = 0; - this.application.initializer({ - name: 'assert-no-autoboot', - initialize() { - appBooted++; - } - }); + this.application.initializer({ + name: 'assert-no-autoboot', + initialize() { + appBooted++; + } + }); - this.application.instanceInitializer({ - name: 'assert-no-autoboot', - initialize() { - instanceBooted++; - } - }); + this.application.instanceInitializer({ + name: 'assert-no-autoboot', + initialize() { + instanceBooted++; + } + }); - return this.runTask(() => this.application.boot()).then(() => { - assert.ok(appBooted === 1, 'the app should be booted'); - assert.ok(instanceBooted === 0, 'no instances should be booted'); + return this.runTask(() => this.application.boot()) + .then(() => { + assert.ok(appBooted === 1, 'the app should be booted'); + assert.ok(instanceBooted === 0, 'no instances should be booted'); - return this.visit('/'); - }).then(() => { - assert.ok(appBooted === 1, 'the app should not be booted again'); - assert.ok(instanceBooted === 1, 'an instance should be booted'); + return this.visit('/'); + }) + .then(() => { + assert.ok(appBooted === 1, 'the app should not be booted again'); + assert.ok(instanceBooted === 1, 'an instance should be booted'); - /* + /* * Destroy the instance. */ - return this.runTask(() => { - this.applicationInstance.destroy(); - this.applicationInstance = null; - }); - }).then(() => { - /* + return this.runTask(() => { + this.applicationInstance.destroy(); + this.applicationInstance = null; + }); + }) + .then(() => { + /* * Visit on the application a second time. The application should remain * booted, but a new instance will be created. */ - return this.application.visit('/').then(instance => { - this.applicationInstance = instance; - }); - }).then(() => { - assert.ok(appBooted === 1, 'the app should not be booted again'); - assert.ok(instanceBooted === 2, 'another instance should be booted'); - }); - } + return this.application.visit('/').then(instance => { + this.applicationInstance = instance; + }); + }) + .then(() => { + assert.ok(appBooted === 1, 'the app should not be booted again'); + assert.ok(instanceBooted === 2, 'another instance should be booted'); + }); + } - [`@test visit() rejects on application boot failure`](assert) { - this.application.initializer({ - name: 'error', - initialize() { - throw new Error('boot failure'); - } - }); + [`@test visit() rejects on application boot failure`](assert) { + this.application.initializer({ + name: 'error', + initialize() { + throw new Error('boot failure'); + } + }); - expectAsyncError(); + expectAsyncError(); - return this.visit('/').then(() => { - assert.ok(false, 'It should not resolve the promise'); - }, error => { - assert.ok(error instanceof Error, 'It should reject the promise with the boot error'); - assert.equal(error.message, 'boot failure'); - }); - } + return this.visit('/').then( + () => { + assert.ok(false, 'It should not resolve the promise'); + }, + error => { + assert.ok( + error instanceof Error, + 'It should reject the promise with the boot error' + ); + assert.equal(error.message, 'boot failure'); + } + ); + } - [`@test visit() rejects on instance boot failure`](assert) { - this.application.instanceInitializer({ - name: 'error', - initialize() { - throw new Error('boot failure'); - } - }); + [`@test visit() rejects on instance boot failure`](assert) { + this.application.instanceInitializer({ + name: 'error', + initialize() { + throw new Error('boot failure'); + } + }); - expectAsyncError(); + expectAsyncError(); - return this.visit('/').then(() => { - assert.ok(false, 'It should not resolve the promise'); - }, error => { - assert.ok(error instanceof Error, 'It should reject the promise with the boot error'); - assert.equal(error.message, 'boot failure'); - }); - } + return this.visit('/').then( + () => { + assert.ok(false, 'It should not resolve the promise'); + }, + error => { + assert.ok( + error instanceof Error, + 'It should reject the promise with the boot error' + ); + assert.equal(error.message, 'boot failure'); + } + ); + } - [`@test visit() follows redirects`](assert) { - this.router.map(function() { - this.route('a'); - this.route('b', { path: '/b/:b' }); - this.route('c', { path: '/c/:c' }); - }); + [`@test visit() follows redirects`](assert) { + this.router.map(function() { + this.route('a'); + this.route('b', { path: '/b/:b' }); + this.route('c', { path: '/c/:c' }); + }); - this.add('route:a', Route.extend({ - afterModel() { - this.replaceWith('b', 'zomg'); - } - })); + this.add( + 'route:a', + Route.extend({ + afterModel() { + this.replaceWith('b', 'zomg'); + } + }) + ); - this.add('route:b', Route.extend({ - afterModel(params) { - this.transitionTo('c', params.b); - } - })); + this.add( + 'route:b', + Route.extend({ + afterModel(params) { + this.transitionTo('c', params.b); + } + }) + ); - /* + /* * First call to `visit` is `this.application.visit` and returns the * applicationInstance. */ - return this.visit('/a').then(instance => { - assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); - assert.equal(instance.getURL(), '/c/zomg', 'It should follow all redirects'); - }); - } + return this.visit('/a').then(instance => { + assert.ok( + instance instanceof ApplicationInstance, + 'promise is resolved with an ApplicationInstance' + ); + assert.equal( + instance.getURL(), + '/c/zomg', + 'It should follow all redirects' + ); + }); + } - [`@test visit() rejects if an error occurred during a transition`](assert) { - this.router.map(function() { - this.route('a'); - this.route('b', { path: '/b/:b' }); - this.route('c', { path: '/c/:c' }); - }); + [`@test visit() rejects if an error occurred during a transition`](assert) { + this.router.map(function() { + this.route('a'); + this.route('b', { path: '/b/:b' }); + this.route('c', { path: '/c/:c' }); + }); - this.add('route:a', Route.extend({ - afterModel() { - this.replaceWith('b', 'zomg'); - } - })); + this.add( + 'route:a', + Route.extend({ + afterModel() { + this.replaceWith('b', 'zomg'); + } + }) + ); - this.add('route:b', Route.extend({ - afterModel(params) { - this.transitionTo('c', params.b); - } - })); + this.add( + 'route:b', + Route.extend({ + afterModel(params) { + this.transitionTo('c', params.b); + } + }) + ); - this.add('route:c', Route.extend({ - afterModel() { - throw new Error('transition failure'); - } - })); + this.add( + 'route:c', + Route.extend({ + afterModel() { + throw new Error('transition failure'); + } + }) + ); - expectAsyncError(); + expectAsyncError(); - return this.visit('/a').then(() => { - assert.ok(false, 'It should not resolve the promise'); - }, error => { - assert.ok(error instanceof Error, 'It should reject the promise with the boot error'); - assert.equal(error.message, 'transition failure'); - }); - } + return this.visit('/a').then( + () => { + assert.ok(false, 'It should not resolve the promise'); + }, + error => { + assert.ok( + error instanceof Error, + 'It should reject the promise with the boot error' + ); + assert.equal(error.message, 'transition failure'); + } + ); + } - [`@test visit() chain`](assert) { - this.router.map(function() { - this.route('a'); - this.route('b'); - this.route('c'); - }); - - return this.visit('/').then(instance => { - assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); - assert.equal(instance.getURL(), '/'); - - return instance.visit('/a'); - }).then(instance => { - assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); - assert.equal(instance.getURL(), '/a'); - - return instance.visit('/b'); - }).then(instance => { - assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); - assert.equal(instance.getURL(), '/b'); - - return instance.visit('/c'); - }).then(instance => { - assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); - assert.equal(instance.getURL(), '/c'); - }); - } + [`@test visit() chain`](assert) { + this.router.map(function() { + this.route('a'); + this.route('b'); + this.route('c'); + }); - [`@test visit() returns a promise that resolves when the view has rendered`](assert) { - this.addTemplate('application', `

Hello world

`); + return this.visit('/') + .then(instance => { + assert.ok( + instance instanceof ApplicationInstance, + 'promise is resolved with an ApplicationInstance' + ); + assert.equal(instance.getURL(), '/'); + + return instance.visit('/a'); + }) + .then(instance => { + assert.ok( + instance instanceof ApplicationInstance, + 'promise is resolved with an ApplicationInstance' + ); + assert.equal(instance.getURL(), '/a'); + + return instance.visit('/b'); + }) + .then(instance => { + assert.ok( + instance instanceof ApplicationInstance, + 'promise is resolved with an ApplicationInstance' + ); + assert.equal(instance.getURL(), '/b'); + + return instance.visit('/c'); + }) + .then(instance => { + assert.ok( + instance instanceof ApplicationInstance, + 'promise is resolved with an ApplicationInstance' + ); + assert.equal(instance.getURL(), '/c'); + }); + } - this.assertEmptyFixture(); + [`@test visit() returns a promise that resolves when the view has rendered`]( + assert + ) { + this.addTemplate('application', `

Hello world

`); - return this.visit('/').then(instance => { - assert.ok( - instance instanceof ApplicationInstance, - 'promise is resolved with an ApplicationInstance' - ); - assert.equal( - this.element.textContent, 'Hello world', - 'the application was rendered once the promise resolves' - ); - }); - } + this.assertEmptyFixture(); - [`@test visit() returns a promise that resolves without rendering when shouldRender is set to false`](assert) { - assert.expect(3); + return this.visit('/').then(instance => { + assert.ok( + instance instanceof ApplicationInstance, + 'promise is resolved with an ApplicationInstance' + ); + assert.equal( + this.element.textContent, + 'Hello world', + 'the application was rendered once the promise resolves' + ); + }); + } - this.addTemplate('application', '

Hello world

'); + [`@test visit() returns a promise that resolves without rendering when shouldRender is set to false`]( + assert + ) { + assert.expect(3); - this.assertEmptyFixture(); + this.addTemplate('application', '

Hello world

'); - return this.visit('/', { shouldRender: false }).then(instance => { - assert.ok( - instance instanceof ApplicationInstance, - 'promise is resolved with an ApplicationInstance' - ); + this.assertEmptyFixture(); - this.assertEmptyFixture('after visit'); - }); - } + return this.visit('/', { shouldRender: false }).then(instance => { + assert.ok( + instance instanceof ApplicationInstance, + 'promise is resolved with an ApplicationInstance' + ); - [`@test visit() renders a template when shouldRender is set to true`](assert) { - assert.expect(3); + this.assertEmptyFixture('after visit'); + }); + } - this.addTemplate('application', '

Hello world

'); + [`@test visit() renders a template when shouldRender is set to true`]( + assert + ) { + assert.expect(3); - this.assertEmptyFixture(); + this.addTemplate('application', '

Hello world

'); - return this.visit('/', { shouldRender: true }).then(instance => { - assert.ok( - instance instanceof ApplicationInstance, - 'promise is resolved with an ApplicationInstance' - ); - assert.strictEqual( - document.querySelector('#qunit-fixture').children.length, 1, - 'there is 1 element in the fixture element after visit' - ); - }); - } + this.assertEmptyFixture(); - [`@test visit() returns a promise that resolves without rendering when shouldRender is set to false with Engines`](assert) { - assert.expect(3); + return this.visit('/', { shouldRender: true }).then(instance => { + assert.ok( + instance instanceof ApplicationInstance, + 'promise is resolved with an ApplicationInstance' + ); + assert.strictEqual( + document.querySelector('#qunit-fixture').children.length, + 1, + 'there is 1 element in the fixture element after visit' + ); + }); + } - this.router.map(function() { - this.mount('blog'); - }); + [`@test visit() returns a promise that resolves without rendering when shouldRender is set to false with Engines`]( + assert + ) { + assert.expect(3); - this.addTemplate('application', '

Hello world

'); + this.router.map(function() { + this.mount('blog'); + }); - // Register engine - let BlogEngine = Engine.extend(); - this.add('engine:blog', BlogEngine); + this.addTemplate('application', '

Hello world

'); - // Register engine route map - let BlogMap = function() {}; - this.add('route-map:blog', BlogMap); + // Register engine + let BlogEngine = Engine.extend(); + this.add('engine:blog', BlogEngine); - this.assertEmptyFixture(); + // Register engine route map + let BlogMap = function() {}; + this.add('route-map:blog', BlogMap); - return this.visit('/blog', { shouldRender: false }).then(instance => { - assert.ok( - instance instanceof ApplicationInstance, - 'promise is resolved with an ApplicationInstance' - ); + this.assertEmptyFixture(); - this.assertEmptyFixture('after visit'); - }); - } + return this.visit('/blog', { shouldRender: false }).then(instance => { + assert.ok( + instance instanceof ApplicationInstance, + 'promise is resolved with an ApplicationInstance' + ); - [`@test visit() does not setup the event_dispatcher:main if isInteractive is false (with Engines) GH#15615`](assert) { - assert.expect(3); + this.assertEmptyFixture('after visit'); + }); + } - this.router.map(function() { - this.mount('blog'); - }); + [`@test visit() does not setup the event_dispatcher:main if isInteractive is false (with Engines) GH#15615`]( + assert + ) { + assert.expect(3); - this.addTemplate('application', '

Hello world

{{outlet}}'); - this.add('event_dispatcher:main', { - create() { throw new Error('should not happen!'); } - }); + this.router.map(function() { + this.mount('blog'); + }); - // Register engine - let BlogEngine = Engine.extend({ - init(...args) { - this._super.apply(this, args); - this.register('template:application', compile('{{cache-money}}')); - this.register('template:components/cache-money', compile(` + this.addTemplate('application', '

Hello world

{{outlet}}'); + this.add('event_dispatcher:main', { + create() { + throw new Error('should not happen!'); + } + }); + + // Register engine + let BlogEngine = Engine.extend({ + init(...args) { + this._super.apply(this, args); + this.register('template:application', compile('{{cache-money}}')); + this.register( + 'template:components/cache-money', + compile(`

Dis cache money

- `)); - this.register('component:cache-money', Component.extend({})); - } - }); - this.add('engine:blog', BlogEngine); + `) + ); + this.register('component:cache-money', Component.extend({})); + } + }); + this.add('engine:blog', BlogEngine); - // Register engine route map - let BlogMap = function() {}; - this.add('route-map:blog', BlogMap); + // Register engine route map + let BlogMap = function() {}; + this.add('route-map:blog', BlogMap); - this.assertEmptyFixture(); + this.assertEmptyFixture(); - return this.visit('/blog', { isInteractive: false }).then(instance => { - assert.ok( - instance instanceof ApplicationInstance, - 'promise is resolved with an ApplicationInstance' - ); - assert.strictEqual( - this.element.querySelector('p').textContent, 'Dis cache money', - 'Engine component is resolved' - ); - }); - } + return this.visit('/blog', { isInteractive: false }).then(instance => { + assert.ok( + instance instanceof ApplicationInstance, + 'promise is resolved with an ApplicationInstance' + ); + assert.strictEqual( + this.element.querySelector('p').textContent, + 'Dis cache money', + 'Engine component is resolved' + ); + }); + } - [`@test visit() on engine resolves engine component`](assert) { - assert.expect(2); + [`@test visit() on engine resolves engine component`](assert) { + assert.expect(2); - this.router.map(function() { - this.mount('blog'); - }); + this.router.map(function() { + this.mount('blog'); + }); - // Register engine - let BlogEngine = Engine.extend({ - init(...args) { - this._super.apply(this, args); - this.register('template:application', compile('{{cache-money}}')); - this.register('template:components/cache-money', compile(` + // Register engine + let BlogEngine = Engine.extend({ + init(...args) { + this._super.apply(this, args); + this.register('template:application', compile('{{cache-money}}')); + this.register( + 'template:components/cache-money', + compile(`

Dis cache money

- `)); - this.register('component:cache-money', Component.extend({})); - } - }); - this.add('engine:blog', BlogEngine); + `) + ); + this.register('component:cache-money', Component.extend({})); + } + }); + this.add('engine:blog', BlogEngine); - // Register engine route map - let BlogMap = function() {}; - this.add('route-map:blog', BlogMap); + // Register engine route map + let BlogMap = function() {}; + this.add('route-map:blog', BlogMap); - this.assertEmptyFixture(); + this.assertEmptyFixture(); - return this.visit('/blog', { shouldRender: true }).then(() => { - assert.strictEqual( - this.element.querySelector('p').textContent, 'Dis cache money', - 'Engine component is resolved' - ); - }); - } + return this.visit('/blog', { shouldRender: true }).then(() => { + assert.strictEqual( + this.element.querySelector('p').textContent, + 'Dis cache money', + 'Engine component is resolved' + ); + }); + } - [`@test visit() on engine resolves engine helper`](assert) { - assert.expect(2); - - this.router.map(function() { - this.mount('blog'); - }); - - // Register engine - let BlogEngine = Engine.extend({ - init(...args) { - this._super.apply(this, args); - this.register('template:application', compile('{{swag}}')); - this.register('helper:swag', helper(function() { - return 'turnt up'; - })); - } - }); - this.add('engine:blog', BlogEngine); + [`@test visit() on engine resolves engine helper`](assert) { + assert.expect(2); - // Register engine route map - let BlogMap = function() {}; - this.add('route-map:blog', BlogMap); + this.router.map(function() { + this.mount('blog'); + }); - this.assertEmptyFixture(); + // Register engine + let BlogEngine = Engine.extend({ + init(...args) { + this._super.apply(this, args); + this.register('template:application', compile('{{swag}}')); + this.register( + 'helper:swag', + helper(function() { + return 'turnt up'; + }) + ); + } + }); + this.add('engine:blog', BlogEngine); - return this.visit('/blog', { shouldRender: true }).then(() => { - assert.strictEqual( - this.element.textContent, 'turnt up', - 'Engine component is resolved' - ); - }); - } + // Register engine route map + let BlogMap = function() {}; + this.add('route-map:blog', BlogMap); - [`@test Ember Islands-style setup`](assert) { - let xFooInitCalled = false; - let xFooDidInsertElementCalled = false; + this.assertEmptyFixture(); - let xBarInitCalled = false; - let xBarDidInsertElementCalled = false; + return this.visit('/blog', { shouldRender: true }).then(() => { + assert.strictEqual( + this.element.textContent, + 'turnt up', + 'Engine component is resolved' + ); + }); + } - this.router.map(function() { - this.route('show', { path: '/:component_name' }); - }); + [`@test Ember Islands-style setup`](assert) { + let xFooInitCalled = false; + let xFooDidInsertElementCalled = false; - this.add('route:show', Route.extend({ - queryParams: { - data: { refreshModel: true } - }, + let xBarInitCalled = false; + let xBarDidInsertElementCalled = false; - model(params) { - return { - componentName: params.component_name, - componentData: params.data ? JSON.parse(params.data) : undefined - }; - } - })); + this.router.map(function() { + this.route('show', { path: '/:component_name' }); + }); - let Counter = EmberObject.extend({ - value: 0, + this.add( + 'route:show', + Route.extend({ + queryParams: { + data: { refreshModel: true } + }, + + model(params) { + return { + componentName: params.component_name, + componentData: params.data ? JSON.parse(params.data) : undefined + }; + } + }) + ); - increment() { - this.incrementProperty('value'); - } - }); + let Counter = EmberObject.extend({ + value: 0, - this.add('service:isolatedCounter', Counter); - this.add('service:sharedCounter', Counter.create()); - this.application.registerOptions('service:sharedCounter', {instantiate: false}); + increment() { + this.incrementProperty('value'); + } + }); - this.addTemplate('show', '{{component model.componentName model=model.componentData}}'); + this.add('service:isolatedCounter', Counter); + this.add('service:sharedCounter', Counter.create()); + this.application.registerOptions('service:sharedCounter', { + instantiate: false + }); - this.addTemplate('components/x-foo', ` + this.addTemplate( + 'show', + '{{component model.componentName model=model.componentData}}' + ); + + this.addTemplate( + 'components/x-foo', + `

X-Foo

Hello {{model.name}}, I have been clicked {{isolatedCounter.value}} times ({{sharedCounter.value}} times combined)!

- `); + ` + ); - this.add('component:x-foo', Component.extend({ - tagName: 'x-foo', + this.add( + 'component:x-foo', + Component.extend({ + tagName: 'x-foo', - isolatedCounter: inject.service(), - sharedCounter: inject.service(), + isolatedCounter: inject.service(), + sharedCounter: inject.service(), - init() { - this._super(); - xFooInitCalled = true; - }, + init() { + this._super(); + xFooInitCalled = true; + }, - didInsertElement() { - xFooDidInsertElementCalled = true; - }, + didInsertElement() { + xFooDidInsertElementCalled = true; + }, - click() { - this.get('isolatedCounter').increment(); - this.get('sharedCounter').increment(); - } - })); + click() { + this.get('isolatedCounter').increment(); + this.get('sharedCounter').increment(); + } + }) + ); - this.addTemplate('components/x-bar', ` + this.addTemplate( + 'components/x-bar', + `

X-Bar

- `); - - this.add('component:x-bar', Component.extend({ - counter: inject.service('sharedCounter'), - - actions: { - incrementCounter() { - this.get('counter').increment(); - } - }, - - init() { - this._super(); - xBarInitCalled = true; - }, - - didInsertElement() { - xBarDidInsertElementCalled = true; - } - })); - - let fixtureElement = document.querySelector('#qunit-fixture'); - let foo = document.createElement('div'); - let bar = document.createElement('div'); - fixtureElement.appendChild(foo); - fixtureElement.appendChild(bar); - - let data = encodeURIComponent(JSON.stringify({ name: 'Godfrey' })); - let instances = []; - - return RSVP.all([ - this.runTask(() => { - return this.application.visit(`/x-foo?data=${data}`, { rootElement: foo }); - }), - this.runTask(() => { - return this.application.visit('/x-bar', { rootElement: bar }); - }) - ]).then(_instances => { - instances = _instances; - - assert.ok(xFooInitCalled); - assert.ok(xFooDidInsertElementCalled); - - assert.ok(xBarInitCalled); - assert.ok(xBarDidInsertElementCalled); + ` + ); - assert.equal(foo.querySelector('h1').textContent, 'X-Foo'); - assert.equal(foo.querySelector('p').textContent, 'Hello Godfrey, I have been clicked 0 times (0 times combined)!'); - assert.ok(foo.textContent.indexOf('X-Bar') === -1); + this.add( + 'component:x-bar', + Component.extend({ + counter: inject.service('sharedCounter'), + + actions: { + incrementCounter() { + this.get('counter').increment(); + } + }, + + init() { + this._super(); + xBarInitCalled = true; + }, + + didInsertElement() { + xBarDidInsertElementCalled = true; + } + }) + ); - assert.equal(bar.querySelector('h1').textContent, 'X-Bar'); - assert.equal(bar.querySelector('button').textContent, 'Join 0 others in clicking me!'); - assert.ok(bar.textContent.indexOf('X-Foo') === -1); + let fixtureElement = document.querySelector('#qunit-fixture'); + let foo = document.createElement('div'); + let bar = document.createElement('div'); + fixtureElement.appendChild(foo); + fixtureElement.appendChild(bar); + + let data = encodeURIComponent(JSON.stringify({ name: 'Godfrey' })); + let instances = []; + + return RSVP.all([ + this.runTask(() => { + return this.application.visit(`/x-foo?data=${data}`, { + rootElement: foo + }); + }), + this.runTask(() => { + return this.application.visit('/x-bar', { rootElement: bar }); + }) + ]) + .then(_instances => { + instances = _instances; + + assert.ok(xFooInitCalled); + assert.ok(xFooDidInsertElementCalled); + + assert.ok(xBarInitCalled); + assert.ok(xBarDidInsertElementCalled); + + assert.equal(foo.querySelector('h1').textContent, 'X-Foo'); + assert.equal( + foo.querySelector('p').textContent, + 'Hello Godfrey, I have been clicked 0 times (0 times combined)!' + ); + assert.ok(foo.textContent.indexOf('X-Bar') === -1); - this.runTask(() => { - this.click(foo.querySelector('x-foo')); - }); + assert.equal(bar.querySelector('h1').textContent, 'X-Bar'); + assert.equal( + bar.querySelector('button').textContent, + 'Join 0 others in clicking me!' + ); + assert.ok(bar.textContent.indexOf('X-Foo') === -1); - assert.equal(foo.querySelector('p').textContent, 'Hello Godfrey, I have been clicked 1 times (1 times combined)!'); - assert.equal(bar.querySelector('button').textContent, 'Join 1 others in clicking me!'); + this.runTask(() => { + this.click(foo.querySelector('x-foo')); + }); - this.runTask(() => { - this.click(bar.querySelector('button')); - this.click(bar.querySelector('button')); - }); + assert.equal( + foo.querySelector('p').textContent, + 'Hello Godfrey, I have been clicked 1 times (1 times combined)!' + ); + assert.equal( + bar.querySelector('button').textContent, + 'Join 1 others in clicking me!' + ); - assert.equal(foo.querySelector('p').textContent, 'Hello Godfrey, I have been clicked 1 times (3 times combined)!'); - assert.equal(bar.querySelector('button').textContent, 'Join 3 others in clicking me!'); + this.runTask(() => { + this.click(bar.querySelector('button')); + this.click(bar.querySelector('button')); + }); - }).finally(() => { - this.runTask(() => { - instances.forEach(instance => { - instance.destroy(); + assert.equal( + foo.querySelector('p').textContent, + 'Hello Godfrey, I have been clicked 1 times (3 times combined)!' + ); + assert.equal( + bar.querySelector('button').textContent, + 'Join 3 others in clicking me!' + ); + }) + .finally(() => { + this.runTask(() => { + instances.forEach(instance => { + instance.destroy(); + }); + }); }); - }); - }); + } } - -}); +); diff --git a/packages/ember-application/tests/test-helpers/registry-check.js b/packages/ember-application/tests/test-helpers/registry-check.js index dd75bf7c65a..2255a661bbf 100644 --- a/packages/ember-application/tests/test-helpers/registry-check.js +++ b/packages/ember-application/tests/test-helpers/registry-check.js @@ -1,8 +1,17 @@ export function verifyRegistration(assert, owner, fullName) { - assert.ok(owner.resolveRegistration(fullName), `has registration: ${fullName}`); + assert.ok( + owner.resolveRegistration(fullName), + `has registration: ${fullName}` + ); } -export function verifyInjection(assert, owner, fullName, property, injectionName) { +export function verifyInjection( + assert, + owner, + fullName, + property, + injectionName +) { let registry = owner.__registry__; let injections; @@ -18,11 +27,17 @@ export function verifyInjection(assert, owner, fullName, property, injectionName for (let i = 0, l = injections.length; i < l; i++) { injection = injections[i]; - if (injection.property === property && injection.specifier === normalizedName) { + if ( + injection.property === property && + injection.specifier === normalizedName + ) { hasInjection = true; break; } } - assert.ok(hasInjection, `has injection: ${fullName}.${property} = ${injectionName}`); + assert.ok( + hasInjection, + `has injection: ${fullName}.${property} = ${injectionName}` + ); } diff --git a/packages/ember-console/lib/index.js b/packages/ember-console/lib/index.js index 33234ef9a36..cbd757fe508 100644 --- a/packages/ember-console/lib/index.js +++ b/packages/ember-console/lib/index.js @@ -2,9 +2,11 @@ import { deprecate } from 'ember-debug'; // Deliver message that the function is deprecated -const DEPRECATION_MESSAGE = 'Use of Ember.Logger is deprecated. Please use `console` for logging.'; +const DEPRECATION_MESSAGE = + 'Use of Ember.Logger is deprecated. Please use `console` for logging.'; const DEPRECATION_ID = 'ember-console.deprecate-logger'; -const DEPRECATION_URL = 'https://emberjs.com/deprecations/v3.x#toc_use-console-rather-than-ember-logger'; +const DEPRECATION_URL = + 'https://emberjs.com/deprecations/v3.x#toc_use-console-rather-than-ember-logger'; /** @module ember */ @@ -34,8 +36,12 @@ export default { @param {*} arguments @public */ - log() { - deprecate( DEPRECATION_MESSAGE, false, { id: DEPRECATION_ID, until: '4.0.0', url: DEPRECATION_URL } ); + log() { + deprecate(DEPRECATION_MESSAGE, false, { + id: DEPRECATION_ID, + until: '4.0.0', + url: DEPRECATION_URL + }); return console.log(...arguments); // eslint-disable-line no-console }, @@ -53,8 +59,12 @@ export default { @param {*} arguments @public */ - warn() { - deprecate( DEPRECATION_MESSAGE, false, { id: DEPRECATION_ID, until: '4.0.0', url: DEPRECATION_URL } ); + warn() { + deprecate(DEPRECATION_MESSAGE, false, { + id: DEPRECATION_ID, + until: '4.0.0', + url: DEPRECATION_URL + }); return console.warn(...arguments); // eslint-disable-line no-console }, @@ -72,8 +82,12 @@ export default { @param {*} arguments @public */ - error() { - deprecate( DEPRECATION_MESSAGE, false, { id: DEPRECATION_ID, until: '4.0.0', url: DEPRECATION_URL } ); + error() { + deprecate(DEPRECATION_MESSAGE, false, { + id: DEPRECATION_ID, + until: '4.0.0', + url: DEPRECATION_URL + }); return console.error(...arguments); // eslint-disable-line no-console }, @@ -92,8 +106,12 @@ export default { @param {*} arguments @public */ - info() { - deprecate( DEPRECATION_MESSAGE, false, { id: DEPRECATION_ID, until: '4.0.0', url: DEPRECATION_URL } ); + info() { + deprecate(DEPRECATION_MESSAGE, false, { + id: DEPRECATION_ID, + until: '4.0.0', + url: DEPRECATION_URL + }); return console.info(...arguments); // eslint-disable-line no-console }, @@ -113,7 +131,11 @@ export default { @public */ debug() { - deprecate( DEPRECATION_MESSAGE, false, { id: DEPRECATION_ID, until: '4.0.0', url: DEPRECATION_URL } ); + deprecate(DEPRECATION_MESSAGE, false, { + id: DEPRECATION_ID, + until: '4.0.0', + url: DEPRECATION_URL + }); /* eslint-disable no-console */ if (console.debug) { return console.debug(...arguments); @@ -137,8 +159,12 @@ export default { @param {String} message Assertion message on failed @public */ - assert() { - deprecate( DEPRECATION_MESSAGE, false, { id: DEPRECATION_ID, until: '4.0.0', url: DEPRECATION_URL } ); + assert() { + deprecate(DEPRECATION_MESSAGE, false, { + id: DEPRECATION_ID, + until: '4.0.0', + url: DEPRECATION_URL + }); return console.assert(...arguments); // eslint-disable-line no-console } }; diff --git a/packages/ember-debug/lib/deprecate.js b/packages/ember-debug/lib/deprecate.js index 6362720105a..46a3c91dc99 100644 --- a/packages/ember-debug/lib/deprecate.js +++ b/packages/ember-debug/lib/deprecate.js @@ -50,7 +50,10 @@ import { registerHandler as genericRegisterHandler, invoke } from './handlers'; @since 2.1.0 */ let registerHandler = () => {}; -let missingOptionsDeprecation, missingOptionsIdDeprecation, missingOptionsUntilDeprecation, deprecate; +let missingOptionsDeprecation, + missingOptionsIdDeprecation, + missingOptionsUntilDeprecation, + deprecate; if (DEBUG) { registerHandler = function registerHandler(handler) { @@ -82,7 +85,11 @@ if (DEBUG) { captureErrorForStack = () => new Error(); } else { captureErrorForStack = () => { - try { __fail__.fail(); } catch (e) { return e; } + try { + __fail__.fail(); + } catch (e) { + return e; + } }; } @@ -95,14 +102,18 @@ if (DEBUG) { if (error.stack) { if (error['arguments']) { // Chrome - stack = error.stack.replace(/^\s+at\s+/gm, ''). - replace(/^([^\(]+?)([\n$])/gm, '{anonymous}($1)$2'). - replace(/^Object.\s*\(([^\)]+)\)/gm, '{anonymous}($1)').split('\n'); + stack = error.stack + .replace(/^\s+at\s+/gm, '') + .replace(/^([^\(]+?)([\n$])/gm, '{anonymous}($1)$2') + .replace(/^Object.\s*\(([^\)]+)\)/gm, '{anonymous}($1)') + .split('\n'); stack.shift(); } else { // Firefox - stack = error.stack.replace(/(?:\n@:0)?\s+$/m, ''). - replace(/^\(/gm, '{anonymous}(').split('\n'); + stack = error.stack + .replace(/(?:\n@:0)?\s+$/m, '') + .replace(/^\(/gm, '{anonymous}(') + .split('\n'); } stackStr = `\n ${stack.slice(2).join('\n ')}`; @@ -110,8 +121,8 @@ if (DEBUG) { let updatedMessage = formatMessage(message, options); - console.warn(`DEPRECATION: ${updatedMessage}${stackStr}`); // eslint-disable-line no-console - } else { + console.warn(`DEPRECATION: ${updatedMessage}${stackStr}`); // eslint-disable-line no-console + } else { next(...arguments); } }); @@ -126,11 +137,14 @@ if (DEBUG) { } }); - missingOptionsDeprecation = 'When calling `deprecate` you ' + + missingOptionsDeprecation = + 'When calling `deprecate` you ' + 'must provide an `options` hash as the third parameter. ' + '`options` should include `id` and `until` properties.'; - missingOptionsIdDeprecation = 'When calling `deprecate` you must provide `id` in options.'; - missingOptionsUntilDeprecation = 'When calling `deprecate` you must provide `until` in options.'; + missingOptionsIdDeprecation = + 'When calling `deprecate` you must provide `id` in options.'; + missingOptionsUntilDeprecation = + 'When calling `deprecate` you must provide `until` in options.'; /** @module @ember/application @public @@ -161,45 +175,50 @@ if (DEBUG) { */ deprecate = function deprecate(message, test, options) { if (ENV._ENABLE_DEPRECATION_OPTIONS_SUPPORT !== true) { - assert(missingOptionsDeprecation, options && (options.id || options.until)); + assert( + missingOptionsDeprecation, + options && (options.id || options.until) + ); assert(missingOptionsIdDeprecation, options.id); assert(missingOptionsUntilDeprecation, options.until); } - if ((!options || (!options.id && !options.until)) && ENV._ENABLE_DEPRECATION_OPTIONS_SUPPORT === true) { - deprecate( - missingOptionsDeprecation, - false, - { - id: 'ember-debug.deprecate-options-missing', - until: '3.0.0', - url: 'https://emberjs.com/deprecations/v2.x/#toc_ember-debug-function-options' - } - ); + if ( + (!options || (!options.id && !options.until)) && + ENV._ENABLE_DEPRECATION_OPTIONS_SUPPORT === true + ) { + deprecate(missingOptionsDeprecation, false, { + id: 'ember-debug.deprecate-options-missing', + until: '3.0.0', + url: + 'https://emberjs.com/deprecations/v2.x/#toc_ember-debug-function-options' + }); } - if (options && !options.id && ENV._ENABLE_DEPRECATION_OPTIONS_SUPPORT === true) { - deprecate( - missingOptionsIdDeprecation, - false, - { - id: 'ember-debug.deprecate-id-missing', - until: '3.0.0', - url: 'https://emberjs.com/deprecations/v2.x/#toc_ember-debug-function-options' - } - ); + if ( + options && + !options.id && + ENV._ENABLE_DEPRECATION_OPTIONS_SUPPORT === true + ) { + deprecate(missingOptionsIdDeprecation, false, { + id: 'ember-debug.deprecate-id-missing', + until: '3.0.0', + url: + 'https://emberjs.com/deprecations/v2.x/#toc_ember-debug-function-options' + }); } - if (options && !options.until && ENV._ENABLE_DEPRECATION_OPTIONS_SUPPORT === true) { - deprecate( - missingOptionsUntilDeprecation, - options && options.until, - { - id: 'ember-debug.deprecate-until-missing', - until: '3.0.0', - url: 'https://emberjs.com/deprecations/v2.x/#toc_ember-debug-function-options' - } - ); + if ( + options && + !options.until && + ENV._ENABLE_DEPRECATION_OPTIONS_SUPPORT === true + ) { + deprecate(missingOptionsUntilDeprecation, options && options.until, { + id: 'ember-debug.deprecate-until-missing', + until: '3.0.0', + url: + 'https://emberjs.com/deprecations/v2.x/#toc_ember-debug-function-options' + }); } invoke('deprecate', ...arguments); diff --git a/packages/ember-debug/lib/features.js b/packages/ember-debug/lib/features.js index 771d82f3058..fbc2c40ec57 100644 --- a/packages/ember-debug/lib/features.js +++ b/packages/ember-debug/lib/features.js @@ -41,7 +41,11 @@ let { FEATURES } = FLAGS; export default function isEnabled(feature) { let featureValue = FEATURES[feature]; - if (featureValue === true || featureValue === false || featureValue === undefined) { + if ( + featureValue === true || + featureValue === false || + featureValue === undefined + ) { return featureValue; } else if (ENV.ENABLE_OPTIONAL_FEATURES) { return true; diff --git a/packages/ember-debug/lib/handlers.js b/packages/ember-debug/lib/handlers.js index 12acb8aadab..e56b8002c2c 100644 --- a/packages/ember-debug/lib/handlers.js +++ b/packages/ember-debug/lib/handlers.js @@ -1,13 +1,13 @@ import { DEBUG } from 'ember-env-flags'; -export let HANDLERS = { }; +export let HANDLERS = {}; let registerHandler = () => {}; let invoke = () => {}; if (DEBUG) { registerHandler = function registerHandler(type, callback) { - let nextHandler = HANDLERS[type] || (() => { }); + let nextHandler = HANDLERS[type] || (() => {}); HANDLERS[type] = (message, options) => { callback(message, options, nextHandler); @@ -15,7 +15,9 @@ if (DEBUG) { }; invoke = function invoke(type, message, test, options) { - if (test) { return; } + if (test) { + return; + } let handlerForType = HANDLERS[type]; @@ -25,7 +27,4 @@ if (DEBUG) { }; } -export { - registerHandler, - invoke -}; +export { registerHandler, invoke }; diff --git a/packages/ember-debug/lib/index.js b/packages/ember-debug/lib/index.js index fb40c4f68e6..d51b1d43a76 100644 --- a/packages/ember-debug/lib/index.js +++ b/packages/ember-debug/lib/index.js @@ -28,34 +28,54 @@ let runInDebug = noop; let setDebugFunction = noop; let getDebugFunction = noop; -let deprecateFunc = function() { return arguments[arguments.length - 1]; }; +let deprecateFunc = function() { + return arguments[arguments.length - 1]; +}; if (DEBUG) { setDebugFunction = function(type, callback) { switch (type) { - case 'assert': return assert = callback; - case 'info': return info = callback; - case 'warn': return warn = callback; - case 'debug': return debug = callback; - case 'deprecate': return deprecate = callback; - case 'debugSeal': return debugSeal = callback; - case 'debugFreeze': return debugFreeze = callback; - case 'runInDebug': return runInDebug = callback; - case 'deprecateFunc': return deprecateFunc = callback; + case 'assert': + return (assert = callback); + case 'info': + return (info = callback); + case 'warn': + return (warn = callback); + case 'debug': + return (debug = callback); + case 'deprecate': + return (deprecate = callback); + case 'debugSeal': + return (debugSeal = callback); + case 'debugFreeze': + return (debugFreeze = callback); + case 'runInDebug': + return (runInDebug = callback); + case 'deprecateFunc': + return (deprecateFunc = callback); } }; getDebugFunction = function(type) { switch (type) { - case 'assert': return assert; - case 'info': return info; - case 'warn': return warn; - case 'debug': return debug; - case 'deprecate': return deprecate; - case 'debugSeal': return debugSeal; - case 'debugFreeze': return debugFreeze; - case 'runInDebug': return runInDebug; - case 'deprecateFunc': return deprecateFunc; + case 'assert': + return assert; + case 'info': + return info; + case 'warn': + return warn; + case 'debug': + return debug; + case 'deprecate': + return deprecate; + case 'debugSeal': + return debugSeal; + case 'debugFreeze': + return debugFreeze; + case 'runInDebug': + return runInDebug; + case 'deprecateFunc': + return deprecateFunc; } }; } @@ -131,10 +151,9 @@ if (DEBUG) { } else { console.log(`DEBUG: ${message}`); } - /* eslint-ensable no-console */ + /* eslint-ensable no-console */ }); - /** Display an info notice. @@ -145,7 +164,7 @@ if (DEBUG) { @method info @private */ - setDebugFunction('info', function info() { + setDebugFunction('info', function info() { console.info(...arguments); /* eslint-disable-line no-console */ }); @@ -195,7 +214,6 @@ if (DEBUG) { } }); - /** @module @ember/debug @public @@ -257,9 +275,17 @@ if (DEBUG && !isTesting()) { @method _warnIfUsingStrippedFeatureFlags @return {void} */ - _warnIfUsingStrippedFeatureFlags = function _warnIfUsingStrippedFeatureFlags(FEATURES, knownFeatures, featuresWereStripped) { + _warnIfUsingStrippedFeatureFlags = function _warnIfUsingStrippedFeatureFlags( + FEATURES, + knownFeatures, + featuresWereStripped + ) { if (featuresWereStripped) { - warn('Ember.ENV.ENABLE_OPTIONAL_FEATURES is only available in canary builds.', !ENV.ENABLE_OPTIONAL_FEATURES, { id: 'ember-debug.feature-flag-with-features-stripped' }); + warn( + 'Ember.ENV.ENABLE_OPTIONAL_FEATURES is only available in canary builds.', + !ENV.ENABLE_OPTIONAL_FEATURES, + { id: 'ember-debug.feature-flag-with-features-stripped' } + ); let keys = Object.keys(FEATURES || {}); for (let i = 0; i < keys.length; i++) { @@ -268,7 +294,11 @@ if (DEBUG && !isTesting()) { continue; } - warn(`FEATURE["${key}"] is set as enabled, but FEATURE flags are only available in canary builds.`, !FEATURES[key], { id: 'ember-debug.feature-flag-with-features-stripped' }); + warn( + `FEATURE["${key}"] is set as enabled, but FEATURE flags are only available in canary builds.`, + !FEATURES[key], + { id: 'ember-debug.feature-flag-with-features-stripped' } + ); } } }; @@ -282,26 +312,46 @@ if (DEBUG && !isTesting()) { } delete FEATURES['features-stripped-test']; - _warnIfUsingStrippedFeatureFlags(ENV.FEATURES, DEFAULT_FEATURES, featuresWereStripped); + _warnIfUsingStrippedFeatureFlags( + ENV.FEATURES, + DEFAULT_FEATURES, + featuresWereStripped + ); // Inform the developer about the Ember Inspector if not installed. let isFirefox = environment.isFirefox; let isChrome = environment.isChrome; - if (typeof window !== 'undefined' && (isFirefox || isChrome) && window.addEventListener) { - window.addEventListener('load', () => { - if (document.documentElement && document.documentElement.dataset && !document.documentElement.dataset.emberExtension) { - let downloadURL; - - if (isChrome) { - downloadURL = 'https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi'; - } else if (isFirefox) { - downloadURL = 'https://addons.mozilla.org/en-US/firefox/addon/ember-inspector/'; + if ( + typeof window !== 'undefined' && + (isFirefox || isChrome) && + window.addEventListener + ) { + window.addEventListener( + 'load', + () => { + if ( + document.documentElement && + document.documentElement.dataset && + !document.documentElement.dataset.emberExtension + ) { + let downloadURL; + + if (isChrome) { + downloadURL = + 'https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi'; + } else if (isFirefox) { + downloadURL = + 'https://addons.mozilla.org/en-US/firefox/addon/ember-inspector/'; + } + + debug( + `For more advanced debugging, install the Ember Inspector from ${downloadURL}` + ); } - - debug(`For more advanced debugging, install the Ember Inspector from ${downloadURL}`); - } - }, false); + }, + false + ); } } diff --git a/packages/ember-debug/lib/warn.js b/packages/ember-debug/lib/warn.js index 0bdcc214459..fccbf0fc5c6 100644 --- a/packages/ember-debug/lib/warn.js +++ b/packages/ember-debug/lib/warn.js @@ -51,17 +51,19 @@ if (DEBUG) { registerHandler(function logWarning(message) { /* eslint-disable no-console */ - console.warn(`WARNING: ${message}`); + console.warn(`WARNING: ${message}`); if (console.trace) { console.trace(); - } + } /* eslint-enable no-console */ }); - missingOptionsDeprecation = 'When calling `warn` you ' + + missingOptionsDeprecation = + 'When calling `warn` you ' + 'must provide an `options` hash as the third parameter. ' + '`options` should include an `id` property.'; - missingOptionsIdDeprecation = 'When calling `warn` you must provide `id` in options.'; + missingOptionsIdDeprecation = + 'When calling `warn` you must provide `id` in options.'; /** Display a warning with the provided message. @@ -94,27 +96,21 @@ if (DEBUG) { } if (!options && ENV._ENABLE_WARN_OPTIONS_SUPPORT === true) { - deprecate( - missingOptionsDeprecation, - false, - { - id: 'ember-debug.warn-options-missing', - until: '3.0.0', - url: 'https://emberjs.com/deprecations/v2.x/#toc_ember-debug-function-options' - } - ); + deprecate(missingOptionsDeprecation, false, { + id: 'ember-debug.warn-options-missing', + until: '3.0.0', + url: + 'https://emberjs.com/deprecations/v2.x/#toc_ember-debug-function-options' + }); } if (options && !options.id && ENV._ENABLE_WARN_OPTIONS_SUPPORT === true) { - deprecate( - missingOptionsIdDeprecation, - false, - { - id: 'ember-debug.warn-id-missing', - until: '3.0.0', - url: 'https://emberjs.com/deprecations/v2.x/#toc_ember-debug-function-options' - } - ); + deprecate(missingOptionsIdDeprecation, false, { + id: 'ember-debug.warn-id-missing', + until: '3.0.0', + url: + 'https://emberjs.com/deprecations/v2.x/#toc_ember-debug-function-options' + }); } invoke('warn', message, test, options); diff --git a/packages/ember-debug/tests/error_test.js b/packages/ember-debug/tests/error_test.js index e9a14001b78..becfa4fa359 100644 --- a/packages/ember-debug/tests/error_test.js +++ b/packages/ember-debug/tests/error_test.js @@ -1,17 +1,19 @@ import EmberError from '../error'; -import { - moduleFor, - AbstractTestCase as TestCase -} from 'internal-test-helpers'; +import { moduleFor, AbstractTestCase as TestCase } from 'internal-test-helpers'; -moduleFor('Ember Error Throwing', class extends TestCase { - ['@test new EmberError displays provided message'](assert) { - assert.throws( - () => { - throw new EmberError('A Message'); - }, - function(e) { return e.message === 'A Message'; }, - 'the assigned message was displayed' - ); +moduleFor( + 'Ember Error Throwing', + class extends TestCase { + ['@test new EmberError displays provided message'](assert) { + assert.throws( + () => { + throw new EmberError('A Message'); + }, + function(e) { + return e.message === 'A Message'; + }, + 'the assigned message was displayed' + ); + } } -}); +); diff --git a/packages/ember-debug/tests/handlers-test.js b/packages/ember-debug/tests/handlers-test.js index 44e4f2bcf25..672560597ee 100644 --- a/packages/ember-debug/tests/handlers-test.js +++ b/packages/ember-debug/tests/handlers-test.js @@ -1,149 +1,180 @@ -import { - HANDLERS, - registerHandler, - invoke -} from '../handlers'; -import { - moduleFor, - AbstractTestCase as TestCase -} from 'internal-test-helpers'; - -moduleFor('Ember Error Throwing', class extends TestCase { - teardown() { - delete HANDLERS.blarz; - } - - ['@test calls handler on `invoke` when `falsey`'](assert) { - assert.expect(2); - - function handler(message) { - assert.ok(true, 'called handler'); - assert.equal(message, 'Foo bar'); +import { HANDLERS, registerHandler, invoke } from '../handlers'; +import { moduleFor, AbstractTestCase as TestCase } from 'internal-test-helpers'; + +moduleFor( + 'Ember Error Throwing', + class extends TestCase { + teardown() { + delete HANDLERS.blarz; } - registerHandler('blarz', handler); + ['@test calls handler on `invoke` when `falsey`'](assert) { + assert.expect(2); - invoke('blarz', 'Foo bar', false); - } + function handler(message) { + assert.ok(true, 'called handler'); + assert.equal(message, 'Foo bar'); + } - ['@test does not call handler on `invoke` when `truthy`'](assert) { - assert.expect(0); + registerHandler('blarz', handler); - function handler() { - assert.ok(false, 'called handler'); + invoke('blarz', 'Foo bar', false); } - registerHandler('blarz', handler); - - invoke('blarz', 'Foo bar', true); - } - - ['@test calling `invoke` without handlers does not throw an error'](assert) { - assert.expect(0); + ['@test does not call handler on `invoke` when `truthy`'](assert) { + assert.expect(0); - invoke('blarz', 'Foo bar', false); - } - - ['@test invoking `next` argument calls the next handler'](assert) { - assert.expect(2); + function handler() { + assert.ok(false, 'called handler'); + } - function handler1() { - assert.ok(true, 'called handler1'); - } + registerHandler('blarz', handler); - function handler2(message, options, next) { - assert.ok(true, 'called handler2'); - next(message, options); + invoke('blarz', 'Foo bar', true); } - registerHandler('blarz', handler1); - registerHandler('blarz', handler2); - - invoke('blarz', 'Foo', false); - } - - ['@test invoking `next` when no other handlers exists does not error'](assert) { - assert.expect(1); - - function handler(message, options, next) { - assert.ok(true, 'called handler1'); + ['@test calling `invoke` without handlers does not throw an error']( + assert + ) { + assert.expect(0); - next(message, options); + invoke('blarz', 'Foo bar', false); } - registerHandler('blarz', handler); + ['@test invoking `next` argument calls the next handler'](assert) { + assert.expect(2); - invoke('blarz', 'Foo', false); - } - - ['@test handlers are called in the proper order'](assert) { - assert.expect(11); + function handler1() { + assert.ok(true, 'called handler1'); + } - let expectedMessage = 'This is the message'; - let expectedOptions = { id: 'foo-bar' }; - let expected = ['first', 'second', 'third', 'fourth', 'fifth']; - let actualCalls = []; - - function generateHandler(item) { - return function(message, options, next) { - assert.equal(message, expectedMessage, `message supplied to ${item} handler is correct`); - assert.equal(options, expectedOptions, `options supplied to ${item} handler is correct`); + function handler2(message, options, next) { + assert.ok(true, 'called handler2'); + next(message, options); + } - actualCalls.push(item); + registerHandler('blarz', handler1); + registerHandler('blarz', handler2); - next(message, options); - }; + invoke('blarz', 'Foo', false); } - expected.forEach(item => registerHandler('blarz', generateHandler(item))); + ['@test invoking `next` when no other handlers exists does not error']( + assert + ) { + assert.expect(1); - invoke('blarz', expectedMessage, false, expectedOptions); + function handler(message, options, next) { + assert.ok(true, 'called handler1'); - assert.deepEqual(actualCalls, expected.reverse(), 'handlers were called in proper order'); - } + next(message, options); + } - ['@test not invoking `next` prevents further handlers from being called'](assert) { - assert.expect(1); + registerHandler('blarz', handler); - function handler1() { - assert.ok(false, 'called handler1'); + invoke('blarz', 'Foo', false); } - function handler2() { - assert.ok(true, 'called handler2'); + ['@test handlers are called in the proper order'](assert) { + assert.expect(11); + + let expectedMessage = 'This is the message'; + let expectedOptions = { id: 'foo-bar' }; + let expected = ['first', 'second', 'third', 'fourth', 'fifth']; + let actualCalls = []; + + function generateHandler(item) { + return function(message, options, next) { + assert.equal( + message, + expectedMessage, + `message supplied to ${item} handler is correct` + ); + assert.equal( + options, + expectedOptions, + `options supplied to ${item} handler is correct` + ); + + actualCalls.push(item); + + next(message, options); + }; + } + + expected.forEach(item => registerHandler('blarz', generateHandler(item))); + + invoke('blarz', expectedMessage, false, expectedOptions); + + assert.deepEqual( + actualCalls, + expected.reverse(), + 'handlers were called in proper order' + ); } - registerHandler('blarz', handler1); - registerHandler('blarz', handler2); + ['@test not invoking `next` prevents further handlers from being called']( + assert + ) { + assert.expect(1); + function handler1() { + assert.ok(false, 'called handler1'); + } - invoke('blarz', 'Foo', false); - } - - ['@test handlers can call `next` with custom message and/or options'](assert) { - assert.expect(4); - - let initialMessage = 'initial message'; - let initialOptions = { id: 'initial-options' }; + function handler2() { + assert.ok(true, 'called handler2'); + } - let handler2Message = 'Handler2 Message'; - let handler2Options = { id: 'handler-2' }; + registerHandler('blarz', handler1); + registerHandler('blarz', handler2); - function handler1(message, options) { - assert.equal(message, handler2Message, 'handler2 message provided to handler1'); - assert.equal(options, handler2Options, 'handler2 options provided to handler1'); + invoke('blarz', 'Foo', false); } - function handler2(message, options, next) { - assert.equal(message, initialMessage, 'initial message provided to handler2'); - assert.equal(options, initialOptions, 'initial options proivided to handler2'); - - next(handler2Message, handler2Options); + ['@test handlers can call `next` with custom message and/or options']( + assert + ) { + assert.expect(4); + + let initialMessage = 'initial message'; + let initialOptions = { id: 'initial-options' }; + + let handler2Message = 'Handler2 Message'; + let handler2Options = { id: 'handler-2' }; + + function handler1(message, options) { + assert.equal( + message, + handler2Message, + 'handler2 message provided to handler1' + ); + assert.equal( + options, + handler2Options, + 'handler2 options provided to handler1' + ); + } + + function handler2(message, options, next) { + assert.equal( + message, + initialMessage, + 'initial message provided to handler2' + ); + assert.equal( + options, + initialOptions, + 'initial options proivided to handler2' + ); + + next(handler2Message, handler2Options); + } + + registerHandler('blarz', handler1); + registerHandler('blarz', handler2); + + invoke('blarz', initialMessage, false, initialOptions); } - - registerHandler('blarz', handler1); - registerHandler('blarz', handler2); - - invoke('blarz', initialMessage, false, initialOptions); } -}); +); diff --git a/packages/ember-debug/tests/main_test.js b/packages/ember-debug/tests/main_test.js index febdb7558ba..14be17fc65a 100644 --- a/packages/ember-debug/tests/main_test.js +++ b/packages/ember-debug/tests/main_test.js @@ -14,16 +14,9 @@ import { registerHandler as registerWarnHandler } from '../warn'; -import { - deprecate, - warn, - assert as emberAssert -} from '../index'; +import { deprecate, warn, assert as emberAssert } from '../index'; -import { - moduleFor, - AbstractTestCase as TestCase -} from 'internal-test-helpers'; +import { moduleFor, AbstractTestCase as TestCase } from 'internal-test-helpers'; let originalEnvValue; let originalDeprecateHandler; @@ -31,384 +24,461 @@ let originalWarnHandler; let originalWarnOptions; let originalDeprecationOptions; const originalConsoleWarn = console.warn; // eslint-disable-line no-console -const noop = function(){}; - -moduleFor('ember-debug', class extends TestCase { - - constructor() { - super(); - - originalEnvValue = ENV.RAISE_ON_DEPRECATION; - originalDeprecateHandler = HANDLERS.deprecate; - originalWarnHandler = HANDLERS.warn; - originalWarnOptions = ENV._ENABLE_WARN_OPTIONS_SUPPORT; - originalDeprecationOptions = ENV._ENABLE_DEPRECATION_OPTIONS_SUPPORT; - - ENV.RAISE_ON_DEPRECATION = true; - ENV._ENABLE_DEPRECATION_OPTIONS_SUPPORT = true; - } +const noop = function() {}; + +moduleFor( + 'ember-debug', + class extends TestCase { + constructor() { + super(); + + originalEnvValue = ENV.RAISE_ON_DEPRECATION; + originalDeprecateHandler = HANDLERS.deprecate; + originalWarnHandler = HANDLERS.warn; + originalWarnOptions = ENV._ENABLE_WARN_OPTIONS_SUPPORT; + originalDeprecationOptions = ENV._ENABLE_DEPRECATION_OPTIONS_SUPPORT; + + ENV.RAISE_ON_DEPRECATION = true; + ENV._ENABLE_DEPRECATION_OPTIONS_SUPPORT = true; + } - teardown() { - HANDLERS.deprecate = originalDeprecateHandler; - HANDLERS.warn = originalWarnHandler; + teardown() { + HANDLERS.deprecate = originalDeprecateHandler; + HANDLERS.warn = originalWarnHandler; - ENV.RAISE_ON_DEPRECATION = originalEnvValue; - ENV._ENABLE_WARN_OPTIONS_SUPPORT = originalWarnOptions; - ENV._ENABLE_DEPRECATION_OPTIONS_SUPPORT = originalDeprecationOptions; - } - - afterEach() { - console.warn = originalConsoleWarn; // eslint-disable-line no-console - } - - ['@test deprecate does not throw if RAISE_ON_DEPRECATION is false'](assert) { - assert.expect(1); - console.warn = noop; // eslint-disable-line no-console + ENV.RAISE_ON_DEPRECATION = originalEnvValue; + ENV._ENABLE_WARN_OPTIONS_SUPPORT = originalWarnOptions; + ENV._ENABLE_DEPRECATION_OPTIONS_SUPPORT = originalDeprecationOptions; + } - ENV.RAISE_ON_DEPRECATION = false; + afterEach() { + console.warn = originalConsoleWarn; // eslint-disable-line no-console + } - try { - deprecate('Should not throw', false, { id: 'test', until: 'forever' }); - assert.ok(true, 'deprecate did not throw'); - } catch (e) { - assert.ok(false, `Expected deprecate not to throw but it did: ${e.message}`); + ['@test deprecate does not throw if RAISE_ON_DEPRECATION is false']( + assert + ) { + assert.expect(1); + console.warn = noop; // eslint-disable-line no-console + + ENV.RAISE_ON_DEPRECATION = false; + + try { + deprecate('Should not throw', false, { id: 'test', until: 'forever' }); + assert.ok(true, 'deprecate did not throw'); + } catch (e) { + assert.ok( + false, + `Expected deprecate not to throw but it did: ${e.message}` + ); + } } - } - ['@test deprecate resets deprecation level to RAISE if ENV.RAISE_ON_DEPRECATION is set'](assert) { - assert.expect(2); - console.warn = noop; // eslint-disable-line no-console + ['@test deprecate resets deprecation level to RAISE if ENV.RAISE_ON_DEPRECATION is set']( + assert + ) { + assert.expect(2); + console.warn = noop; // eslint-disable-line no-console + + ENV.RAISE_ON_DEPRECATION = false; + + try { + deprecate('Should not throw', false, { id: 'test', until: 'forever' }); + assert.ok(true, 'deprecate did not throw'); + } catch (e) { + assert.ok( + false, + `Expected deprecate not to throw but it did: ${e.message}` + ); + } - ENV.RAISE_ON_DEPRECATION = false; + ENV.RAISE_ON_DEPRECATION = true; - try { - deprecate('Should not throw', false, { id: 'test', until: 'forever' }); - assert.ok(true, 'deprecate did not throw'); - } catch (e) { - assert.ok(false, `Expected deprecate not to throw but it did: ${e.message}`); + assert.throws(() => { + deprecate('Should throw', false, { id: 'test', until: 'forever' }); + }, /Should throw/); } - ENV.RAISE_ON_DEPRECATION = true; - - assert.throws(() => { - deprecate('Should throw', false, { id: 'test', until: 'forever' }); - }, /Should throw/); - } + ['@test When ENV.RAISE_ON_DEPRECATION is true, it is still possible to silence a deprecation by id']( + assert + ) { + assert.expect(3); - ['@test When ENV.RAISE_ON_DEPRECATION is true, it is still possible to silence a deprecation by id'](assert) { - assert.expect(3); - - ENV.RAISE_ON_DEPRECATION = true; - registerHandler(function(message, options, next) { - if (!options || options.id !== 'my-deprecation') { - next(...arguments); + ENV.RAISE_ON_DEPRECATION = true; + registerHandler(function(message, options, next) { + if (!options || options.id !== 'my-deprecation') { + next(...arguments); + } + }); + + try { + deprecate('should be silenced with matching id', false, { + id: 'my-deprecation', + until: 'forever' + }); + assert.ok(true, 'Did not throw when level is set by id'); + } catch (e) { + assert.ok( + false, + `Expected deprecate not to throw but it did: ${e.message}` + ); } - }); - try { - deprecate('should be silenced with matching id', false, { id: 'my-deprecation', until: 'forever' }); - assert.ok(true, 'Did not throw when level is set by id'); - } catch (e) { - assert.ok(false, `Expected deprecate not to throw but it did: ${e.message}`); + assert.throws(() => { + deprecate('Should throw with no matching id', false, { + id: 'test', + until: 'forever' + }); + }, /Should throw with no matching id/); + + assert.throws(() => { + deprecate('Should throw with non-matching id', false, { + id: 'other-id', + until: 'forever' + }); + }, /Should throw with non-matching id/); } - assert.throws(() => { - deprecate('Should throw with no matching id', false, { id: 'test', until: 'forever' }); - }, /Should throw with no matching id/); + ['@test deprecate throws deprecation if second argument is falsy'](assert) { + assert.expect(3); + + assert.throws(() => + deprecate('Deprecation is thrown', false, { + id: 'test', + until: 'forever' + }) + ); + assert.throws(() => + deprecate('Deprecation is thrown', '', { id: 'test', until: 'forever' }) + ); + assert.throws(() => + deprecate('Deprecation is thrown', 0, { id: 'test', until: 'forever' }) + ); + } - assert.throws(() => { - deprecate('Should throw with non-matching id', false, { id: 'other-id', until: 'forever' }); - }, /Should throw with non-matching id/); - } + ['@test deprecate does not invoke a function as the second argument']( + assert + ) { + assert.expect(1); - ['@test deprecate throws deprecation if second argument is falsy'](assert) { - assert.expect(3); + deprecate( + 'Deprecation is thrown', + function() { + assert.ok(false, 'this function should not be invoked'); + }, + { id: 'test', until: 'forever' } + ); - assert.throws(() => deprecate('Deprecation is thrown', false, { id: 'test', until: 'forever' })); - assert.throws(() => deprecate('Deprecation is thrown', '', { id: 'test', until: 'forever' })); - assert.throws(() => deprecate('Deprecation is thrown', 0, { id: 'test', until: 'forever' })); - } + assert.ok(true, 'deprecations were not thrown'); + } - ['@test deprecate does not invoke a function as the second argument'](assert) { - assert.expect(1); + ['@test deprecate does not throw deprecations if second argument is truthy']( + assert + ) { + assert.expect(1); - deprecate('Deprecation is thrown', function() { - assert.ok(false, 'this function should not be invoked'); - }, { id: 'test', until: 'forever' }); + deprecate('Deprecation is thrown', true, { + id: 'test', + until: 'forever' + }); + deprecate('Deprecation is thrown', '1', { id: 'test', until: 'forever' }); + deprecate('Deprecation is thrown', 1, { id: 'test', until: 'forever' }); - assert.ok(true, 'deprecations were not thrown'); - } + assert.ok(true, 'deprecations were not thrown'); + } - ['@test deprecate does not throw deprecations if second argument is truthy'](assert) { - assert.expect(1); + ['@test assert throws if second argument is falsy'](assert) { + assert.expect(3); - deprecate('Deprecation is thrown', true, { id: 'test', until: 'forever' }); - deprecate('Deprecation is thrown', '1', { id: 'test', until: 'forever' }); - deprecate('Deprecation is thrown', 1, { id: 'test', until: 'forever' }); + assert.throws(() => emberAssert('Assertion is thrown', false)); + assert.throws(() => emberAssert('Assertion is thrown', '')); + assert.throws(() => emberAssert('Assertion is thrown', 0)); + } - assert.ok(true, 'deprecations were not thrown'); - } + ['@test assert does not throw if second argument is a function'](assert) { + assert.expect(1); - ['@test assert throws if second argument is falsy'](assert) { - assert.expect(3); + emberAssert('Assertion is thrown', () => true); - assert.throws(() => emberAssert('Assertion is thrown', false)); - assert.throws(() => emberAssert('Assertion is thrown', '')); - assert.throws(() => emberAssert('Assertion is thrown', 0)); - } + assert.ok(true, 'assertions were not thrown'); + } - ['@test assert does not throw if second argument is a function'](assert) { - assert.expect(1); + ['@test assert does not throw if second argument is falsy'](assert) { + assert.expect(1); - emberAssert('Assertion is thrown', () => true); + emberAssert('Assertion is thrown', true); + emberAssert('Assertion is thrown', '1'); + emberAssert('Assertion is thrown', 1); - assert.ok(true, 'assertions were not thrown'); - } + assert.ok(true, 'assertions were not thrown'); + } - ['@test assert does not throw if second argument is falsy'](assert) { - assert.expect(1); + ['@test assert does not throw if second argument is an object'](assert) { + assert.expect(1); + let Igor = EmberObject.extend(); - emberAssert('Assertion is thrown', true); - emberAssert('Assertion is thrown', '1'); - emberAssert('Assertion is thrown', 1); + emberAssert('is truthy', Igor); + emberAssert('is truthy', Igor.create()); - assert.ok(true, 'assertions were not thrown'); - } + assert.ok(true, 'assertions were not thrown'); + } - ['@test assert does not throw if second argument is an object'](assert) { - assert.expect(1); - let Igor = EmberObject.extend(); + ['@test deprecate does not throw a deprecation at log and silence']( + assert + ) { + assert.expect(4); + let id = 'ABC'; + let until = 'forever'; + let shouldThrow = false; + + registerHandler(function(message, options) { + if (options && options.id === id) { + if (shouldThrow) { + throw new Error(message); + } + } + }); + + try { + deprecate('Deprecation for testing purposes', false, { id, until }); + assert.ok(true, 'Deprecation did not throw'); + } catch (e) { + assert.ok( + false, + 'Deprecation was thrown despite being added to blacklist' + ); + } - emberAssert('is truthy', Igor); - emberAssert('is truthy', Igor.create()); + try { + deprecate('Deprecation for testing purposes', false, { id, until }); + assert.ok(true, 'Deprecation did not throw'); + } catch (e) { + assert.ok( + false, + 'Deprecation was thrown despite being added to blacklist' + ); + } - assert.ok(true, 'assertions were not thrown'); - } + shouldThrow = true; + assert.throws(function() { + deprecate('Deprecation is thrown', false, { id, until }); + }); - ['@test deprecate does not throw a deprecation at log and silence'](assert) { - assert.expect(4); - let id = 'ABC'; - let until = 'forever'; - let shouldThrow = false; + assert.throws(function() { + deprecate('Deprecation is thrown', false, { id, until }); + }); + } - registerHandler(function(message, options) { - if (options && options.id === id) { - if (shouldThrow) { - throw new Error(message); + ['@test deprecate without options triggers a deprecation'](assert) { + assert.expect(4); + + registerHandler(function(message) { + if (message === missingOptionsDeprecation) { + assert.ok( + true, + 'proper deprecation is triggered when options is missing' + ); + } else if (message === 'foo') { + assert.ok(true, 'original deprecation is still triggered'); } - } - }); + }); - try { - deprecate('Deprecation for testing purposes', false, { id, until }); - assert.ok(true, 'Deprecation did not throw'); - } catch (e) { - assert.ok(false, 'Deprecation was thrown despite being added to blacklist'); + deprecate('foo'); + deprecate('foo', false, {}); } - try { - deprecate('Deprecation for testing purposes', false, { id, until }); - assert.ok(true, 'Deprecation did not throw'); - } catch (e) { - assert.ok(false, 'Deprecation was thrown despite being added to blacklist'); + ['@test deprecate without options triggers an assertion'](assert) { + assert.expect(2); + ENV._ENABLE_DEPRECATION_OPTIONS_SUPPORT = false; + + assert.throws( + () => deprecate('foo'), + new RegExp(missingOptionsDeprecation), + 'proper assertion is triggered when options is missing' + ); + + assert.throws( + () => deprecate('foo', false, {}), + new RegExp(missingOptionsDeprecation), + 'proper assertion is triggered when options is missing' + ); } - shouldThrow = true; - - assert.throws(function() { - deprecate('Deprecation is thrown', false, { id, until }); - }); - - assert.throws(function() { - deprecate('Deprecation is thrown', false, { id, until }); - }); - } - - ['@test deprecate without options triggers a deprecation'](assert) { - assert.expect(4); - - registerHandler(function(message) { - if (message === missingOptionsDeprecation) { - assert.ok(true, 'proper deprecation is triggered when options is missing'); - } else if (message === 'foo') { - assert.ok(true, 'original deprecation is still triggered'); - } - }); - - deprecate('foo'); - deprecate('foo', false, { }); - } - - ['@test deprecate without options triggers an assertion'](assert) { - assert.expect(2); - ENV._ENABLE_DEPRECATION_OPTIONS_SUPPORT = false; - - assert.throws( - () => deprecate('foo'), - new RegExp(missingOptionsDeprecation), - 'proper assertion is triggered when options is missing' - ); - - assert.throws( - () => deprecate('foo', false, { }), - new RegExp(missingOptionsDeprecation), - 'proper assertion is triggered when options is missing' - ); - } - - - ['@test deprecate without options.id triggers a deprecation'](assert) { - assert.expect(2); - - registerHandler(function(message) { - if (message === missingOptionsIdDeprecation) { - assert.ok(true, 'proper deprecation is triggered when options.id is missing'); - } else if (message === 'foo') { - assert.ok(true, 'original deprecation is still triggered'); - } - }); - - deprecate('foo', false, { until: 'forever' }); - } + ['@test deprecate without options.id triggers a deprecation'](assert) { + assert.expect(2); + + registerHandler(function(message) { + if (message === missingOptionsIdDeprecation) { + assert.ok( + true, + 'proper deprecation is triggered when options.id is missing' + ); + } else if (message === 'foo') { + assert.ok(true, 'original deprecation is still triggered'); + } + }); - ['@test deprecate without options.id triggers an assertion'](assert) { - assert.expect(1); - ENV._ENABLE_DEPRECATION_OPTIONS_SUPPORT = false; + deprecate('foo', false, { until: 'forever' }); + } - assert.throws( - () => deprecate('foo', false, { until: 'forever' }), - new RegExp(missingOptionsIdDeprecation), - 'proper assertion is triggered when options.id is missing' - ); - } + ['@test deprecate without options.id triggers an assertion'](assert) { + assert.expect(1); + ENV._ENABLE_DEPRECATION_OPTIONS_SUPPORT = false; - ['@test deprecate without options.until triggers a deprecation'](assert) { - assert.expect(2); + assert.throws( + () => deprecate('foo', false, { until: 'forever' }), + new RegExp(missingOptionsIdDeprecation), + 'proper assertion is triggered when options.id is missing' + ); + } - registerHandler(function(message) { - if (message === missingOptionsUntilDeprecation) { - assert.ok(true, 'proper deprecation is triggered when options.until is missing'); - } else if (message === 'foo') { - assert.ok(true, 'original deprecation is still triggered'); - } - }); + ['@test deprecate without options.until triggers a deprecation'](assert) { + assert.expect(2); + + registerHandler(function(message) { + if (message === missingOptionsUntilDeprecation) { + assert.ok( + true, + 'proper deprecation is triggered when options.until is missing' + ); + } else if (message === 'foo') { + assert.ok(true, 'original deprecation is still triggered'); + } + }); - deprecate('foo', false, { id: 'test' }); - } + deprecate('foo', false, { id: 'test' }); + } - ['@test deprecate without options.until triggers an assertion'](assert) { - assert.expect(1); - ENV._ENABLE_DEPRECATION_OPTIONS_SUPPORT = false; + ['@test deprecate without options.until triggers an assertion'](assert) { + assert.expect(1); + ENV._ENABLE_DEPRECATION_OPTIONS_SUPPORT = false; - assert.throws( - () => deprecate('foo', false, { id: 'test' }), - new RegExp(missingOptionsUntilDeprecation), - 'proper assertion is triggered when options.until is missing' - ); - } + assert.throws( + () => deprecate('foo', false, { id: 'test' }), + new RegExp(missingOptionsUntilDeprecation), + 'proper assertion is triggered when options.until is missing' + ); + } - ['@test warn without options triggers a deprecation'](assert) { - assert.expect(2); + ['@test warn without options triggers a deprecation'](assert) { + assert.expect(2); - ENV._ENABLE_WARN_OPTIONS_SUPPORT = true; + ENV._ENABLE_WARN_OPTIONS_SUPPORT = true; - registerHandler(function(message) { - assert.equal(message, missingWarnOptionsDeprecation, 'deprecation is triggered when options is missing'); - }); + registerHandler(function(message) { + assert.equal( + message, + missingWarnOptionsDeprecation, + 'deprecation is triggered when options is missing' + ); + }); - registerWarnHandler(function(message) { - assert.equal(message, 'foo', 'original warning is triggered'); - }); + registerWarnHandler(function(message) { + assert.equal(message, 'foo', 'original warning is triggered'); + }); - warn('foo'); - } + warn('foo'); + } - ['@test warn without options triggers an assert'](assert) { - assert.expect(1); + ['@test warn without options triggers an assert'](assert) { + assert.expect(1); - assert.throws( - () => warn('foo'), - new RegExp(missingWarnOptionsDeprecation), - 'deprecation is triggered when options is missing' - ); - } + assert.throws( + () => warn('foo'), + new RegExp(missingWarnOptionsDeprecation), + 'deprecation is triggered when options is missing' + ); + } - ['@test warn without options.id triggers a deprecation'](assert) { - assert.expect(2); + ['@test warn without options.id triggers a deprecation'](assert) { + assert.expect(2); - ENV._ENABLE_WARN_OPTIONS_SUPPORT = true; + ENV._ENABLE_WARN_OPTIONS_SUPPORT = true; - registerHandler(function(message) { - assert.equal(message, missingWarnOptionsIdDeprecation, 'deprecation is triggered when options is missing'); - }); + registerHandler(function(message) { + assert.equal( + message, + missingWarnOptionsIdDeprecation, + 'deprecation is triggered when options is missing' + ); + }); - registerWarnHandler(function(message) { - assert.equal(message, 'foo', 'original warning is triggered'); - }); + registerWarnHandler(function(message) { + assert.equal(message, 'foo', 'original warning is triggered'); + }); - warn('foo', false, { }); - } + warn('foo', false, {}); + } - ['@test warn without options.id triggers an assertion'](assert) { - assert.expect(1); + ['@test warn without options.id triggers an assertion'](assert) { + assert.expect(1); - assert.throws( - () => warn('foo', false, { }), - new RegExp(missingWarnOptionsIdDeprecation), - 'deprecation is triggered when options is missing' - ); - } + assert.throws( + () => warn('foo', false, {}), + new RegExp(missingWarnOptionsIdDeprecation), + 'deprecation is triggered when options is missing' + ); + } - ['@test warn without options.id nor test triggers a deprecation'](assert) { - assert.expect(2); + ['@test warn without options.id nor test triggers a deprecation'](assert) { + assert.expect(2); - ENV._ENABLE_WARN_OPTIONS_SUPPORT = true; + ENV._ENABLE_WARN_OPTIONS_SUPPORT = true; - registerHandler(function(message) { - assert.equal(message, missingWarnOptionsIdDeprecation, 'deprecation is triggered when options is missing'); - }); + registerHandler(function(message) { + assert.equal( + message, + missingWarnOptionsIdDeprecation, + 'deprecation is triggered when options is missing' + ); + }); - registerWarnHandler(function(message) { - assert.equal(message, 'foo', 'original warning is triggered'); - }); + registerWarnHandler(function(message) { + assert.equal(message, 'foo', 'original warning is triggered'); + }); - warn('foo', { }); - } + warn('foo', {}); + } - ['@test warn without options.id nor test triggers an assertion'](assert) { - assert.expect(1); + ['@test warn without options.id nor test triggers an assertion'](assert) { + assert.expect(1); - assert.throws( - () => warn('foo', { }), - new RegExp(missingWarnOptionsIdDeprecation), - 'deprecation is triggered when options is missing' - ); - } + assert.throws( + () => warn('foo', {}), + new RegExp(missingWarnOptionsIdDeprecation), + 'deprecation is triggered when options is missing' + ); + } - ['@test warn without test but with options does not trigger a deprecation'](assert) { - assert.expect(1); + ['@test warn without test but with options does not trigger a deprecation']( + assert + ) { + assert.expect(1); - ENV._ENABLE_WARN_OPTIONS_SUPPORT = true; + ENV._ENABLE_WARN_OPTIONS_SUPPORT = true; - registerHandler(function(message) { - assert.ok(false, `there should be no deprecation ${message}`); - }); + registerHandler(function(message) { + assert.ok(false, `there should be no deprecation ${message}`); + }); - registerWarnHandler(function(message) { - assert.equal(message, 'foo', 'warning was triggered'); - }); + registerWarnHandler(function(message) { + assert.equal(message, 'foo', 'warning was triggered'); + }); - warn('foo', { id: 'ember-debug.do-not-raise' }); - } + warn('foo', { id: 'ember-debug.do-not-raise' }); + } - ['@test warn without test but with options does not trigger an assertion'](assert) { - assert.expect(1); + ['@test warn without test but with options does not trigger an assertion']( + assert + ) { + assert.expect(1); - registerWarnHandler(function(message) { - assert.equal(message, 'foo', 'warning was triggered'); - }); + registerWarnHandler(function(message) { + assert.equal(message, 'foo', 'warning was triggered'); + }); - warn('foo', { id: 'ember-debug.do-not-raise' }); + warn('foo', { id: 'ember-debug.do-not-raise' }); + } } -}); +); diff --git a/packages/ember-debug/tests/warn_if_using_stripped_feature_flags_test.js b/packages/ember-debug/tests/warn_if_using_stripped_feature_flags_test.js index 9c2ca00d829..013b8d1dab1 100644 --- a/packages/ember-debug/tests/warn_if_using_stripped_feature_flags_test.js +++ b/packages/ember-debug/tests/warn_if_using_stripped_feature_flags_test.js @@ -1,12 +1,14 @@ import { ENV } from 'ember-environment'; import { getDebugFunction, setDebugFunction } from 'ember-debug'; import { _warnIfUsingStrippedFeatureFlags } from '../index'; -import { - moduleFor, - AbstractTestCase as TestCase -} from 'internal-test-helpers'; +import { moduleFor, AbstractTestCase as TestCase } from 'internal-test-helpers'; -let oldWarn, oldRunInDebug, origEnvFeatures, origEnableOptional, features, knownFeatures; +let oldWarn, + oldRunInDebug, + origEnvFeatures, + origEnableOptional, + features, + knownFeatures; function confirmWarns(assert, expectedMsg) { let featuresWereStripped = true; @@ -17,80 +19,106 @@ function confirmWarns(assert, expectedMsg) { } }); - setDebugFunction('runInDebug', function (func) { + setDebugFunction('runInDebug', function(func) { func(); }); // Should trigger our 1 warning - _warnIfUsingStrippedFeatureFlags(features, knownFeatures, featuresWereStripped); + _warnIfUsingStrippedFeatureFlags( + features, + knownFeatures, + featuresWereStripped + ); // Shouldn't trigger any warnings now that we're "in canary" featuresWereStripped = false; - _warnIfUsingStrippedFeatureFlags(features, knownFeatures, featuresWereStripped); + _warnIfUsingStrippedFeatureFlags( + features, + knownFeatures, + featuresWereStripped + ); } -moduleFor('ember-debug - _warnIfUsingStrippedFeatureFlags', class extends TestCase { - constructor() { - super(); - - oldWarn = getDebugFunction('warn'); - oldRunInDebug = getDebugFunction('runInDebug'); - origEnvFeatures = ENV.FEATURES; - origEnableOptional = ENV.ENABLE_OPTIONAL_FEATURES; - - knownFeatures = { - 'fred': null, - 'barney': null, - 'wilma': null - }; - } - - teardown() { - setDebugFunction('warn', oldWarn); - setDebugFunction('runInDebug', oldRunInDebug); - ENV.FEATURES = origEnvFeatures; - ENV.ENABLE_OPTIONAL_FEATURES = origEnableOptional; - } +moduleFor( + 'ember-debug - _warnIfUsingStrippedFeatureFlags', + class extends TestCase { + constructor() { + super(); + + oldWarn = getDebugFunction('warn'); + oldRunInDebug = getDebugFunction('runInDebug'); + origEnvFeatures = ENV.FEATURES; + origEnableOptional = ENV.ENABLE_OPTIONAL_FEATURES; + + knownFeatures = { + fred: null, + barney: null, + wilma: null + }; + } - ['@test Setting Ember.ENV.ENABLE_OPTIONAL_FEATURES truthy in non-canary, debug build causes a warning'](assert) { - assert.expect(1); + teardown() { + setDebugFunction('warn', oldWarn); + setDebugFunction('runInDebug', oldRunInDebug); + ENV.FEATURES = origEnvFeatures; + ENV.ENABLE_OPTIONAL_FEATURES = origEnableOptional; + } - ENV.ENABLE_OPTIONAL_FEATURES = true; - features = {}; + ['@test Setting Ember.ENV.ENABLE_OPTIONAL_FEATURES truthy in non-canary, debug build causes a warning']( + assert + ) { + assert.expect(1); - confirmWarns(assert, 'Ember.ENV.ENABLE_OPTIONAL_FEATURES is only available in canary builds.'); - } + ENV.ENABLE_OPTIONAL_FEATURES = true; + features = {}; - ['@test Enabling a known FEATURE flag in non-canary, debug build causes a warning'](assert) { - assert.expect(1); - - ENV.ENABLE_OPTIONAL_FEATURES = false; - features = { - 'fred': true, - 'barney': false, - 'wilma': null - }; + confirmWarns( + assert, + 'Ember.ENV.ENABLE_OPTIONAL_FEATURES is only available in canary builds.' + ); + } - confirmWarns(assert, 'FEATURE["fred"] is set as enabled, but FEATURE flags are only available in canary builds.'); - } + ['@test Enabling a known FEATURE flag in non-canary, debug build causes a warning']( + assert + ) { + assert.expect(1); + + ENV.ENABLE_OPTIONAL_FEATURES = false; + features = { + fred: true, + barney: false, + wilma: null + }; + + confirmWarns( + assert, + 'FEATURE["fred"] is set as enabled, but FEATURE flags are only available in canary builds.' + ); + } - ['@test Enabling an unknown FEATURE flag in non-canary debug build does not cause a warning'](assert) { - assert.expect(0); + ['@test Enabling an unknown FEATURE flag in non-canary debug build does not cause a warning']( + assert + ) { + assert.expect(0); - ENV.ENABLE_OPTIONAL_FEATURES = false; - features = { - 'some-ember-data-feature-flag': true - }; + ENV.ENABLE_OPTIONAL_FEATURES = false; + features = { + 'some-ember-data-feature-flag': true + }; - confirmWarns(assert, 'FEATURE["fred"] is set as enabled, but FEATURE flags are only available in canary builds.'); - } + confirmWarns( + assert, + 'FEATURE["fred"] is set as enabled, but FEATURE flags are only available in canary builds.' + ); + } - ['@test `ENV.FEATURES` being undefined does not cause an error'](assert) { - assert.expect(0); + ['@test `ENV.FEATURES` being undefined does not cause an error'](assert) { + assert.expect(0); - ENV.ENABLE_OPTIONAL_FEATURES = false; - features = undefined; + ENV.ENABLE_OPTIONAL_FEATURES = false; + features = undefined; - confirmWarns(assert); + confirmWarns(assert); + } } -}); +); diff --git a/packages/ember-environment/lib/global.js b/packages/ember-environment/lib/global.js index 5ed0902ab6e..2e86af95ad1 100644 --- a/packages/ember-environment/lib/global.js +++ b/packages/ember-environment/lib/global.js @@ -2,17 +2,19 @@ // from lodash to catch fake globals function checkGlobal(value) { - return (value && value.Object === Object) ? value : undefined; + return value && value.Object === Object ? value : undefined; } // element ids can ruin global miss checks function checkElementIdShadowing(value) { - return (value && value.nodeType === undefined) ? value : undefined; + return value && value.nodeType === undefined ? value : undefined; } // export real global -export default checkGlobal(checkElementIdShadowing(typeof global === 'object' && global)) || - checkGlobal(typeof self === 'object' && self) || - checkGlobal(typeof window === 'object' && window) || - mainContext || // set before strict mode in Ember loader/wrapper - new Function('return this')(); // eval outside of strict mode +export default checkGlobal( + checkElementIdShadowing(typeof global === 'object' && global) +) || +checkGlobal(typeof self === 'object' && self) || +checkGlobal(typeof window === 'object' && window) || +mainContext || // set before strict mode in Ember loader/wrapper + new Function('return this')(); // eval outside of strict mode diff --git a/packages/ember-environment/lib/index.js b/packages/ember-environment/lib/index.js index 6e317eaed03..b00f72c51bd 100644 --- a/packages/ember-environment/lib/index.js +++ b/packages/ember-environment/lib/index.js @@ -11,8 +11,10 @@ import { defaultFalse, defaultTrue, normalizeExtendPrototypes } from './utils'; @type Object @public */ -export const ENV = (typeof global.EmberENV === 'object' && global.EmberENV) || - (typeof global.ENV === 'object' && global.ENV) || {}; +export const ENV = + (typeof global.EmberENV === 'object' && global.EmberENV) || + (typeof global.ENV === 'object' && global.ENV) || + {}; // ENABLE_ALL_FEATURES was documented, but you can't actually enable non optional features. if (ENV.ENABLE_ALL_FEATURES) { @@ -50,7 +52,9 @@ ENV.EXTEND_PROTOTYPES = normalizeExtendPrototypes(ENV.EXTEND_PROTOTYPES); @for EmberENV @public */ -ENV.LOG_STACKTRACE_ON_DEPRECATION = defaultTrue(ENV.LOG_STACKTRACE_ON_DEPRECATION); +ENV.LOG_STACKTRACE_ON_DEPRECATION = defaultTrue( + ENV.LOG_STACKTRACE_ON_DEPRECATION +); /** The `LOG_VERSION` property, when true, tells Ember to log versions of all @@ -92,7 +96,9 @@ ENV.RAISE_ON_DEPRECATION = defaultFalse(ENV.RAISE_ON_DEPRECATION); @default true @private */ -ENV._APPLICATION_TEMPLATE_WRAPPER = defaultTrue(ENV._APPLICATION_TEMPLATE_WRAPPER); +ENV._APPLICATION_TEMPLATE_WRAPPER = defaultTrue( + ENV._APPLICATION_TEMPLATE_WRAPPER +); /** Whether to use Glimmer Component semantics (as opposed to the classic "Curly" @@ -107,12 +113,17 @@ ENV._APPLICATION_TEMPLATE_WRAPPER = defaultTrue(ENV._APPLICATION_TEMPLATE_WRAPPE @default false @private */ -ENV._TEMPLATE_ONLY_GLIMMER_COMPONENTS = defaultFalse(ENV._TEMPLATE_ONLY_GLIMMER_COMPONENTS); +ENV._TEMPLATE_ONLY_GLIMMER_COMPONENTS = defaultFalse( + ENV._TEMPLATE_ONLY_GLIMMER_COMPONENTS +); // check if window exists and actually is the global -const hasDOM = typeof window !== 'undefined' && window === global && - window.document && window.document.createElement && - !ENV.disableBrowserEnvironment; // is this a public thing? +const hasDOM = + typeof window !== 'undefined' && + window === global && + window.document && + window.document.createElement && + !ENV.disableBrowserEnvironment; // is this a public thing? // legacy imports/exports/lookup stuff (should we keep this??) const originalContext = global.Ember || {}; @@ -127,20 +138,22 @@ export const context = { }; // TODO: cleanup single source of truth issues with this stuff -export const environment = hasDOM ? { - hasDOM: true, - isChrome: !!window.chrome && !window.opera, - isFirefox: typeof InstallTrigger !== 'undefined', - location: window.location, - history: window.history, - userAgent: window.navigator.userAgent, - window -} : { - hasDOM: false, - isChrome: false, - isFirefox: false, - location: null, - history: null, - userAgent: 'Lynx (textmode)', - window: null -}; +export const environment = hasDOM + ? { + hasDOM: true, + isChrome: !!window.chrome && !window.opera, + isFirefox: typeof InstallTrigger !== 'undefined', + location: window.location, + history: window.history, + userAgent: window.navigator.userAgent, + window + } + : { + hasDOM: false, + isChrome: false, + isFirefox: false, + location: null, + history: null, + userAgent: 'Lynx (textmode)', + window: null + }; diff --git a/packages/ember-extension-support/lib/data_adapter.js b/packages/ember-extension-support/lib/data_adapter.js index f7be80bb9f3..9882b278490 100644 --- a/packages/ember-extension-support/lib/data_adapter.js +++ b/packages/ember-extension-support/lib/data_adapter.js @@ -10,7 +10,7 @@ import { String as StringUtils, Namespace, Object as EmberObject, - A as emberA, + A as emberA } from 'ember-runtime'; /** @@ -154,7 +154,7 @@ export default EmberObject.extend({ typesAdded(typesToSend); let release = () => { - releaseMethods.forEach((fn) => fn()); + releaseMethods.forEach(fn => fn()); this.releaseMethods.removeObject(release); }; this.releaseMethods.pushObject(release); @@ -204,7 +204,7 @@ export default EmberObject.extend({ recordsUpdated([updatedRecord]); } - let recordsToSend = records.map((record) => { + let recordsToSend = records.map(record => { releaseMethods.push(this.observeRecord(record, recordUpdated)); return this.wrapRecord(record); }); @@ -222,7 +222,12 @@ export default EmberObject.extend({ } }; - let observer = { didChange: contentDidChange, willChange() { return this; } }; + let observer = { + didChange: contentDidChange, + willChange() { + return this; + } + }; addArrayObserver(records, this, observer); release = () => { @@ -300,7 +305,9 @@ export default EmberObject.extend({ scheduleOnce('actions', this, onChange); } }, - willChange() { return this; } + willChange() { + return this; + } }; addArrayObserver(records, this, observer); @@ -310,7 +317,6 @@ export default EmberObject.extend({ return release; }, - /** Wraps a given model type and observes changes to it. @@ -342,7 +348,6 @@ export default EmberObject.extend({ return typeToSend; }, - /** Fetches all models defined in the application. @@ -361,7 +366,7 @@ export default EmberObject.extend({ } // New adapters return strings instead of classes. - types = emberA(types).map((name) => { + types = emberA(types).map(name => { return { klass: this._nameToClass(name), name @@ -386,10 +391,14 @@ export default EmberObject.extend({ namespaces.forEach(namespace => { for (let key in namespace) { - if (!namespace.hasOwnProperty(key)) { continue; } + if (!namespace.hasOwnProperty(key)) { + continue; + } // Even though we will filter again in `getModelTypes`, // we should not call `lookupFactory` on non-models - if (!this.detect(namespace[key])) { continue; } + if (!this.detect(namespace[key])) { + continue; + } let name = StringUtils.dasherize(key); types.push(name); } diff --git a/packages/ember-extension-support/lib/index.js b/packages/ember-extension-support/lib/index.js index 99a4a49ebc2..866cced75ce 100644 --- a/packages/ember-extension-support/lib/index.js +++ b/packages/ember-extension-support/lib/index.js @@ -1,3 +1,2 @@ - export { default as DataAdapter } from './data_adapter'; export { default as ContainerDebugAdapter } from './container_debug_adapter'; diff --git a/packages/ember-extension-support/tests/container_debug_adapter_test.js b/packages/ember-extension-support/tests/container_debug_adapter_test.js index 02c75a2b37b..ed5fce63485 100644 --- a/packages/ember-extension-support/tests/container_debug_adapter_test.js +++ b/packages/ember-extension-support/tests/container_debug_adapter_test.js @@ -6,47 +6,78 @@ import '../index'; // Must be required to export Ember.ContainerDebugAdapter. import { getDebugFunction, setDebugFunction } from 'ember-debug'; const originalDebug = getDebugFunction('debug'); -const noop = function(){}; +const noop = function() {}; let adapter; -moduleFor('Container Debug Adapter', class extends ApplicationTestCase { - constructor() { - setDebugFunction('debug', noop); - super(); - adapter = this.application.__deprecatedInstance__.lookup('container-debug-adapter:main'); - } +moduleFor( + 'Container Debug Adapter', + class extends ApplicationTestCase { + constructor() { + setDebugFunction('debug', noop); + super(); + adapter = this.application.__deprecatedInstance__.lookup( + 'container-debug-adapter:main' + ); + } - get applicationOptions() { - return assign(super.applicationOptions, { - autoboot: true - }); - } + get applicationOptions() { + return assign(super.applicationOptions, { + autoboot: true + }); + } - teardown() { - setDebugFunction('debug', originalDebug); - run(() => { - adapter.destroy(); - }); + teardown() { + setDebugFunction('debug', originalDebug); + run(() => { + adapter.destroy(); + }); - super.teardown(); - } + super.teardown(); + } - ['@test default ContainerDebugAdapter cannot catalog certain entries by type'](assert) { - assert.equal(adapter.canCatalogEntriesByType('model'), false, 'canCatalogEntriesByType should return false for model'); - assert.equal(adapter.canCatalogEntriesByType('template'), false, 'canCatalogEntriesByType should return false for template'); - } + ['@test default ContainerDebugAdapter cannot catalog certain entries by type']( + assert + ) { + assert.equal( + adapter.canCatalogEntriesByType('model'), + false, + 'canCatalogEntriesByType should return false for model' + ); + assert.equal( + adapter.canCatalogEntriesByType('template'), + false, + 'canCatalogEntriesByType should return false for template' + ); + } - ['@test default ContainerDebugAdapter can catalog typical entries by type'](assert) { - assert.equal(adapter.canCatalogEntriesByType('controller'), true, 'canCatalogEntriesByType should return true for controller'); - assert.equal(adapter.canCatalogEntriesByType('route'), true, 'canCatalogEntriesByType should return true for route'); - assert.equal(adapter.canCatalogEntriesByType('view'), true, 'canCatalogEntriesByType should return true for view'); - } + ['@test default ContainerDebugAdapter can catalog typical entries by type']( + assert + ) { + assert.equal( + adapter.canCatalogEntriesByType('controller'), + true, + 'canCatalogEntriesByType should return true for controller' + ); + assert.equal( + adapter.canCatalogEntriesByType('route'), + true, + 'canCatalogEntriesByType should return true for route' + ); + assert.equal( + adapter.canCatalogEntriesByType('view'), + true, + 'canCatalogEntriesByType should return true for view' + ); + } - ['@test default ContainerDebugAdapter catalogs controller entries'](assert) { - this.application.PostController = EmberController.extend(); - let controllerClasses = adapter.catalogEntriesByType('controller'); + ['@test default ContainerDebugAdapter catalogs controller entries']( + assert + ) { + this.application.PostController = EmberController.extend(); + let controllerClasses = adapter.catalogEntriesByType('controller'); - assert.equal(controllerClasses.length, 1, 'found 1 class'); - assert.equal(controllerClasses[0], 'post', 'found the right class'); + assert.equal(controllerClasses.length, 1, 'found 1 class'); + assert.equal(controllerClasses[0], 'post', 'found the right class'); + } } -}); +); diff --git a/packages/ember-extension-support/tests/data_adapter_test.js b/packages/ember-extension-support/tests/data_adapter_test.js index 6ff197f1d65..b0abc8c9735 100644 --- a/packages/ember-extension-support/tests/data_adapter_test.js +++ b/packages/ember-extension-support/tests/data_adapter_test.js @@ -1,10 +1,4 @@ -import { - get, - set, - run, - addObserver, - removeObserver -} from 'ember-metal'; +import { get, set, run, addObserver, removeObserver } from 'ember-metal'; import { Object as EmberObject, A as emberA } from 'ember-runtime'; import EmberDataAdapter from '../data_adapter'; import { moduleFor, ApplicationTestCase } from 'internal-test-helpers'; @@ -31,233 +25,292 @@ const DataAdapter = EmberDataAdapter.extend({ } }); +moduleFor( + 'Data Adapter', + class extends ApplicationTestCase { + ['@test Model types added'](assert) { + this.add( + 'data-adapter:main', + DataAdapter.extend({ + getRecords() { + return emberA([1, 2, 3]); + }, + columnsForType() { + return [{ name: 'title', desc: 'Title' }]; + } + }) + ); + this.add('model:post', PostClass); + + return this.visit('/').then(() => { + let adapter = this.applicationInstance.lookup('data-adapter:main'); + + function modelTypesAdded(types) { + assert.equal(types.length, 1); + let postType = types[0]; + assert.equal(postType.name, 'post', 'Correctly sets the name'); + assert.equal(postType.count, 3, 'Correctly sets the record count'); + assert.strictEqual( + postType.object, + PostClass, + 'Correctly sets the object' + ); + assert.deepEqual( + postType.columns, + [{ name: 'title', desc: 'Title' }], + 'Correctly sets the columns' + ); + } -moduleFor('Data Adapter', class extends ApplicationTestCase { - - ['@test Model types added'](assert) { - this.add('data-adapter:main', DataAdapter.extend({ - getRecords() { - return emberA([1, 2, 3]); - }, - columnsForType() { - return [{ name: 'title', desc: 'Title' }]; - } - })); - this.add('model:post', PostClass); - - return this.visit('/').then(() => { - let adapter = this.applicationInstance.lookup('data-adapter:main'); - - function modelTypesAdded(types) { - assert.equal(types.length, 1); - let postType = types[0]; - assert.equal(postType.name, 'post', 'Correctly sets the name'); - assert.equal(postType.count, 3, 'Correctly sets the record count'); - assert.strictEqual(postType.object, PostClass, 'Correctly sets the object'); - assert.deepEqual(postType.columns, [{ name: 'title', desc: 'Title' }], 'Correctly sets the columns'); - } - - adapter.watchModelTypes(modelTypesAdded); - }); - } - - ['@test getRecords gets a model name as second argument'](assert) { - this.add('data-adapter:main', DataAdapter.extend({ - getRecords(klass, name) { - assert.equal(name, 'post'); - return emberA(); - } - })); - this.add('model:post', PostClass); - - return this.visit('/').then(() => { - adapter = this.applicationInstance.lookup('data-adapter:main'); - adapter.watchModelTypes(function() { }); - }); - } - - ['@test Model types added with custom container-debug-adapter'](assert) { - let StubContainerDebugAdapter = EmberObject.extend({ - canCatalogEntriesByType() { - return true; - }, - catalogEntriesByType() { - return emberA(['post']); - } - }); - this.add('container-debug-adapter:main', StubContainerDebugAdapter); - this.add('data-adapter:main', DataAdapter.extend({ - getRecords() { - return emberA([1, 2, 3]); - }, - columnsForType() { - return [{ name: 'title', desc: 'Title' }]; - } - })); - this.add('model:post', PostClass); - - return this.visit('/').then(() => { - let adapter = this.applicationInstance.lookup('data-adapter:main'); - - function modelTypesAdded(types) { - assert.equal(types.length, 1); - let postType = types[0]; - assert.equal(postType.name, 'post', 'Correctly sets the name'); - assert.equal(postType.count, 3, 'Correctly sets the record count'); - assert.strictEqual(postType.object, PostClass, 'Correctly sets the object'); - assert.deepEqual(postType.columns, [{ name: 'title', desc: 'Title' }], 'Correctly sets the columns'); - } - - adapter.watchModelTypes(modelTypesAdded); - }); - } - - ['@test Model Types Updated'](assert) { - let records = emberA([1, 2, 3]); - this.add('data-adapter:main', DataAdapter.extend({ - getRecords() { - return records; - } - })); - this.add('model:post', PostClass); - - return this.visit('/').then(() => { - adapter = this.applicationInstance.lookup('data-adapter:main'); - - function modelTypesAdded() { - run(() => { - records.pushObject(4); - }); - } - - function modelTypesUpdated(types) { - let postType = types[0]; - assert.equal(postType.count, 4, 'Correctly updates the count'); - } - - adapter.watchModelTypes(modelTypesAdded, modelTypesUpdated); - }); - } - - ['@test Model Types Updated but Unchanged Do not Trigger Callbacks'](assert) { - assert.expect(0); - let records = emberA([1, 2, 3]); - this.add('data-adapter:main', DataAdapter.extend({ - getRecords() { - return records; - } - })); - this.add('model:post', PostClass); - - return this.visit('/').then(() => { - adapter = this.applicationInstance.lookup('data-adapter:main'); - - function modelTypesAdded() { - run(() => { - records.arrayContentDidChange(0, 0, 0); - }); - } - - function modelTypesUpdated() { - assert.ok(false, "modelTypesUpdated should not be triggered if the array didn't change"); - } - - adapter.watchModelTypes(modelTypesAdded, modelTypesUpdated); - }); - } - - ['@test Records Added'](assert) { - let countAdded = 1; - let post = PostClass.create(); - let recordList = emberA([post]); + adapter.watchModelTypes(modelTypesAdded); + }); + } + + ['@test getRecords gets a model name as second argument'](assert) { + this.add( + 'data-adapter:main', + DataAdapter.extend({ + getRecords(klass, name) { + assert.equal(name, 'post'); + return emberA(); + } + }) + ); + this.add('model:post', PostClass); + + return this.visit('/').then(() => { + adapter = this.applicationInstance.lookup('data-adapter:main'); + adapter.watchModelTypes(function() {}); + }); + } + + ['@test Model types added with custom container-debug-adapter'](assert) { + let StubContainerDebugAdapter = EmberObject.extend({ + canCatalogEntriesByType() { + return true; + }, + catalogEntriesByType() { + return emberA(['post']); + } + }); + this.add('container-debug-adapter:main', StubContainerDebugAdapter); + this.add( + 'data-adapter:main', + DataAdapter.extend({ + getRecords() { + return emberA([1, 2, 3]); + }, + columnsForType() { + return [{ name: 'title', desc: 'Title' }]; + } + }) + ); + this.add('model:post', PostClass); + + return this.visit('/').then(() => { + let adapter = this.applicationInstance.lookup('data-adapter:main'); + + function modelTypesAdded(types) { + assert.equal(types.length, 1); + let postType = types[0]; + assert.equal(postType.name, 'post', 'Correctly sets the name'); + assert.equal(postType.count, 3, 'Correctly sets the record count'); + assert.strictEqual( + postType.object, + PostClass, + 'Correctly sets the object' + ); + assert.deepEqual( + postType.columns, + [{ name: 'title', desc: 'Title' }], + 'Correctly sets the columns' + ); + } - this.add('data-adapter:main', DataAdapter.extend({ - getRecords() { - return recordList; - }, - getRecordColor() { - return 'blue'; - }, - getRecordColumnValues() { - return { title: 'Post ' + countAdded }; - }, - getRecordKeywords() { - return ['Post ' + countAdded]; - } - })); - this.add('model:post', PostClass); - - return this.visit('/').then(() => { - adapter = this.applicationInstance.lookup('data-adapter:main'); - - function recordsAdded(records) { - let record = records[0]; - assert.equal(record.color, 'blue', 'Sets the color correctly'); - assert.deepEqual(record.columnValues, { title: 'Post ' + countAdded }, 'Sets the column values correctly'); - assert.deepEqual(record.searchKeywords, ['Post ' + countAdded], 'Sets search keywords correctly'); - assert.strictEqual(record.object, post, 'Sets the object to the record instance'); - } + adapter.watchModelTypes(modelTypesAdded); + }); + } + + ['@test Model Types Updated'](assert) { + let records = emberA([1, 2, 3]); + this.add( + 'data-adapter:main', + DataAdapter.extend({ + getRecords() { + return records; + } + }) + ); + this.add('model:post', PostClass); + + return this.visit('/').then(() => { + adapter = this.applicationInstance.lookup('data-adapter:main'); + + function modelTypesAdded() { + run(() => { + records.pushObject(4); + }); + } - adapter.watchRecords('post', recordsAdded); - countAdded++; - post = PostClass.create(); - recordList.pushObject(post); - }); - } + function modelTypesUpdated(types) { + let postType = types[0]; + assert.equal(postType.count, 4, 'Correctly updates the count'); + } - ['@test Observes and releases a record correctly'](assert) { - let updatesCalled = 0; - let post = PostClass.create({ title: 'Post' }); - let recordList = emberA([post]); + adapter.watchModelTypes(modelTypesAdded, modelTypesUpdated); + }); + } + + ['@test Model Types Updated but Unchanged Do not Trigger Callbacks']( + assert + ) { + assert.expect(0); + let records = emberA([1, 2, 3]); + this.add( + 'data-adapter:main', + DataAdapter.extend({ + getRecords() { + return records; + } + }) + ); + this.add('model:post', PostClass); + + return this.visit('/').then(() => { + adapter = this.applicationInstance.lookup('data-adapter:main'); + + function modelTypesAdded() { + run(() => { + records.arrayContentDidChange(0, 0, 0); + }); + } - this.add('data-adapter:main', DataAdapter.extend({ - getRecords() { - return recordList; - }, - observeRecord(record, recordUpdated) { - let self = this; - function callback() { - recordUpdated(self.wrapRecord(record)); + function modelTypesUpdated() { + assert.ok( + false, + "modelTypesUpdated should not be triggered if the array didn't change" + ); } - addObserver(record, 'title', callback); - return function() { - removeObserver(record, 'title', callback); - }; - }, - getRecordColumnValues(record) { - return { title: get(record, 'title') }; - } - })); - this.add('model:post', PostClass); - return this.visit('/').then(() => { - adapter = this.applicationInstance.lookup('data-adapter:main'); + adapter.watchModelTypes(modelTypesAdded, modelTypesUpdated); + }); + } + + ['@test Records Added'](assert) { + let countAdded = 1; + let post = PostClass.create(); + let recordList = emberA([post]); + + this.add( + 'data-adapter:main', + DataAdapter.extend({ + getRecords() { + return recordList; + }, + getRecordColor() { + return 'blue'; + }, + getRecordColumnValues() { + return { title: 'Post ' + countAdded }; + }, + getRecordKeywords() { + return ['Post ' + countAdded]; + } + }) + ); + this.add('model:post', PostClass); + + return this.visit('/').then(() => { + adapter = this.applicationInstance.lookup('data-adapter:main'); + + function recordsAdded(records) { + let record = records[0]; + assert.equal(record.color, 'blue', 'Sets the color correctly'); + assert.deepEqual( + record.columnValues, + { title: 'Post ' + countAdded }, + 'Sets the column values correctly' + ); + assert.deepEqual( + record.searchKeywords, + ['Post ' + countAdded], + 'Sets search keywords correctly' + ); + assert.strictEqual( + record.object, + post, + 'Sets the object to the record instance' + ); + } - function recordsAdded() { - set(post, 'title', 'Post Modified'); - } + adapter.watchRecords('post', recordsAdded); + countAdded++; + post = PostClass.create(); + recordList.pushObject(post); + }); + } + + ['@test Observes and releases a record correctly'](assert) { + let updatesCalled = 0; + let post = PostClass.create({ title: 'Post' }); + let recordList = emberA([post]); + + this.add( + 'data-adapter:main', + DataAdapter.extend({ + getRecords() { + return recordList; + }, + observeRecord(record, recordUpdated) { + let self = this; + function callback() { + recordUpdated(self.wrapRecord(record)); + } + addObserver(record, 'title', callback); + return function() { + removeObserver(record, 'title', callback); + }; + }, + getRecordColumnValues(record) { + return { title: get(record, 'title') }; + } + }) + ); + this.add('model:post', PostClass); + + return this.visit('/').then(() => { + adapter = this.applicationInstance.lookup('data-adapter:main'); + + function recordsAdded() { + set(post, 'title', 'Post Modified'); + } - function recordsUpdated(records) { - updatesCalled++; - assert.equal(records[0].columnValues.title, 'Post Modified'); - } + function recordsUpdated(records) { + updatesCalled++; + assert.equal(records[0].columnValues.title, 'Post Modified'); + } - let release = adapter.watchRecords('post', recordsAdded, recordsUpdated); - release(); - set(post, 'title', 'New Title'); - assert.equal(updatesCalled, 1, 'Release function removes observers'); - }); - } + let release = adapter.watchRecords( + 'post', + recordsAdded, + recordsUpdated + ); + release(); + set(post, 'title', 'New Title'); + assert.equal(updatesCalled, 1, 'Release function removes observers'); + }); + } - ['@test _nameToClass does not error when not found'](assert) { - this.add('data-adapter:main', DataAdapter); + ['@test _nameToClass does not error when not found'](assert) { + this.add('data-adapter:main', DataAdapter); - return this.visit('/').then(() => { - adapter = this.applicationInstance.lookup('data-adapter:main'); + return this.visit('/').then(() => { + adapter = this.applicationInstance.lookup('data-adapter:main'); - let klass = adapter._nameToClass('foo'); + let klass = adapter._nameToClass('foo'); - assert.equal(klass, undefined, 'returns undefined'); - }); + assert.equal(klass, undefined, 'returns undefined'); + }); + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/application/actions-test.js b/packages/ember-glimmer/tests/integration/application/actions-test.js index 39c027ae926..213912ee283 100644 --- a/packages/ember-glimmer/tests/integration/application/actions-test.js +++ b/packages/ember-glimmer/tests/integration/application/actions-test.js @@ -1,89 +1,119 @@ import { Controller } from 'ember-runtime'; -import { moduleFor, ApplicationTest, RenderingTest } from '../../utils/test-case'; +import { + moduleFor, + ApplicationTest, + RenderingTest +} from '../../utils/test-case'; import { Component } from '../../utils/helpers'; import { getDebugFunction, setDebugFunction } from 'ember-debug'; const originalDebug = getDebugFunction('debug'); -const noop = function(){}; - -moduleFor('Application test: actions', class extends ApplicationTest { - constructor() { - setDebugFunction('debug', noop); - super(); - } - - teardown() { - setDebugFunction('debug', originalDebug); - } - - ['@test actions in top level template application template target application controller'](assert) { - assert.expect(1); - - this.add('controller:application', Controller.extend({ - actions: { - handleIt() { - assert.ok(true, 'controller received action properly'); - } - } - })); +const noop = function() {}; + +moduleFor( + 'Application test: actions', + class extends ApplicationTest { + constructor() { + setDebugFunction('debug', noop); + super(); + } + + teardown() { + setDebugFunction('debug', originalDebug); + } + + ['@test actions in top level template application template target application controller']( + assert + ) { + assert.expect(1); + + this.add( + 'controller:application', + Controller.extend({ + actions: { + handleIt() { + assert.ok(true, 'controller received action properly'); + } + } + }) + ); - this.addTemplate('application', ''); + this.addTemplate( + 'application', + '' + ); - return this.visit('/') - .then(() => { + return this.visit('/').then(() => { this.runTask(() => this.$('#handle-it').click()); }); - } + } + + ['@test actions in nested outlet template target their controller']( + assert + ) { + assert.expect(1); + + this.add( + 'controller:application', + Controller.extend({ + actions: { + handleIt() { + assert.ok( + false, + 'application controller should not have received action!' + ); + } + } + }) + ); + + this.add( + 'controller:index', + Controller.extend({ + actions: { + handleIt() { + assert.ok(true, 'controller received action properly'); + } + } + }) + ); - ['@test actions in nested outlet template target their controller'](assert) { - assert.expect(1); - - this.add('controller:application', Controller.extend({ - actions: { - handleIt() { - assert.ok(false, 'application controller should not have received action!'); - } - } - })); - - this.add('controller:index', Controller.extend({ - actions: { - handleIt() { - assert.ok(true, 'controller received action properly'); - } - } - })); - - this.addTemplate('index', ''); - - return this.visit('/') - .then(() => { + this.addTemplate( + 'index', + '' + ); + + return this.visit('/').then(() => { this.runTask(() => this.$('#handle-it').click()); }); + } } -}); - -moduleFor('Rendering test: non-interactive actions', class extends RenderingTest { - getBootOptions() { - return { isInteractive: false }; - } - - [`@test doesn't attatch actions`](assert) { - this.registerComponent('foo-bar', { - ComponentClass: Component.extend({ - actions: { - fire() { - assert.ok(false); +); + +moduleFor( + 'Rendering test: non-interactive actions', + class extends RenderingTest { + getBootOptions() { + return { isInteractive: false }; + } + + [`@test doesn't attatch actions`](assert) { + this.registerComponent('foo-bar', { + ComponentClass: Component.extend({ + actions: { + fire() { + assert.ok(false); + } } - } - }), - template: `` - }); + }), + template: `` + }); - this.render('{{foo-bar tagName=""}}'); + this.render('{{foo-bar tagName=""}}'); - this.assertHTML(''); + this.assertHTML(''); - this.$('button').click(); + this.$('button').click(); + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/application/engine-test.js b/packages/ember-glimmer/tests/integration/application/engine-test.js index be21b3a347e..ba3617d3b10 100644 --- a/packages/ember-glimmer/tests/integration/application/engine-test.js +++ b/packages/ember-glimmer/tests/integration/application/engine-test.js @@ -7,742 +7,952 @@ import { Engine } from 'ember-application'; import { Route } from 'ember-routing'; import { next } from 'ember-metal'; -moduleFor('Application test: engine rendering', class extends ApplicationTest { - get routerOptions() { - return { - location: 'none', - - // This creates a handler function similar to what is in use by ember-engines - // internally. Specifically, it returns a promise when transitioning _into_ - // the first engine route, but returns the synchronously available handler - // _after_ the engine has been resolved. - _getHandlerFunction() { - let syncHandler = this._super(...arguments); - this._enginePromises = Object.create(null); - this._resolvedEngines = Object.create(null); - - return name => { - let engineInfo = this._engineInfoByRoute[name]; - if (!engineInfo) { return syncHandler(name); } - - let engineName = engineInfo.name; - if (this._resolvedEngines[engineName]) { return syncHandler(name); } - - let enginePromise = this._enginePromises[engineName]; - - if (!enginePromise) { - enginePromise = new RSVP.Promise(resolve => { - setTimeout(() => { - this._resolvedEngines[engineName] = true; - - resolve(); - }, 1); - }); - this._enginePromises[engineName] = enginePromise; - } +moduleFor( + 'Application test: engine rendering', + class extends ApplicationTest { + get routerOptions() { + return { + location: 'none', + + // This creates a handler function similar to what is in use by ember-engines + // internally. Specifically, it returns a promise when transitioning _into_ + // the first engine route, but returns the synchronously available handler + // _after_ the engine has been resolved. + _getHandlerFunction() { + let syncHandler = this._super(...arguments); + this._enginePromises = Object.create(null); + this._resolvedEngines = Object.create(null); + + return name => { + let engineInfo = this._engineInfoByRoute[name]; + if (!engineInfo) { + return syncHandler(name); + } + + let engineName = engineInfo.name; + if (this._resolvedEngines[engineName]) { + return syncHandler(name); + } + + let enginePromise = this._enginePromises[engineName]; + + if (!enginePromise) { + enginePromise = new RSVP.Promise(resolve => { + setTimeout(() => { + this._resolvedEngines[engineName] = true; + + resolve(); + }, 1); + }); + this._enginePromises[engineName] = enginePromise; + } + + return enginePromise.then(() => syncHandler(name)); + }; + } + }; + } - return enginePromise.then(() => syncHandler(name)); - }; - } - }; - } + setupAppAndRoutableEngine(hooks = []) { + let self = this; - setupAppAndRoutableEngine(hooks = []) { - let self = this; - - this.addTemplate('application', 'Application{{outlet}}'); - - this.router.map(function() { - this.mount('blog'); - }); - this.add('route-map:blog', function() { - this.route('post', function() { - this.route('comments'); - this.route('likes'); - }); - this.route('category', {path: 'category/:id'}); - this.route('author', {path: 'author/:id'}); - }); - this.add('route:application', Route.extend({ - model() { - hooks.push('application - application'); - } - })); - - this.add('engine:blog', Engine.extend({ - init() { - this._super(...arguments); - this.register('controller:application', Controller.extend({ - queryParams: ['lang'], - lang: '' - })); - this.register('controller:category', Controller.extend({ - queryParams: ['type'], - })); - this.register('controller:authorKtrl', Controller.extend({ - queryParams: ['official'], - })); - this.register('template:application', compile('Engine{{lang}}{{outlet}}')); - this.register('route:application', Route.extend({ + this.addTemplate('application', 'Application{{outlet}}'); + + this.router.map(function() { + this.mount('blog'); + }); + this.add('route-map:blog', function() { + this.route('post', function() { + this.route('comments'); + this.route('likes'); + }); + this.route('category', { path: 'category/:id' }); + this.route('author', { path: 'author/:id' }); + }); + this.add( + 'route:application', + Route.extend({ model() { - hooks.push('engine - application'); + hooks.push('application - application'); } - })); - this.register('route:author', Route.extend({ - controllerName: 'authorKtrl', - })); + }) + ); - if (self._additionalEngineRegistrations) { - self._additionalEngineRegistrations.call(this); - } - } - })); - } + this.add( + 'engine:blog', + Engine.extend({ + init() { + this._super(...arguments); + this.register( + 'controller:application', + Controller.extend({ + queryParams: ['lang'], + lang: '' + }) + ); + this.register( + 'controller:category', + Controller.extend({ + queryParams: ['type'] + }) + ); + this.register( + 'controller:authorKtrl', + Controller.extend({ + queryParams: ['official'] + }) + ); + this.register( + 'template:application', + compile('Engine{{lang}}{{outlet}}') + ); + this.register( + 'route:application', + Route.extend({ + model() { + hooks.push('engine - application'); + } + }) + ); + this.register( + 'route:author', + Route.extend({ + controllerName: 'authorKtrl' + }) + ); + + if (self._additionalEngineRegistrations) { + self._additionalEngineRegistrations.call(this); + } + } + }) + ); + } - setupAppAndRoutelessEngine(hooks) { - this.setupRoutelessEngine(hooks); + setupAppAndRoutelessEngine(hooks) { + this.setupRoutelessEngine(hooks); - this.add('engine:chat-engine', Engine.extend({ - init() { - this._super(...arguments); - this.register('template:application', compile('Engine')); - this.register('controller:application', Controller.extend({ + this.add( + 'engine:chat-engine', + Engine.extend({ init() { this._super(...arguments); - hooks.push('engine - application'); + this.register('template:application', compile('Engine')); + this.register( + 'controller:application', + Controller.extend({ + init() { + this._super(...arguments); + hooks.push('engine - application'); + } + }) + ); } - })); - } - })); - } + }) + ); + } + + setupAppAndRoutableEngineWithPartial(hooks) { + this.addTemplate('application', 'Application{{outlet}}'); - setupAppAndRoutableEngineWithPartial(hooks) { - this.addTemplate('application', 'Application{{outlet}}'); - - this.router.map(function() { - this.mount('blog'); - }); - this.add('route-map:blog', function() { }); - this.add('route:application', Route.extend({ - model() { - hooks.push('application - application'); - } - })); - - this.add('engine:blog', Engine.extend({ - init() { - this._super(...arguments); - this.register('template:foo', compile('foo partial')); - this.register('template:application', compile('Engine{{outlet}} {{partial "foo"}}')); - this.register('route:application', Route.extend({ + this.router.map(function() { + this.mount('blog'); + }); + this.add('route-map:blog', function() {}); + this.add( + 'route:application', + Route.extend({ model() { - hooks.push('engine - application'); + hooks.push('application - application'); } - })); - } - })); - } + }) + ); - setupRoutelessEngine(hooks) { - this.addTemplate('application', 'Application{{mount "chat-engine"}}'); - this.add('route:application', Route.extend({ - model() { - hooks.push('application - application'); - } - })); - } + this.add( + 'engine:blog', + Engine.extend({ + init() { + this._super(...arguments); + this.register('template:foo', compile('foo partial')); + this.register( + 'template:application', + compile('Engine{{outlet}} {{partial "foo"}}') + ); + this.register( + 'route:application', + Route.extend({ + model() { + hooks.push('engine - application'); + } + }) + ); + } + }) + ); + } - setupAppAndRoutlessEngineWithPartial(hooks) { - this.setupRoutelessEngine(hooks); + setupRoutelessEngine(hooks) { + this.addTemplate('application', 'Application{{mount "chat-engine"}}'); + this.add( + 'route:application', + Route.extend({ + model() { + hooks.push('application - application'); + } + }) + ); + } - this.add('engine:chat-engine', Engine.extend({ - init() { - this._super(...arguments); - this.register('template:foo', compile('foo partial')); - this.register('template:application', compile('Engine {{partial "foo"}}')); - this.register('controller:application', Controller.extend({ + setupAppAndRoutlessEngineWithPartial(hooks) { + this.setupRoutelessEngine(hooks); + + this.add( + 'engine:chat-engine', + Engine.extend({ init() { this._super(...arguments); - hooks.push('engine - application'); + this.register('template:foo', compile('foo partial')); + this.register( + 'template:application', + compile('Engine {{partial "foo"}}') + ); + this.register( + 'controller:application', + Controller.extend({ + init() { + this._super(...arguments); + hooks.push('engine - application'); + } + }) + ); } - })); - } - })); - } + }) + ); + } - additionalEngineRegistrations(callback) { - this._additionalEngineRegistrations = callback; - } + additionalEngineRegistrations(callback) { + this._additionalEngineRegistrations = callback; + } - setupEngineWithAttrs() { - this.addTemplate('application', 'Application{{mount "chat-engine"}}'); - - this.add('engine:chat-engine', Engine.extend({ - init() { - this._super(...arguments); - this.register('template:components/foo-bar', compile(`{{partial "troll"}}`)); - this.register('template:troll', compile('{{attrs.wat}}')); - this.register('controller:application', Controller.extend({ - contextType: 'Engine' - })); - this.register('template:application', compile('Engine {{foo-bar wat=contextType}}')); - } - })); - } + setupEngineWithAttrs() { + this.addTemplate('application', 'Application{{mount "chat-engine"}}'); - stringsEndWith(str, suffix) { - return str.indexOf(suffix, str.length - suffix.length) !== -1; - } + this.add( + 'engine:chat-engine', + Engine.extend({ + init() { + this._super(...arguments); + this.register( + 'template:components/foo-bar', + compile(`{{partial "troll"}}`) + ); + this.register('template:troll', compile('{{attrs.wat}}')); + this.register( + 'controller:application', + Controller.extend({ + contextType: 'Engine' + }) + ); + this.register( + 'template:application', + compile('Engine {{foo-bar wat=contextType}}') + ); + } + }) + ); + } - ['@test attrs in an engine']() { - this.setupEngineWithAttrs([]); + stringsEndWith(str, suffix) { + return str.indexOf(suffix, str.length - suffix.length) !== -1; + } - return this.visit('/').then(() => { - this.assertText('ApplicationEngine Engine'); - }); - } + ['@test attrs in an engine']() { + this.setupEngineWithAttrs([]); - ['@test sharing a template between engine and application has separate refinements']() { - this.assert.expect(1); + return this.visit('/').then(() => { + this.assertText('ApplicationEngine Engine'); + }); + } + + ['@test sharing a template between engine and application has separate refinements']() { + this.assert.expect(1); - let sharedTemplate = compile(strip` + let sharedTemplate = compile(strip`

{{contextType}}

{{ambiguous-curlies}} {{outlet}} `); - this.add('template:application', sharedTemplate); - this.add('controller:application', Controller.extend({ - contextType: 'Application', - 'ambiguous-curlies': 'Controller Data!' - })); - - this.router.map(function() { - this.mount('blog'); - }); - this.add('route-map:blog', function() { }); - - this.add('engine:blog', Engine.extend({ - init() { - this._super(...arguments); - - this.register('controller:application', Controller.extend({ - contextType: 'Engine' - })); - this.register('template:application', sharedTemplate); - this.register('template:components/ambiguous-curlies', compile(strip` + this.add('template:application', sharedTemplate); + this.add( + 'controller:application', + Controller.extend({ + contextType: 'Application', + 'ambiguous-curlies': 'Controller Data!' + }) + ); + + this.router.map(function() { + this.mount('blog'); + }); + this.add('route-map:blog', function() {}); + + this.add( + 'engine:blog', + Engine.extend({ + init() { + this._super(...arguments); + + this.register( + 'controller:application', + Controller.extend({ + contextType: 'Engine' + }) + ); + this.register('template:application', sharedTemplate); + this.register( + 'template:components/ambiguous-curlies', + compile(strip`

Component!

- `)); - } - })); + `) + ); + } + }) + ); - return this.visit('/blog').then(() => { - this.assertText('ApplicationController Data!EngineComponent!'); - }); - } + return this.visit('/blog').then(() => { + this.assertText('ApplicationController Data!EngineComponent!'); + }); + } - ['@test sharing a layout between engine and application has separate refinements']() { - this.assert.expect(1); + ['@test sharing a layout between engine and application has separate refinements']() { + this.assert.expect(1); - let sharedLayout = compile(strip` + let sharedLayout = compile(strip` {{ambiguous-curlies}} `); - let sharedComponent = Component.extend({ - layout: sharedLayout - }); + let sharedComponent = Component.extend({ + layout: sharedLayout + }); - this.addTemplate('application', strip` + this.addTemplate( + 'application', + strip`

Application

{{my-component ambiguous-curlies="Local Data!"}} {{outlet}} - `); + ` + ); - this.add('component:my-component', sharedComponent); + this.add('component:my-component', sharedComponent); - this.router.map(function() { - this.mount('blog'); - }); - this.add('route-map:blog', function() { }); + this.router.map(function() { + this.mount('blog'); + }); + this.add('route-map:blog', function() {}); - this.add('engine:blog', Engine.extend({ - init() { - this._super(...arguments); - this.register('template:application', compile(strip` + this.add( + 'engine:blog', + Engine.extend({ + init() { + this._super(...arguments); + this.register( + 'template:application', + compile(strip`

Engine

{{my-component}} {{outlet}} - `)); - this.register('component:my-component', sharedComponent); - this.register('template:components/ambiguous-curlies', compile(strip` + `) + ); + this.register('component:my-component', sharedComponent); + this.register( + 'template:components/ambiguous-curlies', + compile(strip`

Component!

- `)); - } - })); - - return this.visit('/blog').then(() => { - this.assertText('ApplicationLocal Data!EngineComponent!'); - }); - } - - ['@test visit() with `shouldRender: true` returns a promise that resolves when application and engine templates have rendered'](assert) { - assert.expect(2); - - let hooks = []; - - this.setupAppAndRoutableEngine(hooks); - - return this.visit('/blog', { shouldRender: true }).then(() => { - this.assertText('ApplicationEngine'); - - this.assert.deepEqual(hooks, [ - 'application - application', - 'engine - application' - ], 'the expected model hooks were fired'); - }); - } - - ['@test visit() with `shouldRender: false` returns a promise that resolves without rendering'](assert) { - assert.expect(2); - - let hooks = []; - - this.setupAppAndRoutableEngine(hooks); - - return this.visit('/blog', { shouldRender: false }).then(() => { - assert.strictEqual( - document.getElementById('qunit-fixture').children.length, 0, - `there are no elements in the qunit-fixture element` + `) + ); + } + }) ); - this.assert.deepEqual(hooks, [ - 'application - application', - 'engine - application' - ], 'the expected model hooks were fired'); - }); - } - - ['@test visit() with `shouldRender: true` returns a promise that resolves when application and routeless engine templates have rendered'](assert) { - assert.expect(2); - - let hooks = []; - - this.setupAppAndRoutelessEngine(hooks); - - return this.visit('/', { shouldRender: true }).then(() => { - this.assertText('ApplicationEngine'); - - this.assert.deepEqual(hooks, [ - 'application - application', - 'engine - application' - ], 'the expected hooks were fired'); - }); - } + return this.visit('/blog').then(() => { + this.assertText('ApplicationLocal Data!EngineComponent!'); + }); + } - ['@test visit() with partials in routable engine'](assert) { - assert.expect(2); + ['@test visit() with `shouldRender: true` returns a promise that resolves when application and engine templates have rendered']( + assert + ) { + assert.expect(2); - let hooks = []; + let hooks = []; - this.setupAppAndRoutableEngineWithPartial(hooks); + this.setupAppAndRoutableEngine(hooks); - return this.visit('/blog', { shouldRender: true }).then(() => { - this.assertText('ApplicationEngine foo partial'); + return this.visit('/blog', { shouldRender: true }).then(() => { + this.assertText('ApplicationEngine'); - this.assert.deepEqual(hooks, [ - 'application - application', - 'engine - application' - ], 'the expected hooks were fired'); - }); - } + this.assert.deepEqual( + hooks, + ['application - application', 'engine - application'], + 'the expected model hooks were fired' + ); + }); + } - ['@test visit() with partials in non-routable engine'](assert) { - assert.expect(2); + ['@test visit() with `shouldRender: false` returns a promise that resolves without rendering']( + assert + ) { + assert.expect(2); - let hooks = []; + let hooks = []; - this.setupAppAndRoutlessEngineWithPartial(hooks); + this.setupAppAndRoutableEngine(hooks); - return this.visit('/', { shouldRender: true }).then(() => { - this.assertText('ApplicationEngine foo partial'); + return this.visit('/blog', { shouldRender: false }).then(() => { + assert.strictEqual( + document.getElementById('qunit-fixture').children.length, + 0, + `there are no elements in the qunit-fixture element` + ); - this.assert.deepEqual(hooks, [ - 'application - application', - 'engine - application' - ], 'the expected hooks were fired'); - }); - } + this.assert.deepEqual( + hooks, + ['application - application', 'engine - application'], + 'the expected model hooks were fired' + ); + }); + } - ['@test deactivate should be called on Engine Routes before destruction'](assert) { - assert.expect(3); + ['@test visit() with `shouldRender: true` returns a promise that resolves when application and routeless engine templates have rendered']( + assert + ) { + assert.expect(2); - this.setupAppAndRoutableEngine(); + let hooks = []; - this.add('engine:blog', Engine.extend({ - init() { - this._super(...arguments); - this.register('template:application', compile('Engine{{outlet}}')); - this.register('route:application', Route.extend({ - deactivate() { - assert.notOk(this.isDestroyed, 'Route is not destroyed'); - assert.notOk(this.isDestroying, 'Route is not being destroyed'); - } - })); - } - })); + this.setupAppAndRoutelessEngine(hooks); - return this.visit('/blog').then(() => { - this.assertText('ApplicationEngine'); - }); - } + return this.visit('/', { shouldRender: true }).then(() => { + this.assertText('ApplicationEngine'); - ['@test engine should lookup and use correct controller']() { - this.setupAppAndRoutableEngine(); + this.assert.deepEqual( + hooks, + ['application - application', 'engine - application'], + 'the expected hooks were fired' + ); + }); + } - return this.visit('/blog?lang=English').then(() => { - this.assertText('ApplicationEngineEnglish'); - }); - } + ['@test visit() with partials in routable engine'](assert) { + assert.expect(2); - ['@test error substate route works for the application route of an Engine'](assert) { - assert.expect(2); + let hooks = []; - let errorEntered = RSVP.defer(); + this.setupAppAndRoutableEngineWithPartial(hooks); - this.setupAppAndRoutableEngine(); - this.additionalEngineRegistrations(function() { - this.register('route:application_error', Route.extend({ - activate() { - next(errorEntered.resolve); - } - })); - this.register('template:application_error', compile('Error! {{model.message}}')); - this.register('route:post', Route.extend({ - model() { - return RSVP.reject(new Error('Oh, noes!')); - } - })); - }); - - return this.visit('/').then(() => { - this.assertText('Application'); - return this.transitionTo('blog.post'); - }).then(() => { - return errorEntered.promise; - }).then(() => { - this.assertText('ApplicationError! Oh, noes!'); - }); - } + return this.visit('/blog', { shouldRender: true }).then(() => { + this.assertText('ApplicationEngine foo partial'); - ['@test error route works for the application route of an Engine'](assert) { - assert.expect(2); + this.assert.deepEqual( + hooks, + ['application - application', 'engine - application'], + 'the expected hooks were fired' + ); + }); + } - let errorEntered = RSVP.defer(); + ['@test visit() with partials in non-routable engine'](assert) { + assert.expect(2); - this.setupAppAndRoutableEngine(); - this.additionalEngineRegistrations(function() { - this.register('route:error', Route.extend({ - activate() { - next(errorEntered.resolve); - } - })); - this.register('template:error', compile('Error! {{model.message}}')); - this.register('route:post', Route.extend({ - model() { - return RSVP.reject(new Error('Oh, noes!')); - } - })); - }); - - return this.visit('/').then(() => { - this.assertText('Application'); - return this.transitionTo('blog.post'); - }).then(() => { - return errorEntered.promise; - }).then(() => { - this.assertText('ApplicationEngineError! Oh, noes!'); - }); - } + let hooks = []; - ['@test error substate route works for a child route of an Engine'](assert) { - assert.expect(2); + this.setupAppAndRoutlessEngineWithPartial(hooks); - let errorEntered = RSVP.defer(); + return this.visit('/', { shouldRender: true }).then(() => { + this.assertText('ApplicationEngine foo partial'); - this.setupAppAndRoutableEngine(); - this.additionalEngineRegistrations(function() { - this.register('route:post_error', Route.extend({ - activate() { - next(errorEntered.resolve); - } - })); - this.register('template:post_error', compile('Error! {{model.message}}')); - this.register('route:post', Route.extend({ - model() { - return RSVP.reject(new Error('Oh, noes!')); - } - })); - }); - - return this.visit('/').then(() => { - this.assertText('Application'); - return this.transitionTo('blog.post'); - }).then(() => { - return errorEntered.promise; - }).then(() => { - this.assertText('ApplicationEngineError! Oh, noes!'); - }); - } - - ['@test error route works for a child route of an Engine'](assert) { - assert.expect(2); - - let errorEntered = RSVP.defer(); + this.assert.deepEqual( + hooks, + ['application - application', 'engine - application'], + 'the expected hooks were fired' + ); + }); + } - this.setupAppAndRoutableEngine(); - this.additionalEngineRegistrations(function() { - this.register('route:post.error', Route.extend({ - activate() { - next(errorEntered.resolve); - } - })); - this.register('template:post.error', compile('Error! {{model.message}}')); - this.register('route:post.comments', Route.extend({ - model() { - return RSVP.reject(new Error('Oh, noes!')); - } - })); - }); - - return this.visit('/').then(() => { - this.assertText('Application'); - return this.transitionTo('blog.post.comments'); - }).then(() => { - return errorEntered.promise; - }).then(() => { - this.assertText('ApplicationEngineError! Oh, noes!'); - }); - } + ['@test deactivate should be called on Engine Routes before destruction']( + assert + ) { + assert.expect(3); - ['@test loading substate route works for the application route of an Engine'](assert) { - assert.expect(3); - let done = assert.async(); + this.setupAppAndRoutableEngine(); - let loadingEntered = RSVP.defer(); - let resolveLoading = RSVP.defer(); + this.add( + 'engine:blog', + Engine.extend({ + init() { + this._super(...arguments); + this.register('template:application', compile('Engine{{outlet}}')); + this.register( + 'route:application', + Route.extend({ + deactivate() { + assert.notOk(this.isDestroyed, 'Route is not destroyed'); + assert.notOk( + this.isDestroying, + 'Route is not being destroyed' + ); + } + }) + ); + } + }) + ); - this.setupAppAndRoutableEngine(); - this.additionalEngineRegistrations(function() { - this.register('route:application_loading', Route.extend({ - activate() { - next(loadingEntered.resolve); - } - })); - this.register('template:application_loading', compile('Loading')); - this.register('template:post', compile('Post')); - this.register('route:post', Route.extend({ - model() { - return resolveLoading.promise; - } - })); - }); + return this.visit('/blog').then(() => { + this.assertText('ApplicationEngine'); + }); + } - return this.visit('/').then(() => { - this.assertText('Application'); - let transition = this.transitionTo('blog.post'); + ['@test engine should lookup and use correct controller']() { + this.setupAppAndRoutableEngine(); - loadingEntered.promise.then(() => { - this.assertText('ApplicationLoading'); - resolveLoading.resolve(); + return this.visit('/blog?lang=English').then(() => { + this.assertText('ApplicationEngineEnglish'); + }); + } + + ['@test error substate route works for the application route of an Engine']( + assert + ) { + assert.expect(2); + + let errorEntered = RSVP.defer(); + + this.setupAppAndRoutableEngine(); + this.additionalEngineRegistrations(function() { + this.register( + 'route:application_error', + Route.extend({ + activate() { + next(errorEntered.resolve); + } + }) + ); + this.register( + 'template:application_error', + compile('Error! {{model.message}}') + ); + this.register( + 'route:post', + Route.extend({ + model() { + return RSVP.reject(new Error('Oh, noes!')); + } + }) + ); + }); - return this.runTaskNext().then(() => { - this.assertText('ApplicationEnginePost'); - done(); + return this.visit('/') + .then(() => { + this.assertText('Application'); + return this.transitionTo('blog.post'); + }) + .then(() => { + return errorEntered.promise; + }) + .then(() => { + this.assertText('ApplicationError! Oh, noes!'); }); + } + + ['@test error route works for the application route of an Engine'](assert) { + assert.expect(2); + + let errorEntered = RSVP.defer(); + + this.setupAppAndRoutableEngine(); + this.additionalEngineRegistrations(function() { + this.register( + 'route:error', + Route.extend({ + activate() { + next(errorEntered.resolve); + } + }) + ); + this.register('template:error', compile('Error! {{model.message}}')); + this.register( + 'route:post', + Route.extend({ + model() { + return RSVP.reject(new Error('Oh, noes!')); + } + }) + ); }); - return transition; - }); - } - - ['@test loading route works for the application route of an Engine'](assert) { - assert.expect(3); - let done = assert.async(); - - let loadingEntered = RSVP.defer(); - let resolveLoading = RSVP.defer(); - - this.setupAppAndRoutableEngine(); - this.additionalEngineRegistrations(function() { - this.register('route:loading', Route.extend({ - activate() { - next(loadingEntered.resolve); - } - })); - this.register('template:loading', compile('Loading')); - this.register('template:post', compile('Post')); - this.register('route:post', Route.extend({ - model() { - return resolveLoading.promise; - } - })); - }); - - return this.visit('/').then(() => { - this.assertText('Application'); - let transition = this.transitionTo('blog.post'); + return this.visit('/') + .then(() => { + this.assertText('Application'); + return this.transitionTo('blog.post'); + }) + .then(() => { + return errorEntered.promise; + }) + .then(() => { + this.assertText('ApplicationEngineError! Oh, noes!'); + }); + } + + ['@test error substate route works for a child route of an Engine']( + assert + ) { + assert.expect(2); + + let errorEntered = RSVP.defer(); + + this.setupAppAndRoutableEngine(); + this.additionalEngineRegistrations(function() { + this.register( + 'route:post_error', + Route.extend({ + activate() { + next(errorEntered.resolve); + } + }) + ); + this.register( + 'template:post_error', + compile('Error! {{model.message}}') + ); + this.register( + 'route:post', + Route.extend({ + model() { + return RSVP.reject(new Error('Oh, noes!')); + } + }) + ); + }); - loadingEntered.promise.then(() => { - this.assertText('ApplicationEngineLoading'); - resolveLoading.resolve(); + return this.visit('/') + .then(() => { + this.assertText('Application'); + return this.transitionTo('blog.post'); + }) + .then(() => { + return errorEntered.promise; + }) + .then(() => { + this.assertText('ApplicationEngineError! Oh, noes!'); + }); + } + + ['@test error route works for a child route of an Engine'](assert) { + assert.expect(2); + + let errorEntered = RSVP.defer(); + + this.setupAppAndRoutableEngine(); + this.additionalEngineRegistrations(function() { + this.register( + 'route:post.error', + Route.extend({ + activate() { + next(errorEntered.resolve); + } + }) + ); + this.register( + 'template:post.error', + compile('Error! {{model.message}}') + ); + this.register( + 'route:post.comments', + Route.extend({ + model() { + return RSVP.reject(new Error('Oh, noes!')); + } + }) + ); + }); - return this.runTaskNext().then(() => { - this.assertText('ApplicationEnginePost'); - done(); + return this.visit('/') + .then(() => { + this.assertText('Application'); + return this.transitionTo('blog.post.comments'); + }) + .then(() => { + return errorEntered.promise; + }) + .then(() => { + this.assertText('ApplicationEngineError! Oh, noes!'); }); + } + + ['@test loading substate route works for the application route of an Engine']( + assert + ) { + assert.expect(3); + let done = assert.async(); + + let loadingEntered = RSVP.defer(); + let resolveLoading = RSVP.defer(); + + this.setupAppAndRoutableEngine(); + this.additionalEngineRegistrations(function() { + this.register( + 'route:application_loading', + Route.extend({ + activate() { + next(loadingEntered.resolve); + } + }) + ); + this.register('template:application_loading', compile('Loading')); + this.register('template:post', compile('Post')); + this.register( + 'route:post', + Route.extend({ + model() { + return resolveLoading.promise; + } + }) + ); }); - return transition; - }); - } + return this.visit('/').then(() => { + this.assertText('Application'); + let transition = this.transitionTo('blog.post'); - ['@test loading substate route works for a child route of an Engine'](assert) { - assert.expect(3); - - let resolveLoading; - - this.setupAppAndRoutableEngine(); - this.additionalEngineRegistrations(function() { - this.register('template:post', compile('{{outlet}}')); - this.register('template:post.comments', compile('Comments')); - this.register('template:post.likes_loading', compile('Loading')); - this.register('template:post.likes', compile('Likes')); - this.register('route:post.likes', Route.extend({ - model() { - return new RSVP.Promise((resolve) => { - resolveLoading = resolve; - }); - } - })); - }); + loadingEntered.promise.then(() => { + this.assertText('ApplicationLoading'); + resolveLoading.resolve(); - return this.visit('/blog/post/comments').then(() => { - this.assertText('ApplicationEngineComments'); - let transition = this.transitionTo('blog.post.likes'); + return this.runTaskNext().then(() => { + this.assertText('ApplicationEnginePost'); + done(); + }); + }); - this.runTaskNext().then(() => { - this.assertText('ApplicationEngineLoading'); - resolveLoading(); + return transition; + }); + } + + ['@test loading route works for the application route of an Engine']( + assert + ) { + assert.expect(3); + let done = assert.async(); + + let loadingEntered = RSVP.defer(); + let resolveLoading = RSVP.defer(); + + this.setupAppAndRoutableEngine(); + this.additionalEngineRegistrations(function() { + this.register( + 'route:loading', + Route.extend({ + activate() { + next(loadingEntered.resolve); + } + }) + ); + this.register('template:loading', compile('Loading')); + this.register('template:post', compile('Post')); + this.register( + 'route:post', + Route.extend({ + model() { + return resolveLoading.promise; + } + }) + ); }); - return transition - .then(() => this.runTaskNext()) - .then(() => this.assertText('ApplicationEngineLikes')); - }); - } - - ['@test loading route works for a child route of an Engine'](assert) { - assert.expect(3); - let done = assert.async(); + return this.visit('/').then(() => { + this.assertText('Application'); + let transition = this.transitionTo('blog.post'); - let loadingEntered = RSVP.defer(); - let resolveLoading = RSVP.defer(); + loadingEntered.promise.then(() => { + this.assertText('ApplicationEngineLoading'); + resolveLoading.resolve(); - this.setupAppAndRoutableEngine(); - this.additionalEngineRegistrations(function() { - this.register('template:post', compile('{{outlet}}')); - this.register('template:post.comments', compile('Comments')); - this.register('route:post.loading', Route.extend({ - activate() { - next(loadingEntered.resolve); - } - })); - this.register('template:post.loading', compile('Loading')); - this.register('template:post.likes', compile('Likes')); - this.register('route:post.likes', Route.extend({ - model() { - return resolveLoading.promise; - } - })); - }); + return this.runTaskNext().then(() => { + this.assertText('ApplicationEnginePost'); + done(); + }); + }); - return this.visit('/blog/post/comments').then(() => { - this.assertText('ApplicationEngineComments'); - let transition = this.transitionTo('blog.post.likes'); + return transition; + }); + } + + ['@test loading substate route works for a child route of an Engine']( + assert + ) { + assert.expect(3); + + let resolveLoading; + + this.setupAppAndRoutableEngine(); + this.additionalEngineRegistrations(function() { + this.register('template:post', compile('{{outlet}}')); + this.register('template:post.comments', compile('Comments')); + this.register('template:post.likes_loading', compile('Loading')); + this.register('template:post.likes', compile('Likes')); + this.register( + 'route:post.likes', + Route.extend({ + model() { + return new RSVP.Promise(resolve => { + resolveLoading = resolve; + }); + } + }) + ); + }); - loadingEntered.promise.then(() => { - this.assertText('ApplicationEngineLoading'); - resolveLoading.resolve(); + return this.visit('/blog/post/comments').then(() => { + this.assertText('ApplicationEngineComments'); + let transition = this.transitionTo('blog.post.likes'); - return this.runTaskNext().then(() => { - this.assertText('ApplicationEngineLikes'); - done(); + this.runTaskNext().then(() => { + this.assertText('ApplicationEngineLoading'); + resolveLoading(); }); - }); - return transition; - }); - } + return transition + .then(() => this.runTaskNext()) + .then(() => this.assertText('ApplicationEngineLikes')); + }); + } + + ['@test loading route works for a child route of an Engine'](assert) { + assert.expect(3); + let done = assert.async(); + + let loadingEntered = RSVP.defer(); + let resolveLoading = RSVP.defer(); + + this.setupAppAndRoutableEngine(); + this.additionalEngineRegistrations(function() { + this.register('template:post', compile('{{outlet}}')); + this.register('template:post.comments', compile('Comments')); + this.register( + 'route:post.loading', + Route.extend({ + activate() { + next(loadingEntered.resolve); + } + }) + ); + this.register('template:post.loading', compile('Loading')); + this.register('template:post.likes', compile('Likes')); + this.register( + 'route:post.likes', + Route.extend({ + model() { + return resolveLoading.promise; + } + }) + ); + }); - ['@test query params don\'t have stickiness by default between model'](assert) { - assert.expect(1); - let tmpl = '{{#link-to "blog.category" 1337}}Category 1337{{/link-to}}'; - this.setupAppAndRoutableEngine(); - this.additionalEngineRegistrations(function() { - this.register('template:category', compile(tmpl)); - }); - - return this.visit('/blog/category/1?type=news').then(() => { - let suffix = '/blog/category/1337'; - let href = this.element.querySelector('a').href; - - // check if link ends with the suffix - assert.ok(this.stringsEndWith(href, suffix)); - }); - } + return this.visit('/blog/post/comments').then(() => { + this.assertText('ApplicationEngineComments'); + let transition = this.transitionTo('blog.post.likes'); - ['@test query params in customized controllerName have stickiness by default between model'](assert) { - assert.expect(2); - let tmpl = '{{#link-to "blog.author" 1337 class="author-1337"}}Author 1337{{/link-to}}{{#link-to "blog.author" 1 class="author-1"}}Author 1{{/link-to}}'; - this.setupAppAndRoutableEngine(); - this.additionalEngineRegistrations(function() { - this.register('template:author', compile(tmpl)); - }); - - return this.visit('/blog/author/1?official=true').then(() => { - let suffix1 = '/blog/author/1?official=true'; - let href1 = this.element.querySelector('.author-1').href; - let suffix1337 = '/blog/author/1337'; - let href1337 = this.element.querySelector('.author-1337').href; - - // check if link ends with the suffix - assert.ok(this.stringsEndWith(href1, suffix1), `${href1} ends with ${suffix1}`); - assert.ok(this.stringsEndWith(href1337, suffix1337), `${href1337} ends with ${suffix1337}`); - }); - } + loadingEntered.promise.then(() => { + this.assertText('ApplicationEngineLoading'); + resolveLoading.resolve(); - ['@test visit() routable engine which errors on init'](assert) { - assert.expect(1); + return this.runTaskNext().then(() => { + this.assertText('ApplicationEngineLikes'); + done(); + }); + }); - let hooks = []; + return transition; + }); + } + + ["@test query params don't have stickiness by default between model"]( + assert + ) { + assert.expect(1); + let tmpl = '{{#link-to "blog.category" 1337}}Category 1337{{/link-to}}'; + this.setupAppAndRoutableEngine(); + this.additionalEngineRegistrations(function() { + this.register('template:category', compile(tmpl)); + }); - this.additionalEngineRegistrations(function() { - this.register('route:application', Route.extend({ - init() { - throw new Error('Whoops! Something went wrong...'); - } - })); - }); + return this.visit('/blog/category/1?type=news').then(() => { + let suffix = '/blog/category/1337'; + let href = this.element.querySelector('a').href; - this.setupAppAndRoutableEngine(hooks); + // check if link ends with the suffix + assert.ok(this.stringsEndWith(href, suffix)); + }); + } + + ['@test query params in customized controllerName have stickiness by default between model']( + assert + ) { + assert.expect(2); + let tmpl = + '{{#link-to "blog.author" 1337 class="author-1337"}}Author 1337{{/link-to}}{{#link-to "blog.author" 1 class="author-1"}}Author 1{{/link-to}}'; + this.setupAppAndRoutableEngine(); + this.additionalEngineRegistrations(function() { + this.register('template:author', compile(tmpl)); + }); - return this.visit('/', { shouldRender: true }) - .then(() => { - return this.visit('/blog'); - }) - .catch((error) => { - assert.equal(error.message, 'Whoops! Something went wrong...'); + return this.visit('/blog/author/1?official=true').then(() => { + let suffix1 = '/blog/author/1?official=true'; + let href1 = this.element.querySelector('.author-1').href; + let suffix1337 = '/blog/author/1337'; + let href1337 = this.element.querySelector('.author-1337').href; + + // check if link ends with the suffix + assert.ok( + this.stringsEndWith(href1, suffix1), + `${href1} ends with ${suffix1}` + ); + assert.ok( + this.stringsEndWith(href1337, suffix1337), + `${href1337} ends with ${suffix1337}` + ); }); + } + + ['@test visit() routable engine which errors on init'](assert) { + assert.expect(1); + + let hooks = []; + + this.additionalEngineRegistrations(function() { + this.register( + 'route:application', + Route.extend({ + init() { + throw new Error('Whoops! Something went wrong...'); + } + }) + ); + }); + + this.setupAppAndRoutableEngine(hooks); + + return this.visit('/', { shouldRender: true }) + .then(() => { + return this.visit('/blog'); + }) + .catch(error => { + assert.equal(error.message, 'Whoops! Something went wrong...'); + }); + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/application/rendering-test.js b/packages/ember-glimmer/tests/integration/application/rendering-test.js index 478dc8bdf77..0e8e49da387 100644 --- a/packages/ember-glimmer/tests/integration/application/rendering-test.js +++ b/packages/ember-glimmer/tests/integration/application/rendering-test.js @@ -5,138 +5,167 @@ import { strip } from '../../utils/abstract-test-case'; import { Route } from 'ember-routing'; import { Component } from 'ember-glimmer'; -moduleFor('Application test: rendering', class extends ApplicationTest { - constructor() { - super(); - this._APPLICATION_TEMPLATE_WRAPPER = ENV._APPLICATION_TEMPLATE_WRAPPER; - } - - teardown() { - super.teardown(); - ENV._APPLICATION_TEMPLATE_WRAPPER = this._APPLICATION_TEMPLATE_WRAPPER; - } - - ['@test it can render the application template with a wrapper']() { - ENV._APPLICATION_TEMPLATE_WRAPPER = true; - - this.addTemplate('application', 'Hello world!'); - - return this.visit('/').then(() => { - this.assertComponentElement(this.element, { content: 'Hello world!' }); - }); - } - - ['@test it can render the application template without a wrapper']() { - ENV._APPLICATION_TEMPLATE_WRAPPER = false; - - this.addTemplate('application', 'Hello world!'); +moduleFor( + 'Application test: rendering', + class extends ApplicationTest { + constructor() { + super(); + this._APPLICATION_TEMPLATE_WRAPPER = ENV._APPLICATION_TEMPLATE_WRAPPER; + } + + teardown() { + super.teardown(); + ENV._APPLICATION_TEMPLATE_WRAPPER = this._APPLICATION_TEMPLATE_WRAPPER; + } + + ['@test it can render the application template with a wrapper']() { + ENV._APPLICATION_TEMPLATE_WRAPPER = true; + + this.addTemplate('application', 'Hello world!'); + + return this.visit('/').then(() => { + this.assertComponentElement(this.element, { content: 'Hello world!' }); + }); + } - return this.visit('/').then(() => { - this.assertInnerHTML('Hello world!'); - }); - } + ['@test it can render the application template without a wrapper']() { + ENV._APPLICATION_TEMPLATE_WRAPPER = false; - ['@test it can access the model provided by the route']() { - this.add('route:application', Route.extend({ - model() { - return ['red', 'yellow', 'blue']; - } - })); + this.addTemplate('application', 'Hello world!'); - this.addTemplate('application', strip` + return this.visit('/').then(() => { + this.assertInnerHTML('Hello world!'); + }); + } + + ['@test it can access the model provided by the route']() { + this.add( + 'route:application', + Route.extend({ + model() { + return ['red', 'yellow', 'blue']; + } + }) + ); + + this.addTemplate( + 'application', + strip`
    {{#each model as |item|}}
  • {{item}}
  • {{/each}}
- `); + ` + ); - return this.visit('/').then(() => { - this.assertInnerHTML(strip` + return this.visit('/').then(() => { + this.assertInnerHTML(strip`
  • red
  • yellow
  • blue
`); - }); - } - - ['@test it can render a nested route']() { - this.router.map(function() { - this.route('lists', function() { - this.route('colors', function() { - this.route('favorite'); + }); + } + + ['@test it can render a nested route']() { + this.router.map(function() { + this.route('lists', function() { + this.route('colors', function() { + this.route('favorite'); + }); }); }); - }); - - // The "favorite" route will inherit the model - this.add('route:lists.colors', Route.extend({ - model() { - return ['red', 'yellow', 'blue']; - } - })); - this.addTemplate('lists.colors.favorite', strip` + // The "favorite" route will inherit the model + this.add( + 'route:lists.colors', + Route.extend({ + model() { + return ['red', 'yellow', 'blue']; + } + }) + ); + + this.addTemplate( + 'lists.colors.favorite', + strip`
    {{#each model as |item|}}
  • {{item}}
  • {{/each}}
- `); + ` + ); - return this.visit('/lists/colors/favorite').then(() => { - this.assertInnerHTML(strip` + return this.visit('/lists/colors/favorite').then(() => { + this.assertInnerHTML(strip`
  • red
  • yellow
  • blue
`); - }); - } + }); + } - ['@test it can render into named outlets']() { - this.router.map(function() { - this.route('colors'); - }); + ['@test it can render into named outlets']() { + this.router.map(function() { + this.route('colors'); + }); - this.addTemplate('application', strip` + this.addTemplate( + 'application', + strip`
{{outlet}}
- `); + ` + ); - this.addTemplate('nav', strip` + this.addTemplate( + 'nav', + strip` Ember - `); - - this.add('route:application', Route.extend({ - renderTemplate() { - this.render(); - this.render('nav', { - into: 'application', - outlet: 'nav' - }); - } - })); - - this.add('route:colors', Route.extend({ - model() { - return ['red', 'yellow', 'blue']; - } - })); - - this.addTemplate('colors', strip` + ` + ); + + this.add( + 'route:application', + Route.extend({ + renderTemplate() { + this.render(); + this.render('nav', { + into: 'application', + outlet: 'nav' + }); + } + }) + ); + + this.add( + 'route:colors', + Route.extend({ + model() { + return ['red', 'yellow', 'blue']; + } + }) + ); + + this.addTemplate( + 'colors', + strip`
    {{#each model as |item|}}
  • {{item}}
  • {{/each}}
- `); + ` + ); - return this.visit('/colors').then(() => { - this.assertInnerHTML(strip` + return this.visit('/colors').then(() => { + this.assertInnerHTML(strip` @@ -148,49 +177,64 @@ moduleFor('Application test: rendering', class extends ApplicationTest { `); - }); - } + }); + } - ['@test it can render into named outlets']() { - this.router.map(function() { - this.route('colors'); - }); + ['@test it can render into named outlets']() { + this.router.map(function() { + this.route('colors'); + }); - this.addTemplate('application', strip` + this.addTemplate( + 'application', + strip`
{{outlet}}
- `); + ` + ); - this.addTemplate('nav', strip` + this.addTemplate( + 'nav', + strip` Ember - `); - - this.add('route:application', Route.extend({ - renderTemplate() { - this.render(); - this.render('nav', { - into: 'application', - outlet: 'nav' - }); - } - })); - - this.add('route:colors', Route.extend({ - model() { - return ['red', 'yellow', 'blue']; - } - })); - - this.addTemplate('colors', strip` + ` + ); + + this.add( + 'route:application', + Route.extend({ + renderTemplate() { + this.render(); + this.render('nav', { + into: 'application', + outlet: 'nav' + }); + } + }) + ); + + this.add( + 'route:colors', + Route.extend({ + model() { + return ['red', 'yellow', 'blue']; + } + }) + ); + + this.addTemplate( + 'colors', + strip`
    {{#each model as |item|}}
  • {{item}}
  • {{/each}}
- `); + ` + ); - return this.visit('/colors').then(() => { - this.assertInnerHTML(strip` + return this.visit('/colors').then(() => { + this.assertInnerHTML(strip` @@ -202,217 +246,268 @@ moduleFor('Application test: rendering', class extends ApplicationTest { `); - }); - } + }); + } + + ['@test it should update the outlets when switching between routes']() { + this.router.map(function() { + this.route('a'); + this.route('b', function() { + this.route('c'); + this.route('d'); + }); + }); + + this.addTemplate('a', 'A{{outlet}}'); + this.addTemplate('b', 'B{{outlet}}'); + this.addTemplate('b.c', 'C'); + this.addTemplate('b.d', 'D'); + + return this.visit('/b/c') + .then(() => { + // this.assertComponentElement(this.firstChild, { content: 'BC' }); + this.assertText('BC'); + return this.visit('/a'); + }) + .then(() => { + // this.assertComponentElement(this.firstChild, { content: 'A' }); + this.assertText('A'); + return this.visit('/b/d'); + }) + .then(() => { + this.assertText('BD'); + // this.assertComponentElement(this.firstChild, { content: 'BD' }); + }); + } - ['@test it should update the outlets when switching between routes']() { - this.router.map(function() { - this.route('a'); - this.route('b', function() { - this.route('c'); - this.route('d'); + ['@test it should produce a stable DOM when the model changes']() { + this.router.map(function() { + this.route('color', { path: '/colors/:color' }); }); - }); - - this.addTemplate('a', 'A{{outlet}}'); - this.addTemplate('b', 'B{{outlet}}'); - this.addTemplate('b.c', 'C'); - this.addTemplate('b.d', 'D'); - - return this.visit('/b/c').then(() => { - // this.assertComponentElement(this.firstChild, { content: 'BC' }); - this.assertText('BC'); - return this.visit('/a'); - }).then(() => { - // this.assertComponentElement(this.firstChild, { content: 'A' }); - this.assertText('A'); - return this.visit('/b/d'); - }).then(() => { - this.assertText('BD'); - // this.assertComponentElement(this.firstChild, { content: 'BD' }); - }); - } - ['@test it should produce a stable DOM when the model changes']() { - this.router.map(function() { - this.route('color', { path: '/colors/:color' }); - }); - - this.add('route:color', Route.extend({ - model(params) { - return params.color; - } - })); - - this.addTemplate('color', 'color: {{model}}'); - - return this.visit('/colors/red').then(() => { - this.assertInnerHTML('color: red'); - this.takeSnapshot(); - return this.visit('/colors/green'); - }).then(() => { - this.assertInnerHTML('color: green'); - this.assertInvariants(); - }); - } + this.add( + 'route:color', + Route.extend({ + model(params) { + return params.color; + } + }) + ); + + this.addTemplate('color', 'color: {{model}}'); + + return this.visit('/colors/red') + .then(() => { + this.assertInnerHTML('color: red'); + this.takeSnapshot(); + return this.visit('/colors/green'); + }) + .then(() => { + this.assertInnerHTML('color: green'); + this.assertInvariants(); + }); + } - ['@test it should have the right controller in scope for the route template']() { - this.router.map(function() { - this.route('a'); - this.route('b'); - }); + ['@test it should have the right controller in scope for the route template']() { + this.router.map(function() { + this.route('a'); + this.route('b'); + }); - this.add('controller:a', Controller.extend({ - value: 'a' - })); + this.add( + 'controller:a', + Controller.extend({ + value: 'a' + }) + ); + + this.add( + 'controller:b', + Controller.extend({ + value: 'b' + }) + ); + + this.addTemplate('a', '{{value}}'); + this.addTemplate('b', '{{value}}'); + + return this.visit('/a') + .then(() => { + this.assertText('a'); + return this.visit('/b'); + }) + .then(() => this.assertText('b')); + } + + ['@test it should update correctly when the controller changes']() { + this.router.map(function() { + this.route('color', { path: '/colors/:color' }); + }); - this.add('controller:b', Controller.extend({ - value: 'b' - })); + this.add( + 'route:color', + Route.extend({ + model(params) { + return { color: params.color }; + }, + + renderTemplate(controller, model) { + this.render({ controller: model.color, model }); + } + }) + ); + + this.add( + 'controller:red', + Controller.extend({ + color: 'red' + }) + ); + + this.add( + 'controller:green', + Controller.extend({ + color: 'green' + }) + ); + + this.addTemplate( + 'color', + 'model color: {{model.color}}, controller color: {{color}}' + ); + + return this.visit('/colors/red') + .then(() => { + this.assertInnerHTML('model color: red, controller color: red'); + return this.visit('/colors/green'); + }) + .then(() => { + this.assertInnerHTML('model color: green, controller color: green'); + }); + } - this.addTemplate('a', '{{value}}'); - this.addTemplate('b', '{{value}}'); + ['@test it should produce a stable DOM when two routes render the same template']() { + this.router.map(function() { + this.route('a'); + this.route('b'); + }); - return this.visit('/a').then(() => { - this.assertText('a'); - return this.visit('/b'); - }).then(() => this.assertText('b')); - } + this.add( + 'route:a', + Route.extend({ + model() { + return 'A'; + }, + + renderTemplate(controller, model) { + this.render('common', { controller: 'common', model }); + } + }) + ); + + this.add( + 'route:b', + Route.extend({ + model() { + return 'B'; + }, + + renderTemplate(controller, model) { + this.render('common', { controller: 'common', model }); + } + }) + ); + + this.add( + 'controller:common', + Controller.extend({ + prefix: 'common' + }) + ); + + this.addTemplate('common', '{{prefix}} {{model}}'); + + return this.visit('/a') + .then(() => { + this.assertInnerHTML('common A'); + this.takeSnapshot(); + return this.visit('/b'); + }) + .then(() => { + this.assertInnerHTML('common B'); + this.assertInvariants(); + }); + } + + // Regression test, glimmer child outlets tried to assume the first element. + // but the if put-args clobbered the args used by did-create-element. + // I wish there was a way to assert that the OutletComponentManager did not + // receive a didCreateElement. + ['@test a child outlet is always a fragment']() { + this.addTemplate('application', '{{outlet}}'); + this.addTemplate('index', '{{#if true}}1{{/if}}
2
'); + return this.visit('/').then(() => { + this.assertInnerHTML('1
2
'); + }); + } - ['@test it should update correctly when the controller changes']() { - this.router.map(function() { - this.route('color', { path: '/colors/:color' }); - }); - - this.add('route:color', Route.extend({ - model(params) { - return { color: params.color }; - }, - - renderTemplate(controller, model) { - this.render({ controller: model.color, model }); - } - })); - - this.add('controller:red', Controller.extend({ - color: 'red' - })); - - this.add('controller:green', Controller.extend({ - color: 'green' - })); - - this.addTemplate('color', 'model color: {{model.color}}, controller color: {{color}}'); - - return this.visit('/colors/red').then(() => { - this.assertInnerHTML('model color: red, controller color: red'); - return this.visit('/colors/green'); - }).then(() => { - this.assertInnerHTML('model color: green, controller color: green'); - }); - } + ['@test it allows a transition during route activate']() { + this.router.map(function() { + this.route('a'); + }); - ['@test it should produce a stable DOM when two routes render the same template']() { - this.router.map(function() { - this.route('a'); - this.route('b'); - }); - - this.add('route:a', Route.extend({ - model() { - return 'A'; - }, - - renderTemplate(controller, model) { - this.render('common', { controller: 'common', model }); - } - })); - - this.add('route:b', Route.extend({ - model() { - return 'B'; - }, - - renderTemplate(controller, model) { - this.render('common', { controller: 'common', model }); - } - })); - - this.add('controller:common', Controller.extend({ - prefix: 'common' - })); - - this.addTemplate('common', '{{prefix}} {{model}}'); - - return this.visit('/a').then(() => { - this.assertInnerHTML('common A'); - this.takeSnapshot(); - return this.visit('/b'); - }).then(() => { - this.assertInnerHTML('common B'); - this.assertInvariants(); - }); - } + this.add( + 'route:index', + Route.extend({ + activate() { + this.transitionTo('a'); + } + }) + ); - // Regression test, glimmer child outlets tried to assume the first element. - // but the if put-args clobbered the args used by did-create-element. - // I wish there was a way to assert that the OutletComponentManager did not - // receive a didCreateElement. - ['@test a child outlet is always a fragment']() { - this.addTemplate('application', '{{outlet}}'); - this.addTemplate('index', '{{#if true}}1{{/if}}
2
'); - return this.visit('/').then(() => { - this.assertInnerHTML('1
2
'); - }); - } + this.addTemplate('a', 'Hello from A!'); - ['@test it allows a transition during route activate']() { - this.router.map(function() { - this.route('a'); - }); + return this.visit('/').then(() => { + this.assertInnerHTML('Hello from A!'); + }); + } - this.add('route:index', Route.extend({ - activate() { - this.transitionTo('a'); - } - })); + ['@test it emits a useful backtracking re-render assertion message']() { + this.router.map(function() { + this.route('routeWithError'); + }); - this.addTemplate('a', 'Hello from A!'); + this.add( + 'route:routeWithError', + Route.extend({ + model() { + return { name: 'Alex' }; + } + }) + ); + + this.addTemplate( + 'routeWithError', + 'Hi {{model.name}} {{x-foo person=model}}' + ); + + this.addComponent('x-foo', { + ComponentClass: Component.extend({ + init() { + this._super(...arguments); + this.set('person.name', 'Ben'); + } + }), + template: 'Hi {{person.name}} from component' + }); - return this.visit('/').then(() => { - this.assertInnerHTML('Hello from A!'); - }); - } + let expectedBacktrackingMessage = /modified "model\.name" twice on \[object Object\] in a single render\. It was rendered in "template:my-app\/templates\/routeWithError.hbs" and modified in "component:x-foo"/; - ['@test it emits a useful backtracking re-render assertion message']() { - this.router.map(function() { - this.route('routeWithError'); - }); - - this.add('route:routeWithError', Route.extend({ - model() { - return { name: 'Alex' }; - } - })); - - this.addTemplate('routeWithError', 'Hi {{model.name}} {{x-foo person=model}}'); - - this.addComponent('x-foo', { - ComponentClass: Component.extend({ - init() { - this._super(...arguments); - this.set('person.name', 'Ben'); - } - }), - template: 'Hi {{person.name}} from component' - }); - - let expectedBacktrackingMessage = /modified "model\.name" twice on \[object Object\] in a single render\. It was rendered in "template:my-app\/templates\/routeWithError.hbs" and modified in "component:x-foo"/; - - return this.visit('/').then(() => { - expectAssertion(() => { - this.visit('/routeWithError'); - }, expectedBacktrackingMessage); - }); + return this.visit('/').then(() => { + expectAssertion(() => { + this.visit('/routeWithError'); + }, expectedBacktrackingMessage); + }); + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/components/append-test.js b/packages/ember-glimmer/tests/integration/components/append-test.js index b964616527d..04f5400ac2d 100644 --- a/packages/ember-glimmer/tests/integration/components/append-test.js +++ b/packages/ember-glimmer/tests/integration/components/append-test.js @@ -4,7 +4,6 @@ import { Component, compile } from '../../utils/helpers'; import { strip } from '../../utils/abstract-test-case'; class AbstractAppendTest extends RenderingTest { - constructor() { super(); @@ -21,7 +20,9 @@ class AbstractAppendTest extends RenderingTest { this.ids.forEach(id => { let $element = document.getElementById(id); - if ($element) { $element.parentNode.removeChild($element); } + if ($element) { + $element.parentNode.removeChild($element); + } // this.assert.strictEqual($element.length, 0, `Should not leak element: #${id}`); }); @@ -52,7 +53,9 @@ class AbstractAppendTest extends RenderingTest { init() { this._super(...arguments); if (name in componentsByName) { - throw new TypeError('Component named: ` ' + name + ' ` already registered'); + throw new TypeError( + 'Component named: ` ' + name + ' ` already registered' + ); } componentsByName[name] = this; pushHook('init'); @@ -119,7 +122,8 @@ class AbstractAppendTest extends RenderingTest { layoutName: 'components/x-parent' }), - template: '[parent: {{foo}}]{{#x-child bar=foo}}[yielded: {{foo}}]{{/x-child}}' + template: + '[parent: {{foo}}]{{#x-child bar=foo}}[yielded: {{foo}}]{{/x-child}}' }); this.registerComponent('x-child', { @@ -136,120 +140,145 @@ class AbstractAppendTest extends RenderingTest { this.component = XParent.create({ foo: 'zomg' }); - assert.deepEqual(hooks, [ - ['x-parent', 'init'], - ['x-parent', 'on(init)'] - ], 'creation of x-parent'); + assert.deepEqual( + hooks, + [['x-parent', 'init'], ['x-parent', 'on(init)']], + 'creation of x-parent' + ); hooks.length = 0; this.element = this.append(this.component); - assert.deepEqual(hooks, [ - ['x-parent', 'willInsertElement'], + assert.deepEqual( + hooks, + [ + ['x-parent', 'willInsertElement'], - ['x-child', 'init'], - ['x-child', 'on(init)'], - ['x-child', 'didReceiveAttrs'], - ['x-child', 'willRender'], - ['x-child', 'willInsertElement'], + ['x-child', 'init'], + ['x-child', 'on(init)'], + ['x-child', 'didReceiveAttrs'], + ['x-child', 'willRender'], + ['x-child', 'willInsertElement'], - ['x-child', 'didInsertElement'], - ['x-child', 'didRender'], + ['x-child', 'didInsertElement'], + ['x-child', 'didRender'], - ['x-parent', 'didInsertElement'], - ['x-parent', 'didRender'] - ], 'appending of x-parent'); + ['x-parent', 'didInsertElement'], + ['x-parent', 'didRender'] + ], + 'appending of x-parent' + ); hooks.length = 0; this.runTask(() => componentsByName['x-parent'].rerender()); - assert.deepEqual(hooks, [ - ['x-parent', 'willUpdate'], - ['x-parent', 'willRender'], + assert.deepEqual( + hooks, + [ + ['x-parent', 'willUpdate'], + ['x-parent', 'willRender'], - ['x-parent', 'didUpdate'], - ['x-parent', 'didRender'] - ], 'rerender x-parent'); + ['x-parent', 'didUpdate'], + ['x-parent', 'didRender'] + ], + 'rerender x-parent' + ); hooks.length = 0; this.runTask(() => componentsByName['x-child'].rerender()); - assert.deepEqual(hooks, [ - ['x-parent', 'willUpdate'], - ['x-parent', 'willRender'], + assert.deepEqual( + hooks, + [ + ['x-parent', 'willUpdate'], + ['x-parent', 'willRender'], - ['x-child', 'willUpdate'], - ['x-child', 'willRender'], + ['x-child', 'willUpdate'], + ['x-child', 'willRender'], - ['x-child', 'didUpdate'], - ['x-child', 'didRender'], + ['x-child', 'didUpdate'], + ['x-child', 'didRender'], - ['x-parent', 'didUpdate'], - ['x-parent', 'didRender'] - ], 'rerender x-child'); + ['x-parent', 'didUpdate'], + ['x-parent', 'didRender'] + ], + 'rerender x-child' + ); hooks.length = 0; this.runTask(() => set(this.component, 'foo', 'wow')); - assert.deepEqual(hooks, [ - ['x-parent', 'willUpdate'], - ['x-parent', 'willRender'], + assert.deepEqual( + hooks, + [ + ['x-parent', 'willUpdate'], + ['x-parent', 'willRender'], - ['x-child', 'didUpdateAttrs'], - ['x-child', 'didReceiveAttrs'], + ['x-child', 'didUpdateAttrs'], + ['x-child', 'didReceiveAttrs'], - ['x-child', 'willUpdate'], - ['x-child', 'willRender'], + ['x-child', 'willUpdate'], + ['x-child', 'willRender'], - ['x-child', 'didUpdate'], - ['x-child', 'didRender'], + ['x-child', 'didUpdate'], + ['x-child', 'didRender'], - ['x-parent', 'didUpdate'], - ['x-parent', 'didRender'] - ], 'set foo = wow'); + ['x-parent', 'didUpdate'], + ['x-parent', 'didRender'] + ], + 'set foo = wow' + ); hooks.length = 0; this.runTask(() => set(this.component, 'foo', 'zomg')); - assert.deepEqual(hooks, [ - ['x-parent', 'willUpdate'], - ['x-parent', 'willRender'], + assert.deepEqual( + hooks, + [ + ['x-parent', 'willUpdate'], + ['x-parent', 'willRender'], - ['x-child', 'didUpdateAttrs'], - ['x-child', 'didReceiveAttrs'], + ['x-child', 'didUpdateAttrs'], + ['x-child', 'didReceiveAttrs'], - ['x-child', 'willUpdate'], - ['x-child', 'willRender'], + ['x-child', 'willUpdate'], + ['x-child', 'willRender'], - ['x-child', 'didUpdate'], - ['x-child', 'didRender'], + ['x-child', 'didUpdate'], + ['x-child', 'didRender'], - ['x-parent', 'didUpdate'], - ['x-parent', 'didRender'] - ], 'set foo = zomg'); + ['x-parent', 'didUpdate'], + ['x-parent', 'didRender'] + ], + 'set foo = zomg' + ); hooks.length = 0; this.runTask(() => this.component.destroy()); - assert.deepEqual(hooks, [ - ['x-parent', 'willDestroyElement'], - ['x-parent', 'willClearRender'], + assert.deepEqual( + hooks, + [ + ['x-parent', 'willDestroyElement'], + ['x-parent', 'willClearRender'], - ['x-child', 'willDestroyElement'], - ['x-child', 'willClearRender'], + ['x-child', 'willDestroyElement'], + ['x-child', 'willClearRender'], - ['x-child', 'didDestroyElement'], - ['x-parent', 'didDestroyElement'], + ['x-child', 'didDestroyElement'], + ['x-parent', 'didDestroyElement'], - ['x-parent', 'willDestroy'], - ['x-child', 'willDestroy'] - ], 'destroy'); + ['x-parent', 'willDestroy'], + ['x-child', 'willDestroy'] + ], + 'destroy' + ); } ['@test appending, updating and destroying a single component'](assert) { @@ -263,7 +292,8 @@ class AbstractAppendTest extends RenderingTest { } }), - template: '[parent: {{foo}}]{{#x-child bar=foo}}[yielded: {{foo}}]{{/x-child}}' + template: + '[parent: {{foo}}]{{#x-child bar=foo}}[yielded: {{foo}}]{{/x-child}}' }); this.registerComponent('x-child', { @@ -286,32 +316,59 @@ class AbstractAppendTest extends RenderingTest { let componentElement = this.component.element; - this.assertComponentElement(componentElement, { content: '[parent: zomg][child: zomg][yielded: zomg]' }); + this.assertComponentElement(componentElement, { + content: '[parent: zomg][child: zomg][yielded: zomg]' + }); - assert.equal(componentElement.parentElement, this.element, 'It should be attached to the target'); + assert.equal( + componentElement.parentElement, + this.element, + 'It should be attached to the target' + ); this.runTask(() => this.rerender()); - this.assertComponentElement(componentElement, { content: '[parent: zomg][child: zomg][yielded: zomg]' }); + this.assertComponentElement(componentElement, { + content: '[parent: zomg][child: zomg][yielded: zomg]' + }); - assert.equal(componentElement.parentElement, this.element, 'It should be attached to the target'); + assert.equal( + componentElement.parentElement, + this.element, + 'It should be attached to the target' + ); this.runTask(() => set(this.component, 'foo', 'wow')); - this.assertComponentElement(componentElement, { content: '[parent: wow][child: wow][yielded: wow]' }); + this.assertComponentElement(componentElement, { + content: '[parent: wow][child: wow][yielded: wow]' + }); - assert.equal(componentElement.parentElement, this.element, 'It should be attached to the target'); + assert.equal( + componentElement.parentElement, + this.element, + 'It should be attached to the target' + ); this.runTask(() => set(this.component, 'foo', 'zomg')); - this.assertComponentElement(componentElement, { content: '[parent: zomg][child: zomg][yielded: zomg]' }); + this.assertComponentElement(componentElement, { + content: '[parent: zomg][child: zomg][yielded: zomg]' + }); - assert.equal(componentElement.parentElement, this.element, 'It should be attached to the target'); + assert.equal( + componentElement.parentElement, + this.element, + 'It should be attached to the target' + ); this.runTask(() => this.component.destroy()); assert.ok(!this.component.element, 'It should not have an element'); - assert.ok(!componentElement.parentElement, 'The component element should be detached'); + assert.ok( + !componentElement.parentElement, + 'The component element should be detached' + ); this.assert.equal(willDestroyCalled, 1); } @@ -373,33 +430,63 @@ class AbstractAppendTest extends RenderingTest { let wrapper1, wrapper2; - this.runTask(() => wrapper1 = this.append(first)); - this.runTask(() => wrapper2 = this.append(second)); + this.runTask(() => (wrapper1 = this.append(first))); + this.runTask(() => (wrapper2 = this.append(second))); let componentElement1 = first.element; let componentElement2 = second.element; this.assertComponentElement(componentElement1, { content: 'x-first foo!' }); - this.assertComponentElement(componentElement2, { content: 'x-second bar!' }); + this.assertComponentElement(componentElement2, { + content: 'x-second bar!' + }); - assert.equal(componentElement1.parentElement, wrapper1, 'The first component should be attached to the target'); - assert.equal(componentElement2.parentElement, wrapper2, 'The second component should be attached to the target'); + assert.equal( + componentElement1.parentElement, + wrapper1, + 'The first component should be attached to the target' + ); + assert.equal( + componentElement2.parentElement, + wrapper2, + 'The second component should be attached to the target' + ); this.runTask(() => set(first, 'foo', 'FOO')); this.assertComponentElement(componentElement1, { content: 'x-first FOO!' }); - this.assertComponentElement(componentElement2, { content: 'x-second bar!' }); + this.assertComponentElement(componentElement2, { + content: 'x-second bar!' + }); - assert.equal(componentElement1.parentElement, wrapper1, 'The first component should be attached to the target'); - assert.equal(componentElement2.parentElement, wrapper2, 'The second component should be attached to the target'); + assert.equal( + componentElement1.parentElement, + wrapper1, + 'The first component should be attached to the target' + ); + assert.equal( + componentElement2.parentElement, + wrapper2, + 'The second component should be attached to the target' + ); this.runTask(() => set(second, 'bar', 'BAR')); this.assertComponentElement(componentElement1, { content: 'x-first FOO!' }); - this.assertComponentElement(componentElement2, { content: 'x-second BAR!' }); + this.assertComponentElement(componentElement2, { + content: 'x-second BAR!' + }); - assert.equal(componentElement1.parentElement, wrapper1, 'The first component should be attached to the target'); - assert.equal(componentElement2.parentElement, wrapper2, 'The second component should be attached to the target'); + assert.equal( + componentElement1.parentElement, + wrapper1, + 'The first component should be attached to the target' + ); + assert.equal( + componentElement2.parentElement, + wrapper2, + 'The second component should be attached to the target' + ); this.runTask(() => { set(first, 'foo', 'foo'); @@ -407,10 +494,20 @@ class AbstractAppendTest extends RenderingTest { }); this.assertComponentElement(componentElement1, { content: 'x-first foo!' }); - this.assertComponentElement(componentElement2, { content: 'x-second bar!' }); + this.assertComponentElement(componentElement2, { + content: 'x-second bar!' + }); - assert.equal(componentElement1.parentElement, wrapper1, 'The first component should be attached to the target'); - assert.equal(componentElement2.parentElement, wrapper2, 'The second component should be attached to the target'); + assert.equal( + componentElement1.parentElement, + wrapper1, + 'The first component should be attached to the target' + ); + assert.equal( + componentElement2.parentElement, + wrapper2, + 'The second component should be attached to the target' + ); this.runTask(() => { first.destroy(); @@ -418,10 +515,19 @@ class AbstractAppendTest extends RenderingTest { }); assert.ok(!first.element, 'The first component should not have an element'); - assert.ok(!second.element, 'The second component should not have an element'); - - assert.ok(!componentElement1.parentElement, 'The first component element should be detached'); - assert.ok(!componentElement2.parentElement, 'The second component element should be detached'); + assert.ok( + !second.element, + 'The second component should not have an element' + ); + + assert.ok( + !componentElement1.parentElement, + 'The first component element should be detached' + ); + assert.ok( + !componentElement2.parentElement, + 'The second component element should be detached' + ); this.assert.equal(willDestroyCalled, 2); } @@ -429,7 +535,7 @@ class AbstractAppendTest extends RenderingTest { ['@test can appendTo while rendering']() { let owner = this.owner; - let append = (component) => { + let append = component => { return this.append(component); }; @@ -469,7 +575,7 @@ class AbstractAppendTest extends RenderingTest { ['@test can appendTo and remove while rendering'](assert) { let owner = this.owner; - let append = (component) => { + let append = component => { return this.append(component); }; @@ -548,15 +654,18 @@ class AbstractAppendTest extends RenderingTest { }) }); - this.render(strip` + this.render( + strip` {{#if showFooBar}} {{foo-bar}} {{else}} {{baz-qux}} {{/if}} - `, { showFooBar: true }); + `, + { showFooBar: true } + ); - this.assertComponentElement(element1, { }); + this.assertComponentElement(element1, {}); this.assertComponentElement(element2, { content: 'fake-thing: 0' }); assert.equal(instantiatedRoots, 1); @@ -567,7 +676,7 @@ class AbstractAppendTest extends RenderingTest { assert.equal(instantiatedRoots, 2); assert.equal(destroyedRoots, 1); - this.assertComponentElement(element3, { }); + this.assertComponentElement(element3, {}); this.assertComponentElement(element4, { content: 'fake-thing: 1' }); this.runTask(() => { @@ -578,68 +687,80 @@ class AbstractAppendTest extends RenderingTest { assert.equal(instantiatedRoots, 2); assert.equal(destroyedRoots, 2); } - } -moduleFor('append: no arguments (attaching to document.body)', class extends AbstractAppendTest { - - append(component) { - this.runTask(() => component.append()); - this.didAppend(component); - return document.body; - } - -}); - -moduleFor('appendTo: a selector', class extends AbstractAppendTest { - - append(component) { - this.runTask(() => component.appendTo('#qunit-fixture')); - this.didAppend(component); - return document.getElementById('qunit-fixture'); +moduleFor( + 'append: no arguments (attaching to document.body)', + class extends AbstractAppendTest { + append(component) { + this.runTask(() => component.append()); + this.didAppend(component); + return document.body; + } } +); + +moduleFor( + 'appendTo: a selector', + class extends AbstractAppendTest { + append(component) { + this.runTask(() => component.appendTo('#qunit-fixture')); + this.didAppend(component); + return document.getElementById('qunit-fixture'); + } + + ['@test raises an assertion when the target does not exist in the DOM']( + assert + ) { + this.registerComponent('foo-bar', { + ComponentClass: Component.extend({ + layoutName: 'components/foo-bar' + }), + template: 'FOO BAR!' + }); - ['@test raises an assertion when the target does not exist in the DOM'](assert) { - this.registerComponent('foo-bar', { - ComponentClass: Component.extend({ - layoutName: 'components/foo-bar' - }), - template: 'FOO BAR!' - }); - - let FooBar = this.owner.factoryFor('component:foo-bar'); + let FooBar = this.owner.factoryFor('component:foo-bar'); - this.component = FooBar.create(); + this.component = FooBar.create(); - assert.ok(!this.component.element, 'precond - should not have an element'); + assert.ok( + !this.component.element, + 'precond - should not have an element' + ); - this.runTask(() => { - expectAssertion(() => { - this.component.appendTo('#does-not-exist-in-dom'); - }, /You tried to append to \(#does-not-exist-in-dom\) but that isn't in the DOM/); - }); + this.runTask(() => { + expectAssertion(() => { + this.component.appendTo('#does-not-exist-in-dom'); + }, /You tried to append to \(#does-not-exist-in-dom\) but that isn't in the DOM/); + }); - assert.ok(!this.component.element, 'component should not have an element'); + assert.ok( + !this.component.element, + 'component should not have an element' + ); + } } - -}); - -moduleFor('appendTo: an element', class extends AbstractAppendTest { - - append(component) { - let element = document.getElementById('qunit-fixture'); - this.runTask(() => component.appendTo(element)); - this.didAppend(component); - return element; +); + +moduleFor( + 'appendTo: an element', + class extends AbstractAppendTest { + append(component) { + let element = document.getElementById('qunit-fixture'); + this.runTask(() => component.appendTo(element)); + this.didAppend(component); + return element; + } } - -}); - -moduleFor('appendTo: with multiple components', class extends AbstractAppendTest { - - append(component) { - this.runTask(() => component.appendTo('#qunit-fixture')); - this.didAppend(component); - return document.getElementById('qunit-fixture'); +); + +moduleFor( + 'appendTo: with multiple components', + class extends AbstractAppendTest { + append(component) { + this.runTask(() => component.appendTo('#qunit-fixture')); + this.didAppend(component); + return document.getElementById('qunit-fixture'); + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/components/attribute-bindings-test.js b/packages/ember-glimmer/tests/integration/components/attribute-bindings-test.js index f2b15d34047..3f1bf9c3d22 100644 --- a/packages/ember-glimmer/tests/integration/components/attribute-bindings-test.js +++ b/packages/ember-glimmer/tests/integration/components/attribute-bindings-test.js @@ -3,595 +3,973 @@ import { Component } from '../../utils/helpers'; import { strip } from '../../utils/abstract-test-case'; import { set } from 'ember-metal'; -moduleFor('Attribute bindings integration', class extends RenderingTest { - ['@test it can have attribute bindings']() { - let FooBarComponent = Component.extend({ - attributeBindings: ['foo:data-foo', 'bar:data-bar'] - }); +moduleFor( + 'Attribute bindings integration', + class extends RenderingTest { + ['@test it can have attribute bindings']() { + let FooBarComponent = Component.extend({ + attributeBindings: ['foo:data-foo', 'bar:data-bar'] + }); + + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); + + this.render('{{foo-bar foo=foo bar=bar}}', { foo: 'foo', bar: 'bar' }); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { 'data-foo': 'foo', 'data-bar': 'bar' }, + content: 'hello' + }); + + this.runTask(() => this.rerender()); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { 'data-foo': 'foo', 'data-bar': 'bar' }, + content: 'hello' + }); + + this.runTask(() => { + set(this.context, 'foo', 'FOO'); + set(this.context, 'bar', undefined); + }); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { 'data-foo': 'FOO' }, + content: 'hello' + }); + + this.runTask(() => { + set(this.context, 'foo', 'foo'); + set(this.context, 'bar', 'bar'); + }); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { 'data-foo': 'foo', 'data-bar': 'bar' }, + content: 'hello' + }); + } + + ['@test it can have attribute bindings with attrs']() { + let FooBarComponent = Component.extend({ + attributeBindings: ['attrs.foo:data-foo', 'attrs.baz.bar:data-bar'] + }); + + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); + + this.render('{{foo-bar foo=model.foo baz=model.baz}}', { + model: { foo: undefined, baz: { bar: 'bar' } } + }); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + content: 'hello', + attrs: { 'data-bar': 'bar' } + }); + + this.runTask(() => this.rerender()); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + content: 'hello', + attrs: { 'data-bar': 'bar' } + }); + + this.runTask(() => { + set(this.context, 'model.foo', 'foo'); + set(this.context, 'model.baz.bar', undefined); + }); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { 'data-foo': 'foo' }, + content: 'hello' + }); + + this.runTask(() => + set(this.context, 'model', { + foo: undefined, + baz: { bar: 'bar' } + }) + ); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + content: 'hello', + attrs: { 'data-bar': 'bar' } + }); + } + + ['@test it can have attribute bindings with a nested path']() { + let FooBarComponent = Component.extend({ + attributeBindings: ['foo.bar:data-foo-bar'] + }); + + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); - - this.render('{{foo-bar foo=foo bar=bar}}', { foo: 'foo', bar: 'bar' }); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'data-foo': 'foo', 'data-bar': 'bar' }, content: 'hello' }); - - this.runTask(() => this.rerender()); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'data-foo': 'foo', 'data-bar': 'bar' }, content: 'hello' }); - - this.runTask(() => { - set(this.context, 'foo', 'FOO'); - set(this.context, 'bar', undefined); - }); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'data-foo': 'FOO' }, content: 'hello' }); - - this.runTask(() => { - set(this.context, 'foo', 'foo'); - set(this.context, 'bar', 'bar'); - }); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'data-foo': 'foo', 'data-bar': 'bar' }, content: 'hello' }); - } - - ['@test it can have attribute bindings with attrs']() { - let FooBarComponent = Component.extend({ - attributeBindings: ['attrs.foo:data-foo', 'attrs.baz.bar:data-bar'] - }); - - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); - - this.render('{{foo-bar foo=model.foo baz=model.baz}}', { - model: { foo: undefined, baz: { bar: 'bar' } } - }); - - this.assertComponentElement(this.firstChild, { tagName: 'div', content: 'hello', attrs: { 'data-bar': 'bar' } }); - - this.runTask(() => this.rerender()); - - this.assertComponentElement(this.firstChild, { tagName: 'div', content: 'hello', attrs: { 'data-bar': 'bar' } }); - - this.runTask(() => { - set(this.context, 'model.foo', 'foo'); - set(this.context, 'model.baz.bar', undefined); - }); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'data-foo': 'foo' }, content: 'hello' }); - - this.runTask(() => set(this.context, 'model', { - foo: undefined, baz: { bar: 'bar' } - })); - - this.assertComponentElement(this.firstChild, { tagName: 'div', content: 'hello', attrs: { 'data-bar': 'bar' } }); - } - - ['@test it can have attribute bindings with a nested path']() { - let FooBarComponent = Component.extend({ - attributeBindings: ['foo.bar:data-foo-bar'] - }); - - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); - - this.render('{{foo-bar foo=foo}}', { foo: { bar: 'foo-bar' } }); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'data-foo-bar': 'foo-bar' }, content: 'hello' }); - - this.runTask(() => this.rerender()); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'data-foo-bar': 'foo-bar' }, content: 'hello' }); - - this.runTask(() => set(this.context, 'foo.bar', 'FOO-BAR')); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'data-foo-bar': 'FOO-BAR' }, content: 'hello' }); - - this.runTask(() => set(this.context, 'foo.bar', undefined)); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { }, content: 'hello' }); - - this.runTask(() => set(this.context, 'foo', undefined)); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { }, content: 'hello' }); - - this.runTask(() => set(this.context, 'foo', { bar: 'foo-bar' })); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'data-foo-bar': 'foo-bar' }, content: 'hello' }); - } - - ['@test handles non-microsyntax attributeBindings']() { - let FooBarComponent = Component.extend({ - attributeBindings: ['type'] - }); - - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); - - this.render('{{foo-bar type=submit}}', { - submit: 'submit' - }); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { type: 'submit' }, content: 'hello' }); - - this.runTask(() => this.rerender()); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { type: 'submit' }, content: 'hello' }); - - this.runTask(() => set(this.context, 'submit', 'password')); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { type: 'password' }, content: 'hello' }); - - this.runTask(() => set(this.context, 'submit', null)); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { }, content: 'hello' }); - - this.runTask(() => set(this.context, 'submit', 'submit')); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { type: 'submit' }, content: 'hello' }); - } - - ['@test non-microsyntax attributeBindings cannot contain nested paths']() { - let FooBarComponent = Component.extend({ - attributeBindings: ['foo.bar'] - }); - - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); - - expectAssertion(() => { this.render('{{foo-bar foo=foo}}', { foo: { bar: 'foo-bar' } }); - }, /Illegal attributeBinding: 'foo.bar' is not a valid attribute name./); - } - - ['@test normalizes attributeBindings for property names']() { - let FooBarComponent = Component.extend({ - attributeBindings: ['tiTLe'] - }); - - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); - - this.render('{{foo-bar tiTLe=name}}', { - name: 'qux' - }); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { title: 'qux' }, content: 'hello' }); - - this.assertStableRerender(); - - this.runTask(() => set(this.context, 'name', null)); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: {}, content: 'hello' }); - - this.runTask(() => set(this.context, 'name', 'qux')); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { title: 'qux' }, content: 'hello' }); - } - - ['@test normalizes attributeBindings for attribute names']() { - let FooBarComponent = Component.extend({ - attributeBindings: ['foo:data-FOO'] - }); - - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); - - this.render('{{foo-bar foo=foo}}', { - foo: 'qux' - }); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'data-foo': 'qux' }, content: 'hello' }); - - this.assertStableRerender(); - - this.runTask(() => set(this.context, 'foo', null)); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: {}, content: 'hello' }); - - this.runTask(() => set(this.context, 'foo', 'qux')); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'data-foo': 'qux' }, content: 'hello' }); - } - - ['@test attributeBindings handles null/undefined']() { - let FooBarComponent = Component.extend({ - attributeBindings: ['fizz', 'bar'] - }); - - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); - - this.render('{{foo-bar fizz=fizz bar=bar}}', { - fizz: null, - bar: undefined - }); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: {}, content: 'hello' }); - - this.runTask(() => this.rerender()); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: {}, content: 'hello' }); - - this.runTask(() => { - set(this.context, 'fizz', 'fizz'); - set(this.context, 'bar', 'bar'); - }); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { fizz: 'fizz', bar: 'bar' }, content: 'hello' }); - - this.runTask(() => { - set(this.context, 'fizz', null); - set(this.context, 'bar', undefined); - }); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: {}, content: 'hello' }); - } - - ['@test attributeBindings handles number value']() { - let FooBarComponent = Component.extend({ - attributeBindings: ['size'] - }); - - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); - - this.render('{{foo-bar size=size}}', { - size: 21 - }); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { size: '21' }, content: 'hello' }); - - this.runTask(() => this.rerender()); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { size: '21' }, content: 'hello' }); - - this.runTask(() => set(this.context, 'size', 0)); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { size: '0' }, content: 'hello' }); - - this.runTask(() => set(this.context, 'size', 21)); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { size: '21' }, content: 'hello' }); - } - - ['@test handles internal and external changes']() { - let component; - let FooBarComponent = Component.extend({ - attributeBindings: ['type'], - type: 'password', - init() { - this._super(...arguments); - component = this; - } - }); - - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); - - this.render('{{foo-bar}}'); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { type: 'password' }, content: 'hello' }); - - this.runTask(() => this.rerender()); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { type: 'password' }, content: 'hello' }); - - this.runTask(() => set(component, 'type', 'checkbox')); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { type: 'checkbox' }, content: 'hello' }); - - this.runTask(() => set(component, 'type', 'password')); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { type: 'password' }, content: 'hello' }); - } - - ['@test can set attributeBindings on component with a different tagName']() { - let FooBarComponent = Component.extend({ - tagName: 'input', - attributeBindings: ['type', 'isDisabled:disabled'] - }); - - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent }); - - this.render('{{foo-bar type=type isDisabled=disabled}}', { - type: 'password', - disabled: false - }); - - this.assertComponentElement(this.firstChild, { tagName: 'input', attrs: { type: 'password' } }); - - this.runTask(() => this.rerender()); - - this.assertComponentElement(this.firstChild, { tagName: 'input', attrs: { type: 'password' } }); - - this.runTask(() => { - set(this.context, 'type', 'checkbox'); - set(this.context, 'disabled', true); - }); - - this.assertComponentElement(this.firstChild, { tagName: 'input', attrs: { type: 'checkbox', disabled: '' } }); - - this.runTask(() => { - set(this.context, 'type', 'password'); - set(this.context, 'disabled', false); - }); - - this.assertComponentElement(this.firstChild, { tagName: 'input', attrs: { type: 'password' } }); - } - - ['@test should allow namespaced attributes in micro syntax']() { - let FooBarComponent = Component.extend({ - attributeBindings: ['xlinkHref:xlink:href'] - }); - - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent }); - - this.render('{{foo-bar type=type xlinkHref=xlinkHref}}', { - xlinkHref: '/foo.png' - }); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'xlink:href': '/foo.png' } }); - - this.runTask(() => this.rerender()); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'xlink:href': '/foo.png' } }); - - this.runTask(() => set(this.context, 'xlinkHref', '/lol.png')); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'xlink:href': '/lol.png' } }); - - this.runTask(() => set(this.context, 'xlinkHref', '/foo.png')); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'xlink:href': '/foo.png' } }); - } - - // This comes into play when using the {{#each}} helper. If the - // passed array item is a String, it will be converted into a - // String object instead of a normal string. - ['@test should allow for String objects']() { - let FooBarComponent = Component.extend({ - attributeBindings: ['foo'] - }); - - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent }); - - this.render('{{foo-bar foo=foo}}', { - foo: (function() { return this; }).call('bar') - }); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'foo': 'bar' } }); - - this.runTask(() => this.rerender()); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'foo': 'bar' } }); - - this.runTask(() => set(this.context, 'foo', (function() { return this; }).call('baz'))); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'foo': 'baz' } }); - - this.runTask(() => set(this.context, 'foo', (function() { return this; }).call('bar'))); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'foo': 'bar' } }); - } - - ['@test can set id initially via attributeBindings ']() { - let FooBarComponent = Component.extend({ - attributeBindings: ['specialSauce:id'] - }); - - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent }); - - this.render('{{foo-bar specialSauce=sauce}}', { - sauce: 'special-sauce' - }); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'id': 'special-sauce' } }); - - this.runTask(() => this.rerender()); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'id': 'special-sauce' } }); - - this.runTask(() => set(this.context, 'sauce', 'foo')); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'id': 'special-sauce' } }); - - this.runTask(() => set(this.context, 'sauce', 'special-sauce')); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'id': 'special-sauce' } }); - } - - ['@test attributeBindings are overwritten']() { - let FooBarComponent = Component.extend({ - attributeBindings: ['href'], - href: 'a href' - }); - - let FizzBarComponent = FooBarComponent.extend({ - attributeBindings: ['newHref:href'] - }); - - this.registerComponent('fizz-bar', { ComponentClass: FizzBarComponent }); - - this.render('{{fizz-bar newHref=href}}', { - href: 'dog.html' - }); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { href: 'dog.html' } }); - - this.runTask(() => this.rerender()); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { href: 'dog.html' } }); - - this.runTask(() => set(this.context, 'href', 'cat.html')); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { href: 'cat.html' } }); - } + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { 'data-foo-bar': 'foo-bar' }, + content: 'hello' + }); + + this.runTask(() => this.rerender()); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { 'data-foo-bar': 'foo-bar' }, + content: 'hello' + }); + + this.runTask(() => set(this.context, 'foo.bar', 'FOO-BAR')); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { 'data-foo-bar': 'FOO-BAR' }, + content: 'hello' + }); + + this.runTask(() => set(this.context, 'foo.bar', undefined)); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: {}, + content: 'hello' + }); + + this.runTask(() => set(this.context, 'foo', undefined)); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: {}, + content: 'hello' + }); + + this.runTask(() => set(this.context, 'foo', { bar: 'foo-bar' })); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { 'data-foo-bar': 'foo-bar' }, + content: 'hello' + }); + } + + ['@test handles non-microsyntax attributeBindings']() { + let FooBarComponent = Component.extend({ + attributeBindings: ['type'] + }); + + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); + + this.render('{{foo-bar type=submit}}', { + submit: 'submit' + }); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { type: 'submit' }, + content: 'hello' + }); + + this.runTask(() => this.rerender()); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { type: 'submit' }, + content: 'hello' + }); + + this.runTask(() => set(this.context, 'submit', 'password')); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { type: 'password' }, + content: 'hello' + }); + + this.runTask(() => set(this.context, 'submit', null)); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: {}, + content: 'hello' + }); + + this.runTask(() => set(this.context, 'submit', 'submit')); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { type: 'submit' }, + content: 'hello' + }); + } + + ['@test non-microsyntax attributeBindings cannot contain nested paths']() { + let FooBarComponent = Component.extend({ + attributeBindings: ['foo.bar'] + }); + + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); + + expectAssertion(() => { + this.render('{{foo-bar foo=foo}}', { foo: { bar: 'foo-bar' } }); + }, /Illegal attributeBinding: 'foo.bar' is not a valid attribute name./); + } + + ['@test normalizes attributeBindings for property names']() { + let FooBarComponent = Component.extend({ + attributeBindings: ['tiTLe'] + }); + + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); + + this.render('{{foo-bar tiTLe=name}}', { + name: 'qux' + }); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { title: 'qux' }, + content: 'hello' + }); + + this.assertStableRerender(); + + this.runTask(() => set(this.context, 'name', null)); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: {}, + content: 'hello' + }); + + this.runTask(() => set(this.context, 'name', 'qux')); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { title: 'qux' }, + content: 'hello' + }); + } + + ['@test normalizes attributeBindings for attribute names']() { + let FooBarComponent = Component.extend({ + attributeBindings: ['foo:data-FOO'] + }); + + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); + + this.render('{{foo-bar foo=foo}}', { + foo: 'qux' + }); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { 'data-foo': 'qux' }, + content: 'hello' + }); + + this.assertStableRerender(); + + this.runTask(() => set(this.context, 'foo', null)); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: {}, + content: 'hello' + }); + + this.runTask(() => set(this.context, 'foo', 'qux')); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { 'data-foo': 'qux' }, + content: 'hello' + }); + } + + ['@test attributeBindings handles null/undefined']() { + let FooBarComponent = Component.extend({ + attributeBindings: ['fizz', 'bar'] + }); + + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); + + this.render('{{foo-bar fizz=fizz bar=bar}}', { + fizz: null, + bar: undefined + }); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: {}, + content: 'hello' + }); + + this.runTask(() => this.rerender()); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: {}, + content: 'hello' + }); + + this.runTask(() => { + set(this.context, 'fizz', 'fizz'); + set(this.context, 'bar', 'bar'); + }); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { fizz: 'fizz', bar: 'bar' }, + content: 'hello' + }); + + this.runTask(() => { + set(this.context, 'fizz', null); + set(this.context, 'bar', undefined); + }); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: {}, + content: 'hello' + }); + } + + ['@test attributeBindings handles number value']() { + let FooBarComponent = Component.extend({ + attributeBindings: ['size'] + }); + + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); + + this.render('{{foo-bar size=size}}', { + size: 21 + }); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { size: '21' }, + content: 'hello' + }); + + this.runTask(() => this.rerender()); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { size: '21' }, + content: 'hello' + }); + + this.runTask(() => set(this.context, 'size', 0)); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { size: '0' }, + content: 'hello' + }); + + this.runTask(() => set(this.context, 'size', 21)); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { size: '21' }, + content: 'hello' + }); + } + + ['@test handles internal and external changes']() { + let component; + let FooBarComponent = Component.extend({ + attributeBindings: ['type'], + type: 'password', + init() { + this._super(...arguments); + component = this; + } + }); - ['@test it can set attribute bindings in the constructor']() { - let FooBarComponent = Component.extend({ - init() { - this._super(); + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); - let bindings = []; + this.render('{{foo-bar}}'); - if (this.get('hasFoo')) { - bindings.push('foo:data-foo'); - } + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { type: 'password' }, + content: 'hello' + }); + + this.runTask(() => this.rerender()); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { type: 'password' }, + content: 'hello' + }); + + this.runTask(() => set(component, 'type', 'checkbox')); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { type: 'checkbox' }, + content: 'hello' + }); + + this.runTask(() => set(component, 'type', 'password')); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { type: 'password' }, + content: 'hello' + }); + } + + ['@test can set attributeBindings on component with a different tagName']() { + let FooBarComponent = Component.extend({ + tagName: 'input', + attributeBindings: ['type', 'isDisabled:disabled'] + }); + + this.registerComponent('foo-bar', { ComponentClass: FooBarComponent }); + + this.render('{{foo-bar type=type isDisabled=disabled}}', { + type: 'password', + disabled: false + }); + + this.assertComponentElement(this.firstChild, { + tagName: 'input', + attrs: { type: 'password' } + }); + + this.runTask(() => this.rerender()); + + this.assertComponentElement(this.firstChild, { + tagName: 'input', + attrs: { type: 'password' } + }); + + this.runTask(() => { + set(this.context, 'type', 'checkbox'); + set(this.context, 'disabled', true); + }); + + this.assertComponentElement(this.firstChild, { + tagName: 'input', + attrs: { type: 'checkbox', disabled: '' } + }); + + this.runTask(() => { + set(this.context, 'type', 'password'); + set(this.context, 'disabled', false); + }); + + this.assertComponentElement(this.firstChild, { + tagName: 'input', + attrs: { type: 'password' } + }); + } + + ['@test should allow namespaced attributes in micro syntax']() { + let FooBarComponent = Component.extend({ + attributeBindings: ['xlinkHref:xlink:href'] + }); + + this.registerComponent('foo-bar', { ComponentClass: FooBarComponent }); + + this.render('{{foo-bar type=type xlinkHref=xlinkHref}}', { + xlinkHref: '/foo.png' + }); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { 'xlink:href': '/foo.png' } + }); + + this.runTask(() => this.rerender()); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { 'xlink:href': '/foo.png' } + }); + + this.runTask(() => set(this.context, 'xlinkHref', '/lol.png')); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { 'xlink:href': '/lol.png' } + }); + + this.runTask(() => set(this.context, 'xlinkHref', '/foo.png')); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { 'xlink:href': '/foo.png' } + }); + } + + // This comes into play when using the {{#each}} helper. If the + // passed array item is a String, it will be converted into a + // String object instead of a normal string. + ['@test should allow for String objects']() { + let FooBarComponent = Component.extend({ + attributeBindings: ['foo'] + }); + + this.registerComponent('foo-bar', { ComponentClass: FooBarComponent }); + + this.render('{{foo-bar foo=foo}}', { + foo: function() { + return this; + }.call('bar') + }); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { foo: 'bar' } + }); + + this.runTask(() => this.rerender()); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { foo: 'bar' } + }); + + this.runTask(() => + set( + this.context, + 'foo', + function() { + return this; + }.call('baz') + ) + ); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { foo: 'baz' } + }); + + this.runTask(() => + set( + this.context, + 'foo', + function() { + return this; + }.call('bar') + ) + ); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { foo: 'bar' } + }); + } + + ['@test can set id initially via attributeBindings ']() { + let FooBarComponent = Component.extend({ + attributeBindings: ['specialSauce:id'] + }); + + this.registerComponent('foo-bar', { ComponentClass: FooBarComponent }); + + this.render('{{foo-bar specialSauce=sauce}}', { + sauce: 'special-sauce' + }); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { id: 'special-sauce' } + }); + + this.runTask(() => this.rerender()); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { id: 'special-sauce' } + }); + + this.runTask(() => set(this.context, 'sauce', 'foo')); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { id: 'special-sauce' } + }); + + this.runTask(() => set(this.context, 'sauce', 'special-sauce')); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { id: 'special-sauce' } + }); + } + + ['@test attributeBindings are overwritten']() { + let FooBarComponent = Component.extend({ + attributeBindings: ['href'], + href: 'a href' + }); + + let FizzBarComponent = FooBarComponent.extend({ + attributeBindings: ['newHref:href'] + }); + + this.registerComponent('fizz-bar', { ComponentClass: FizzBarComponent }); + + this.render('{{fizz-bar newHref=href}}', { + href: 'dog.html' + }); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { href: 'dog.html' } + }); + + this.runTask(() => this.rerender()); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { href: 'dog.html' } + }); + + this.runTask(() => set(this.context, 'href', 'cat.html')); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { href: 'cat.html' } + }); + } + + ['@test it can set attribute bindings in the constructor']() { + let FooBarComponent = Component.extend({ + init() { + this._super(); + + let bindings = []; + + if (this.get('hasFoo')) { + bindings.push('foo:data-foo'); + } + + if (this.get('hasBar')) { + bindings.push('bar:data-bar'); + } - if (this.get('hasBar')) { - bindings.push('bar:data-bar'); + this.attributeBindings = bindings; } + }); - this.attributeBindings = bindings; - } - }); + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); - - this.render(strip` + this.render( + strip` {{foo-bar hasFoo=true foo=foo hasBar=false bar=bar}} {{foo-bar hasFoo=false foo=foo hasBar=true bar=bar}} {{foo-bar hasFoo=true foo=foo hasBar=true bar=bar}} {{foo-bar hasFoo=false foo=foo hasBar=false bar=bar}} - `, { foo: 'foo', bar: 'bar' }); - - this.assertComponentElement(this.nthChild(0), { tagName: 'div', attrs: { 'data-foo': 'foo' }, content: 'hello' }); - this.assertComponentElement(this.nthChild(1), { tagName: 'div', attrs: { 'data-bar': 'bar' }, content: 'hello' }); - this.assertComponentElement(this.nthChild(2), { tagName: 'div', attrs: { 'data-foo': 'foo', 'data-bar': 'bar' }, content: 'hello' }); - this.assertComponentElement(this.nthChild(3), { tagName: 'div', attrs: { }, content: 'hello' }); - - this.runTask(() => this.rerender()); - - this.assertComponentElement(this.nthChild(0), { tagName: 'div', attrs: { 'data-foo': 'foo' }, content: 'hello' }); - this.assertComponentElement(this.nthChild(1), { tagName: 'div', attrs: { 'data-bar': 'bar' }, content: 'hello' }); - this.assertComponentElement(this.nthChild(2), { tagName: 'div', attrs: { 'data-foo': 'foo', 'data-bar': 'bar' }, content: 'hello' }); - this.assertComponentElement(this.nthChild(3), { tagName: 'div', attrs: { }, content: 'hello' }); - - this.runTask(() => { - set(this.context, 'foo', 'FOO'); - set(this.context, 'bar', undefined); - }); - - this.assertComponentElement(this.nthChild(0), { tagName: 'div', attrs: { 'data-foo': 'FOO' }, content: 'hello' }); - this.assertComponentElement(this.nthChild(1), { tagName: 'div', attrs: { }, content: 'hello' }); - this.assertComponentElement(this.nthChild(2), { tagName: 'div', attrs: { 'data-foo': 'FOO' }, content: 'hello' }); - this.assertComponentElement(this.nthChild(3), { tagName: 'div', attrs: { }, content: 'hello' }); - - this.runTask(() => set(this.context, 'bar', 'BAR')); - - this.assertComponentElement(this.nthChild(0), { tagName: 'div', attrs: { 'data-foo': 'FOO' }, content: 'hello' }); - this.assertComponentElement(this.nthChild(1), { tagName: 'div', attrs: { 'data-bar': 'BAR' }, content: 'hello' }); - this.assertComponentElement(this.nthChild(2), { tagName: 'div', attrs: { 'data-foo': 'FOO', 'data-bar': 'BAR' }, content: 'hello' }); - this.assertComponentElement(this.nthChild(3), { tagName: 'div', attrs: { }, content: 'hello' }); - - this.runTask(() => { - set(this.context, 'foo', 'foo'); - set(this.context, 'bar', 'bar'); - }); - - this.assertComponentElement(this.nthChild(0), { tagName: 'div', attrs: { 'data-foo': 'foo' }, content: 'hello' }); - this.assertComponentElement(this.nthChild(1), { tagName: 'div', attrs: { 'data-bar': 'bar' }, content: 'hello' }); - this.assertComponentElement(this.nthChild(2), { tagName: 'div', attrs: { 'data-foo': 'foo', 'data-bar': 'bar' }, content: 'hello' }); - this.assertComponentElement(this.nthChild(3), { tagName: 'div', attrs: { }, content: 'hello' }); - } - - ['@test it should not allow attributeBindings to be set']() { - this.registerComponent('foo-bar', { template: 'hello' }); - - expectAssertion(() => { - this.render('{{foo-bar attributeBindings="one two"}}'); - }, /Setting 'attributeBindings' via template helpers is not allowed/); - } - - ['@test asserts if an attributeBinding is setup on class']() { - let FooBarComponent = Component.extend({ - attributeBindings: ['class'] - }); - - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); - - expectAssertion(() => { - this.render('{{foo-bar}}'); - }, /You cannot use class as an attributeBinding, use classNameBindings instead./i); - } - - ['@test blacklists href bindings based on protocol']() { - /* jshint scripturl:true */ - - let FooBarComponent = Component.extend({ - tagName: 'a', - attributeBindings: ['href'] - }); - - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); - - this.render('{{foo-bar href=xss}}', { - xss: 'javascript:alert(\'foo\')' - }); - - this.assertComponentElement(this.firstChild, { tagName: 'a', attrs: { href: 'unsafe:javascript:alert(\'foo\')' } }); - } - - ['@test it can bind the role attribute (issue #14007)']() { - let FooBarComponent = Component.extend({ attributeBindings: ['role'] }); - - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); - - this.render('{{foo-bar role=role}}', { role: 'button' }); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { role: 'button' } }); - - this.runTask(() => this.rerender()); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { role: 'button' } }); - - this.runTask(() => set(this.context, 'role', 'combobox')); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { role: 'combobox' } }); - - this.runTask(() => set(this.context, 'role', null)); - - this.assertComponentElement(this.firstChild, { tagName: 'div' }); - } - - ['@test component with an `id` attribute binding of undefined']() { - this.registerComponent('foo-bar', { - ComponentClass: Component.extend({ - attributeBindings: ['id'], - - id: undefined - }) - }); - - this.registerComponent('baz-qux', { - ComponentClass: Component.extend({ - attributeBindings: ['somethingUndefined:id'], - - somethingUndefined: undefined - }) - }); - this.render(`{{foo-bar}}{{baz-qux}}`); - - this.assertComponentElement(this.nthChild(0), { content: '' }); - this.assertComponentElement(this.nthChild(1), { content: '' }); - - this.assert.ok(this.nthChild(0).id.match(/ember\d+/), 'a valid `id` was used'); - this.assert.ok(this.nthChild(1).id.match(/ember\d+/), 'a valid `id` was used'); - } - - ['@test component with an `id` attribute binding of null']() { - this.registerComponent('foo-bar', { - ComponentClass: Component.extend({ - attributeBindings: ['id'], - - id: null - }) - }); - - this.registerComponent('baz-qux', { - ComponentClass: Component.extend({ - attributeBindings: ['somethingNull:id'], - - somethingNull: null - }) - }); - this.render(`{{foo-bar}}{{baz-qux}}`); - - this.assertComponentElement(this.nthChild(0), { content: '' }); - this.assertComponentElement(this.nthChild(1), { content: '' }); - - this.assert.ok(this.nthChild(0).id.match(/ember\d+/), 'a valid `id` was used'); - this.assert.ok(this.nthChild(1).id.match(/ember\d+/), 'a valid `id` was used'); + `, + { foo: 'foo', bar: 'bar' } + ); + + this.assertComponentElement(this.nthChild(0), { + tagName: 'div', + attrs: { 'data-foo': 'foo' }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(1), { + tagName: 'div', + attrs: { 'data-bar': 'bar' }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(2), { + tagName: 'div', + attrs: { 'data-foo': 'foo', 'data-bar': 'bar' }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(3), { + tagName: 'div', + attrs: {}, + content: 'hello' + }); + + this.runTask(() => this.rerender()); + + this.assertComponentElement(this.nthChild(0), { + tagName: 'div', + attrs: { 'data-foo': 'foo' }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(1), { + tagName: 'div', + attrs: { 'data-bar': 'bar' }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(2), { + tagName: 'div', + attrs: { 'data-foo': 'foo', 'data-bar': 'bar' }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(3), { + tagName: 'div', + attrs: {}, + content: 'hello' + }); + + this.runTask(() => { + set(this.context, 'foo', 'FOO'); + set(this.context, 'bar', undefined); + }); + + this.assertComponentElement(this.nthChild(0), { + tagName: 'div', + attrs: { 'data-foo': 'FOO' }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(1), { + tagName: 'div', + attrs: {}, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(2), { + tagName: 'div', + attrs: { 'data-foo': 'FOO' }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(3), { + tagName: 'div', + attrs: {}, + content: 'hello' + }); + + this.runTask(() => set(this.context, 'bar', 'BAR')); + + this.assertComponentElement(this.nthChild(0), { + tagName: 'div', + attrs: { 'data-foo': 'FOO' }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(1), { + tagName: 'div', + attrs: { 'data-bar': 'BAR' }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(2), { + tagName: 'div', + attrs: { 'data-foo': 'FOO', 'data-bar': 'BAR' }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(3), { + tagName: 'div', + attrs: {}, + content: 'hello' + }); + + this.runTask(() => { + set(this.context, 'foo', 'foo'); + set(this.context, 'bar', 'bar'); + }); + + this.assertComponentElement(this.nthChild(0), { + tagName: 'div', + attrs: { 'data-foo': 'foo' }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(1), { + tagName: 'div', + attrs: { 'data-bar': 'bar' }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(2), { + tagName: 'div', + attrs: { 'data-foo': 'foo', 'data-bar': 'bar' }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(3), { + tagName: 'div', + attrs: {}, + content: 'hello' + }); + } + + ['@test it should not allow attributeBindings to be set']() { + this.registerComponent('foo-bar', { template: 'hello' }); + + expectAssertion(() => { + this.render('{{foo-bar attributeBindings="one two"}}'); + }, /Setting 'attributeBindings' via template helpers is not allowed/); + } + + ['@test asserts if an attributeBinding is setup on class']() { + let FooBarComponent = Component.extend({ + attributeBindings: ['class'] + }); + + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); + + expectAssertion(() => { + this.render('{{foo-bar}}'); + }, /You cannot use class as an attributeBinding, use classNameBindings instead./i); + } + + ['@test blacklists href bindings based on protocol']() { + /* jshint scripturl:true */ + + let FooBarComponent = Component.extend({ + tagName: 'a', + attributeBindings: ['href'] + }); + + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); + + this.render('{{foo-bar href=xss}}', { + xss: "javascript:alert('foo')" + }); + + this.assertComponentElement(this.firstChild, { + tagName: 'a', + attrs: { href: "unsafe:javascript:alert('foo')" } + }); + } + + ['@test it can bind the role attribute (issue #14007)']() { + let FooBarComponent = Component.extend({ attributeBindings: ['role'] }); + + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); + + this.render('{{foo-bar role=role}}', { role: 'button' }); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { role: 'button' } + }); + + this.runTask(() => this.rerender()); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { role: 'button' } + }); + + this.runTask(() => set(this.context, 'role', 'combobox')); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { role: 'combobox' } + }); + + this.runTask(() => set(this.context, 'role', null)); + + this.assertComponentElement(this.firstChild, { tagName: 'div' }); + } + + ['@test component with an `id` attribute binding of undefined']() { + this.registerComponent('foo-bar', { + ComponentClass: Component.extend({ + attributeBindings: ['id'], + + id: undefined + }) + }); + + this.registerComponent('baz-qux', { + ComponentClass: Component.extend({ + attributeBindings: ['somethingUndefined:id'], + + somethingUndefined: undefined + }) + }); + this.render(`{{foo-bar}}{{baz-qux}}`); + + this.assertComponentElement(this.nthChild(0), { content: '' }); + this.assertComponentElement(this.nthChild(1), { content: '' }); + + this.assert.ok( + this.nthChild(0).id.match(/ember\d+/), + 'a valid `id` was used' + ); + this.assert.ok( + this.nthChild(1).id.match(/ember\d+/), + 'a valid `id` was used' + ); + } + + ['@test component with an `id` attribute binding of null']() { + this.registerComponent('foo-bar', { + ComponentClass: Component.extend({ + attributeBindings: ['id'], + + id: null + }) + }); + + this.registerComponent('baz-qux', { + ComponentClass: Component.extend({ + attributeBindings: ['somethingNull:id'], + + somethingNull: null + }) + }); + this.render(`{{foo-bar}}{{baz-qux}}`); + + this.assertComponentElement(this.nthChild(0), { content: '' }); + this.assertComponentElement(this.nthChild(1), { content: '' }); + + this.assert.ok( + this.nthChild(0).id.match(/ember\d+/), + 'a valid `id` was used' + ); + this.assert.ok( + this.nthChild(1).id.match(/ember\d+/), + 'a valid `id` was used' + ); + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/components/attrs-lookup-test.js b/packages/ember-glimmer/tests/integration/components/attrs-lookup-test.js index 322eac350d5..75e2df15495 100644 --- a/packages/ember-glimmer/tests/integration/components/attrs-lookup-test.js +++ b/packages/ember-glimmer/tests/integration/components/attrs-lookup-test.js @@ -3,241 +3,322 @@ import { Component, htmlSafe } from '../../utils/helpers'; import { set, computed } from 'ember-metal'; import { styles } from '../../utils/test-helpers'; -moduleFor('Components test: attrs lookup', class extends RenderingTest { +moduleFor( + 'Components test: attrs lookup', + class extends RenderingTest { + ['@test it should be able to lookup attrs without `attrs.` - template access']() { + this.registerComponent('foo-bar', { template: '{{first}}' }); - ['@test it should be able to lookup attrs without `attrs.` - template access']() { - this.registerComponent('foo-bar', { template: '{{first}}' }); + this.render(`{{foo-bar first=firstAttr}}`, { + firstAttr: 'first attr' + }); - this.render(`{{foo-bar first=firstAttr}}`, { - firstAttr: 'first attr' - }); + this.assertText('first attr'); - this.assertText('first attr'); + this.runTask(() => this.rerender()); - this.runTask(() => this.rerender()); + this.assertText('first attr'); + + this.runTask(() => set(this.context, 'firstAttr', 'second attr')); + + this.assertText('second attr'); + + this.runTask(() => set(this.context, 'firstAttr', 'first attr')); + + this.assertText('first attr'); + } + + ['@test it should be able to lookup attrs without `attrs.` - component access']( + assert + ) { + let instance; - this.assertText('first attr'); - - this.runTask(() => set(this.context, 'firstAttr', 'second attr')); - - this.assertText('second attr'); - - this.runTask(() => set(this.context, 'firstAttr', 'first attr')); - - this.assertText('first attr'); - } - - ['@test it should be able to lookup attrs without `attrs.` - component access'](assert) { - let instance; - - let FooBarComponent = Component.extend({ - init() { - this._super(...arguments); - instance = this; - } - }); - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: '{{first}}' }); - - this.render(`{{foo-bar first=firstAttr}}`, { - firstAttr: 'first attr' - }); - - assert.equal(instance.get('first'), 'first attr'); - - this.runTask(() => this.rerender()); - - assert.equal(instance.get('first'), 'first attr'); - - this.runTask(() => set(this.context, 'firstAttr', 'second attr')); - - assert.equal(instance.get('first'), 'second attr'); - - this.runTask(() => set(this.context, 'firstAttr', 'first attr')); - - this.assertText('first attr'); - } - - ['@test should be able to modify a provided attr into local state #11571 / #11559'](assert) { - let instance; - let FooBarComponent = Component.extend({ - init() { - this._super(...arguments); - instance = this; - }, - - didReceiveAttrs() { - this.set('first', this.get('first').toUpperCase()); - } - }); - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: '{{first}}' }); - - this.render(`{{foo-bar first="first attr"}}`); - - assert.equal(instance.get('first'), 'FIRST ATTR', 'component lookup uses local state'); - this.assertText('FIRST ATTR'); - - this.runTask(() => this.rerender()); - - assert.equal(instance.get('first'), 'FIRST ATTR', 'component lookup uses local state during rerender'); - this.assertText('FIRST ATTR'); - - // This is testing that passing string literals for use as initial values, - // so there is no update step - } - - ['@test should be able to access unspecified attr #12035'](assert) { - let instance; - let wootVal = 'yes'; - - let FooBarComponent = Component.extend({ - init() { - this._super(...arguments); - instance = this; - }, - - didReceiveAttrs() { - assert.equal(this.get('woot'), wootVal, 'found attr in didReceiveAttrs'); - } - }); - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent }); - - this.render(`{{foo-bar woot=woot}}`, { - woot: wootVal - }); - - assert.equal(instance.get('woot'), 'yes', 'component found attr'); - - this.runTask(() => this.rerender()); - - assert.equal(instance.get('woot'), 'yes', 'component found attr after rerender'); - - this.runTask(() => { - wootVal = 'nope'; - set(this.context, 'woot', wootVal); - }); - - assert.equal(instance.get('woot'), 'nope', 'component found attr after attr change'); - - this.runTask(() => { - wootVal = 'yes'; - set(this.context, 'woot', wootVal); - }); - - assert.equal(instance.get('woot'), 'yes', 'component found attr after reset'); - } - - ['@test getAttr() should return the same value as get()'](assert) { - assert.expect(33); - - let instance; - let FooBarComponent = Component.extend({ - init() { - this._super(...arguments); - instance = this; - }, - - didReceiveAttrs() { - let rootFirstPositional = this.get('firstPositional'); - let rootFirst = this.get('first'); - let rootSecond = this.get('second'); - let attrFirstPositional = this.getAttr('firstPositional'); - let attrFirst = this.getAttr('first'); - let attrSecond = this.getAttr('second'); - - assert.equal(rootFirstPositional, attrFirstPositional, 'root property matches attrs value'); - assert.equal(rootFirst, attrFirst, 'root property matches attrs value'); - assert.equal(rootSecond, attrSecond, 'root property matches attrs value'); - } - }); - - FooBarComponent.reopenClass({ - positionalParams: ['firstPositional'] - }); - - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent }); - - this.render(`{{foo-bar firstPositional first=first second=second}}`, { - firstPositional: 'firstPositional', - first: 'first', - second: 'second' - }); - - assert.equal(instance.get('firstPositional'), 'firstPositional', 'matches known value'); - assert.equal(instance.get('first'), 'first', 'matches known value'); - assert.equal(instance.get('second'), 'second', 'matches known value'); - - this.runTask(() => this.rerender()); - - assert.equal(instance.get('firstPositional'), 'firstPositional', 'matches known value'); - assert.equal(instance.get('first'), 'first', 'matches known value'); - assert.equal(instance.get('second'), 'second', 'matches known value'); - - this.runTask(() => { - set(this.context, 'first', 'third'); - }); - - assert.equal(instance.get('firstPositional'), 'firstPositional', 'matches known value'); - assert.equal(instance.get('first'), 'third', 'matches known value'); - assert.equal(instance.get('second'), 'second', 'matches known value'); - - this.runTask(() => { - set(this.context, 'second', 'fourth'); - }); - - assert.equal(instance.get('firstPositional'), 'firstPositional', 'matches known value'); - assert.equal(instance.get('first'), 'third', 'matches known value'); - assert.equal(instance.get('second'), 'fourth', 'matches known value'); - - this.runTask(() => { - set(this.context, 'firstPositional', 'fifth'); - }); - - assert.equal(instance.get('firstPositional'), 'fifth', 'matches known value'); - assert.equal(instance.get('first'), 'third', 'matches known value'); - assert.equal(instance.get('second'), 'fourth', 'matches known value'); - - this.runTask(() => { - set(this.context, 'firstPositional', 'firstPositional'); - set(this.context, 'first', 'first'); - set(this.context, 'second', 'second'); - }); - - assert.equal(instance.get('firstPositional'), 'firstPositional', 'matches known value'); - assert.equal(instance.get('first'), 'first', 'matches known value'); - assert.equal(instance.get('second'), 'second', 'matches known value'); - } - - ['@test bound computed properties can be overridden in extensions, set during init, and passed in as attrs']() { - let FooClass = Component.extend({ - attributeBindings: ['style'], - style: computed('height', 'color', function() { - let height = this.get('height'); - let color = this.get('color'); - return htmlSafe(`height: ${height}px; background-color: ${color};`); - }), - color: 'red', - height: 20 - }); - - let BarClass = FooClass.extend({ - init() { - this._super(...arguments); - this.height = 150; - }, - color: 'yellow' - }); - - this.registerComponent('x-foo', { ComponentClass: FooClass }); - this.registerComponent('x-bar', { ComponentClass: BarClass }); - - this.render('{{x-foo}}{{x-bar}}{{x-bar color="green"}}'); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { style: styles('height: 20px; background-color: red;') } }); - this.assertComponentElement(this.nthChild(1), { tagName: 'div', attrs: { style: styles('height: 150px; background-color: yellow;') } }); - this.assertComponentElement(this.nthChild(2), { tagName: 'div', attrs: { style: styles('height: 150px; background-color: green;') } }); - - this.assertStableRerender(); - - // No U-R + let FooBarComponent = Component.extend({ + init() { + this._super(...arguments); + instance = this; + } + }); + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: '{{first}}' + }); + + this.render(`{{foo-bar first=firstAttr}}`, { + firstAttr: 'first attr' + }); + + assert.equal(instance.get('first'), 'first attr'); + + this.runTask(() => this.rerender()); + + assert.equal(instance.get('first'), 'first attr'); + + this.runTask(() => set(this.context, 'firstAttr', 'second attr')); + + assert.equal(instance.get('first'), 'second attr'); + + this.runTask(() => set(this.context, 'firstAttr', 'first attr')); + + this.assertText('first attr'); + } + + ['@test should be able to modify a provided attr into local state #11571 / #11559']( + assert + ) { + let instance; + let FooBarComponent = Component.extend({ + init() { + this._super(...arguments); + instance = this; + }, + + didReceiveAttrs() { + this.set('first', this.get('first').toUpperCase()); + } + }); + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: '{{first}}' + }); + + this.render(`{{foo-bar first="first attr"}}`); + + assert.equal( + instance.get('first'), + 'FIRST ATTR', + 'component lookup uses local state' + ); + this.assertText('FIRST ATTR'); + + this.runTask(() => this.rerender()); + + assert.equal( + instance.get('first'), + 'FIRST ATTR', + 'component lookup uses local state during rerender' + ); + this.assertText('FIRST ATTR'); + + // This is testing that passing string literals for use as initial values, + // so there is no update step + } + + ['@test should be able to access unspecified attr #12035'](assert) { + let instance; + let wootVal = 'yes'; + + let FooBarComponent = Component.extend({ + init() { + this._super(...arguments); + instance = this; + }, + + didReceiveAttrs() { + assert.equal( + this.get('woot'), + wootVal, + 'found attr in didReceiveAttrs' + ); + } + }); + this.registerComponent('foo-bar', { ComponentClass: FooBarComponent }); + + this.render(`{{foo-bar woot=woot}}`, { + woot: wootVal + }); + + assert.equal(instance.get('woot'), 'yes', 'component found attr'); + + this.runTask(() => this.rerender()); + + assert.equal( + instance.get('woot'), + 'yes', + 'component found attr after rerender' + ); + + this.runTask(() => { + wootVal = 'nope'; + set(this.context, 'woot', wootVal); + }); + + assert.equal( + instance.get('woot'), + 'nope', + 'component found attr after attr change' + ); + + this.runTask(() => { + wootVal = 'yes'; + set(this.context, 'woot', wootVal); + }); + + assert.equal( + instance.get('woot'), + 'yes', + 'component found attr after reset' + ); + } + + ['@test getAttr() should return the same value as get()'](assert) { + assert.expect(33); + + let instance; + let FooBarComponent = Component.extend({ + init() { + this._super(...arguments); + instance = this; + }, + + didReceiveAttrs() { + let rootFirstPositional = this.get('firstPositional'); + let rootFirst = this.get('first'); + let rootSecond = this.get('second'); + let attrFirstPositional = this.getAttr('firstPositional'); + let attrFirst = this.getAttr('first'); + let attrSecond = this.getAttr('second'); + + assert.equal( + rootFirstPositional, + attrFirstPositional, + 'root property matches attrs value' + ); + assert.equal( + rootFirst, + attrFirst, + 'root property matches attrs value' + ); + assert.equal( + rootSecond, + attrSecond, + 'root property matches attrs value' + ); + } + }); + + FooBarComponent.reopenClass({ + positionalParams: ['firstPositional'] + }); + + this.registerComponent('foo-bar', { ComponentClass: FooBarComponent }); + + this.render(`{{foo-bar firstPositional first=first second=second}}`, { + firstPositional: 'firstPositional', + first: 'first', + second: 'second' + }); + + assert.equal( + instance.get('firstPositional'), + 'firstPositional', + 'matches known value' + ); + assert.equal(instance.get('first'), 'first', 'matches known value'); + assert.equal(instance.get('second'), 'second', 'matches known value'); + + this.runTask(() => this.rerender()); + + assert.equal( + instance.get('firstPositional'), + 'firstPositional', + 'matches known value' + ); + assert.equal(instance.get('first'), 'first', 'matches known value'); + assert.equal(instance.get('second'), 'second', 'matches known value'); + + this.runTask(() => { + set(this.context, 'first', 'third'); + }); + + assert.equal( + instance.get('firstPositional'), + 'firstPositional', + 'matches known value' + ); + assert.equal(instance.get('first'), 'third', 'matches known value'); + assert.equal(instance.get('second'), 'second', 'matches known value'); + + this.runTask(() => { + set(this.context, 'second', 'fourth'); + }); + + assert.equal( + instance.get('firstPositional'), + 'firstPositional', + 'matches known value' + ); + assert.equal(instance.get('first'), 'third', 'matches known value'); + assert.equal(instance.get('second'), 'fourth', 'matches known value'); + + this.runTask(() => { + set(this.context, 'firstPositional', 'fifth'); + }); + + assert.equal( + instance.get('firstPositional'), + 'fifth', + 'matches known value' + ); + assert.equal(instance.get('first'), 'third', 'matches known value'); + assert.equal(instance.get('second'), 'fourth', 'matches known value'); + + this.runTask(() => { + set(this.context, 'firstPositional', 'firstPositional'); + set(this.context, 'first', 'first'); + set(this.context, 'second', 'second'); + }); + + assert.equal( + instance.get('firstPositional'), + 'firstPositional', + 'matches known value' + ); + assert.equal(instance.get('first'), 'first', 'matches known value'); + assert.equal(instance.get('second'), 'second', 'matches known value'); + } + + ['@test bound computed properties can be overridden in extensions, set during init, and passed in as attrs']() { + let FooClass = Component.extend({ + attributeBindings: ['style'], + style: computed('height', 'color', function() { + let height = this.get('height'); + let color = this.get('color'); + return htmlSafe(`height: ${height}px; background-color: ${color};`); + }), + color: 'red', + height: 20 + }); + + let BarClass = FooClass.extend({ + init() { + this._super(...arguments); + this.height = 150; + }, + color: 'yellow' + }); + + this.registerComponent('x-foo', { ComponentClass: FooClass }); + this.registerComponent('x-bar', { ComponentClass: BarClass }); + + this.render('{{x-foo}}{{x-bar}}{{x-bar color="green"}}'); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { style: styles('height: 20px; background-color: red;') } + }); + this.assertComponentElement(this.nthChild(1), { + tagName: 'div', + attrs: { style: styles('height: 150px; background-color: yellow;') } + }); + this.assertComponentElement(this.nthChild(2), { + tagName: 'div', + attrs: { style: styles('height: 150px; background-color: green;') } + }); + + this.assertStableRerender(); + + // No U-R + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/components/class-bindings-test.js b/packages/ember-glimmer/tests/integration/components/class-bindings-test.js index b7a0b16310e..1c69e3ece85 100644 --- a/packages/ember-glimmer/tests/integration/components/class-bindings-test.js +++ b/packages/ember-glimmer/tests/integration/components/class-bindings-test.js @@ -4,504 +4,859 @@ import { classes } from '../../utils/test-helpers'; import { set, computed } from 'ember-metal'; import { strip } from '../../utils/abstract-test-case'; -moduleFor('ClassNameBindings integration', class extends RenderingTest { +moduleFor( + 'ClassNameBindings integration', + class extends RenderingTest { + ['@test it can have class name bindings on the class definition']() { + let FooBarComponent = Component.extend({ + classNameBindings: ['foo', 'isEnabled:enabled', 'isHappy:happy:sad'] + }); - ['@test it can have class name bindings on the class definition']() { - let FooBarComponent = Component.extend({ - classNameBindings: ['foo', 'isEnabled:enabled', 'isHappy:happy:sad'] - }); + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); + this.render('{{foo-bar foo=foo isEnabled=isEnabled isHappy=isHappy}}', { + foo: 'foo', + isEnabled: true, + isHappy: false + }); - this.render('{{foo-bar foo=foo isEnabled=isEnabled isHappy=isHappy}}', { foo: 'foo', isEnabled: true, isHappy: false }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view foo enabled sad') }, + content: 'hello' + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view foo enabled sad') }, content: 'hello' }); + this.runTask(() => this.rerender()); - this.runTask(() => this.rerender()); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view foo enabled sad') }, + content: 'hello' + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view foo enabled sad') }, content: 'hello' }); + this.runTask(() => { + set(this.context, 'foo', 'FOO'); + set(this.context, 'isEnabled', false); + }); - this.runTask(() => { - set(this.context, 'foo', 'FOO'); - set(this.context, 'isEnabled', false); - }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view FOO sad') }, + content: 'hello' + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view FOO sad') }, content: 'hello' }); + this.runTask(() => { + set(this.context, 'foo', undefined); + set(this.context, 'isHappy', true); + }); - this.runTask(() => { - set(this.context, 'foo', undefined); - set(this.context, 'isHappy', true); - }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view happy') }, + content: 'hello' + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view happy') }, content: 'hello' }); + this.runTask(() => { + set(this.context, 'foo', 'foo'); + set(this.context, 'isEnabled', true); + set(this.context, 'isHappy', false); + }); - this.runTask(() => { - set(this.context, 'foo', 'foo'); - set(this.context, 'isEnabled', true); - set(this.context, 'isHappy', false); - }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view foo enabled sad') }, + content: 'hello' + }); + } + + ['@test attrs in classNameBindings']() { + let FooBarComponent = Component.extend({ + classNameBindings: [ + 'attrs.joker:purple:green', + 'attrs.batman.robin:black:red' + ] + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view foo enabled sad') }, content: 'hello' }); - } + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); - ['@test attrs in classNameBindings']() { - let FooBarComponent = Component.extend({ - classNameBindings: ['attrs.joker:purple:green', 'attrs.batman.robin:black:red'] - }); + this.render('{{foo-bar joker=model.wat batman=model.super}}', { + model: { wat: false, super: { robin: true } } + }); - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view green black') }, + content: 'hello' + }); - this.render('{{foo-bar joker=model.wat batman=model.super}}', { - model: { wat: false, super: { robin: true } } - }); + this.runTask(() => this.rerender()); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view green black') }, content: 'hello' }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view green black') }, + content: 'hello' + }); - this.runTask(() => this.rerender()); + this.runTask(() => { + set(this.context, 'model.wat', true); + set(this.context, 'model.super.robin', false); + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view green black') }, content: 'hello' }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view purple red') }, + content: 'hello' + }); - this.runTask(() => { - set(this.context, 'model.wat', true); - set(this.context, 'model.super.robin', false); - }); + this.runTask(() => + set(this.context, 'model', { + wat: false, + super: { robin: true } + }) + ); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view green black') }, + content: 'hello' + }); + } + + ['@test it can have class name bindings in the template']() { + this.registerComponent('foo-bar', { template: 'hello' }); + + this.render( + '{{foo-bar classNameBindings="model.someInitiallyTrueProperty model.someInitiallyFalseProperty model.someInitiallyUndefinedProperty :static model.isBig:big model.isOpen:open:closed model.isUp::down model.bar:isTruthy:isFalsy"}}', + { + model: { + someInitiallyTrueProperty: true, + someInitiallyFalseProperty: false, + isBig: true, + isOpen: false, + isUp: true, + bar: true + } + } + ); + + this.assertComponentElement(this.firstChild, { + attrs: { + class: classes( + 'ember-view some-initially-true-property static big closed isTruthy' + ) + }, + content: 'hello' + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view purple red') }, content: 'hello' }); + this.runTask(() => this.rerender()); - this.runTask(() => set(this.context, 'model', { - wat: false, super: { robin: true } - })); + this.assertComponentElement(this.firstChild, { + attrs: { + class: classes( + 'ember-view some-initially-true-property static big closed isTruthy' + ) + }, + content: 'hello' + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view green black') }, content: 'hello' }); - } + this.runTask(() => { + set(this.context, 'model.someInitiallyTrueProperty', false); + set(this.context, 'model.someInitiallyFalseProperty', true); + set(this.context, 'model.someInitiallyUndefinedProperty', true); + set(this.context, 'model.isBig', false); + set(this.context, 'model.isOpen', true); + set(this.context, 'model.isUp', false); + set(this.context, 'model.bar', false); + }); - ['@test it can have class name bindings in the template']() { - this.registerComponent('foo-bar', { template: 'hello' }); - - this.render('{{foo-bar classNameBindings="model.someInitiallyTrueProperty model.someInitiallyFalseProperty model.someInitiallyUndefinedProperty :static model.isBig:big model.isOpen:open:closed model.isUp::down model.bar:isTruthy:isFalsy"}}', { - model: { - someInitiallyTrueProperty: true, - someInitiallyFalseProperty: false, - isBig: true, - isOpen: false, - isUp: true, - bar: true - } - }); - - this.assertComponentElement(this.firstChild, { - attrs: { 'class': classes('ember-view some-initially-true-property static big closed isTruthy') }, - content: 'hello' - }); - - this.runTask(() => this.rerender()); - - this.assertComponentElement(this.firstChild, { - attrs: { 'class': classes('ember-view some-initially-true-property static big closed isTruthy') }, - content: 'hello' - }); - - this.runTask(() => { - set(this.context, 'model.someInitiallyTrueProperty', false); - set(this.context, 'model.someInitiallyFalseProperty', true); - set(this.context, 'model.someInitiallyUndefinedProperty', true); - set(this.context, 'model.isBig', false); - set(this.context, 'model.isOpen', true); - set(this.context, 'model.isUp', false); - set(this.context, 'model.bar', false); - }); - - this.assertComponentElement(this.firstChild, { - attrs: { 'class': classes('ember-view some-initially-false-property some-initially-undefined-property static open down isFalsy') }, - content: 'hello' - }); - - this.runTask(() => { - set(this.context, 'model', { - someInitiallyTrueProperty: true, - someInitiallyFalseProperty: false, - someInitiallyUndefinedProperty: undefined, - isBig: true, - isOpen: false, - isUp: true, - bar: true - }); - }); - - this.assertComponentElement(this.firstChild, { - attrs: { 'class': classes('ember-view some-initially-true-property static big closed isTruthy') }, - content: 'hello' - }); - } + this.assertComponentElement(this.firstChild, { + attrs: { + class: classes( + 'ember-view some-initially-false-property some-initially-undefined-property static open down isFalsy' + ) + }, + content: 'hello' + }); - ['@test it can have class name bindings with nested paths']() { - let FooBarComponent = Component.extend({ - classNameBindings: ['foo.bar', 'is.enabled:enabled', 'is.happy:happy:sad'] - }); + this.runTask(() => { + set(this.context, 'model', { + someInitiallyTrueProperty: true, + someInitiallyFalseProperty: false, + someInitiallyUndefinedProperty: undefined, + isBig: true, + isOpen: false, + isUp: true, + bar: true + }); + }); - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); + this.assertComponentElement(this.firstChild, { + attrs: { + class: classes( + 'ember-view some-initially-true-property static big closed isTruthy' + ) + }, + content: 'hello' + }); + } + + ['@test it can have class name bindings with nested paths']() { + let FooBarComponent = Component.extend({ + classNameBindings: [ + 'foo.bar', + 'is.enabled:enabled', + 'is.happy:happy:sad' + ] + }); - this.render('{{foo-bar foo=foo is=is}}', { foo: { bar: 'foo-bar' }, is: { enabled: true, happy: false } }); + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view foo-bar enabled sad') }, content: 'hello' }); + this.render('{{foo-bar foo=foo is=is}}', { + foo: { bar: 'foo-bar' }, + is: { enabled: true, happy: false } + }); - this.runTask(() => this.rerender()); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view foo-bar enabled sad') }, + content: 'hello' + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view foo-bar enabled sad') }, content: 'hello' }); + this.runTask(() => this.rerender()); - this.runTask(() => { - set(this.context, 'foo.bar', 'FOO-BAR'); - set(this.context, 'is.enabled', false); - }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view foo-bar enabled sad') }, + content: 'hello' + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view FOO-BAR sad') }, content: 'hello' }); + this.runTask(() => { + set(this.context, 'foo.bar', 'FOO-BAR'); + set(this.context, 'is.enabled', false); + }); - this.runTask(() => { - set(this.context, 'foo.bar', null); - set(this.context, 'is.happy', true); - }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view FOO-BAR sad') }, + content: 'hello' + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view happy') }, content: 'hello' }); + this.runTask(() => { + set(this.context, 'foo.bar', null); + set(this.context, 'is.happy', true); + }); - this.runTask(() => { - set(this.context, 'foo', null); - set(this.context, 'is', null); - }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view happy') }, + content: 'hello' + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view sad') }, content: 'hello' }); + this.runTask(() => { + set(this.context, 'foo', null); + set(this.context, 'is', null); + }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view sad') }, + content: 'hello' + }); - this.runTask(() => { - set(this.context, 'foo', { bar: 'foo-bar' }); - set(this.context, 'is', { enabled: true, happy: false }); - }); + this.runTask(() => { + set(this.context, 'foo', { bar: 'foo-bar' }); + set(this.context, 'is', { enabled: true, happy: false }); + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view foo-bar enabled sad') }, content: 'hello' }); - } + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view foo-bar enabled sad') }, + content: 'hello' + }); + } - ['@test it should dasherize the path when the it resolves to true']() { - let FooBarComponent = Component.extend({ - classNameBindings: ['fooBar', 'nested.fooBarBaz'] - }); + ['@test it should dasherize the path when the it resolves to true']() { + let FooBarComponent = Component.extend({ + classNameBindings: ['fooBar', 'nested.fooBarBaz'] + }); - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); - this.render('{{foo-bar fooBar=fooBar nested=nested}}', { fooBar: true, nested: { fooBarBaz: false } }); + this.render('{{foo-bar fooBar=fooBar nested=nested}}', { + fooBar: true, + nested: { fooBarBaz: false } + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view foo-bar') }, content: 'hello' }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view foo-bar') }, + content: 'hello' + }); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view foo-bar') }, content: 'hello' }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view foo-bar') }, + content: 'hello' + }); - this.runTask(() => { - set(this.context, 'fooBar', false); - set(this.context, 'nested.fooBarBaz', true); - }); + this.runTask(() => { + set(this.context, 'fooBar', false); + set(this.context, 'nested.fooBarBaz', true); + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view foo-bar-baz') }, content: 'hello' }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view foo-bar-baz') }, + content: 'hello' + }); - this.runTask(() => { - set(this.context, 'fooBar', 'FOO-BAR'); - set(this.context, 'nested.fooBarBaz', null); - }); + this.runTask(() => { + set(this.context, 'fooBar', 'FOO-BAR'); + set(this.context, 'nested.fooBarBaz', null); + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view FOO-BAR') }, content: 'hello' }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view FOO-BAR') }, + content: 'hello' + }); - this.runTask(() => set(this.context, 'nested', null)); + this.runTask(() => set(this.context, 'nested', null)); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view FOO-BAR') }, content: 'hello' }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view FOO-BAR') }, + content: 'hello' + }); - this.runTask(() => { - set(this.context, 'fooBar', true); - set(this.context, 'nested', { fooBarBaz: false }); - }); + this.runTask(() => { + set(this.context, 'fooBar', true); + set(this.context, 'nested', { fooBarBaz: false }); + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view foo-bar') }, content: 'hello' }); - } + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view foo-bar') }, + content: 'hello' + }); + } - ['@test const bindings can be set as attrs']() { - this.registerComponent('foo-bar', { template: 'hello' }); - this.render('{{foo-bar classNameBindings="foo:enabled:disabled"}}', { - foo: true - }); + ['@test const bindings can be set as attrs']() { + this.registerComponent('foo-bar', { template: 'hello' }); + this.render('{{foo-bar classNameBindings="foo:enabled:disabled"}}', { + foo: true + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view enabled') }, content: 'hello' }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view enabled') }, + content: 'hello' + }); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view enabled') }, content: 'hello' }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view enabled') }, + content: 'hello' + }); - this.runTask(() => set(this.context, 'foo', false)); + this.runTask(() => set(this.context, 'foo', false)); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view disabled') }, content: 'hello' }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view disabled') }, + content: 'hello' + }); - this.runTask(() => set(this.context, 'foo', true)); + this.runTask(() => set(this.context, 'foo', true)); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view enabled') }, content: 'hello' }); - } + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view enabled') }, + content: 'hello' + }); + } - ['@test :: class name syntax works with an empty true class']() { - let FooBarComponent = Component.extend({ - classNameBindings: ['isEnabled::not-enabled'] - }); + ['@test :: class name syntax works with an empty true class']() { + let FooBarComponent = Component.extend({ + classNameBindings: ['isEnabled::not-enabled'] + }); - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); - this.render('{{foo-bar isEnabled=enabled}}', { - enabled: false - }); + this.render('{{foo-bar isEnabled=enabled}}', { + enabled: false + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view not-enabled') }, content: 'hello' }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view not-enabled') }, + content: 'hello' + }); - this.runTask(() => set(this.context, 'enabled', true)); + this.runTask(() => set(this.context, 'enabled', true)); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view') }, content: 'hello' }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view') }, + content: 'hello' + }); - this.runTask(() => set(this.context, 'enabled', false)); + this.runTask(() => set(this.context, 'enabled', false)); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view not-enabled') }, content: 'hello' }); - } + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view not-enabled') }, + content: 'hello' + }); + } - ['@test uses all provided static class names (issue #11193)']() { - let FooBarComponent = Component.extend({ - classNameBindings: [':class-one', ':class-two'] - }); + ['@test uses all provided static class names (issue #11193)']() { + let FooBarComponent = Component.extend({ + classNameBindings: [':class-one', ':class-two'] + }); - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); - this.render('{{foo-bar}}', { - enabled: false - }); + this.render('{{foo-bar}}', { + enabled: false + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view class-one class-two') }, content: 'hello' }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view class-one class-two') }, + content: 'hello' + }); - this.runTask(() => set(this.context, 'enabled', true)); + this.runTask(() => set(this.context, 'enabled', true)); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { 'class': classes('ember-view class-one class-two') }, content: 'hello' }); - } + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { class: classes('ember-view class-one class-two') }, + content: 'hello' + }); + } - ['@test Providing a binding with a space in it asserts']() { - let FooBarComponent = Component.extend({ - classNameBindings: 'i:think:i am:so:clever' - }); + ['@test Providing a binding with a space in it asserts']() { + let FooBarComponent = Component.extend({ + classNameBindings: 'i:think:i am:so:clever' + }); - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); - expectAssertion(() => { - this.render('{{foo-bar}}'); - }, /classNameBindings must not have spaces in them/i); - } + expectAssertion(() => { + this.render('{{foo-bar}}'); + }, /classNameBindings must not have spaces in them/i); + } - ['@test it asserts that items must be strings']() { - let FooBarComponent = Component.extend({ - foo: 'foo', - bar: 'bar', - classNameBindings: ['foo', , 'bar'] // eslint-disable-line no-sparse-arrays - }); + ['@test it asserts that items must be strings']() { + let FooBarComponent = Component.extend({ + foo: 'foo', + bar: 'bar', + classNameBindings: ['foo', , 'bar'] // eslint-disable-line no-sparse-arrays + }); - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); - expectAssertion(() => { - this.render('{{foo-bar}}'); - }, /classNameBindings must be non-empty strings/); - } + expectAssertion(() => { + this.render('{{foo-bar}}'); + }, /classNameBindings must be non-empty strings/); + } - ['@test it asserts that items must be non-empty strings']() { - let FooBarComponent = Component.extend({ - foo: 'foo', - bar: 'bar', - classNameBindings: ['foo', '', 'bar'] - }); + ['@test it asserts that items must be non-empty strings']() { + let FooBarComponent = Component.extend({ + foo: 'foo', + bar: 'bar', + classNameBindings: ['foo', '', 'bar'] + }); - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); - expectAssertion(() => { - this.render('{{foo-bar}}'); - }, /classNameBindings must be non-empty strings/); - } + expectAssertion(() => { + this.render('{{foo-bar}}'); + }, /classNameBindings must be non-empty strings/); + } - ['@test it can set class name bindings in the constructor']() { - let FooBarComponent = Component.extend({ - classNameBindings: ['foo'], + ['@test it can set class name bindings in the constructor']() { + let FooBarComponent = Component.extend({ + classNameBindings: ['foo'], - init() { - this._super(); + init() { + this._super(); - let bindings = this.classNameBindings = this.classNameBindings.slice(); + let bindings = (this.classNameBindings = this.classNameBindings.slice()); - if (this.get('bindIsEnabled')) { - bindings.push('isEnabled:enabled'); - } + if (this.get('bindIsEnabled')) { + bindings.push('isEnabled:enabled'); + } - if (this.get('bindIsHappy')) { - bindings.push('isHappy:happy:sad'); + if (this.get('bindIsHappy')) { + bindings.push('isHappy:happy:sad'); + } } - } - }); + }); - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); - this.render(strip` + this.render( + strip` {{foo-bar foo=foo bindIsEnabled=true isEnabled=isEnabled bindIsHappy=false isHappy=isHappy}} {{foo-bar foo=foo bindIsEnabled=false isEnabled=isEnabled bindIsHappy=true isHappy=isHappy}} {{foo-bar foo=foo bindIsEnabled=true isEnabled=isEnabled bindIsHappy=true isHappy=isHappy}} {{foo-bar foo=foo bindIsEnabled=false isEnabled=isEnabled bindIsHappy=false isHappy=isHappy}} - `, { foo: 'foo', isEnabled: true, isHappy: false }); - - this.assertComponentElement(this.nthChild(0), { tagName: 'div', attrs: { 'class': classes('ember-view foo enabled') }, content: 'hello' }); - this.assertComponentElement(this.nthChild(1), { tagName: 'div', attrs: { 'class': classes('ember-view foo sad') }, content: 'hello' }); - this.assertComponentElement(this.nthChild(2), { tagName: 'div', attrs: { 'class': classes('ember-view foo enabled sad') }, content: 'hello' }); - this.assertComponentElement(this.nthChild(3), { tagName: 'div', attrs: { 'class': classes('ember-view foo') }, content: 'hello' }); - - this.runTask(() => this.rerender()); - - this.assertComponentElement(this.nthChild(0), { tagName: 'div', attrs: { 'class': classes('ember-view foo enabled') }, content: 'hello' }); - this.assertComponentElement(this.nthChild(1), { tagName: 'div', attrs: { 'class': classes('ember-view foo sad') }, content: 'hello' }); - this.assertComponentElement(this.nthChild(2), { tagName: 'div', attrs: { 'class': classes('ember-view foo enabled sad') }, content: 'hello' }); - this.assertComponentElement(this.nthChild(3), { tagName: 'div', attrs: { 'class': classes('ember-view foo') }, content: 'hello' }); - - this.runTask(() => { - set(this.context, 'foo', 'FOO'); - set(this.context, 'isEnabled', false); - }); - - this.assertComponentElement(this.nthChild(0), { tagName: 'div', attrs: { 'class': classes('ember-view FOO') }, content: 'hello' }); - this.assertComponentElement(this.nthChild(1), { tagName: 'div', attrs: { 'class': classes('ember-view FOO sad') }, content: 'hello' }); - this.assertComponentElement(this.nthChild(2), { tagName: 'div', attrs: { 'class': classes('ember-view FOO sad') }, content: 'hello' }); - this.assertComponentElement(this.nthChild(3), { tagName: 'div', attrs: { 'class': classes('ember-view FOO') }, content: 'hello' }); - - this.runTask(() => { - set(this.context, 'foo', undefined); - set(this.context, 'isHappy', true); - }); - - this.assertComponentElement(this.nthChild(0), { tagName: 'div', attrs: { 'class': classes('ember-view') }, content: 'hello' }); - this.assertComponentElement(this.nthChild(1), { tagName: 'div', attrs: { 'class': classes('ember-view happy') }, content: 'hello' }); - this.assertComponentElement(this.nthChild(2), { tagName: 'div', attrs: { 'class': classes('ember-view happy') }, content: 'hello' }); - this.assertComponentElement(this.nthChild(3), { tagName: 'div', attrs: { 'class': classes('ember-view') }, content: 'hello' }); - - this.runTask(() => { - set(this.context, 'foo', 'foo'); - set(this.context, 'isEnabled', true); - set(this.context, 'isHappy', false); - }); - - this.assertComponentElement(this.nthChild(0), { tagName: 'div', attrs: { 'class': classes('ember-view foo enabled') }, content: 'hello' }); - this.assertComponentElement(this.nthChild(1), { tagName: 'div', attrs: { 'class': classes('ember-view foo sad') }, content: 'hello' }); - this.assertComponentElement(this.nthChild(2), { tagName: 'div', attrs: { 'class': classes('ember-view foo enabled sad') }, content: 'hello' }); - this.assertComponentElement(this.nthChild(3), { tagName: 'div', attrs: { 'class': classes('ember-view foo') }, content: 'hello' }); - } + `, + { foo: 'foo', isEnabled: true, isHappy: false } + ); + + this.assertComponentElement(this.nthChild(0), { + tagName: 'div', + attrs: { class: classes('ember-view foo enabled') }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(1), { + tagName: 'div', + attrs: { class: classes('ember-view foo sad') }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(2), { + tagName: 'div', + attrs: { class: classes('ember-view foo enabled sad') }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(3), { + tagName: 'div', + attrs: { class: classes('ember-view foo') }, + content: 'hello' + }); - ['@test using a computed property for classNameBindings triggers an assertion']() { - let FooBarComponent = Component.extend({ - classNameBindings: computed(function() { - return ['isHappy:happy:sad']; - }) - }); + this.runTask(() => this.rerender()); + + this.assertComponentElement(this.nthChild(0), { + tagName: 'div', + attrs: { class: classes('ember-view foo enabled') }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(1), { + tagName: 'div', + attrs: { class: classes('ember-view foo sad') }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(2), { + tagName: 'div', + attrs: { class: classes('ember-view foo enabled sad') }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(3), { + tagName: 'div', + attrs: { class: classes('ember-view foo') }, + content: 'hello' + }); - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' }); + this.runTask(() => { + set(this.context, 'foo', 'FOO'); + set(this.context, 'isEnabled', false); + }); - expectAssertion(() => { - this.render('{{foo-bar}}'); - }, /Only arrays are allowed/); - } -}); + this.assertComponentElement(this.nthChild(0), { + tagName: 'div', + attrs: { class: classes('ember-view FOO') }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(1), { + tagName: 'div', + attrs: { class: classes('ember-view FOO sad') }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(2), { + tagName: 'div', + attrs: { class: classes('ember-view FOO sad') }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(3), { + tagName: 'div', + attrs: { class: classes('ember-view FOO') }, + content: 'hello' + }); -moduleFor('ClassBinding integration', class extends RenderingTest { - ['@test it should apply classBinding without condition always']() { - this.registerComponent('foo-bar', { template: 'hello' }); + this.runTask(() => { + set(this.context, 'foo', undefined); + set(this.context, 'isHappy', true); + }); - this.render('{{foo-bar classBinding=":foo"}}'); + this.assertComponentElement(this.nthChild(0), { + tagName: 'div', + attrs: { class: classes('ember-view') }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(1), { + tagName: 'div', + attrs: { class: classes('ember-view happy') }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(2), { + tagName: 'div', + attrs: { class: classes('ember-view happy') }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(3), { + tagName: 'div', + attrs: { class: classes('ember-view') }, + content: 'hello' + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', content: 'hello', attrs: { 'class': classes('foo ember-view') } }); + this.runTask(() => { + set(this.context, 'foo', 'foo'); + set(this.context, 'isEnabled', true); + set(this.context, 'isHappy', false); + }); - this.runTask(() => this.rerender()); + this.assertComponentElement(this.nthChild(0), { + tagName: 'div', + attrs: { class: classes('ember-view foo enabled') }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(1), { + tagName: 'div', + attrs: { class: classes('ember-view foo sad') }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(2), { + tagName: 'div', + attrs: { class: classes('ember-view foo enabled sad') }, + content: 'hello' + }); + this.assertComponentElement(this.nthChild(3), { + tagName: 'div', + attrs: { class: classes('ember-view foo') }, + content: 'hello' + }); + } - this.assertComponentElement(this.firstChild, { tagName: 'div', content: 'hello', attrs: { 'class': classes('foo ember-view') } }); + ['@test using a computed property for classNameBindings triggers an assertion']() { + let FooBarComponent = Component.extend({ + classNameBindings: computed(function() { + return ['isHappy:happy:sad']; + }) + }); + + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: 'hello' + }); + + expectAssertion(() => { + this.render('{{foo-bar}}'); + }, /Only arrays are allowed/); + } } +); - ['@test it should merge classBinding with class']() { - this.registerComponent('foo-bar', { template: 'hello' }); +moduleFor( + 'ClassBinding integration', + class extends RenderingTest { + ['@test it should apply classBinding without condition always']() { + this.registerComponent('foo-bar', { template: 'hello' }); - this.render('{{foo-bar classBinding="birdman:respeck" class="myName"}}', { birdman: true }); + this.render('{{foo-bar classBinding=":foo"}}'); - this.assertComponentElement(this.firstChild, { tagName: 'div', content: 'hello', attrs: { 'class': classes('respeck myName ember-view') } }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + content: 'hello', + attrs: { class: classes('foo ember-view') } + }); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertComponentElement(this.firstChild, { tagName: 'div', content: 'hello', attrs: { 'class': classes('respeck myName ember-view') } }); - } + this.assertComponentElement(this.firstChild, { + tagName: 'div', + content: 'hello', + attrs: { class: classes('foo ember-view') } + }); + } - ['@test it should apply classBinding with only truthy condition']() { - this.registerComponent('foo-bar', { template: 'hello' }); + ['@test it should merge classBinding with class']() { + this.registerComponent('foo-bar', { template: 'hello' }); - this.render('{{foo-bar classBinding="myName:respeck"}}', { myName: true }); + this.render('{{foo-bar classBinding="birdman:respeck" class="myName"}}', { + birdman: true + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', content: 'hello', attrs: { 'class': classes('respeck ember-view') } }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + content: 'hello', + attrs: { class: classes('respeck myName ember-view') } + }); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertComponentElement(this.firstChild, { tagName: 'div', content: 'hello', attrs: { 'class': classes('respeck ember-view') } }); - } + this.assertComponentElement(this.firstChild, { + tagName: 'div', + content: 'hello', + attrs: { class: classes('respeck myName ember-view') } + }); + } - ['@test it should apply classBinding with only falsy condition']() { - this.registerComponent('foo-bar', { template: 'hello' }); + ['@test it should apply classBinding with only truthy condition']() { + this.registerComponent('foo-bar', { template: 'hello' }); - this.render('{{foo-bar classBinding="myName::shade"}}', { myName: false }); + this.render('{{foo-bar classBinding="myName:respeck"}}', { + myName: true + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', content: 'hello', attrs: { 'class': classes('shade ember-view') } }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + content: 'hello', + attrs: { class: classes('respeck ember-view') } + }); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertComponentElement(this.firstChild, { tagName: 'div', content: 'hello', attrs: { 'class': classes('shade ember-view') } }); - } + this.assertComponentElement(this.firstChild, { + tagName: 'div', + content: 'hello', + attrs: { class: classes('respeck ember-view') } + }); + } - ['@test it should apply nothing when classBinding is falsy but only supplies truthy class']() { - this.registerComponent('foo-bar', { template: 'hello' }); + ['@test it should apply classBinding with only falsy condition']() { + this.registerComponent('foo-bar', { template: 'hello' }); - this.render('{{foo-bar classBinding="myName:respeck"}}', { myName: false }); + this.render('{{foo-bar classBinding="myName::shade"}}', { + myName: false + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', content: 'hello', attrs: { 'class': classes('ember-view') } }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + content: 'hello', + attrs: { class: classes('shade ember-view') } + }); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertComponentElement(this.firstChild, { tagName: 'div', content: 'hello', attrs: { 'class': classes('ember-view') } }); - } + this.assertComponentElement(this.firstChild, { + tagName: 'div', + content: 'hello', + attrs: { class: classes('shade ember-view') } + }); + } - ['@test it should apply nothing when classBinding is truthy but only supplies falsy class']() { - this.registerComponent('foo-bar', { template: 'hello' }); + ['@test it should apply nothing when classBinding is falsy but only supplies truthy class']() { + this.registerComponent('foo-bar', { template: 'hello' }); - this.render('{{foo-bar classBinding="myName::shade"}}', { myName: true }); + this.render('{{foo-bar classBinding="myName:respeck"}}', { + myName: false + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', content: 'hello', attrs: { 'class': classes('ember-view') } }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + content: 'hello', + attrs: { class: classes('ember-view') } + }); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertComponentElement(this.firstChild, { tagName: 'div', content: 'hello', attrs: { 'class': classes('ember-view') } }); - } + this.assertComponentElement(this.firstChild, { + tagName: 'div', + content: 'hello', + attrs: { class: classes('ember-view') } + }); + } - ['@test it should apply classBinding with falsy condition']() { - this.registerComponent('foo-bar', { template: 'hello' }); + ['@test it should apply nothing when classBinding is truthy but only supplies falsy class']() { + this.registerComponent('foo-bar', { template: 'hello' }); - this.render('{{foo-bar classBinding="swag:fresh:scrub"}}', { swag: false }); + this.render('{{foo-bar classBinding="myName::shade"}}', { myName: true }); - this.assertComponentElement(this.firstChild, { tagName: 'div', content: 'hello', attrs: { 'class': classes('scrub ember-view') } }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + content: 'hello', + attrs: { class: classes('ember-view') } + }); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertComponentElement(this.firstChild, { tagName: 'div', content: 'hello', attrs: { 'class': classes('scrub ember-view') } }); - } + this.assertComponentElement(this.firstChild, { + tagName: 'div', + content: 'hello', + attrs: { class: classes('ember-view') } + }); + } + + ['@test it should apply classBinding with falsy condition']() { + this.registerComponent('foo-bar', { template: 'hello' }); + + this.render('{{foo-bar classBinding="swag:fresh:scrub"}}', { + swag: false + }); - ['@test it should apply classBinding with truthy condition']() { - this.registerComponent('foo-bar', { template: 'hello' }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + content: 'hello', + attrs: { class: classes('scrub ember-view') } + }); - this.render('{{foo-bar classBinding="swag:fresh:scrub"}}', { swag: true }); + this.runTask(() => this.rerender()); - this.assertComponentElement(this.firstChild, { tagName: 'div', content: 'hello', attrs: { 'class': classes('fresh ember-view') } }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + content: 'hello', + attrs: { class: classes('scrub ember-view') } + }); + } - this.runTask(() => this.rerender()); + ['@test it should apply classBinding with truthy condition']() { + this.registerComponent('foo-bar', { template: 'hello' }); + + this.render('{{foo-bar classBinding="swag:fresh:scrub"}}', { + swag: true + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', content: 'hello', attrs: { 'class': classes('fresh ember-view') } }); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + content: 'hello', + attrs: { class: classes('fresh ember-view') } + }); + + this.runTask(() => this.rerender()); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + content: 'hello', + attrs: { class: classes('fresh ember-view') } + }); + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/components/contextual-components-test.js b/packages/ember-glimmer/tests/integration/components/contextual-components-test.js index 3b3ee60388b..742aade1b5f 100644 --- a/packages/ember-glimmer/tests/integration/components/contextual-components-test.js +++ b/packages/ember-glimmer/tests/integration/components/contextual-components-test.js @@ -5,1310 +5,1504 @@ import { moduleFor, RenderingTest } from '../../utils/test-case'; import { isEmpty } from 'ember-metal'; import { A as emberA } from 'ember-runtime/mixins/array'; -moduleFor('Components test: contextual components', class extends RenderingTest { - ['@test renders with component helper']() { - let expectedText = 'Hodi'; +moduleFor( + 'Components test: contextual components', + class extends RenderingTest { + ['@test renders with component helper']() { + let expectedText = 'Hodi'; + + this.registerComponent('-looked-up', { + template: expectedText + }); - this.registerComponent('-looked-up', { - template: expectedText - }); + this.render('{{component (component "-looked-up")}}'); - this.render('{{component (component "-looked-up")}}'); + this.assertText(expectedText); - this.assertText(expectedText); + this.runTask(() => this.rerender()); - this.runTask(() => this.rerender()); + this.assertText(expectedText); + } - this.assertText(expectedText); - } + ['@test renders with component helper with invocation params, hash']() { + this.registerComponent('-looked-up', { + ComponentClass: Component.extend().reopenClass({ + positionalParams: ['name'] + }), + template: '{{greeting}} {{name}}' + }); - ['@test renders with component helper with invocation params, hash']() { - this.registerComponent('-looked-up', { - ComponentClass: Component.extend().reopenClass({ - positionalParams: ['name'] - }), - template: '{{greeting}} {{name}}' - }); + this.render(strip` + {{component (component "-looked-up") "Hodari" greeting="Hodi"}}`); - this.render(strip` - {{component (component "-looked-up") "Hodari" greeting="Hodi"}}` - ); + this.assertText('Hodi Hodari'); - this.assertText('Hodi Hodari'); + this.runTask(() => this.rerender()); - this.runTask(() => this.rerender()); + this.assertText('Hodi Hodari'); + } - this.assertText('Hodi Hodari'); - } + ['@test GH#13742 keeps nested rest positional parameters if rendered with no positional parameters']() { + this.registerComponent('-looked-up', { + ComponentClass: Component.extend().reopenClass({ + positionalParams: 'params' + }), + template: '{{#each params as |p|}}{{p}}{{/each}}' + }); - ['@test GH#13742 keeps nested rest positional parameters if rendered with no positional parameters']() { - this.registerComponent('-looked-up', { - ComponentClass: Component.extend().reopenClass({ - positionalParams: 'params' - }), - template: '{{#each params as |p|}}{{p}}{{/each}}' - }); - - this.render('{{component (component "-looked-up" model.greeting model.name)}}', { - model: { - greeting: 'Gabon ', - name: 'Zack' - } - }); + this.render( + '{{component (component "-looked-up" model.greeting model.name)}}', + { + model: { + greeting: 'Gabon ', + name: 'Zack' + } + } + ); - this.assertText('Gabon Zack'); + this.assertText('Gabon Zack'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Gabon Zack'); + this.assertText('Gabon Zack'); - this.runTask(() => this.context.set('model.greeting', 'Good morning ')); + this.runTask(() => this.context.set('model.greeting', 'Good morning ')); - this.assertText('Good morning Zack'); + this.assertText('Good morning Zack'); - this.runTask(() => this.context.set('model.name', 'Matthew')); + this.runTask(() => this.context.set('model.name', 'Matthew')); - this.assertText('Good morning Matthew'); + this.assertText('Good morning Matthew'); - this.runTask(() => this.context.set('model', { greeting: 'Gabon ', name: 'Zack' })); + this.runTask(() => + this.context.set('model', { greeting: 'Gabon ', name: 'Zack' }) + ); - this.assertText('Gabon Zack'); - } + this.assertText('Gabon Zack'); + } - // Take a look at this one. Seems to pass even when currying isn't implemented. - ['@test overwrites nested rest positional parameters if rendered with positional parameters']() { - this.registerComponent('-looked-up', { - ComponentClass: Component.extend().reopenClass({ - positionalParams: 'params' - }), - template: '{{#each params as |p|}}{{p}}{{/each}}' - }); - - this.render('{{component (component "-looked-up" model.greeting model.name) model.name model.greeting}}', { - model: { - greeting: 'Gabon ', - name: 'Zack ' - } - }); + // Take a look at this one. Seems to pass even when currying isn't implemented. + ['@test overwrites nested rest positional parameters if rendered with positional parameters']() { + this.registerComponent('-looked-up', { + ComponentClass: Component.extend().reopenClass({ + positionalParams: 'params' + }), + template: '{{#each params as |p|}}{{p}}{{/each}}' + }); - this.assertText('Gabon Zack Zack Gabon '); + this.render( + '{{component (component "-looked-up" model.greeting model.name) model.name model.greeting}}', + { + model: { + greeting: 'Gabon ', + name: 'Zack ' + } + } + ); - this.runTask(() => this.rerender()); + this.assertText('Gabon Zack Zack Gabon '); - this.assertText('Gabon Zack Zack Gabon '); + this.runTask(() => this.rerender()); - this.runTask(() => this.context.set('model.greeting', 'Good morning ')); + this.assertText('Gabon Zack Zack Gabon '); - this.assertText('Good morning Zack Zack Good morning '); + this.runTask(() => this.context.set('model.greeting', 'Good morning ')); - this.runTask(() => this.context.set('model.name', 'Matthew ')); + this.assertText('Good morning Zack Zack Good morning '); - this.assertText('Good morning Matthew Matthew Good morning '); + this.runTask(() => this.context.set('model.name', 'Matthew ')); - this.runTask(() => this.context.set('model', { greeting: 'Gabon ', name: 'Zack ' })); + this.assertText('Good morning Matthew Matthew Good morning '); - this.assertText('Gabon Zack Zack Gabon '); - } + this.runTask(() => + this.context.set('model', { greeting: 'Gabon ', name: 'Zack ' }) + ); - ['@test GH#13742 keeps nested rest positional parameters if nested and rendered with no positional parameters']() { - this.registerComponent('-looked-up', { - ComponentClass: Component.extend().reopenClass({ - positionalParams: 'params' - }), - template: '{{#each params as |p|}}{{p}}{{/each}}' - }); - - this.render('{{component (component (component "-looked-up" model.greeting model.name))}}', { - model: { - greeting: 'Gabon ', - name: 'Zack' - } - }); + this.assertText('Gabon Zack Zack Gabon '); + } - this.assertText('Gabon Zack'); + ['@test GH#13742 keeps nested rest positional parameters if nested and rendered with no positional parameters']() { + this.registerComponent('-looked-up', { + ComponentClass: Component.extend().reopenClass({ + positionalParams: 'params' + }), + template: '{{#each params as |p|}}{{p}}{{/each}}' + }); - this.runTask(() => this.rerender()); + this.render( + '{{component (component (component "-looked-up" model.greeting model.name))}}', + { + model: { + greeting: 'Gabon ', + name: 'Zack' + } + } + ); - this.assertText('Gabon Zack'); + this.assertText('Gabon Zack'); - this.runTask(() => this.context.set('model.greeting', 'Good morning ')); + this.runTask(() => this.rerender()); - this.assertText('Good morning Zack'); + this.assertText('Gabon Zack'); - this.runTask(() => this.context.set('model.name', 'Matthew')); + this.runTask(() => this.context.set('model.greeting', 'Good morning ')); - this.assertText('Good morning Matthew'); + this.assertText('Good morning Zack'); - this.runTask(() => this.context.set('model', { greeting: 'Gabon ', name: 'Zack' })); + this.runTask(() => this.context.set('model.name', 'Matthew')); - this.assertText('Gabon Zack'); - } + this.assertText('Good morning Matthew'); - ['@test overwrites nested rest positional parameters if nested with new pos params and rendered with no positional parameters']() { - this.registerComponent('-looked-up', { - ComponentClass: Component.extend().reopenClass({ - positionalParams: 'params' - }), - template: '{{#each params as |p|}}{{p}}{{/each}}' - }); - - this.render('{{component (component (component "-looked-up" model.greeting model.name) model.name model.greeting)}}', { - model: { - greeting: 'Gabon ', - name: 'Zack ' - } - }); + this.runTask(() => + this.context.set('model', { greeting: 'Gabon ', name: 'Zack' }) + ); + + this.assertText('Gabon Zack'); + } + + ['@test overwrites nested rest positional parameters if nested with new pos params and rendered with no positional parameters']() { + this.registerComponent('-looked-up', { + ComponentClass: Component.extend().reopenClass({ + positionalParams: 'params' + }), + template: '{{#each params as |p|}}{{p}}{{/each}}' + }); + + this.render( + '{{component (component (component "-looked-up" model.greeting model.name) model.name model.greeting)}}', + { + model: { + greeting: 'Gabon ', + name: 'Zack ' + } + } + ); - this.assertText('Gabon Zack Zack Gabon '); + this.assertText('Gabon Zack Zack Gabon '); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Gabon Zack Zack Gabon '); + this.assertText('Gabon Zack Zack Gabon '); - this.runTask(() => this.context.set('model.greeting', 'Good morning ')); + this.runTask(() => this.context.set('model.greeting', 'Good morning ')); - this.assertText('Good morning Zack Zack Good morning '); + this.assertText('Good morning Zack Zack Good morning '); - this.runTask(() => this.context.set('model.name', 'Matthew ')); + this.runTask(() => this.context.set('model.name', 'Matthew ')); - this.assertText('Good morning Matthew Matthew Good morning '); + this.assertText('Good morning Matthew Matthew Good morning '); - this.runTask(() => this.context.set('model', { greeting: 'Gabon ', name: 'Zack ' })); + this.runTask(() => + this.context.set('model', { greeting: 'Gabon ', name: 'Zack ' }) + ); - this.assertText('Gabon Zack Zack Gabon '); - } + this.assertText('Gabon Zack Zack Gabon '); + } - ['@test renders with component helper with curried params, hash']() { - this.registerComponent('-looked-up', { - ComponentClass: Component.extend().reopenClass({ - positionalParams: ['name'] - }), - template: '{{greeting}} {{name}}' - }); + ['@test renders with component helper with curried params, hash']() { + this.registerComponent('-looked-up', { + ComponentClass: Component.extend().reopenClass({ + positionalParams: ['name'] + }), + template: '{{greeting}} {{name}}' + }); - this.render(strip` + this.render(strip` {{component (component "-looked-up" "Hodari" greeting="Hodi") - greeting="Hola"}}` - ); + greeting="Hola"}}`); - this.assertText('Hola Hodari'); + this.assertText('Hola Hodari'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Hola Hodari'); - } + this.assertText('Hola Hodari'); + } - ['@test updates when component path is bound']() { - this.registerComponent('-mandarin', { - template: 'ni hao' - }); + ['@test updates when component path is bound']() { + this.registerComponent('-mandarin', { + template: 'ni hao' + }); - this.registerComponent('-hindi', { - template: 'Namaste' - }); + this.registerComponent('-hindi', { + template: 'Namaste' + }); - this.render('{{component (component model.lookupComponent)}}', { - model: { - lookupComponent: '-mandarin' - } - }); + this.render('{{component (component model.lookupComponent)}}', { + model: { + lookupComponent: '-mandarin' + } + }); - this.assertText('ni hao'); + this.assertText('ni hao'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('ni hao'); + this.assertText('ni hao'); - this.runTask(() => this.context.set('model.lookupComponent', '-hindi')); + this.runTask(() => this.context.set('model.lookupComponent', '-hindi')); - this.assertText('Namaste'); + this.assertText('Namaste'); - this.runTask(() => this.context.set('model', { lookupComponent: '-mandarin' })); + this.runTask(() => + this.context.set('model', { lookupComponent: '-mandarin' }) + ); - this.assertText('ni hao'); - } + this.assertText('ni hao'); + } - ['@test updates when curried hash argument is bound']() { - this.registerComponent('-looked-up', { - template: '{{greeting}}' - }); + ['@test updates when curried hash argument is bound']() { + this.registerComponent('-looked-up', { + template: '{{greeting}}' + }); - this.render(`{{component (component "-looked-up" greeting=model.greeting)}}`, { - model: { - greeting: 'Hodi' - } - }); + this.render( + `{{component (component "-looked-up" greeting=model.greeting)}}`, + { + model: { + greeting: 'Hodi' + } + } + ); - this.assertText('Hodi'); + this.assertText('Hodi'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Hodi'); + this.assertText('Hodi'); - this.runTask(() => this.context.set('model.greeting', 'Hola')); + this.runTask(() => this.context.set('model.greeting', 'Hola')); - this.assertText('Hola'); + this.assertText('Hola'); - this.runTask(() => this.context.set('model', { greeting: 'Hodi' })); + this.runTask(() => this.context.set('model', { greeting: 'Hodi' })); - this.assertText('Hodi'); - } + this.assertText('Hodi'); + } - ['@test updates when curried hash arguments is bound in block form']() { - this.registerComponent('-looked-up', { - template: '{{greeting}}' - }); + ['@test updates when curried hash arguments is bound in block form']() { + this.registerComponent('-looked-up', { + template: '{{greeting}}' + }); - this.render(strip` + this.render( + strip` {{#with (hash comp=(component "-looked-up" greeting=model.greeting)) as |my|}} {{#my.comp}}{{/my.comp}} - {{/with}}`, { - model: { - greeting: 'Hodi' + {{/with}}`, + { + model: { + greeting: 'Hodi' + } } - } - ); + ); - this.assertText('Hodi'); + this.assertText('Hodi'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Hodi'); + this.assertText('Hodi'); - this.runTask(() => this.context.set('model.greeting', 'Hola')); + this.runTask(() => this.context.set('model.greeting', 'Hola')); - this.assertText('Hola'); + this.assertText('Hola'); - this.runTask(() => this.context.set('model', { greeting: 'Hodi' })); + this.runTask(() => this.context.set('model', { greeting: 'Hodi' })); - this.assertText('Hodi'); - } + this.assertText('Hodi'); + } - ['@test nested components do not overwrite positional parameters']() { - this.registerComponent('-looked-up', { - ComponentClass: Component.extend().reopenClass({ - positionalParams: ['name', 'age'] - }), - template: '{{name}} {{age}}' - }); + ['@test nested components do not overwrite positional parameters']() { + this.registerComponent('-looked-up', { + ComponentClass: Component.extend().reopenClass({ + positionalParams: ['name', 'age'] + }), + template: '{{name}} {{age}}' + }); - this.render('{{component (component (component "-looked-up" "Sergio" 29) "Marvin" 21) "Hodari"}}'); + this.render( + '{{component (component (component "-looked-up" "Sergio" 29) "Marvin" 21) "Hodari"}}' + ); - this.assertText('Sergio 29'); + this.assertText('Sergio 29'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Sergio 29'); - } + this.assertText('Sergio 29'); + } - ['@test positional parameters are combined not clobbered']() { - this.registerComponent('-looked-up', { - ComponentClass: Component.extend().reopenClass({ - positionalParams: ['greeting', 'name', 'age'] - }), - template: '{{greeting}} {{name}} {{age}}' - }); + ['@test positional parameters are combined not clobbered']() { + this.registerComponent('-looked-up', { + ComponentClass: Component.extend().reopenClass({ + positionalParams: ['greeting', 'name', 'age'] + }), + template: '{{greeting}} {{name}} {{age}}' + }); - this.render('{{component (component (component "-looked-up" "Hi") "Max") 9}}'); + this.render( + '{{component (component (component "-looked-up" "Hi") "Max") 9}}' + ); - this.assertText('Hi Max 9'); + this.assertText('Hi Max 9'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Hi Max 9'); - } + this.assertText('Hi Max 9'); + } - ['@test nested components positional parameters override named parameters [DEPRECATED]']() { - this.registerComponent('-looked-up', { - ComponentClass: Component.extend().reopenClass({ - positionalParams: ['name', 'age'] - }), - template: '{{name}} {{age}}' - }); + ['@test nested components positional parameters override named parameters [DEPRECATED]']() { + this.registerComponent('-looked-up', { + ComponentClass: Component.extend().reopenClass({ + positionalParams: ['name', 'age'] + }), + template: '{{name}} {{age}}' + }); - expectDeprecation(() => { - this.render('{{component (component (component "-looked-up" "Sergio" 29) name="Marvin" age=21)}}'); - }, 'You cannot specify both a positional param (at position 1) and the hash argument `age`.'); + expectDeprecation(() => { + this.render( + '{{component (component (component "-looked-up" "Sergio" 29) name="Marvin" age=21)}}' + ); + }, 'You cannot specify both a positional param (at position 1) and the hash argument `age`.'); - this.assertText('Sergio 29'); + this.assertText('Sergio 29'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Sergio 29'); - } + this.assertText('Sergio 29'); + } - ['@test nested components with positional params at outer layer are override hash parameters [DEPRECATED]']() { - this.registerComponent('-looked-up', { - ComponentClass: Component.extend().reopenClass({ - positionalParams: ['greeting', 'name', 'age'] - }), - template: '{{greeting}} {{name}} {{age}}' - }); + ['@test nested components with positional params at outer layer are override hash parameters [DEPRECATED]']() { + this.registerComponent('-looked-up', { + ComponentClass: Component.extend().reopenClass({ + positionalParams: ['greeting', 'name', 'age'] + }), + template: '{{greeting}} {{name}} {{age}}' + }); - expectDeprecation(() => { - this.render( - strip` + expectDeprecation(() => { + this.render( + strip` {{#with (component "-looked-up" "Hola" "Dolores" 33) as |first|}} {{#with (component first greeting="Hej" name="Sigmundur") as |second|}} {{component second greeting=model.greeting}} {{/with}} {{/with}}`, - { - model: { - greeting: 'Hodi' + { + model: { + greeting: 'Hodi' + } } - } - ); - }, 'You cannot specify both a positional param (at position 1) and the hash argument `name`.'); + ); + }, 'You cannot specify both a positional param (at position 1) and the hash argument `name`.'); - this.assertText('Hola Dolores 33'); + this.assertText('Hola Dolores 33'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Hola Dolores 33'); - } + this.assertText('Hola Dolores 33'); + } - ['@test nested components with positional params at middle layer partially override hash parameters [DEPRECATED]']() { - this.registerComponent('-looked-up', { - ComponentClass: Component.extend().reopenClass({ - positionalParams: ['greeting', 'name', 'age'] - }), + ['@test nested components with positional params at middle layer partially override hash parameters [DEPRECATED]']() { + this.registerComponent('-looked-up', { + ComponentClass: Component.extend().reopenClass({ + positionalParams: ['greeting', 'name', 'age'] + }), - template: '{{greeting}} {{name}} {{age}}' - }); + template: '{{greeting}} {{name}} {{age}}' + }); - expectDeprecation(() => { - this.render( - strip` + expectDeprecation(() => { + this.render( + strip` {{#with (component "-looked-up" greeting="Hola" name="Dolores" age=33) as |first|}} {{#with (component first "Hej" "Sigmundur") as |second|}} {{component second greeting=model.greeting}} {{/with}} {{/with}}`, - { - model: { - greeting: 'Hodi' + { + model: { + greeting: 'Hodi' + } } - } - ); - }, 'You cannot specify both a positional param (at position 0) and the hash argument `greeting`.'); + ); + }, 'You cannot specify both a positional param (at position 0) and the hash argument `greeting`.'); - this.assertText('Hej Sigmundur 33'); + this.assertText('Hej Sigmundur 33'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Hej Sigmundur 33'); - } + this.assertText('Hej Sigmundur 33'); + } - ['@test nested components with positional params at invocation override earlier hash parameters [DEPRECATED]']() { - this.registerComponent('-looked-up', { - ComponentClass: Component.extend().reopenClass({ - positionalParams: ['greeting', 'name', 'age'] - }), + ['@test nested components with positional params at invocation override earlier hash parameters [DEPRECATED]']() { + this.registerComponent('-looked-up', { + ComponentClass: Component.extend().reopenClass({ + positionalParams: ['greeting', 'name', 'age'] + }), - template: '{{greeting}} {{name}} {{age}}' - }); + template: '{{greeting}} {{name}} {{age}}' + }); - expectDeprecation(() => { - this.render( - strip` + expectDeprecation(() => { + this.render( + strip` {{#with (component "-looked-up" greeting="Hola" name="Dolores" age=33) as |first|}} {{#with (component first greeting="Hej" name="Sigmundur") as |second|}} {{component second model.greeting}} {{/with}} {{/with}}`, - { - model: { - greeting: 'Hodi' + { + model: { + greeting: 'Hodi' + } } - } - ); - }, 'You cannot specify both a positional param (at position 0) and the hash argument `greeting`.'); + ); + }, 'You cannot specify both a positional param (at position 0) and the hash argument `greeting`.'); - this.assertText('Hodi Sigmundur 33'); + this.assertText('Hodi Sigmundur 33'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Hodi Sigmundur 33'); + this.assertText('Hodi Sigmundur 33'); - this.runTask(() => this.context.set('model.greeting', 'Kaixo')); + this.runTask(() => this.context.set('model.greeting', 'Kaixo')); - this.assertText('Kaixo Sigmundur 33'); + this.assertText('Kaixo Sigmundur 33'); - this.runTask(() => this.context.set('model', { greeting: 'Hodi' })); + this.runTask(() => this.context.set('model', { greeting: 'Hodi' })); - this.assertText('Hodi Sigmundur 33'); - } + this.assertText('Hodi Sigmundur 33'); + } - ['@test nested components overwrite hash parameters']() { - this.registerComponent('-looked-up', { - template: '{{greeting}} {{name}} {{age}}' - }); + ['@test nested components overwrite hash parameters']() { + this.registerComponent('-looked-up', { + template: '{{greeting}} {{name}} {{age}}' + }); - this.render(strip` + this.render( + strip` {{#with (component "-looked-up" greeting="Hola" name="Dolores" age=33) as |first|}} {{#with (component first greeting="Hej" name="Sigmundur") as |second|}} {{component second greeting=model.greeting}} {{/with}} - {{/with}}`, { - model: { - greeting: 'Hodi' + {{/with}}`, + { + model: { + greeting: 'Hodi' + } } - }); + ); - this.assertText('Hodi Sigmundur 33'); + this.assertText('Hodi Sigmundur 33'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Hodi Sigmundur 33'); + this.assertText('Hodi Sigmundur 33'); - this.runTask(() => this.context.set('model.greeting', 'Kaixo')); + this.runTask(() => this.context.set('model.greeting', 'Kaixo')); - this.assertText('Kaixo Sigmundur 33'); + this.assertText('Kaixo Sigmundur 33'); - this.runTask(() => this.context.set('model', { greeting: 'Hodi' })); + this.runTask(() => this.context.set('model', { greeting: 'Hodi' })); - this.assertText('Hodi Sigmundur 33'); - } + this.assertText('Hodi Sigmundur 33'); + } - ['@test bound outer named parameters get updated in the right scope']() { - this.registerComponent('-inner-component', { - ComponentClass: Component.extend().reopenClass({ - positionalParams: ['comp'] - }), - template: '{{component comp "Inner"}}' - }); - - this.registerComponent('-looked-up', { - ComponentClass: Component.extend().reopenClass({ - positionalParams: ['name', 'age'] - }), - template: '{{name}} {{age}}' - }); - - this.render('{{component "-inner-component" (component "-looked-up" model.outerName model.outerAge)}}', { - model: { - outerName: 'Outer', - outerAge: 28 - } - }); + ['@test bound outer named parameters get updated in the right scope']() { + this.registerComponent('-inner-component', { + ComponentClass: Component.extend().reopenClass({ + positionalParams: ['comp'] + }), + template: '{{component comp "Inner"}}' + }); + + this.registerComponent('-looked-up', { + ComponentClass: Component.extend().reopenClass({ + positionalParams: ['name', 'age'] + }), + template: '{{name}} {{age}}' + }); + + this.render( + '{{component "-inner-component" (component "-looked-up" model.outerName model.outerAge)}}', + { + model: { + outerName: 'Outer', + outerAge: 28 + } + } + ); - this.assertText('Outer 28'); + this.assertText('Outer 28'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Outer 28'); + this.assertText('Outer 28'); - this.runTask(() => this.context.set('model.outerAge', 29)); + this.runTask(() => this.context.set('model.outerAge', 29)); - this.assertText('Outer 29'); + this.assertText('Outer 29'); - this.runTask(() => this.context.set('model.outerName', 'Not outer')); + this.runTask(() => this.context.set('model.outerName', 'Not outer')); - this.assertText('Not outer 29'); + this.assertText('Not outer 29'); - this.runTask(() => { - this.context.set('model', { - outerName: 'Outer', - outerAge: 28 + this.runTask(() => { + this.context.set('model', { + outerName: 'Outer', + outerAge: 28 + }); }); - }); - this.assertText('Outer 28'); - } + this.assertText('Outer 28'); + } - ['@test bound outer hash parameters get updated in the right scope']() { - this.registerComponent('-inner-component', { - ComponentClass: Component.extend().reopenClass({ - positionalParams: ['comp'] - }), - template: '{{component comp name="Inner"}}' - }); - - this.registerComponent('-looked-up', { - template: '{{name}} {{age}}' - }); - - this.render('{{component "-inner-component" (component "-looked-up" name=model.outerName age=model.outerAge)}}', { - model: { - outerName: 'Outer', - outerAge: 28 - } - }); + ['@test bound outer hash parameters get updated in the right scope']() { + this.registerComponent('-inner-component', { + ComponentClass: Component.extend().reopenClass({ + positionalParams: ['comp'] + }), + template: '{{component comp name="Inner"}}' + }); - this.assertText('Inner 28'); + this.registerComponent('-looked-up', { + template: '{{name}} {{age}}' + }); - this.runTask(() => this.rerender()); + this.render( + '{{component "-inner-component" (component "-looked-up" name=model.outerName age=model.outerAge)}}', + { + model: { + outerName: 'Outer', + outerAge: 28 + } + } + ); + + this.assertText('Inner 28'); + + this.runTask(() => this.rerender()); - this.assertText('Inner 28'); + this.assertText('Inner 28'); - this.runTask(() => this.context.set('model.outerAge', 29)); + this.runTask(() => this.context.set('model.outerAge', 29)); - this.assertText('Inner 29'); + this.assertText('Inner 29'); - this.runTask(() => this.context.set('model.outerName', 'Not outer')); + this.runTask(() => this.context.set('model.outerName', 'Not outer')); - this.assertText('Inner 29'); + this.assertText('Inner 29'); - this.runTask(() => { - this.context.set('model', { - outerName: 'Outer', - outerAge: 28 + this.runTask(() => { + this.context.set('model', { + outerName: 'Outer', + outerAge: 28 + }); }); - }); - this.assertText('Inner 28'); - } + this.assertText('Inner 28'); + } - ['@test conflicting positional and hash parameters trigger a deprecation if in the same component context [DEPRECATED]']() { - this.registerComponent('-looked-up', { - ComponentClass: Component.extend().reopenClass({ - positionalParams: ['name'] - }), - template: '{{greeting}} {{name}}' - }); - - expectDeprecation(() => { - this.render('{{component (component "-looked-up" "Hodari" name="Sergio") "Hodari" greeting="Hodi"}}'); - }, 'You cannot specify both a positional param (at position 0) and the hash argument `name`.'); - } + ['@test conflicting positional and hash parameters trigger a deprecation if in the same component context [DEPRECATED]']() { + this.registerComponent('-looked-up', { + ComponentClass: Component.extend().reopenClass({ + positionalParams: ['name'] + }), + template: '{{greeting}} {{name}}' + }); - ['@test conflicting positional and hash parameters does not raise an assertion if rerendered']() { - // In some cases, rerendering with a positional param used to cause an - // assertion. This test checks it does not. - this.registerComponent('-looked-up', { - ComponentClass: Component.extend().reopenClass({ - positionalParams: ['name'] - }), - template: '{{greeting}} {{name}}' - }); - - this.render('{{component (component "-looked-up" model.name greeting="Hodi")}}', { - model: { - name: 'Hodari' - } - }); + expectDeprecation(() => { + this.render( + '{{component (component "-looked-up" "Hodari" name="Sergio") "Hodari" greeting="Hodi"}}' + ); + }, 'You cannot specify both a positional param (at position 0) and the hash argument `name`.'); + } - this.assertText('Hodi Hodari'); + ['@test conflicting positional and hash parameters does not raise an assertion if rerendered']() { + // In some cases, rerendering with a positional param used to cause an + // assertion. This test checks it does not. + this.registerComponent('-looked-up', { + ComponentClass: Component.extend().reopenClass({ + positionalParams: ['name'] + }), + template: '{{greeting}} {{name}}' + }); - this.runTask(() => this.rerender()); + this.render( + '{{component (component "-looked-up" model.name greeting="Hodi")}}', + { + model: { + name: 'Hodari' + } + } + ); - this.assertText('Hodi Hodari'); + this.assertText('Hodi Hodari'); - this.runTask(() => this.context.set('model.name', 'Sergio')); + this.runTask(() => this.rerender()); - this.assertText('Hodi Sergio'); + this.assertText('Hodi Hodari'); - this.runTask(() => this.context.set('model', { name: 'Hodari' })); + this.runTask(() => this.context.set('model.name', 'Sergio')); - this.assertText('Hodi Hodari'); - } + this.assertText('Hodi Sergio'); + + this.runTask(() => this.context.set('model', { name: 'Hodari' })); + + this.assertText('Hodi Hodari'); + } - ['@test conflicting positional and hash parameters trigger a deprecation [DEPRECATED]']() { - this.registerComponent('-looked-up', { - ComponentClass: Component.extend().reopenClass({ - positionalParams: ['name'] - }), - template: '{{greeting}} {{name}}' - }); + ['@test conflicting positional and hash parameters trigger a deprecation [DEPRECATED]']() { + this.registerComponent('-looked-up', { + ComponentClass: Component.extend().reopenClass({ + positionalParams: ['name'] + }), + template: '{{greeting}} {{name}}' + }); - expectDeprecation(() => { - this.render('{{component (component "-looked-up" "Hodari") name="Sergio" greeting="Hodi"}}'); - }, 'You cannot specify both a positional param (at position 0) and the hash argument `name`.'); + expectDeprecation(() => { + this.render( + '{{component (component "-looked-up" "Hodari") name="Sergio" greeting="Hodi"}}' + ); + }, 'You cannot specify both a positional param (at position 0) and the hash argument `name`.'); - this.assertText('Hodi Hodari'); + this.assertText('Hodi Hodari'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Hodi Hodari'); - } + this.assertText('Hodi Hodari'); + } - ['@test component with dynamic component name resolving to undefined, then an existing component']() { - this.registerComponent('foo-bar', { template: 'hello {{name}}' }); + ['@test component with dynamic component name resolving to undefined, then an existing component']() { + this.registerComponent('foo-bar', { template: 'hello {{name}}' }); - this.render('{{component (component componentName name=name)}}', { componentName: undefined, name: 'Alex' }); + this.render('{{component (component componentName name=name)}}', { + componentName: undefined, + name: 'Alex' + }); - this.assertText(''); + this.assertText(''); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText(''); + this.assertText(''); - this.runTask(() => this.context.set('componentName', 'foo-bar')); + this.runTask(() => this.context.set('componentName', 'foo-bar')); - this.assertText('hello Alex'); + this.assertText('hello Alex'); - this.runTask(() => this.context.set('componentName', undefined)); + this.runTask(() => this.context.set('componentName', undefined)); - this.assertText(''); - } + this.assertText(''); + } - ['@test component with dynamic component name resolving to a component, then undefined']() { - this.registerComponent('foo-bar', { template: 'hello {{name}}' }); + ['@test component with dynamic component name resolving to a component, then undefined']() { + this.registerComponent('foo-bar', { template: 'hello {{name}}' }); - this.render('{{component (component componentName name=name)}}', { componentName: 'foo-bar', name: 'Alex' }); + this.render('{{component (component componentName name=name)}}', { + componentName: 'foo-bar', + name: 'Alex' + }); - this.assertText('hello Alex'); + this.assertText('hello Alex'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('hello Alex'); + this.assertText('hello Alex'); - this.runTask(() => this.context.set('componentName', undefined)); + this.runTask(() => this.context.set('componentName', undefined)); - this.assertText(''); + this.assertText(''); - this.runTask(() => this.context.set('componentName', 'foo-bar')); + this.runTask(() => this.context.set('componentName', 'foo-bar')); - this.assertText('hello Alex'); - } + this.assertText('hello Alex'); + } - ['@test component with dynamic component name resolving to null, then an existing component']() { - this.registerComponent('foo-bar', { template: 'hello {{name}}' }); + ['@test component with dynamic component name resolving to null, then an existing component']() { + this.registerComponent('foo-bar', { template: 'hello {{name}}' }); - this.render('{{component (component componentName name=name)}}', { componentName: null, name: 'Alex' }); + this.render('{{component (component componentName name=name)}}', { + componentName: null, + name: 'Alex' + }); - this.assertText(''); + this.assertText(''); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText(''); + this.assertText(''); - this.runTask(() => this.context.set('componentName', 'foo-bar')); + this.runTask(() => this.context.set('componentName', 'foo-bar')); - this.assertText('hello Alex'); + this.assertText('hello Alex'); - this.runTask(() => this.context.set('componentName', null)); + this.runTask(() => this.context.set('componentName', null)); - this.assertText(''); - } + this.assertText(''); + } - ['@test component with dynamic component name resolving to a component, then null']() { - this.registerComponent('foo-bar', { template: 'hello {{name}}' }); + ['@test component with dynamic component name resolving to a component, then null']() { + this.registerComponent('foo-bar', { template: 'hello {{name}}' }); - this.render('{{component (component componentName name=name)}}', { componentName: 'foo-bar', name: 'Alex' }); + this.render('{{component (component componentName name=name)}}', { + componentName: 'foo-bar', + name: 'Alex' + }); - this.assertText('hello Alex'); + this.assertText('hello Alex'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('hello Alex'); + this.assertText('hello Alex'); - this.runTask(() => this.context.set('componentName', null)); + this.runTask(() => this.context.set('componentName', null)); - this.assertText(''); + this.assertText(''); - this.runTask(() => this.context.set('componentName', 'foo-bar')); + this.runTask(() => this.context.set('componentName', 'foo-bar')); - this.assertText('hello Alex'); - } + this.assertText('hello Alex'); + } - ['@test raises an assertion when component path is not a component name (static)']() { - expectAssertion(() => { - this.render('{{component (component "not-a-component")}}'); - }, 'Could not find component named \"not-a-component\" (no component or template with that name was found)'); - } + ['@test raises an assertion when component path is not a component name (static)']() { + expectAssertion(() => { + this.render('{{component (component "not-a-component")}}'); + }, 'Could not find component named "not-a-component" (no component or template with that name was found)'); + } - ['@test raises an assertion when component path is not a component name (dynamic)']() { - expectAssertion(() => { - this.render('{{component (component compName)}}', { compName: "not-a-component" }); - }, 'Could not find component named \"not-a-component\" (no component or template with that name was found)'); - } + ['@test raises an assertion when component path is not a component name (dynamic)']() { + expectAssertion(() => { + this.render('{{component (component compName)}}', { + compName: 'not-a-component' + }); + }, 'Could not find component named "not-a-component" (no component or template with that name was found)'); + } - ['@test renders with dot path']() { - let expectedText = 'Hodi'; - this.registerComponent('-looked-up', { - template: expectedText - }); + ['@test renders with dot path']() { + let expectedText = 'Hodi'; + this.registerComponent('-looked-up', { + template: expectedText + }); - this.render(strip` + this.render(strip` {{#with (hash lookedup=(component "-looked-up")) as |object|}} {{object.lookedup}} {{/with}}`); - this.assertText(expectedText); + this.assertText(expectedText); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText(expectedText); - } + this.assertText(expectedText); + } - ['@test renders with dot path and attr']() { - let expectedText = 'Hodi'; - this.registerComponent('-looked-up', { - template: '{{expectedText}}' - }); + ['@test renders with dot path and attr']() { + let expectedText = 'Hodi'; + this.registerComponent('-looked-up', { + template: '{{expectedText}}' + }); - this.render(strip` + this.render( + strip` {{#with (hash lookedup=(component "-looked-up")) as |object|}} {{object.lookedup expectedText=model.expectedText}} - {{/with}}`, { - model: { - expectedText + {{/with}}`, + { + model: { + expectedText + } } - } - ); + ); - this.assertText(expectedText); + this.assertText(expectedText); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText(expectedText); + this.assertText(expectedText); - this.runTask(() => this.context.set('model.expectedText', 'Hola')); + this.runTask(() => this.context.set('model.expectedText', 'Hola')); - this.assertText('Hola'); + this.assertText('Hola'); - this.runTask(() => this.context.set('model', { expectedText })); + this.runTask(() => this.context.set('model', { expectedText })); - this.assertText(expectedText); - } + this.assertText(expectedText); + } - ['@test renders with dot path and curried over attr']() { - let expectedText = 'Hodi'; - this.registerComponent('-looked-up', { - template: '{{expectedText}}' - }); + ['@test renders with dot path and curried over attr']() { + let expectedText = 'Hodi'; + this.registerComponent('-looked-up', { + template: '{{expectedText}}' + }); - this.render(strip` + this.render( + strip` {{#with (hash lookedup=(component "-looked-up" expectedText=model.expectedText)) as |object|}} {{object.lookedup}} - {{/with}}`, { - model: { - expectedText + {{/with}}`, + { + model: { + expectedText + } } - } - ); + ); - this.assertText(expectedText); + this.assertText(expectedText); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText(expectedText); + this.assertText(expectedText); - this.runTask(() => this.context.set('model.expectedText', 'Hola')); + this.runTask(() => this.context.set('model.expectedText', 'Hola')); - this.assertText('Hola'); + this.assertText('Hola'); - this.runTask(() => this.context.set('model', { expectedText })); + this.runTask(() => this.context.set('model', { expectedText })); - this.assertText(expectedText); - } + this.assertText(expectedText); + } - ['@test renders with dot path and with rest positional parameters']() { - this.registerComponent('-looked-up', { - ComponentClass: Component.extend().reopenClass({ - positionalParams: 'params' - }), - template: '{{params}}' - }); + ['@test renders with dot path and with rest positional parameters']() { + this.registerComponent('-looked-up', { + ComponentClass: Component.extend().reopenClass({ + positionalParams: 'params' + }), + template: '{{params}}' + }); - let expectedText = 'Hodi'; + let expectedText = 'Hodi'; - this.render(strip` + this.render( + strip` {{#with (hash lookedup=(component "-looked-up")) as |object|}} {{object.lookedup model.expectedText "Hola"}} - {{/with}}`, { - model: { - expectedText + {{/with}}`, + { + model: { + expectedText + } } - } - ); + ); - this.assertText(`${expectedText},Hola`); + this.assertText(`${expectedText},Hola`); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText(`${expectedText},Hola`); + this.assertText(`${expectedText},Hola`); - this.runTask(() => this.context.set('model.expectedText', 'Kaixo')); + this.runTask(() => this.context.set('model.expectedText', 'Kaixo')); - this.assertText('Kaixo,Hola'); + this.assertText('Kaixo,Hola'); - this.runTask(() => this.context.set('model', { expectedText })); + this.runTask(() => this.context.set('model', { expectedText })); - this.assertText(`${expectedText},Hola`); - } + this.assertText(`${expectedText},Hola`); + } - ['@test renders with dot path and rest parameter does not leak'](assert) { - // In the original implementation, positional parameters were not handled - // correctly causing the first positional parameter to be the contextual - // component itself. - let value = false; + ['@test renders with dot path and rest parameter does not leak'](assert) { + // In the original implementation, positional parameters were not handled + // correctly causing the first positional parameter to be the contextual + // component itself. + let value = false; - this.registerComponent('my-component', { - ComponentClass: Component.extend({ - didReceiveAttrs() { - value = this.getAttr('value'); - } - }).reopenClass({ - positionalParams: ['value'] - }) - }); + this.registerComponent('my-component', { + ComponentClass: Component.extend({ + didReceiveAttrs() { + value = this.getAttr('value'); + } + }).reopenClass({ + positionalParams: ['value'] + }) + }); - this.render(strip` + this.render( + strip` {{#with (hash my-component=(component 'my-component' first)) as |c|}} {{c.my-component}} - {{/with}}`, { first: 'first' } - ); + {{/with}}`, + { first: 'first' } + ); - assert.equal(value, 'first', 'value is the expected parameter'); - } + assert.equal(value, 'first', 'value is the expected parameter'); + } - ['@test renders with dot path and updates attributes'](assert) { - this.registerComponent('my-nested-component', { - ComponentClass: Component.extend({ - didReceiveAttrs() { - this.set('myProp', this.getAttr('my-parent-attr')); - } - }), - template: '{{myProp}}' - }); - - this.registerComponent('my-component', { - template: '{{yield (hash my-nested-component=(component "my-nested-component" my-parent-attr=my-attr))}}' - }); - - this.registerComponent('my-action-component', { - ComponentClass: Component.extend({ - actions: { - changeValue() { this.incrementProperty('myProp'); } - } - }), - template: strip` + ['@test renders with dot path and updates attributes'](assert) { + this.registerComponent('my-nested-component', { + ComponentClass: Component.extend({ + didReceiveAttrs() { + this.set('myProp', this.getAttr('my-parent-attr')); + } + }), + template: '{{myProp}}' + }); + + this.registerComponent('my-component', { + template: + '{{yield (hash my-nested-component=(component "my-nested-component" my-parent-attr=my-attr))}}' + }); + + this.registerComponent('my-action-component', { + ComponentClass: Component.extend({ + actions: { + changeValue() { + this.incrementProperty('myProp'); + } + } + }), + template: strip` {{#my-component my-attr=myProp as |api|}} {{api.my-nested-component}} {{/my-component}}
` - }); + }); - this.render('{{my-action-component myProp=model.myProp}}', { - model: { - myProp: 1 - } - }); + this.render('{{my-action-component myProp=model.myProp}}', { + model: { + myProp: 1 + } + }); - assert.equal(this.$('#nested-prop').text(), '1'); + assert.equal(this.$('#nested-prop').text(), '1'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - assert.equal(this.$('#nested-prop').text(), '1'); + assert.equal(this.$('#nested-prop').text(), '1'); - this.runTask(() => this.$('button').click()); + this.runTask(() => this.$('button').click()); - assert.equal(this.$('#nested-prop').text(), '2'); + assert.equal(this.$('#nested-prop').text(), '2'); - this.runTask(() => this.$('button').click()); + this.runTask(() => this.$('button').click()); - assert.equal(this.$('#nested-prop').text(), '3'); + assert.equal(this.$('#nested-prop').text(), '3'); - this.runTask(() => this.context.set('model', { myProp: 1 })); + this.runTask(() => this.context.set('model', { myProp: 1 })); - assert.equal(this.$('#nested-prop').text(), '1'); - } + assert.equal(this.$('#nested-prop').text(), '1'); + } - ['@test adding parameters to a contextual component\'s instance does not add it to other instances']() { - // If parameters and attributes are not handled correctly, setting a value - // in an invokation can leak to others invocation. - this.registerComponent('select-box', { - template: '{{yield (hash option=(component "select-box-option"))}}' - }); + ["@test adding parameters to a contextual component's instance does not add it to other instances"]() { + // If parameters and attributes are not handled correctly, setting a value + // in an invokation can leak to others invocation. + this.registerComponent('select-box', { + template: '{{yield (hash option=(component "select-box-option"))}}' + }); - this.registerComponent('select-box-option', { - template: '{{label}}' - }); + this.registerComponent('select-box-option', { + template: '{{label}}' + }); - this.render(strip` + this.render(strip` {{#select-box as |sb|}} {{sb.option label="Foo"}} {{sb.option}} {{/select-box}}`); - this.assertText('Foo'); + this.assertText('Foo'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Foo'); - } - - ['@test parameters in a contextual component are mutable when value is a param'](assert) { - // This checks that a `(mut)` is added to parameters and attributes to - // contextual components when it is a param. + this.assertText('Foo'); + } - this.registerComponent('change-button', { - ComponentClass: Component.extend().reopenClass({ - positionalParams: ['val'] - }), - template: strip` + ['@test parameters in a contextual component are mutable when value is a param']( + assert + ) { + // This checks that a `(mut)` is added to parameters and attributes to + // contextual components when it is a param. + + this.registerComponent('change-button', { + ComponentClass: Component.extend().reopenClass({ + positionalParams: ['val'] + }), + template: strip` ` - }); + }); - this.render(strip` + this.render( + strip` {{component (component "change-button" model.val2)}} - {{model.val2}}`, { - model: { - val2: 8 + {{model.val2}}`, + { + model: { + val2: 8 + } } - } - ); + ); - assert.equal(this.$('.value').text(), '8'); + assert.equal(this.$('.value').text(), '8'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - assert.equal(this.$('.value').text(), '8'); + assert.equal(this.$('.value').text(), '8'); - this.runTask(() => this.$('.my-button').click()); + this.runTask(() => this.$('.my-button').click()); - assert.equal(this.$('.value').text(), '10'); + assert.equal(this.$('.value').text(), '10'); - this.runTask(() => this.context.set('model', { val2: 8 })); + this.runTask(() => this.context.set('model', { val2: 8 })); - assert.equal(this.$('.value').text(), '8'); - } + assert.equal(this.$('.value').text(), '8'); + } - ['@test tagless blockless components render'](assert) { - this.registerComponent('my-comp', { - ComponentClass: Component.extend({ tagName: '' }) - }); + ['@test tagless blockless components render'](assert) { + this.registerComponent('my-comp', { + ComponentClass: Component.extend({ tagName: '' }) + }); - this.render(`{{my-comp}}`); + this.render(`{{my-comp}}`); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - assert.equal(this.$().text(), ''); - } + assert.equal(this.$().text(), ''); + } - ['@test GH#13494 tagless blockless component with property binding'](assert) { - this.registerComponent('outer-component', { - ComponentClass: Component.extend({ - message: 'hello', - actions: { - change() { - this.set('message', 'goodbye'); + ['@test GH#13494 tagless blockless component with property binding']( + assert + ) { + this.registerComponent('outer-component', { + ComponentClass: Component.extend({ + message: 'hello', + actions: { + change() { + this.set('message', 'goodbye'); + } } - } - }), - template: strip` + }), + template: strip` message: {{message}}{{inner-component message=message}} ' + }); + + this.registerComponent('outer-component', { + ComponentClass: OuterComponent, + template: '{{inner-component submit=(action outerSubmit)}}' + }); + + this.subscribe('interaction.ember-action', { + before(name, timestamp, payload) { + beforeParameters.push(payload.args); + }, + after(name, timestamp, payload) { + afterParameters.push(payload.args); + } + }); + + this.render(`{{outer-component}}`); + + this.runTask(() => { + this.$('#instrument-button').trigger('click'); + }); + + this.assert.deepEqual( + beforeParameters, + [[], [actionParam]], + 'instrumentation subscriber before function was passed closure action parameters' + ); + this.assert.deepEqual( + afterParameters, + [[actionParam], []], + 'instrumentation subscriber after function was passed closure action parameters' + ); + } + + ['@test interaction event subscriber should be passed target']() { + let beforeParameters = []; + let afterParameters = []; + + let InnerComponent = Component.extend({ + myProperty: 'inner-thing', + actions: { + fireAction() { + this.attrs.submit(); + } + } + }); + + let OuterComponent = Component.extend({ + myProperty: 'outer-thing', + outerSubmit() {} + }); + + this.registerComponent('inner-component', { + ComponentClass: InnerComponent, + template: + '' + }); + + this.registerComponent('outer-component', { + ComponentClass: OuterComponent, + template: '{{inner-component submit=(action outerSubmit)}}' + }); + + this.subscribe('interaction.ember-action', { + before(name, timestamp, payload) { + beforeParameters.push(payload.target.get('myProperty')); + }, + after(name, timestamp, payload) { + afterParameters.push(payload.target.get('myProperty')); + } + }); - teardown() { - if (this.subscriber) { - instrumentationUnsubscribe(this.subscriber); + this.render(`{{outer-component}}`); + + this.runTask(() => { + this.$('#instrument-button').trigger('click'); + }); + + this.assert.deepEqual( + beforeParameters, + ['inner-thing', 'outer-thing'], + 'instrumentation subscriber before function was passed target' + ); + this.assert.deepEqual( + afterParameters, + ['outer-thing', 'inner-thing'], + 'instrumentation subscriber after function was passed target' + ); } - super.teardown(); + ['@test instrumented action should return value']() { + let returnedValue = 'Chris P is so krispy'; + let actualReturnedValue; + + let InnerComponent = Component.extend({ + actions: { + fireAction() { + actualReturnedValue = this.attrs.submit(); + } + } + }); + + let OuterComponent = Component.extend({ + outerSubmit() { + return returnedValue; + } + }); + + this.registerComponent('inner-component', { + ComponentClass: InnerComponent, + template: + '' + }); + + this.registerComponent('outer-component', { + ComponentClass: OuterComponent, + template: '{{inner-component submit=(action outerSubmit)}}' + }); + + this.subscribe('interaction.ember-action', { + before() {}, + after() {} + }); + + this.render(`{{outer-component}}`); + + this.runTask(() => { + this.$('#instrument-button').trigger('click'); + }); + + this.assert.equal( + actualReturnedValue, + returnedValue, + 'action can return to caller' + ); + } } + ); +} - ['@test interaction event subscriber should be passed parameters']() { - let actionParam = 'So krispy'; - let beforeParameters = []; - let afterParameters = []; +moduleFor( + 'Helpers test: closure {{action}}', + class extends RenderingTest { + ['@test action should be called']() { + let outerActionCalled = false; + let component; let InnerComponent = Component.extend({ - actions: { - fireAction() { - this.attrs.submit(actionParam); - } + init() { + this._super(...arguments); + component = this; + }, + fireAction() { + this.attrs.submit(); } }); let OuterComponent = Component.extend({ outerSubmit() { + outerActionCalled = true; } }); this.registerComponent('inner-component', { ComponentClass: InnerComponent, - template: '' + template: 'inner' }); - this.registerComponent('outer-component', { ComponentClass: OuterComponent, template: '{{inner-component submit=(action outerSubmit)}}' }); - this.subscribe('interaction.ember-action', { - before(name, timestamp, payload) { - beforeParameters.push(payload.args); - }, - after(name, timestamp, payload) { - afterParameters.push(payload.args); - } + this.render('{{outer-component}}'); + + this.runTask(() => { + component.fireAction(); }); - this.render(`{{outer-component}}`); + this.assert.ok(outerActionCalled, 'the action was called'); + } - this.runTask(() => { - this.$('#instrument-button').trigger('click'); + ['@test an error is triggered when bound action function is undefined']() { + this.registerComponent('inner-component', { + template: 'inner' + }); + this.registerComponent('outer-component', { + template: '{{inner-component submit=(action somethingThatIsUndefined)}}' + }); + + expectAssertion(() => { + this.render('{{outer-component}}'); + }, /Action passed is null or undefined in \(action[^)]*\) from .*\./); + } + + ['@test an error is triggered when bound action being passed in is a non-function']() { + this.registerComponent('inner-component', { + template: 'inner' + }); + this.registerComponent('outer-component', { + ComponentClass: Component.extend({ + nonFunctionThing: {} + }), + template: '{{inner-component submit=(action nonFunctionThing)}}' + }); + + expectAssertion(() => { + this.render('{{outer-component}}'); + }, /An action could not be made for `.*` in .*\. Please confirm that you are using either a quoted action name \(i\.e\. `\(action '.*'\)`\) or a function available in .*\./); + } + + ['@test [#12718] a nice error is shown when a bound action function is undefined and it is passed as attrs.foo']() { + this.registerComponent('inner-component', { + template: + '' + }); + + this.registerComponent('outer-component', { + template: '{{inner-component}}' }); - this.assert.deepEqual(beforeParameters, [[], [actionParam]], 'instrumentation subscriber before function was passed closure action parameters'); - this.assert.deepEqual(afterParameters, [[actionParam], []], 'instrumentation subscriber after function was passed closure action parameters'); + expectAssertion(() => { + this.render('{{outer-component}}'); + }, /Action passed is null or undefined in \(action[^)]*\) from .*\./); } - ['@test interaction event subscriber should be passed target']() { - let beforeParameters = []; - let afterParameters = []; + ['@test action value is returned']() { + let expectedValue = 'terrible tom'; + let returnedValue; + let innerComponent; let InnerComponent = Component.extend({ - myProperty: 'inner-thing', - actions: { - fireAction() { - this.attrs.submit(); - } + init() { + this._super(...arguments); + innerComponent = this; + }, + fireAction() { + returnedValue = this.attrs.submit(); } }); let OuterComponent = Component.extend({ - myProperty: 'outer-thing', - outerSubmit() {} + outerSubmit() { + return expectedValue; + } }); this.registerComponent('inner-component', { ComponentClass: InnerComponent, - template: '' + template: 'inner' }); this.registerComponent('outer-component', { @@ -100,46 +303,48 @@ if (EMBER_IMPROVED_INSTRUMENTATION) { template: '{{inner-component submit=(action outerSubmit)}}' }); - this.subscribe('interaction.ember-action', { - before(name, timestamp, payload) { - beforeParameters.push(payload.target.get('myProperty')); - }, - after(name, timestamp, payload) { - afterParameters.push(payload.target.get('myProperty')); - } - }); - - this.render(`{{outer-component}}`); + this.render('{{outer-component}}'); this.runTask(() => { - this.$('#instrument-button').trigger('click'); + innerComponent.fireAction(); }); - this.assert.deepEqual(beforeParameters, ['inner-thing', 'outer-thing'], 'instrumentation subscriber before function was passed target'); - this.assert.deepEqual(afterParameters, ['outer-thing', 'inner-thing'], 'instrumentation subscriber after function was passed target'); + this.assert.equal( + returnedValue, + expectedValue, + 'action can return to caller' + ); } - ['@test instrumented action should return value']() { - let returnedValue = 'Chris P is so krispy'; - let actualReturnedValue; + ['@test action should be called on the correct scope']() { + let innerComponent; + let outerComponent; + let actualComponent; let InnerComponent = Component.extend({ - actions: { - fireAction() { - actualReturnedValue = this.attrs.submit(); - } + init() { + this._super(...arguments); + innerComponent = this; + }, + fireAction() { + this.attrs.submit(); } }); let OuterComponent = Component.extend({ + init() { + this._super(...arguments); + outerComponent = this; + }, + isOuterComponent: true, outerSubmit() { - return returnedValue; + actualComponent = this; } }); this.registerComponent('inner-component', { ComponentClass: InnerComponent, - template: '' + template: 'inner' }); this.registerComponent('outer-component', { @@ -147,1059 +352,940 @@ if (EMBER_IMPROVED_INSTRUMENTATION) { template: '{{inner-component submit=(action outerSubmit)}}' }); - this.subscribe('interaction.ember-action', { - before() { - }, - after() { - } - }); - - this.render(`{{outer-component}}`); + this.render('{{outer-component}}'); this.runTask(() => { - this.$('#instrument-button').trigger('click'); + innerComponent.fireAction(); }); - this.assert.equal(actualReturnedValue, returnedValue, 'action can return to caller'); + this.assert.equal( + actualComponent, + outerComponent, + 'action has the correct context' + ); + this.assert.ok( + actualComponent.isOuterComponent, + 'action has the correct context' + ); } - }); -} - -moduleFor('Helpers test: closure {{action}}', class extends RenderingTest { - - ['@test action should be called']() { - let outerActionCalled = false; - let component; - - let InnerComponent = Component.extend({ - init() { - this._super(...arguments); - component = this; - }, - fireAction() { - this.attrs.submit(); - } - }); - let OuterComponent = Component.extend({ - outerSubmit() { - outerActionCalled = true; - } - }); + ['@test arguments to action are passed, curry']() { + let first = 'mitch'; + let second = 'martin'; + let third = 'matt'; + let fourth = 'wacky wycats'; - this.registerComponent('inner-component', { ComponentClass: InnerComponent, template: 'inner' }); - this.registerComponent('outer-component', { - ComponentClass: OuterComponent, - template: '{{inner-component submit=(action outerSubmit)}}' - }); + let innerComponent; + let actualArgs; - this.render('{{outer-component}}'); + let InnerComponent = Component.extend({ + init() { + this._super(...arguments); + innerComponent = this; + }, + fireAction() { + this.attrs.submit(fourth); + } + }); - this.runTask(() => { - component.fireAction(); - }); + let OuterComponent = Component.extend({ + third, + outerSubmit() { + // eslint-disable-line no-unused-vars + actualArgs = [...arguments]; + } + }); - this.assert.ok(outerActionCalled, 'the action was called'); - } + this.registerComponent('inner-component', { + ComponentClass: InnerComponent, + template: 'inner' + }); - ['@test an error is triggered when bound action function is undefined']() { - this.registerComponent('inner-component', { - template: 'inner' - }); - this.registerComponent('outer-component', { - template: '{{inner-component submit=(action somethingThatIsUndefined)}}' - }); + this.registerComponent('outer-component', { + ComponentClass: OuterComponent, + template: `{{inner-component submit=(action (action outerSubmit "${first}") "${second}" third)}}` + }); - expectAssertion(() => { this.render('{{outer-component}}'); - }, /Action passed is null or undefined in \(action[^)]*\) from .*\./); - } - ['@test an error is triggered when bound action being passed in is a non-function']() { - this.registerComponent('inner-component', { - template: 'inner' - }); - this.registerComponent('outer-component', { - ComponentClass: Component.extend({ - nonFunctionThing: {} - }), - template: '{{inner-component submit=(action nonFunctionThing)}}' - }); - - expectAssertion(() => { - this.render('{{outer-component}}'); - }, /An action could not be made for `.*` in .*\. Please confirm that you are using either a quoted action name \(i\.e\. `\(action '.*'\)`\) or a function available in .*\./); - } + this.runTask(() => { + innerComponent.fireAction(); + }); - ['@test [#12718] a nice error is shown when a bound action function is undefined and it is passed as attrs.foo']() { - this.registerComponent('inner-component', { - template: '' - }); + this.assert.deepEqual( + actualArgs, + [first, second, third, fourth], + 'action has the correct args' + ); + } - this.registerComponent('outer-component', { - template: '{{inner-component}}' - }); + ['@test `this` can be passed as an argument']() { + let value = {}; + let component; + let innerComponent; - expectAssertion(() => { - this.render('{{outer-component}}'); - }, /Action passed is null or undefined in \(action[^)]*\) from .*\./); - } + let InnerComponent = Component.extend({ + init() { + this._super(...arguments); + innerComponent = this; + }, + fireAction() { + this.attrs.submit(); + } + }); - ['@test action value is returned']() { - let expectedValue = 'terrible tom'; - let returnedValue; - let innerComponent; - - let InnerComponent = Component.extend({ - init() { - this._super(...arguments); - innerComponent = this; - }, - fireAction() { - returnedValue = this.attrs.submit(); - } - }); + let OuterComponent = Component.extend({ + init() { + this._super(...arguments); + component = this; + }, + actions: { + outerAction(incomingValue) { + value = incomingValue; + } + } + }); - let OuterComponent = Component.extend({ - outerSubmit() { - return expectedValue; - } - }); + this.registerComponent('inner-component', { + ComponentClass: InnerComponent, + template: 'inner' + }); + this.registerComponent('outer-component', { + ComponentClass: OuterComponent, + template: '{{inner-component submit=(action "outerAction" this)}}' + }); - this.registerComponent('inner-component', { - ComponentClass: InnerComponent, - template: 'inner' - }); + this.render('{{outer-component}}'); - this.registerComponent('outer-component', { - ComponentClass: OuterComponent, - template: '{{inner-component submit=(action outerSubmit)}}' - }); + this.runTask(() => { + innerComponent.fireAction(); + }); - this.render('{{outer-component}}'); + this.assert.strictEqual( + value, + component, + 'the component is passed at `this`' + ); + } - this.runTask(() => { - innerComponent.fireAction(); - }); + ['@test arguments to action are bound']() { + let value = 'lazy leah'; - this.assert.equal(returnedValue, expectedValue, 'action can return to caller'); - } + let innerComponent; + let outerComponent; + let actualArg; - ['@test action should be called on the correct scope']() { - let innerComponent; - let outerComponent; - let actualComponent; - - let InnerComponent = Component.extend({ - init() { - this._super(...arguments); - innerComponent = this; - }, - fireAction() { - this.attrs.submit(); - } - }); - - let OuterComponent = Component.extend({ - init() { - this._super(...arguments); - outerComponent = this; - }, - isOuterComponent: true, - outerSubmit() { - actualComponent = this; - } - }); + let InnerComponent = Component.extend({ + init() { + this._super(...arguments); + innerComponent = this; + }, + fireAction() { + this.attrs.submit(); + } + }); - this.registerComponent('inner-component', { - ComponentClass: InnerComponent, - template: 'inner' - }); + let OuterComponent = Component.extend({ + init() { + this._super(...arguments); + outerComponent = this; + }, + value: '', + outerSubmit(incomingValue) { + actualArg = incomingValue; + } + }); - this.registerComponent('outer-component', { - ComponentClass: OuterComponent, - template: '{{inner-component submit=(action outerSubmit)}}' - }); + this.registerComponent('inner-component', { + ComponentClass: InnerComponent, + template: 'inner' + }); - this.render('{{outer-component}}'); + this.registerComponent('outer-component', { + ComponentClass: OuterComponent, + template: `{{inner-component submit=(action outerSubmit value)}}` + }); - this.runTask(() => { - innerComponent.fireAction(); - }); + this.render('{{outer-component}}'); - this.assert.equal(actualComponent, outerComponent, 'action has the correct context'); - this.assert.ok(actualComponent.isOuterComponent, 'action has the correct context'); - } + this.runTask(() => { + innerComponent.fireAction(); + }); - ['@test arguments to action are passed, curry']() { - let first = 'mitch'; - let second = 'martin'; - let third = 'matt'; - let fourth = 'wacky wycats'; - - let innerComponent; - let actualArgs; - - let InnerComponent = Component.extend({ - init() { - this._super(...arguments); - innerComponent = this; - }, - fireAction() { - this.attrs.submit(fourth); - } - }); + this.assert.strictEqual( + actualArg, + '', + 'action has the correct first arg' + ); - let OuterComponent = Component.extend({ - third, - outerSubmit(actualFirst, actualSecond, actualThird, actualFourth) { // eslint-disable-line no-unused-vars - actualArgs = [...arguments]; - } - }); + this.runTask(() => { + outerComponent.set('value', value); + }); - this.registerComponent('inner-component', { - ComponentClass: InnerComponent, - template: 'inner' - }); + this.runTask(() => { + innerComponent.fireAction(); + }); - this.registerComponent('outer-component', { - ComponentClass: OuterComponent, - template: `{{inner-component submit=(action (action outerSubmit "${first}") "${second}" third)}}` - }); + this.assert.strictEqual( + actualArg, + value, + 'action has the correct first arg' + ); + } - this.render('{{outer-component}}'); + ['@test array arguments are passed correctly to action']() { + let first = 'foo'; + let second = [3, 5]; + let third = [4, 9]; - this.runTask(() => { - innerComponent.fireAction(); - }); + let actualFirst; + let actualSecond; + let actualThird; - this.assert.deepEqual(actualArgs, [first, second, third, fourth], 'action has the correct args'); - } + let innerComponent; + let outerComponent; - ['@test `this` can be passed as an argument']() { - let value = {}; - let component; - let innerComponent; - - let InnerComponent = Component.extend({ - init() { - this._super(...arguments); - innerComponent = this; - }, - fireAction() { - this.attrs.submit(); - } - }); - - let OuterComponent = Component.extend({ - init() { - this._super(...arguments); - component = this; - }, - actions: { - outerAction(incomingValue) { - value = incomingValue; + let InnerComponent = Component.extend({ + init() { + this._super(...arguments); + innerComponent = this; + }, + fireAction() { + this.attrs.submit(second, third); } - } - }); - - this.registerComponent('inner-component', { ComponentClass: InnerComponent, template: 'inner' }); - this.registerComponent('outer-component', { - ComponentClass: OuterComponent, - template: '{{inner-component submit=(action "outerAction" this)}}' - }); - - this.render('{{outer-component}}'); - - this.runTask(() => { - innerComponent.fireAction(); - }); - - this.assert.strictEqual(value, component, 'the component is passed at `this`'); - } - - ['@test arguments to action are bound']() { - let value = 'lazy leah'; + }); - let innerComponent; - let outerComponent; - let actualArg; + let OuterComponent = Component.extend({ + init() { + this._super(...arguments); + outerComponent = this; + }, + outerSubmit(incomingFirst, incomingSecond, incomingThird) { + actualFirst = incomingFirst; + actualSecond = incomingSecond; + actualThird = incomingThird; + } + }); - let InnerComponent = Component.extend({ - init() { - this._super(...arguments); - innerComponent = this; - }, - fireAction() { - this.attrs.submit(); - } - }); - - let OuterComponent = Component.extend({ - init() { - this._super(...arguments); - outerComponent = this; - }, - value: '', - outerSubmit(incomingValue) { - actualArg = incomingValue; - } - }); + this.registerComponent('inner-component', { + ComponentClass: InnerComponent, + template: 'inner' + }); - this.registerComponent('inner-component', { - ComponentClass: InnerComponent, - template: 'inner' - }); + this.registerComponent('outer-component', { + ComponentClass: OuterComponent, + template: `{{inner-component submit=(action outerSubmit first)}}` + }); - this.registerComponent('outer-component', { - ComponentClass: OuterComponent, - template: `{{inner-component submit=(action outerSubmit value)}}` - }); + this.render('{{outer-component}}'); - this.render('{{outer-component}}'); + this.runTask(() => { + outerComponent.set('first', first); + outerComponent.set('second', second); + }); - this.runTask(() => { - innerComponent.fireAction(); - }); + this.runTask(() => { + innerComponent.fireAction(); + }); - this.assert.strictEqual(actualArg, '', 'action has the correct first arg'); + this.assert.equal(actualFirst, first, 'action has the correct first arg'); + this.assert.equal( + actualSecond, + second, + 'action has the correct second arg' + ); + this.assert.equal(actualThird, third, 'action has the correct third arg'); + } - this.runTask(() => { - outerComponent.set('value', value); - }); + ['@test mut values can be wrapped in actions, are settable']() { + let newValue = 'trollin trek'; - this.runTask(() => { - innerComponent.fireAction(); - }); + let innerComponent; + let outerComponent; - this.assert.strictEqual(actualArg, value, 'action has the correct first arg'); - } + let InnerComponent = Component.extend({ + init() { + this._super(...arguments); + innerComponent = this; + }, + fireAction() { + this.attrs.submit(newValue); + } + }); - ['@test array arguments are passed correctly to action']() { - let first = 'foo'; - let second = [3, 5]; - let third = [4, 9]; - - let actualFirst; - let actualSecond; - let actualThird; - - let innerComponent; - let outerComponent; - - let InnerComponent = Component.extend({ - init() { - this._super(...arguments); - innerComponent = this; - }, - fireAction() { - this.attrs.submit(second, third); - } - }); - - let OuterComponent = Component.extend({ - init() { - this._super(...arguments); - outerComponent = this; - }, - outerSubmit(incomingFirst, incomingSecond, incomingThird) { - actualFirst = incomingFirst; - actualSecond = incomingSecond; - actualThird = incomingThird; - } - }); + let OuterComponent = Component.extend({ + init() { + this._super(...arguments); + outerComponent = this; + }, + outerMut: 'patient peter' + }); - this.registerComponent('inner-component', { - ComponentClass: InnerComponent, - template: 'inner' - }); + this.registerComponent('inner-component', { + ComponentClass: InnerComponent, + template: 'inner' + }); - this.registerComponent('outer-component', { - ComponentClass: OuterComponent, - template: `{{inner-component submit=(action outerSubmit first)}}` - }); + this.registerComponent('outer-component', { + ComponentClass: OuterComponent, + template: `{{inner-component submit=(action (mut outerMut))}}` + }); - this.render('{{outer-component}}'); + this.render('{{outer-component}}'); - this.runTask(() => { - outerComponent.set('first', first); - outerComponent.set('second', second); - }); + this.runTask(() => { + innerComponent.fireAction(); + }); - this.runTask(() => { - innerComponent.fireAction(); - }); + this.assert.equal( + outerComponent.get('outerMut'), + newValue, + 'mut value is set' + ); + } - this.assert.equal(actualFirst, first, 'action has the correct first arg'); - this.assert.equal(actualSecond, second, 'action has the correct second arg'); - this.assert.equal(actualThird, third, 'action has the correct third arg'); - } + ['@test mut values can be wrapped in actions, are settable with a curry']() { + let newValue = 'trollin trek'; - ['@test mut values can be wrapped in actions, are settable']() { - let newValue = 'trollin trek'; + let innerComponent; + let outerComponent; - let innerComponent; - let outerComponent; + let InnerComponent = Component.extend({ + init() { + this._super(...arguments); + innerComponent = this; + }, + fireAction() { + this.attrs.submit(); + } + }); - let InnerComponent = Component.extend({ - init() { - this._super(...arguments); - innerComponent = this; - }, - fireAction() { - this.attrs.submit(newValue); - } - }); + let OuterComponent = Component.extend({ + init() { + this._super(...arguments); + outerComponent = this; + }, + outerMut: 'patient peter' + }); - let OuterComponent = Component.extend({ - init() { - this._super(...arguments); - outerComponent = this; - }, - outerMut: 'patient peter' - }); + this.registerComponent('inner-component', { + ComponentClass: InnerComponent, + template: 'inner' + }); - this.registerComponent('inner-component', { - ComponentClass: InnerComponent, - template: 'inner' - }); + this.registerComponent('outer-component', { + ComponentClass: OuterComponent, + template: `{{inner-component submit=(action (mut outerMut) '${newValue}')}}` + }); - this.registerComponent('outer-component', { - ComponentClass: OuterComponent, - template: `{{inner-component submit=(action (mut outerMut))}}` - }); + this.render('{{outer-component}}'); - this.render('{{outer-component}}'); + this.runTask(() => { + innerComponent.fireAction(); + }); - this.runTask(() => { - innerComponent.fireAction(); - }); + this.assert.equal( + outerComponent.get('outerMut'), + newValue, + 'mut value is set' + ); + } - this.assert.equal(outerComponent.get('outerMut'), newValue, 'mut value is set'); - } + ['@test action can create closures over actions']() { + let first = 'raging robert'; + let second = 'mild machty'; + let returnValue = 'butch brian'; - ['@test mut values can be wrapped in actions, are settable with a curry']() { - let newValue = 'trollin trek'; + let actualFirst; + let actualSecond; + let actualReturnedValue; - let innerComponent; - let outerComponent; + let innerComponent; - let InnerComponent = Component.extend({ - init() { - this._super(...arguments); - innerComponent = this; - }, - fireAction() { - this.attrs.submit(); - } - }); + let InnerComponent = Component.extend({ + init() { + this._super(...arguments); + innerComponent = this; + }, + fireAction() { + actualReturnedValue = this.attrs.submit(second); + } + }); - let OuterComponent = Component.extend({ - init() { - this._super(...arguments); - outerComponent = this; - }, - outerMut: 'patient peter' - }); + let OuterComponent = Component.extend({ + actions: { + outerAction(incomingFirst, incomingSecond) { + actualFirst = incomingFirst; + actualSecond = incomingSecond; + return returnValue; + } + } + }); - this.registerComponent('inner-component', { - ComponentClass: InnerComponent, - template: 'inner' - }); + this.registerComponent('inner-component', { + ComponentClass: InnerComponent, + template: 'inner' + }); - this.registerComponent('outer-component', { - ComponentClass: OuterComponent, - template: `{{inner-component submit=(action (mut outerMut) '${newValue}')}}` - }); + this.registerComponent('outer-component', { + ComponentClass: OuterComponent, + template: `{{inner-component submit=(action 'outerAction' '${first}')}}` + }); - this.render('{{outer-component}}'); + this.render('{{outer-component}}'); - this.runTask(() => { - innerComponent.fireAction(); - }); + this.runTask(() => { + innerComponent.fireAction(); + }); - this.assert.equal(outerComponent.get('outerMut'), newValue, 'mut value is set'); - } + this.assert.equal( + actualReturnedValue, + returnValue, + 'return value is present' + ); + this.assert.equal(actualFirst, first, 'first argument is correct'); + this.assert.equal(actualSecond, second, 'second argument is correct'); + } - ['@test action can create closures over actions']() { - let first = 'raging robert'; - let second = 'mild machty'; - let returnValue = 'butch brian'; + ['@test provides a helpful error if an action is not present']() { + let InnerComponent = Component.extend({}); - let actualFirst; - let actualSecond; - let actualReturnedValue; + let OuterComponent = Component.extend({ + actions: { + something() { + // this is present to ensure `actions` hash is present + // a different error is triggered if `actions` is missing + // completely + } + } + }); - let innerComponent; + this.registerComponent('inner-component', { + ComponentClass: InnerComponent, + template: 'inner' + }); - let InnerComponent = Component.extend({ - init() { - this._super(...arguments); - innerComponent = this; - }, - fireAction() { - actualReturnedValue = this.attrs.submit(second); - } - }); + this.registerComponent('outer-component', { + ComponentClass: OuterComponent, + template: `{{inner-component submit=(action 'doesNotExist')}}` + }); - let OuterComponent = Component.extend({ - actions: { - outerAction(incomingFirst, incomingSecond) { - actualFirst = incomingFirst; - actualSecond = incomingSecond; - return returnValue; - } - } - }); + expectAssertion(() => { + this.render('{{outer-component}}'); + }, /An action named 'doesNotExist' was not found in /); + } - this.registerComponent('inner-component', { - ComponentClass: InnerComponent, - template: 'inner' - }); + ['@test provides a helpful error if actions hash is not present']() { + let InnerComponent = Component.extend({}); - this.registerComponent('outer-component', { - ComponentClass: OuterComponent, - template: `{{inner-component submit=(action 'outerAction' '${first}')}}` - }); + let OuterComponent = Component.extend({}); - this.render('{{outer-component}}'); + this.registerComponent('inner-component', { + ComponentClass: InnerComponent, + template: 'inner' + }); - this.runTask(() => { - innerComponent.fireAction(); - }); + this.registerComponent('outer-component', { + ComponentClass: OuterComponent, + template: `{{inner-component submit=(action 'doesNotExist')}}` + }); - this.assert.equal(actualReturnedValue, returnValue, 'return value is present'); - this.assert.equal(actualFirst, first, 'first argument is correct'); - this.assert.equal(actualSecond, second, 'second argument is correct'); - } + expectAssertion(() => { + this.render('{{outer-component}}'); + }, /An action named 'doesNotExist' was not found in /); + } - ['@test provides a helpful error if an action is not present']() { - let InnerComponent = Component.extend({ - }); + ['@test action can create closures over actions with target']() { + let innerComponent; + let actionCalled = false; - let OuterComponent = Component.extend({ - actions: { - something() { - // this is present to ensure `actions` hash is present - // a different error is triggered if `actions` is missing - // completely + let InnerComponent = Component.extend({ + init() { + this._super(...arguments); + innerComponent = this; + }, + fireAction() { + this.attrs.submit(); } - } - }); + }); - this.registerComponent('inner-component', { - ComponentClass: InnerComponent, - template: 'inner' - }); + let OuterComponent = Component.extend({ + otherComponent: computed(function() { + return { + actions: { + outerAction() { + actionCalled = true; + } + } + }; + }) + }); - this.registerComponent('outer-component', { - ComponentClass: OuterComponent, - template: `{{inner-component submit=(action 'doesNotExist')}}` - }); + this.registerComponent('inner-component', { + ComponentClass: InnerComponent, + template: 'inner' + }); - expectAssertion(() => { - this.render('{{outer-component}}'); - }, /An action named 'doesNotExist' was not found in /); - } + this.registerComponent('outer-component', { + ComponentClass: OuterComponent, + template: `{{inner-component submit=(action 'outerAction' target=otherComponent)}}` + }); - ['@test provides a helpful error if actions hash is not present']() { - let InnerComponent = Component.extend({ - }); + this.render('{{outer-component}}'); - let OuterComponent = Component.extend({ - }); + this.runTask(() => { + innerComponent.fireAction(); + }); - this.registerComponent('inner-component', { - ComponentClass: InnerComponent, - template: 'inner' - }); + this.assert.ok(actionCalled, 'action called on otherComponent'); + } - this.registerComponent('outer-component', { - ComponentClass: OuterComponent, - template: `{{inner-component submit=(action 'doesNotExist')}}` - }); + ['@test value can be used with action over actions']() { + let newValue = 'yelping yehuda'; - expectAssertion(() => { - this.render('{{outer-component}}'); - }, /An action named 'doesNotExist' was not found in /); - } + let innerComponent; + let actualValue; - ['@test action can create closures over actions with target']() { - let innerComponent; - let actionCalled = false; - - let InnerComponent = Component.extend({ - init() { - this._super(...arguments); - innerComponent = this; - }, - fireAction() { - this.attrs.submit(); - } - }); + let InnerComponent = Component.extend({ + init() { + this._super(...arguments); + innerComponent = this; + }, + fireAction() { + this.attrs.submit({ + readProp: newValue + }); + } + }); - let OuterComponent = Component.extend({ - otherComponent: computed(function() { - return { - actions: { - outerAction() { - actionCalled = true; - } + let OuterComponent = Component.extend({ + outerContent: { + readProp: newValue + }, + actions: { + outerAction(incomingValue) { + actualValue = incomingValue; } - }; - }) - }); + } + }); - this.registerComponent('inner-component', { - ComponentClass: InnerComponent, - template: 'inner' - }); + this.registerComponent('inner-component', { + ComponentClass: InnerComponent, + template: 'inner' + }); - this.registerComponent('outer-component', { - ComponentClass: OuterComponent, - template: `{{inner-component submit=(action 'outerAction' target=otherComponent)}}` - }); + this.registerComponent('outer-component', { + ComponentClass: OuterComponent, + template: `{{inner-component submit=(action 'outerAction' value="readProp")}}` + }); - this.render('{{outer-component}}'); + this.render('{{outer-component}}'); - this.runTask(() => { - innerComponent.fireAction(); - }); + this.runTask(() => { + innerComponent.fireAction(); + }); - this.assert.ok(actionCalled, 'action called on otherComponent'); - } + this.assert.equal(actualValue, newValue, 'value is read'); + } - ['@test value can be used with action over actions']() { - let newValue = 'yelping yehuda'; + ['@test action will read the value of a first property']() { + let newValue = 'irate igor'; - let innerComponent; - let actualValue; + let innerComponent; + let actualValue; - let InnerComponent = Component.extend({ - init() { - this._super(...arguments); - innerComponent = this; - }, - fireAction() { - this.attrs.submit({ - readProp: newValue - }); - } - }); + let InnerComponent = Component.extend({ + init() { + this._super(...arguments); + innerComponent = this; + }, + fireAction() { + this.attrs.submit({ + readProp: newValue + }); + } + }); - let OuterComponent = Component.extend({ - outerContent: { - readProp: newValue - }, - actions: { + let OuterComponent = Component.extend({ outerAction(incomingValue) { actualValue = incomingValue; } - } - }); + }); - this.registerComponent('inner-component', { - ComponentClass: InnerComponent, - template: 'inner' - }); + this.registerComponent('inner-component', { + ComponentClass: InnerComponent, + template: 'inner' + }); - this.registerComponent('outer-component', { - ComponentClass: OuterComponent, - template: `{{inner-component submit=(action 'outerAction' value="readProp")}}` - }); + this.registerComponent('outer-component', { + ComponentClass: OuterComponent, + template: `{{inner-component submit=(action outerAction value="readProp")}}` + }); - this.render('{{outer-component}}'); + this.render('{{outer-component}}'); - this.runTask(() => { - innerComponent.fireAction(); - }); + this.runTask(() => { + innerComponent.fireAction(); + }); - this.assert.equal(actualValue, newValue, 'value is read'); - } + this.assert.equal(actualValue, newValue, 'property is read'); + } - ['@test action will read the value of a first property']() { - let newValue = 'irate igor'; + ['@test action will read the value of a curried first argument property']() { + let newValue = 'kissing kris'; - let innerComponent; - let actualValue; + let innerComponent; + let actualValue; - let InnerComponent = Component.extend({ - init() { - this._super(...arguments); - innerComponent = this; - }, - fireAction() { - this.attrs.submit({ + let InnerComponent = Component.extend({ + init() { + this._super(...arguments); + innerComponent = this; + }, + fireAction() { + this.attrs.submit(); + } + }); + + let OuterComponent = Component.extend({ + objectArgument: { readProp: newValue - }); - } - }); + }, + outerAction(incomingValue) { + actualValue = incomingValue; + } + }); - let OuterComponent = Component.extend({ - outerAction(incomingValue) { - actualValue = incomingValue; - } - }); + this.registerComponent('inner-component', { + ComponentClass: InnerComponent, + template: 'inner' + }); - this.registerComponent('inner-component', { - ComponentClass: InnerComponent, - template: 'inner' - }); + this.registerComponent('outer-component', { + ComponentClass: OuterComponent, + template: `{{inner-component submit=(action outerAction objectArgument value="readProp")}}` + }); - this.registerComponent('outer-component', { - ComponentClass: OuterComponent, - template: `{{inner-component submit=(action outerAction value="readProp")}}` - }); + this.render('{{outer-component}}'); - this.render('{{outer-component}}'); + this.runTask(() => { + innerComponent.fireAction(); + }); - this.runTask(() => { - innerComponent.fireAction(); - }); + this.assert.equal(actualValue, newValue, 'property is read'); + } - this.assert.equal(actualValue, newValue, 'property is read'); - } + ['@test action closure does not get auto-mut wrapped'](assert) { + let first = 'raging robert'; + let second = 'mild machty'; + let returnValue = 'butch brian'; - ['@test action will read the value of a curried first argument property']() { - let newValue = 'kissing kris'; + let innerComponent; + let actualFirst; + let actualSecond; + let actualReturnedValue; - let innerComponent; - let actualValue; + let InnerComponent = Component.extend({ + init() { + this._super(...arguments); + innerComponent = this; + }, + fireAction() { + this.get('submit')(second); + this.get('attrs-submit')(second); + let attrsSubmitReturnValue = this.attrs['attrs-submit'](second); + let submitReturnValue = this.attrs.submit(second); + + assert.equal( + attrsSubmitReturnValue, + submitReturnValue, + 'both attrs.foo and foo should behave the same' + ); + + return submitReturnValue; + } + }); - let InnerComponent = Component.extend({ - init() { - this._super(...arguments); - innerComponent = this; - }, - fireAction() { - this.attrs.submit(); - } - }); - - let OuterComponent = Component.extend({ - objectArgument: { - readProp: newValue - }, - outerAction(incomingValue) { - actualValue = incomingValue; - } - }); + let MiddleComponent = Component.extend({}); - this.registerComponent('inner-component', { - ComponentClass: InnerComponent, - template: 'inner' - }); + let OuterComponent = Component.extend({ + actions: { + outerAction(incomingFirst, incomingSecond) { + actualFirst = incomingFirst; + actualSecond = incomingSecond; + return returnValue; + } + } + }); - this.registerComponent('outer-component', { - ComponentClass: OuterComponent, - template: `{{inner-component submit=(action outerAction objectArgument value="readProp")}}` - }); + this.registerComponent('inner-component', { + ComponentClass: InnerComponent, + template: 'inner' + }); - this.render('{{outer-component}}'); + this.registerComponent('middle-component', { + ComponentClass: MiddleComponent, + template: `{{inner-component attrs-submit=attrs.submit submit=submit}}` + }); - this.runTask(() => { - innerComponent.fireAction(); - }); + this.registerComponent('outer-component', { + ComponentClass: OuterComponent, + template: `{{middle-component submit=(action 'outerAction' '${first}')}}` + }); - this.assert.equal(actualValue, newValue, 'property is read'); - } + this.render('{{outer-component}}'); - ['@test action closure does not get auto-mut wrapped'](assert) { - let first = 'raging robert'; - let second = 'mild machty'; - let returnValue = 'butch brian'; - - let innerComponent; - let actualFirst; - let actualSecond; - let actualReturnedValue; - - let InnerComponent = Component.extend({ - init() { - this._super(...arguments); - innerComponent = this; - }, - fireAction() { - this.get('submit')(second); - this.get('attrs-submit')(second); - let attrsSubmitReturnValue = this.attrs['attrs-submit'](second); - let submitReturnValue = this.attrs.submit(second); - - assert.equal(attrsSubmitReturnValue, submitReturnValue, 'both attrs.foo and foo should behave the same'); - - return submitReturnValue; - } - }); + this.runTask(() => { + actualReturnedValue = innerComponent.fireAction(); + }); - let MiddleComponent = Component.extend({ - }); + this.assert.equal(actualFirst, first, 'first argument is correct'); + this.assert.equal(actualSecond, second, 'second argument is correct'); + this.assert.equal( + actualReturnedValue, + returnValue, + 'return value is present' + ); + } - let OuterComponent = Component.extend({ - actions: { - outerAction(incomingFirst, incomingSecond) { - actualFirst = incomingFirst; - actualSecond = incomingSecond; - return returnValue; + ['@test action should be called within a run loop']() { + let innerComponent; + let capturedRunLoop; + + let InnerComponent = Component.extend({ + init() { + this._super(...arguments); + innerComponent = this; + }, + fireAction() { + this.attrs.submit(); } - } - }); + }); - this.registerComponent('inner-component', { - ComponentClass: InnerComponent, - template: 'inner' - }); + let OuterComponent = Component.extend({ + actions: { + submit() { + capturedRunLoop = getCurrentRunLoop(); + } + } + }); - this.registerComponent('middle-component', { - ComponentClass: MiddleComponent, - template: `{{inner-component attrs-submit=attrs.submit submit=submit}}` - }); + this.registerComponent('inner-component', { + ComponentClass: InnerComponent, + template: 'inner' + }); - this.registerComponent('outer-component', { - ComponentClass: OuterComponent, - template: `{{middle-component submit=(action 'outerAction' '${first}')}}` - }); + this.registerComponent('outer-component', { + ComponentClass: OuterComponent, + template: `{{inner-component submit=(action 'submit')}}` + }); - this.render('{{outer-component}}'); + this.render('{{outer-component}}'); - this.runTask(() => { - actualReturnedValue = innerComponent.fireAction(); - }); + this.runTask(() => { + innerComponent.fireAction(); + }); - this.assert.equal(actualFirst, first, 'first argument is correct'); - this.assert.equal(actualSecond, second, 'second argument is correct'); - this.assert.equal(actualReturnedValue, returnValue, 'return value is present'); - } + this.assert.ok(capturedRunLoop, 'action is called within a run loop'); + } - ['@test action should be called within a run loop']() { - let innerComponent; - let capturedRunLoop; - - let InnerComponent = Component.extend({ - init() { - this._super(...arguments); - innerComponent = this; - }, - fireAction() { - this.attrs.submit(); - } - }); + ['@test objects that define INVOKE can be casted to actions']() { + let innerComponent; + let actionArgs; + let invokableArgs; - let OuterComponent = Component.extend({ - actions: { - submit() { - capturedRunLoop = getCurrentRunLoop(); + let InnerComponent = Component.extend({ + init() { + this._super(...arguments); + innerComponent = this; + }, + fireAction() { + actionArgs = this.attrs.submit(4, 5, 6); } - } - }); - - this.registerComponent('inner-component', { - ComponentClass: InnerComponent, - template: 'inner' - }); - - this.registerComponent('outer-component', { - ComponentClass: OuterComponent, - template: `{{inner-component submit=(action 'submit')}}` - }); - - this.render('{{outer-component}}'); + }); - this.runTask(() => { - innerComponent.fireAction(); - }); + let OuterComponent = Component.extend({ + foo: 123, + submitTask: computed(function() { + return { + [INVOKE]: (...args) => { + invokableArgs = args; + return this.foo; + } + }; + }) + }); - this.assert.ok(capturedRunLoop, 'action is called within a run loop'); - } + this.registerComponent('inner-component', { + ComponentClass: InnerComponent, + template: 'inner' + }); - ['@test objects that define INVOKE can be casted to actions']() { - let innerComponent; - let actionArgs; - let invokableArgs; - - let InnerComponent = Component.extend({ - init() { - this._super(...arguments); - innerComponent = this; - }, - fireAction() { - actionArgs = this.attrs.submit(4, 5, 6); - } - }); - - let OuterComponent = Component.extend({ - foo: 123, - submitTask: computed(function() { - return { - [INVOKE]: (...args) => { - invokableArgs = args; - return this.foo; - } - }; - }) - }); + this.registerComponent('outer-component', { + ComponentClass: OuterComponent, + template: `{{inner-component submit=(action submitTask 1 2 3)}}` + }); - this.registerComponent('inner-component', { - ComponentClass: InnerComponent, - template: 'inner' - }); + this.render('{{outer-component}}'); - this.registerComponent('outer-component', { - ComponentClass: OuterComponent, - template: `{{inner-component submit=(action submitTask 1 2 3)}}` - }); + this.runTask(() => { + innerComponent.fireAction(); + }); - this.render('{{outer-component}}'); + this.assert.equal(actionArgs, 123); + this.assert.deepEqual(invokableArgs, [1, 2, 3, 4, 5, 6]); + } - this.runTask(() => { - innerComponent.fireAction(); - }); + ['@test closure action with `(mut undefinedThing)` works properly [GH#13959]']() { + let component; - this.assert.equal(actionArgs, 123); - this.assert.deepEqual(invokableArgs, [1, 2, 3, 4, 5, 6]); - } - - ['@test closure action with `(mut undefinedThing)` works properly [GH#13959]']() { - let component; + let ExampleComponent = Component.extend({ + label: undefined, + init() { + this._super(...arguments); + component = this; + } + }); - let ExampleComponent = Component.extend({ - label: undefined, - init() { - this._super(...arguments); - component = this; - } - }); + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: + '' + }); - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: '' - }); + this.render('{{example-component}}'); - this.render('{{example-component}}'); + this.assertText('Click me'); - this.assertText('Click me'); + this.assertStableRerender(); - this.assertStableRerender(); + this.runTask(() => { + this.$('button').click(); + }); - this.runTask(() => { - this.$('button').click(); - }); + this.assertText('Clicked!'); - this.assertText('Clicked!'); + this.runTask(() => { + component.set('label', 'Dun clicked'); + }); - this.runTask(() => { - component.set('label', 'Dun clicked'); - }); + this.assertText('Dun clicked'); - this.assertText('Dun clicked'); + this.runTask(() => { + this.$('button').click(); + }); - this.runTask(() => { - this.$('button').click(); - }); + this.assertText('Clicked!'); - this.assertText('Clicked!'); + this.runTask(() => { + component.set('label', undefined); + }); - this.runTask(() => { - component.set('label', undefined); - }); + this.assertText('Click me'); + } - this.assertText('Click me'); - } + ['@test closure actions does not cause component hooks to fire unnecessarily [GH#14305] [GH#14654]']( + assert + ) { + let clicked = 0; + let didReceiveAttrsFired = 0; - ['@test closure actions does not cause component hooks to fire unnecessarily [GH#14305] [GH#14654]'](assert) { - let clicked = 0; - let didReceiveAttrsFired = 0; + let ClickMeComponent = Component.extend({ + tagName: 'button', - let ClickMeComponent = Component.extend({ - tagName: 'button', + click() { + this.get('onClick').call(undefined, ++clicked); + }, - click() { - this.get('onClick').call(undefined, ++clicked); - }, + didReceiveAttrs() { + didReceiveAttrsFired++; + } + }); - didReceiveAttrs() { - didReceiveAttrsFired++; - } - }); + this.registerComponent('click-me', { + ComponentClass: ClickMeComponent + }); - this.registerComponent('click-me', { - ComponentClass: ClickMeComponent - }); + let outer; - let outer; + let OuterComponent = Component.extend({ + clicked: 0, - let OuterComponent = Component.extend({ - clicked: 0, + actions: { + 'on-click': function() { + this.incrementProperty('clicked'); + } + }, - actions: { - 'on-click': function() { - this.incrementProperty('clicked'); + init() { + this._super(); + outer = this; + this.set('onClick', () => this.incrementProperty('clicked')); } - }, - - init() { - this._super(); - outer = this; - this.set('onClick', () => this.incrementProperty('clicked')); - } - }); + }); - this.registerComponent('outer-component', { - ComponentClass: OuterComponent, - template: strip` + this.registerComponent('outer-component', { + ComponentClass: OuterComponent, + template: strip`
clicked: {{clicked}}; foo: {{foo}}
{{click-me id="string-action" onClick=(action "on-click")}} {{click-me id="function-action" onClick=(action onClick)}} {{click-me id="mut-action" onClick=(action (mut clicked))}} ` - }); + }); - this.render('{{outer-component foo=foo}}', { foo: 1 }); + this.render('{{outer-component foo=foo}}', { foo: 1 }); - this.assertText('clicked: 0; foo: 1'); + this.assertText('clicked: 0; foo: 1'); - assert.equal(didReceiveAttrsFired, 3); + assert.equal(didReceiveAttrsFired, 3); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('clicked: 0; foo: 1'); + this.assertText('clicked: 0; foo: 1'); - assert.equal(didReceiveAttrsFired, 3); + assert.equal(didReceiveAttrsFired, 3); - this.runTask(() => set(this.context, 'foo', 2)); + this.runTask(() => set(this.context, 'foo', 2)); - this.assertText('clicked: 0; foo: 2'); + this.assertText('clicked: 0; foo: 2'); - assert.equal(didReceiveAttrsFired, 3); + assert.equal(didReceiveAttrsFired, 3); - this.runTask(() => this.$('#string-action').click()); + this.runTask(() => this.$('#string-action').click()); - this.assertText('clicked: 1; foo: 2'); + this.assertText('clicked: 1; foo: 2'); - assert.equal(didReceiveAttrsFired, 3); + assert.equal(didReceiveAttrsFired, 3); - this.runTask(() => this.$('#function-action').click()); + this.runTask(() => this.$('#function-action').click()); - this.assertText('clicked: 2; foo: 2'); + this.assertText('clicked: 2; foo: 2'); - assert.equal(didReceiveAttrsFired, 3); + assert.equal(didReceiveAttrsFired, 3); - this.runTask(() => set(outer, 'onClick', function() { outer.incrementProperty('clicked'); })); + this.runTask(() => + set(outer, 'onClick', function() { + outer.incrementProperty('clicked'); + }) + ); - this.assertText('clicked: 2; foo: 2'); + this.assertText('clicked: 2; foo: 2'); - assert.equal(didReceiveAttrsFired, 3); + assert.equal(didReceiveAttrsFired, 3); - this.runTask(() => this.$('#function-action').click()); + this.runTask(() => this.$('#function-action').click()); - this.assertText('clicked: 3; foo: 2'); + this.assertText('clicked: 3; foo: 2'); - assert.equal(didReceiveAttrsFired, 3); + assert.equal(didReceiveAttrsFired, 3); - this.runTask(() => this.$('#mut-action').click()); + this.runTask(() => this.$('#mut-action').click()); - this.assertText('clicked: 4; foo: 2'); + this.assertText('clicked: 4; foo: 2'); - assert.equal(didReceiveAttrsFired, 3); + assert.equal(didReceiveAttrsFired, 3); + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/helpers/concat-test.js b/packages/ember-glimmer/tests/integration/helpers/concat-test.js index b5db9a07778..a81896f1678 100644 --- a/packages/ember-glimmer/tests/integration/helpers/concat-test.js +++ b/packages/ember-glimmer/tests/integration/helpers/concat-test.js @@ -1,98 +1,110 @@ import { RenderingTest, moduleFor } from '../../utils/test-case'; import { set } from 'ember-metal'; -moduleFor('Helpers test: {{concat}}', class extends RenderingTest { - - ['@test it concats static arguments']() { - this.render(`{{concat "foo" " " "bar" " " "baz"}}`); - this.assertText('foo bar baz'); - } +moduleFor( + 'Helpers test: {{concat}}', + class extends RenderingTest { + ['@test it concats static arguments']() { + this.render(`{{concat "foo" " " "bar" " " "baz"}}`); + this.assertText('foo bar baz'); + } + + ['@test it updates for bound arguments']() { + this.render(`{{concat model.first model.second}}`, { + model: { first: 'one', second: 'two' } + }); - ['@test it updates for bound arguments']() { - this.render(`{{concat model.first model.second}}`, { - model: { first: 'one', second: 'two' } - }); + this.assertText('onetwo'); - this.assertText('onetwo'); + this.runTask(() => this.rerender()); - this.runTask(() => this.rerender()); + this.assertText('onetwo'); - this.assertText('onetwo'); + this.runTask(() => set(this.context, 'model.first', 'three')); - this.runTask(() => set(this.context, 'model.first', 'three')); + this.assertText('threetwo'); - this.assertText('threetwo'); + this.runTask(() => set(this.context, 'model.second', 'four')); - this.runTask(() => set(this.context, 'model.second', 'four')); + this.assertText('threefour'); - this.assertText('threefour'); + this.runTask(() => + set(this.context, 'model', { first: 'one', second: 'two' }) + ); - this.runTask(() => set(this.context, 'model', { first: 'one', second: 'two' })); + this.assertText('onetwo'); + } - this.assertText('onetwo'); - } + ['@test it can be used as a sub-expression']() { + this.render( + `{{concat (concat model.first model.second) (concat model.third model.fourth)}}`, + { + model: { + first: 'one', + second: 'two', + third: 'three', + fourth: 'four' + } + } + ); - ['@test it can be used as a sub-expression']() { - this.render(`{{concat (concat model.first model.second) (concat model.third model.fourth)}}`, { - model: { - first: 'one', - second: 'two', - third: 'three', - fourth: 'four' - } - }); + this.assertText('onetwothreefour'); - this.assertText('onetwothreefour'); + this.runTask(() => this.rerender()); - this.runTask(() => this.rerender()); + this.assertText('onetwothreefour'); - this.assertText('onetwothreefour'); + this.runTask(() => set(this.context, 'model.first', 'five')); - this.runTask(() => set(this.context, 'model.first', 'five')); + this.assertText('fivetwothreefour'); - this.assertText('fivetwothreefour'); - - this.runTask(() => { - set(this.context, 'model.second', 'six'); - set(this.context, 'model.third', 'seven'); - }); + this.runTask(() => { + set(this.context, 'model.second', 'six'); + set(this.context, 'model.third', 'seven'); + }); - this.assertText('fivesixsevenfour'); + this.assertText('fivesixsevenfour'); - this.runTask(() => { - set(this.context, 'model', { - first: 'one', - second: 'two', - third: 'three', - fourth: 'four' + this.runTask(() => { + set(this.context, 'model', { + first: 'one', + second: 'two', + third: 'three', + fourth: 'four' + }); }); - }); - this.assertText('onetwothreefour'); - } + this.assertText('onetwothreefour'); + } - ['@test it can be used as input for other helpers']() { - this.registerHelper('x-eq', ([ actual, expected]) => actual === expected); + ['@test it can be used as input for other helpers']() { + this.registerHelper('x-eq', ([actual, expected]) => actual === expected); - this.render(`{{#if (x-eq (concat model.first model.second) "onetwo")}}Truthy!{{else}}False{{/if}}`, { - model: { - first: 'one', - second: 'two' - } - }); + this.render( + `{{#if (x-eq (concat model.first model.second) "onetwo")}}Truthy!{{else}}False{{/if}}`, + { + model: { + first: 'one', + second: 'two' + } + } + ); - this.assertText('Truthy!'); + this.assertText('Truthy!'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Truthy!'); + this.assertText('Truthy!'); - this.runTask(() => set(this.context, 'model.first', 'three')); + this.runTask(() => set(this.context, 'model.first', 'three')); - this.assertText('False'); + this.assertText('False'); - this.runTask(() => set(this.context, 'model', { first: 'one', second: 'two' })); + this.runTask(() => + set(this.context, 'model', { first: 'one', second: 'two' }) + ); - this.assertText('Truthy!'); + this.assertText('Truthy!'); + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/helpers/custom-helper-test.js b/packages/ember-glimmer/tests/integration/helpers/custom-helper-test.js index e3a01b49c1b..afeef1ec86b 100644 --- a/packages/ember-glimmer/tests/integration/helpers/custom-helper-test.js +++ b/packages/ember-glimmer/tests/integration/helpers/custom-helper-test.js @@ -5,591 +5,656 @@ import { set } from 'ember-metal'; let assert = QUnit.assert; -moduleFor('Helpers test: custom helpers', class extends RenderingTest { - - ['@test it cannot override built-in syntax']() { - this.registerHelper('if', () => 'Nope'); - expectAssertion(() => { - this.render(`{{if foo 'LOL'}}`, { foo: true }); - }, /You attempted to overwrite the built-in helper \"if\" which is not allowed. Please rename the helper./); - } +moduleFor( + 'Helpers test: custom helpers', + class extends RenderingTest { + ['@test it cannot override built-in syntax']() { + this.registerHelper('if', () => 'Nope'); + expectAssertion(() => { + this.render(`{{if foo 'LOL'}}`, { foo: true }); + }, /You attempted to overwrite the built-in helper \"if\" which is not allowed. Please rename the helper./); + } - ['@test it can resolve custom simple helpers with or without dashes']() { - this.registerHelper('hello', () => 'hello'); - this.registerHelper('hello-world', () => 'hello world'); + ['@test it can resolve custom simple helpers with or without dashes']() { + this.registerHelper('hello', () => 'hello'); + this.registerHelper('hello-world', () => 'hello world'); - this.render('{{hello}} | {{hello-world}}'); + this.render('{{hello}} | {{hello-world}}'); - this.assertText('hello | hello world'); + this.assertText('hello | hello world'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('hello | hello world'); - } + this.assertText('hello | hello world'); + } - ['@test it does not resolve helpers with a `.` (period)']() { - this.registerHelper('hello.world', () => 'hello world'); + ['@test it does not resolve helpers with a `.` (period)']() { + this.registerHelper('hello.world', () => 'hello world'); - this.render('{{hello.world}}', { - hello: { - world: '' - } - }); + this.render('{{hello.world}}', { + hello: { + world: '' + } + }); - this.assertText(''); + this.assertText(''); - this.assertStableRerender(); + this.assertStableRerender(); - this.assertText(''); + this.assertText(''); - this.runTask(() => set(this.context, 'hello', { world: 'hello world!' })); + this.runTask(() => set(this.context, 'hello', { world: 'hello world!' })); - this.assertText('hello world!'); + this.assertText('hello world!'); - this.runTask(() => { - set(this.context, 'hello', { - world: '' + this.runTask(() => { + set(this.context, 'hello', { + world: '' + }); }); - }); - this.assertText(''); - } - - ['@test it can resolve custom class-based helpers with or without dashes']() { - this.registerHelper('hello', { - compute() { - return 'hello'; - } - }); + this.assertText(''); + } - this.registerHelper('hello-world', { - compute() { - return 'hello world'; - } - }); + ['@test it can resolve custom class-based helpers with or without dashes']() { + this.registerHelper('hello', { + compute() { + return 'hello'; + } + }); - this.render('{{hello}} | {{hello-world}}'); + this.registerHelper('hello-world', { + compute() { + return 'hello world'; + } + }); - this.assertText('hello | hello world'); + this.render('{{hello}} | {{hello-world}}'); - this.runTask(() => this.rerender()); + this.assertText('hello | hello world'); - this.assertText('hello | hello world'); - } + this.runTask(() => this.rerender()); - ['@test throws if `this._super` is not called from `init`']() { - this.registerHelper('hello-world', { - init() {} - }); + this.assertText('hello | hello world'); + } - expectAssertion(() => { - this.render('{{hello-world}}'); - }, /You must call `this._super\(...arguments\);` when overriding `init` on a framework object. Please update .* to call `this._super\(...arguments\);` from `init`./); - } + ['@test throws if `this._super` is not called from `init`']() { + this.registerHelper('hello-world', { + init() {} + }); - ['@test class-based helper can recompute a new value']() { - let destroyCount = 0; - let computeCount = 0; - let helper; - - this.registerHelper('hello-world', { - init() { - this._super(...arguments); - helper = this; - }, - compute() { - return ++computeCount; - }, - destroy() { - destroyCount++; - this._super(); - } - }); + expectAssertion(() => { + this.render('{{hello-world}}'); + }, /You must call `this._super\(...arguments\);` when overriding `init` on a framework object. Please update .* to call `this._super\(...arguments\);` from `init`./); + } - this.render('{{hello-world}}'); + ['@test class-based helper can recompute a new value']() { + let destroyCount = 0; + let computeCount = 0; + let helper; + + this.registerHelper('hello-world', { + init() { + this._super(...arguments); + helper = this; + }, + compute() { + return ++computeCount; + }, + destroy() { + destroyCount++; + this._super(); + } + }); - this.assertText('1'); + this.render('{{hello-world}}'); - this.runTask(() => this.rerender()); + this.assertText('1'); - this.assertText('1'); + this.runTask(() => this.rerender()); - this.runTask(() => helper.recompute()); + this.assertText('1'); - this.assertText('2'); + this.runTask(() => helper.recompute()); - assert.strictEqual(destroyCount, 0, 'destroy is not called on recomputation'); - } + this.assertText('2'); - ['@test class-based helper with static arguments can recompute a new value']() { - let destroyCount = 0; - let computeCount = 0; - let helper; - - this.registerHelper('hello-world', { - init() { - this._super(...arguments); - helper = this; - }, - compute() { - return ++computeCount; - }, - destroy() { - destroyCount++; - this._super(); - } - }); + assert.strictEqual( + destroyCount, + 0, + 'destroy is not called on recomputation' + ); + } - this.render('{{hello-world "whut"}}'); + ['@test class-based helper with static arguments can recompute a new value']() { + let destroyCount = 0; + let computeCount = 0; + let helper; + + this.registerHelper('hello-world', { + init() { + this._super(...arguments); + helper = this; + }, + compute() { + return ++computeCount; + }, + destroy() { + destroyCount++; + this._super(); + } + }); - this.assertText('1'); + this.render('{{hello-world "whut"}}'); - this.runTask(() => this.rerender()); + this.assertText('1'); - this.assertText('1'); + this.runTask(() => this.rerender()); - this.runTask(() => helper.recompute()); + this.assertText('1'); - this.assertText('2'); + this.runTask(() => helper.recompute()); - assert.strictEqual(destroyCount, 0, 'destroy is not called on recomputation'); - } + this.assertText('2'); - ['@test helper params can be returned']() { - this.registerHelper('hello-world', values => { - return values; - }); + assert.strictEqual( + destroyCount, + 0, + 'destroy is not called on recomputation' + ); + } - this.render('{{#each (hello-world model) as |item|}}({{item}}){{/each}}', { - model: ['bob'] - }); + ['@test helper params can be returned']() { + this.registerHelper('hello-world', values => { + return values; + }); - this.assertText('(bob)'); - } + this.render( + '{{#each (hello-world model) as |item|}}({{item}}){{/each}}', + { + model: ['bob'] + } + ); - ['@test helper hash can be returned']() { - this.registerHelper('hello-world', (_, hash) => { - return hash.model; - }); + this.assertText('(bob)'); + } - this.render(`{{get (hello-world model=model) 'name'}}`, { - model: { name: 'bob' } - }); + ['@test helper hash can be returned']() { + this.registerHelper('hello-world', (_, hash) => { + return hash.model; + }); - this.assertText('bob'); - } + this.render(`{{get (hello-world model=model) 'name'}}`, { + model: { name: 'bob' } + }); - ['@test simple helper is called for param changes']() { - let computeCount = 0; + this.assertText('bob'); + } - this.registerHelper('hello-world', ([value]) => { - computeCount++; - return `${value}-value`; - }); + ['@test simple helper is called for param changes']() { + let computeCount = 0; - this.render('{{hello-world model.name}}', { - model: { name: 'bob' } - }); + this.registerHelper('hello-world', ([value]) => { + computeCount++; + return `${value}-value`; + }); - this.assertText('bob-value'); + this.render('{{hello-world model.name}}', { + model: { name: 'bob' } + }); - assert.strictEqual(computeCount, 1, 'compute is called exactly 1 time'); + this.assertText('bob-value'); - this.runTask(() => this.rerender()); + assert.strictEqual(computeCount, 1, 'compute is called exactly 1 time'); - this.assertText('bob-value'); + this.runTask(() => this.rerender()); - assert.strictEqual(computeCount, 1, 'compute is called exactly 1 time'); + this.assertText('bob-value'); - this.runTask(() => set(this.context, 'model.name', 'sal')); + assert.strictEqual(computeCount, 1, 'compute is called exactly 1 time'); - this.assertText('sal-value'); + this.runTask(() => set(this.context, 'model.name', 'sal')); - assert.strictEqual(computeCount, 2, 'compute is called exactly 2 times'); + this.assertText('sal-value'); - this.runTask(() => set(this.context, 'model', { name: 'bob' })); + assert.strictEqual(computeCount, 2, 'compute is called exactly 2 times'); - this.assertText('bob-value'); + this.runTask(() => set(this.context, 'model', { name: 'bob' })); - assert.strictEqual(computeCount, 3, 'compute is called exactly 3 times'); - } + this.assertText('bob-value'); - ['@test class-based helper compute is called for param changes']() { - let createCount = 0; - let computeCount = 0; + assert.strictEqual(computeCount, 3, 'compute is called exactly 3 times'); + } - this.registerHelper('hello-world', { - init() { - this._super(...arguments); - createCount++; - }, - compute([value]) { - computeCount++; - return `${value}-value`; - } - }); + ['@test class-based helper compute is called for param changes']() { + let createCount = 0; + let computeCount = 0; + + this.registerHelper('hello-world', { + init() { + this._super(...arguments); + createCount++; + }, + compute([value]) { + computeCount++; + return `${value}-value`; + } + }); - this.render('{{hello-world model.name}}', { - model: { name: 'bob' } - }); + this.render('{{hello-world model.name}}', { + model: { name: 'bob' } + }); - this.assertText('bob-value'); + this.assertText('bob-value'); - assert.strictEqual(computeCount, 1, 'compute is called exactly 1 time'); + assert.strictEqual(computeCount, 1, 'compute is called exactly 1 time'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('bob-value'); + this.assertText('bob-value'); - assert.strictEqual(computeCount, 1, 'compute is called exactly 1 time'); + assert.strictEqual(computeCount, 1, 'compute is called exactly 1 time'); - this.runTask(() => set(this.context, 'model.name', 'sal')); + this.runTask(() => set(this.context, 'model.name', 'sal')); - this.assertText('sal-value'); + this.assertText('sal-value'); - assert.strictEqual(computeCount, 2, 'compute is called exactly 2 times'); + assert.strictEqual(computeCount, 2, 'compute is called exactly 2 times'); - this.runTask(() => set(this.context, 'model', { name: 'bob' })); + this.runTask(() => set(this.context, 'model', { name: 'bob' })); - this.assertText('bob-value'); + this.assertText('bob-value'); - assert.strictEqual(computeCount, 3, 'compute is called exactly 3 times'); - assert.strictEqual(createCount, 1, 'helper is only created once'); - } + assert.strictEqual(computeCount, 3, 'compute is called exactly 3 times'); + assert.strictEqual(createCount, 1, 'helper is only created once'); + } - ['@test simple helper receives params, hash']() { - this.registerHelper('hello-world', (_params, _hash) => { - return `params: ${JSON.stringify(_params)}, hash: ${JSON.stringify(_hash)}`; - }); + ['@test simple helper receives params, hash']() { + this.registerHelper('hello-world', (_params, _hash) => { + return `params: ${JSON.stringify(_params)}, hash: ${JSON.stringify( + _hash + )}`; + }); - this.render('{{hello-world model.name "rich" first=model.age last="sam"}}', { - model: { - name: 'bob', - age: 42 - } - }); + this.render( + '{{hello-world model.name "rich" first=model.age last="sam"}}', + { + model: { + name: 'bob', + age: 42 + } + } + ); - this.assertText('params: ["bob","rich"], hash: {"first":42,"last":"sam"}'); + this.assertText( + 'params: ["bob","rich"], hash: {"first":42,"last":"sam"}' + ); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('params: ["bob","rich"], hash: {"first":42,"last":"sam"}'); + this.assertText( + 'params: ["bob","rich"], hash: {"first":42,"last":"sam"}' + ); - this.runTask(() => set(this.context, 'model.name', 'sal')); + this.runTask(() => set(this.context, 'model.name', 'sal')); - this.assertText('params: ["sal","rich"], hash: {"first":42,"last":"sam"}'); + this.assertText( + 'params: ["sal","rich"], hash: {"first":42,"last":"sam"}' + ); - this.runTask(() => set(this.context, 'model.age', 28)); + this.runTask(() => set(this.context, 'model.age', 28)); - this.assertText('params: ["sal","rich"], hash: {"first":28,"last":"sam"}'); + this.assertText( + 'params: ["sal","rich"], hash: {"first":28,"last":"sam"}' + ); - this.runTask(() => set(this.context, 'model', { name: 'bob', age: 42 })); + this.runTask(() => set(this.context, 'model', { name: 'bob', age: 42 })); - this.assertText('params: ["bob","rich"], hash: {"first":42,"last":"sam"}'); - } + this.assertText( + 'params: ["bob","rich"], hash: {"first":42,"last":"sam"}' + ); + } - ['@test class-based helper receives params, hash']() { - this.registerHelper('hello-world', { - compute(_params, _hash) { - return `params: ${JSON.stringify(_params)}, hash: ${JSON.stringify(_hash)}`; - } - }); + ['@test class-based helper receives params, hash']() { + this.registerHelper('hello-world', { + compute(_params, _hash) { + return `params: ${JSON.stringify(_params)}, hash: ${JSON.stringify( + _hash + )}`; + } + }); - this.render('{{hello-world model.name "rich" first=model.age last="sam"}}', { - model: { - name: 'bob', - age: 42 - } - }); + this.render( + '{{hello-world model.name "rich" first=model.age last="sam"}}', + { + model: { + name: 'bob', + age: 42 + } + } + ); - this.assertText('params: ["bob","rich"], hash: {"first":42,"last":"sam"}'); + this.assertText( + 'params: ["bob","rich"], hash: {"first":42,"last":"sam"}' + ); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('params: ["bob","rich"], hash: {"first":42,"last":"sam"}'); + this.assertText( + 'params: ["bob","rich"], hash: {"first":42,"last":"sam"}' + ); - this.runTask(() => set(this.context, 'model.name', 'sal')); + this.runTask(() => set(this.context, 'model.name', 'sal')); - this.assertText('params: ["sal","rich"], hash: {"first":42,"last":"sam"}'); + this.assertText( + 'params: ["sal","rich"], hash: {"first":42,"last":"sam"}' + ); - this.runTask(() => set(this.context, 'model.age', 28)); + this.runTask(() => set(this.context, 'model.age', 28)); - this.assertText('params: ["sal","rich"], hash: {"first":28,"last":"sam"}'); + this.assertText( + 'params: ["sal","rich"], hash: {"first":28,"last":"sam"}' + ); - this.runTask(() => set(this.context, 'model', { name: 'bob', age: 42 })); + this.runTask(() => set(this.context, 'model', { name: 'bob', age: 42 })); - this.assertText('params: ["bob","rich"], hash: {"first":42,"last":"sam"}'); - } + this.assertText( + 'params: ["bob","rich"], hash: {"first":42,"last":"sam"}' + ); + } - ['@test class-based helper usable in subexpressions']() { - this.registerHelper('join-words', { - compute(params) { - return params.join(' '); - } - }); + ['@test class-based helper usable in subexpressions']() { + this.registerHelper('join-words', { + compute(params) { + return params.join(' '); + } + }); - this.render( - `{{join-words "Who" + this.render( + `{{join-words "Who" (join-words "overcomes" "by") model.reason (join-words (join-words "hath overcome but" "half")) (join-words "his" (join-words "foe"))}}`, - { model: { reason: 'force' } }); + { model: { reason: 'force' } } + ); - this.assertText('Who overcomes by force hath overcome but half his foe'); + this.assertText('Who overcomes by force hath overcome but half his foe'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Who overcomes by force hath overcome but half his foe'); + this.assertText('Who overcomes by force hath overcome but half his foe'); - this.runTask(() => set(this.context, 'model.reason', 'Nickleback')); + this.runTask(() => set(this.context, 'model.reason', 'Nickleback')); - this.assertText('Who overcomes by Nickleback hath overcome but half his foe'); + this.assertText( + 'Who overcomes by Nickleback hath overcome but half his foe' + ); - this.runTask(() => set(this.context, 'model', { reason: 'force' })); + this.runTask(() => set(this.context, 'model', { reason: 'force' })); - this.assertText('Who overcomes by force hath overcome but half his foe'); - } + this.assertText('Who overcomes by force hath overcome but half his foe'); + } - ['@test parameterless helper is usable in subexpressions']() { - this.registerHelper('should-show', () => { return true; }); + ['@test parameterless helper is usable in subexpressions']() { + this.registerHelper('should-show', () => { + return true; + }); - this.render(`{{#if (should-show)}}true{{/if}}`); + this.render(`{{#if (should-show)}}true{{/if}}`); - this.assertText('true'); + this.assertText('true'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('true'); - } + this.assertText('true'); + } - ['@test parameterless helper is usable in attributes']() { - this.registerHelper('foo-bar', () => { return 'baz'; }); + ['@test parameterless helper is usable in attributes']() { + this.registerHelper('foo-bar', () => { + return 'baz'; + }); - this.render(`
`); + this.render(`
`); - this.assertHTML('
'); + this.assertHTML('
'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertHTML('
'); - } - - ['@test simple helper not usable with a block']() { - this.registerHelper('some-helper', () => {}); + this.assertHTML('
'); + } - expectAssertion(() => { - this.render(`{{#some-helper}}{{/some-helper}}`); - }, /Helpers may not be used in the block form/); - } + ['@test simple helper not usable with a block']() { + this.registerHelper('some-helper', () => {}); - ['@test class-based helper not usable with a block']() { - this.registerHelper('some-helper', { - compute() { - } - }); + expectAssertion(() => { + this.render(`{{#some-helper}}{{/some-helper}}`); + }, /Helpers may not be used in the block form/); + } - expectAssertion(() => { - this.render(`{{#some-helper}}{{/some-helper}}`); - }, /Helpers may not be used in the block form/); - } + ['@test class-based helper not usable with a block']() { + this.registerHelper('some-helper', { + compute() {} + }); - ['@test simple helper not usable within element']() { - this.registerHelper('some-helper', () => {}); + expectAssertion(() => { + this.render(`{{#some-helper}}{{/some-helper}}`); + }, /Helpers may not be used in the block form/); + } - this.assert.throws(() => { - this.render(`
`); - }, /Compile Error some-helper is not a modifier: Helpers may not be used in the element form/); - } + ['@test simple helper not usable within element']() { + this.registerHelper('some-helper', () => {}); - ['@test class-based helper not usable within element']() { - this.registerHelper('some-helper', { - compute() { - } - }); + this.assert.throws(() => { + this.render(`
`); + }, /Compile Error some-helper is not a modifier: Helpers may not be used in the element form/); + } - this.assert.throws(() => { - this.render(`
`); - }, /Compile Error some-helper is not a modifier: Helpers may not be used in the element form/); - } + ['@test class-based helper not usable within element']() { + this.registerHelper('some-helper', { + compute() {} + }); - ['@test class-based helper is torn down']() { - let destroyCalled = 0; + this.assert.throws(() => { + this.render(`
`); + }, /Compile Error some-helper is not a modifier: Helpers may not be used in the element form/); + } - this.registerHelper('some-helper', { - destroy() { - destroyCalled++; - this._super(...arguments); - }, - compute() { - return 'must define a compute'; - } - }); + ['@test class-based helper is torn down']() { + let destroyCalled = 0; + + this.registerHelper('some-helper', { + destroy() { + destroyCalled++; + this._super(...arguments); + }, + compute() { + return 'must define a compute'; + } + }); - this.render(`{{some-helper}}`); + this.render(`{{some-helper}}`); - runDestroy(this.component); + runDestroy(this.component); - assert.strictEqual(destroyCalled, 1, 'destroy called once'); - } + assert.strictEqual(destroyCalled, 1, 'destroy called once'); + } - ['@test class-based helper used in subexpression can recompute']() { - let helper; - let phrase = 'overcomes by'; - - this.registerHelper('dynamic-segment', { - init() { - this._super(...arguments); - helper = this; - }, - compute() { - return phrase; - } - }); + ['@test class-based helper used in subexpression can recompute']() { + let helper; + let phrase = 'overcomes by'; + + this.registerHelper('dynamic-segment', { + init() { + this._super(...arguments); + helper = this; + }, + compute() { + return phrase; + } + }); - this.registerHelper('join-words', { - compute(params) { - return params.join(' '); - } - }); + this.registerHelper('join-words', { + compute(params) { + return params.join(' '); + } + }); - this.render( - `{{join-words "Who" + this.render( + `{{join-words "Who" (dynamic-segment) "force" (join-words (join-words "hath overcome but" "half")) - (join-words "his" (join-words "foe"))}}`); + (join-words "his" (join-words "foe"))}}` + ); - this.assertText('Who overcomes by force hath overcome but half his foe'); + this.assertText('Who overcomes by force hath overcome but half his foe'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Who overcomes by force hath overcome but half his foe'); + this.assertText('Who overcomes by force hath overcome but half his foe'); - phrase = 'believes his'; + phrase = 'believes his'; - this.runTask(() => helper.recompute()); + this.runTask(() => helper.recompute()); - this.assertText('Who believes his force hath overcome but half his foe'); + this.assertText('Who believes his force hath overcome but half his foe'); - phrase = 'overcomes by'; + phrase = 'overcomes by'; - this.runTask(() => helper.recompute()); + this.runTask(() => helper.recompute()); - this.assertText('Who overcomes by force hath overcome but half his foe'); - } + this.assertText('Who overcomes by force hath overcome but half his foe'); + } - ['@test class-based helper used in subexpression can recompute component']() { - let helper; - let phrase = 'overcomes by'; - - this.registerHelper('dynamic-segment', { - init() { - this._super(...arguments); - helper = this; - }, - compute() { - return phrase; - } - }); + ['@test class-based helper used in subexpression can recompute component']() { + let helper; + let phrase = 'overcomes by'; + + this.registerHelper('dynamic-segment', { + init() { + this._super(...arguments); + helper = this; + }, + compute() { + return phrase; + } + }); - this.registerHelper('join-words', { - compute(params) { - return params.join(' '); - } - }); + this.registerHelper('join-words', { + compute(params) { + return params.join(' '); + } + }); - this.registerComponent('some-component', { - template: '{{first}} {{second}} {{third}} {{fourth}} {{fifth}}' - }); + this.registerComponent('some-component', { + template: '{{first}} {{second}} {{third}} {{fourth}} {{fifth}}' + }); - this.render( - `{{some-component first="Who" + this.render( + `{{some-component first="Who" second=(dynamic-segment) third="force" fourth=(join-words (join-words "hath overcome but" "half")) - fifth=(join-words "his" (join-words "foe"))}}`); + fifth=(join-words "his" (join-words "foe"))}}` + ); - this.assertText('Who overcomes by force hath overcome but half his foe'); + this.assertText('Who overcomes by force hath overcome but half his foe'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Who overcomes by force hath overcome but half his foe'); + this.assertText('Who overcomes by force hath overcome but half his foe'); - phrase = 'believes his'; + phrase = 'believes his'; - this.runTask(() => helper.recompute()); + this.runTask(() => helper.recompute()); - this.assertText('Who believes his force hath overcome but half his foe'); + this.assertText('Who believes his force hath overcome but half his foe'); - phrase = 'overcomes by'; + phrase = 'overcomes by'; - this.runTask(() => helper.recompute()); + this.runTask(() => helper.recompute()); - this.assertText('Who overcomes by force hath overcome but half his foe'); - } + this.assertText('Who overcomes by force hath overcome but half his foe'); + } - ['@test class-based helper used in subexpression is destroyed'](assert) { - let destroyCount = 0; - - this.registerHelper('dynamic-segment', { - phrase: 'overcomes by', - init() { - this._super(...arguments); - }, - compute() { - return this.phrase; - }, - destroy() { - destroyCount++; - this._super(...arguments); - } - }); + ['@test class-based helper used in subexpression is destroyed'](assert) { + let destroyCount = 0; + + this.registerHelper('dynamic-segment', { + phrase: 'overcomes by', + init() { + this._super(...arguments); + }, + compute() { + return this.phrase; + }, + destroy() { + destroyCount++; + this._super(...arguments); + } + }); - this.registerHelper('join-words', { - compute(params) { - return params.join(' '); - } - }); + this.registerHelper('join-words', { + compute(params) { + return params.join(' '); + } + }); - this.render( - `{{join-words "Who" + this.render( + `{{join-words "Who" (dynamic-segment) "force" (join-words (join-words "hath overcome but" "half")) - (join-words "his" (join-words "foe"))}}`); + (join-words "his" (join-words "foe"))}}` + ); - runDestroy(this.component); + runDestroy(this.component); - assert.equal(destroyCount, 1, 'destroy is called after a view is destroyed'); - } + assert.equal( + destroyCount, + 1, + 'destroy is called after a view is destroyed' + ); + } - ['@test simple helper can be invoked manually via `owner.factoryFor(...).create().compute()'](assert) { - this.registerHelper('some-helper', () => { - assert.ok(true, 'some-helper helper invoked'); - return 'lolol'; - }); + ['@test simple helper can be invoked manually via `owner.factoryFor(...).create().compute()']( + assert + ) { + this.registerHelper('some-helper', () => { + assert.ok(true, 'some-helper helper invoked'); + return 'lolol'; + }); - let instance = this.owner.factoryFor('helper:some-helper').create(); + let instance = this.owner.factoryFor('helper:some-helper').create(); - assert.equal(typeof instance.compute, 'function', 'expected instance.compute to be present'); - assert.equal(instance.compute(), 'lolol', 'can invoke `.compute`'); - } + assert.equal( + typeof instance.compute, + 'function', + 'expected instance.compute to be present' + ); + assert.equal(instance.compute(), 'lolol', 'can invoke `.compute`'); + } - ['@test class-based helper can be invoked manually via `owner.factoryFor(...).create().compute()']() { - this.registerHelper('some-helper', { - compute() { - assert.ok(true, 'some-helper helper invoked'); - return 'lolol'; - } - }); + ['@test class-based helper can be invoked manually via `owner.factoryFor(...).create().compute()']() { + this.registerHelper('some-helper', { + compute() { + assert.ok(true, 'some-helper helper invoked'); + return 'lolol'; + } + }); - let instance = this.owner.factoryFor('helper:some-helper').create(); + let instance = this.owner.factoryFor('helper:some-helper').create(); - assert.equal(typeof instance.compute, 'function', 'expected instance.compute to be present'); - assert.equal(instance.compute(), 'lolol', 'can invoke `.compute`'); + assert.equal( + typeof instance.compute, + 'function', + 'expected instance.compute to be present' + ); + assert.equal(instance.compute(), 'lolol', 'can invoke `.compute`'); + } } -}); +); if (!EmberDev.runningProdBuild) { class HelperMutatingArgsTests extends RenderingTest { @@ -632,25 +697,31 @@ if (!EmberDev.runningProdBuild) { } } - moduleFor('Helpers test: mutation triggers errors - class based helper', class extends HelperMutatingArgsTests { - constructor() { - super(); + moduleFor( + 'Helpers test: mutation triggers errors - class based helper', + class extends HelperMutatingArgsTests { + constructor() { + super(); - let compute = this.buildCompute(); + let compute = this.buildCompute(); - this.registerHelper('test-helper', { - compute - }); + this.registerHelper('test-helper', { + compute + }); + } } - }); + ); - moduleFor('Helpers test: mutation triggers errors - simple helper', class extends HelperMutatingArgsTests { - constructor() { - super(); + moduleFor( + 'Helpers test: mutation triggers errors - simple helper', + class extends HelperMutatingArgsTests { + constructor() { + super(); - let compute = this.buildCompute(); + let compute = this.buildCompute(); - this.registerHelper('test-helper', compute); + this.registerHelper('test-helper', compute); + } } - }); + ); } diff --git a/packages/ember-glimmer/tests/integration/helpers/element-action-test.js b/packages/ember-glimmer/tests/integration/helpers/element-action-test.js index 8aa03e26ad2..ae7d594cdd6 100644 --- a/packages/ember-glimmer/tests/integration/helpers/element-action-test.js +++ b/packages/ember-glimmer/tests/integration/helpers/element-action-test.js @@ -28,1441 +28,1814 @@ function getActionAttributes(element) { } function getActionIds(element) { - return getActionAttributes(element).map(attribute => attribute.slice('data-ember-action-'.length)); + return getActionAttributes(element).map(attribute => + attribute.slice('data-ember-action-'.length) + ); } const isIE11 = !window.ActiveXObject && 'ActiveXObject' in window; if (EMBER_IMPROVED_INSTRUMENTATION) { - moduleFor('Helpers test: element action instrumentation', class extends RenderingTest { - teardown() { - super.teardown(); - instrumentationReset(); + moduleFor( + 'Helpers test: element action instrumentation', + class extends RenderingTest { + teardown() { + super.teardown(); + instrumentationReset(); + } + + ['@test action should fire interaction event with proper params']() { + let subscriberCallCount = 0; + let subscriberPayload = null; + + let ExampleComponent = Component.extend({ + actions: { + foo() {} + } + }); + + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: '' + }); + + instrumentationSubscribe('interaction.ember-action', { + before() { + subscriberCallCount++; + }, + after(name, time, payload) { + subscriberPayload = payload; + } + }); + + this.render('{{example-component}}'); + + this.assert.equal( + subscriberCallCount, + 0, + 'subscriber has not been called' + ); + + this.runTask(() => this.rerender()); + + this.assert.equal( + subscriberCallCount, + 0, + 'subscriber has not been called' + ); + + this.runTask(() => { + this.$('button').click(); + }); + + this.assert.equal( + subscriberCallCount, + 1, + 'subscriber has been called 1 time' + ); + this.assert.equal( + subscriberPayload.name, + 'foo', + 'subscriber called with correct name' + ); + this.assert.equal( + subscriberPayload.args[0], + 'bar', + 'subscriber called with correct args' + ); + } } + ); +} - ['@test action should fire interaction event with proper params']() { - let subscriberCallCount = 0; - let subscriberPayload = null; +moduleFor( + 'Helpers test: element action', + class extends RenderingTest { + ['@test it can call an action on its enclosing component']() { + let fooCallCount = 0; let ExampleComponent = Component.extend({ actions: { - foo() {} + foo() { + fooCallCount++; + } } }); this.registerComponent('example-component', { ComponentClass: ExampleComponent, - template: '' - }); - - instrumentationSubscribe('interaction.ember-action', { - before() { - subscriberCallCount++; - }, - after(name, time, payload) { - subscriberPayload = payload; - } + template: '' }); this.render('{{example-component}}'); - this.assert.equal(subscriberCallCount, 0, 'subscriber has not been called'); + this.assert.equal(fooCallCount, 0, 'foo has not been called'); this.runTask(() => this.rerender()); - this.assert.equal(subscriberCallCount, 0, 'subscriber has not been called'); + this.assert.equal(fooCallCount, 0, 'foo has not been called'); this.runTask(() => { this.$('button').click(); }); - this.assert.equal(subscriberCallCount, 1, 'subscriber has been called 1 time'); - this.assert.equal(subscriberPayload.name, 'foo', 'subscriber called with correct name'); - this.assert.equal(subscriberPayload.args[0], 'bar', 'subscriber called with correct args'); - } - }); -} - - -moduleFor('Helpers test: element action', class extends RenderingTest { - - ['@test it can call an action on its enclosing component']() { - let fooCallCount = 0; - - let ExampleComponent = Component.extend({ - actions: { - foo() { - fooCallCount++; - } - } - }); - - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: '' - }); - - this.render('{{example-component}}'); - - this.assert.equal(fooCallCount, 0, 'foo has not been called'); - - this.runTask(() => this.rerender()); + this.assert.equal(fooCallCount, 1, 'foo has been called 1 time'); - this.assert.equal(fooCallCount, 0, 'foo has not been called'); - - this.runTask(() => { - this.$('button').click(); - }); - - this.assert.equal(fooCallCount, 1, 'foo has been called 1 time'); + this.runTask(() => { + this.$('button').click(); + }); - this.runTask(() => { - this.$('button').click(); - }); + this.assert.equal(fooCallCount, 2, 'foo has been called 2 times'); + } - this.assert.equal(fooCallCount, 2, 'foo has been called 2 times'); - } + ['@test it can call an action with parameters']() { + let fooArgs = []; + let component; - ['@test it can call an action with parameters']() { - let fooArgs = []; - let component; - - let ExampleComponent = Component.extend({ - member: 'a', - init() { - this._super(...arguments); - component = this; - }, - actions: { - foo(thing) { - fooArgs.push(thing); + let ExampleComponent = Component.extend({ + member: 'a', + init() { + this._super(...arguments); + component = this; + }, + actions: { + foo(thing) { + fooArgs.push(thing); + } } - } - }); + }); - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: '' - }); + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: '' + }); - this.render('{{example-component}}'); + this.render('{{example-component}}'); - this.assert.deepEqual(fooArgs, [], 'foo has not been called'); + this.assert.deepEqual(fooArgs, [], 'foo has not been called'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assert.deepEqual(fooArgs, [], 'foo has not been called'); + this.assert.deepEqual(fooArgs, [], 'foo has not been called'); - this.runTask(() => { - this.$('button').click(); - }); + this.runTask(() => { + this.$('button').click(); + }); - this.assert.deepEqual(fooArgs, ['a'], 'foo has not been called'); + this.assert.deepEqual(fooArgs, ['a'], 'foo has not been called'); - this.runTask(() => { - component.set('member', 'b'); - }); + this.runTask(() => { + component.set('member', 'b'); + }); - this.runTask(() => { - this.$('button').click(); - }); + this.runTask(() => { + this.$('button').click(); + }); - this.assert.deepEqual(fooArgs, ['a', 'b'], 'foo has been called with an updated value'); - } + this.assert.deepEqual( + fooArgs, + ['a', 'b'], + 'foo has been called with an updated value' + ); + } - ['@test it should output a marker attribute with a guid']() { - this.render(''); + ['@test it should output a marker attribute with a guid']() { + this.render(''); - let button = this.$('button'); + let button = this.$('button'); - let attributes = getActionAttributes(button[0]); + let attributes = getActionAttributes(button[0]); - this.assert.ok(button.attr('data-ember-action').match(''), 'An empty data-ember-action attribute was added'); - this.assert.ok(attributes[0].match(/data-ember-action-\d+/), 'A data-ember-action-xyz attribute with a guid was added'); - } + this.assert.ok( + button.attr('data-ember-action').match(''), + 'An empty data-ember-action attribute was added' + ); + this.assert.ok( + attributes[0].match(/data-ember-action-\d+/), + 'A data-ember-action-xyz attribute with a guid was added' + ); + } - ['@test it should allow alternative events to be handled']() { - let showCalled = false; + ['@test it should allow alternative events to be handled']() { + let showCalled = false; - let ExampleComponent = Component.extend({ - actions: { - show() { - showCalled = true; + let ExampleComponent = Component.extend({ + actions: { + show() { + showCalled = true; + } } - } - }); + }); - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: '
' - }); + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: '
' + }); - this.render('{{example-component}}'); + this.render('{{example-component}}'); - this.runTask(() => { - this.$('#show').trigger('mouseup'); - }); + this.runTask(() => { + this.$('#show').trigger('mouseup'); + }); - this.assert.ok(showCalled, 'show action was called on mouseUp'); - } + this.assert.ok(showCalled, 'show action was called on mouseUp'); + } - ['@test inside a yield, the target points at the original target']() { - let targetWatted = false; - let innerWatted = false; + ['@test inside a yield, the target points at the original target']() { + let targetWatted = false; + let innerWatted = false; - let TargetComponent = Component.extend({ - actions: { - wat() { - targetWatted = true; + let TargetComponent = Component.extend({ + actions: { + wat() { + targetWatted = true; + } } - } - }); + }); - let InnerComponent = Component.extend({ - actions: { - wat() { - innerWatted = true; + let InnerComponent = Component.extend({ + actions: { + wat() { + innerWatted = true; + } } - } - }); + }); - this.registerComponent('inner-component', { - ComponentClass: InnerComponent, - template: '{{yield}}' - }); + this.registerComponent('inner-component', { + ComponentClass: InnerComponent, + template: '{{yield}}' + }); - this.registerComponent('target-component', { - ComponentClass: TargetComponent, - template: strip` + this.registerComponent('target-component', { + ComponentClass: TargetComponent, + template: strip` {{#inner-component}} {{/inner-component}} ` - }); + }); - this.render('{{target-component}}'); + this.render('{{target-component}}'); - this.runTask(() => { - this.$('button').click(); - }); + this.runTask(() => { + this.$('button').click(); + }); - this.assert.ok(targetWatted, 'the correct target was watted'); - this.assert.notOk(innerWatted, 'the inner target was not watted'); - } + this.assert.ok(targetWatted, 'the correct target was watted'); + this.assert.notOk(innerWatted, 'the inner target was not watted'); + } - ['@test it should allow a target to be specified']() { - let targetWatted = false; + ['@test it should allow a target to be specified']() { + let targetWatted = false; - let TargetComponent = Component.extend({ - actions: { - wat() { - targetWatted = true; + let TargetComponent = Component.extend({ + actions: { + wat() { + targetWatted = true; + } } - } - }); + }); - let OtherComponent = Component.extend({ - }); + let OtherComponent = Component.extend({}); - this.registerComponent('target-component', { - ComponentClass: TargetComponent, - template: '{{yield this}}' - }); + this.registerComponent('target-component', { + ComponentClass: TargetComponent, + template: '{{yield this}}' + }); - this.registerComponent('other-component', { - ComponentClass: OtherComponent, - template: 'Wat?' - }); + this.registerComponent('other-component', { + ComponentClass: OtherComponent, + template: 'Wat?' + }); - this.render(strip` + this.render(strip` {{#target-component as |parent|}} {{other-component anotherTarget=parent}} {{/target-component}} `); - this.runTask(() => { - this.$('a').click(); - }); - - this.assert.equal(targetWatted, true, 'the specified target was watted'); - } + this.runTask(() => { + this.$('a').click(); + }); - ['@test it should lazily evaluate the target']() { - let firstEdit = 0; - let secondEdit = 0; - let component; + this.assert.equal(targetWatted, true, 'the specified target was watted'); + } - let first = { - edit() { - firstEdit++; - } - }; + ['@test it should lazily evaluate the target']() { + let firstEdit = 0; + let secondEdit = 0; + let component; - let second = { - edit() { - secondEdit++; - } - }; + let first = { + edit() { + firstEdit++; + } + }; - let ExampleComponent = Component.extend({ - init() { - this._super(...arguments); - component = this; - }, - theTarget: first - }); + let second = { + edit() { + secondEdit++; + } + }; - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: 'Edit' - }); + let ExampleComponent = Component.extend({ + init() { + this._super(...arguments); + component = this; + }, + theTarget: first + }); - this.render('{{example-component}}'); + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: 'Edit' + }); - this.runTask(() => { - this.$('a').click(); - }); + this.render('{{example-component}}'); - this.assert.equal(firstEdit, 1); + this.runTask(() => { + this.$('a').click(); + }); - this.runTask(() => { - set(component, 'theTarget', second); - }); + this.assert.equal(firstEdit, 1); - this.runTask(() => { - this.$('a').click(); - }); + this.runTask(() => { + set(component, 'theTarget', second); + }); - this.assert.equal(firstEdit, 1); - this.assert.equal(secondEdit, 1); - } + this.runTask(() => { + this.$('a').click(); + }); - ['@test it should register an event handler']() { - let editHandlerWasCalled = false; - let shortcutHandlerWasCalled = false; + this.assert.equal(firstEdit, 1); + this.assert.equal(secondEdit, 1); + } - let ExampleComponent = Component.extend({ - actions: { - edit() { editHandlerWasCalled = true; }, - shortcut() { shortcutHandlerWasCalled = true; } - } - }); + ['@test it should register an event handler']() { + let editHandlerWasCalled = false; + let shortcutHandlerWasCalled = false; - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: 'click me
click me too
' - }); + let ExampleComponent = Component.extend({ + actions: { + edit() { + editHandlerWasCalled = true; + }, + shortcut() { + shortcutHandlerWasCalled = true; + } + } + }); - this.render('{{example-component}}'); + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: + 'click me
click me too
' + }); - this.runTask(() => { - this.$('a[data-ember-action]').trigger('click', { altKey: true }); - }); + this.render('{{example-component}}'); - this.assert.equal(editHandlerWasCalled, true, 'the event handler was called'); + this.runTask(() => { + this.$('a[data-ember-action]').trigger('click', { altKey: true }); + }); - this.runTask(() => { - this.$('div[data-ember-action]').trigger('click', { ctrlKey: true }); - }); + this.assert.equal( + editHandlerWasCalled, + true, + 'the event handler was called' + ); - this.assert.equal(shortcutHandlerWasCalled, true, 'the "any" shortcut\'s event handler was called'); - } + this.runTask(() => { + this.$('div[data-ember-action]').trigger('click', { ctrlKey: true }); + }); - ['@test it handles whitelisted bound modifier keys']() { - let editHandlerWasCalled = false; - let shortcutHandlerWasCalled = false; + this.assert.equal( + shortcutHandlerWasCalled, + true, + 'the "any" shortcut\'s event handler was called' + ); + } - let ExampleComponent = Component.extend({ - altKey: 'alt', - anyKey: 'any', - actions: { - edit() { editHandlerWasCalled = true; }, - shortcut() { shortcutHandlerWasCalled = true; } - } - }); + ['@test it handles whitelisted bound modifier keys']() { + let editHandlerWasCalled = false; + let shortcutHandlerWasCalled = false; - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: 'click me
click me too
' - }); + let ExampleComponent = Component.extend({ + altKey: 'alt', + anyKey: 'any', + actions: { + edit() { + editHandlerWasCalled = true; + }, + shortcut() { + shortcutHandlerWasCalled = true; + } + } + }); - this.render('{{example-component}}'); + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: + 'click me
click me too
' + }); - this.runTask(() => { - this.$('a[data-ember-action]').trigger('click', { altKey: true }); - }); + this.render('{{example-component}}'); - this.assert.equal(editHandlerWasCalled, true, 'the event handler was called'); + this.runTask(() => { + this.$('a[data-ember-action]').trigger('click', { altKey: true }); + }); - this.runTask(() => { - this.$('div[data-ember-action]').trigger('click', { ctrlKey: true }); - }); + this.assert.equal( + editHandlerWasCalled, + true, + 'the event handler was called' + ); - this.assert.equal(shortcutHandlerWasCalled, true, 'the "any" shortcut\'s event handler was called'); - } + this.runTask(() => { + this.$('div[data-ember-action]').trigger('click', { ctrlKey: true }); + }); - ['@test it handles whitelisted bound modifier keys with current value']() { - let editHandlerWasCalled = false; - let component; - - let ExampleComponent = Component.extend({ - init() { - this._super(...arguments); - component = this; - }, - acceptedKeys: 'alt', - actions: { - edit() { editHandlerWasCalled = true; } - } - }); + this.assert.equal( + shortcutHandlerWasCalled, + true, + 'the "any" shortcut\'s event handler was called' + ); + } - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: 'click me' - }); + ['@test it handles whitelisted bound modifier keys with current value']() { + let editHandlerWasCalled = false; + let component; - this.render('{{example-component}}'); + let ExampleComponent = Component.extend({ + init() { + this._super(...arguments); + component = this; + }, + acceptedKeys: 'alt', + actions: { + edit() { + editHandlerWasCalled = true; + } + } + }); - this.runTask(() => { - this.$('a[data-ember-action]').trigger('click', { altKey: true }); - }); + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: + 'click me' + }); - this.assert.equal(editHandlerWasCalled, true, 'the event handler was called'); + this.render('{{example-component}}'); - editHandlerWasCalled = false; + this.runTask(() => { + this.$('a[data-ember-action]').trigger('click', { altKey: true }); + }); - this.runTask(() => { - component.set('acceptedKeys', ''); - }); + this.assert.equal( + editHandlerWasCalled, + true, + 'the event handler was called' + ); - this.runTask(() => { - this.$('div[data-ember-action]').click(); - }); + editHandlerWasCalled = false; - this.assert.equal(editHandlerWasCalled, false, 'the event handler was not called'); - } + this.runTask(() => { + component.set('acceptedKeys', ''); + }); - ['@test should be able to use action more than once for the same event within a view']() { - let editHandlerWasCalled = false; - let deleteHandlerWasCalled = false; - let originalHandlerWasCalled = false; - let component; - - let ExampleComponent = Component.extend({ - init() { - this._super(...arguments); - component = this; - }, - actions: { - edit() { editHandlerWasCalled = true; }, - 'delete'() { deleteHandlerWasCalled = true; } - }, - click() { originalHandlerWasCalled = true; } - }); - - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: 'editdelete' - }); - - this.render('{{example-component}}'); - - this.runTask(() => { - this.$('#edit').click(); - }); - - this.assert.equal(editHandlerWasCalled, true, 'the edit action was called'); - this.assert.equal(deleteHandlerWasCalled, false, 'the delete action was not called'); - this.assert.equal(originalHandlerWasCalled, true, 'the click handler was called (due to bubbling)'); - - editHandlerWasCalled = deleteHandlerWasCalled = originalHandlerWasCalled = false; - - this.runTask(() => { - this.$('#delete').click(); - }); - - this.assert.equal(editHandlerWasCalled, false, 'the edit action was not called'); - this.assert.equal(deleteHandlerWasCalled, true, 'the delete action was called'); - this.assert.equal(originalHandlerWasCalled, true, 'the click handler was called (due to bubbling)'); - - editHandlerWasCalled = deleteHandlerWasCalled = originalHandlerWasCalled = false; - - this.runTask(() => { - this.wrap(component.element).click(); - }); - - this.assert.equal(editHandlerWasCalled, false, 'the edit action was not called'); - this.assert.equal(deleteHandlerWasCalled, false, 'the delete action was not called'); - this.assert.equal(originalHandlerWasCalled, true, 'the click handler was called'); - } + this.runTask(() => { + this.$('div[data-ember-action]').click(); + }); - ['@test the event should not bubble if `bubbles=false` is passed']() { - let editHandlerWasCalled = false; - let deleteHandlerWasCalled = false; - let originalHandlerWasCalled = false; - let component; - - let ExampleComponent = Component.extend({ - init() { - this._super(...arguments); - component = this; - }, - actions: { - edit() { editHandlerWasCalled = true; }, - 'delete'() { deleteHandlerWasCalled = true; } - }, - click() { originalHandlerWasCalled = true; } - }); - - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: 'editdelete' - }); - - this.render('{{example-component}}'); - - this.runTask(() => { - this.$('#edit').click(); - }); - - this.assert.equal(editHandlerWasCalled, true, 'the edit action was called'); - this.assert.equal(deleteHandlerWasCalled, false, 'the delete action was not called'); - this.assert.equal(originalHandlerWasCalled, false, 'the click handler was not called'); - - editHandlerWasCalled = deleteHandlerWasCalled = originalHandlerWasCalled = false; - - this.runTask(() => { - this.$('#delete').click(); - }); - - this.assert.equal(editHandlerWasCalled, false, 'the edit action was not called'); - this.assert.equal(deleteHandlerWasCalled, true, 'the delete action was called'); - this.assert.equal(originalHandlerWasCalled, false, 'the click handler was not called'); - - editHandlerWasCalled = deleteHandlerWasCalled = originalHandlerWasCalled = false; - - this.runTask(() => { - this.wrap(component.element).click(); - }); - - this.assert.equal(editHandlerWasCalled, false, 'the edit action was not called'); - this.assert.equal(deleteHandlerWasCalled, false, 'the delete action was not called'); - this.assert.equal(originalHandlerWasCalled, true, 'the click handler was called'); - } + this.assert.equal( + editHandlerWasCalled, + false, + 'the event handler was not called' + ); + } - ['@test the event should not bubble if `bubbles=false` is passed bound']() { - let editHandlerWasCalled = false; - let deleteHandlerWasCalled = false; - let originalHandlerWasCalled = false; - let component; - - let ExampleComponent = Component.extend({ - init() { - this._super(...arguments); - component = this; - }, - isFalse: false, - actions: { - edit() { editHandlerWasCalled = true; }, - 'delete'() { deleteHandlerWasCalled = true; } - }, - click() { originalHandlerWasCalled = true; } - }); - - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: 'editdelete' - }); - - this.render('{{example-component}}'); - - this.runTask(() => { - this.$('#edit').click(); - }); - - this.assert.equal(editHandlerWasCalled, true, 'the edit action was called'); - this.assert.equal(deleteHandlerWasCalled, false, 'the delete action was not called'); - this.assert.equal(originalHandlerWasCalled, false, 'the click handler was not called'); - - editHandlerWasCalled = deleteHandlerWasCalled = originalHandlerWasCalled = false; - - this.runTask(() => { - this.$('#delete').click(); - }); - - this.assert.equal(editHandlerWasCalled, false, 'the edit action was not called'); - this.assert.equal(deleteHandlerWasCalled, true, 'the delete action was called'); - this.assert.equal(originalHandlerWasCalled, false, 'the click handler was not called'); - - editHandlerWasCalled = deleteHandlerWasCalled = originalHandlerWasCalled = false; - - this.runTask(() => { - this.wrap(component.element).click(); - }); - - this.assert.equal(editHandlerWasCalled, false, 'the edit action was not called'); - this.assert.equal(deleteHandlerWasCalled, false, 'the delete action was not called'); - this.assert.equal(originalHandlerWasCalled, true, 'the click handler was called'); - } + ['@test should be able to use action more than once for the same event within a view']() { + let editHandlerWasCalled = false; + let deleteHandlerWasCalled = false; + let originalHandlerWasCalled = false; + let component; - ['@test the bubbling depends on the bound parameter']() { - let editHandlerWasCalled = false; - let originalHandlerWasCalled = false; - let component; - - let ExampleComponent = Component.extend({ - init() { - this._super(...arguments); - component = this; - }, - shouldBubble: false, - actions: { - edit() { editHandlerWasCalled = true; } - }, - click() { originalHandlerWasCalled = true; } - }); - - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: 'edit' - }); - - this.render('{{example-component}}'); - - this.runTask(() => { - this.$('#edit').click(); - }); - - this.assert.equal(editHandlerWasCalled, true, 'the edit action was called'); - this.assert.equal(originalHandlerWasCalled, false, 'the click handler was not called'); - - editHandlerWasCalled = originalHandlerWasCalled = false; - - this.runTask(() => { - component.set('shouldBubble', true); - }); - - this.runTask(() => { - this.$('#edit').click(); - }); - - this.assert.equal(editHandlerWasCalled, true, 'the edit action was called'); - this.assert.equal(originalHandlerWasCalled, true, 'the click handler was called'); - } + let ExampleComponent = Component.extend({ + init() { + this._super(...arguments); + component = this; + }, + actions: { + edit() { + editHandlerWasCalled = true; + }, + delete() { + deleteHandlerWasCalled = true; + } + }, + click() { + originalHandlerWasCalled = true; + } + }); - ['@test it should work properly in an #each block']() { - let editHandlerWasCalled = false; + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: + 'editdelete' + }); - let ExampleComponent = Component.extend({ - items: emberA([1, 2, 3, 4]), - actions: { - edit() { editHandlerWasCalled = true; } - } - }); + this.render('{{example-component}}'); - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: '{{#each items as |item|}}click me{{/each}}' - }); + this.runTask(() => { + this.$('#edit').click(); + }); - this.render('{{example-component}}'); + this.assert.equal( + editHandlerWasCalled, + true, + 'the edit action was called' + ); + this.assert.equal( + deleteHandlerWasCalled, + false, + 'the delete action was not called' + ); + this.assert.equal( + originalHandlerWasCalled, + true, + 'the click handler was called (due to bubbling)' + ); + + editHandlerWasCalled = deleteHandlerWasCalled = originalHandlerWasCalled = false; - this.runTask(() => { - this.$('a').click(); - }); + this.runTask(() => { + this.$('#delete').click(); + }); - this.assert.equal(editHandlerWasCalled, true, 'the event handler was called'); - } + this.assert.equal( + editHandlerWasCalled, + false, + 'the edit action was not called' + ); + this.assert.equal( + deleteHandlerWasCalled, + true, + 'the delete action was called' + ); + this.assert.equal( + originalHandlerWasCalled, + true, + 'the click handler was called (due to bubbling)' + ); + + editHandlerWasCalled = deleteHandlerWasCalled = originalHandlerWasCalled = false; - ['@test it should work properly in a {{#with foo as |bar|}} block']() { - let editHandlerWasCalled = false; + this.runTask(() => { + this.wrap(component.element).click(); + }); - let ExampleComponent = Component.extend({ - something: { ohai: 'there' }, - actions: { - edit() { editHandlerWasCalled = true; } - } - }); + this.assert.equal( + editHandlerWasCalled, + false, + 'the edit action was not called' + ); + this.assert.equal( + deleteHandlerWasCalled, + false, + 'the delete action was not called' + ); + this.assert.equal( + originalHandlerWasCalled, + true, + 'the click handler was called' + ); + } - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: '{{#with something as |somethingElse|}}click me{{/with}}' - }); + ['@test the event should not bubble if `bubbles=false` is passed']() { + let editHandlerWasCalled = false; + let deleteHandlerWasCalled = false; + let originalHandlerWasCalled = false; + let component; - this.render('{{example-component}}'); + let ExampleComponent = Component.extend({ + init() { + this._super(...arguments); + component = this; + }, + actions: { + edit() { + editHandlerWasCalled = true; + }, + delete() { + deleteHandlerWasCalled = true; + } + }, + click() { + originalHandlerWasCalled = true; + } + }); - this.runTask(() => { - this.$('a').click(); - }); + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: + 'editdelete' + }); - this.assert.equal(editHandlerWasCalled, true, 'the event handler was called'); - } + this.render('{{example-component}}'); - ['@test it should unregister event handlers when an element action is removed'](assert) { - let ExampleComponent = Component.extend({ - actions: { - edit() { } - } - }); + this.runTask(() => { + this.$('#edit').click(); + }); - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: '{{#if isActive}}click me{{/if}}' - }); + this.assert.equal( + editHandlerWasCalled, + true, + 'the edit action was called' + ); + this.assert.equal( + deleteHandlerWasCalled, + false, + 'the delete action was not called' + ); + this.assert.equal( + originalHandlerWasCalled, + false, + 'the click handler was not called' + ); + + editHandlerWasCalled = deleteHandlerWasCalled = originalHandlerWasCalled = false; - this.render('{{example-component isActive=isActive}}', { isActive: true }); + this.runTask(() => { + this.$('#delete').click(); + }); - assert.equal(this.$('a[data-ember-action]').length, 1, 'The element is rendered'); + this.assert.equal( + editHandlerWasCalled, + false, + 'the edit action was not called' + ); + this.assert.equal( + deleteHandlerWasCalled, + true, + 'the delete action was called' + ); + this.assert.equal( + originalHandlerWasCalled, + false, + 'the click handler was not called' + ); + + editHandlerWasCalled = deleteHandlerWasCalled = originalHandlerWasCalled = false; - let actionId; + this.runTask(() => { + this.wrap(component.element).click(); + }); - actionId = getActionIds(this.$('a[data-ember-action]')[0])[0]; + this.assert.equal( + editHandlerWasCalled, + false, + 'the edit action was not called' + ); + this.assert.equal( + deleteHandlerWasCalled, + false, + 'the delete action was not called' + ); + this.assert.equal( + originalHandlerWasCalled, + true, + 'the click handler was called' + ); + } - assert.ok(ActionManager.registeredActions[actionId], 'An action is registered'); + ['@test the event should not bubble if `bubbles=false` is passed bound']() { + let editHandlerWasCalled = false; + let deleteHandlerWasCalled = false; + let originalHandlerWasCalled = false; + let component; - this.runTask(() => this.rerender()); + let ExampleComponent = Component.extend({ + init() { + this._super(...arguments); + component = this; + }, + isFalse: false, + actions: { + edit() { + editHandlerWasCalled = true; + }, + delete() { + deleteHandlerWasCalled = true; + } + }, + click() { + originalHandlerWasCalled = true; + } + }); - assert.equal(this.$('a[data-ember-action]').length, 1, 'The element is still present'); + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: + 'editdelete' + }); - assert.ok(ActionManager.registeredActions[actionId], 'The action is still registered'); + this.render('{{example-component}}'); - this.runTask(() => set(this.context, 'isActive', false)); + this.runTask(() => { + this.$('#edit').click(); + }); - assert.strictEqual(this.$('a[data-ember-action]').length, 0, 'The element is removed'); + this.assert.equal( + editHandlerWasCalled, + true, + 'the edit action was called' + ); + this.assert.equal( + deleteHandlerWasCalled, + false, + 'the delete action was not called' + ); + this.assert.equal( + originalHandlerWasCalled, + false, + 'the click handler was not called' + ); + + editHandlerWasCalled = deleteHandlerWasCalled = originalHandlerWasCalled = false; - assert.ok(!ActionManager.registeredActions[actionId], 'The action is unregistered'); + this.runTask(() => { + this.$('#delete').click(); + }); - this.runTask(() => set(this.context, 'isActive', true)); + this.assert.equal( + editHandlerWasCalled, + false, + 'the edit action was not called' + ); + this.assert.equal( + deleteHandlerWasCalled, + true, + 'the delete action was called' + ); + this.assert.equal( + originalHandlerWasCalled, + false, + 'the click handler was not called' + ); + + editHandlerWasCalled = deleteHandlerWasCalled = originalHandlerWasCalled = false; - assert.equal(this.$('a[data-ember-action]').length, 1, 'The element is rendered'); + this.runTask(() => { + this.wrap(component.element).click(); + }); - actionId = getActionIds(this.$('a[data-ember-action]')[0])[0]; + this.assert.equal( + editHandlerWasCalled, + false, + 'the edit action was not called' + ); + this.assert.equal( + deleteHandlerWasCalled, + false, + 'the delete action was not called' + ); + this.assert.equal( + originalHandlerWasCalled, + true, + 'the click handler was called' + ); + } - assert.ok(ActionManager.registeredActions[actionId], 'A new action is registered'); - } + ['@test the bubbling depends on the bound parameter']() { + let editHandlerWasCalled = false; + let originalHandlerWasCalled = false; + let component; - ['@test it should capture events from child elements and allow them to trigger the action']() { - let editHandlerWasCalled = false; + let ExampleComponent = Component.extend({ + init() { + this._super(...arguments); + component = this; + }, + shouldBubble: false, + actions: { + edit() { + editHandlerWasCalled = true; + } + }, + click() { + originalHandlerWasCalled = true; + } + }); - let ExampleComponent = Component.extend({ - actions: { - edit() { editHandlerWasCalled = true; } - } - }); + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: + 'edit' + }); - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: '
' - }); + this.render('{{example-component}}'); - this.render('{{example-component}}'); + this.runTask(() => { + this.$('#edit').click(); + }); - this.runTask(() => { - this.$('button').click(); - }); + this.assert.equal( + editHandlerWasCalled, + true, + 'the edit action was called' + ); + this.assert.equal( + originalHandlerWasCalled, + false, + 'the click handler was not called' + ); - this.assert.ok(editHandlerWasCalled, 'event on a child target triggered the action of its parent'); - } + editHandlerWasCalled = originalHandlerWasCalled = false; - ['@test it should allow bubbling of events from action helper to original parent event']() { - let editHandlerWasCalled = false; - let originalHandlerWasCalled = false; + this.runTask(() => { + component.set('shouldBubble', true); + }); - let ExampleComponent = Component.extend({ - actions: { - edit() { editHandlerWasCalled = true; } - }, - click() { originalHandlerWasCalled = true; } - }); + this.runTask(() => { + this.$('#edit').click(); + }); - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: 'click me' - }); + this.assert.equal( + editHandlerWasCalled, + true, + 'the edit action was called' + ); + this.assert.equal( + originalHandlerWasCalled, + true, + 'the click handler was called' + ); + } - this.render('{{example-component}}'); + ['@test it should work properly in an #each block']() { + let editHandlerWasCalled = false; - this.runTask(() => { - this.$('a').click(); - }); + let ExampleComponent = Component.extend({ + items: emberA([1, 2, 3, 4]), + actions: { + edit() { + editHandlerWasCalled = true; + } + } + }); - this.assert.ok(editHandlerWasCalled && originalHandlerWasCalled, 'both event handlers were called'); - } + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: + '{{#each items as |item|}}click me{{/each}}' + }); - ['@test it should not bubble an event from action helper to original parent event if `bubbles=false` is passed']() { - let editHandlerWasCalled = false; - let originalHandlerWasCalled = false; + this.render('{{example-component}}'); - let ExampleComponent = Component.extend({ - actions: { - edit() { editHandlerWasCalled = true; } - }, - click() { originalHandlerWasCalled = true; } - }); + this.runTask(() => { + this.$('a').click(); + }); - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: 'click me' - }); + this.assert.equal( + editHandlerWasCalled, + true, + 'the event handler was called' + ); + } - this.render('{{example-component}}'); + ['@test it should work properly in a {{#with foo as |bar|}} block']() { + let editHandlerWasCalled = false; - this.runTask(() => { - this.$('a').click(); - }); + let ExampleComponent = Component.extend({ + something: { ohai: 'there' }, + actions: { + edit() { + editHandlerWasCalled = true; + } + } + }); - this.assert.ok(editHandlerWasCalled, 'the child event handler was called'); - this.assert.notOk(originalHandlerWasCalled, 'the parent handler was not called'); - } + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: + '{{#with something as |somethingElse|}}click me{{/with}}' + }); - ['@test it should allow "send" as the action name (#594)']() { - let sendHandlerWasCalled = false; + this.render('{{example-component}}'); - let ExampleComponent = Component.extend({ - actions: { - send() { sendHandlerWasCalled = true; } - } - }); + this.runTask(() => { + this.$('a').click(); + }); - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: 'click me' - }); + this.assert.equal( + editHandlerWasCalled, + true, + 'the event handler was called' + ); + } - this.render('{{example-component}}'); + ['@test it should unregister event handlers when an element action is removed']( + assert + ) { + let ExampleComponent = Component.extend({ + actions: { + edit() {} + } + }); + + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: + '{{#if isActive}}click me{{/if}}' + }); - this.runTask(() => { - this.$('a').click(); - }); + this.render('{{example-component isActive=isActive}}', { + isActive: true + }); - this.assert.ok(sendHandlerWasCalled, 'the event handler was called'); - } + assert.equal( + this.$('a[data-ember-action]').length, + 1, + 'The element is rendered' + ); + + let actionId; + + actionId = getActionIds(this.$('a[data-ember-action]')[0])[0]; + + assert.ok( + ActionManager.registeredActions[actionId], + 'An action is registered' + ); + + this.runTask(() => this.rerender()); + + assert.equal( + this.$('a[data-ember-action]').length, + 1, + 'The element is still present' + ); + + assert.ok( + ActionManager.registeredActions[actionId], + 'The action is still registered' + ); + + this.runTask(() => set(this.context, 'isActive', false)); + + assert.strictEqual( + this.$('a[data-ember-action]').length, + 0, + 'The element is removed' + ); + + assert.ok( + !ActionManager.registeredActions[actionId], + 'The action is unregistered' + ); - ['@test it should send the view, event, and current context to the action']() { - let passedTarget; - let passedContext; - let targetThis; - - let TargetComponent = Component.extend({ - init() { - this._super(...arguments); - targetThis = this; - }, - actions: { - edit(context) { - passedTarget = this === targetThis; - passedContext = context; + this.runTask(() => set(this.context, 'isActive', true)); + + assert.equal( + this.$('a[data-ember-action]').length, + 1, + 'The element is rendered' + ); + + actionId = getActionIds(this.$('a[data-ember-action]')[0])[0]; + + assert.ok( + ActionManager.registeredActions[actionId], + 'A new action is registered' + ); + } + + ['@test it should capture events from child elements and allow them to trigger the action']() { + let editHandlerWasCalled = false; + + let ExampleComponent = Component.extend({ + actions: { + edit() { + editHandlerWasCalled = true; + } } - } - }); + }); - let aContext; + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: '
' + }); - let ExampleComponent = Component.extend({ - init() { - this._super(...arguments); - aContext = this; - } - }); + this.render('{{example-component}}'); - this.registerComponent('target-component', { - ComponentClass: TargetComponent, - template: '{{yield this}}' - }); + this.runTask(() => { + this.$('button').click(); + }); - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: strip` - {{#target-component as |aTarget|}} - click me - {{/target-component}} - ` - }); + this.assert.ok( + editHandlerWasCalled, + 'event on a child target triggered the action of its parent' + ); + } - this.render('{{example-component}}'); + ['@test it should allow bubbling of events from action helper to original parent event']() { + let editHandlerWasCalled = false; + let originalHandlerWasCalled = false; - this.runTask(() => { - this.$('#edit').click(); - }); + let ExampleComponent = Component.extend({ + actions: { + edit() { + editHandlerWasCalled = true; + } + }, + click() { + originalHandlerWasCalled = true; + } + }); - this.assert.ok(passedTarget, 'the action is called with the target as this'); - this.assert.strictEqual(passedContext, aContext, 'the parameter is passed along'); - } + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: 'click me' + }); - ['@test it should only trigger actions for the event they were registered on']() { - let editHandlerWasCalled = false; + this.render('{{example-component}}'); - let ExampleComponent = Component.extend({ - actions: { - edit() { editHandlerWasCalled = true; } - } - }); + this.runTask(() => { + this.$('a').click(); + }); - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: 'click me' - }); + this.assert.ok( + editHandlerWasCalled && originalHandlerWasCalled, + 'both event handlers were called' + ); + } - this.render('{{example-component}}'); + ['@test it should not bubble an event from action helper to original parent event if `bubbles=false` is passed']() { + let editHandlerWasCalled = false; + let originalHandlerWasCalled = false; - this.runTask(() => { - this.$('a').click(); - }); + let ExampleComponent = Component.extend({ + actions: { + edit() { + editHandlerWasCalled = true; + } + }, + click() { + originalHandlerWasCalled = true; + } + }); - this.assert.ok(editHandlerWasCalled, 'the event handler was called on click'); + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: 'click me' + }); - editHandlerWasCalled = false; + this.render('{{example-component}}'); - this.runTask(() => { - this.$('a').trigger('mouseover'); - }); + this.runTask(() => { + this.$('a').click(); + }); - this.assert.notOk(editHandlerWasCalled, 'the event handler was not called on mouseover'); - } + this.assert.ok( + editHandlerWasCalled, + 'the child event handler was called' + ); + this.assert.notOk( + originalHandlerWasCalled, + 'the parent handler was not called' + ); + } - ['@test it should allow multiple contexts to be specified']() { - let passedContexts; - let models = [EmberObject.create(), EmberObject.create()]; + ['@test it should allow "send" as the action name (#594)']() { + let sendHandlerWasCalled = false; - let ExampleComponent = Component.extend({ - modelA: models[0], - modelB: models[1], - actions: { - edit(...args) { - passedContexts = args; + let ExampleComponent = Component.extend({ + actions: { + send() { + sendHandlerWasCalled = true; + } } - } - }); + }); - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: '' - }); + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: 'click me' + }); - this.render('{{example-component}}'); + this.render('{{example-component}}'); - this.runTask(() => { - this.$('button').click(); - }); + this.runTask(() => { + this.$('a').click(); + }); - this.assert.deepEqual(passedContexts, models, 'the action was called with the passed contexts'); - } + this.assert.ok(sendHandlerWasCalled, 'the event handler was called'); + } - ['@test it should allow multiple contexts to be specified mixed with string args']() { - let passedContexts; - let model = EmberObject.create(); + ['@test it should send the view, event, and current context to the action']() { + let passedTarget; + let passedContext; + let targetThis; - let ExampleComponent = Component.extend({ - model: model, - actions: { - edit(...args) { - passedContexts = args; + let TargetComponent = Component.extend({ + init() { + this._super(...arguments); + targetThis = this; + }, + actions: { + edit(context) { + passedTarget = this === targetThis; + passedContext = context; + } } - } - }); + }); + + let aContext; - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: '' - }); + let ExampleComponent = Component.extend({ + init() { + this._super(...arguments); + aContext = this; + } + }); - this.render('{{example-component}}'); + this.registerComponent('target-component', { + ComponentClass: TargetComponent, + template: '{{yield this}}' + }); - this.runTask(() => { - this.$('button').click(); - }); + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: strip` + {{#target-component as |aTarget|}} + click me + {{/target-component}} + ` + }); - this.assert.deepEqual(passedContexts, ['herp', model], 'the action was called with the passed contexts'); - } + this.render('{{example-component}}'); - ['@test it should not trigger action with special clicks']() { - let showCalled = false; - let component; - - let ExampleComponent = Component.extend({ - init() { - this._super(...arguments); - component = this; - }, - actions: { - show() { - showCalled = true; + this.runTask(() => { + this.$('#edit').click(); + }); + + this.assert.ok( + passedTarget, + 'the action is called with the target as this' + ); + this.assert.strictEqual( + passedContext, + aContext, + 'the parameter is passed along' + ); + } + + ['@test it should only trigger actions for the event they were registered on']() { + let editHandlerWasCalled = false; + + let ExampleComponent = Component.extend({ + actions: { + edit() { + editHandlerWasCalled = true; + } } - } - }); + }); - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: '' - }); + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: 'click me' + }); + + this.render('{{example-component}}'); - this.render('{{example-component}}'); + this.runTask(() => { + this.$('a').click(); + }); + + this.assert.ok( + editHandlerWasCalled, + 'the event handler was called on click' + ); - let assert = this.assert; + editHandlerWasCalled = false; - let checkClick = (prop, value, expected) => { - showCalled = false; - let event = this.wrap(component.element).findAll('button').trigger('click', { [prop]: value })[0]; - if (expected) { - assert.ok(showCalled, `should call action with ${prop}:${value}`); + this.runTask(() => { + this.$('a').trigger('mouseover'); + }); - // IE11 does not allow simulated events to have a valid `defaultPrevented` - if (!isIE11) { - assert.ok(event.defaultPrevented, 'should prevent default'); + this.assert.notOk( + editHandlerWasCalled, + 'the event handler was not called on mouseover' + ); + } + + ['@test it should allow multiple contexts to be specified']() { + let passedContexts; + let models = [EmberObject.create(), EmberObject.create()]; + + let ExampleComponent = Component.extend({ + modelA: models[0], + modelB: models[1], + actions: { + edit(...args) { + passedContexts = args; + } } - } else { - assert.notOk(showCalled, `should not call action with ${prop}:${value}`); - assert.notOk(event.defaultPrevented, 'should not prevent default'); - } - }; - - checkClick('ctrlKey', true, false); - checkClick('altKey', true, false); - checkClick('metaKey', true, false); - checkClick('shiftKey', true, false); - - checkClick('button', 0, true); - checkClick('button', 1, false); - checkClick('button', 2, false); - checkClick('button', 3, false); - checkClick('button', 4, false); - } + }); + + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: '' + }); + + this.render('{{example-component}}'); + + this.runTask(() => { + this.$('button').click(); + }); + + this.assert.deepEqual( + passedContexts, + models, + 'the action was called with the passed contexts' + ); + } - ['@test it can trigger actions for keyboard events']() { - let showCalled = false; + ['@test it should allow multiple contexts to be specified mixed with string args']() { + let passedContexts; + let model = EmberObject.create(); - let ExampleComponent = Component.extend({ - actions: { - show() { - showCalled = true; + let ExampleComponent = Component.extend({ + model: model, + actions: { + edit(...args) { + passedContexts = args; + } } - } - }); + }); - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: '' - }); + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: '' + }); - this.render('{{example-component}}'); + this.render('{{example-component}}'); - this.runTask(() => { - this.$('input').trigger('keyup', { char: 'a', which: 65 }); - }); + this.runTask(() => { + this.$('button').click(); + }); - this.assert.ok(showCalled, 'the action was called with keyup'); - } + this.assert.deepEqual( + passedContexts, + ['herp', model], + 'the action was called with the passed contexts' + ); + } - ['@test a quoteless parameter should allow dynamic lookup of the actionName']() { - let lastAction; - let actionOrder = []; - let component; - - let ExampleComponent = Component.extend({ - init() { - this._super(...arguments); - component = this; - }, - hookMeUp: 'rock', - actions: { - rock() { - lastAction = 'rock'; - actionOrder.push('rock'); - }, - paper() { - lastAction = 'paper'; - actionOrder.push('paper'); + ['@test it should not trigger action with special clicks']() { + let showCalled = false; + let component; + + let ExampleComponent = Component.extend({ + init() { + this._super(...arguments); + component = this; }, - scissors() { - lastAction = 'scissors'; - actionOrder.push('scissors'); + actions: { + show() { + showCalled = true; + } } - } - }); + }); - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: 'Whistle tips go woop woooop' - }); + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: '' + }); + + this.render('{{example-component}}'); - this.render('{{example-component}}'); + let assert = this.assert; + + let checkClick = (prop, value, expected) => { + showCalled = false; + let event = this.wrap(component.element) + .findAll('button') + .trigger('click', { [prop]: value })[0]; + if (expected) { + assert.ok(showCalled, `should call action with ${prop}:${value}`); + + // IE11 does not allow simulated events to have a valid `defaultPrevented` + if (!isIE11) { + assert.ok(event.defaultPrevented, 'should prevent default'); + } + } else { + assert.notOk( + showCalled, + `should not call action with ${prop}:${value}` + ); + assert.notOk(event.defaultPrevented, 'should not prevent default'); + } + }; + + checkClick('ctrlKey', true, false); + checkClick('altKey', true, false); + checkClick('metaKey', true, false); + checkClick('shiftKey', true, false); + + checkClick('button', 0, true); + checkClick('button', 1, false); + checkClick('button', 2, false); + checkClick('button', 3, false); + checkClick('button', 4, false); + } - let test = this; + ['@test it can trigger actions for keyboard events']() { + let showCalled = false; - let testBoundAction = (propertyValue) => { - test.runTask(() => { - component.set('hookMeUp', propertyValue); + let ExampleComponent = Component.extend({ + actions: { + show() { + showCalled = true; + } + } }); - test.runTask(() => { - this.wrap(component.element).findAll('#bound-param').click(); + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: '' }); - test.assert.ok(lastAction, propertyValue, `lastAction set to ${propertyValue}`); - }; + this.render('{{example-component}}'); + + this.runTask(() => { + this.$('input').trigger('keyup', { char: 'a', which: 65 }); + }); - testBoundAction('rock'); - testBoundAction('paper'); - testBoundAction('scissors'); + this.assert.ok(showCalled, 'the action was called with keyup'); + } - this.assert.deepEqual(actionOrder, ['rock', 'paper', 'scissors'], 'action name was looked up properly'); - } + ['@test a quoteless parameter should allow dynamic lookup of the actionName']() { + let lastAction; + let actionOrder = []; + let component; - ['@test a quoteless string parameter should resolve actionName, including path']() { - let lastAction; - let actionOrder = []; - let component; - - let ExampleComponent = Component.extend({ - init() { - this._super(...arguments); - component = this; - }, - allactions: emberA([ - { title: 'Rock', name: 'rock' }, - { title: 'Paper', name: 'paper' }, - { title: 'Scissors', name: 'scissors' } - ]), - actions: { - rock() { - lastAction = 'rock'; - actionOrder.push('rock'); - }, - paper() { - lastAction = 'paper'; - actionOrder.push('paper'); + let ExampleComponent = Component.extend({ + init() { + this._super(...arguments); + component = this; }, - scissors() { - lastAction = 'scissors'; - actionOrder.push('scissors'); + hookMeUp: 'rock', + actions: { + rock() { + lastAction = 'rock'; + actionOrder.push('rock'); + }, + paper() { + lastAction = 'paper'; + actionOrder.push('paper'); + }, + scissors() { + lastAction = 'scissors'; + actionOrder.push('scissors'); + } } - } - }); + }); + + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: + 'Whistle tips go woop woooop' + }); - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: '{{#each allactions as |allaction|}}{{allaction.title}}{{/each}}' - }); + this.render('{{example-component}}'); - this.render('{{example-component}}'); + let test = this; + + let testBoundAction = propertyValue => { + test.runTask(() => { + component.set('hookMeUp', propertyValue); + }); + + test.runTask(() => { + this.wrap(component.element) + .findAll('#bound-param') + .click(); + }); + + test.assert.ok( + lastAction, + propertyValue, + `lastAction set to ${propertyValue}` + ); + }; + + testBoundAction('rock'); + testBoundAction('paper'); + testBoundAction('scissors'); + + this.assert.deepEqual( + actionOrder, + ['rock', 'paper', 'scissors'], + 'action name was looked up properly' + ); + } - let test = this; + ['@test a quoteless string parameter should resolve actionName, including path']() { + let lastAction; + let actionOrder = []; + let component; - let testBoundAction = (propertyValue) => { - test.runTask(() => { - this.wrap(component.element).findAll(`#${propertyValue}`).click(); + let ExampleComponent = Component.extend({ + init() { + this._super(...arguments); + component = this; + }, + allactions: emberA([ + { title: 'Rock', name: 'rock' }, + { title: 'Paper', name: 'paper' }, + { title: 'Scissors', name: 'scissors' } + ]), + actions: { + rock() { + lastAction = 'rock'; + actionOrder.push('rock'); + }, + paper() { + lastAction = 'paper'; + actionOrder.push('paper'); + }, + scissors() { + lastAction = 'scissors'; + actionOrder.push('scissors'); + } + } }); - test.assert.ok(lastAction, propertyValue, `lastAction set to ${propertyValue}`); - }; + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: + '{{#each allactions as |allaction|}}{{allaction.title}}{{/each}}' + }); - testBoundAction('rock'); - testBoundAction('paper'); - testBoundAction('scissors'); + this.render('{{example-component}}'); - this.assert.deepEqual(actionOrder, ['rock', 'paper', 'scissors'], 'action name was looked up properly'); - } + let test = this; + + let testBoundAction = propertyValue => { + test.runTask(() => { + this.wrap(component.element) + .findAll(`#${propertyValue}`) + .click(); + }); + + test.assert.ok( + lastAction, + propertyValue, + `lastAction set to ${propertyValue}` + ); + }; + + testBoundAction('rock'); + testBoundAction('paper'); + testBoundAction('scissors'); + + this.assert.deepEqual( + actionOrder, + ['rock', 'paper', 'scissors'], + 'action name was looked up properly' + ); + } - ['@test a quoteless function parameter should be called, including arguments']() { - let submitCalled = false; - let incomingArg; + ['@test a quoteless function parameter should be called, including arguments']() { + let submitCalled = false; + let incomingArg; - let arg = 'rough ray'; + let arg = 'rough ray'; - let ExampleComponent = Component.extend({ - submit(actualArg) { - incomingArg = actualArg; - submitCalled = true; - } - }); + let ExampleComponent = Component.extend({ + submit(actualArg) { + incomingArg = actualArg; + submitCalled = true; + } + }); - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: `Hi` - }); + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: `Hi` + }); - this.render('{{example-component}}'); + this.render('{{example-component}}'); - this.runTask(() => { - this.$('a').click(); - }); + this.runTask(() => { + this.$('a').click(); + }); - this.assert.ok(submitCalled, 'submit function called'); - this.assert.equal(incomingArg, arg, 'argument passed'); - } + this.assert.ok(submitCalled, 'submit function called'); + this.assert.equal(incomingArg, arg, 'argument passed'); + } - ['@test a quoteless parameter that does not resolve to a value asserts']() { - let ExampleComponent = Component.extend({ - actions: { - ohNoeNotValid() {} - } - }); + ['@test a quoteless parameter that does not resolve to a value asserts']() { + let ExampleComponent = Component.extend({ + actions: { + ohNoeNotValid() {} + } + }); - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: 'Hi' - }); + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: 'Hi' + }); - expectAssertion(() => { - this.render('{{example-component}}'); - }, 'You specified a quoteless path, `ohNoeNotValid`, to the {{action}} helper ' + - 'which did not resolve to an action name (a string). ' + - 'Perhaps you meant to use a quoted actionName? (e.g. {{action "ohNoeNotValid"}}).'); - } + expectAssertion(() => { + this.render('{{example-component}}'); + }, 'You specified a quoteless path, `ohNoeNotValid`, to the {{action}} helper ' + 'which did not resolve to an action name (a string). ' + 'Perhaps you meant to use a quoted actionName? (e.g. {{action "ohNoeNotValid"}}).'); + } - ['@test allows multiple actions on a single element']() { - let clickActionWasCalled = false; - let doubleClickActionWasCalled = false; + ['@test allows multiple actions on a single element']() { + let clickActionWasCalled = false; + let doubleClickActionWasCalled = false; - let ExampleComponent = Component.extend({ - actions: { - clicked() { - clickActionWasCalled = true; - }, - doubleClicked() { - doubleClickActionWasCalled = true; + let ExampleComponent = Component.extend({ + actions: { + clicked() { + clickActionWasCalled = true; + }, + doubleClicked() { + doubleClickActionWasCalled = true; + } } - } - }); + }); - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: strip` + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: strip` click me` - }); + }); - this.render('{{example-component}}'); + this.render('{{example-component}}'); - this.runTask(() => { - this.$('a').trigger('click'); - }); + this.runTask(() => { + this.$('a').trigger('click'); + }); - this.assert.ok(clickActionWasCalled, 'the clicked action was called'); + this.assert.ok(clickActionWasCalled, 'the clicked action was called'); - this.runTask(() => { - this.$('a').trigger('dblclick'); - }); + this.runTask(() => { + this.$('a').trigger('dblclick'); + }); - this.assert.ok(doubleClickActionWasCalled, 'the doubleClicked action was called'); - } + this.assert.ok( + doubleClickActionWasCalled, + 'the doubleClicked action was called' + ); + } - ['@test it should respect preventDefault option if provided']() { - let ExampleComponent = Component.extend({ - actions: { - show() { + ['@test it should respect preventDefault option if provided']() { + let ExampleComponent = Component.extend({ + actions: { + show() {} } - } - }); + }); + + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: 'Hi' + }); - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: 'Hi' - }); + this.render('{{example-component}}'); - this.render('{{example-component}}'); + let event; - let event; + this.runTask(() => { + event = this.$('a').click()[0]; + }); - this.runTask(() => { - event = this.$('a').click()[0]; - }); + this.assert.equal( + event.defaultPrevented, + false, + 'should not preventDefault' + ); + } - this.assert.equal(event.defaultPrevented, false, 'should not preventDefault'); - } + ['@test it should respect preventDefault option if provided bound']() { + let component; - ['@test it should respect preventDefault option if provided bound']() { - let component; - - let ExampleComponent = Component.extend({ - shouldPreventDefault: false, - init() { - this._super(...arguments); - component = this; - }, - actions: { - show() { + let ExampleComponent = Component.extend({ + shouldPreventDefault: false, + init() { + this._super(...arguments); + component = this; + }, + actions: { + show() {} } - } - }); + }); - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: 'Hi' - }); + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: + 'Hi' + }); - this.render('{{example-component}}'); + this.render('{{example-component}}'); - let event; + let event; - this.runTask(() => { - event = this.$('a').trigger(event)[0]; - }); + this.runTask(() => { + event = this.$('a').trigger(event)[0]; + }); - this.assert.equal(event.defaultPrevented, false, 'should not preventDefault'); + this.assert.equal( + event.defaultPrevented, + false, + 'should not preventDefault' + ); - this.runTask(() => { - component.set('shouldPreventDefault', true); - event = this.$('a').trigger('click')[0]; - }); + this.runTask(() => { + component.set('shouldPreventDefault', true); + event = this.$('a').trigger('click')[0]; + }); - // IE11 does not allow simulated events to have a valid `defaultPrevented` - if (!isIE11) { - this.assert.equal(event.defaultPrevented, true, 'should preventDefault'); + // IE11 does not allow simulated events to have a valid `defaultPrevented` + if (!isIE11) { + this.assert.equal( + event.defaultPrevented, + true, + 'should preventDefault' + ); + } } - } - ['@test it should target the proper component when `action` is in yielded block [GH #12409]']() { - let outerActionCalled = false; - let innerClickCalled = false; + ['@test it should target the proper component when `action` is in yielded block [GH #12409]']() { + let outerActionCalled = false; + let innerClickCalled = false; - let OuterComponent = Component.extend({ - actions: { - hey() { - outerActionCalled = true; + let OuterComponent = Component.extend({ + actions: { + hey() { + outerActionCalled = true; + } } - } - }); + }); - let MiddleComponent = Component.extend({ - }); + let MiddleComponent = Component.extend({}); - let InnerComponent = Component.extend({ - click() { - innerClickCalled = true; - this.sendAction(); - } - }); + let InnerComponent = Component.extend({ + click() { + innerClickCalled = true; + this.sendAction(); + } + }); - this.registerComponent('outer-component', { - ComponentClass: OuterComponent, - template: strip` + this.registerComponent('outer-component', { + ComponentClass: OuterComponent, + template: strip` {{#middle-component}} {{inner-component action="hey"}} {{/middle-component}} ` - }); + }); - this.registerComponent('middle-component', { - ComponentClass: MiddleComponent, - template: '{{yield}}' - }); + this.registerComponent('middle-component', { + ComponentClass: MiddleComponent, + template: '{{yield}}' + }); - this.registerComponent('inner-component', { - ComponentClass: InnerComponent, - template: strip` + this.registerComponent('inner-component', { + ComponentClass: InnerComponent, + template: strip` {{yield}} ` - }); + }); - this.render('{{outer-component}}'); + this.render('{{outer-component}}'); - this.runTask(() => { - this.$('button').click(); - }); + this.runTask(() => { + this.$('button').click(); + }); - this.assert.ok(outerActionCalled, 'the action fired on the proper target'); - this.assert.ok(innerClickCalled, 'the click was triggered'); - } + this.assert.ok( + outerActionCalled, + 'the action fired on the proper target' + ); + this.assert.ok(innerClickCalled, 'the click was triggered'); + } - ['@test element action with (mut undefinedThing) works properly']() { - let component; + ['@test element action with (mut undefinedThing) works properly']() { + let component; - let ExampleComponent = Component.extend({ - label: undefined, - init() { - this._super(...arguments); - component = this; - } - }); + let ExampleComponent = Component.extend({ + label: undefined, + init() { + this._super(...arguments); + component = this; + } + }); - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: '' - }); + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: + '' + }); - this.render('{{example-component}}'); + this.render('{{example-component}}'); - this.assertText('Click me'); + this.assertText('Click me'); - this.assertStableRerender(); + this.assertStableRerender(); - this.runTask(() => { - this.$('button').click(); - }); + this.runTask(() => { + this.$('button').click(); + }); - this.assertText('Clicked!'); + this.assertText('Clicked!'); - this.runTask(() => { - component.set('label', 'Dun clicked'); - }); + this.runTask(() => { + component.set('label', 'Dun clicked'); + }); - this.assertText('Dun clicked'); + this.assertText('Dun clicked'); - this.runTask(() => { - this.$('button').click(); - }); + this.runTask(() => { + this.$('button').click(); + }); - this.assertText('Clicked!'); + this.assertText('Clicked!'); - this.runTask(() => { - component.set('label', undefined); - }); + this.runTask(() => { + component.set('label', undefined); + }); - this.assertText('Click me'); - } + this.assertText('Click me'); + } - ['@test it supports non-registered actions [GH#14888]']() { - this.render(` + ['@test it supports non-registered actions [GH#14888]']() { + this.render( + ` {{#if show}} {{/if}} - `, { show: true }); - - this.assert.equal(this.$('button').text().trim(), 'Show (true)'); - // We need to focus in to simulate an actual click. - this.runTask(() => { - document.getElementById('ddButton').focus(); - document.getElementById('ddButton').click(); - }); - } + `, + { show: true } + ); + + this.assert.equal( + this.$('button') + .text() + .trim(), + 'Show (true)' + ); + // We need to focus in to simulate an actual click. + this.runTask(() => { + document.getElementById('ddButton').focus(); + document.getElementById('ddButton').click(); + }); + } - ['@test action handler that shifts element attributes doesn\'t trigger multiple invocations']() { - let actionCount = 0; - let ExampleComponent = Component.extend({ - selected: false, - actions: { - toggleSelected() { - actionCount++; - this.toggleProperty('selected'); + ["@test action handler that shifts element attributes doesn't trigger multiple invocations"]() { + let actionCount = 0; + let ExampleComponent = Component.extend({ + selected: false, + actions: { + toggleSelected() { + actionCount++; + this.toggleProperty('selected'); + } } - } - }); + }); - this.registerComponent('example-component', { - ComponentClass: ExampleComponent, - template: '' - }); + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: + '' + }); - this.render('{{example-component}}'); + this.render('{{example-component}}'); - this.runTask(() => { - this.$('button').click(); - }); + this.runTask(() => { + this.$('button').click(); + }); - this.assert.equal(actionCount, 1, 'Click action only fired once.'); - this.assert.ok(this.$('button').hasClass('selected'), 'Element with action handler has properly updated it\'s conditional class'); + this.assert.equal(actionCount, 1, 'Click action only fired once.'); + this.assert.ok( + this.$('button').hasClass('selected'), + "Element with action handler has properly updated it's conditional class" + ); - this.runTask(() => { - this.$('button').click(); - }); + this.runTask(() => { + this.$('button').click(); + }); - this.assert.equal(actionCount, 2, 'Second click action only fired once.'); - this.assert.ok(!this.$('button').hasClass('selected'), 'Element with action handler has properly updated it\'s conditional class'); + this.assert.equal(actionCount, 2, 'Second click action only fired once.'); + this.assert.ok( + !this.$('button').hasClass('selected'), + "Element with action handler has properly updated it's conditional class" + ); + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/helpers/get-test.js b/packages/ember-glimmer/tests/integration/helpers/get-test.js index 723cbdeaba5..0ebf4f6a35f 100644 --- a/packages/ember-glimmer/tests/integration/helpers/get-test.js +++ b/packages/ember-glimmer/tests/integration/helpers/get-test.js @@ -2,573 +2,673 @@ import { RenderingTest, moduleFor } from '../../utils/test-case'; import { Component } from '../../utils/helpers'; import { set, get } from 'ember-metal'; -moduleFor('Helpers test: {{get}}', class extends RenderingTest { - - ['@test should be able to get an object value with a static key']() { - this.render(`[{{get colors 'apple'}}] [{{if true (get colors 'apple')}}]`, { - colors: { apple: 'red' } - }); +moduleFor( + 'Helpers test: {{get}}', + class extends RenderingTest { + ['@test should be able to get an object value with a static key']() { + this.render( + `[{{get colors 'apple'}}] [{{if true (get colors 'apple')}}]`, + { + colors: { apple: 'red' } + } + ); - this.assertText('[red] [red]'); + this.assertText('[red] [red]'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('[red] [red]'); + this.assertText('[red] [red]'); - this.runTask(() => set(this.context, 'colors.apple', 'green')); + this.runTask(() => set(this.context, 'colors.apple', 'green')); - this.assertText('[green] [green]'); + this.assertText('[green] [green]'); - this.runTask(() => set(this.context, 'colors', { - apple: 'red' - })); + this.runTask(() => + set(this.context, 'colors', { + apple: 'red' + }) + ); - this.assertText('[red] [red]'); - } + this.assertText('[red] [red]'); + } - ['@test should be able to get an object value with nested static key']() { - this.render(`[{{get colors "apple.gala"}}] [{{if true (get colors "apple.gala")}}]`, { - colors: { - apple: { - gala: 'red and yellow' + ['@test should be able to get an object value with nested static key']() { + this.render( + `[{{get colors "apple.gala"}}] [{{if true (get colors "apple.gala")}}]`, + { + colors: { + apple: { + gala: 'red and yellow' + } + } } - } - }); + ); - this.assertText('[red and yellow] [red and yellow]'); + this.assertText('[red and yellow] [red and yellow]'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('[red and yellow] [red and yellow]'); + this.assertText('[red and yellow] [red and yellow]'); - this.runTask(() => set(this.context, 'colors.apple.gala', 'yellow and red striped')); + this.runTask(() => + set(this.context, 'colors.apple.gala', 'yellow and red striped') + ); - this.assertText('[yellow and red striped] [yellow and red striped]'); + this.assertText('[yellow and red striped] [yellow and red striped]'); - this.runTask(() => set(this.context, 'colors', { apple: { gala: 'red and yellow' } })); + this.runTask(() => + set(this.context, 'colors', { apple: { gala: 'red and yellow' } }) + ); - this.assertText('[red and yellow] [red and yellow]'); - } + this.assertText('[red and yellow] [red and yellow]'); + } - ['@test should be able to get an object value with a number']() { - this.render(`[{{get items 1}}][{{get items 2}}][{{get items 3}}]`, { - indexes: [1, 2, 3], - items: { - 1: 'First', - 2: 'Second', - 3: 'Third' - } - }); + ['@test should be able to get an object value with a number']() { + this.render(`[{{get items 1}}][{{get items 2}}][{{get items 3}}]`, { + indexes: [1, 2, 3], + items: { + 1: 'First', + 2: 'Second', + 3: 'Third' + } + }); - this.assertText('[First][Second][Third]'); + this.assertText('[First][Second][Third]'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('[First][Second][Third]'); + this.assertText('[First][Second][Third]'); - this.runTask(() => set(this.context, 'items.1', 'Qux')); + this.runTask(() => set(this.context, 'items.1', 'Qux')); - this.assertText('[Qux][Second][Third]'); + this.assertText('[Qux][Second][Third]'); - this.runTask(() => set(this.context, 'items', { 1: 'First', 2: 'Second', 3: 'Third' })); + this.runTask(() => + set(this.context, 'items', { 1: 'First', 2: 'Second', 3: 'Third' }) + ); - this.assertText('[First][Second][Third]'); - } + this.assertText('[First][Second][Third]'); + } - ['@test should be able to get an array value with a number']() { - this.render(`[{{get numbers 0}}][{{get numbers 1}}][{{get numbers 2}}]`, { - numbers: [1, 2, 3], - }); + ['@test should be able to get an array value with a number']() { + this.render(`[{{get numbers 0}}][{{get numbers 1}}][{{get numbers 2}}]`, { + numbers: [1, 2, 3] + }); - this.assertText('[1][2][3]'); + this.assertText('[1][2][3]'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('[1][2][3]'); + this.assertText('[1][2][3]'); - this.runTask(() => set(this.context, 'numbers', [3, 2, 1])); + this.runTask(() => set(this.context, 'numbers', [3, 2, 1])); - this.assertText('[3][2][1]'); + this.assertText('[3][2][1]'); - this.runTask(() => set(this.context, 'numbers', [1, 2, 3])); + this.runTask(() => set(this.context, 'numbers', [1, 2, 3])); - this.assertText('[1][2][3]'); - } + this.assertText('[1][2][3]'); + } - ['@test should be able to get an object value with a path evaluating to a number']() { - this.render(`{{#each indexes as |index|}}[{{get items index}}]{{/each}}`, { - indexes: [1, 2, 3], - items: { - 1: 'First', - 2: 'Second', - 3: 'Third' - } - }); + ['@test should be able to get an object value with a path evaluating to a number']() { + this.render( + `{{#each indexes as |index|}}[{{get items index}}]{{/each}}`, + { + indexes: [1, 2, 3], + items: { + 1: 'First', + 2: 'Second', + 3: 'Third' + } + } + ); - this.assertText('[First][Second][Third]'); + this.assertText('[First][Second][Third]'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('[First][Second][Third]'); + this.assertText('[First][Second][Third]'); - this.runTask(() => set(this.context, 'items.1', 'Qux')); + this.runTask(() => set(this.context, 'items.1', 'Qux')); - this.assertText('[Qux][Second][Third]'); + this.assertText('[Qux][Second][Third]'); - this.runTask(() => set(this.context, 'items', { 1: 'First', 2: 'Second', 3: 'Third' })); + this.runTask(() => + set(this.context, 'items', { 1: 'First', 2: 'Second', 3: 'Third' }) + ); - this.assertText('[First][Second][Third]'); - } + this.assertText('[First][Second][Third]'); + } - ['@test should be able to get an array value with a path evaluating to a number']() { - this.render(`{{#each numbers as |num index|}}[{{get numbers index}}]{{/each}}`, { - numbers: [1, 2, 3], - }); + ['@test should be able to get an array value with a path evaluating to a number']() { + this.render( + `{{#each numbers as |num index|}}[{{get numbers index}}]{{/each}}`, + { + numbers: [1, 2, 3] + } + ); - this.assertText('[1][2][3]'); + this.assertText('[1][2][3]'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('[1][2][3]'); + this.assertText('[1][2][3]'); - this.runTask(() => set(this.context, 'numbers', [3, 2, 1])); + this.runTask(() => set(this.context, 'numbers', [3, 2, 1])); - this.assertText('[3][2][1]'); - } + this.assertText('[3][2][1]'); + } - ['@test should be able to get an object value with a bound/dynamic key']() { - this.render(`[{{get colors key}}] [{{if true (get colors key)}}]`, { - colors: { apple: 'red', banana: 'yellow' }, - key: 'apple' - }); + ['@test should be able to get an object value with a bound/dynamic key']() { + this.render(`[{{get colors key}}] [{{if true (get colors key)}}]`, { + colors: { apple: 'red', banana: 'yellow' }, + key: 'apple' + }); - this.assertText('[red] [red]'); + this.assertText('[red] [red]'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('[red] [red]'); + this.assertText('[red] [red]'); - this.runTask(() => set(this.context, 'key', 'banana')); + this.runTask(() => set(this.context, 'key', 'banana')); - this.assertText('[yellow] [yellow]'); + this.assertText('[yellow] [yellow]'); - this.runTask(() => { - set(this.context, 'colors.apple', 'green'); - set(this.context, 'colors.banana', 'purple'); - }); + this.runTask(() => { + set(this.context, 'colors.apple', 'green'); + set(this.context, 'colors.banana', 'purple'); + }); - this.assertText('[purple] [purple]'); + this.assertText('[purple] [purple]'); - this.runTask(() => set(this.context, 'key', 'apple')); + this.runTask(() => set(this.context, 'key', 'apple')); - this.assertText('[green] [green]'); + this.assertText('[green] [green]'); - this.runTask(() => set(this.context, 'colors', { apple: 'red' })); + this.runTask(() => set(this.context, 'colors', { apple: 'red' })); - this.assertText('[red] [red]'); - } + this.assertText('[red] [red]'); + } - ['@test should be able to get an object value with nested dynamic key']() { - this.render(`[{{get colors key}}] [{{if true (get colors key)}}]`, { - colors: { - apple: { - gala: 'red and yellow', - mcintosh: 'red' + ['@test should be able to get an object value with nested dynamic key']() { + this.render(`[{{get colors key}}] [{{if true (get colors key)}}]`, { + colors: { + apple: { + gala: 'red and yellow', + mcintosh: 'red' + }, + banana: 'yellow' }, - banana: 'yellow' - }, - key: 'apple.gala' - }); + key: 'apple.gala' + }); - this.assertText('[red and yellow] [red and yellow]'); + this.assertText('[red and yellow] [red and yellow]'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('[red and yellow] [red and yellow]'); + this.assertText('[red and yellow] [red and yellow]'); - this.runTask(() => set(this.context, 'key', 'apple.mcintosh')); + this.runTask(() => set(this.context, 'key', 'apple.mcintosh')); - this.assertText('[red] [red]'); + this.assertText('[red] [red]'); - this.runTask(() => set(this.context, 'key', 'banana')); + this.runTask(() => set(this.context, 'key', 'banana')); - this.assertText('[yellow] [yellow]'); + this.assertText('[yellow] [yellow]'); - this.runTask(() => set(this.context, 'key', 'apple.gala')); + this.runTask(() => set(this.context, 'key', 'apple.gala')); - this.assertText('[red and yellow] [red and yellow]'); - } + this.assertText('[red and yellow] [red and yellow]'); + } - ['@test should be able to get an object value with subexpression returning nested key']() { - this.render(`[{{get colors (concat 'apple' '.' 'gala')}}] [{{if true (get colors (concat 'apple' '.' 'gala'))}}]`, { - colors: { - apple: { - gala: 'red and yellow', - mcintosh: 'red' + ['@test should be able to get an object value with subexpression returning nested key']() { + this.render( + `[{{get colors (concat 'apple' '.' 'gala')}}] [{{if true (get colors (concat 'apple' '.' 'gala'))}}]`, + { + colors: { + apple: { + gala: 'red and yellow', + mcintosh: 'red' + } + }, + key: 'apple.gala' } - }, - key: 'apple.gala' - }); - - this.assertText('[red and yellow] [red and yellow]'); + ); - this.runTask(() => this.rerender()); + this.assertText('[red and yellow] [red and yellow]'); - this.assertText('[red and yellow] [red and yellow]'); + this.runTask(() => this.rerender()); - this.runTask(() => set(this.context, 'colors.apple.gala', 'yellow and red striped')); + this.assertText('[red and yellow] [red and yellow]'); - this.assertText('[yellow and red striped] [yellow and red striped]'); + this.runTask(() => + set(this.context, 'colors.apple.gala', 'yellow and red striped') + ); - this.runTask(() => set(this.context, 'colors.apple.gala', 'yellow-redish')); + this.assertText('[yellow and red striped] [yellow and red striped]'); - this.assertText('[yellow-redish] [yellow-redish]'); + this.runTask(() => + set(this.context, 'colors.apple.gala', 'yellow-redish') + ); - this.runTask(() => set(this.context, 'colors', { - apple: { - gala: 'red and yellow', - mcintosh: 'red' - } - })); + this.assertText('[yellow-redish] [yellow-redish]'); - this.assertText('[red and yellow] [red and yellow]'); - } + this.runTask(() => + set(this.context, 'colors', { + apple: { + gala: 'red and yellow', + mcintosh: 'red' + } + }) + ); - ['@test should be able to get an object value with a get helper as the key']() { - this.render(`[{{get colors (get possibleKeys key)}}] [{{if true (get colors (get possibleKeys key))}}]`, { - colors: { apple: 'red', banana: 'yellow' }, - key: 'key1', - possibleKeys: { key1: 'apple', key2: 'banana' } - }); + this.assertText('[red and yellow] [red and yellow]'); + } - this.assertText('[red] [red]'); - - this.runTask(() => this.rerender()); + ['@test should be able to get an object value with a get helper as the key']() { + this.render( + `[{{get colors (get possibleKeys key)}}] [{{if true (get colors (get possibleKeys key))}}]`, + { + colors: { apple: 'red', banana: 'yellow' }, + key: 'key1', + possibleKeys: { key1: 'apple', key2: 'banana' } + } + ); - this.assertText('[red] [red]'); + this.assertText('[red] [red]'); - this.runTask(() => set(this.context, 'key', 'key2')); + this.runTask(() => this.rerender()); - this.assertText('[yellow] [yellow]'); + this.assertText('[red] [red]'); - this.runTask(() => { - set(this.context, 'colors.apple', 'green'); - set(this.context, 'colors.banana', 'purple'); - }); + this.runTask(() => set(this.context, 'key', 'key2')); - this.assertText('[purple] [purple]'); + this.assertText('[yellow] [yellow]'); - this.runTask(() => set(this.context, 'key', 'key1')); + this.runTask(() => { + set(this.context, 'colors.apple', 'green'); + set(this.context, 'colors.banana', 'purple'); + }); - this.assertText('[green] [green]'); + this.assertText('[purple] [purple]'); - this.runTask(() => set(this.context, 'colors', { apple: 'red', banana: 'yellow' })); + this.runTask(() => set(this.context, 'key', 'key1')); - this.assertText('[red] [red]'); - } + this.assertText('[green] [green]'); - ['@test should be able to get an object value with a get helper value as a bound/dynamic key']() { - this.render(`[{{get (get possibleValues objectKey) key}}] [{{if true (get (get possibleValues objectKey) key)}}]`, { - possibleValues: { - colors1: { apple: 'red', banana: 'yellow' }, - colors2: { apple: 'green', banana: 'purple' } - }, - objectKey: 'colors1', - key: 'apple' - }); + this.runTask(() => + set(this.context, 'colors', { apple: 'red', banana: 'yellow' }) + ); - this.assertText('[red] [red]'); + this.assertText('[red] [red]'); + } - this.runTask(() => this.rerender()); + ['@test should be able to get an object value with a get helper value as a bound/dynamic key']() { + this.render( + `[{{get (get possibleValues objectKey) key}}] [{{if true (get (get possibleValues objectKey) key)}}]`, + { + possibleValues: { + colors1: { apple: 'red', banana: 'yellow' }, + colors2: { apple: 'green', banana: 'purple' } + }, + objectKey: 'colors1', + key: 'apple' + } + ); - this.assertText('[red] [red]'); + this.assertText('[red] [red]'); - this.runTask(() => set(this.context, 'objectKey', 'colors2')); + this.runTask(() => this.rerender()); - this.assertText('[green] [green]'); + this.assertText('[red] [red]'); - this.runTask(() => set(this.context, 'objectKey', 'colors1')); + this.runTask(() => set(this.context, 'objectKey', 'colors2')); - this.assertText('[red] [red]'); + this.assertText('[green] [green]'); - this.runTask(() => set(this.context, 'key', 'banana')); + this.runTask(() => set(this.context, 'objectKey', 'colors1')); - this.assertText('[yellow] [yellow]'); + this.assertText('[red] [red]'); - this.runTask(() => set(this.context, 'objectKey', 'colors2')); + this.runTask(() => set(this.context, 'key', 'banana')); - this.assertText('[purple] [purple]'); + this.assertText('[yellow] [yellow]'); - this.runTask(() => set(this.context, 'objectKey', 'colors1')); + this.runTask(() => set(this.context, 'objectKey', 'colors2')); - this.assertText('[yellow] [yellow]'); + this.assertText('[purple] [purple]'); - this.runTask(() => set(this.context, 'key', 'apple')); - } + this.runTask(() => set(this.context, 'objectKey', 'colors1')); - ['@test should be able to get an object value with a get helper as the value and a get helper as the key']() { - this.render(`[{{get (get possibleValues objectKey) (get possibleKeys key)}}] [{{if true (get (get possibleValues objectKey) (get possibleKeys key))}}]`, { - possibleValues: { - colors1: { apple: 'red', banana: 'yellow' }, - colors2: { apple: 'green', banana: 'purple' } - }, - objectKey: 'colors1', - possibleKeys: { - key1: 'apple', - key2: 'banana' - }, - key: 'key1' - }); + this.assertText('[yellow] [yellow]'); - this.assertText('[red] [red]'); + this.runTask(() => set(this.context, 'key', 'apple')); + } - this.runTask(() => this.rerender()); + ['@test should be able to get an object value with a get helper as the value and a get helper as the key']() { + this.render( + `[{{get (get possibleValues objectKey) (get possibleKeys key)}}] [{{if true (get (get possibleValues objectKey) (get possibleKeys key))}}]`, + { + possibleValues: { + colors1: { apple: 'red', banana: 'yellow' }, + colors2: { apple: 'green', banana: 'purple' } + }, + objectKey: 'colors1', + possibleKeys: { + key1: 'apple', + key2: 'banana' + }, + key: 'key1' + } + ); - this.assertText('[red] [red]'); + this.assertText('[red] [red]'); - this.runTask(() => set(this.context, 'objectKey', 'colors2')); + this.runTask(() => this.rerender()); - this.assertText('[green] [green]'); + this.assertText('[red] [red]'); - this.runTask(() => set(this.context, 'objectKey', 'colors1')); + this.runTask(() => set(this.context, 'objectKey', 'colors2')); - this.assertText('[red] [red]'); + this.assertText('[green] [green]'); - this.runTask(() => set(this.context, 'key', 'key2')); + this.runTask(() => set(this.context, 'objectKey', 'colors1')); - this.assertText('[yellow] [yellow]'); + this.assertText('[red] [red]'); - this.runTask(() => set(this.context, 'objectKey', 'colors2')); + this.runTask(() => set(this.context, 'key', 'key2')); - this.assertText('[purple] [purple]'); + this.assertText('[yellow] [yellow]'); - this.runTask(() => { - set(this.context, 'objectKey', 'colors1'); - set(this.context, 'key', 'key1'); - }); + this.runTask(() => set(this.context, 'objectKey', 'colors2')); - this.assertText('[red] [red]'); - } + this.assertText('[purple] [purple]'); - ['@test the result of a get helper can be yielded']() { - let fooBarInstance; - let FooBarComponent = Component.extend({ - init() { - this._super(); - fooBarInstance = this; - this.mcintosh = 'red'; - } - }); + this.runTask(() => { + set(this.context, 'objectKey', 'colors1'); + set(this.context, 'key', 'key1'); + }); - this.registerComponent('foo-bar', { - ComponentClass: FooBarComponent, - template: `{{yield (get colors mcintosh)}}` - }); + this.assertText('[red] [red]'); + } - this.render(`{{#foo-bar colors=colors as |value|}}{{value}}{{/foo-bar}}`, { - colors: { - red: 'banana' - } - }); + ['@test the result of a get helper can be yielded']() { + let fooBarInstance; + let FooBarComponent = Component.extend({ + init() { + this._super(); + fooBarInstance = this; + this.mcintosh = 'red'; + } + }); - this.assertText('banana'); + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: `{{yield (get colors mcintosh)}}` + }); - this.runTask(() => this.rerender()); + this.render( + `{{#foo-bar colors=colors as |value|}}{{value}}{{/foo-bar}}`, + { + colors: { + red: 'banana' + } + } + ); - this.assertText('banana'); + this.assertText('banana'); - this.runTask(() => { - set(fooBarInstance, 'mcintosh', 'yellow'); - set(this.context, 'colors', { yellow: 'bus' }); - }); + this.runTask(() => this.rerender()); - this.assertText('bus'); + this.assertText('banana'); - this.runTask(() => { - set(fooBarInstance, 'mcintosh', 'red'); - set(this.context, 'colors', { red: 'banana' }); - }); + this.runTask(() => { + set(fooBarInstance, 'mcintosh', 'yellow'); + set(this.context, 'colors', { yellow: 'bus' }); + }); - this.assertText('banana'); - } + this.assertText('bus'); - ['@test should handle object values as nulls']() { - this.render(`[{{get colors 'apple'}}] [{{if true (get colors 'apple')}}]`, { - colors: null - }); + this.runTask(() => { + set(fooBarInstance, 'mcintosh', 'red'); + set(this.context, 'colors', { red: 'banana' }); + }); - this.assertText('[] []'); + this.assertText('banana'); + } - this.runTask(() => this.rerender()); + ['@test should handle object values as nulls']() { + this.render( + `[{{get colors 'apple'}}] [{{if true (get colors 'apple')}}]`, + { + colors: null + } + ); - this.assertText('[] []'); + this.assertText('[] []'); - this.runTask(() => set(this.context, 'colors', { apple: 'green', banana: 'purple' })); + this.runTask(() => this.rerender()); - this.assertText('[green] [green]'); + this.assertText('[] []'); - this.runTask(() => set(this.context, 'colors', null)); + this.runTask(() => + set(this.context, 'colors', { apple: 'green', banana: 'purple' }) + ); - this.assertText('[] []'); - } + this.assertText('[green] [green]'); - ['@test should handle object keys as nulls']() { - this.render(`[{{get colors key}}] [{{if true (get colors key)}}]`, { - colors: { - apple: 'red', - banana: 'yellow' - }, - key: null - }); + this.runTask(() => set(this.context, 'colors', null)); - this.assertText('[] []'); + this.assertText('[] []'); + } - this.runTask(() => this.rerender()); + ['@test should handle object keys as nulls']() { + this.render(`[{{get colors key}}] [{{if true (get colors key)}}]`, { + colors: { + apple: 'red', + banana: 'yellow' + }, + key: null + }); - this.assertText('[] []'); + this.assertText('[] []'); - this.runTask(() => set(this.context, 'key', 'banana')); + this.runTask(() => this.rerender()); - this.assertText('[yellow] [yellow]'); + this.assertText('[] []'); - this.runTask(() => set(this.context, 'key', null)); + this.runTask(() => set(this.context, 'key', 'banana')); - this.assertText('[] []'); - } + this.assertText('[yellow] [yellow]'); - ['@test should handle object values and keys as nulls']() { - this.render(`[{{get colors 'apple'}}] [{{if true (get colors key)}}]`, { - colors: null, - key: null - }); + this.runTask(() => set(this.context, 'key', null)); - this.assertText('[] []'); - } + this.assertText('[] []'); + } - ['@test get helper value should be updatable using {{input}} and (mut) - static key'](assert) { - this.render(`{{input type='text' value=(mut (get source 'banana')) id='get-input'}}`, { - source: { - banana: 'banana' - } - }); + ['@test should handle object values and keys as nulls']() { + this.render(`[{{get colors 'apple'}}] [{{if true (get colors key)}}]`, { + colors: null, + key: null + }); - assert.strictEqual(this.$('#get-input').val(), 'banana'); + this.assertText('[] []'); + } + + ['@test get helper value should be updatable using {{input}} and (mut) - static key']( + assert + ) { + this.render( + `{{input type='text' value=(mut (get source 'banana')) id='get-input'}}`, + { + source: { + banana: 'banana' + } + } + ); - this.runTask(() => this.rerender()); + assert.strictEqual(this.$('#get-input').val(), 'banana'); - assert.strictEqual(this.$('#get-input').val(), 'banana'); + this.runTask(() => this.rerender()); - this.runTask(() => set(this.context, 'source.banana', 'yellow')); + assert.strictEqual(this.$('#get-input').val(), 'banana'); - assert.strictEqual(this.$('#get-input').val(), 'yellow'); + this.runTask(() => set(this.context, 'source.banana', 'yellow')); - this.runTask(() => this.$('#get-input').val('some value').trigger('change')); + assert.strictEqual(this.$('#get-input').val(), 'yellow'); - assert.strictEqual(this.$('#get-input').val(), 'some value'); - assert.strictEqual(get(this.context, 'source.banana'), 'some value'); + this.runTask(() => + this.$('#get-input') + .val('some value') + .trigger('change') + ); - this.runTask(() => set(this.context, 'source', { banana: 'banana' })); + assert.strictEqual(this.$('#get-input').val(), 'some value'); + assert.strictEqual(get(this.context, 'source.banana'), 'some value'); - assert.strictEqual(this.$('#get-input').val(), 'banana'); - } + this.runTask(() => set(this.context, 'source', { banana: 'banana' })); - ['@test get helper value should be updatable using {{input}} and (mut) - dynamic key'](assert) { - this.render(`{{input type='text' value=(mut (get source key)) id='get-input'}}`, { - source: { - apple: 'apple', - banana: 'banana' - }, - key: 'banana' - }); + assert.strictEqual(this.$('#get-input').val(), 'banana'); + } - assert.strictEqual(this.$('#get-input').val(), 'banana'); + ['@test get helper value should be updatable using {{input}} and (mut) - dynamic key']( + assert + ) { + this.render( + `{{input type='text' value=(mut (get source key)) id='get-input'}}`, + { + source: { + apple: 'apple', + banana: 'banana' + }, + key: 'banana' + } + ); - this.runTask(() => this.rerender()); + assert.strictEqual(this.$('#get-input').val(), 'banana'); - assert.strictEqual(this.$('#get-input').val(), 'banana'); + this.runTask(() => this.rerender()); - this.runTask(() => set(this.context, 'source.banana', 'yellow')); + assert.strictEqual(this.$('#get-input').val(), 'banana'); - assert.strictEqual(this.$('#get-input').val(), 'yellow'); + this.runTask(() => set(this.context, 'source.banana', 'yellow')); - this.runTask(() => this.$('#get-input').val('some value').trigger('change')); + assert.strictEqual(this.$('#get-input').val(), 'yellow'); - assert.strictEqual(this.$('#get-input').val(), 'some value'); - assert.strictEqual(get(this.context, 'source.banana'), 'some value'); + this.runTask(() => + this.$('#get-input') + .val('some value') + .trigger('change') + ); - this.runTask(() => set(this.context, 'key', 'apple')); + assert.strictEqual(this.$('#get-input').val(), 'some value'); + assert.strictEqual(get(this.context, 'source.banana'), 'some value'); - assert.strictEqual(this.$('#get-input').val(), 'apple'); + this.runTask(() => set(this.context, 'key', 'apple')); - this.runTask(() => this.$('#get-input').val('some other value').trigger('change')); + assert.strictEqual(this.$('#get-input').val(), 'apple'); - assert.strictEqual(this.$('#get-input').val(), 'some other value'); - assert.strictEqual(get(this.context, 'source.apple'), 'some other value'); + this.runTask(() => + this.$('#get-input') + .val('some other value') + .trigger('change') + ); - this.runTask(() => { - set(this.context, 'key', 'banana'); - set(this.context, 'source', { banana: 'banana' }); - }); + assert.strictEqual(this.$('#get-input').val(), 'some other value'); + assert.strictEqual(get(this.context, 'source.apple'), 'some other value'); - assert.strictEqual(this.$('#get-input').val(), 'banana'); - } + this.runTask(() => { + set(this.context, 'key', 'banana'); + set(this.context, 'source', { banana: 'banana' }); + }); - ['@test get helper value should be updatable using {{input}} and (mut) - dynamic nested key'](assert) { - this.render(`{{input type='text' value=(mut (get source key)) id='get-input'}}`, { - source: { - apple: { - gala: 'gala', - mcintosh: 'mcintosh' - }, - banana: 'banana' - }, - key: 'apple.mcintosh' - }); + assert.strictEqual(this.$('#get-input').val(), 'banana'); + } + + ['@test get helper value should be updatable using {{input}} and (mut) - dynamic nested key']( + assert + ) { + this.render( + `{{input type='text' value=(mut (get source key)) id='get-input'}}`, + { + source: { + apple: { + gala: 'gala', + mcintosh: 'mcintosh' + }, + banana: 'banana' + }, + key: 'apple.mcintosh' + } + ); - assert.strictEqual(this.$('#get-input').val(), 'mcintosh'); + assert.strictEqual(this.$('#get-input').val(), 'mcintosh'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - assert.strictEqual(this.$('#get-input').val(), 'mcintosh'); + assert.strictEqual(this.$('#get-input').val(), 'mcintosh'); - this.runTask(() => set(this.context, 'source.apple.mcintosh', 'red')); + this.runTask(() => set(this.context, 'source.apple.mcintosh', 'red')); - assert.strictEqual(this.$('#get-input').val(), 'red'); + assert.strictEqual(this.$('#get-input').val(), 'red'); - this.runTask(() => this.$('#get-input').val('some value').trigger('change')); + this.runTask(() => + this.$('#get-input') + .val('some value') + .trigger('change') + ); - assert.strictEqual(this.$('#get-input').val(), 'some value'); - assert.strictEqual(get(this.context, 'source.apple.mcintosh'), 'some value'); + assert.strictEqual(this.$('#get-input').val(), 'some value'); + assert.strictEqual( + get(this.context, 'source.apple.mcintosh'), + 'some value' + ); - this.runTask(() => set(this.context, 'key', 'apple.gala')); + this.runTask(() => set(this.context, 'key', 'apple.gala')); - assert.strictEqual(this.$('#get-input').val(), 'gala'); + assert.strictEqual(this.$('#get-input').val(), 'gala'); - this.runTask(() => this.$('#get-input').val('some other value').trigger('change')); + this.runTask(() => + this.$('#get-input') + .val('some other value') + .trigger('change') + ); - assert.strictEqual(this.$('#get-input').val(), 'some other value'); - assert.strictEqual(get(this.context, 'source.apple.gala'), 'some other value'); + assert.strictEqual(this.$('#get-input').val(), 'some other value'); + assert.strictEqual( + get(this.context, 'source.apple.gala'), + 'some other value' + ); - this.runTask(() => set(this.context, 'key', 'banana')); + this.runTask(() => set(this.context, 'key', 'banana')); - assert.strictEqual(this.$('#get-input').val(), 'banana'); + assert.strictEqual(this.$('#get-input').val(), 'banana'); - this.runTask(() => this.$('#get-input').val('yet another value').trigger('change')); + this.runTask(() => + this.$('#get-input') + .val('yet another value') + .trigger('change') + ); - assert.strictEqual(this.$('#get-input').val(), 'yet another value'); - assert.strictEqual(get(this.context, 'source.banana'), 'yet another value'); + assert.strictEqual(this.$('#get-input').val(), 'yet another value'); + assert.strictEqual( + get(this.context, 'source.banana'), + 'yet another value' + ); - this.runTask(() => { - set(this.context, 'key', 'apple.mcintosh'); - set(this.context, 'source', { - apple: { - gala: 'gala', - mcintosh: 'mcintosh' - }, - banana: 'banana' + this.runTask(() => { + set(this.context, 'key', 'apple.mcintosh'); + set(this.context, 'source', { + apple: { + gala: 'gala', + mcintosh: 'mcintosh' + }, + banana: 'banana' + }); }); - }); - assert.strictEqual(this.$('#get-input').val(), 'mcintosh'); + assert.strictEqual(this.$('#get-input').val(), 'mcintosh'); + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/helpers/hash-test.js b/packages/ember-glimmer/tests/integration/helpers/hash-test.js index 356c38b0679..5894a18dd7e 100644 --- a/packages/ember-glimmer/tests/integration/helpers/hash-test.js +++ b/packages/ember-glimmer/tests/integration/helpers/hash-test.js @@ -2,169 +2,189 @@ import { RenderingTest, moduleFor } from '../../utils/test-case'; import { Component } from '../../utils/helpers'; import { set } from 'ember-metal'; -moduleFor('Helpers test: {{hash}}', class extends RenderingTest { +moduleFor( + 'Helpers test: {{hash}}', + class extends RenderingTest { + ['@test returns a hash with the right key-value']() { + this.render( + `{{#with (hash name=\"Sergio\") as |person|}}{{person.name}}{{/with}}` + ); - ['@test returns a hash with the right key-value']() { - this.render(`{{#with (hash name=\"Sergio\") as |person|}}{{person.name}}{{/with}}`); + this.assertText('Sergio'); - this.assertText('Sergio'); + this.runTask(() => this.rerender()); - this.runTask(() => this.rerender()); + this.assertText('Sergio'); + } - this.assertText('Sergio'); - } + ['@test can have more than one key-value']() { + this.render( + `{{#with (hash name="Sergio" lastName="Arbeo") as |person|}}{{person.name}} {{person.lastName}}{{/with}}` + ); - ['@test can have more than one key-value']() { - this.render(`{{#with (hash name="Sergio" lastName="Arbeo") as |person|}}{{person.name}} {{person.lastName}}{{/with}}`); + this.assertText('Sergio Arbeo'); - this.assertText('Sergio Arbeo'); + this.runTask(() => this.rerender()); - this.runTask(() => this.rerender()); + this.assertText('Sergio Arbeo'); + } - this.assertText('Sergio Arbeo'); - } + ['@test binds values when variables are used']() { + this.render( + `{{#with (hash name=model.firstName lastName="Arbeo") as |person|}}{{person.name}} {{person.lastName}}{{/with}}`, + { + model: { + firstName: 'Marisa' + } + } + ); - ['@test binds values when variables are used']() { - this.render(`{{#with (hash name=model.firstName lastName="Arbeo") as |person|}}{{person.name}} {{person.lastName}}{{/with}}`, { - model: { - firstName: 'Marisa' - } - }); + this.assertText('Marisa Arbeo'); - this.assertText('Marisa Arbeo'); + this.runTask(() => this.rerender()); - this.runTask(() => this.rerender()); + this.assertText('Marisa Arbeo'); - this.assertText('Marisa Arbeo'); + this.runTask(() => set(this.context, 'model.firstName', 'Sergio')); - this.runTask(() => set(this.context, 'model.firstName', 'Sergio')); + this.assertText('Sergio Arbeo'); - this.assertText('Sergio Arbeo'); + this.runTask(() => set(this.context, 'model', { firstName: 'Marisa' })); - this.runTask(() => set(this.context, 'model', { firstName: 'Marisa' })); + this.assertText('Marisa Arbeo'); + } - this.assertText('Marisa Arbeo'); - } + ['@test binds multiple values when variables are used']() { + this.render( + `{{#with (hash name=model.firstName lastName=model.lastName) as |person|}}{{person.name}} {{person.lastName}}{{/with}}`, + { + model: { + firstName: 'Marisa', + lastName: 'Arbeo' + } + } + ); - ['@test binds multiple values when variables are used']() { - this.render(`{{#with (hash name=model.firstName lastName=model.lastName) as |person|}}{{person.name}} {{person.lastName}}{{/with}}`, { - model: { - firstName: 'Marisa', - lastName: 'Arbeo' - } - }); + this.assertText('Marisa Arbeo'); - this.assertText('Marisa Arbeo'); + this.runTask(() => this.rerender()); - this.runTask(() => this.rerender()); + this.assertText('Marisa Arbeo'); - this.assertText('Marisa Arbeo'); + this.runTask(() => set(this.context, 'model.firstName', 'Sergio')); - this.runTask(() => set(this.context, 'model.firstName', 'Sergio')); + this.assertText('Sergio Arbeo'); - this.assertText('Sergio Arbeo'); + this.runTask(() => set(this.context, 'model.lastName', 'Smith')); - this.runTask(() => set(this.context, 'model.lastName', 'Smith')); + this.assertText('Sergio Smith'); - this.assertText('Sergio Smith'); + this.runTask(() => + set(this.context, 'model', { + firstName: 'Marisa', + lastName: 'Arbeo' + }) + ); - this.runTask(() => set(this.context, 'model', { - firstName: 'Marisa', - lastName: 'Arbeo' - })); + this.assertText('Marisa Arbeo'); + } - this.assertText('Marisa Arbeo'); - } + ['@test hash helpers can be nested']() { + this.render( + `{{#with (hash person=(hash name=model.firstName)) as |ctx|}}{{ctx.person.name}}{{/with}}`, + { + model: { firstName: 'Balint' } + } + ); - ['@test hash helpers can be nested']() { - this.render(`{{#with (hash person=(hash name=model.firstName)) as |ctx|}}{{ctx.person.name}}{{/with}}`, { - model: { firstName: 'Balint' } - }); + this.assertText('Balint'); - this.assertText('Balint'); + this.runTask(() => this.rerender()); - this.runTask(() => this.rerender()); + this.assertText('Balint'); - this.assertText('Balint'); + this.runTask(() => set(this.context, 'model.firstName', 'Chad')); - this.runTask(() => set(this.context, 'model.firstName', 'Chad')); + this.assertText('Chad'); - this.assertText('Chad'); + this.runTask(() => set(this.context, 'model', { firstName: 'Balint' })); - this.runTask(() => set(this.context, 'model', { firstName: 'Balint' })); + this.assertText('Balint'); + } - this.assertText('Balint'); - } - - ['@test should yield hash of internal properties']() { - let fooBarInstance; - let FooBarComponent = Component.extend({ - init() { - this._super(); - fooBarInstance = this; - this.model = { firstName: 'Chad' }; - } - }); + ['@test should yield hash of internal properties']() { + let fooBarInstance; + let FooBarComponent = Component.extend({ + init() { + this._super(); + fooBarInstance = this; + this.model = { firstName: 'Chad' }; + } + }); - this.registerComponent('foo-bar', { - ComponentClass: FooBarComponent, - template: `{{yield (hash firstName=model.firstName)}}` - }); + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: `{{yield (hash firstName=model.firstName)}}` + }); - this.render(`{{#foo-bar as |values|}}{{values.firstName}}{{/foo-bar}}`); + this.render(`{{#foo-bar as |values|}}{{values.firstName}}{{/foo-bar}}`); - this.assertText('Chad'); + this.assertText('Chad'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Chad'); + this.assertText('Chad'); - this.runTask(() => set(fooBarInstance, 'model.firstName', 'Godfrey')); + this.runTask(() => set(fooBarInstance, 'model.firstName', 'Godfrey')); - this.assertText('Godfrey'); + this.assertText('Godfrey'); - this.runTask(() => set(fooBarInstance, 'model', { firstName: 'Chad' })); + this.runTask(() => set(fooBarInstance, 'model', { firstName: 'Chad' })); - this.assertText('Chad'); - } + this.assertText('Chad'); + } - ['@test should yield hash of internal and external properties']() { - let fooBarInstance; - let FooBarComponent = Component.extend({ - init() { - this._super(); - fooBarInstance = this; - this.model = { firstName: 'Chad' }; - } - }); + ['@test should yield hash of internal and external properties']() { + let fooBarInstance; + let FooBarComponent = Component.extend({ + init() { + this._super(); + fooBarInstance = this; + this.model = { firstName: 'Chad' }; + } + }); - this.registerComponent('foo-bar', { - ComponentClass: FooBarComponent, - template: `{{yield (hash firstName=model.firstName lastName=lastName)}}` - }); + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: `{{yield (hash firstName=model.firstName lastName=lastName)}}` + }); - this.render(`{{#foo-bar lastName=model.lastName as |values|}}{{values.firstName}} {{values.lastName}}{{/foo-bar}}`, { - model: { lastName: 'Hietala' } - }); + this.render( + `{{#foo-bar lastName=model.lastName as |values|}}{{values.firstName}} {{values.lastName}}{{/foo-bar}}`, + { + model: { lastName: 'Hietala' } + } + ); - this.assertText('Chad Hietala'); + this.assertText('Chad Hietala'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Chad Hietala'); + this.assertText('Chad Hietala'); - this.runTask(() => { - set(fooBarInstance, 'model.firstName', 'Godfrey'); - set(this.context, 'model.lastName', 'Chan'); - }); + this.runTask(() => { + set(fooBarInstance, 'model.firstName', 'Godfrey'); + set(this.context, 'model.lastName', 'Chan'); + }); - this.assertText('Godfrey Chan'); + this.assertText('Godfrey Chan'); - this.runTask(() => { - set(fooBarInstance, 'model', { firstName: 'Chad' }); - set(this.context, 'model', { lastName: 'Hietala' }); - }); + this.runTask(() => { + set(fooBarInstance, 'model', { firstName: 'Chad' }); + set(this.context, 'model', { lastName: 'Hietala' }); + }); - this.assertText('Chad Hietala'); + this.assertText('Chad Hietala'); + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/helpers/if-unless-test.js b/packages/ember-glimmer/tests/integration/helpers/if-unless-test.js index ba65adf64ce..55557b5aa7f 100644 --- a/packages/ember-glimmer/tests/integration/helpers/if-unless-test.js +++ b/packages/ember-glimmer/tests/integration/helpers/if-unless-test.js @@ -1,138 +1,149 @@ import { moduleFor } from '../../utils/test-case'; import { IfUnlessHelperTest } from '../../utils/shared-conditional-tests'; -moduleFor('Helpers test: inline {{if}}', class extends IfUnlessHelperTest { - - templateFor({ cond, truthy, falsy }) { - return `{{if ${cond} ${truthy} ${falsy}}}`; - } - - ['@test it raises when there are more than three arguments']() { - expectAssertion(() => { - this.render(`{{if condition 'a' 'b' 'c'}}`, { condition: true }); - }, `The inline form of the 'if' helper expects two or three arguments. ('-top-level' @ L1:C0) `); - } - - ['@test it raises when there are less than two arguments']() { - expectAssertion(() => { - this.render(`{{if condition}}`, { condition: true }); - }, `The inline form of the 'if' helper expects two or three arguments. ('-top-level' @ L1:C0) `); - } - -}); - -moduleFor('Helpers test: nested {{if}} helpers (returning truthy values)', class extends IfUnlessHelperTest { - - templateFor({ cond, truthy, falsy }) { - return `{{if (if ${cond} ${cond} false) ${truthy} ${falsy}}}`; - } - -}); - -moduleFor('Helpers test: nested {{if}} helpers (returning falsy values)', class extends IfUnlessHelperTest { - - templateFor({ cond, truthy, falsy }) { - return `{{if (if ${cond} true ${cond}) ${truthy} ${falsy}}}`; - } - -}); - -moduleFor('Helpers test: {{if}} used with another helper', class extends IfUnlessHelperTest { - - wrapperFor(templates) { - return `{{concat ${templates.join(' ')}}}`; - } - - templateFor({ cond, truthy, falsy }) { - return `(if ${cond} ${truthy} ${falsy})`; - } - -}); - -moduleFor('Helpers test: {{if}} used in attribute position', class extends IfUnlessHelperTest { - - wrapperFor(templates) { - return `
`; - } - - templateFor({ cond, truthy, falsy }) { - return `{{if ${cond} ${truthy} ${falsy}}}`; - } - - textValue() { - return this.$('div').attr('data-foo'); - } - -}); - -moduleFor('Helpers test: inline {{if}} and {{unless}} without the inverse argument', class extends IfUnlessHelperTest { - - templateFor({ cond, truthy, falsy }) { - return `{{if ${cond} ${truthy}}}{{unless ${cond} ${falsy}}}`; - } - -}); - -moduleFor('Helpers test: inline {{unless}}', class extends IfUnlessHelperTest { - - templateFor({ cond, truthy, falsy }) { - return `{{unless ${cond} ${falsy} ${truthy}}}`; - } - - ['@test it raises when there are more than three arguments']() { - expectAssertion(() => { - this.render(`{{unless condition 'a' 'b' 'c'}}`, { condition: true }); - }, /The inline form of the `unless` helper expects two or three arguments/); - } - - ['@test it raises when there are less than two arguments']() { - expectAssertion(() => { - this.render(`{{unless condition}}`, { condition: true }); - }, /The inline form of the `unless` helper expects two or three arguments/); - } - -}); - -moduleFor('Helpers test: nested {{unless}} helpers (returning truthy values)', class extends IfUnlessHelperTest { - - templateFor({ cond, truthy, falsy }) { - return `{{unless (unless ${cond} false ${cond}) ${falsy} ${truthy}}}`; - } - -}); - -moduleFor('Helpers test: nested {{unless}} helpers (returning falsy values)', class extends IfUnlessHelperTest { - - templateFor({ cond, truthy, falsy }) { - return `{{unless (unless ${cond} ${cond} true) ${falsy} ${truthy}}}`; - } - -}); - -moduleFor('Helpers test: {{unless}} used with another helper', class extends IfUnlessHelperTest { - - wrapperFor(templates) { - return `{{concat ${templates.join(' ')}}}`; - } - - templateFor({ cond, truthy, falsy }) { - return `(unless ${cond} ${falsy} ${truthy})`; - } - -}); - -moduleFor('Helpers test: {{unless}} used in attribute position', class extends IfUnlessHelperTest { - - wrapperFor(templates) { - return `
`; - } - - templateFor({ cond, truthy, falsy }) { - return `{{unless ${cond} ${falsy} ${truthy}}}`; - } - - textValue() { - return this.$('div').attr('data-foo'); - } - -}); +moduleFor( + 'Helpers test: inline {{if}}', + class extends IfUnlessHelperTest { + templateFor({ cond, truthy, falsy }) { + return `{{if ${cond} ${truthy} ${falsy}}}`; + } + + ['@test it raises when there are more than three arguments']() { + expectAssertion(() => { + this.render(`{{if condition 'a' 'b' 'c'}}`, { condition: true }); + }, `The inline form of the 'if' helper expects two or three arguments. ('-top-level' @ L1:C0) `); + } + + ['@test it raises when there are less than two arguments']() { + expectAssertion(() => { + this.render(`{{if condition}}`, { condition: true }); + }, `The inline form of the 'if' helper expects two or three arguments. ('-top-level' @ L1:C0) `); + } + } +); + +moduleFor( + 'Helpers test: nested {{if}} helpers (returning truthy values)', + class extends IfUnlessHelperTest { + templateFor({ cond, truthy, falsy }) { + return `{{if (if ${cond} ${cond} false) ${truthy} ${falsy}}}`; + } + } +); + +moduleFor( + 'Helpers test: nested {{if}} helpers (returning falsy values)', + class extends IfUnlessHelperTest { + templateFor({ cond, truthy, falsy }) { + return `{{if (if ${cond} true ${cond}) ${truthy} ${falsy}}}`; + } + } +); + +moduleFor( + 'Helpers test: {{if}} used with another helper', + class extends IfUnlessHelperTest { + wrapperFor(templates) { + return `{{concat ${templates.join(' ')}}}`; + } + + templateFor({ cond, truthy, falsy }) { + return `(if ${cond} ${truthy} ${falsy})`; + } + } +); + +moduleFor( + 'Helpers test: {{if}} used in attribute position', + class extends IfUnlessHelperTest { + wrapperFor(templates) { + return `
`; + } + + templateFor({ cond, truthy, falsy }) { + return `{{if ${cond} ${truthy} ${falsy}}}`; + } + + textValue() { + return this.$('div').attr('data-foo'); + } + } +); + +moduleFor( + 'Helpers test: inline {{if}} and {{unless}} without the inverse argument', + class extends IfUnlessHelperTest { + templateFor({ cond, truthy, falsy }) { + return `{{if ${cond} ${truthy}}}{{unless ${cond} ${falsy}}}`; + } + } +); + +moduleFor( + 'Helpers test: inline {{unless}}', + class extends IfUnlessHelperTest { + templateFor({ cond, truthy, falsy }) { + return `{{unless ${cond} ${falsy} ${truthy}}}`; + } + + ['@test it raises when there are more than three arguments']() { + expectAssertion(() => { + this.render(`{{unless condition 'a' 'b' 'c'}}`, { condition: true }); + }, /The inline form of the `unless` helper expects two or three arguments/); + } + + ['@test it raises when there are less than two arguments']() { + expectAssertion(() => { + this.render(`{{unless condition}}`, { condition: true }); + }, /The inline form of the `unless` helper expects two or three arguments/); + } + } +); + +moduleFor( + 'Helpers test: nested {{unless}} helpers (returning truthy values)', + class extends IfUnlessHelperTest { + templateFor({ cond, truthy, falsy }) { + return `{{unless (unless ${cond} false ${cond}) ${falsy} ${truthy}}}`; + } + } +); + +moduleFor( + 'Helpers test: nested {{unless}} helpers (returning falsy values)', + class extends IfUnlessHelperTest { + templateFor({ cond, truthy, falsy }) { + return `{{unless (unless ${cond} ${cond} true) ${falsy} ${truthy}}}`; + } + } +); + +moduleFor( + 'Helpers test: {{unless}} used with another helper', + class extends IfUnlessHelperTest { + wrapperFor(templates) { + return `{{concat ${templates.join(' ')}}}`; + } + + templateFor({ cond, truthy, falsy }) { + return `(unless ${cond} ${falsy} ${truthy})`; + } + } +); + +moduleFor( + 'Helpers test: {{unless}} used in attribute position', + class extends IfUnlessHelperTest { + wrapperFor(templates) { + return `
`; + } + + templateFor({ cond, truthy, falsy }) { + return `{{unless ${cond} ${falsy} ${truthy}}}`; + } + + textValue() { + return this.$('div').attr('data-foo'); + } + } +); diff --git a/packages/ember-glimmer/tests/integration/helpers/input-test.js b/packages/ember-glimmer/tests/integration/helpers/input-test.js index 8fa9f5f31d2..bc7794976bd 100644 --- a/packages/ember-glimmer/tests/integration/helpers/input-test.js +++ b/packages/ember-glimmer/tests/integration/helpers/input-test.js @@ -18,45 +18,84 @@ class InputRenderingTest extends RenderingTest { } assertNotDisabled() { - this.assert.ok(this.$('input').is(':not(:disabled)'), 'The input is not disabled'); + this.assert.ok( + this.$('input').is(':not(:disabled)'), + 'The input is not disabled' + ); } assertInputId(expectedId) { - this.assert.equal(this.inputID(), expectedId, 'the input id should be `expectedId`'); + this.assert.equal( + this.inputID(), + expectedId, + 'the input id should be `expectedId`' + ); } assertSingleInput() { - this.assert.equal(this.$('input').length, 1, 'A single text field was inserted'); + this.assert.equal( + this.$('input').length, + 1, + 'A single text field was inserted' + ); } assertSingleCheckbox() { - this.assert.equal(this.$('input[type=checkbox]').length, 1, 'A single checkbox is added'); + this.assert.equal( + this.$('input[type=checkbox]').length, + 1, + 'A single checkbox is added' + ); } assertCheckboxIsChecked() { - this.assert.equal(this.$input().prop('checked'), true, 'the checkbox is checked'); + this.assert.equal( + this.$input().prop('checked'), + true, + 'the checkbox is checked' + ); } assertCheckboxIsNotChecked() { - this.assert.equal(this.$input().prop('checked'), false, 'the checkbox is not checked'); + this.assert.equal( + this.$input().prop('checked'), + false, + 'the checkbox is not checked' + ); } assertValue(expected) { - this.assert.equal(this.$input().val(), expected, `the input value should be ${expected}`); + this.assert.equal( + this.$input().val(), + expected, + `the input value should be ${expected}` + ); } assertAttr(name, expected) { - this.assert.equal(this.$input().attr(name), expected, `the input ${name} attribute has the value '${expected}'`); + this.assert.equal( + this.$input().attr(name), + expected, + `the input ${name} attribute has the value '${expected}'` + ); } assertAllAttrs(names, expected) { - names.forEach((name) => this.assertAttr(name, expected)); + names.forEach(name => this.assertAttr(name, expected)); } assertSelectionRange(start, end) { let input = this.$input()[0]; - this.assert.equal(input.selectionStart, start, `the cursor start position should be ${start}`); - this.assert.equal(input.selectionEnd, end, `the cursor end position should be ${end}`); + this.assert.equal( + input.selectionStart, + start, + `the cursor start position should be ${start}` + ); + this.assert.equal( + input.selectionEnd, + end, + `the cursor end position should be ${end}` + ); } triggerEvent(type, options) { @@ -71,47 +110,49 @@ class InputRenderingTest extends RenderingTest { } } -moduleFor('Helpers test: {{input}}', class extends InputRenderingTest { +moduleFor( + 'Helpers test: {{input}}', + class extends InputRenderingTest { + ['@test a single text field is inserted into the DOM']() { + this.render(`{{input type="text" value=value}}`, { value: 'hello' }); - ['@test a single text field is inserted into the DOM']() { - this.render(`{{input type="text" value=value}}`, { value: 'hello' }); + let id = this.inputID(); - let id = this.inputID(); + this.assertValue('hello'); + this.assertSingleInput(); - this.assertValue('hello'); - this.assertSingleInput(); + this.runTask(() => this.rerender()); - this.runTask(() => this.rerender()); + this.assertValue('hello'); + this.assertSingleInput(); + this.assertInputId(id); - this.assertValue('hello'); - this.assertSingleInput(); - this.assertInputId(id); + this.runTask(() => set(this.context, 'value', 'goodbye')); - this.runTask(() => set(this.context, 'value', 'goodbye')); + this.assertValue('goodbye'); + this.assertSingleInput(); + this.assertInputId(id); - this.assertValue('goodbye'); - this.assertSingleInput(); - this.assertInputId(id); + this.runTask(() => set(this.context, 'value', 'hello')); - this.runTask(() => set(this.context, 'value', 'hello')); - - this.assertValue('hello'); - this.assertSingleInput(); - this.assertInputId(id); - } + this.assertValue('hello'); + this.assertSingleInput(); + this.assertInputId(id); + } - ['@test default type']() { - this.render(`{{input}}`); + ['@test default type']() { + this.render(`{{input}}`); - this.assertAttr('type', 'text'); + this.assertAttr('type', 'text'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertAttr('type', 'text'); - } + this.assertAttr('type', 'text'); + } - ['@test dynamic attributes']() { - this.render(` + ['@test dynamic attributes']() { + this.render( + ` {{input type="text" disabled=disabled value=value @@ -121,81 +162,82 @@ moduleFor('Helpers test: {{input}}', class extends InputRenderingTest { minlength=minlength size=size tabindex=tabindex - }}`, { - disabled: false, - value: 'Original value', - placeholder: 'Original placeholder', - name: 'original-name', - maxlength: 10, - minlength: 5, - size: 20, - tabindex: 30 - } - ); - - this.assertNotDisabled(); - this.assertValue('Original value'); - this.assertAttr('placeholder', 'Original placeholder'); - this.assertAttr('name', 'original-name'); - this.assertAttr('maxlength', '10'); - this.assertAttr('minlength', '5'); - // this.assertAttr('size', '20'); //NOTE: failing in IE (TEST_SUITE=sauce) - // this.assertAttr('tabindex', '30'); //NOTE: failing in IE (TEST_SUITE=sauce) - - this.runTask(() => this.rerender()); - - this.assertNotDisabled(); - this.assertValue('Original value'); - this.assertAttr('placeholder', 'Original placeholder'); - this.assertAttr('name', 'original-name'); - this.assertAttr('maxlength', '10'); - this.assertAttr('minlength', '5'); - // this.assertAttr('size', '20'); //NOTE: failing in IE (TEST_SUITE=sauce) - // this.assertAttr('tabindex', '30'); //NOTE: failing in IE (TEST_SUITE=sauce) - - this.runTask(() => { - set(this.context, 'value', 'Updated value'); - set(this.context, 'disabled', true); - set(this.context, 'placeholder', 'Updated placeholder'); - set(this.context, 'name', 'updated-name'); - set(this.context, 'maxlength', 11); - set(this.context, 'minlength', 6); - // set(this.context, 'size', 21); //NOTE: failing in IE (TEST_SUITE=sauce) - // set(this.context, 'tabindex', 31); //NOTE: failing in IE (TEST_SUITE=sauce) - }); - - this.assertDisabled(); - this.assertValue('Updated value'); - this.assertAttr('placeholder', 'Updated placeholder'); - this.assertAttr('name', 'updated-name'); - this.assertAttr('maxlength', '11'); - this.assertAttr('minlength', '6'); - // this.assertAttr('size', '21'); //NOTE: failing in IE (TEST_SUITE=sauce) - // this.assertAttr('tabindex', '31'); //NOTE: failing in IE (TEST_SUITE=sauce) - - this.runTask(() => { - set(this.context, 'value', 'Original value'); - set(this.context, 'disabled', false); - set(this.context, 'placeholder', 'Original placeholder'); - set(this.context, 'name', 'original-name'); - set(this.context, 'maxlength', 10); - set(this.context, 'minlength', 5); - // set(this.context, 'size', 20); //NOTE: failing in IE (TEST_SUITE=sauce) - // set(this.context, 'tabindex', 30); //NOTE: failing in IE (TEST_SUITE=sauce) - }); - - this.assertNotDisabled(); - this.assertValue('Original value'); - this.assertAttr('placeholder', 'Original placeholder'); - this.assertAttr('name', 'original-name'); - this.assertAttr('maxlength', '10'); - this.assertAttr('minlength', '5'); - // this.assertAttr('size', '20'); //NOTE: failing in IE (TEST_SUITE=sauce) - // this.assertAttr('tabindex', '30'); //NOTE: failing in IE (TEST_SUITE=sauce) - } + }}`, + { + disabled: false, + value: 'Original value', + placeholder: 'Original placeholder', + name: 'original-name', + maxlength: 10, + minlength: 5, + size: 20, + tabindex: 30 + } + ); + + this.assertNotDisabled(); + this.assertValue('Original value'); + this.assertAttr('placeholder', 'Original placeholder'); + this.assertAttr('name', 'original-name'); + this.assertAttr('maxlength', '10'); + this.assertAttr('minlength', '5'); + // this.assertAttr('size', '20'); //NOTE: failing in IE (TEST_SUITE=sauce) + // this.assertAttr('tabindex', '30'); //NOTE: failing in IE (TEST_SUITE=sauce) + + this.runTask(() => this.rerender()); + + this.assertNotDisabled(); + this.assertValue('Original value'); + this.assertAttr('placeholder', 'Original placeholder'); + this.assertAttr('name', 'original-name'); + this.assertAttr('maxlength', '10'); + this.assertAttr('minlength', '5'); + // this.assertAttr('size', '20'); //NOTE: failing in IE (TEST_SUITE=sauce) + // this.assertAttr('tabindex', '30'); //NOTE: failing in IE (TEST_SUITE=sauce) + + this.runTask(() => { + set(this.context, 'value', 'Updated value'); + set(this.context, 'disabled', true); + set(this.context, 'placeholder', 'Updated placeholder'); + set(this.context, 'name', 'updated-name'); + set(this.context, 'maxlength', 11); + set(this.context, 'minlength', 6); + // set(this.context, 'size', 21); //NOTE: failing in IE (TEST_SUITE=sauce) + // set(this.context, 'tabindex', 31); //NOTE: failing in IE (TEST_SUITE=sauce) + }); + + this.assertDisabled(); + this.assertValue('Updated value'); + this.assertAttr('placeholder', 'Updated placeholder'); + this.assertAttr('name', 'updated-name'); + this.assertAttr('maxlength', '11'); + this.assertAttr('minlength', '6'); + // this.assertAttr('size', '21'); //NOTE: failing in IE (TEST_SUITE=sauce) + // this.assertAttr('tabindex', '31'); //NOTE: failing in IE (TEST_SUITE=sauce) + + this.runTask(() => { + set(this.context, 'value', 'Original value'); + set(this.context, 'disabled', false); + set(this.context, 'placeholder', 'Original placeholder'); + set(this.context, 'name', 'original-name'); + set(this.context, 'maxlength', 10); + set(this.context, 'minlength', 5); + // set(this.context, 'size', 20); //NOTE: failing in IE (TEST_SUITE=sauce) + // set(this.context, 'tabindex', 30); //NOTE: failing in IE (TEST_SUITE=sauce) + }); + + this.assertNotDisabled(); + this.assertValue('Original value'); + this.assertAttr('placeholder', 'Original placeholder'); + this.assertAttr('name', 'original-name'); + this.assertAttr('maxlength', '10'); + this.assertAttr('minlength', '5'); + // this.assertAttr('size', '20'); //NOTE: failing in IE (TEST_SUITE=sauce) + // this.assertAttr('tabindex', '30'); //NOTE: failing in IE (TEST_SUITE=sauce) + } - ['@test static attributes']() { - this.render(` + ['@test static attributes']() { + this.render(` {{input type="text" disabled=true value="Original value" @@ -205,377 +247,417 @@ moduleFor('Helpers test: {{input}}', class extends InputRenderingTest { minlength=5 size=20 tabindex=30 - }}` - ); + }}`); + + this.assertDisabled(); + this.assertValue('Original value'); + this.assertAttr('placeholder', 'Original placeholder'); + this.assertAttr('name', 'original-name'); + this.assertAttr('maxlength', '10'); + this.assertAttr('minlength', '5'); + // this.assertAttr('size', '20'); //NOTE: failing in IE (TEST_SUITE=sauce) + // this.assertAttr('tabindex', '30'); //NOTE: failing in IE (TEST_SUITE=sauce) + + this.runTask(() => this.rerender()); + + this.assertDisabled(); + this.assertValue('Original value'); + this.assertAttr('placeholder', 'Original placeholder'); + this.assertAttr('name', 'original-name'); + this.assertAttr('maxlength', '10'); + this.assertAttr('minlength', '5'); + // this.assertAttr('size', '20'); //NOTE: failing in IE (TEST_SUITE=sauce) + // this.assertAttr('tabindex', '30'); //NOTE: failing in IE (TEST_SUITE=sauce) + } - this.assertDisabled(); - this.assertValue('Original value'); - this.assertAttr('placeholder', 'Original placeholder'); - this.assertAttr('name', 'original-name'); - this.assertAttr('maxlength', '10'); - this.assertAttr('minlength', '5'); - // this.assertAttr('size', '20'); //NOTE: failing in IE (TEST_SUITE=sauce) - // this.assertAttr('tabindex', '30'); //NOTE: failing in IE (TEST_SUITE=sauce) - - this.runTask(() => this.rerender()); - - this.assertDisabled(); - this.assertValue('Original value'); - this.assertAttr('placeholder', 'Original placeholder'); - this.assertAttr('name', 'original-name'); - this.assertAttr('maxlength', '10'); - this.assertAttr('minlength', '5'); - // this.assertAttr('size', '20'); //NOTE: failing in IE (TEST_SUITE=sauce) - // this.assertAttr('tabindex', '30'); //NOTE: failing in IE (TEST_SUITE=sauce) - } + ['@test cursor selection range']() { + // Modifying input.selectionStart, which is utilized in the cursor tests, + // causes an event in Safari. + runDestroy(this.owner.lookup('event_dispatcher:main')); - ['@test cursor selection range']() { - // Modifying input.selectionStart, which is utilized in the cursor tests, - // causes an event in Safari. - runDestroy(this.owner.lookup('event_dispatcher:main')); + this.render(`{{input type="text" value=value}}`, { value: 'original' }); - this.render(`{{input type="text" value=value}}`, { value: 'original' }); + let input = this.$input()[0]; - let input = this.$input()[0]; + // See https://ember-twiddle.com/33e506329f8176ae874422644d4cc08c?openFiles=components.input-component.js%2Ctemplates.components.input-component.hbs + // this.assertSelectionRange(8, 8); //NOTE: this is (0, 0) on Firefox (TEST_SUITE=sauce) - // See https://ember-twiddle.com/33e506329f8176ae874422644d4cc08c?openFiles=components.input-component.js%2Ctemplates.components.input-component.hbs - // this.assertSelectionRange(8, 8); //NOTE: this is (0, 0) on Firefox (TEST_SUITE=sauce) + this.runTask(() => this.rerender()); - this.runTask(() => this.rerender()); + // this.assertSelectionRange(8, 8); //NOTE: this is (0, 0) on Firefox (TEST_SUITE=sauce) - // this.assertSelectionRange(8, 8); //NOTE: this is (0, 0) on Firefox (TEST_SUITE=sauce) + this.runTask(() => { + input.selectionStart = 2; + input.selectionEnd = 4; + }); - this.runTask(() => { - input.selectionStart = 2; - input.selectionEnd = 4; - }); + this.assertSelectionRange(2, 4); - this.assertSelectionRange(2, 4); + this.runTask(() => this.rerender()); - this.runTask(() => this.rerender()); + this.assertSelectionRange(2, 4); - this.assertSelectionRange(2, 4); - - // this.runTask(() => set(this.context, 'value', 'updated')); - // - // this.assertSelectionRange(7, 7); //NOTE: this fails in IE, the range is 0 -> 0 (TEST_SUITE=sauce) - // - // this.runTask(() => set(this.context, 'value', 'original')); - // - // this.assertSelectionRange(8, 8); //NOTE: this fails in IE, the range is 0 -> 0 (TEST_SUITE=sauce) - } + // this.runTask(() => set(this.context, 'value', 'updated')); + // + // this.assertSelectionRange(7, 7); //NOTE: this fails in IE, the range is 0 -> 0 (TEST_SUITE=sauce) + // + // this.runTask(() => set(this.context, 'value', 'original')); + // + // this.assertSelectionRange(8, 8); //NOTE: this fails in IE, the range is 0 -> 0 (TEST_SUITE=sauce) + } - ['@test sends an action with `{{input enter="foo"}}` when is pressed'](assert) { - assert.expect(1); + ['@test sends an action with `{{input enter="foo"}}` when is pressed']( + assert + ) { + assert.expect(1); - this.render(`{{input enter='foo'}}`, { - actions: { - foo() { - assert.ok(true, 'action was triggered'); + this.render(`{{input enter='foo'}}`, { + actions: { + foo() { + assert.ok(true, 'action was triggered'); + } } - } - }); + }); - this.triggerEvent('keyup', { - keyCode: 13 - }); - } + this.triggerEvent('keyup', { + keyCode: 13 + }); + } - ['@test sends an action with `{{input key-press="foo"}}` is pressed'](assert) { - assert.expect(1); + ['@test sends an action with `{{input key-press="foo"}}` is pressed']( + assert + ) { + assert.expect(1); - this.render(`{{input value=value key-press='foo'}}`, { - value: 'initial', + this.render(`{{input value=value key-press='foo'}}`, { + value: 'initial', - actions: { - foo() { - assert.ok(true, 'action was triggered'); + actions: { + foo() { + assert.ok(true, 'action was triggered'); + } } - } - }); + }); - this.triggerEvent('keypress', { - keyCode: 65 - }); - } + this.triggerEvent('keypress', { + keyCode: 65 + }); + } - ['@test sends an action to the parent level when `bubbles=true` is provided'](assert) { - assert.expect(1); + ['@test sends an action to the parent level when `bubbles=true` is provided']( + assert + ) { + assert.expect(1); - let ParentComponent = Component.extend({ - change() { - assert.ok(true, 'bubbled upwards'); - } - }); + let ParentComponent = Component.extend({ + change() { + assert.ok(true, 'bubbled upwards'); + } + }); - this.registerComponent('x-parent', { - ComponentClass: ParentComponent, - template: `{{input bubbles=true}}` - }); - this.render(`{{x-parent}}`); + this.registerComponent('x-parent', { + ComponentClass: ParentComponent, + template: `{{input bubbles=true}}` + }); + this.render(`{{x-parent}}`); - this.triggerEvent('change'); - } + this.triggerEvent('change'); + } - ['@test triggers `focus-in` when focused'](assert) { - let wasFocused = false; + ['@test triggers `focus-in` when focused'](assert) { + let wasFocused = false; - this.render(`{{input focus-in='foo'}}`, { - actions: { - foo() { - wasFocused = true; + this.render(`{{input focus-in='foo'}}`, { + actions: { + foo() { + wasFocused = true; + } } - } - }); + }); - this.runTask(() => { this.$input().focus(); }); + this.runTask(() => { + this.$input().focus(); + }); - assert.ok(wasFocused, 'action was triggered'); - } + assert.ok(wasFocused, 'action was triggered'); + } - ['@test sends `insert-newline` when is pressed'](assert) { - assert.expect(1); + ['@test sends `insert-newline` when is pressed'](assert) { + assert.expect(1); - this.render(`{{input insert-newline='foo'}}`, { - actions: { - foo() { - assert.ok(true, 'action was triggered'); + this.render(`{{input insert-newline='foo'}}`, { + actions: { + foo() { + assert.ok(true, 'action was triggered'); + } } - } - }); + }); - this.triggerEvent('keyup', { - keyCode: 13 - }); - } + this.triggerEvent('keyup', { + keyCode: 13 + }); + } - ['@test sends an action with `{{input escape-press="foo"}}` when is pressed'](assert) { - assert.expect(1); + ['@test sends an action with `{{input escape-press="foo"}}` when is pressed']( + assert + ) { + assert.expect(1); - this.render(`{{input escape-press='foo'}}`, { - actions: { - foo() { - assert.ok(true, 'action was triggered'); + this.render(`{{input escape-press='foo'}}`, { + actions: { + foo() { + assert.ok(true, 'action was triggered'); + } } - } - }); + }); - this.triggerEvent('keyup', { - keyCode: 27 - }); - } + this.triggerEvent('keyup', { + keyCode: 27 + }); + } - ['@test sends an action with `{{input key-down="foo"}}` when a key is pressed'](assert) { - assert.expect(1); + ['@test sends an action with `{{input key-down="foo"}}` when a key is pressed']( + assert + ) { + assert.expect(1); - this.render(`{{input key-down='foo'}}`, { - actions: { - foo() { - assert.ok(true, 'action was triggered'); + this.render(`{{input key-down='foo'}}`, { + actions: { + foo() { + assert.ok(true, 'action was triggered'); + } } - } - }); + }); - this.triggerEvent('keydown', { - keyCode: 65 - }); - } + this.triggerEvent('keydown', { + keyCode: 65 + }); + } - ['@test sends an action with `{{input key-up="foo"}}` when a key is pressed'](assert) { - assert.expect(1); + ['@test sends an action with `{{input key-up="foo"}}` when a key is pressed']( + assert + ) { + assert.expect(1); - this.render(`{{input key-up='foo'}}`, { - actions: { - foo() { - assert.ok(true, 'action was triggered'); + this.render(`{{input key-up='foo'}}`, { + actions: { + foo() { + assert.ok(true, 'action was triggered'); + } } - } - }); + }); - this.triggerEvent('keyup', { - keyCode: 65 - }); - } + this.triggerEvent('keyup', { + keyCode: 65 + }); + } - ['@test GH#14727 can render a file input after having had render an input of other type']() { - this.render(`{{input type="text"}}{{input type="file"}}`); + ['@test GH#14727 can render a file input after having had render an input of other type']() { + this.render(`{{input type="text"}}{{input type="file"}}`); - this.assert.equal(this.$input()[0].type, 'text'); - this.assert.equal(this.$input()[1].type, 'file'); + this.assert.equal(this.$input()[0].type, 'text'); + this.assert.equal(this.$input()[1].type, 'file'); + } } -}); +); -moduleFor('Helpers test: {{input}} with dynamic type', class extends InputRenderingTest { +moduleFor( + 'Helpers test: {{input}} with dynamic type', + class extends InputRenderingTest { + ['@test a bound property can be used to determine type']() { + this.render(`{{input type=type}}`, { type: 'password' }); - ['@test a bound property can be used to determine type']() { - this.render(`{{input type=type}}`, { type: 'password' }); + this.assertAttr('type', 'password'); - this.assertAttr('type', 'password'); + this.runTask(() => this.rerender()); - this.runTask(() => this.rerender()); + this.assertAttr('type', 'password'); - this.assertAttr('type', 'password'); + this.runTask(() => set(this.context, 'type', 'text')); - this.runTask(() => set(this.context, 'type', 'text')); + this.assertAttr('type', 'text'); - this.assertAttr('type', 'text'); + this.runTask(() => set(this.context, 'type', 'password')); - this.runTask(() => set(this.context, 'type', 'password')); - - this.assertAttr('type', 'password'); - } + this.assertAttr('type', 'password'); + } - ['@test a subexpression can be used to determine type']() { - this.render(`{{input type=(if isTruthy trueType falseType)}}`, { - isTruthy: true, - trueType: 'text', - falseType: 'password' - }); + ['@test a subexpression can be used to determine type']() { + this.render(`{{input type=(if isTruthy trueType falseType)}}`, { + isTruthy: true, + trueType: 'text', + falseType: 'password' + }); - this.assertAttr('type', 'text'); + this.assertAttr('type', 'text'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertAttr('type', 'text'); + this.assertAttr('type', 'text'); - this.runTask(() => set(this.context, 'isTruthy', false)); + this.runTask(() => set(this.context, 'isTruthy', false)); - this.assertAttr('type', 'password'); + this.assertAttr('type', 'password'); - this.runTask(() => set(this.context, 'isTruthy', true)); + this.runTask(() => set(this.context, 'isTruthy', true)); - this.assertAttr('type', 'text'); - } + this.assertAttr('type', 'text'); + } - ['@test GH16256 input macro does not modify params in place']() { - this.registerComponent('my-input', { - template: `{{input type=inputType}}` - }); + ['@test GH16256 input macro does not modify params in place']() { + this.registerComponent('my-input', { + template: `{{input type=inputType}}` + }); - this.render(`{{my-input inputType=firstType}}{{my-input inputType=secondType}}`, { - firstType: 'password', - secondType: 'email' - }); + this.render( + `{{my-input inputType=firstType}}{{my-input inputType=secondType}}`, + { + firstType: 'password', + secondType: 'email' + } + ); - let inputs = this.element.querySelectorAll('input'); - this.assert.equal(inputs.length, 2, 'there are two inputs'); - this.assert.equal(inputs[0].getAttribute('type'), 'password'); - this.assert.equal(inputs[1].getAttribute('type'), 'email'); + let inputs = this.element.querySelectorAll('input'); + this.assert.equal(inputs.length, 2, 'there are two inputs'); + this.assert.equal(inputs[0].getAttribute('type'), 'password'); + this.assert.equal(inputs[1].getAttribute('type'), 'email'); + } } -}); +); -moduleFor(`Helpers test: {{input type='checkbox'}}`, class extends InputRenderingTest { - - ['@test dynamic attributes']() { - this.render(`{{input +moduleFor( + `Helpers test: {{input type='checkbox'}}`, + class extends InputRenderingTest { + ['@test dynamic attributes']() { + this.render( + `{{input type='checkbox' disabled=disabled name=name checked=checked tabindex=tabindex - }}`, { - disabled: false, - name: 'original-name', - checked: false, - tabindex: 10 - }); - - this.assertSingleCheckbox(); - this.assertNotDisabled(); - this.assertAttr('name', 'original-name'); - this.assertAttr('tabindex', '10'); - - this.runTask(() => this.rerender()); - - this.assertSingleCheckbox(); - this.assertNotDisabled(); - this.assertAttr('name', 'original-name'); - this.assertAttr('tabindex', '10'); - - this.runTask(() => { - set(this.context, 'disabled', true); - set(this.context, 'name', 'updated-name'); - set(this.context, 'tabindex', 11); - }); - - this.assertSingleCheckbox(); - this.assertDisabled(); - this.assertAttr('name', 'updated-name'); - this.assertAttr('tabindex', '11'); - - this.runTask(() => { - set(this.context, 'disabled', false); - set(this.context, 'name', 'original-name'); - set(this.context, 'tabindex', 10); - }); - - this.assertSingleCheckbox(); - this.assertNotDisabled(); - this.assertAttr('name', 'original-name'); - this.assertAttr('tabindex', '10'); - } + }}`, + { + disabled: false, + name: 'original-name', + checked: false, + tabindex: 10 + } + ); + + this.assertSingleCheckbox(); + this.assertNotDisabled(); + this.assertAttr('name', 'original-name'); + this.assertAttr('tabindex', '10'); + + this.runTask(() => this.rerender()); + + this.assertSingleCheckbox(); + this.assertNotDisabled(); + this.assertAttr('name', 'original-name'); + this.assertAttr('tabindex', '10'); + + this.runTask(() => { + set(this.context, 'disabled', true); + set(this.context, 'name', 'updated-name'); + set(this.context, 'tabindex', 11); + }); + + this.assertSingleCheckbox(); + this.assertDisabled(); + this.assertAttr('name', 'updated-name'); + this.assertAttr('tabindex', '11'); + + this.runTask(() => { + set(this.context, 'disabled', false); + set(this.context, 'name', 'original-name'); + set(this.context, 'tabindex', 10); + }); + + this.assertSingleCheckbox(); + this.assertNotDisabled(); + this.assertAttr('name', 'original-name'); + this.assertAttr('tabindex', '10'); + } - ['@test `value` property assertion']() { - expectAssertion(() => { - this.render(`{{input type="checkbox" value=value}}`, { value: 'value' }); - }, /you must use `checked=/); - } + ['@test `value` property assertion']() { + expectAssertion(() => { + this.render(`{{input type="checkbox" value=value}}`, { + value: 'value' + }); + }, /you must use `checked=/); + } - ['@test with a bound type']() { - this.render(`{{input type=inputType checked=isChecked}}`, { inputType: 'checkbox', isChecked: true }); + ['@test with a bound type']() { + this.render(`{{input type=inputType checked=isChecked}}`, { + inputType: 'checkbox', + isChecked: true + }); - this.assertSingleCheckbox(); - this.assertCheckboxIsChecked(); + this.assertSingleCheckbox(); + this.assertCheckboxIsChecked(); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertCheckboxIsChecked(); + this.assertCheckboxIsChecked(); - this.runTask(() => set(this.context, 'isChecked', false)); + this.runTask(() => set(this.context, 'isChecked', false)); - this.assertCheckboxIsNotChecked(); + this.assertCheckboxIsNotChecked(); - this.runTask(() => set(this.context, 'isChecked', true)); + this.runTask(() => set(this.context, 'isChecked', true)); - this.assertCheckboxIsChecked(); - } + this.assertCheckboxIsChecked(); + } - ['@test native click changes check property']() { - this.render(`{{input type="checkbox"}}`); + ['@test native click changes check property']() { + this.render(`{{input type="checkbox"}}`); - this.assertSingleCheckbox(); - this.assertCheckboxIsNotChecked(); - this.$input()[0].click(); - this.assertCheckboxIsChecked(); - this.$input()[0].click(); - this.assertCheckboxIsNotChecked(); - } + this.assertSingleCheckbox(); + this.assertCheckboxIsNotChecked(); + this.$input()[0].click(); + this.assertCheckboxIsChecked(); + this.$input()[0].click(); + this.assertCheckboxIsNotChecked(); + } - ['@test with static values']() { - this.render(`{{input type="checkbox" disabled=false tabindex=10 name="original-name" checked=false}}`); + ['@test with static values']() { + this.render( + `{{input type="checkbox" disabled=false tabindex=10 name="original-name" checked=false}}` + ); - this.assertSingleCheckbox(); - this.assertCheckboxIsNotChecked(); - this.assertNotDisabled(); - this.assertAttr('tabindex', '10'); - this.assertAttr('name', 'original-name'); + this.assertSingleCheckbox(); + this.assertCheckboxIsNotChecked(); + this.assertNotDisabled(); + this.assertAttr('tabindex', '10'); + this.assertAttr('name', 'original-name'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertSingleCheckbox(); - this.assertCheckboxIsNotChecked(); - this.assertNotDisabled(); - this.assertAttr('tabindex', '10'); - this.assertAttr('name', 'original-name'); + this.assertSingleCheckbox(); + this.assertCheckboxIsNotChecked(); + this.assertNotDisabled(); + this.assertAttr('tabindex', '10'); + this.assertAttr('name', 'original-name'); + } } -}); - -moduleFor(`Helpers test: {{input type='text'}}`, class extends InputRenderingTest { - - ['@test null values']() { - let attributes = ['disabled', 'placeholder', 'name', 'maxlength', 'size', 'tabindex']; - - this.render(` +); + +moduleFor( + `Helpers test: {{input type='text'}}`, + class extends InputRenderingTest { + ['@test null values']() { + let attributes = [ + 'disabled', + 'placeholder', + 'name', + 'maxlength', + 'size', + 'tabindex' + ]; + + this.render( + ` {{input type="text" disabled=disabled value=value @@ -584,62 +666,64 @@ moduleFor(`Helpers test: {{input type='text'}}`, class extends InputRenderingTes maxlength=maxlength size=size tabindex=tabindex - }}`, { - disabled: null, - value: null, - placeholder: null, - name: null, - maxlength: null, - size: null, - tabindex: null - } - ); - - this.assertValue(''); - this.assertAllAttrs(attributes, undefined); - - this.runTask(() => this.rerender()); - - this.assertValue(''); - this.assertAllAttrs(attributes, undefined); - - this.runTask(() => { - set(this.context, 'disabled', true); - set(this.context, 'value', 'Updated value'); - set(this.context, 'placeholder', 'Updated placeholder'); - set(this.context, 'name', 'updated-name'); - set(this.context, 'maxlength', 11); - set(this.context, 'size', 21); - set(this.context, 'tabindex', 31); - }); - - this.assertDisabled(); - this.assertValue('Updated value'); - this.assertAttr('placeholder', 'Updated placeholder'); - this.assertAttr('name', 'updated-name'); - this.assertAttr('maxlength', '11'); - this.assertAttr('size', '21'); - this.assertAttr('tabindex', '31'); - - this.runTask(() => { - set(this.context, 'disabled', null); - set(this.context, 'value', null); - set(this.context, 'placeholder', null); - set(this.context, 'name', null); - set(this.context, 'maxlength', null); - // set(this.context, 'size', null); //NOTE: this fails with `Error: Failed to set the 'size' property on 'HTMLInputElement': The value provided is 0, which is an invalid size.` (TEST_SUITE=sauce) - set(this.context, 'tabindex', null); - }); - - this.assertAttr('disabled', undefined); - this.assertValue(''); - // this.assertAttr('placeholder', undefined); //NOTE: this fails with a value of "null" (TEST_SUITE=sauce) - // this.assertAttr('name', undefined); //NOTE: this fails with a value of "null" (TEST_SUITE=sauce) - this.assertAttr('maxlength', undefined); - // this.assertAttr('size', undefined); //NOTE: re-enable once `size` bug above has been addressed - this.assertAttr('tabindex', undefined); + }}`, + { + disabled: null, + value: null, + placeholder: null, + name: null, + maxlength: null, + size: null, + tabindex: null + } + ); + + this.assertValue(''); + this.assertAllAttrs(attributes, undefined); + + this.runTask(() => this.rerender()); + + this.assertValue(''); + this.assertAllAttrs(attributes, undefined); + + this.runTask(() => { + set(this.context, 'disabled', true); + set(this.context, 'value', 'Updated value'); + set(this.context, 'placeholder', 'Updated placeholder'); + set(this.context, 'name', 'updated-name'); + set(this.context, 'maxlength', 11); + set(this.context, 'size', 21); + set(this.context, 'tabindex', 31); + }); + + this.assertDisabled(); + this.assertValue('Updated value'); + this.assertAttr('placeholder', 'Updated placeholder'); + this.assertAttr('name', 'updated-name'); + this.assertAttr('maxlength', '11'); + this.assertAttr('size', '21'); + this.assertAttr('tabindex', '31'); + + this.runTask(() => { + set(this.context, 'disabled', null); + set(this.context, 'value', null); + set(this.context, 'placeholder', null); + set(this.context, 'name', null); + set(this.context, 'maxlength', null); + // set(this.context, 'size', null); //NOTE: this fails with `Error: Failed to set the 'size' property on 'HTMLInputElement': The value provided is 0, which is an invalid size.` (TEST_SUITE=sauce) + set(this.context, 'tabindex', null); + }); + + this.assertAttr('disabled', undefined); + this.assertValue(''); + // this.assertAttr('placeholder', undefined); //NOTE: this fails with a value of "null" (TEST_SUITE=sauce) + // this.assertAttr('name', undefined); //NOTE: this fails with a value of "null" (TEST_SUITE=sauce) + this.assertAttr('maxlength', undefined); + // this.assertAttr('size', undefined); //NOTE: re-enable once `size` bug above has been addressed + this.assertAttr('tabindex', undefined); + } } -}); +); // These are the permutations of the set: // ['type="range"', 'min="-5" max="50"', 'value="%x"'] @@ -649,36 +733,39 @@ moduleFor(`Helpers test: {{input type='text'}}`, class extends InputRenderingTes 'min="-5" max="50" type="range" value="%x"', 'min="-5" max="50" value="%x" type="range"', 'value="%x" min="-5" max="50" type="range"', - 'value="%x" type="range" min="-5" max="50"', + 'value="%x" type="range" min="-5" max="50"' ].forEach(attrs => { - moduleFor(`[GH#15675] Helpers test: {{input ${attrs}}}`, class extends InputRenderingTest { - renderInput(value = 25) { - this.render(`{{input ${ attrs.replace("%x", value) }}}`); - } + moduleFor( + `[GH#15675] Helpers test: {{input ${attrs}}}`, + class extends InputRenderingTest { + renderInput(value = 25) { + this.render(`{{input ${attrs.replace('%x', value)}}}`); + } - ['@test value over default max but below set max is kept']() { - this.renderInput("25"); - this.assertValue("25"); - } + ['@test value over default max but below set max is kept']() { + this.renderInput('25'); + this.assertValue('25'); + } - ['@test value below default min but above set min is kept']() { - this.renderInput("-2"); - this.assertValue("-2"); - } + ['@test value below default min but above set min is kept']() { + this.renderInput('-2'); + this.assertValue('-2'); + } - ['@test in the valid default range is kept']() { - this.renderInput("5"); - this.assertValue("5"); - } + ['@test in the valid default range is kept']() { + this.renderInput('5'); + this.assertValue('5'); + } - ['@test value above max is reset to max']() { - this.renderInput("55"); - this.assertValue("50"); - } + ['@test value above max is reset to max']() { + this.renderInput('55'); + this.assertValue('50'); + } - ['@test value below min is reset to min']() { - this.renderInput("-10"); - this.assertValue("-5"); + ['@test value below min is reset to min']() { + this.renderInput('-10'); + this.assertValue('-5'); + } } - }); + ); }); diff --git a/packages/ember-glimmer/tests/integration/helpers/loc-test.js b/packages/ember-glimmer/tests/integration/helpers/loc-test.js index 09beae4b607..a3bb131fb66 100644 --- a/packages/ember-glimmer/tests/integration/helpers/loc-test.js +++ b/packages/ember-glimmer/tests/integration/helpers/loc-test.js @@ -2,94 +2,126 @@ import { RenderingTest, moduleFor } from '../../utils/test-case'; import { set } from 'ember-metal'; import { setStrings } from 'ember-runtime'; -moduleFor('Helpers test: {{loc}}', class extends RenderingTest { +moduleFor( + 'Helpers test: {{loc}}', + class extends RenderingTest { + constructor() { + super(); + setStrings({ + 'Hello Friend': 'Hallo Freund', + Hello: 'Hallo, %@' + }); + } - constructor() { - super(); - setStrings({ - 'Hello Friend': 'Hallo Freund', - 'Hello': 'Hallo, %@' - }); - } - - teardown() { - super.teardown(); - setStrings({}); - } + teardown() { + super.teardown(); + setStrings({}); + } - ['@test it lets the original value through by default']() { - this.render(`{{loc "Hiya buddy!"}}`); - this.assertText('Hiya buddy!', 'the unlocalized string is correct'); - this.runTask(() => this.rerender()); - this.assertText('Hiya buddy!', 'the unlocalized string is correct after rerender'); - } + ['@test it lets the original value through by default']() { + this.render(`{{loc "Hiya buddy!"}}`); + this.assertText('Hiya buddy!', 'the unlocalized string is correct'); + this.runTask(() => this.rerender()); + this.assertText( + 'Hiya buddy!', + 'the unlocalized string is correct after rerender' + ); + } - ['@test it localizes a simple string']() { - this.render(`{{loc "Hello Friend"}}`); - this.assertText('Hallo Freund', 'the localized string is correct'); - this.runTask(() => this.rerender()); - this.assertText('Hallo Freund', 'the localized string is correct after rerender'); - } + ['@test it localizes a simple string']() { + this.render(`{{loc "Hello Friend"}}`); + this.assertText('Hallo Freund', 'the localized string is correct'); + this.runTask(() => this.rerender()); + this.assertText( + 'Hallo Freund', + 'the localized string is correct after rerender' + ); + } - ['@test it takes passed formats into an account']() { - this.render(`{{loc "%@, %@" "Hello" "Mr. Pitkin"}}`); - this.assertText('Hello, Mr. Pitkin', 'the formatted string is correct'); - this.runTask(() => this.rerender()); - this.assertText('Hello, Mr. Pitkin', 'the formatted string is correct after rerender'); - } + ['@test it takes passed formats into an account']() { + this.render(`{{loc "%@, %@" "Hello" "Mr. Pitkin"}}`); + this.assertText('Hello, Mr. Pitkin', 'the formatted string is correct'); + this.runTask(() => this.rerender()); + this.assertText( + 'Hello, Mr. Pitkin', + 'the formatted string is correct after rerender' + ); + } - ['@test it updates when bound params change']() { - this.render(`{{loc simple}} - {{loc personal 'Mr. Pitkin'}}`, { - simple: 'Hello Friend', - personal: 'Hello' - }); - this.assertText('Hallo Freund - Hallo, Mr. Pitkin', - 'the bound value is correct'); + ['@test it updates when bound params change']() { + this.render(`{{loc simple}} - {{loc personal 'Mr. Pitkin'}}`, { + simple: 'Hello Friend', + personal: 'Hello' + }); + this.assertText( + 'Hallo Freund - Hallo, Mr. Pitkin', + 'the bound value is correct' + ); - this.runTask(() => this.rerender()); - this.assertText('Hallo Freund - Hallo, Mr. Pitkin', - 'the bound value is correct after rerender'); + this.runTask(() => this.rerender()); + this.assertText( + 'Hallo Freund - Hallo, Mr. Pitkin', + 'the bound value is correct after rerender' + ); - this.runTask(() => set(this.context, 'simple', 'G\'day mate')); - this.assertText('G\'day mate - Hallo, Mr. Pitkin', - 'the bound value is correct after update'); + this.runTask(() => set(this.context, 'simple', "G'day mate")); + this.assertText( + "G'day mate - Hallo, Mr. Pitkin", + 'the bound value is correct after update' + ); - this.runTask(() => set(this.context, 'simple', 'Hello Friend')); - this.assertText('Hallo Freund - Hallo, Mr. Pitkin', - 'the bound value is correct after reset'); - } + this.runTask(() => set(this.context, 'simple', 'Hello Friend')); + this.assertText( + 'Hallo Freund - Hallo, Mr. Pitkin', + 'the bound value is correct after reset' + ); + } - ['@test it updates when nested bound params change']() { - this.render(`{{loc greetings.simple}} - {{loc greetings.personal 'Mr. Pitkin'}}`, { - greetings: { - simple: 'Hello Friend', - personal: 'Hello' - } - }); - this.assertText('Hallo Freund - Hallo, Mr. Pitkin', - 'the bound value is correct'); + ['@test it updates when nested bound params change']() { + this.render( + `{{loc greetings.simple}} - {{loc greetings.personal 'Mr. Pitkin'}}`, + { + greetings: { + simple: 'Hello Friend', + personal: 'Hello' + } + } + ); + this.assertText( + 'Hallo Freund - Hallo, Mr. Pitkin', + 'the bound value is correct' + ); - this.runTask(() => this.rerender()); - this.assertText('Hallo Freund - Hallo, Mr. Pitkin', - 'the bound value is correct after rerender'); + this.runTask(() => this.rerender()); + this.assertText( + 'Hallo Freund - Hallo, Mr. Pitkin', + 'the bound value is correct after rerender' + ); - this.runTask(() => set(this.context, 'greetings.simple', 'G\'day mate')); - this.assertText('G\'day mate - Hallo, Mr. Pitkin', - 'the bound value is correct after interior mutation'); + this.runTask(() => set(this.context, 'greetings.simple', "G'day mate")); + this.assertText( + "G'day mate - Hallo, Mr. Pitkin", + 'the bound value is correct after interior mutation' + ); - this.runTask(() => set(this.context, 'greetings', { - simple: 'Hello Friend', - personal: 'Hello' - })); - this.assertText('Hallo Freund - Hallo, Mr. Pitkin', - 'the bound value is correct after replacement'); - } + this.runTask(() => + set(this.context, 'greetings', { + simple: 'Hello Friend', + personal: 'Hello' + }) + ); + this.assertText( + 'Hallo Freund - Hallo, Mr. Pitkin', + 'the bound value is correct after replacement' + ); + } - ['@test it can be overriden']() { - this.registerHelper('loc', () => 'Yup'); - this.render(`{{loc greeting}}`, { - greeting: 'Hello Friend' - }); - this.assertText('Yup', 'the localized string is correct'); + ['@test it can be overriden']() { + this.registerHelper('loc', () => 'Yup'); + this.render(`{{loc greeting}}`, { + greeting: 'Hello Friend' + }); + this.assertText('Yup', 'the localized string is correct'); + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/helpers/log-test.js b/packages/ember-glimmer/tests/integration/helpers/log-test.js index 8385344e324..ac88a71f555 100644 --- a/packages/ember-glimmer/tests/integration/helpers/log-test.js +++ b/packages/ember-glimmer/tests/integration/helpers/log-test.js @@ -1,61 +1,61 @@ import { RenderingTest, moduleFor } from '../../utils/test-case'; +moduleFor( + 'Helpers test: {{log}}', + class extends RenderingTest { + constructor() { + super(); + /* eslint-disable no-console */ + this.originalLog = console.log; + this.logCalls = []; + console.log = (...args) => { + this.logCalls.push(...args); + /* eslint-enable no-console */ + }; + } -moduleFor('Helpers test: {{log}}', class extends RenderingTest { - - constructor() { - super(); - /* eslint-disable no-console */ - this.originalLog = console.log; - this.logCalls = []; - console.log = (...args) => { - this.logCalls.push(...args); - /* eslint-enable no-console */ - }; - } - - teardown() { - super.teardown(); - /* eslint-disable no-console */ - console.log = this.originalLog; - /* eslint-enable no-console */ - } + teardown() { + super.teardown(); + /* eslint-disable no-console */ + console.log = this.originalLog; + /* eslint-enable no-console */ + } - assertLog(values) { - this.assertText(''); - this.assert.strictEqual(this.logCalls.length, values.length); + assertLog(values) { + this.assertText(''); + this.assert.strictEqual(this.logCalls.length, values.length); - for (let i = 0, len = values.length; i < len; i++) { - this.assert.strictEqual(this.logCalls[i], values[i]); + for (let i = 0, len = values.length; i < len; i++) { + this.assert.strictEqual(this.logCalls[i], values[i]); + } } - } - ['@test correctly logs primitives']() { - this.render(`{{log "one" 1 true}}`); + ['@test correctly logs primitives']() { + this.render(`{{log "one" 1 true}}`); - this.assertLog(['one', 1, true]); - } + this.assertLog(['one', 1, true]); + } - ['@test correctly logs a property']() { - this.render(`{{log value}}`, { - value: 'one' - }); + ['@test correctly logs a property']() { + this.render(`{{log value}}`, { + value: 'one' + }); - this.assertLog(['one']); - } + this.assertLog(['one']); + } - ['@test correctly logs multiple arguments']() { - this.render(`{{log "my variable:" value}}`, { - value: 'one' - }); + ['@test correctly logs multiple arguments']() { + this.render(`{{log "my variable:" value}}`, { + value: 'one' + }); - this.assertLog(['my variable:', 'one']); - } + this.assertLog(['my variable:', 'one']); + } - ['@test correctly logs `this`']() { - this.render(`{{log this}}`); + ['@test correctly logs `this`']() { + this.render(`{{log this}}`); - this.assertLog([this.context]); + this.assertLog([this.context]); + } } - -}); +); diff --git a/packages/ember-glimmer/tests/integration/helpers/mut-test.js b/packages/ember-glimmer/tests/integration/helpers/mut-test.js index 31a67446354..5785545f9c8 100644 --- a/packages/ember-glimmer/tests/integration/helpers/mut-test.js +++ b/packages/ember-glimmer/tests/integration/helpers/mut-test.js @@ -3,531 +3,702 @@ import { Component, htmlSafe } from '../../utils/helpers'; import { set, get, computed } from 'ember-metal'; import { styles } from '../../utils/test-helpers'; -moduleFor('Helpers test: {{mut}}', class extends RenderingTest { - - ['@test a simple mutable binding using `mut` propagates properly']() { - let bottom; - - this.registerComponent('bottom-mut', { - ComponentClass: Component.extend({ - didInsertElement() { - bottom = this; - } - }), - template: '{{setMe}}' - }); - - this.registerComponent('middle-mut', { - template: '{{bottom-mut setMe=value}}' - }); - - this.render('{{middle-mut value=(mut val)}}', { - val: 12 - }); - - this.assertText('12', 'the data propagated downwards'); - - this.assertStableRerender(); - - this.runTask(() => bottom.attrs.setMe.update(13)); - - this.assertText('13', 'the set took effect'); - this.assert.strictEqual(get(bottom, 'setMe'), 13, 'the set took effect on bottom\'s prop'); - this.assert.strictEqual(bottom.attrs.setMe.value, 13, 'the set took effect on bottom\'s attr'); - this.assert.strictEqual(get(this.context, 'val'), 13, 'the set propagated back up'); - - this.runTask(() => set(bottom, 'setMe', 14)); - - this.assertText('14', 'the set took effect'); - this.assert.strictEqual(get(bottom, 'setMe'), 14, 'the set took effect on bottom\'s prop'); - this.assert.strictEqual(bottom.attrs.setMe.value, 14, 'the set took effect on bottom\'s attr'); - this.assert.strictEqual(get(this.context, 'val'), 14, 'the set propagated back up'); - - this.runTask(() => set(this.context, 'val', 12)); - - this.assertText('12'); - } - - ['@test a simple mutable binding using `mut` inserts into the DOM']() { - let bottom, middle; - - this.registerComponent('bottom-mut', { - ComponentClass: Component.extend({ - didInsertElement() { - bottom = this; - } - }), - template: '{{setMe}}' - }); - - this.registerComponent('middle-mut', { - ComponentClass: Component.extend({ - didInsertElement() { - middle = this; - } - }), - template: '{{bottom-mut setMe=(mut value)}}' - }); - - this.render('{{middle-mut value=(mut val)}}', { - val: 12 - }); - - this.assertText('12', 'the data propagated downwards'); - - this.assertStableRerender(); - - this.runTask(() => bottom.attrs.setMe.update(13)); - - this.assertText('13', 'the set took effect'); - this.assert.strictEqual(get(bottom, 'setMe'), 13, 'the set took effect on bottom\'s prop'); - this.assert.strictEqual(bottom.attrs.setMe.value, 13, 'the set took effect on bottom\'s attr'); - this.assert.strictEqual(get(middle, 'value'), 13, 'the set propagated to middle\'s prop'); - this.assert.strictEqual(middle.attrs.value.value, 13, 'the set propagated to middle\'s attr'); - this.assert.strictEqual(get(this.context, 'val'), 13, 'the set propagated back up'); - - this.runTask(() => set(bottom, 'setMe', 14)); - - this.assertText('14', 'the set took effect'); - this.assert.strictEqual(get(bottom, 'setMe'), 14, 'the set took effect on bottom\'s prop'); - this.assert.strictEqual(bottom.attrs.setMe.value, 14, 'the set took effect on bottom\'s attr'); - this.assert.strictEqual(get(middle, 'value'), 14, 'the set propagated to middle\'s prop'); - this.assert.strictEqual(middle.attrs.value.value, 14, 'the set propagated to middle\'s attr'); - this.assert.strictEqual(get(this.context, 'val'), 14, 'the set propagated back up'); - - this.runTask(() => set(this.context, 'val', 12)); - - this.assertText('12'); - } - - ['@test passing a literal results in a assertion']() { - this.registerComponent('bottom-mut', { template: '{{setMe}}' }); - - expectAssertion(() => { - this.render('{{bottom-mut setMe=(mut "foo bar")}}'); - }, 'You can only pass a path to mut'); - } - - ['@test passing the result of a helper invocation results in an assertion']() { - this.registerComponent('bottom-mut', { template: '{{setMe}}' }); - - expectAssertion(() => { - this.render('{{bottom-mut setMe=(mut (concat "foo" " " "bar"))}}'); - }, 'You can only pass a path to mut'); - } - - // See https://github.com/emberjs/ember.js/commit/807a0cd for an explanation of this test - ['@test using a string value through middle tier does not trigger assertion (due to the auto-mut transform)']() { - let bottom; - - this.registerComponent('bottom-mut', { - ComponentClass: Component.extend({ - didInsertElement() { - bottom = this; - } - }), - template: '{{stuff}}' - }); - - this.registerComponent('middle-mut', { - template: '{{bottom-mut stuff=value}}' - }); - - this.render('{{middle-mut value="foo"}}'); - - this.assert.equal(get(bottom, 'stuff'), 'foo', 'the data propagated'); - this.assertText('foo'); - - this.assertStableRerender(); - - // No U-R for this test - } - - ['@test {{readonly}} of a {{mut}} is converted into an immutable binding']() { - let middle, bottom; - - this.registerComponent('bottom-mut', { - ComponentClass: Component.extend({ - didInsertElement() { - bottom = this; - } - }), - template: '{{setMe}}' - }); - - this.registerComponent('middle-mut', { - ComponentClass: Component.extend({ - didInsertElement() { - middle = this; - } - }), - template: '{{bottom-mut setMe=(readonly value)}}' - }); - - this.render('{{middle-mut value=(mut val)}}', { - val: 12 - }); - - this.assertText('12'); - - this.assertStableRerender(); - - this.runTask(() => middle.attrs.value.update(13)); - - this.assert.strictEqual(get(middle, 'value'), 13, 'the set took effect on middle\'s prop'); - this.assert.strictEqual(middle.attrs.value.value, 13, 'the set took effect on middle\'s attr'); - - this.runTask(() => set(middle, 'value', 14)); - - this.assert.strictEqual(get(middle, 'value'), 14, 'the set took effect on middle\'s prop'); - this.assert.strictEqual(middle.attrs.value.value, 14, 'the set took effect on middle\'s attr'); - this.assert.strictEqual(bottom.attrs.setMe, 14, 'the mutable binding has been converted to an immutable cell'); - this.assertText('14'); - this.assert.strictEqual(get(this.context, 'val'), 14, 'the set propagated back up'); - - this.runTask(() => set(this.context, 'val', 12)); - - this.assertText('12'); - } - - ['@test mutable bindings work inside of yielded content']() { - this.registerComponent('bottom-mut', { - template: '{{yield}}' - }); - - this.registerComponent('middle-mut', { - template: '{{#bottom-mut}}{{model.name}}{{/bottom-mut}}' - }); - - this.render('{{middle-mut model=(mut model)}}', { - model: { name: 'Matthew Beale' } - }); - - this.assertText('Matthew Beale'); - - this.assertStableRerender(); - - this.runTask(() => set(this.context, 'model.name', 'Joel Kang')); - - this.assertText('Joel Kang'); - - this.runTask(() => set(this.context, 'model', { name: 'Matthew Beale' })); - - this.assertText('Matthew Beale'); - } - - ['@test a simple mutable binding using {{mut}} is available in hooks']() { - let bottom; - let willRender = []; - let didInsert = []; - - this.registerComponent('bottom-mut', { - ComponentClass: Component.extend({ - willRender() { - willRender.push(get(this, 'setMe')); - }, - didInsertElement() { - didInsert.push(get(this, 'setMe')); - bottom = this; - } - }), - template: '{{setMe}}' - }); - - this.registerComponent('middle-mut', { - template: '{{bottom-mut setMe=(mut value)}}' - }); - - this.render('{{middle-mut value=(mut val)}}', { - val: 12 - }); - - this.assert.deepEqual(willRender, [12], 'willReceive is [12]'); - this.assert.deepEqual(didInsert, [12], 'didInsert is [12]'); - this.assertText('12'); - - this.assertStableRerender(); - - this.assert.deepEqual(willRender, [12], 'willReceive is [12]'); - this.assert.deepEqual(didInsert, [12], 'didInsert is [12]'); - this.assert.strictEqual(get(bottom, 'setMe'), 12, 'the data propagated'); - - this.runTask(() => bottom.attrs.setMe.update(13)); - - this.assert.strictEqual(get(bottom, 'setMe'), 13, 'the set took effect on bottom\'s prop'); - this.assert.strictEqual(bottom.attrs.setMe.value, 13, 'the set took effect on bottom\'s attr'); - this.assert.strictEqual(get(this.context, 'val'), 13, 'the set propagated back up'); - - this.runTask(() => set(bottom, 'setMe', 14)); - - this.assert.strictEqual(get(bottom, 'setMe'), 14, 'the set took effect on bottom\'s prop'); - this.assert.strictEqual(bottom.attrs.setMe.value, 14, 'the set took effect on bottom\'s attr'); - this.assert.strictEqual(get(this.context, 'val'), 14, 'the set propagated back up'); - - this.runTask(() => set(this.context, 'val', 12)); - - this.assertText('12'); - } - - ['@test a mutable binding with a backing computed property and attribute present in the root of the component is updated when the upstream property invalidates #11023']() { - let bottom, middle; - - this.registerComponent('bottom-mut', { - ComponentClass: Component.extend({ - thingy: null, - didInsertElement() { - bottom = this; - } - }), - template: '{{thingy}}' - }); - - this.registerComponent('middle-mut', { - ComponentClass: Component.extend({ - baseValue: 12, - val: computed('baseValue', function() { - return this.get('baseValue'); +moduleFor( + 'Helpers test: {{mut}}', + class extends RenderingTest { + ['@test a simple mutable binding using `mut` propagates properly']() { + let bottom; + + this.registerComponent('bottom-mut', { + ComponentClass: Component.extend({ + didInsertElement() { + bottom = this; + } }), - didInsertElement() { - middle = this; - } - }), - template: '{{bottom-mut thingy=(mut val)}}' - }); + template: '{{setMe}}' + }); + + this.registerComponent('middle-mut', { + template: '{{bottom-mut setMe=value}}' + }); + + this.render('{{middle-mut value=(mut val)}}', { + val: 12 + }); + + this.assertText('12', 'the data propagated downwards'); + + this.assertStableRerender(); + + this.runTask(() => bottom.attrs.setMe.update(13)); + + this.assertText('13', 'the set took effect'); + this.assert.strictEqual( + get(bottom, 'setMe'), + 13, + "the set took effect on bottom's prop" + ); + this.assert.strictEqual( + bottom.attrs.setMe.value, + 13, + "the set took effect on bottom's attr" + ); + this.assert.strictEqual( + get(this.context, 'val'), + 13, + 'the set propagated back up' + ); + + this.runTask(() => set(bottom, 'setMe', 14)); + + this.assertText('14', 'the set took effect'); + this.assert.strictEqual( + get(bottom, 'setMe'), + 14, + "the set took effect on bottom's prop" + ); + this.assert.strictEqual( + bottom.attrs.setMe.value, + 14, + "the set took effect on bottom's attr" + ); + this.assert.strictEqual( + get(this.context, 'val'), + 14, + 'the set propagated back up' + ); + + this.runTask(() => set(this.context, 'val', 12)); + + this.assertText('12'); + } + + ['@test a simple mutable binding using `mut` inserts into the DOM']() { + let bottom, middle; + + this.registerComponent('bottom-mut', { + ComponentClass: Component.extend({ + didInsertElement() { + bottom = this; + } + }), + template: '{{setMe}}' + }); - this.render('{{middle-mut}}'); + this.registerComponent('middle-mut', { + ComponentClass: Component.extend({ + didInsertElement() { + middle = this; + } + }), + template: '{{bottom-mut setMe=(mut value)}}' + }); + + this.render('{{middle-mut value=(mut val)}}', { + val: 12 + }); + + this.assertText('12', 'the data propagated downwards'); + + this.assertStableRerender(); + + this.runTask(() => bottom.attrs.setMe.update(13)); + + this.assertText('13', 'the set took effect'); + this.assert.strictEqual( + get(bottom, 'setMe'), + 13, + "the set took effect on bottom's prop" + ); + this.assert.strictEqual( + bottom.attrs.setMe.value, + 13, + "the set took effect on bottom's attr" + ); + this.assert.strictEqual( + get(middle, 'value'), + 13, + "the set propagated to middle's prop" + ); + this.assert.strictEqual( + middle.attrs.value.value, + 13, + "the set propagated to middle's attr" + ); + this.assert.strictEqual( + get(this.context, 'val'), + 13, + 'the set propagated back up' + ); + + this.runTask(() => set(bottom, 'setMe', 14)); + + this.assertText('14', 'the set took effect'); + this.assert.strictEqual( + get(bottom, 'setMe'), + 14, + "the set took effect on bottom's prop" + ); + this.assert.strictEqual( + bottom.attrs.setMe.value, + 14, + "the set took effect on bottom's attr" + ); + this.assert.strictEqual( + get(middle, 'value'), + 14, + "the set propagated to middle's prop" + ); + this.assert.strictEqual( + middle.attrs.value.value, + 14, + "the set propagated to middle's attr" + ); + this.assert.strictEqual( + get(this.context, 'val'), + 14, + 'the set propagated back up' + ); + + this.runTask(() => set(this.context, 'val', 12)); + + this.assertText('12'); + } + + ['@test passing a literal results in a assertion']() { + this.registerComponent('bottom-mut', { template: '{{setMe}}' }); + + expectAssertion(() => { + this.render('{{bottom-mut setMe=(mut "foo bar")}}'); + }, 'You can only pass a path to mut'); + } + + ['@test passing the result of a helper invocation results in an assertion']() { + this.registerComponent('bottom-mut', { template: '{{setMe}}' }); + + expectAssertion(() => { + this.render('{{bottom-mut setMe=(mut (concat "foo" " " "bar"))}}'); + }, 'You can only pass a path to mut'); + } + + // See https://github.com/emberjs/ember.js/commit/807a0cd for an explanation of this test + ['@test using a string value through middle tier does not trigger assertion (due to the auto-mut transform)']() { + let bottom; + + this.registerComponent('bottom-mut', { + ComponentClass: Component.extend({ + didInsertElement() { + bottom = this; + } + }), + template: '{{stuff}}' + }); - this.assert.strictEqual(get(bottom, 'thingy'), 12, 'data propagated'); - this.assertText('12'); + this.registerComponent('middle-mut', { + template: '{{bottom-mut stuff=value}}' + }); - this.assertStableRerender(); + this.render('{{middle-mut value="foo"}}'); - this.runTask(() => set(middle, 'baseValue', 13)); + this.assert.equal(get(bottom, 'stuff'), 'foo', 'the data propagated'); + this.assertText('foo'); - this.assert.strictEqual(get(middle, 'val'), 13, 'the set took effect'); - this.assert.strictEqual(bottom.attrs.thingy.value, 13, 'the set propagated down to bottom\'s attrs'); - this.assert.strictEqual(get(bottom, 'thingy'), 13, 'the set propagated down to bottom\'s prop'); - this.assertText('13'); + this.assertStableRerender(); - this.runTask(() => set(middle, 'baseValue', 12)); + // No U-R for this test + } - this.assertText('12'); - } + ['@test {{readonly}} of a {{mut}} is converted into an immutable binding']() { + let middle, bottom; - ['@test automatic mutable bindings exposes a mut cell in attrs']() { - let inner; + this.registerComponent('bottom-mut', { + ComponentClass: Component.extend({ + didInsertElement() { + bottom = this; + } + }), + template: '{{setMe}}' + }); - this.registerComponent('x-inner', { - ComponentClass: Component.extend({ - didInsertElement() { - inner = this; - } - }), - template: '{{foo}}' - }); + this.registerComponent('middle-mut', { + ComponentClass: Component.extend({ + didInsertElement() { + middle = this; + } + }), + template: '{{bottom-mut setMe=(readonly value)}}' + }); + + this.render('{{middle-mut value=(mut val)}}', { + val: 12 + }); + + this.assertText('12'); + + this.assertStableRerender(); + + this.runTask(() => middle.attrs.value.update(13)); + + this.assert.strictEqual( + get(middle, 'value'), + 13, + "the set took effect on middle's prop" + ); + this.assert.strictEqual( + middle.attrs.value.value, + 13, + "the set took effect on middle's attr" + ); + + this.runTask(() => set(middle, 'value', 14)); + + this.assert.strictEqual( + get(middle, 'value'), + 14, + "the set took effect on middle's prop" + ); + this.assert.strictEqual( + middle.attrs.value.value, + 14, + "the set took effect on middle's attr" + ); + this.assert.strictEqual( + bottom.attrs.setMe, + 14, + 'the mutable binding has been converted to an immutable cell' + ); + this.assertText('14'); + this.assert.strictEqual( + get(this.context, 'val'), + 14, + 'the set propagated back up' + ); + + this.runTask(() => set(this.context, 'val', 12)); + + this.assertText('12'); + } + + ['@test mutable bindings work inside of yielded content']() { + this.registerComponent('bottom-mut', { + template: '{{yield}}' + }); + + this.registerComponent('middle-mut', { + template: '{{#bottom-mut}}{{model.name}}{{/bottom-mut}}' + }); + + this.render('{{middle-mut model=(mut model)}}', { + model: { name: 'Matthew Beale' } + }); + + this.assertText('Matthew Beale'); + + this.assertStableRerender(); + + this.runTask(() => set(this.context, 'model.name', 'Joel Kang')); + + this.assertText('Joel Kang'); + + this.runTask(() => set(this.context, 'model', { name: 'Matthew Beale' })); + + this.assertText('Matthew Beale'); + } + + ['@test a simple mutable binding using {{mut}} is available in hooks']() { + let bottom; + let willRender = []; + let didInsert = []; + + this.registerComponent('bottom-mut', { + ComponentClass: Component.extend({ + willRender() { + willRender.push(get(this, 'setMe')); + }, + didInsertElement() { + didInsert.push(get(this, 'setMe')); + bottom = this; + } + }), + template: '{{setMe}}' + }); + + this.registerComponent('middle-mut', { + template: '{{bottom-mut setMe=(mut value)}}' + }); + + this.render('{{middle-mut value=(mut val)}}', { + val: 12 + }); + + this.assert.deepEqual(willRender, [12], 'willReceive is [12]'); + this.assert.deepEqual(didInsert, [12], 'didInsert is [12]'); + this.assertText('12'); + + this.assertStableRerender(); + + this.assert.deepEqual(willRender, [12], 'willReceive is [12]'); + this.assert.deepEqual(didInsert, [12], 'didInsert is [12]'); + this.assert.strictEqual(get(bottom, 'setMe'), 12, 'the data propagated'); + + this.runTask(() => bottom.attrs.setMe.update(13)); + + this.assert.strictEqual( + get(bottom, 'setMe'), + 13, + "the set took effect on bottom's prop" + ); + this.assert.strictEqual( + bottom.attrs.setMe.value, + 13, + "the set took effect on bottom's attr" + ); + this.assert.strictEqual( + get(this.context, 'val'), + 13, + 'the set propagated back up' + ); + + this.runTask(() => set(bottom, 'setMe', 14)); + + this.assert.strictEqual( + get(bottom, 'setMe'), + 14, + "the set took effect on bottom's prop" + ); + this.assert.strictEqual( + bottom.attrs.setMe.value, + 14, + "the set took effect on bottom's attr" + ); + this.assert.strictEqual( + get(this.context, 'val'), + 14, + 'the set propagated back up' + ); + + this.runTask(() => set(this.context, 'val', 12)); + + this.assertText('12'); + } + + ['@test a mutable binding with a backing computed property and attribute present in the root of the component is updated when the upstream property invalidates #11023']() { + let bottom, middle; + + this.registerComponent('bottom-mut', { + ComponentClass: Component.extend({ + thingy: null, + didInsertElement() { + bottom = this; + } + }), + template: '{{thingy}}' + }); + + this.registerComponent('middle-mut', { + ComponentClass: Component.extend({ + baseValue: 12, + val: computed('baseValue', function() { + return this.get('baseValue'); + }), + didInsertElement() { + middle = this; + } + }), + template: '{{bottom-mut thingy=(mut val)}}' + }); - this.registerComponent('x-outer', { - template: '{{x-inner foo=bar}}' - }); + this.render('{{middle-mut}}'); - this.render('{{x-outer bar=baz}}', { baz: 'foo' }); + this.assert.strictEqual(get(bottom, 'thingy'), 12, 'data propagated'); + this.assertText('12'); - this.assertText('foo'); + this.assertStableRerender(); - this.assertStableRerender(); + this.runTask(() => set(middle, 'baseValue', 13)); - this.runTask(() => inner.attrs.foo.update('bar')); + this.assert.strictEqual(get(middle, 'val'), 13, 'the set took effect'); + this.assert.strictEqual( + bottom.attrs.thingy.value, + 13, + "the set propagated down to bottom's attrs" + ); + this.assert.strictEqual( + get(bottom, 'thingy'), + 13, + "the set propagated down to bottom's prop" + ); + this.assertText('13'); - this.assert.equal(inner.attrs.foo.value, 'bar'); - this.assert.equal(get(inner, 'foo'), 'bar'); - this.assertText('bar'); + this.runTask(() => set(middle, 'baseValue', 12)); - this.runTask(() => inner.attrs.foo.update('foo')); + this.assertText('12'); + } - this.assertText('foo'); - } + ['@test automatic mutable bindings exposes a mut cell in attrs']() { + let inner; - ['@test automatic mutable bindings tolerate undefined non-stream inputs and attempts to set them']() { - let inner; + this.registerComponent('x-inner', { + ComponentClass: Component.extend({ + didInsertElement() { + inner = this; + } + }), + template: '{{foo}}' + }); - this.registerComponent('x-inner', { - ComponentClass: Component.extend({ - didInsertElement() { - inner = this; - } - }), - template: '{{model}}' - }); + this.registerComponent('x-outer', { + template: '{{x-inner foo=bar}}' + }); - this.registerComponent('x-outer', { - template: '{{x-inner model=nonexistent}}' - }); + this.render('{{x-outer bar=baz}}', { baz: 'foo' }); - this.render('{{x-outer}}'); + this.assertText('foo'); - this.assertText(''); + this.assertStableRerender(); - this.assertStableRerender(); + this.runTask(() => inner.attrs.foo.update('bar')); - this.runTask(() => inner.attrs.model.update(42)); + this.assert.equal(inner.attrs.foo.value, 'bar'); + this.assert.equal(get(inner, 'foo'), 'bar'); + this.assertText('bar'); - this.assert.equal(inner.attrs.model.value, 42); - this.assert.equal(get(inner, 'model'), 42); - this.assertText('42'); + this.runTask(() => inner.attrs.foo.update('foo')); - this.runTask(() => inner.attrs.model.update(undefined)); + this.assertText('foo'); + } - this.assertText(''); - } + ['@test automatic mutable bindings tolerate undefined non-stream inputs and attempts to set them']() { + let inner; - ['@test automatic mutable bindings tolerate constant non-stream inputs and attempts to set them']() { - let inner; + this.registerComponent('x-inner', { + ComponentClass: Component.extend({ + didInsertElement() { + inner = this; + } + }), + template: '{{model}}' + }); - this.registerComponent('x-inner', { - ComponentClass: Component.extend({ - didInsertElement() { - inner = this; - } - }), - template: 'hello{{model}}' - }); + this.registerComponent('x-outer', { + template: '{{x-inner model=nonexistent}}' + }); - this.registerComponent('x-outer', { - template: '{{x-inner model=x}}' - }); + this.render('{{x-outer}}'); - this.render('{{x-outer x="foo"}}'); + this.assertText(''); - this.assertText('hellofoo'); + this.assertStableRerender(); - this.assertStableRerender(); + this.runTask(() => inner.attrs.model.update(42)); - this.runTask(() => inner.attrs.model.update(42)); + this.assert.equal(inner.attrs.model.value, 42); + this.assert.equal(get(inner, 'model'), 42); + this.assertText('42'); - this.assert.equal(inner.attrs.model.value, 42); - this.assert.equal(get(inner, 'model'), 42); - this.assertText('hello42'); + this.runTask(() => inner.attrs.model.update(undefined)); - this.runTask(() => inner.attrs.model.update('foo')); + this.assertText(''); + } - this.assertText('hellofoo'); - } + ['@test automatic mutable bindings tolerate constant non-stream inputs and attempts to set them']() { + let inner; -}); - -moduleFor('Mutable Bindings used in Computed Properties that are bound as attributeBindings', class extends RenderingTest { - - ['@test an attribute binding of a computed property of a 2-way bound attr recomputes when the attr changes']() { - let input, output; - - this.registerComponent('x-input', { - ComponentClass: Component.extend({ - didInsertElement() { - input = this; - } - }) - }); - - this.registerComponent('x-output', { - ComponentClass: Component.extend({ - attributeBindings: ['style'], - didInsertElement() { - output = this; - }, - style: computed('height', function() { - let height = this.get('height'); - return htmlSafe(`height: ${height}px;`); + this.registerComponent('x-inner', { + ComponentClass: Component.extend({ + didInsertElement() { + inner = this; + } }), - height: 20 - }), - template: '{{height}}' - }); + template: 'hello{{model}}' + }); - this.render('{{x-output height=height}}{{x-input height=(mut height)}}', { - height: 60 - }); + this.registerComponent('x-outer', { + template: '{{x-inner model=x}}' + }); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { style: styles('height: 60px;') }, content: '60' }); + this.render('{{x-outer x="foo"}}'); - this.assertStableRerender(); + this.assertText('hellofoo'); - this.runTask(() => input.attrs.height.update(35)); + this.assertStableRerender(); - this.assert.strictEqual(get(output, 'height'), 35, 'the set took effect'); - this.assert.strictEqual(get(this.context, 'height'), 35, 'the set propagated back up'); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { style: styles('height: 35px;') }, content: '35' }); + this.runTask(() => inner.attrs.model.update(42)); - this.runTask(() => set(input, 'height', 36)); + this.assert.equal(inner.attrs.model.value, 42); + this.assert.equal(get(inner, 'model'), 42); + this.assertText('hello42'); - this.assert.strictEqual(get(output, 'height'), 36, 'the set took effect'); - this.assert.strictEqual(get(this.context, 'height'), 36, 'the set propagated back up'); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { style: styles('height: 36px;') }, content: '36' }); + this.runTask(() => inner.attrs.model.update('foo')); - this.runTask(() => set(this.context, 'height', 60)); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { style: styles('height: 60px;') }, content: '60' }); - this.assert.strictEqual(get(input, 'height'), 60); + this.assertText('hellofoo'); + } } +); + +moduleFor( + 'Mutable Bindings used in Computed Properties that are bound as attributeBindings', + class extends RenderingTest { + ['@test an attribute binding of a computed property of a 2-way bound attr recomputes when the attr changes']() { + let input, output; + + this.registerComponent('x-input', { + ComponentClass: Component.extend({ + didInsertElement() { + input = this; + } + }) + }); - ['@test an attribute binding of a computed property with a setter of a 2-way bound attr recomputes when the attr changes']() { - let input, output; - - this.registerComponent('x-input', { - ComponentClass: Component.extend({ - didInsertElement() { - input = this; - } - }) - }); - - this.registerComponent('x-output', { - ComponentClass: Component.extend({ - attributeBindings: ['style'], - didInsertElement() { - output = this; - }, - style: computed('height', 'width', function() { - let height = this.get('height'); - let width = this.get('width'); - return htmlSafe(`height: ${height}px; width: ${width}px;`); - }), - height: 20, - width: computed('height', { - get() { - return this.get('height') * 2; + this.registerComponent('x-output', { + ComponentClass: Component.extend({ + attributeBindings: ['style'], + didInsertElement() { + output = this; }, - set(keyName, width) { - this.set('height', width / 2); - return width; + style: computed('height', function() { + let height = this.get('height'); + return htmlSafe(`height: ${height}px;`); + }), + height: 20 + }), + template: '{{height}}' + }); + + this.render('{{x-output height=height}}{{x-input height=(mut height)}}', { + height: 60 + }); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { style: styles('height: 60px;') }, + content: '60' + }); + + this.assertStableRerender(); + + this.runTask(() => input.attrs.height.update(35)); + + this.assert.strictEqual(get(output, 'height'), 35, 'the set took effect'); + this.assert.strictEqual( + get(this.context, 'height'), + 35, + 'the set propagated back up' + ); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { style: styles('height: 35px;') }, + content: '35' + }); + + this.runTask(() => set(input, 'height', 36)); + + this.assert.strictEqual(get(output, 'height'), 36, 'the set took effect'); + this.assert.strictEqual( + get(this.context, 'height'), + 36, + 'the set propagated back up' + ); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { style: styles('height: 36px;') }, + content: '36' + }); + + this.runTask(() => set(this.context, 'height', 60)); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { style: styles('height: 60px;') }, + content: '60' + }); + this.assert.strictEqual(get(input, 'height'), 60); + } + + ['@test an attribute binding of a computed property with a setter of a 2-way bound attr recomputes when the attr changes']() { + let input, output; + + this.registerComponent('x-input', { + ComponentClass: Component.extend({ + didInsertElement() { + input = this; } }) - }), - template: '{{width}}x{{height}}' - }); - - this.render('{{x-output width=width}}{{x-input width=(mut width)}}', { - width: 70 - }); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { style: styles('height: 35px; width: 70px;') }, content: '70x35' }); - - this.assertStableRerender(); + }); - this.runTask(() => set(input, 'width', 80)); - - this.assert.strictEqual(get(output, 'width'), 80, 'the set took effect'); - this.assert.strictEqual(get(this.context, 'width'), 80, 'the set propagated back up'); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { style: styles('height: 40px; width: 80px;') }, content: '80x40' }); - - this.runTask(() => input.attrs.width.update(90)); - - this.assert.strictEqual(get(output, 'width'), 90, 'the set took effect'); - this.assert.strictEqual(get(this.context, 'width'), 90, 'the set propagated back up'); - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { style: styles('height: 45px; width: 90px;') }, content: '90x45' }); - - this.runTask(() => set(this.context, 'width', 70)); - - this.assertComponentElement(this.firstChild, { tagName: 'div', attrs: { style: styles('height: 35px; width: 70px;') }, content: '70x35' }); - this.assert.strictEqual(get(input, 'width'), 70); + this.registerComponent('x-output', { + ComponentClass: Component.extend({ + attributeBindings: ['style'], + didInsertElement() { + output = this; + }, + style: computed('height', 'width', function() { + let height = this.get('height'); + let width = this.get('width'); + return htmlSafe(`height: ${height}px; width: ${width}px;`); + }), + height: 20, + width: computed('height', { + get() { + return this.get('height') * 2; + }, + set(keyName, width) { + this.set('height', width / 2); + return width; + } + }) + }), + template: '{{width}}x{{height}}' + }); + + this.render('{{x-output width=width}}{{x-input width=(mut width)}}', { + width: 70 + }); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { style: styles('height: 35px; width: 70px;') }, + content: '70x35' + }); + + this.assertStableRerender(); + + this.runTask(() => set(input, 'width', 80)); + + this.assert.strictEqual(get(output, 'width'), 80, 'the set took effect'); + this.assert.strictEqual( + get(this.context, 'width'), + 80, + 'the set propagated back up' + ); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { style: styles('height: 40px; width: 80px;') }, + content: '80x40' + }); + + this.runTask(() => input.attrs.width.update(90)); + + this.assert.strictEqual(get(output, 'width'), 90, 'the set took effect'); + this.assert.strictEqual( + get(this.context, 'width'), + 90, + 'the set propagated back up' + ); + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { style: styles('height: 45px; width: 90px;') }, + content: '90x45' + }); + + this.runTask(() => set(this.context, 'width', 70)); + + this.assertComponentElement(this.firstChild, { + tagName: 'div', + attrs: { style: styles('height: 35px; width: 70px;') }, + content: '70x35' + }); + this.assert.strictEqual(get(input, 'width'), 70); + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/helpers/partial-test.js b/packages/ember-glimmer/tests/integration/helpers/partial-test.js index 4c2f80e569c..a24a7b610c4 100644 --- a/packages/ember-glimmer/tests/integration/helpers/partial-test.js +++ b/packages/ember-glimmer/tests/integration/helpers/partial-test.js @@ -3,332 +3,410 @@ import { set } from 'ember-metal'; import { A as emberA } from 'ember-runtime'; import { strip } from '../../utils/abstract-test-case'; +moduleFor( + 'Helpers test: {{partial}}', + class extends RenderingTest { + ['@test should render other templates registered with the container']() { + this.registerPartial('_subTemplateFromContainer', 'sub-template'); -moduleFor('Helpers test: {{partial}}', class extends RenderingTest { + this.render( + `This {{partial "subTemplateFromContainer"}} is pretty great.` + ); - ['@test should render other templates registered with the container']() { - this.registerPartial('_subTemplateFromContainer', 'sub-template'); + this.assertStableRerender(); - this.render(`This {{partial "subTemplateFromContainer"}} is pretty great.`); + this.assertText('This sub-template is pretty great.'); + } - this.assertStableRerender(); + ['@test should render other slash-separated templates registered with the container']() { + this.registerPartial('child/_subTemplateFromContainer', 'sub-template'); - this.assertText('This sub-template is pretty great.'); - } - - ['@test should render other slash-separated templates registered with the container']() { - this.registerPartial('child/_subTemplateFromContainer', 'sub-template'); + this.render( + `This {{partial "child/subTemplateFromContainer"}} is pretty great.` + ); - this.render(`This {{partial "child/subTemplateFromContainer"}} is pretty great.`); + this.assertStableRerender(); - this.assertStableRerender(); + this.assertText('This sub-template is pretty great.'); + } - this.assertText('This sub-template is pretty great.'); - } + ['@test should use the current context']() { + this.registerPartial( + '_person_name', + '{{model.firstName}} {{model.lastName}}' + ); - ['@test should use the current context']() { - this.registerPartial('_person_name', '{{model.firstName}} {{model.lastName}}'); - - this.render('Who is {{partial "person_name"}}?', { - model: { - firstName: 'Kris', - lastName: 'Selden' - } - }); + this.render('Who is {{partial "person_name"}}?', { + model: { + firstName: 'Kris', + lastName: 'Selden' + } + }); - this.assertStableRerender(); + this.assertStableRerender(); - this.assertText('Who is Kris Selden?'); + this.assertText('Who is Kris Selden?'); - this.runTask(() => set(this.context, 'model.firstName', 'Kelly')); + this.runTask(() => set(this.context, 'model.firstName', 'Kelly')); - this.assertText('Who is Kelly Selden?'); + this.assertText('Who is Kelly Selden?'); - this.runTask(() => set(this.context, 'model', { firstName: 'Kris', lastName: 'Selden' })); + this.runTask(() => + set(this.context, 'model', { firstName: 'Kris', lastName: 'Selden' }) + ); - this.assertText('Who is Kris Selden?'); - } + this.assertText('Who is Kris Selden?'); + } - ['@test Quoteless parameters passed to {{partial}} perform a bound property lookup of the partial name']() { - this.registerPartial('_subTemplate', 'sub-template'); - this.registerPartial('_otherTemplate', 'other-template'); + ['@test Quoteless parameters passed to {{partial}} perform a bound property lookup of the partial name']() { + this.registerPartial('_subTemplate', 'sub-template'); + this.registerPartial('_otherTemplate', 'other-template'); - this.render('This {{partial templates.partialName}} is pretty {{partial nonexistent}}great.', { - templates: { partialName: 'subTemplate' } - }); + this.render( + 'This {{partial templates.partialName}} is pretty {{partial nonexistent}}great.', + { + templates: { partialName: 'subTemplate' } + } + ); - this.assertStableRerender(); + this.assertStableRerender(); - this.assertText('This sub-template is pretty great.'); + this.assertText('This sub-template is pretty great.'); - this.runTask(() => set(this.context, 'templates.partialName', 'otherTemplate')); + this.runTask(() => + set(this.context, 'templates.partialName', 'otherTemplate') + ); - this.assertText('This other-template is pretty great.'); + this.assertText('This other-template is pretty great.'); - this.runTask(() => set(this.context, 'templates.partialName', null)); + this.runTask(() => set(this.context, 'templates.partialName', null)); - this.assertText('This is pretty great.'); + this.assertText('This is pretty great.'); - this.runTask(() => set(this.context, 'templates', { partialName: 'subTemplate' })); + this.runTask(() => + set(this.context, 'templates', { partialName: 'subTemplate' }) + ); - this.assertText('This sub-template is pretty great.'); - } + this.assertText('This sub-template is pretty great.'); + } - ['@test partial using data from {{#each}}']() { - this.registerPartial('show-item', '{{item}}'); + ['@test partial using data from {{#each}}']() { + this.registerPartial('show-item', '{{item}}'); - this.render(strip` + this.render( + strip` {{#each model.items as |item|}} {{item}}: {{partial 'show-item'}} | - {{/each}}`, { - model: { - items: emberA(['apple', 'orange', 'banana']), + {{/each}}`, + { + model: { + items: emberA(['apple', 'orange', 'banana']) + } } - }); + ); - this.assertStableRerender(); + this.assertStableRerender(); - this.assertText('apple: apple |orange: orange |banana: banana |'); + this.assertText('apple: apple |orange: orange |banana: banana |'); - this.runTask(() => this.context.model.items.pushObject('strawberry')); + this.runTask(() => this.context.model.items.pushObject('strawberry')); - this.assertText('apple: apple |orange: orange |banana: banana |strawberry: strawberry |'); + this.assertText( + 'apple: apple |orange: orange |banana: banana |strawberry: strawberry |' + ); - this.runTask(() => set(this.context, 'model', { - items: emberA(['apple', 'orange', 'banana']), - })); + this.runTask(() => + set(this.context, 'model', { + items: emberA(['apple', 'orange', 'banana']) + }) + ); - this.assertText('apple: apple |orange: orange |banana: banana |'); - } + this.assertText('apple: apple |orange: orange |banana: banana |'); + } - ['@test partial using `{{get` on data from {{#with}}']() { - this.registerPartial('show-id', '{{get item "id"}}'); + ['@test partial using `{{get` on data from {{#with}}']() { + this.registerPartial('show-id', '{{get item "id"}}'); - this.render(strip` + this.render( + strip` {{#with model as |item|}} {{item.name}}: {{partial 'show-id'}} - {{/with}}`, { - model: { id: 1, name: 'foo' } - }); + {{/with}}`, + { + model: { id: 1, name: 'foo' } + } + ); - this.assertStableRerender(); + this.assertStableRerender(); - this.assertText('foo: 1'); + this.assertText('foo: 1'); - this.runTask(() => set(this.context, 'model.id', 2)); + this.runTask(() => set(this.context, 'model.id', 2)); - this.assertText('foo: 2'); + this.assertText('foo: 2'); - this.runTask(() => set(this.context, 'model.name', 'bar')); + this.runTask(() => set(this.context, 'model.name', 'bar')); - this.assertText('bar: 2'); + this.assertText('bar: 2'); - this.runTask(() => set(this.context, 'model', { id: 1, name: 'foo' })); + this.runTask(() => set(this.context, 'model', { id: 1, name: 'foo' })); - this.assertText('foo: 1'); - } + this.assertText('foo: 1'); + } - ['@test partial using `{{get` on data from {{#each}}']() { - this.registerPartial('show-item', '{{get item "id"}}'); + ['@test partial using `{{get` on data from {{#each}}']() { + this.registerPartial('show-item', '{{get item "id"}}'); - this.render(strip` + this.render( + strip` {{#each items as |item|}} {{item.id}}: {{partial 'show-item'}} | - {{/each}}`, { - items: emberA([{ id: 1 }, { id: 2 }, { id: 3 }]), - }); + {{/each}}`, + { + items: emberA([{ id: 1 }, { id: 2 }, { id: 3 }]) + } + ); - this.assertStableRerender(); + this.assertStableRerender(); - this.assertText('1: 1 |2: 2 |3: 3 |'); + this.assertText('1: 1 |2: 2 |3: 3 |'); - this.runTask(() => this.context.items.pushObject({ id: 4 })); + this.runTask(() => this.context.items.pushObject({ id: 4 })); - this.assertText('1: 1 |2: 2 |3: 3 |4: 4 |'); + this.assertText('1: 1 |2: 2 |3: 3 |4: 4 |'); - this.runTask(() => set(this.context, 'items', - emberA([{ id: 1 }, { id: 2 }, { id: 3 }]) - )); + this.runTask(() => + set(this.context, 'items', emberA([{ id: 1 }, { id: 2 }, { id: 3 }])) + ); - this.assertText('1: 1 |2: 2 |3: 3 |'); - } + this.assertText('1: 1 |2: 2 |3: 3 |'); + } - ['@test partial using conditional on data from {{#each}}']() { - this.registerPartial('show-item', '{{#if item}}{{item}}{{/if}}'); + ['@test partial using conditional on data from {{#each}}']() { + this.registerPartial('show-item', '{{#if item}}{{item}}{{/if}}'); - this.render(strip` + this.render( + strip` {{#each items as |item|}} {{item}}: {{partial 'show-item'}} | - {{/each}}`, { - items: emberA(['apple', null, 'orange', 'banana']), - }); + {{/each}}`, + { + items: emberA(['apple', null, 'orange', 'banana']) + } + ); - this.assertStableRerender(); + this.assertStableRerender(); - this.assertText('apple: apple |: |orange: orange |banana: banana |'); + this.assertText('apple: apple |: |orange: orange |banana: banana |'); - this.runTask(() => this.context.items.pushObject('strawberry')); + this.runTask(() => this.context.items.pushObject('strawberry')); - this.assertText('apple: apple |: |orange: orange |banana: banana |strawberry: strawberry |'); + this.assertText( + 'apple: apple |: |orange: orange |banana: banana |strawberry: strawberry |' + ); - this.runTask(() => set(this.context, 'items', - emberA(['apple', null, 'orange', 'banana']) - )); + this.runTask(() => + set(this.context, 'items', emberA(['apple', null, 'orange', 'banana'])) + ); - this.assertText('apple: apple |: |orange: orange |banana: banana |'); - } + this.assertText('apple: apple |: |orange: orange |banana: banana |'); + } - ['@test nested partials using data from {{#each}}']() { - this.registerPartial('_outer-partial', strip` + ['@test nested partials using data from {{#each}}']() { + this.registerPartial( + '_outer-partial', + strip` [outer: {{name}}] {{partial 'inner-partial'}} - `); + ` + ); - this.registerPartial('inner-partial', '[inner: {{name}}]'); + this.registerPartial('inner-partial', '[inner: {{name}}]'); - this.render(strip` + this.render( + strip` {{#each names as |name i|}} {{i}}: {{partial 'outer-partial'}} - {{/each}}`, { - names: emberA(['Alex', 'Ben']) - }); + {{/each}}`, + { + names: emberA(['Alex', 'Ben']) + } + ); - this.assertStableRerender(); + this.assertStableRerender(); - this.assertText('0: [outer: Alex] [inner: Alex]1: [outer: Ben] [inner: Ben]'); + this.assertText( + '0: [outer: Alex] [inner: Alex]1: [outer: Ben] [inner: Ben]' + ); - this.runTask(() => this.context.names.pushObject('Sophie')); + this.runTask(() => this.context.names.pushObject('Sophie')); - this.assertText('0: [outer: Alex] [inner: Alex]1: [outer: Ben] [inner: Ben]2: [outer: Sophie] [inner: Sophie]'); + this.assertText( + '0: [outer: Alex] [inner: Alex]1: [outer: Ben] [inner: Ben]2: [outer: Sophie] [inner: Sophie]' + ); - this.runTask(() => set(this.context, 'names', emberA(['Alex', 'Ben']))); + this.runTask(() => set(this.context, 'names', emberA(['Alex', 'Ben']))); - this.assertText('0: [outer: Alex] [inner: Alex]1: [outer: Ben] [inner: Ben]'); - } + this.assertText( + '0: [outer: Alex] [inner: Alex]1: [outer: Ben] [inner: Ben]' + ); + } - ['@test nested partials within nested `{{#with}}` blocks']() { - this.registerPartial('_person2-partial', strip` + ['@test nested partials within nested `{{#with}}` blocks']() { + this.registerPartial( + '_person2-partial', + strip` {{#with 'Ben' as |person2|}} Hi {{person1}} (aged {{age}}) and {{person2}}. {{partial 'person3-partial'}} {{/with}} - `); + ` + ); - this.registerPartial('_person3-partial', strip` + this.registerPartial( + '_person3-partial', + strip` {{#with 'Alex' as |person3|}} Hi {{person1}} (aged {{age}}), {{person2}} and {{person3}}. {{partial 'person4-partial'}} {{/with}} - `); + ` + ); - this.registerPartial('_person4-partial', strip` + this.registerPartial( + '_person4-partial', + strip` {{#with 'Sarah' as |person4|}} Hi {{person1}} (aged {{age}}), {{person2}}, {{person3}} and {{person4}}. {{/with}} - `); + ` + ); - this.render(strip` + this.render( + strip` {{#with 'Sophie' as |person1|}} Hi {{person1}} (aged {{age}}). {{partial 'person2-partial'}} {{/with}}`, - { age: 0 } - ); + { age: 0 } + ); - this.assertStableRerender(); + this.assertStableRerender(); - this.assertText('Hi Sophie (aged 0). Hi Sophie (aged 0) and Ben. Hi Sophie (aged 0), Ben and Alex. Hi Sophie (aged 0), Ben, Alex and Sarah.'); + this.assertText( + 'Hi Sophie (aged 0). Hi Sophie (aged 0) and Ben. Hi Sophie (aged 0), Ben and Alex. Hi Sophie (aged 0), Ben, Alex and Sarah.' + ); - this.runTask(() => set(this.context, 'age', 1)); + this.runTask(() => set(this.context, 'age', 1)); - this.assertText('Hi Sophie (aged 1). Hi Sophie (aged 1) and Ben. Hi Sophie (aged 1), Ben and Alex. Hi Sophie (aged 1), Ben, Alex and Sarah.'); + this.assertText( + 'Hi Sophie (aged 1). Hi Sophie (aged 1) and Ben. Hi Sophie (aged 1), Ben and Alex. Hi Sophie (aged 1), Ben, Alex and Sarah.' + ); - this.runTask(() => set(this.context, 'age', 0)); + this.runTask(() => set(this.context, 'age', 0)); - this.assertText('Hi Sophie (aged 0). Hi Sophie (aged 0) and Ben. Hi Sophie (aged 0), Ben and Alex. Hi Sophie (aged 0), Ben, Alex and Sarah.'); - } + this.assertText( + 'Hi Sophie (aged 0). Hi Sophie (aged 0) and Ben. Hi Sophie (aged 0), Ben and Alex. Hi Sophie (aged 0), Ben, Alex and Sarah.' + ); + } - ['@test dynamic partials in {{#each}}']() { - this.registerPartial('_odd', 'ODD{{i}}'); - this.registerPartial('_even', 'EVEN{{i}}'); + ['@test dynamic partials in {{#each}}']() { + this.registerPartial('_odd', 'ODD{{i}}'); + this.registerPartial('_even', 'EVEN{{i}}'); - this.render(strip` + this.render( + strip` {{#each model.items as |template i|}} {{model.type}}: {{partial template}} - {{/each}}`, { - model: { - items: ['even', 'odd', 'even', 'odd'], - type: 'number' + {{/each}}`, + { + model: { + items: ['even', 'odd', 'even', 'odd'], + type: 'number' + } } - }); + ); - this.assertStableRerender(); + this.assertStableRerender(); - this.assertText('number: EVEN0number: ODD1number: EVEN2number: ODD3'); + this.assertText('number: EVEN0number: ODD1number: EVEN2number: ODD3'); - this.runTask(() => set(this.context, 'model.type', 'integer')); + this.runTask(() => set(this.context, 'model.type', 'integer')); - this.assertText('integer: EVEN0integer: ODD1integer: EVEN2integer: ODD3'); + this.assertText('integer: EVEN0integer: ODD1integer: EVEN2integer: ODD3'); - this.runTask(() => set(this.context, 'model', { - items: ['even', 'odd', 'even', 'odd'], - type: 'number' - })); + this.runTask(() => + set(this.context, 'model', { + items: ['even', 'odd', 'even', 'odd'], + type: 'number' + }) + ); - this.assertText('number: EVEN0number: ODD1number: EVEN2number: ODD3'); - } + this.assertText('number: EVEN0number: ODD1number: EVEN2number: ODD3'); + } - ['@test dynamic partials in {{#with}}']() { - this.registerPartial('_thing', '{{t}}'); + ['@test dynamic partials in {{#with}}']() { + this.registerPartial('_thing', '{{t}}'); - this.render(strip` + this.render( + strip` {{#with item.thing as |t|}} {{partial t}} {{else}} Nothing! - {{/with}}`, { - item: { thing: false } - }); + {{/with}}`, + { + item: { thing: false } + } + ); - this.assertStableRerender(); + this.assertStableRerender(); - this.assertText('Nothing!'); + this.assertText('Nothing!'); - this.runTask(() => set(this.context, 'item.thing', 'thing')); + this.runTask(() => set(this.context, 'item.thing', 'thing')); - this.assertText('thing'); + this.assertText('thing'); - this.runTask(() => set(this.context, 'item', { thing: false })); + this.runTask(() => set(this.context, 'item', { thing: false })); - this.assertText('Nothing!'); - } + this.assertText('Nothing!'); + } - ['@test partials which contain contextual components']() { - this.registerComponent('outer-component', { - template: '{{yield (hash inner=(component "inner-component" name=name))}}' - }); + ['@test partials which contain contextual components']() { + this.registerComponent('outer-component', { + template: + '{{yield (hash inner=(component "inner-component" name=name))}}' + }); - this.registerComponent('inner-component', { - template: '{{yield (hash name=name)}}' - }); + this.registerComponent('inner-component', { + template: '{{yield (hash name=name)}}' + }); - this.registerPartial('_some-partial', strip` + this.registerPartial( + '_some-partial', + strip` {{#outer.inner as |inner|}} inner.name: {{inner.name}} {{/outer.inner}} - `); + ` + ); - this.render(strip` + this.render( + strip` {{#outer-component name=name as |outer|}} {{partial 'some-partial'}} - {{/outer-component}}`, { name: 'Sophie' }); + {{/outer-component}}`, + { name: 'Sophie' } + ); - this.assertStableRerender(); + this.assertStableRerender(); - this.assertText('inner.name: Sophie'); + this.assertText('inner.name: Sophie'); - this.runTask(() => set(this.context, 'name', 'Ben')); + this.runTask(() => set(this.context, 'name', 'Ben')); - this.assertText('inner.name: Ben'); + this.assertText('inner.name: Ben'); - this.runTask(() => set(this.context, 'name', 'Sophie')); + this.runTask(() => set(this.context, 'name', 'Sophie')); - this.assertText('inner.name: Sophie'); + this.assertText('inner.name: Sophie'); + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/helpers/readonly-test.js b/packages/ember-glimmer/tests/integration/helpers/readonly-test.js index 91eefb2d5e6..226b4a73503 100644 --- a/packages/ember-glimmer/tests/integration/helpers/readonly-test.js +++ b/packages/ember-glimmer/tests/integration/helpers/readonly-test.js @@ -2,247 +2,333 @@ import { RenderingTest, moduleFor } from '../../utils/test-case'; import { Component } from '../../utils/helpers'; import { set, get } from 'ember-metal'; -moduleFor('Helpers test: {{readonly}}', class extends RenderingTest { - - ['@test {{readonly}} of a path should work']() { - let component; - - this.registerComponent('foo-bar', { - ComponentClass: Component.extend({ - didInsertElement() { - component = this; - } - }), - template: '{{value}}' - }); - - this.render('{{foo-bar value=(readonly val)}}', { - val: 12 - }); - - this.assertText('12'); - - this.assertStableRerender(); - - this.runTask(() => set(component, 'value', 13)); - this.assert.notOk(component.attrs.value.update); - - this.assertText('13', 'local property is updated'); - this.assert.equal(get(this.context, 'val'), 12, 'upstream attribute is not updated'); - - // No U-R - } - - '@test passing an action to {{readonly}} avoids mutable cell wrapping'(assert) { - assert.expect(4); - let outer, inner; - - this.registerComponent('x-inner', { - ComponentClass: Component.extend({ - init() { - this._super(...arguments); - inner = this; - }, - }), - }); - - this.registerComponent('x-outer', { - ComponentClass: Component.extend({ - init() { - this._super(...arguments); - outer = this; - }, - }), - template: '{{x-inner onClick=(readonly onClick)}}' - }); - - this.render('{{x-outer onClick=(action doIt)}}', { - doIt() { - assert.ok(true, 'action was called'); - } - }); - - assert.equal(typeof outer.attrs.onClick, 'function', 'function itself is present in outer component attrs'); - outer.attrs.onClick(); - - assert.equal(typeof inner.attrs.onClick, 'function', 'function itself is present in inner component attrs'); - inner.attrs.onClick(); - } - - '@test updating a {{readonly}} property from above works'(assert) { - let component; - - this.registerComponent('foo-bar', { - ComponentClass: Component.extend({ - init() { - this._super(...arguments); - component = this; +moduleFor( + 'Helpers test: {{readonly}}', + class extends RenderingTest { + ['@test {{readonly}} of a path should work']() { + let component; + + this.registerComponent('foo-bar', { + ComponentClass: Component.extend({ + didInsertElement() { + component = this; + } + }), + template: '{{value}}' + }); + + this.render('{{foo-bar value=(readonly val)}}', { + val: 12 + }); + + this.assertText('12'); + + this.assertStableRerender(); + + this.runTask(() => set(component, 'value', 13)); + this.assert.notOk(component.attrs.value.update); + + this.assertText('13', 'local property is updated'); + this.assert.equal( + get(this.context, 'val'), + 12, + 'upstream attribute is not updated' + ); + + // No U-R + } + + '@test passing an action to {{readonly}} avoids mutable cell wrapping'( + assert + ) { + assert.expect(4); + let outer, inner; + + this.registerComponent('x-inner', { + ComponentClass: Component.extend({ + init() { + this._super(...arguments); + inner = this; + } + }) + }); + + this.registerComponent('x-outer', { + ComponentClass: Component.extend({ + init() { + this._super(...arguments); + outer = this; + } + }), + template: '{{x-inner onClick=(readonly onClick)}}' + }); + + this.render('{{x-outer onClick=(action doIt)}}', { + doIt() { + assert.ok(true, 'action was called'); } - }), - template: '{{value}}' - }); - - this.render('{{foo-bar value=(readonly thing)}}', { - thing: 'initial' - }); - - this.assertText('initial'); - - this.assertStableRerender(); - - assert.strictEqual(component.attrs.value, 'initial', 'no mutable cell'); - assert.strictEqual(get(component, 'value'), 'initial', 'no mutable cell'); - assert.strictEqual(this.context.thing, 'initial'); - - this.runTask(() => set(this.context, 'thing', 'updated!')); - - this.assertText('updated!'); - assert.strictEqual(component.attrs.value, 'updated!', 'passed down value was set in attrs'); - assert.strictEqual(get(component, 'value'), 'updated!', 'passed down value was set'); - - this.runTask(() => set(this.context, 'thing', 'initial')); - - this.assertText('initial'); - } - - '@test updating a nested path of a {{readonly}}'(assert) { - let component; - - this.registerComponent('foo-bar', { - ComponentClass: Component.extend({ - didInsertElement() { - component = this; + }); + + assert.equal( + typeof outer.attrs.onClick, + 'function', + 'function itself is present in outer component attrs' + ); + outer.attrs.onClick(); + + assert.equal( + typeof inner.attrs.onClick, + 'function', + 'function itself is present in inner component attrs' + ); + inner.attrs.onClick(); + } + + '@test updating a {{readonly}} property from above works'(assert) { + let component; + + this.registerComponent('foo-bar', { + ComponentClass: Component.extend({ + init() { + this._super(...arguments); + component = this; + } + }), + template: '{{value}}' + }); + + this.render('{{foo-bar value=(readonly thing)}}', { + thing: 'initial' + }); + + this.assertText('initial'); + + this.assertStableRerender(); + + assert.strictEqual(component.attrs.value, 'initial', 'no mutable cell'); + assert.strictEqual(get(component, 'value'), 'initial', 'no mutable cell'); + assert.strictEqual(this.context.thing, 'initial'); + + this.runTask(() => set(this.context, 'thing', 'updated!')); + + this.assertText('updated!'); + assert.strictEqual( + component.attrs.value, + 'updated!', + 'passed down value was set in attrs' + ); + assert.strictEqual( + get(component, 'value'), + 'updated!', + 'passed down value was set' + ); + + this.runTask(() => set(this.context, 'thing', 'initial')); + + this.assertText('initial'); + } + + '@test updating a nested path of a {{readonly}}'(assert) { + let component; + + this.registerComponent('foo-bar', { + ComponentClass: Component.extend({ + didInsertElement() { + component = this; + } + }), + template: '{{value.prop}}' + }); + + this.render('{{foo-bar value=(readonly thing)}}', { + thing: { + prop: 'initial' } - }), - template: '{{value.prop}}' - }); - - this.render('{{foo-bar value=(readonly thing)}}', { - thing: { - prop: 'initial', - } - }); - - this.assertText('initial'); - - this.assertStableRerender(); + }); - assert.notOk(component.attrs.value.update, 'no update available'); - assert.deepEqual(get(component, 'value'), { prop: 'initial' }); - assert.deepEqual(this.context.thing, { prop: 'initial' }); + this.assertText('initial'); - this.runTask(() => set(component, 'value.prop', 'updated!')); + this.assertStableRerender(); - this.assertText('updated!', 'nested path is updated'); - assert.deepEqual(get(component, 'value'), { prop: 'updated!' }); - assert.deepEqual(this.context.thing, { prop: 'updated!' }); - - this.runTask(() => set(component, 'value.prop', 'initial')); - - this.assertText('initial'); + assert.notOk(component.attrs.value.update, 'no update available'); + assert.deepEqual(get(component, 'value'), { prop: 'initial' }); + assert.deepEqual(this.context.thing, { prop: 'initial' }); + + this.runTask(() => set(component, 'value.prop', 'updated!')); + + this.assertText('updated!', 'nested path is updated'); + assert.deepEqual(get(component, 'value'), { prop: 'updated!' }); + assert.deepEqual(this.context.thing, { prop: 'updated!' }); + + this.runTask(() => set(component, 'value.prop', 'initial')); + + this.assertText('initial'); + } + + ['@test {{readonly}} of a string renders correctly']() { + let component; + + this.registerComponent('foo-bar', { + ComponentClass: Component.extend({ + didInsertElement() { + component = this; + } + }), + template: '{{value}}' + }); + + this.render('{{foo-bar value=(readonly "12")}}'); + + this.assertText('12'); + + this.assertStableRerender(); + + this.assert.notOk(component.attrs.value.update); + this.assert.strictEqual(get(component, 'value'), '12'); + + this.runTask(() => set(component, 'value', '13')); + + this.assertText('13', 'local property is updated'); + this.assert.strictEqual(get(component, 'value'), '13'); + + this.runTask(() => set(component, 'value', '12')); + + this.assertText('12'); + } + + ['@test {{mut}} of a {{readonly}} mutates only the middle and bottom tiers']() { + let middle, bottom; + + this.registerComponent('x-bottom', { + ComponentClass: Component.extend({ + didInsertElement() { + bottom = this; + } + }), + template: '{{bar}}' + }); + + this.registerComponent('x-middle', { + ComponentClass: Component.extend({ + didInsertElement() { + middle = this; + } + }), + template: '{{foo}} {{x-bottom bar=(mut foo)}}' + }); + + this.render('{{x-middle foo=(readonly val)}}', { + val: 12 + }); + + this.assertText('12 12'); + + this.assertStableRerender(); + + this.assert.equal( + get(bottom, 'bar'), + 12, + "bottom's local bar received the value" + ); + this.assert.equal( + get(middle, 'foo'), + 12, + "middle's local foo received the value" + ); + + // updating the mut-cell directly + this.runTask(() => bottom.attrs.bar.update(13)); + + this.assert.equal( + get(bottom, 'bar'), + 13, + "bottom's local bar was updated after set of bottom's bar" + ); + this.assert.equal( + get(middle, 'foo'), + 13, + "middle's local foo was updated after set of bottom's bar" + ); + this.assertText('13 13'); + this.assert.equal( + get(this.context, 'val'), + 12, + 'But context val is not updated' + ); + + this.runTask(() => set(bottom, 'bar', 14)); + + this.assert.equal( + get(bottom, 'bar'), + 14, + "bottom's local bar was updated after set of bottom's bar" + ); + this.assert.equal( + get(middle, 'foo'), + 14, + "middle's local foo was updated after set of bottom's bar" + ); + this.assertText('14 14'); + this.assert.equal( + get(this.context, 'val'), + 12, + 'But context val is not updated' + ); + + this.assert.notOk( + middle.attrs.foo.update, + "middle's foo attr is not a mutable cell" + ); + this.runTask(() => set(middle, 'foo', 15)); + + this.assertText('15 15'); + this.assert.equal( + get(middle, 'foo'), + 15, + "set of middle's foo took effect" + ); + this.assert.equal( + get(bottom, 'bar'), + 15, + "bottom's local bar was updated after set of middle's foo" + ); + this.assert.equal( + get(this.context, 'val'), + 12, + 'Context val remains unchanged' + ); + + this.runTask(() => set(this.context, 'val', 10)); + + this.assertText('10 10'); + this.assert.equal( + get(bottom, 'bar'), + 10, + "bottom's local bar was updated after set of context's val" + ); + this.assert.equal( + get(middle, 'foo'), + 10, + "middle's local foo was updated after set of context's val" + ); + + // setting as a normal property + this.runTask(() => set(bottom, 'bar', undefined)); + + this.assertText(' '); + this.assert.equal( + get(bottom, 'bar'), + undefined, + "bottom's local bar was updated to a falsy value" + ); + this.assert.equal( + get(middle, 'foo'), + undefined, + "middle's local foo was updated to a falsy value" + ); + + this.runTask(() => set(this.context, 'val', 12)); + this.assertText('12 12', 'bottom and middle were both reset'); + } } - - ['@test {{readonly}} of a string renders correctly']() { - let component; - - this.registerComponent('foo-bar', { - ComponentClass: Component.extend({ - didInsertElement() { - component = this; - } - }), - template: '{{value}}' - }); - - this.render('{{foo-bar value=(readonly "12")}}'); - - this.assertText('12'); - - this.assertStableRerender(); - - this.assert.notOk(component.attrs.value.update); - this.assert.strictEqual(get(component, 'value'), '12'); - - this.runTask(() => set(component, 'value', '13')); - - this.assertText('13', 'local property is updated'); - this.assert.strictEqual(get(component, 'value'), '13'); - - this.runTask(() => set(component, 'value', '12')); - - this.assertText('12'); - } - - ['@test {{mut}} of a {{readonly}} mutates only the middle and bottom tiers']() { - let middle, bottom; - - this.registerComponent('x-bottom', { - ComponentClass: Component.extend({ - didInsertElement() { - bottom = this; - } - }), - template: '{{bar}}' - }); - - this.registerComponent('x-middle', { - ComponentClass: Component.extend({ - didInsertElement() { - middle = this; - } - }), - template: '{{foo}} {{x-bottom bar=(mut foo)}}' - }); - - this.render('{{x-middle foo=(readonly val)}}', { - val: 12 - }); - - this.assertText('12 12'); - - this.assertStableRerender(); - - this.assert.equal(get(bottom, 'bar'), 12, 'bottom\'s local bar received the value'); - this.assert.equal(get(middle, 'foo'), 12, 'middle\'s local foo received the value'); - - // updating the mut-cell directly - this.runTask(() => bottom.attrs.bar.update(13)); - - this.assert.equal(get(bottom, 'bar'), 13, 'bottom\'s local bar was updated after set of bottom\'s bar'); - this.assert.equal(get(middle, 'foo'), 13, 'middle\'s local foo was updated after set of bottom\'s bar'); - this.assertText('13 13'); - this.assert.equal(get(this.context, 'val'), 12, 'But context val is not updated'); - - this.runTask(() => set(bottom, 'bar', 14)); - - this.assert.equal(get(bottom, 'bar'), 14, 'bottom\'s local bar was updated after set of bottom\'s bar'); - this.assert.equal(get(middle, 'foo'), 14, 'middle\'s local foo was updated after set of bottom\'s bar'); - this.assertText('14 14'); - this.assert.equal(get(this.context, 'val'), 12, 'But context val is not updated'); - - this.assert.notOk(middle.attrs.foo.update, 'middle\'s foo attr is not a mutable cell'); - this.runTask(() => set(middle, 'foo', 15)); - - this.assertText('15 15'); - this.assert.equal(get(middle, 'foo'), 15, 'set of middle\'s foo took effect'); - this.assert.equal(get(bottom, 'bar'), 15, 'bottom\'s local bar was updated after set of middle\'s foo'); - this.assert.equal(get(this.context, 'val'), 12, 'Context val remains unchanged'); - - this.runTask(() => set(this.context, 'val', 10)); - - this.assertText('10 10'); - this.assert.equal(get(bottom, 'bar'), 10, 'bottom\'s local bar was updated after set of context\'s val'); - this.assert.equal(get(middle, 'foo'), 10, 'middle\'s local foo was updated after set of context\'s val'); - - // setting as a normal property - this.runTask(() => set(bottom, 'bar', undefined)); - - this.assertText(' '); - this.assert.equal(get(bottom, 'bar'), undefined, 'bottom\'s local bar was updated to a falsy value'); - this.assert.equal(get(middle, 'foo'), undefined, 'middle\'s local foo was updated to a falsy value'); - - this.runTask(() => set(this.context, 'val', 12)); - this.assertText('12 12', 'bottom and middle were both reset'); - } - - }); +); diff --git a/packages/ember-glimmer/tests/integration/helpers/render-test.js b/packages/ember-glimmer/tests/integration/helpers/render-test.js index 406ea2d908d..e3348ab29a7 100644 --- a/packages/ember-glimmer/tests/integration/helpers/render-test.js +++ b/packages/ember-glimmer/tests/integration/helpers/render-test.js @@ -3,469 +3,579 @@ import { Controller } from 'ember-runtime'; import { ENV } from 'ember-environment'; import { RenderingTest, moduleFor } from '../../utils/test-case'; -moduleFor('Helpers test: {{render}}', class extends RenderingTest { - constructor() { - super(); - this.originalRenderSupport = ENV._ENABLE_RENDER_SUPPORT; - ENV._ENABLE_RENDER_SUPPORT = true; - } +moduleFor( + 'Helpers test: {{render}}', + class extends RenderingTest { + constructor() { + super(); + this.originalRenderSupport = ENV._ENABLE_RENDER_SUPPORT; + ENV._ENABLE_RENDER_SUPPORT = true; + } + + teardown() { + super.teardown(); + ENV._ENABLE_RENDER_SUPPORT = this.originalRenderSupport; + } + + ['@test should render given template']() { + this.registerTemplate('home', '

BYE

'); + + expectDeprecation(() => { + this.render(`

HI

{{render 'home'}}`); + }, /Please refactor [\w\{\}"` ]+ to a component/); + + this.assertText('HIBYE'); + } + + ['@test uses `controller:basic` as the basis for a generated controller when none exists for specified name']() { + this.owner.register( + 'controller:basic', + Controller.extend({ + isBasicController: true + }) + ); + this.registerTemplate('home', '{{isBasicController}}'); + + expectDeprecation(() => { + this.render(`{{render 'home'}}`); + }, /Please refactor [\w\{\}"` ]+ to a component/); + + this.assertText('true'); + } + + ['@test generates a controller if none exists']() { + this.registerTemplate('home', '

{{this}}

'); + + expectDeprecation(() => { + this.render(`

HI

{{render 'home'}}`); + }, /Please refactor [\w\{\}"` ]+ to a component/); + + this.assertText('HI(generated home controller)'); + } + + ['@test should use controller with the same name as template if present']() { + this.owner.register( + 'controller:home', + Controller.extend({ name: 'home' }) + ); + this.registerTemplate('home', '{{name}}

BYE

'); + + expectDeprecation(() => { + this.render(`

HI

{{render 'home'}}`); + }, /Please refactor [\w\{\}"` ]+ to a component/); + + this.assertText('HIhomeBYE'); + } + + ['@test should render nested helpers']() { + this.owner.register('controller:home', Controller.extend()); + this.owner.register('controller:foo', Controller.extend()); + this.owner.register('controller:bar', Controller.extend()); + this.owner.register('controller:baz', Controller.extend()); + + this.registerTemplate('home', '

BYE

'); + this.registerTemplate('baz', `

BAZ

`); + + expectDeprecation(() => { + this.registerTemplate('foo', `

FOO

{{render 'bar'}}`); + this.registerTemplate('bar', `

BAR

{{render 'baz'}}`); + this.render("

HI

{{render 'foo'}}"); + }, /Please refactor [\w\{\}"` ]+ to a component/); + + this.assertText('HIFOOBARBAZ'); + } - teardown() { - super.teardown(); - ENV._ENABLE_RENDER_SUPPORT = this.originalRenderSupport; - } + ['@test should have assertion if the template does not exist']() { + this.owner.register('controller:oops', Controller.extend()); + + expectDeprecation(() => { + expectAssertion(() => { + this.render(`

HI

{{render 'oops'}}`); + }, "You used `{{render 'oops'}}`, but 'oops' can not be found as a template."); + }, /Please refactor [\w\{\}"` ]+ to a component/); + } + + ['@test should render given template with the singleton controller as its context']() { + this.owner.register( + 'controller:post', + Controller.extend({ + init() { + this.set('title', `It's Simple Made Easy`); + } + }) + ); + this.registerTemplate('post', '

{{title}}

'); + + expectDeprecation(() => { + this.render(`

HI

{{render 'post'}}`); + }, /Please refactor [\w\{\}"` ]+ to a component/); - ['@test should render given template']() { - this.registerTemplate('home', '

BYE

'); + this.assertText(`HIIt's Simple Made Easy`); - expectDeprecation(() => { - this.render(`

HI

{{render 'home'}}`); - }, /Please refactor [\w\{\}"` ]+ to a component/); + this.runTask(() => this.rerender()); - this.assertText('HIBYE'); - } + this.assertText(`HIIt's Simple Made Easy`); - ['@test uses `controller:basic` as the basis for a generated controller when none exists for specified name']() { - this.owner.register('controller:basic', Controller.extend({ - isBasicController: true - })); - this.registerTemplate('home', '{{isBasicController}}'); + let controller = this.owner.lookup('controller:post'); - expectDeprecation(() => { - this.render(`{{render 'home'}}`); - }, /Please refactor [\w\{\}"` ]+ to a component/); + this.runTask(() => set(controller, 'title', `Rails is omakase`)); - this.assertText('true'); - } + this.assertText(`HIRails is omakase`); - ['@test generates a controller if none exists']() { - this.registerTemplate('home', '

{{this}}

'); + this.runTask(() => set(controller, 'title', `It's Simple Made Easy`)); - expectDeprecation(() => { - this.render(`

HI

{{render 'home'}}`); - }, /Please refactor [\w\{\}"` ]+ to a component/); + this.assertText(`HIIt's Simple Made Easy`); + } - this.assertText('HI(generated home controller)'); - } - - ['@test should use controller with the same name as template if present']() { - this.owner.register('controller:home', Controller.extend({ name: 'home' })); - this.registerTemplate('home', '{{name}}

BYE

'); + ['@test should not destroy the singleton controller on teardown'](assert) { + let willDestroyFired = 0; - expectDeprecation(() => { - this.render(`

HI

{{render 'home'}}`); - }, /Please refactor [\w\{\}"` ]+ to a component/); + this.owner.register( + 'controller:post', + Controller.extend({ + init() { + this.set('title', `It's Simple Made Easy`); + }, - this.assertText('HIhomeBYE'); - } + willDestroy() { + this._super(...arguments); + willDestroyFired++; + } + }) + ); - ['@test should render nested helpers']() { - this.owner.register('controller:home', Controller.extend()); - this.owner.register('controller:foo', Controller.extend()); - this.owner.register('controller:bar', Controller.extend()); - this.owner.register('controller:baz', Controller.extend()); + this.registerTemplate('post', '

{{title}}

'); - this.registerTemplate('home', '

BYE

'); - this.registerTemplate('baz', `

BAZ

`); + expectDeprecation(() => { + this.render( + `{{#if showPost}}{{render 'post'}}{{else}}Nothing here{{/if}}`, + { showPost: false } + ); + }, /Please refactor [\w\{\}"` ]+ to a component/); - expectDeprecation(() => { - this.registerTemplate('foo', `

FOO

{{render 'bar'}}`); - this.registerTemplate('bar', `

BAR

{{render 'baz'}}`); - this.render('

HI

{{render \'foo\'}}'); - }, /Please refactor [\w\{\}"` ]+ to a component/); + this.assertText(`Nothing here`); + + assert.strictEqual( + willDestroyFired, + 0, + 'it did not destroy the controller' + ); - this.assertText('HIFOOBARBAZ'); - } + this.runTask(() => this.rerender()); - ['@test should have assertion if the template does not exist']() { - this.owner.register('controller:oops', Controller.extend()); + this.assertText(`Nothing here`); - expectDeprecation(() => { - expectAssertion(() => { - this.render(`

HI

{{render 'oops'}}`); - }, 'You used `{{render \'oops\'}}`, but \'oops\' can not be found as a template.'); - }, /Please refactor [\w\{\}"` ]+ to a component/); - } + assert.strictEqual( + willDestroyFired, + 0, + 'it did not destroy the controller' + ); - ['@test should render given template with the singleton controller as its context']() { - this.owner.register('controller:post', Controller.extend({ - init() { - this.set('title', `It's Simple Made Easy`); - } - })); - this.registerTemplate('post', '

{{title}}

'); + this.runTask(() => set(this.context, 'showPost', true)); - expectDeprecation(() => { - this.render(`

HI

{{render 'post'}}`); - }, /Please refactor [\w\{\}"` ]+ to a component/); + this.assertText(`It's Simple Made Easy`); - this.assertText(`HIIt's Simple Made Easy`); + assert.strictEqual( + willDestroyFired, + 0, + 'it did not destroy the controller' + ); - this.runTask(() => this.rerender()); + this.runTask(() => set(this.context, 'showPost', false)); - this.assertText(`HIIt's Simple Made Easy`); + this.assertText(`Nothing here`); - let controller = this.owner.lookup('controller:post'); + assert.strictEqual( + willDestroyFired, + 0, + 'it did not destroy the controller' + ); + } - this.runTask(() => set(controller, 'title', `Rails is omakase`)); + ['@test should render given template with a supplied model']() { + this.owner.register('controller:post', Controller.extend()); + this.registerTemplate('post', '

{{model.title}}

'); - this.assertText(`HIRails is omakase`); + expectDeprecation(() => { + this.render(`

HI

{{render 'post' post}}`, { + post: { + title: `It's Simple Made Easy` + } + }); + }, /Please refactor [\w\{\}"` ]+ to a component/); - this.runTask(() => set(controller, 'title', `It's Simple Made Easy`)); + this.assertText(`HIIt's Simple Made Easy`); - this.assertText(`HIIt's Simple Made Easy`); - } + this.runTask(() => this.rerender()); - ['@test should not destroy the singleton controller on teardown'](assert) { - let willDestroyFired = 0; + this.assertText(`HIIt's Simple Made Easy`); - this.owner.register('controller:post', Controller.extend({ - init() { - this.set('title', `It's Simple Made Easy`); - }, + this.runTask(() => set(this.context, 'post.title', `Rails is omakase`)); - willDestroy() { - this._super(...arguments); - willDestroyFired++; - } - })); + this.assertText(`HIRails is omakase`); - this.registerTemplate('post', '

{{title}}

'); + this.runTask(() => + set(this.context, 'post', { title: `It's Simple Made Easy` }) + ); - expectDeprecation(() => { - this.render(`{{#if showPost}}{{render 'post'}}{{else}}Nothing here{{/if}}`, { showPost: false }); - }, /Please refactor [\w\{\}"` ]+ to a component/); + this.assertText(`HIIt's Simple Made Easy`); + } - this.assertText(`Nothing here`); + ['@test should destroy the non-singleton controllers on teardown'](assert) { + let willDestroyFired = 0; - assert.strictEqual(willDestroyFired, 0, 'it did not destroy the controller'); + this.owner.register( + 'controller:post', + Controller.extend({ + willDestroy() { + this._super(...arguments); + willDestroyFired++; + } + }) + ); - this.runTask(() => this.rerender()); + this.registerTemplate('post', '

{{model.title}}

'); - this.assertText(`Nothing here`); + expectDeprecation(() => { + this.render( + `{{#if showPost}}{{render 'post' post}}{{else}}Nothing here{{/if}}`, + { + showPost: false, + post: { + title: `It's Simple Made Easy` + } + } + ); + }, /Please refactor [\w\{\}"` ]+ to a component/); - assert.strictEqual(willDestroyFired, 0, 'it did not destroy the controller'); + this.assertText(`Nothing here`); - this.runTask(() => set(this.context, 'showPost', true)); + assert.strictEqual( + willDestroyFired, + 0, + 'it did not destroy the controller' + ); - this.assertText(`It's Simple Made Easy`); + this.runTask(() => this.rerender()); - assert.strictEqual(willDestroyFired, 0, 'it did not destroy the controller'); + this.assertText(`Nothing here`); - this.runTask(() => set(this.context, 'showPost', false)); + assert.strictEqual( + willDestroyFired, + 0, + 'it did not destroy the controller' + ); - this.assertText(`Nothing here`); + this.runTask(() => set(this.context, 'showPost', true)); - assert.strictEqual(willDestroyFired, 0, 'it did not destroy the controller'); - } + this.assertText(`It's Simple Made Easy`); - ['@test should render given template with a supplied model']() { - this.owner.register('controller:post', Controller.extend()); - this.registerTemplate('post', '

{{model.title}}

'); + assert.strictEqual( + willDestroyFired, + 0, + 'it did not destroy the controller' + ); - expectDeprecation(() => { - this.render(`

HI

{{render 'post' post}}`, { - post: { - title: `It's Simple Made Easy` - } - }); - }, /Please refactor [\w\{\}"` ]+ to a component/); + this.runTask(() => set(this.context, 'showPost', false)); - this.assertText(`HIIt's Simple Made Easy`); - - this.runTask(() => this.rerender()); - - this.assertText(`HIIt's Simple Made Easy`); - - this.runTask(() => set(this.context, 'post.title', `Rails is omakase`)); - - this.assertText(`HIRails is omakase`); - - this.runTask(() => set(this.context, 'post', { title: `It's Simple Made Easy` })); - - this.assertText(`HIIt's Simple Made Easy`); - } - - ['@test should destroy the non-singleton controllers on teardown'](assert) { - let willDestroyFired = 0; - - this.owner.register('controller:post', Controller.extend({ - willDestroy() { - this._super(...arguments); - willDestroyFired++; - } - })); - - this.registerTemplate('post', '

{{model.title}}

'); - - expectDeprecation(() => { - this.render(`{{#if showPost}}{{render 'post' post}}{{else}}Nothing here{{/if}}`, { - showPost: false, - post: { - title: `It's Simple Made Easy` - } - }); - }, /Please refactor [\w\{\}"` ]+ to a component/); + this.assertText(`Nothing here`); - this.assertText(`Nothing here`); + assert.strictEqual(willDestroyFired, 1, 'it did destroy the controller'); + + this.runTask(() => set(this.context, 'showPost', true)); + + this.assertText(`It's Simple Made Easy`); + + assert.strictEqual( + willDestroyFired, + 1, + 'it did not destroy the controller' + ); + + this.runTask(() => set(this.context, 'showPost', false)); + + this.assertText(`Nothing here`); - assert.strictEqual(willDestroyFired, 0, 'it did not destroy the controller'); + assert.strictEqual(willDestroyFired, 2, 'it did destroy the controller'); + } - this.runTask(() => this.rerender()); + ['@test with a supplied model should not fire observers on the controller']( + assert + ) { + this.owner.register('controller:post', Controller.extend()); + this.registerTemplate('post', '

{{model.title}}

'); - this.assertText(`Nothing here`); + let postDidChange = 0; + expectDeprecation(() => { + this.render(`

HI

{{render 'post' post}}`, { + postDidChange: observer('post', function() { + postDidChange++; + }), + post: { + title: `It's Simple Made Easy` + } + }); + }, /Please refactor [\w\{\}"` ]+ to a component/); + + this.assertText(`HIIt's Simple Made Easy`); + + this.runTask(() => this.rerender()); + + this.assertText(`HIIt's Simple Made Easy`); + assert.equal(postDidChange, 0); + } + + ['@test should raise an error when a given controller name does not resolve to a controller']() { + this.registerTemplate('home', '

BYE

'); + this.owner.register('controller:posts', Controller.extend()); + + expectDeprecation(() => { + expectAssertion(() => { + this.render(`

HI

{{render "home" controller="postss"}}`); + }, /The controller name you supplied \'postss\' did not resolve to a controller./); + }, /Please refactor [\w\{\}"` ]+ to a component/); + } + + ['@test should render with given controller'](assert) { + this.registerTemplate('home', '{{uniqueId}}'); + + let id = 0; + let model = {}; + + this.owner.register( + 'controller:posts', + Controller.extend({ + init() { + this._super(...arguments); + this.uniqueId = id++; + this.set('model', model); + } + }) + ); + + expectDeprecation(() => { + this.render('{{render "home" controller="posts"}}'); + }, /Please refactor [\w\{\}"` ]+ to a component/); + + let renderedController = this.owner.lookup('controller:posts'); + let uniqueId = renderedController.get('uniqueId'); + let renderedModel = renderedController.get('model'); + + assert.equal(uniqueId, 0); + assert.equal(renderedModel, model); + this.assertText('0'); + + this.runTask(() => this.rerender()); + + assert.equal(uniqueId, 0); + assert.equal(renderedModel, model); + this.assertText('0'); + } + + ['@test should render templates with models multiple times']() { + this.owner.register('controller:post', Controller.extend()); + + this.registerTemplate('post', '

{{model.title}}

'); + expectDeprecation(() => { + this.render( + `

HI

{{render 'post' post1}} {{render 'post' post2}}`, + { + post1: { + title: 'Me First' + }, + post2: { + title: 'Then me' + } + } + ); + }, /Please refactor [\w\{\}"` ]+ to a component/); + + this.assertText('HI Me First Then me'); + + this.runTask(() => this.rerender()); + + this.assertText('HI Me First Then me'); + + this.runTask(() => set(this.context, 'post1.title', 'I am new')); + + this.assertText('HI I am new Then me'); + + this.runTask(() => set(this.context, 'post1', { title: 'Me First' })); + + this.assertText('HI Me First Then me'); + } + + ['@test should not treat invocations with falsy contexts as context-less']( + assert + ) { + this.registerTemplate( + 'post', + '

{{#unless model.zero}}NOTHING{{/unless}}

' + ); + this.owner.register('controller:post', Controller.extend()); + + expectDeprecation(() => { + this.render( + `

HI

{{render 'post' zero}} {{render 'post' nonexistent}}`, + { + model: { + zero: false + } + } + ); + }, /Please refactor [\w\{\}"` ]+ to a component/); + + assert.ok( + this.$() + .text() + .match(/^HI ?NOTHING ?NOTHING$/) + ); + } + + ['@test should render templates both with and without models'](assert) { + this.registerTemplate('post', `

Title:{{model.title}}

`); + this.owner.register('controller:post', Controller.extend()); + + let post = { + title: 'Rails is omakase' + }; + expectDeprecation(() => { + this.render(`

HI

{{render 'post'}} {{render 'post' post}}`, { + post + }); + }, /Please refactor [\w\{\}"` ]+ to a component/); + + assert.ok( + this.$() + .text() + .match(/^HI ?Title: ?Title:Rails is omakase$/) + ); + + this.runTask(() => this.rerender()); + + assert.ok( + this.$() + .text() + .match(/^HI ?Title: ?Title:Rails is omakase$/) + ); + + this.runTask(() => set(this.context, 'post.title', 'Simple Made Easy')); + + assert.ok( + this.$() + .text() + .match(/^HI ?Title: ?Title:Simple Made Easy$/) + ); + + this.runTask(() => + set(this.context, 'post', { title: 'Rails is omakase' }) + ); + + assert.ok( + this.$() + .text() + .match(/^HI ?Title: ?Title:Rails is omakase$/) + ); + } + + ['@test works with dot notation']() { + this.registerTemplate('blog.post', '{{uniqueId}}'); + + let id = 0; + this.owner.register( + 'controller:blog.post', + Controller.extend({ + init() { + this._super(...arguments); + this.uniqueId = id++; + } + }) + ); + + expectDeprecation(() => { + this.render('{{render "blog.post"}}'); + }, /Please refactor [\w\.{\}"` ]+ to a component/); + + this.assertText(`0`); + } + + ['@test throws an assertion if called with an unquoted template name']() { + this.registerTemplate('home', '

BYE

'); - assert.strictEqual(willDestroyFired, 0, 'it did not destroy the controller'); - - this.runTask(() => set(this.context, 'showPost', true)); - - this.assertText(`It's Simple Made Easy`); - - assert.strictEqual(willDestroyFired, 0, 'it did not destroy the controller'); - - this.runTask(() => set(this.context, 'showPost', false)); - - this.assertText(`Nothing here`); - - assert.strictEqual(willDestroyFired, 1, 'it did destroy the controller'); - - this.runTask(() => set(this.context, 'showPost', true)); - - this.assertText(`It's Simple Made Easy`); - - assert.strictEqual(willDestroyFired, 1, 'it did not destroy the controller'); - - this.runTask(() => set(this.context, 'showPost', false)); - - this.assertText(`Nothing here`); - - assert.strictEqual(willDestroyFired, 2, 'it did destroy the controller'); - } - - ['@test with a supplied model should not fire observers on the controller'](assert) { - this.owner.register('controller:post', Controller.extend()); - this.registerTemplate('post', '

{{model.title}}

'); - - let postDidChange = 0; - expectDeprecation(() => { - this.render(`

HI

{{render 'post' post}}`, { - postDidChange: observer('post', function() { - postDidChange++; - }), - post: { - title: `It's Simple Made Easy` - } - }); - }, /Please refactor [\w\{\}"` ]+ to a component/); - - this.assertText(`HIIt's Simple Made Easy`); - - this.runTask(() => this.rerender()); - - this.assertText(`HIIt's Simple Made Easy`); - assert.equal(postDidChange, 0); - } - - ['@test should raise an error when a given controller name does not resolve to a controller']() { - this.registerTemplate('home', '

BYE

'); - this.owner.register('controller:posts', Controller.extend()); - - expectDeprecation(() => { expectAssertion(() => { - this.render(`

HI

{{render "home" controller="postss"}}`); - }, /The controller name you supplied \'postss\' did not resolve to a controller./); - }, /Please refactor [\w\{\}"` ]+ to a component/); - } - - ['@test should render with given controller'](assert) { - this.registerTemplate('home', '{{uniqueId}}'); - - let id = 0; - let model = {}; - - this.owner.register('controller:posts', Controller.extend({ - init() { - this._super(...arguments); - this.uniqueId = id++; - this.set('model', model); - } - })); + this.render('

HI

{{render home}}'); + }, 'The first argument of {{render}} must be quoted, e.g. {{render "sidebar"}}.'); + } - expectDeprecation(() => { - this.render('{{render "home" controller="posts"}}'); - }, /Please refactor [\w\{\}"` ]+ to a component/); - - let renderedController = this.owner.lookup('controller:posts'); - let uniqueId = renderedController.get('uniqueId'); - let renderedModel = renderedController.get('model'); - - assert.equal(uniqueId, 0); - assert.equal(renderedModel, model); - this.assertText('0'); - - this.runTask(() => this.rerender()); - - assert.equal(uniqueId, 0); - assert.equal(renderedModel, model); - this.assertText('0'); - } - - ['@test should render templates with models multiple times']() { - this.owner.register('controller:post', Controller.extend()); - - this.registerTemplate('post', '

{{model.title}}

'); - expectDeprecation(() => { - this.render(`

HI

{{render 'post' post1}} {{render 'post' post2}}`, { - post1: { - title: 'Me First' - }, - post2: { - title: 'Then me' - } - }); - }, /Please refactor [\w\{\}"` ]+ to a component/); - - this.assertText('HI Me First Then me'); - - this.runTask(() => this.rerender()); - - this.assertText('HI Me First Then me'); - - this.runTask(() => set(this.context, 'post1.title', 'I am new')); - - this.assertText('HI I am new Then me'); - - this.runTask(() => set(this.context, 'post1', { title: 'Me First' })); - - this.assertText('HI Me First Then me'); - } - - ['@test should not treat invocations with falsy contexts as context-less'](assert) { - this.registerTemplate('post', '

{{#unless model.zero}}NOTHING{{/unless}}

'); - this.owner.register('controller:post', Controller.extend()); - - expectDeprecation(() => { - this.render(`

HI

{{render 'post' zero}} {{render 'post' nonexistent}}`, { - model: { - zero: false - } - }); - }, /Please refactor [\w\{\}"` ]+ to a component/); - - assert.ok(this.$().text().match(/^HI ?NOTHING ?NOTHING$/)); - } - - ['@test should render templates both with and without models'](assert) { - this.registerTemplate('post', `

Title:{{model.title}}

`); - this.owner.register('controller:post', Controller.extend()); - - let post = { - title: 'Rails is omakase' - }; - expectDeprecation(() => { - this.render(`

HI

{{render 'post'}} {{render 'post' post}}`, { - post - }); - }, /Please refactor [\w\{\}"` ]+ to a component/); - - assert.ok(this.$().text().match(/^HI ?Title: ?Title:Rails is omakase$/)); - - this.runTask(() => this.rerender()); - - assert.ok(this.$().text().match(/^HI ?Title: ?Title:Rails is omakase$/)); - - this.runTask(() => set(this.context, 'post.title', 'Simple Made Easy')); - - assert.ok(this.$().text().match(/^HI ?Title: ?Title:Simple Made Easy$/)); - - this.runTask(() => set(this.context, 'post', { title: 'Rails is omakase' })); - - assert.ok(this.$().text().match(/^HI ?Title: ?Title:Rails is omakase$/)); - } - - ['@test works with dot notation']() { - this.registerTemplate('blog.post', '{{uniqueId}}'); - - let id = 0; - this.owner.register('controller:blog.post', Controller.extend({ - init() { - this._super(...arguments); - this.uniqueId = id++; - } - })); - - expectDeprecation(() => { - this.render('{{render "blog.post"}}'); - }, /Please refactor [\w\.{\}"` ]+ to a component/); - - this.assertText(`0`); - } - - ['@test throws an assertion if called with an unquoted template name']() { - this.registerTemplate('home', '

BYE

'); - - expectAssertion(() => { - this.render('

HI

{{render home}}'); - }, 'The first argument of {{render}} must be quoted, e.g. {{render "sidebar"}}.'); - } - - ['@test throws an assertion if called with a literal for a model']() { - this.registerTemplate('home', '

BYE

'); - expectAssertion(() => { - this.render('

HI

{{render "home" "model"}}', { - model: { - title: 'Simple Made Easy' + ['@test throws an assertion if called with a literal for a model']() { + this.registerTemplate('home', '

BYE

'); + expectAssertion(() => { + this.render('

HI

{{render "home" "model"}}', { + model: { + title: 'Simple Made Easy' + } + }); + }, 'The second argument of {{render}} must be a path, e.g. {{render "post" post}}.'); + } + + ['@test should set router as target when action not found on parentController is not found']( + assert + ) { + let postController; + this.registerTemplate('post', 'post template'); + this.owner.register( + 'controller:post', + Controller.extend({ + init() { + this._super(...arguments); + postController = this; + } + }) + ); + + let routerStub = { + send(actionName) { + assert.equal(actionName, 'someAction'); + assert.ok(true, 'routerStub#send called'); } + }; + + this.owner.register('router:main', routerStub, { instantiate: false }); + + expectDeprecation(() => { + this.render(`{{render 'post' post1}}`); + }, /Please refactor [\w\{\}"` ]+ to a component/); + + postController.send('someAction'); + } + + ['@test render helper emits useful backtracking re-render assertion message']() { + this.owner.register('controller:outer', Controller.extend()); + this.owner.register( + 'controller:inner', + Controller.extend({ + propertyWithError: computed(function() { + this.set('model.name', 'this will cause a backtracking error'); + return 'foo'; + }) + }) + ); + + let expectedBacktrackingMessage = /modified "model\.name" twice on \[object Object\] in a single render\. It was rendered in "controller:outer \(with the render helper\)" and modified in "controller:inner \(with the render helper\)"/; + + expectDeprecation(() => { + let person = { name: 'Ben' }; + + this.registerTemplate( + 'outer', + `Hi {{model.name}} | {{render 'inner' model}}` + ); + this.registerTemplate('inner', `Hi {{propertyWithError}}`); + + expectAssertion(() => { + this.render(`{{render 'outer' person}}`, { person }); + }, expectedBacktrackingMessage); }); - }, 'The second argument of {{render}} must be a path, e.g. {{render "post" post}}.'); - } - - ['@test should set router as target when action not found on parentController is not found'](assert) { - let postController; - this.registerTemplate('post', 'post template'); - this.owner.register('controller:post', Controller.extend({ - init() { - this._super(...arguments); - postController = this; - } - })); - - let routerStub = { - send(actionName) { - assert.equal(actionName, 'someAction'); - assert.ok(true, 'routerStub#send called'); - } - }; - - this.owner.register('router:main', routerStub, { instantiate: false }); - - expectDeprecation(() => { - this.render(`{{render 'post' post1}}`); - }, /Please refactor [\w\{\}"` ]+ to a component/); - - postController.send('someAction'); - } - - ['@test render helper emits useful backtracking re-render assertion message']() { - this.owner.register('controller:outer', Controller.extend()); - this.owner.register('controller:inner', Controller.extend({ - propertyWithError: computed(function() { - this.set('model.name', 'this will cause a backtracking error'); - return 'foo'; - }) - })); - - let expectedBacktrackingMessage = /modified "model\.name" twice on \[object Object\] in a single render\. It was rendered in "controller:outer \(with the render helper\)" and modified in "controller:inner \(with the render helper\)"/; - - expectDeprecation(() => { - let person = { name: 'Ben' }; - - this.registerTemplate('outer', `Hi {{model.name}} | {{render 'inner' model}}`); - this.registerTemplate('inner', `Hi {{propertyWithError}}`); - - expectAssertion(() => { - this.render(`{{render 'outer' person}}`, { person }); - }, expectedBacktrackingMessage); - }); + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/helpers/text-area-test.js b/packages/ember-glimmer/tests/integration/helpers/text-area-test.js index e2727f88341..bb064e5696a 100644 --- a/packages/ember-glimmer/tests/integration/helpers/text-area-test.js +++ b/packages/ember-glimmer/tests/integration/helpers/text-area-test.js @@ -6,8 +6,14 @@ import { applyMixins } from '../../utils/abstract-test-case'; class TextAreaRenderingTest extends RenderingTest { assertTextArea({ attrs, value } = {}) { - let mergedAttrs = assign({ 'class': classes('ember-view ember-text-area') }, attrs); - this.assertComponentElement(this.firstChild, { tagName: 'textarea', attrs: mergedAttrs }); + let mergedAttrs = assign( + { class: classes('ember-view ember-text-area') }, + attrs + ); + this.assertComponentElement(this.firstChild, { + tagName: 'textarea', + attrs: mergedAttrs + }); if (value) { this.assert.strictEqual(value, this.firstChild.value); @@ -61,101 +67,107 @@ applyMixins( ]) ); -moduleFor('Helpers test: {{textarea}}', class extends TextAreaRenderingTest { - - ['@test Should insert a textarea'](assert) { - this.render('{{textarea}}'); - - assert.equal(this.$('textarea').length, 1); - - this.assertStableRerender(); - } - - ['@test Should respect disabled'](assert) { - this.render('{{textarea disabled=disabled}}', { - disabled: true - }); - assert.ok(this.$('textarea').is(':disabled')); - } - - ['@test Should respect disabled when false'](assert) { - this.render('{{textarea disabled=disabled}}', { - disabled: false - }); - assert.ok(this.$('textarea').is(':not(:disabled)')); - } +moduleFor( + 'Helpers test: {{textarea}}', + class extends TextAreaRenderingTest { + ['@test Should insert a textarea'](assert) { + this.render('{{textarea}}'); - ['@test Should become disabled when the context changes'](assert) { - this.render('{{textarea disabled=disabled}}'); - assert.ok(this.$('textarea').is(':not(:disabled)')); + assert.equal(this.$('textarea').length, 1); - this.assertStableRerender(); - - this.runTask(() => set(this.context, 'disabled', true)); - assert.ok(this.$('textarea').is(':disabled')); + this.assertStableRerender(); + } - this.runTask(() => set(this.context, 'disabled', false)); - assert.ok(this.$('textarea').is(':not(:disabled)')); - } + ['@test Should respect disabled'](assert) { + this.render('{{textarea disabled=disabled}}', { + disabled: true + }); + assert.ok(this.$('textarea').is(':disabled')); + } - ['@test Should bind its contents to the specified value']() { - this.render('{{textarea value=model.val}}', { - model: { val: 'A beautiful day in Seattle' } - }); - this.assertTextArea({ value: 'A beautiful day in Seattle' }); + ['@test Should respect disabled when false'](assert) { + this.render('{{textarea disabled=disabled}}', { + disabled: false + }); + assert.ok(this.$('textarea').is(':not(:disabled)')); + } - this.assertStableRerender(); + ['@test Should become disabled when the context changes'](assert) { + this.render('{{textarea disabled=disabled}}'); + assert.ok(this.$('textarea').is(':not(:disabled)')); - this.runTask(() => set(this.context, 'model.val', 'Auckland')); - this.assertTextArea({ value: 'Auckland' }); + this.assertStableRerender(); - this.runTask(() => set(this.context, 'model', { val: 'A beautiful day in Seattle' })); - this.assertTextArea({ value: 'A beautiful day in Seattle' }); - } + this.runTask(() => set(this.context, 'disabled', true)); + assert.ok(this.$('textarea').is(':disabled')); - ['@test GH#14001 Should correctly handle an empty string bound value']() { - this.render('{{textarea value=message}}', { message: '' }); + this.runTask(() => set(this.context, 'disabled', false)); + assert.ok(this.$('textarea').is(':not(:disabled)')); + } - this.assert.strictEqual(this.firstChild.value, ''); + ['@test Should bind its contents to the specified value']() { + this.render('{{textarea value=model.val}}', { + model: { val: 'A beautiful day in Seattle' } + }); + this.assertTextArea({ value: 'A beautiful day in Seattle' }); - this.assertStableRerender(); + this.assertStableRerender(); - this.runTask(() => set(this.context, 'message', 'hello')); + this.runTask(() => set(this.context, 'model.val', 'Auckland')); + this.assertTextArea({ value: 'Auckland' }); - this.assert.strictEqual(this.firstChild.value, 'hello'); + this.runTask(() => + set(this.context, 'model', { val: 'A beautiful day in Seattle' }) + ); + this.assertTextArea({ value: 'A beautiful day in Seattle' }); + } - this.runTask(() => set(this.context, 'message', '')); + ['@test GH#14001 Should correctly handle an empty string bound value']() { + this.render('{{textarea value=message}}', { message: '' }); - this.assert.strictEqual(this.firstChild.value, ''); - } + this.assert.strictEqual(this.firstChild.value, ''); - ['@test should update the value for `cut` / `input` / `change` events']() { - this.render('{{textarea value=model.val}}', { - model: { val: 'A beautiful day in Seattle' } - }); - this.assertTextArea({ value: 'A beautiful day in Seattle' }); + this.assertStableRerender(); - this.assertStableRerender(); + this.runTask(() => set(this.context, 'message', 'hello')); - this.runTask(() => { - this.firstChild.value = 'Auckland'; - this.triggerEvent('cut'); - }); - this.assertTextArea({ value: 'Auckland' }); + this.assert.strictEqual(this.firstChild.value, 'hello'); - this.runTask(() => { - this.firstChild.value = 'Hope'; - this.triggerEvent('paste'); - }); - this.assertTextArea({ value: 'Hope' }); + this.runTask(() => set(this.context, 'message', '')); - this.runTask(() => { - this.firstChild.value = 'Boston'; - this.triggerEvent('input'); - }); - this.assertTextArea({ value: 'Boston' }); + this.assert.strictEqual(this.firstChild.value, ''); + } - this.runTask(() => set(this.context, 'model', { val: 'A beautiful day in Seattle' })); - this.assertTextArea({ value: 'A beautiful day in Seattle' }); + ['@test should update the value for `cut` / `input` / `change` events']() { + this.render('{{textarea value=model.val}}', { + model: { val: 'A beautiful day in Seattle' } + }); + this.assertTextArea({ value: 'A beautiful day in Seattle' }); + + this.assertStableRerender(); + + this.runTask(() => { + this.firstChild.value = 'Auckland'; + this.triggerEvent('cut'); + }); + this.assertTextArea({ value: 'Auckland' }); + + this.runTask(() => { + this.firstChild.value = 'Hope'; + this.triggerEvent('paste'); + }); + this.assertTextArea({ value: 'Hope' }); + + this.runTask(() => { + this.firstChild.value = 'Boston'; + this.triggerEvent('input'); + }); + this.assertTextArea({ value: 'Boston' }); + + this.runTask(() => + set(this.context, 'model', { val: 'A beautiful day in Seattle' }) + ); + this.assertTextArea({ value: 'A beautiful day in Seattle' }); + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/helpers/unbound-test.js b/packages/ember-glimmer/tests/integration/helpers/unbound-test.js index 1cd522ab512..2842928c84a 100644 --- a/packages/ember-glimmer/tests/integration/helpers/unbound-test.js +++ b/packages/ember-glimmer/tests/integration/helpers/unbound-test.js @@ -4,116 +4,133 @@ import { set, get, setProperties } from 'ember-metal'; import { Component } from '../../utils/helpers'; import { A as emberA } from 'ember-runtime'; -moduleFor('Helpers test: {{unbound}}', class extends RenderingTest { +moduleFor( + 'Helpers test: {{unbound}}', + class extends RenderingTest { + ['@test should be able to output a property without binding']() { + this.render(`
{{unbound content.anUnboundString}}
`, { + content: { + anUnboundString: 'No spans here, son.' + } + }); - ['@test should be able to output a property without binding']() { - this.render(`
{{unbound content.anUnboundString}}
`, { - content: { - anUnboundString: 'No spans here, son.' - } - }); + this.assertText('No spans here, son.'); - this.assertText('No spans here, son.'); + this.runTask(() => this.rerender()); - this.runTask(() => this.rerender()); + this.assertText('No spans here, son.'); - this.assertText('No spans here, son.'); + this.runTask(() => set(this.context, 'content.anUnboundString', 'HEY')); - this.runTask(() => set(this.context, 'content.anUnboundString', 'HEY')); + this.assertText('No spans here, son.'); - this.assertText('No spans here, son.'); + this.runTask(() => + set(this.context, 'content', { + anUnboundString: 'No spans here, son.' + }) + ); - this.runTask(() => set(this.context, 'content', { - anUnboundString: 'No spans here, son.' - })); + this.assertText('No spans here, son.'); + } - this.assertText('No spans here, son.'); - } + ['@test should be able to use unbound helper in #each helper']() { + this.render( + `
    {{#each items as |item|}}
  • {{unbound item}}
  • {{/each}}
`, + { + items: emberA(['a', 'b', 'c', 1, 2, 3]) + } + ); - ['@test should be able to use unbound helper in #each helper']() { - this.render(`
    {{#each items as |item|}}
  • {{unbound item}}
  • {{/each}}
`, { - items: emberA(['a', 'b', 'c', 1, 2, 3]) - }); + this.assertText('abc123'); - this.assertText('abc123'); + this.runTask(() => this.rerender()); - this.runTask(() => this.rerender()); + this.assertText('abc123'); + } - this.assertText('abc123'); - } + ['@test should be able to use unbound helper in #each helper (with objects)']() { + this.render( + `
    {{#each items as |item|}}
  • {{unbound item.wham}}
  • {{/each}}
`, + { + items: emberA([{ wham: 'bam' }, { wham: 1 }]) + } + ); - ['@test should be able to use unbound helper in #each helper (with objects)']() { - this.render(`
    {{#each items as |item|}}
  • {{unbound item.wham}}
  • {{/each}}
`, { - items: emberA([{ wham: 'bam' }, { wham: 1 }]) - }); + this.assertText('bam1'); - this.assertText('bam1'); + this.runTask(() => this.rerender()); - this.runTask(() => this.rerender()); + this.assertText('bam1'); - this.assertText('bam1'); + this.runTask(() => this.context.items.setEach('wham', 'HEY')); - this.runTask(() => this.context.items.setEach('wham', 'HEY')); + this.assertText('bam1'); - this.assertText('bam1'); + this.runTask(() => + set(this.context, 'items', emberA([{ wham: 'bam' }, { wham: 1 }])) + ); - this.runTask(() => set(this.context, 'items', emberA([{ wham: 'bam' }, { wham: 1 }]))); + this.assertText('bam1'); + } - this.assertText('bam1'); - } + ['@test it should assert unbound cannot be called with multiple arguments']() { + let willThrow = () => { + this.render(`{{unbound foo bar}}`, { + foo: 'BORK', + bar: 'BLOOP' + }); + }; + + expectAssertion( + willThrow, + /unbound helper cannot be called with multiple params or hash params/ + ); + } - ['@test it should assert unbound cannot be called with multiple arguments']() { - let willThrow = () => { - this.render(`{{unbound foo bar}}`, { - foo: 'BORK', - bar: 'BLOOP' + ['@test should render on attributes']() { + this.render(``, { + model: { foo: 'BORK' } }); - }; - expectAssertion(willThrow, /unbound helper cannot be called with multiple params or hash params/); - } + this.assertHTML(''); - ['@test should render on attributes']() { - this.render(``, { - model: { foo: 'BORK' } - }); + this.runTask(() => this.rerender()); - this.assertHTML(''); + this.assertHTML(''); - this.runTask(() => this.rerender()); + this.runTask(() => set(this.context, 'model.foo', 'OOF')); - this.assertHTML(''); + this.assertHTML(''); - this.runTask(() => set(this.context, 'model.foo', 'OOF')); + this.runTask(() => set(this.context, 'model', { foo: 'BORK' })); - this.assertHTML(''); + this.assertHTML(''); + } - this.runTask(() => set(this.context, 'model', { foo: 'BORK' })); + ['@test should property escape unsafe hrefs']() { + let unsafeUrls = emberA([ + { + name: 'Bob', + url: 'javascript:bob-is-cool' // jshint ignore:line + }, + { + name: 'James', + url: 'vbscript:james-is-cool' // jshint ignore:line + }, + { + name: 'Richard', + url: 'javascript:richard-is-cool' // jshint ignore:line + } + ]); - this.assertHTML(''); - } + this.render( + ``, + { + people: unsafeUrls + } + ); - ['@test should property escape unsafe hrefs']() { - let unsafeUrls = emberA([ - { - name: 'Bob', - url: 'javascript:bob-is-cool' // jshint ignore:line - }, - { - name: 'James', - url: 'vbscript:james-is-cool' // jshint ignore:line - }, - { - name: 'Richard', - url: 'javascript:richard-is-cool' // jshint ignore:line - } - ]); - - this.render(``, { - people: unsafeUrls - }); - - let escapedHtml = strip` + let escapedHtml = strip`
  • Bob @@ -127,384 +144,432 @@ moduleFor('Helpers test: {{unbound}}', class extends RenderingTest {
`; - this.assertHTML(escapedHtml); - - this.runTask(() => this.rerender()); + this.assertHTML(escapedHtml); - this.assertHTML(escapedHtml); + this.runTask(() => this.rerender()); - this.runTask(() => this.context.people.setEach('url', 'http://google.com')); + this.assertHTML(escapedHtml); - this.assertHTML(escapedHtml); + this.runTask(() => + this.context.people.setEach('url', 'http://google.com') + ); - this.runTask(() => set(this.context, 'people', unsafeUrls)); + this.assertHTML(escapedHtml); - this.assertHTML(escapedHtml); - } + this.runTask(() => set(this.context, 'people', unsafeUrls)); - ['@skip helper form updates on parent re-render']() { - this.render(`{{unbound foo}}`, { - foo: 'BORK' - }); + this.assertHTML(escapedHtml); + } - this.assertText('BORK'); + ['@skip helper form updates on parent re-render']() { + this.render(`{{unbound foo}}`, { + foo: 'BORK' + }); - this.runTask(() => this.rerender()); + this.assertText('BORK'); - this.assertText('BORK'); + this.runTask(() => this.rerender()); - this.runTask(() => set(this.context, 'foo', 'OOF')); + this.assertText('BORK'); - this.assertText('BORK'); + this.runTask(() => set(this.context, 'foo', 'OOF')); - this.runTask(() => this.rerender()); + this.assertText('BORK'); - this.assertText('OOF'); + this.runTask(() => this.rerender()); - this.runTask(() => set(this.context, 'foo', '')); + this.assertText('OOF'); - this.assertText('OOF'); + this.runTask(() => set(this.context, 'foo', '')); - this.runTask(() => set(this.context, 'foo', 'BORK')); + this.assertText('OOF'); - this.runTask(() => this.rerender()); + this.runTask(() => set(this.context, 'foo', 'BORK')); - this.assertText('BORK'); - } + this.runTask(() => this.rerender()); - // semantics here is not guaranteed - ['@test sexpr form does not update no matter what']() { - this.registerHelper('capitalize', (args) => args[0].toUpperCase()); + this.assertText('BORK'); + } - this.render(`{{capitalize (unbound foo)}}`, { - foo: 'bork' - }); + // semantics here is not guaranteed + ['@test sexpr form does not update no matter what']() { + this.registerHelper('capitalize', args => args[0].toUpperCase()); - this.assertText('BORK'); + this.render(`{{capitalize (unbound foo)}}`, { + foo: 'bork' + }); - this.runTask(() => this.rerender()); + this.assertText('BORK'); - this.assertText('BORK'); + this.runTask(() => this.rerender()); - this.runTask(() => { - set(this.context, 'foo', 'oof'); - this.rerender(); - }); + this.assertText('BORK'); - this.assertText('BORK'); + this.runTask(() => { + set(this.context, 'foo', 'oof'); + this.rerender(); + }); - this.runTask(() => set(this.context, 'foo', 'blip')); + this.assertText('BORK'); - this.assertText('BORK'); + this.runTask(() => set(this.context, 'foo', 'blip')); - this.runTask(() => { - set(this.context, 'foo', 'bork'); - this.rerender(); - }); + this.assertText('BORK'); - this.assertText('BORK'); - } + this.runTask(() => { + set(this.context, 'foo', 'bork'); + this.rerender(); + }); - ['@test sexpr in helper form does not update on parent re-render']() { - this.registerHelper('capitalize', (params) => params[0].toUpperCase()); + this.assertText('BORK'); + } - this.registerHelper('doublize', (params) => `${params[0]} ${params[0]}`); + ['@test sexpr in helper form does not update on parent re-render']() { + this.registerHelper('capitalize', params => params[0].toUpperCase()); - this.render(`{{capitalize (unbound (doublize foo))}}`, { - foo: 'bork' - }); + this.registerHelper('doublize', params => `${params[0]} ${params[0]}`); - this.assertText('BORK BORK'); + this.render(`{{capitalize (unbound (doublize foo))}}`, { + foo: 'bork' + }); - this.runTask(() => this.rerender()); + this.assertText('BORK BORK'); - this.assertText('BORK BORK'); + this.runTask(() => this.rerender()); - this.runTask(() => { - set(this.context, 'foo', 'oof'); - this.rerender(); - }); + this.assertText('BORK BORK'); - this.assertText('BORK BORK'); + this.runTask(() => { + set(this.context, 'foo', 'oof'); + this.rerender(); + }); - this.runTask(() => set(this.context, 'foo', 'blip')); + this.assertText('BORK BORK'); - this.assertText('BORK BORK'); + this.runTask(() => set(this.context, 'foo', 'blip')); - this.runTask(() => { - set(this.context, 'foo', 'bork'); - this.rerender(); - }); + this.assertText('BORK BORK'); - this.assertText('BORK BORK'); - } + this.runTask(() => { + set(this.context, 'foo', 'bork'); + this.rerender(); + }); - ['@test should be able to render an unbound helper invocation']() { - this.registerHelper('repeat', ([value], { count }) => { - let a = []; - while (a.length < count) { - a.push(value); - } - return a.join(''); - }); + this.assertText('BORK BORK'); + } - this.render(`{{unbound (repeat foo count=bar)}} {{repeat foo count=bar}} {{unbound (repeat foo count=2)}} {{repeat foo count=4}}`, { - foo: 'X', - bar: 5 - }); + ['@test should be able to render an unbound helper invocation']() { + this.registerHelper('repeat', ([value], { count }) => { + let a = []; + while (a.length < count) { + a.push(value); + } + return a.join(''); + }); + this.render( + `{{unbound (repeat foo count=bar)}} {{repeat foo count=bar}} {{unbound (repeat foo count=2)}} {{repeat foo count=4}}`, + { + foo: 'X', + bar: 5 + } + ); - this.assertText('XXXXX XXXXX XX XXXX'); + this.assertText('XXXXX XXXXX XX XXXX'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('XXXXX XXXXX XX XXXX'); + this.assertText('XXXXX XXXXX XX XXXX'); - this.runTask(() => set(this.context, 'bar', 1)); + this.runTask(() => set(this.context, 'bar', 1)); - this.assertText('XXXXX X XX XXXX'); + this.assertText('XXXXX X XX XXXX'); - this.runTask(() => set(this.context, 'bar', 5)); + this.runTask(() => set(this.context, 'bar', 5)); - this.assertText('XXXXX XXXXX XX XXXX'); - } + this.assertText('XXXXX XXXXX XX XXXX'); + } - ['@test should be able to render an bound helper invocation mixed with static values']() { - this.registerHelper('surround', ([prefix, value, suffix]) => `${prefix}-${value}-${suffix}`); + ['@test should be able to render an bound helper invocation mixed with static values']() { + this.registerHelper( + 'surround', + ([prefix, value, suffix]) => `${prefix}-${value}-${suffix}` + ); - this.render(strip` - {{unbound (surround model.prefix model.value "bar")}} {{surround model.prefix model.value "bar"}} {{unbound (surround "bar" model.value model.suffix)}} {{surround "bar" model.value model.suffix}}`, { - model: { - prefix: 'before', - value: 'core', - suffix: 'after' + this.render( + strip` + {{unbound (surround model.prefix model.value "bar")}} {{surround model.prefix model.value "bar"}} {{unbound (surround "bar" model.value model.suffix)}} {{surround "bar" model.value model.suffix}}`, + { + model: { + prefix: 'before', + value: 'core', + suffix: 'after' + } } - }); + ); - this.assertText('before-core-bar before-core-bar bar-core-after bar-core-after'); + this.assertText( + 'before-core-bar before-core-bar bar-core-after bar-core-after' + ); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('before-core-bar before-core-bar bar-core-after bar-core-after'); + this.assertText( + 'before-core-bar before-core-bar bar-core-after bar-core-after' + ); - this.runTask(() => { - setProperties(this.context.model, { - prefix: 'beforeChanged', - value: 'coreChanged', - suffix: 'afterChanged' + this.runTask(() => { + setProperties(this.context.model, { + prefix: 'beforeChanged', + value: 'coreChanged', + suffix: 'afterChanged' + }); }); - }); - this.assertText('before-core-bar beforeChanged-coreChanged-bar bar-core-after bar-coreChanged-afterChanged'); + this.assertText( + 'before-core-bar beforeChanged-coreChanged-bar bar-core-after bar-coreChanged-afterChanged' + ); - this.runTask(() => { - set(this.context, 'model', { - prefix: 'before', - value: 'core', - suffix: 'after' + this.runTask(() => { + set(this.context, 'model', { + prefix: 'before', + value: 'core', + suffix: 'after' + }); }); - }); - this.assertText('before-core-bar before-core-bar bar-core-after bar-core-after'); - } + this.assertText( + 'before-core-bar before-core-bar bar-core-after bar-core-after' + ); + } - ['@test should be able to render unbound forms of multi-arg helpers']() { - this.registerHelper('fauxconcat', (params) => params.join('')); + ['@test should be able to render unbound forms of multi-arg helpers']() { + this.registerHelper('fauxconcat', params => params.join('')); - this.render(`{{fauxconcat model.foo model.bar model.bing}} {{unbound (fauxconcat model.foo model.bar model.bing)}}`, { - model: { - foo: 'a', - bar: 'b', - bing: 'c' - } - }); + this.render( + `{{fauxconcat model.foo model.bar model.bing}} {{unbound (fauxconcat model.foo model.bar model.bing)}}`, + { + model: { + foo: 'a', + bar: 'b', + bing: 'c' + } + } + ); - this.assertText('abc abc'); + this.assertText('abc abc'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('abc abc'); + this.assertText('abc abc'); - this.runTask(() => set(this.context, 'model.bar', 'X')); + this.runTask(() => set(this.context, 'model.bar', 'X')); - this.assertText('aXc abc'); + this.assertText('aXc abc'); - this.runTask(() => set(this.context, 'model', { - foo: 'a', - bar: 'b', - bing: 'c' - })); + this.runTask(() => + set(this.context, 'model', { + foo: 'a', + bar: 'b', + bing: 'c' + }) + ); - this.assertText('abc abc'); - } + this.assertText('abc abc'); + } - ['@test should be able to render an unbound helper invocation for helpers with dependent keys']() { - this.registerHelper('capitalizeName', { - destroy() { - this.removeObserver('value.firstName'); - this._super(...arguments); - }, - - compute([value]) { - if (this.get('value')) { + ['@test should be able to render an unbound helper invocation for helpers with dependent keys']() { + this.registerHelper('capitalizeName', { + destroy() { this.removeObserver('value.firstName'); + this._super(...arguments); + }, + + compute([value]) { + if (this.get('value')) { + this.removeObserver('value.firstName'); + } + this.set('value', value); + this.addObserver('value.firstName', this, this.recompute); + return value ? get(value, 'firstName').toUpperCase() : ''; } - this.set('value', value); - this.addObserver('value.firstName', this, this.recompute); - return (value ? get(value, 'firstName').toUpperCase() : ''); - } - }); - - this.registerHelper('concatNames', { - destroy() { - this.teardown(); - this._super(...arguments); - }, - teardown() { - this.removeObserver('value.firstName'); - this.removeObserver('value.lastName'); - }, - compute([value]) { - if (this.get('value')) { + }); + + this.registerHelper('concatNames', { + destroy() { this.teardown(); + this._super(...arguments); + }, + teardown() { + this.removeObserver('value.firstName'); + this.removeObserver('value.lastName'); + }, + compute([value]) { + if (this.get('value')) { + this.teardown(); + } + this.set('value', value); + this.addObserver('value.firstName', this, this.recompute); + this.addObserver('value.lastName', this, this.recompute); + return ( + (value ? get(value, 'firstName') : '') + + (value ? get(value, 'lastName') : '') + ); } - this.set('value', value); - this.addObserver('value.firstName', this, this.recompute); - this.addObserver('value.lastName', this, this.recompute); - return (value ? get(value, 'firstName') : '') + (value ? get(value, 'lastName') : ''); - } - }); + }); - this.render(`{{capitalizeName person}} {{unbound (capitalizeName person)}} {{concatNames person}} {{unbound (concatNames person)}}`, { - person: { - firstName: 'shooby', - lastName: 'taylor' - } - }); + this.render( + `{{capitalizeName person}} {{unbound (capitalizeName person)}} {{concatNames person}} {{unbound (concatNames person)}}`, + { + person: { + firstName: 'shooby', + lastName: 'taylor' + } + } + ); - this.assertText('SHOOBY SHOOBY shoobytaylor shoobytaylor'); + this.assertText('SHOOBY SHOOBY shoobytaylor shoobytaylor'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('SHOOBY SHOOBY shoobytaylor shoobytaylor'); + this.assertText('SHOOBY SHOOBY shoobytaylor shoobytaylor'); - this.runTask(() => set(this.context, 'person.firstName', 'sally')); + this.runTask(() => set(this.context, 'person.firstName', 'sally')); - this.assertText('SALLY SHOOBY sallytaylor shoobytaylor'); + this.assertText('SALLY SHOOBY sallytaylor shoobytaylor'); - this.runTask(() => set(this.context, 'person', { - firstName: 'shooby', - lastName: 'taylor' - })); + this.runTask(() => + set(this.context, 'person', { + firstName: 'shooby', + lastName: 'taylor' + }) + ); - this.assertText('SHOOBY SHOOBY shoobytaylor shoobytaylor'); - } + this.assertText('SHOOBY SHOOBY shoobytaylor shoobytaylor'); + } - ['@test should be able to render an unbound helper invocation in #each helper']() { - this.registerHelper('capitalize', (params) => params[0].toUpperCase()); + ['@test should be able to render an unbound helper invocation in #each helper']() { + this.registerHelper('capitalize', params => params[0].toUpperCase()); - this.render(`{{#each people as |person|}}{{capitalize person.firstName}} {{unbound (capitalize person.firstName)}}{{/each}}`, { - people: emberA([ - { - firstName: 'shooby', - lastName: 'taylor' - }, + this.render( + `{{#each people as |person|}}{{capitalize person.firstName}} {{unbound (capitalize person.firstName)}}{{/each}}`, { - firstName: 'cindy', - lastName: 'taylor' + people: emberA([ + { + firstName: 'shooby', + lastName: 'taylor' + }, + { + firstName: 'cindy', + lastName: 'taylor' + } + ]) } - ]) - }); - - this.assertText('SHOOBY SHOOBYCINDY CINDY'); + ); - this.runTask(() => this.rerender()); + this.assertText('SHOOBY SHOOBYCINDY CINDY'); - this.assertText('SHOOBY SHOOBYCINDY CINDY'); + this.runTask(() => this.rerender()); - this.runTask(() => this.context.people.setEach('firstName', 'chad')); + this.assertText('SHOOBY SHOOBYCINDY CINDY'); - this.assertText('CHAD SHOOBYCHAD CINDY'); + this.runTask(() => this.context.people.setEach('firstName', 'chad')); - this.runTask(() => set(this.context, 'people', emberA([ - { - firstName: 'shooby', - lastName: 'taylor' - }, - { - firstName: 'cindy', - lastName: 'taylor' - } - ]))); + this.assertText('CHAD SHOOBYCHAD CINDY'); - this.assertText('SHOOBY SHOOBYCINDY CINDY'); - } + this.runTask(() => + set( + this.context, + 'people', + emberA([ + { + firstName: 'shooby', + lastName: 'taylor' + }, + { + firstName: 'cindy', + lastName: 'taylor' + } + ]) + ) + ); - ['@test should be able to render an unbound helper invocation with bound hash options']() { - this.registerHelper('capitalizeName', { - destroy() { - this.removeObserver('value.firstName'); - this._super(...arguments); - }, + this.assertText('SHOOBY SHOOBYCINDY CINDY'); + } - compute([value]) { - if (this.get('value')) { + ['@test should be able to render an unbound helper invocation with bound hash options']() { + this.registerHelper('capitalizeName', { + destroy() { this.removeObserver('value.firstName'); + this._super(...arguments); + }, + + compute([value]) { + if (this.get('value')) { + this.removeObserver('value.firstName'); + } + this.set('value', value); + this.addObserver('value.firstName', this, this.recompute); + return value ? get(value, 'firstName').toUpperCase() : ''; } - this.set('value', value); - this.addObserver('value.firstName', this, this.recompute); - return (value ? get(value, 'firstName').toUpperCase() : ''); - } - }); - - this.registerHelper('concatNames', { - destroy() { - this.teardown(); - this._super(...arguments); - }, - teardown() { - this.removeObserver('value.firstName'); - this.removeObserver('value.lastName'); - }, - compute([value]) { - if (this.get('value')) { + }); + + this.registerHelper('concatNames', { + destroy() { this.teardown(); + this._super(...arguments); + }, + teardown() { + this.removeObserver('value.firstName'); + this.removeObserver('value.lastName'); + }, + compute([value]) { + if (this.get('value')) { + this.teardown(); + } + this.set('value', value); + this.addObserver('value.firstName', this, this.recompute); + this.addObserver('value.lastName', this, this.recompute); + return ( + (value ? get(value, 'firstName') : '') + + (value ? get(value, 'lastName') : '') + ); } - this.set('value', value); - this.addObserver('value.firstName', this, this.recompute); - this.addObserver('value.lastName', this, this.recompute); - return (value ? get(value, 'firstName') : '') + (value ? get(value, 'lastName') : ''); - } - }); + }); - this.render(`{{capitalizeName person}} {{unbound (capitalizeName person)}} {{concatNames person}} {{unbound (concatNames person)}}`, { - person: { - firstName: 'shooby', - lastName: 'taylor' - } - }); + this.render( + `{{capitalizeName person}} {{unbound (capitalizeName person)}} {{concatNames person}} {{unbound (concatNames person)}}`, + { + person: { + firstName: 'shooby', + lastName: 'taylor' + } + } + ); - this.assertText('SHOOBY SHOOBY shoobytaylor shoobytaylor'); + this.assertText('SHOOBY SHOOBY shoobytaylor shoobytaylor'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('SHOOBY SHOOBY shoobytaylor shoobytaylor'); + this.assertText('SHOOBY SHOOBY shoobytaylor shoobytaylor'); - this.runTask(() => set(this.context, 'person.firstName', 'sally')); + this.runTask(() => set(this.context, 'person.firstName', 'sally')); - this.assertText('SALLY SHOOBY sallytaylor shoobytaylor'); + this.assertText('SALLY SHOOBY sallytaylor shoobytaylor'); - this.runTask(() => set(this.context, 'person', { - firstName: 'shooby', - lastName: 'taylor' - })); + this.runTask(() => + set(this.context, 'person', { + firstName: 'shooby', + lastName: 'taylor' + }) + ); - this.assertText('SHOOBY SHOOBY shoobytaylor shoobytaylor'); - } + this.assertText('SHOOBY SHOOBY shoobytaylor shoobytaylor'); + } - ['@test should be able to render bound form of a helper inside unbound form of same helper']() { - this.render( - strip` + ['@test should be able to render bound form of a helper inside unbound form of same helper']() { + this.render( + strip` {{#if (unbound model.foo)}} {{#if model.bar}}true{{/if}} {{#unless model.bar}}false{{/unless}} @@ -512,94 +577,99 @@ moduleFor('Helpers test: {{unbound}}', class extends RenderingTest { {{#unless (unbound model.notfoo)}} {{#if model.bar}}true{{/if}} {{#unless model.bar}}false{{/unless}} - {{/unless}}`, { - model: { - foo: true, - notfoo: false, - bar: true + {{/unless}}`, + { + model: { + foo: true, + notfoo: false, + bar: true + } } - }); - - this.assertText('truetrue'); + ); - this.runTask(() => this.rerender()); + this.assertText('truetrue'); - this.assertText('truetrue'); + this.runTask(() => this.rerender()); - this.runTask(() => set(this.context, 'model.bar', false)); + this.assertText('truetrue'); - this.assertText('falsefalse'); + this.runTask(() => set(this.context, 'model.bar', false)); - this.runTask(() => set(this.context, 'model', { - foo: true, - notfoo: false, - bar: true - })); + this.assertText('falsefalse'); - this.assertText('truetrue'); - } - - ['@test yielding unbound does not update']() { - let fooBarInstance; - let FooBarComponent = Component.extend({ - init() { - this._super(...arguments); - fooBarInstance = this; - }, - model: { foo: 'bork' } - }); + this.runTask(() => + set(this.context, 'model', { + foo: true, + notfoo: false, + bar: true + }) + ); + + this.assertText('truetrue'); + } + + ['@test yielding unbound does not update']() { + let fooBarInstance; + let FooBarComponent = Component.extend({ + init() { + this._super(...arguments); + fooBarInstance = this; + }, + model: { foo: 'bork' } + }); - this.registerComponent('foo-bar', { - ComponentClass: FooBarComponent, - template: `{{yield (unbound model.foo)}}` - }); + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: `{{yield (unbound model.foo)}}` + }); - this.render(`{{#foo-bar as |value|}}{{value}}{{/foo-bar}}`); + this.render(`{{#foo-bar as |value|}}{{value}}{{/foo-bar}}`); - this.assertText('bork'); + this.assertText('bork'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('bork'); + this.assertText('bork'); - this.runTask(() => set(fooBarInstance, 'model.foo', 'oof')); + this.runTask(() => set(fooBarInstance, 'model.foo', 'oof')); - this.assertText('bork'); + this.assertText('bork'); - this.runTask(() => set(fooBarInstance, 'model', { foo: 'bork' })); + this.runTask(() => set(fooBarInstance, 'model', { foo: 'bork' })); - this.assertText('bork'); - } + this.assertText('bork'); + } - ['@test yielding unbound hash does not update']() { - let fooBarInstance; - let FooBarComponent = Component.extend({ - init() { - this._super(...arguments); - fooBarInstance = this; - }, - model: { foo: 'bork' } - }); + ['@test yielding unbound hash does not update']() { + let fooBarInstance; + let FooBarComponent = Component.extend({ + init() { + this._super(...arguments); + fooBarInstance = this; + }, + model: { foo: 'bork' } + }); - this.registerComponent('foo-bar', { - ComponentClass: FooBarComponent, - template: `{{yield (unbound (hash foo=model.foo))}}` - }); + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: `{{yield (unbound (hash foo=model.foo))}}` + }); - this.render(`{{#foo-bar as |value|}}{{value.foo}}{{/foo-bar}}`); + this.render(`{{#foo-bar as |value|}}{{value.foo}}{{/foo-bar}}`); - this.assertText('bork'); + this.assertText('bork'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('bork'); + this.assertText('bork'); - this.runTask(() => set(fooBarInstance, 'model.foo', 'oof')); + this.runTask(() => set(fooBarInstance, 'model.foo', 'oof')); - this.assertText('bork'); + this.assertText('bork'); - this.runTask(() => set(fooBarInstance, 'model', { foo: 'bork' })); + this.runTask(() => set(fooBarInstance, 'model', { foo: 'bork' })); - this.assertText('bork'); + this.assertText('bork'); + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/helpers/yield-test.js b/packages/ember-glimmer/tests/integration/helpers/yield-test.js index 201f4984970..2a8b35355ea 100644 --- a/packages/ember-glimmer/tests/integration/helpers/yield-test.js +++ b/packages/ember-glimmer/tests/integration/helpers/yield-test.js @@ -2,217 +2,279 @@ import { RenderingTest, moduleFor } from '../../utils/test-case'; import { set } from 'ember-metal'; import { Component } from '../../utils/helpers'; -moduleFor('Helpers test: {{yield}} helper', class extends RenderingTest { +moduleFor( + 'Helpers test: {{yield}} helper', + class extends RenderingTest { + ['@test can yield to block']() { + this.registerComponent('yield-comp', { + template: '[In layout:] {{yield}}' + }); + + this.render( + '{{#yield-comp}}[In Block:] {{object.title}}{{/yield-comp}}', + { object: { title: 'Seattle' } } + ); + this.assertText('[In layout:] [In Block:] Seattle'); + + this.assertStableRerender(); + + this.runTask(() => set(this.context, 'object.title', 'Vancouver')); + this.assertText('[In layout:] [In Block:] Vancouver'); - ['@test can yield to block']() { - this.registerComponent('yield-comp', { template: '[In layout:] {{yield}}' }); + this.runTask(() => set(this.context, 'object', { title: 'Seattle' })); + this.assertText('[In layout:] [In Block:] Seattle'); + } - this.render('{{#yield-comp}}[In Block:] {{object.title}}{{/yield-comp}}', { object: { title: 'Seattle' } }); - this.assertText('[In layout:] [In Block:] Seattle'); + ['@test templates should yield to block inside a nested component']() { + this.registerComponent('outer-comp', { + template: '
[In layout:] {{yield}}
' + }); + this.registerComponent('inner-comp', { + template: '{{#outer-comp}}[In Block:] {{object.title}}{{/outer-comp}}' + }); - this.assertStableRerender(); + this.render('{{inner-comp object=object}}', { + object: { title: 'Seattle' } + }); + this.assertText('[In layout:] [In Block:] Seattle'); - this.runTask(() => set(this.context, 'object.title', 'Vancouver')); - this.assertText('[In layout:] [In Block:] Vancouver'); + this.assertStableRerender(); - this.runTask(() => set(this.context, 'object', { title: 'Seattle' })); - this.assertText('[In layout:] [In Block:] Seattle'); - } - - ['@test templates should yield to block inside a nested component']() { - this.registerComponent('outer-comp', { template: '
[In layout:] {{yield}}
' }); - this.registerComponent('inner-comp', { template: '{{#outer-comp}}[In Block:] {{object.title}}{{/outer-comp}}' }); - - this.render('{{inner-comp object=object}}', { object: { title: 'Seattle' } }); - this.assertText('[In layout:] [In Block:] Seattle'); + this.runTask(() => set(this.context, 'object.title', 'Vancouver')); + this.assertText('[In layout:] [In Block:] Vancouver'); - this.assertStableRerender(); + this.runTask(() => set(this.context, 'object', { title: 'Seattle' })); + this.assertText('[In layout:] [In Block:] Seattle'); + } - this.runTask(() => set(this.context, 'object.title', 'Vancouver')); - this.assertText('[In layout:] [In Block:] Vancouver'); - - this.runTask(() => set(this.context, 'object', { title: 'Seattle' })); - this.assertText('[In layout:] [In Block:] Seattle'); - } + ['@test templates should yield to block, when the yield is embedded in a each helper']() { + let list = [1, 2, 3]; - ['@test templates should yield to block, when the yield is embedded in a each helper']() { - let list = [1, 2, 3]; + this.registerComponent('outer-comp', { + template: '{{#each list as |item|}}{{yield}}{{/each}}' + }); - this.registerComponent('outer-comp', { template: '{{#each list as |item|}}{{yield}}{{/each}}' }); + this.render('{{#outer-comp list=list}}Hello{{/outer-comp}}', { + list: list + }); + this.assertText('HelloHelloHello'); - this.render('{{#outer-comp list=list}}Hello{{/outer-comp}}', { list: list }); - this.assertText('HelloHelloHello'); - - this.assertStableRerender(); - - this.runTask(() => set(this.context, 'list', [4, 5])); - this.assertText('HelloHello'); - - this.runTask(() => set(this.context, 'list', list)); - this.assertText('HelloHelloHello'); - } + this.assertStableRerender(); - ['@test templates should yield to block, when the yield is embedded in a if helper']() { - this.registerComponent('outer-comp', { template: '{{#if boolean}}{{yield}}{{/if}}' }); + this.runTask(() => set(this.context, 'list', [4, 5])); + this.assertText('HelloHello'); - this.render('{{#outer-comp boolean=boolean}}Hello{{/outer-comp}}', { boolean: true }); - this.assertText('Hello'); + this.runTask(() => set(this.context, 'list', list)); + this.assertText('HelloHelloHello'); + } - this.assertStableRerender(); + ['@test templates should yield to block, when the yield is embedded in a if helper']() { + this.registerComponent('outer-comp', { + template: '{{#if boolean}}{{yield}}{{/if}}' + }); - this.runTask(() => set(this.context, 'boolean', false)); - this.assertText(''); + this.render('{{#outer-comp boolean=boolean}}Hello{{/outer-comp}}', { + boolean: true + }); + this.assertText('Hello'); - this.runTask(() => set(this.context, 'boolean', true)); - this.assertText('Hello'); - } + this.assertStableRerender(); - ['@test simple curlies inside of a yielded clock should work when the yield is nested inside of another view']() { - this.registerComponent('kiwi-comp', { template: '{{#if falsy}}{{else}}{{yield}}{{/if}}' }); + this.runTask(() => set(this.context, 'boolean', false)); + this.assertText(''); - this.render('{{#kiwi-comp}}{{text}}{{/kiwi-comp}}', { text: 'ohai' }); - this.assertText('ohai'); + this.runTask(() => set(this.context, 'boolean', true)); + this.assertText('Hello'); + } - this.assertStableRerender(); + ['@test simple curlies inside of a yielded clock should work when the yield is nested inside of another view']() { + this.registerComponent('kiwi-comp', { + template: '{{#if falsy}}{{else}}{{yield}}{{/if}}' + }); - this.runTask(() => set(this.context, 'text', 'portland')); - this.assertText('portland'); + this.render('{{#kiwi-comp}}{{text}}{{/kiwi-comp}}', { text: 'ohai' }); + this.assertText('ohai'); - this.runTask(() => set(this.context, 'text', 'ohai')); - this.assertText('ohai'); - } + this.assertStableRerender(); - ['@test nested simple curlies inside of a yielded block should work when the yield is nested inside of another view']() { - this.registerComponent('parent-comp', { template: '{{#if falsy}}{{else}}{{yield}}{{/if}}' }); - this.registerComponent('child-comp', { template: '{{#if falsy}}{{else}}{{text}}{{/if}}' }); + this.runTask(() => set(this.context, 'text', 'portland')); + this.assertText('portland'); - this.render('{{#parent-comp}}{{child-comp text=text}}{{/parent-comp}}', { text: 'ohai' }); - this.assertText('ohai'); + this.runTask(() => set(this.context, 'text', 'ohai')); + this.assertText('ohai'); + } - this.assertStableRerender(); + ['@test nested simple curlies inside of a yielded block should work when the yield is nested inside of another view']() { + this.registerComponent('parent-comp', { + template: '{{#if falsy}}{{else}}{{yield}}{{/if}}' + }); + this.registerComponent('child-comp', { + template: '{{#if falsy}}{{else}}{{text}}{{/if}}' + }); - this.runTask(() => set(this.context, 'text', 'portland')); - this.assertText('portland'); + this.render('{{#parent-comp}}{{child-comp text=text}}{{/parent-comp}}', { + text: 'ohai' + }); + this.assertText('ohai'); - this.runTask(() => set(this.context, 'text', 'ohai')); - this.assertText('ohai'); - } + this.assertStableRerender(); - ['@test yielding to a non-existent block is not an error']() { - this.registerComponent('yielding-comp', { template: 'Hello:{{yield}}' }); - this.registerComponent('outer-comp', { template: '{{yielding-comp}} {{title}}' }); + this.runTask(() => set(this.context, 'text', 'portland')); + this.assertText('portland'); - this.render('{{outer-comp title=title}}', { title: 'Mr. Selden' }); + this.runTask(() => set(this.context, 'text', 'ohai')); + this.assertText('ohai'); + } - this.assertText('Hello: Mr. Selden'); + ['@test yielding to a non-existent block is not an error']() { + this.registerComponent('yielding-comp', { template: 'Hello:{{yield}}' }); + this.registerComponent('outer-comp', { + template: '{{yielding-comp}} {{title}}' + }); - this.assertStableRerender(); + this.render('{{outer-comp title=title}}', { title: 'Mr. Selden' }); - this.runTask(() => set(this.context, 'title', 'Mr. Chag')); - this.assertText('Hello: Mr. Chag'); + this.assertText('Hello: Mr. Selden'); - this.runTask(() => set(this.context, 'title', 'Mr. Selden')); - this.assertText('Hello: Mr. Selden'); - } + this.assertStableRerender(); - ['@test yield uses the original context']() { - let KiwiCompComponent = Component.extend({ boundText: 'Inner' }); + this.runTask(() => set(this.context, 'title', 'Mr. Chag')); + this.assertText('Hello: Mr. Chag'); - this.registerComponent('kiwi-comp', { ComponentClass: KiwiCompComponent, template: '

{{boundText}}

{{yield}}

' }); + this.runTask(() => set(this.context, 'title', 'Mr. Selden')); + this.assertText('Hello: Mr. Selden'); + } - this.render('{{#kiwi-comp}}{{boundText}}{{/kiwi-comp}}', { boundText: 'Original' }); - this.assertText('InnerOriginal'); + ['@test yield uses the original context']() { + let KiwiCompComponent = Component.extend({ boundText: 'Inner' }); - this.assertStableRerender(); + this.registerComponent('kiwi-comp', { + ComponentClass: KiwiCompComponent, + template: '

{{boundText}}

{{yield}}

' + }); - this.runTask(() => set(this.context, 'boundText', 'Otherworld')); - this.assertText('InnerOtherworld'); + this.render('{{#kiwi-comp}}{{boundText}}{{/kiwi-comp}}', { + boundText: 'Original' + }); + this.assertText('InnerOriginal'); - this.runTask(() => set(this.context, 'boundText', 'Original')); - this.assertText('InnerOriginal'); - } + this.assertStableRerender(); - ['@test outer block param doesn\'t mask inner component property']() { - let KiwiCompComponent = Component.extend({ boundText: 'Inner' }); + this.runTask(() => set(this.context, 'boundText', 'Otherworld')); + this.assertText('InnerOtherworld'); - this.registerComponent('kiwi-comp', { ComponentClass: KiwiCompComponent, template: '

{{boundText}}

{{yield}}

' }); + this.runTask(() => set(this.context, 'boundText', 'Original')); + this.assertText('InnerOriginal'); + } - this.render('{{#with boundText as |item|}}{{#kiwi-comp}}{{item}}{{/kiwi-comp}}{{/with}}', { boundText: 'Outer' }); - this.assertText('InnerOuter'); + ["@test outer block param doesn't mask inner component property"]() { + let KiwiCompComponent = Component.extend({ boundText: 'Inner' }); - this.assertStableRerender(); + this.registerComponent('kiwi-comp', { + ComponentClass: KiwiCompComponent, + template: '

{{boundText}}

{{yield}}

' + }); - this.runTask(() => set(this.context, 'boundText', 'Otherworld')); - this.assertText('InnerOtherworld'); + this.render( + '{{#with boundText as |item|}}{{#kiwi-comp}}{{item}}{{/kiwi-comp}}{{/with}}', + { boundText: 'Outer' } + ); + this.assertText('InnerOuter'); - this.runTask(() => set(this.context, 'boundText', 'Outer')); - this.assertText('InnerOuter'); - } + this.assertStableRerender(); - ['@test inner block param doesn\'t mask yield property']() { - let KiwiCompComponent = Component.extend({ boundText: 'Inner' }); + this.runTask(() => set(this.context, 'boundText', 'Otherworld')); + this.assertText('InnerOtherworld'); - this.registerComponent('kiwi-comp', { ComponentClass: KiwiCompComponent, template: '{{#with boundText as |item|}}

{{item}}

{{yield}}

{{/with}}' }); + this.runTask(() => set(this.context, 'boundText', 'Outer')); + this.assertText('InnerOuter'); + } - this.render('{{#kiwi-comp}}{{item}}{{/kiwi-comp}}', { item: 'Outer' }); - this.assertText('InnerOuter'); + ["@test inner block param doesn't mask yield property"]() { + let KiwiCompComponent = Component.extend({ boundText: 'Inner' }); - this.assertStableRerender(); + this.registerComponent('kiwi-comp', { + ComponentClass: KiwiCompComponent, + template: + '{{#with boundText as |item|}}

{{item}}

{{yield}}

{{/with}}' + }); - this.runTask(() => set(this.context, 'item', 'Otherworld')); - this.assertText('InnerOtherworld'); + this.render('{{#kiwi-comp}}{{item}}{{/kiwi-comp}}', { item: 'Outer' }); + this.assertText('InnerOuter'); - this.runTask(() => set(this.context, 'item', 'Outer')); - this.assertText('InnerOuter'); - } + this.assertStableRerender(); - ['@test can bind a block param to a component and use it in yield']() { - this.registerComponent('kiwi-comp', { template: '

{{content}}

{{yield}}

' }); + this.runTask(() => set(this.context, 'item', 'Otherworld')); + this.assertText('InnerOtherworld'); - this.render('{{#with boundText as |item|}}{{#kiwi-comp content=item}}{{item}}{{/kiwi-comp}}{{/with}}', { boundText: 'Outer' }); - this.assertText('OuterOuter'); + this.runTask(() => set(this.context, 'item', 'Outer')); + this.assertText('InnerOuter'); + } - this.assertStableRerender(); + ['@test can bind a block param to a component and use it in yield']() { + this.registerComponent('kiwi-comp', { + template: '

{{content}}

{{yield}}

' + }); - this.runTask(() => set(this.context, 'boundText', 'Update')); - this.assertText('UpdateUpdate'); + this.render( + '{{#with boundText as |item|}}{{#kiwi-comp content=item}}{{item}}{{/kiwi-comp}}{{/with}}', + { boundText: 'Outer' } + ); + this.assertText('OuterOuter'); - this.runTask(() => set(this.context, 'boundText', 'Outer')); - this.assertText('OuterOuter'); - } + this.assertStableRerender(); - // INUR not need with no data update - ['@test yield should not introduce a view'](assert) { - let ParentCompComponent = Component.extend({ isParentComponent: true }); + this.runTask(() => set(this.context, 'boundText', 'Update')); + this.assertText('UpdateUpdate'); - let ChildCompComponent = Component.extend({ - didReceiveAttrs() { - this._super(); - let parentView = this.get('parentView'); + this.runTask(() => set(this.context, 'boundText', 'Outer')); + this.assertText('OuterOuter'); + } - assert.ok(parentView.get('isParentComponent')); - } - }); + // INUR not need with no data update + ['@test yield should not introduce a view'](assert) { + let ParentCompComponent = Component.extend({ isParentComponent: true }); - this.registerComponent('parent-comp', { ComponentClass: ParentCompComponent, template: '{{yield}}' }); - this.registerComponent('child-comp', { ComponentClass: ChildCompComponent }); + let ChildCompComponent = Component.extend({ + didReceiveAttrs() { + this._super(); + let parentView = this.get('parentView'); - this.render('{{#parent-comp}}{{child-comp}}{{/parent-comp}}'); - } + assert.ok(parentView.get('isParentComponent')); + } + }); - ['@test yield with nested components (#3220)']() { - this.registerComponent('inner-component', { template: '{{yield}}' }); - this.registerComponent('outer-component', { template: '{{#inner-component}}{{yield}}{{/inner-component}}' }); + this.registerComponent('parent-comp', { + ComponentClass: ParentCompComponent, + template: '{{yield}}' + }); + this.registerComponent('child-comp', { + ComponentClass: ChildCompComponent + }); - this.render('{{#outer-component}}Hello {{boundText}}{{/outer-component}}', { boundText: 'world' }); - this.assertText('Hello world'); + this.render('{{#parent-comp}}{{child-comp}}{{/parent-comp}}'); + } - this.assertStableRerender(); + ['@test yield with nested components (#3220)']() { + this.registerComponent('inner-component', { template: '{{yield}}' }); + this.registerComponent('outer-component', { + template: + '{{#inner-component}}{{yield}}{{/inner-component}}' + }); - this.runTask(() => set(this.context, 'boundText', 'update')); - this.assertText('Hello update'); + this.render( + '{{#outer-component}}Hello {{boundText}}{{/outer-component}}', + { boundText: 'world' } + ); + this.assertText('Hello world'); + + this.assertStableRerender(); - this.runTask(() => set(this.context, 'boundText', 'world')); - this.assertText('Hello world'); + this.runTask(() => set(this.context, 'boundText', 'update')); + this.assertText('Hello update'); + + this.runTask(() => set(this.context, 'boundText', 'world')); + this.assertText('Hello world'); + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/input-test.js b/packages/ember-glimmer/tests/integration/input-test.js index 4befbe0752b..f4570770d3e 100644 --- a/packages/ember-glimmer/tests/integration/input-test.js +++ b/packages/ember-glimmer/tests/integration/input-test.js @@ -1,216 +1,274 @@ import { RenderingTest, moduleFor } from '../utils/test-case'; import { set } from 'ember-metal'; -moduleFor('Input element tests', class extends RenderingTest { - runAttributeTest(attributeName, values) { - let template = ``; - this.render(template, { value: values[0] }); - this.assertAttributeHasValue(attributeName, values[0], `${attributeName} is set on initial render`); +moduleFor( + 'Input element tests', + class extends RenderingTest { + runAttributeTest(attributeName, values) { + let template = ``; + this.render(template, { value: values[0] }); + this.assertAttributeHasValue( + attributeName, + values[0], + `${attributeName} is set on initial render` + ); + + this.runTask(() => this.rerender()); + this.assertAttributeHasValue( + attributeName, + values[0], + `${attributeName} is set on noop rerender` + ); + + this.setComponentValue(values[1]); + this.assertAttributeHasValue( + attributeName, + values[1], + `${attributeName} is set on rerender` + ); + + this.setComponentValue(values[0]); + this.assertAttributeHasValue( + attributeName, + values[0], + `${attributeName} can be set back to the initial value` + ); + } + + runPropertyTest(propertyName, values) { + let attributeName = propertyName; + let template = ``; + this.render(template, { value: values[0] }); + this.assertPropertyHasValue( + propertyName, + values[0], + `${propertyName} is set on initial render` + ); + + this.runTask(() => this.rerender()); + this.assertPropertyHasValue( + propertyName, + values[0], + `${propertyName} is set on noop rerender` + ); + + this.setComponentValue(values[1]); + this.assertPropertyHasValue( + propertyName, + values[1], + `${propertyName} is set on rerender` + ); + + this.setComponentValue(values[0]); + this.assertPropertyHasValue( + propertyName, + values[0], + `${propertyName} can be set back to the initial value` + ); + } + + runFalsyValueProperty(values) { + let value = 'value'; + let template = ``; + this.render(template, { value: values[0] }); + this.assertPropertyHasValue( + value, + '', + `${value} is set on initial render` + ); + + this.runTask(() => this.rerender()); + this.assertPropertyHasValue( + value, + '', + `${value} is set on noop rerender` + ); + this.setComponentValue(values[1]); + + this.assertPropertyHasValue( + value, + values[1], + `${value} is set on rerender` + ); + + this.setComponentValue(values[0]); + this.assertPropertyHasValue( + value, + '', + `${value} can be set back to the initial value` + ); + } + + ['@test input disabled attribute']() { + let model = { model: { value: false } }; + + this.render(``, model); + + this.assert.equal(this.$inputElement().prop('disabled'), false); + + this.runTask(() => this.rerender()); + + this.assert.equal(this.$inputElement().prop('disabled'), false); + + this.runTask(() => this.context.set('model.value', true)); + + this.assert.equal(this.$inputElement().prop('disabled'), true); + this.assertHTML(''); // Note the DOM output is - this.runTask(() => this.rerender()); - this.assertAttributeHasValue(attributeName, values[0], `${attributeName} is set on noop rerender`); + this.runTask(() => this.context.set('model.value', 'wat')); - this.setComponentValue(values[1]); - this.assertAttributeHasValue(attributeName, values[1], `${attributeName} is set on rerender`); + this.assert.equal(this.$inputElement().prop('disabled'), true); + this.assertHTML(''); // Note the DOM output is - this.setComponentValue(values[0]); - this.assertAttributeHasValue(attributeName, values[0], `${attributeName} can be set back to the initial value`); - } - - runPropertyTest(propertyName, values) { - let attributeName = propertyName; - let template = ``; - this.render(template, { value: values[0] }); - this.assertPropertyHasValue(propertyName, values[0], `${propertyName} is set on initial render`); - - this.runTask(() => this.rerender()); - this.assertPropertyHasValue(propertyName, values[0], `${propertyName} is set on noop rerender`); + this.runTask(() => this.context.set('model', { value: false })); - this.setComponentValue(values[1]); - this.assertPropertyHasValue(propertyName, values[1], `${propertyName} is set on rerender`); + this.assert.equal(this.$inputElement().prop('disabled'), false); + this.assertHTML(''); + } - this.setComponentValue(values[0]); - this.assertPropertyHasValue(propertyName, values[0], `${propertyName} can be set back to the initial value`); - } - - runFalsyValueProperty(values) { - let value = 'value'; - let template = ``; - this.render(template, { value: values[0] }); - this.assertPropertyHasValue(value, '', `${value} is set on initial render`); + ['@test input value attribute']() { + this.runPropertyTest('value', ['foo', 'bar']); + } - this.runTask(() => this.rerender()); - this.assertPropertyHasValue(value, '', `${value} is set on noop rerender`); - this.setComponentValue(values[1]); + ['@test input placeholder attribute']() { + this.runAttributeTest('placeholder', ['foo', 'bar']); + } - this.assertPropertyHasValue(value, values[1], `${value} is set on rerender`); + ['@test input name attribute']() { + this.runAttributeTest('name', ['nam', 'name']); + } - this.setComponentValue(values[0]); - this.assertPropertyHasValue(value, '', `${value} can be set back to the initial value`); - } + ['@test input maxlength attribute']() { + this.runAttributeTest('maxlength', [2, 3]); + } - ['@test input disabled attribute']() { - let model = { model: { value: false } }; + ['@test input size attribute']() { + this.runAttributeTest('size', [2, 3]); + } - this.render(``, model); + ['@test input tabindex attribute']() { + this.runAttributeTest('tabindex', [2, 3]); + } - this.assert.equal(this.$inputElement().prop('disabled'), false); + ['@test null input value']() { + this.runFalsyValueProperty([null, 'hello']); + } - this.runTask(() => this.rerender()); + ['@test undefined input value']() { + this.runFalsyValueProperty([undefined, 'hello']); + } - this.assert.equal(this.$inputElement().prop('disabled'), false); + ['@test undefined `toString` method as input value']() { + this.runFalsyValueProperty([Object.create(null), 'hello']); + } - this.runTask(() => this.context.set('model.value', true)); + ['@test cursor position is not lost when updating content']() { + let template = ``; + this.render(template, { value: 'hola' }); - this.assert.equal(this.$inputElement().prop('disabled'), true); - this.assertHTML(''); // Note the DOM output is - - this.runTask(() => this.context.set('model.value', 'wat')); - - this.assert.equal(this.$inputElement().prop('disabled'), true); - this.assertHTML(''); // Note the DOM output is - - this.runTask(() => this.context.set('model', { value: false })); - - this.assert.equal(this.$inputElement().prop('disabled'), false); - this.assertHTML(''); - } + this.setDOMValue('hello'); + this.setSelectionRange(1, 3); - ['@test input value attribute']() { - this.runPropertyTest('value', ['foo', 'bar']); - } + this.setComponentValue('hello'); - ['@test input placeholder attribute']() { - this.runAttributeTest('placeholder', ['foo', 'bar']); - } + this.assertSelectionRange(1, 3); - ['@test input name attribute']() { - this.runAttributeTest('name', ['nam', 'name']); - } + // Note: We should eventually get around to testing reseting, however + // browsers handle `selectionStart` and `selectionEnd` differently + // when are synthetically testing movement of the cursor. + } - ['@test input maxlength attribute']() { - this.runAttributeTest('maxlength', [2, 3]); - } + ['@test input can be updated multiple times']() { + let template = ``; + this.render(template, { value: 'hola' }); - ['@test input size attribute']() { - this.runAttributeTest('size', [2, 3]); - } + this.assertValue('hola', 'Value is initialised'); - ['@test input tabindex attribute']() { - this.runAttributeTest('tabindex', [2, 3]); - } + this.setComponentValue(''); + this.assertValue('', 'Value is set in the DOM'); - ['@test null input value']() { - this.runFalsyValueProperty([null, 'hello']); - } + this.setDOMValue('hola'); + this.setComponentValue('hola'); + this.assertValue('hola', 'Value is updated the first time'); - ['@test undefined input value']() { - this.runFalsyValueProperty([undefined, 'hello']); - } + this.setComponentValue(''); + this.assertValue('', 'Value is updated the second time'); + } - ['@test undefined `toString` method as input value']() { - this.runFalsyValueProperty([Object.create(null), 'hello']); - } + ['@test DOM is SSOT if value is set']() { + let template = ``; + this.render(template, { value: 'hola' }); - ['@test cursor position is not lost when updating content']() { - let template = ``; - this.render(template, { value: 'hola' }); + this.assertValue('hola', 'Value is initialised'); - this.setDOMValue('hello'); - this.setSelectionRange(1, 3); + this.setComponentValue('hello'); - this.setComponentValue('hello'); + this.assertValue('hello', 'Value is initialised'); - this.assertSelectionRange(1, 3); + this.setDOMValue('hola'); - // Note: We should eventually get around to testing reseting, however - // browsers handle `selectionStart` and `selectionEnd` differently - // when are synthetically testing movement of the cursor. - } + this.assertValue('hola', 'DOM is used'); - ['@test input can be updated multiple times']() { - let template = ``; - this.render(template, { value: 'hola' }); + this.setComponentValue('bye'); - this.assertValue('hola', 'Value is initialised'); + this.assertValue('bye', 'Value is used'); - this.setComponentValue(''); - this.assertValue('', 'Value is set in the DOM'); + // Simulates setting the input to the same value as it already is which won't cause a rerender - this.setDOMValue('hola'); - this.setComponentValue('hola'); - this.assertValue('hola', 'Value is updated the first time'); + this.setDOMValue('hola'); - this.setComponentValue(''); - this.assertValue('', 'Value is updated the second time'); - } + this.assertValue('hola', 'DOM is used'); - ['@test DOM is SSOT if value is set']() { - let template = ``; - this.render(template, { value: 'hola' }); + this.setComponentValue('hola'); - this.assertValue('hola', 'Value is initialised'); + this.assertValue('hola', 'Value is used'); + } - this.setComponentValue('hello'); + // private helpers and assertions + setDOMValue(value) { + this.inputElement().value = value; + } - this.assertValue('hello', 'Value is initialised'); + setComponentValue(value) { + this.runTask(() => set(this.context, 'value', value)); + } - this.setDOMValue('hola'); + setSelectionRange(start, end) { + this.inputElement().selectionStart = start; + this.inputElement().selectionEnd = end; + } - this.assertValue('hola', 'DOM is used'); + inputElement() { + return this.$inputElement()[0]; + } - this.setComponentValue('bye'); + $inputElement() { + return this.$('input'); + } - this.assertValue('bye', 'Value is used'); + assertValue(value, message) { + this.assertPropertyHasValue('value', value, message); + } - // Simulates setting the input to the same value as it already is which won't cause a rerender + assertAttributeHasValue(attribute, value, message) { + this.assert.equal( + this.$inputElement().attr(attribute), + value, + `${attribute} ${message}` + ); + } - this.setDOMValue('hola'); + assertPropertyHasValue(property, value, message) { + this.assert.equal( + this.$inputElement().prop(property), + value, + `${property} ${message}` + ); + } - this.assertValue('hola', 'DOM is used'); - - this.setComponentValue('hola'); - - this.assertValue('hola', 'Value is used'); - } - - // private helpers and assertions - setDOMValue(value) { - this.inputElement().value = value; - } - - setComponentValue(value) { - this.runTask(() => set(this.context, 'value', value)); + assertSelectionRange(start, end) { + this.assert.equal(this.inputElement().selectionStart, start); + this.assert.equal(this.inputElement().selectionEnd, end); + } } - - setSelectionRange(start, end) { - this.inputElement().selectionStart = start; - this.inputElement().selectionEnd = end; - } - - inputElement() { - return this.$inputElement()[0]; - } - - $inputElement() { - return this.$('input'); - } - - assertValue(value, message) { - this.assertPropertyHasValue('value', value, message); - } - - assertAttributeHasValue(attribute, value, message) { - this.assert.equal(this.$inputElement().attr(attribute), value, `${attribute} ${message}`); - } - - assertPropertyHasValue(property, value, message) { - this.assert.equal(this.$inputElement().prop(property), value, `${property} ${message}`); - } - - assertSelectionRange(start, end) { - this.assert.equal(this.inputElement().selectionStart, start); - this.assert.equal(this.inputElement().selectionEnd, end); - } - -}); +); diff --git a/packages/ember-glimmer/tests/integration/mount-test.js b/packages/ember-glimmer/tests/integration/mount-test.js index 768b2ab0a86..ff6a11bf640 100644 --- a/packages/ember-glimmer/tests/integration/mount-test.js +++ b/packages/ember-glimmer/tests/integration/mount-test.js @@ -1,9 +1,5 @@ import { getOwner } from 'ember-utils'; -import { - moduleFor, - ApplicationTest, - RenderingTest -} from '../utils/test-case'; +import { moduleFor, ApplicationTest, RenderingTest } from '../utils/test-case'; import { compile, Component } from '../utils/helpers'; import { Controller } from 'ember-runtime'; import { set } from 'ember-metal'; @@ -11,314 +7,429 @@ import { Engine, getEngineParent } from 'ember-application'; import { EMBER_ENGINES_MOUNT_PARAMS } from 'ember/features'; if (EMBER_ENGINES_MOUNT_PARAMS) { - moduleFor('{{mount}} single param assertion', class extends RenderingTest { - ['@test it asserts that only a single param is passed']() { - expectAssertion(() => { - this.render('{{mount "chat" "foo"}}'); - }, /You can only pass a single positional argument to the {{mount}} helper, e.g. {{mount "chat-engine"}}./i); + moduleFor( + '{{mount}} single param assertion', + class extends RenderingTest { + ['@test it asserts that only a single param is passed']() { + expectAssertion(() => { + this.render('{{mount "chat" "foo"}}'); + }, /You can only pass a single positional argument to the {{mount}} helper, e.g. {{mount "chat-engine"}}./i); + } } - }); + ); } else { - moduleFor('{{mount}} single param assertion', class extends RenderingTest { - ['@test it asserts that only a single param is passed']() { - expectAssertion(() => { - this.render('{{mount "chat" "foo"}}'); - }, /You can only pass a single argument to the {{mount}} helper, e.g. {{mount "chat-engine"}}./i); + moduleFor( + '{{mount}} single param assertion', + class extends RenderingTest { + ['@test it asserts that only a single param is passed']() { + expectAssertion(() => { + this.render('{{mount "chat" "foo"}}'); + }, /You can only pass a single argument to the {{mount}} helper, e.g. {{mount "chat-engine"}}./i); + } } - }); + ); } -moduleFor('{{mount}} assertions', class extends RenderingTest { - ['@test it asserts when an invalid engine name is provided']() { - expectAssertion(() => { - this.render('{{mount engineName}}', { engineName: {} }); - }, /Invalid engine name '\[object Object\]' specified, engine name must be either a string, null or undefined./i); - } +moduleFor( + '{{mount}} assertions', + class extends RenderingTest { + ['@test it asserts when an invalid engine name is provided']() { + expectAssertion(() => { + this.render('{{mount engineName}}', { engineName: {} }); + }, /Invalid engine name '\[object Object\]' specified, engine name must be either a string, null or undefined./i); + } - ['@test it asserts that the specified engine is registered']() { - expectAssertion(() => { - this.render('{{mount "chat"}}'); - }, /You used `{{mount 'chat'}}`, but the engine 'chat' can not be found./i); + ['@test it asserts that the specified engine is registered']() { + expectAssertion(() => { + this.render('{{mount "chat"}}'); + }, /You used `{{mount 'chat'}}`, but the engine 'chat' can not be found./i); + } } -}); +); -moduleFor('{{mount}} test', class extends ApplicationTest { - constructor() { - super(); +moduleFor( + '{{mount}} test', + class extends ApplicationTest { + constructor() { + super(); - let engineRegistrations = this.engineRegistrations = {}; + let engineRegistrations = (this.engineRegistrations = {}); - this.add('engine:chat', Engine.extend({ - router: null, + this.add( + 'engine:chat', + Engine.extend({ + router: null, - init() { - this._super(...arguments); + init() { + this._super(...arguments); - Object.keys(engineRegistrations).forEach(fullName => { - this.register(fullName, engineRegistrations[fullName]); - }); - } - })); + Object.keys(engineRegistrations).forEach(fullName => { + this.register(fullName, engineRegistrations[fullName]); + }); + } + }) + ); - this.addTemplate('index', '{{mount "chat"}}'); - } + this.addTemplate('index', '{{mount "chat"}}'); + } - ['@test it boots an engine, instantiates its application controller, and renders its application template'](assert) { - this.engineRegistrations['template:application'] = compile('

Chat here, {{username}}

', { moduleName: 'my-app/templates/application.hbs' }); + ['@test it boots an engine, instantiates its application controller, and renders its application template']( + assert + ) { + this.engineRegistrations['template:application'] = compile( + '

Chat here, {{username}}

', + { moduleName: 'my-app/templates/application.hbs' } + ); - let controller; + let controller; - this.engineRegistrations['controller:application'] = Controller.extend({ - username: 'dgeb', + this.engineRegistrations['controller:application'] = Controller.extend({ + username: 'dgeb', - init() { - this._super(); - controller = this; - } - }); + init() { + this._super(); + controller = this; + } + }); - return this.visit('/').then(() => { - assert.ok(controller, 'engine\'s application controller has been instantiated'); + return this.visit('/').then(() => { + assert.ok( + controller, + "engine's application controller has been instantiated" + ); - let engineInstance = getOwner(controller); - assert.strictEqual(getEngineParent(engineInstance), this.applicationInstance, 'engine instance has the application instance as its parent'); + let engineInstance = getOwner(controller); + assert.strictEqual( + getEngineParent(engineInstance), + this.applicationInstance, + 'engine instance has the application instance as its parent' + ); - this.assertInnerHTML('

Chat here, dgeb

'); + this.assertInnerHTML('

Chat here, dgeb

'); - this.runTask(() => set(controller, 'username', 'chancancode')); + this.runTask(() => set(controller, 'username', 'chancancode')); - this.assertInnerHTML('

Chat here, chancancode

'); + this.assertInnerHTML('

Chat here, chancancode

'); - this.runTask(() => set(controller, 'username', 'dgeb')); + this.runTask(() => set(controller, 'username', 'dgeb')); - this.assertInnerHTML('

Chat here, dgeb

'); - }); - } + this.assertInnerHTML('

Chat here, dgeb

'); + }); + } - ['@test it emits a useful backtracking re-render assertion message']() { - this.router.map(function() { - this.route('route-with-mount'); - }); + ['@test it emits a useful backtracking re-render assertion message']() { + this.router.map(function() { + this.route('route-with-mount'); + }); - this.addTemplate('index', ''); - this.addTemplate('route-with-mount', '{{mount "chat"}}'); + this.addTemplate('index', ''); + this.addTemplate('route-with-mount', '{{mount "chat"}}'); - this.engineRegistrations['template:application'] = compile('hi {{person.name}} [{{component-with-backtracking-set person=person}}]', { moduleName: 'my-app/templates/application.hbs' }); - this.engineRegistrations['controller:application'] = Controller.extend({ - person: { name: 'Alex' } - }); + this.engineRegistrations['template:application'] = compile( + 'hi {{person.name}} [{{component-with-backtracking-set person=person}}]', + { moduleName: 'my-app/templates/application.hbs' } + ); + this.engineRegistrations['controller:application'] = Controller.extend({ + person: { name: 'Alex' } + }); - this.engineRegistrations['template:components/component-with-backtracking-set'] = compile('[component {{person.name}}]', { moduleName: 'my-app/templates/components/component-with-backtracking-set.hbs' }); - this.engineRegistrations['component:component-with-backtracking-set'] = Component.extend({ - init() { - this._super(...arguments); - this.set('person.name', 'Ben'); - } - }); + this.engineRegistrations[ + 'template:components/component-with-backtracking-set' + ] = compile('[component {{person.name}}]', { + moduleName: + 'my-app/templates/components/component-with-backtracking-set.hbs' + }); + this.engineRegistrations[ + 'component:component-with-backtracking-set' + ] = Component.extend({ + init() { + this._super(...arguments); + this.set('person.name', 'Ben'); + } + }); - let expectedBacktrackingMessage = /modified "person\.name" twice on \[object Object\] in a single render\. It was rendered in "template:my-app\/templates\/route-with-mount.hbs" \(in "engine:chat"\) and modified in "component:component-with-backtracking-set" \(in "engine:chat"\)/; + let expectedBacktrackingMessage = /modified "person\.name" twice on \[object Object\] in a single render\. It was rendered in "template:my-app\/templates\/route-with-mount.hbs" \(in "engine:chat"\) and modified in "component:component-with-backtracking-set" \(in "engine:chat"\)/; - return this.visit('/').then(() => { - expectAssertion(() => { - this.visit('/route-with-mount'); - }, expectedBacktrackingMessage); - }); - } + return this.visit('/').then(() => { + expectAssertion(() => { + this.visit('/route-with-mount'); + }, expectedBacktrackingMessage); + }); + } - ['@test it renders with a bound engine name']() { - this.router.map(function() { - this.route('bound-engine-name'); - }); - let controller; - this.add('controller:bound-engine-name', Controller.extend({ - engineName: null, - init() { - this._super(); - controller = this; - } - })); - this.addTemplate('bound-engine-name', '{{mount engineName}}'); - - this.add('engine:foo', Engine.extend({ - router: null, - init() { - this._super(...arguments); - this.register('template:application', compile('

Foo Engine

', { moduleName: 'my-app/templates/application.hbs' })); - } - })); - this.add('engine:bar', Engine.extend({ - router: null, - init() { - this._super(...arguments); - this.register('template:application', compile('

Bar Engine

', { moduleName: 'my-app/templates/application.hbs' })); - } - })); + ['@test it renders with a bound engine name']() { + this.router.map(function() { + this.route('bound-engine-name'); + }); + let controller; + this.add( + 'controller:bound-engine-name', + Controller.extend({ + engineName: null, + init() { + this._super(); + controller = this; + } + }) + ); + this.addTemplate('bound-engine-name', '{{mount engineName}}'); + + this.add( + 'engine:foo', + Engine.extend({ + router: null, + init() { + this._super(...arguments); + this.register( + 'template:application', + compile('

Foo Engine

', { + moduleName: 'my-app/templates/application.hbs' + }) + ); + } + }) + ); + this.add( + 'engine:bar', + Engine.extend({ + router: null, + init() { + this._super(...arguments); + this.register( + 'template:application', + compile('

Bar Engine

', { + moduleName: 'my-app/templates/application.hbs' + }) + ); + } + }) + ); - return this.visit('/bound-engine-name').then(() => { - this.assertInnerHTML(''); + return this.visit('/bound-engine-name').then(() => { + this.assertInnerHTML(''); - this.runTask(() => set(controller, 'engineName', 'foo')); + this.runTask(() => set(controller, 'engineName', 'foo')); - this.assertInnerHTML('

Foo Engine

'); + this.assertInnerHTML('

Foo Engine

'); - this.runTask(() => set(controller, 'engineName', undefined)); + this.runTask(() => set(controller, 'engineName', undefined)); - this.assertInnerHTML(''); + this.assertInnerHTML(''); - this.runTask(() => set(controller, 'engineName', 'foo')); + this.runTask(() => set(controller, 'engineName', 'foo')); - this.assertInnerHTML('

Foo Engine

'); + this.assertInnerHTML('

Foo Engine

'); - this.runTask(() => set(controller, 'engineName', 'bar')); + this.runTask(() => set(controller, 'engineName', 'bar')); - this.assertInnerHTML('

Bar Engine

'); + this.assertInnerHTML('

Bar Engine

'); - this.runTask(() => set(controller, 'engineName', 'foo')); + this.runTask(() => set(controller, 'engineName', 'foo')); - this.assertInnerHTML('

Foo Engine

'); + this.assertInnerHTML('

Foo Engine

'); - this.runTask(() => set(controller, 'engineName', null)); + this.runTask(() => set(controller, 'engineName', null)); - this.assertInnerHTML(''); - }); - } + this.assertInnerHTML(''); + }); + } - ['@test it declares the event dispatcher as a singleton']() { - this.router.map(function() { - this.route('engine-event-dispatcher-singleton'); - }); + ['@test it declares the event dispatcher as a singleton']() { + this.router.map(function() { + this.route('engine-event-dispatcher-singleton'); + }); - let controller; - let component; + let controller; + let component; - this.add('controller:engine-event-dispatcher-singleton', Controller.extend({ - init() { - this._super(...arguments); - controller = this; - } - })); - this.addTemplate('engine-event-dispatcher-singleton', '{{mount "foo"}}'); - - this.add('engine:foo', Engine.extend({ - router: null, - init() { - this._super(...arguments); - this.register('template:application', compile('

Foo Engine: {{tagless-component}}

', { moduleName: 'my-app/templates/application.hbs' })); - this.register('component:tagless-component', Component.extend({ - tagName: "", + this.add( + 'controller:engine-event-dispatcher-singleton', + Controller.extend({ init() { this._super(...arguments); - component = this; + controller = this; } - })); - this.register('template:components/tagless-component', compile('Tagless Component', { moduleName: 'my-app/templates/components/tagless-component.hbs' })); - } - })); - - return this.visit('/engine-event-dispatcher-singleton').then(() => { - this.assertInnerHTML('

Foo Engine: Tagless Component

'); - - let controllerOwnerEventDispatcher = getOwner(controller).lookup('event_dispatcher:main'); - let taglessComponentOwnerEventDispatcher = getOwner(component).lookup('event_dispatcher:main'); - - this.assert.strictEqual(controllerOwnerEventDispatcher, taglessComponentOwnerEventDispatcher); - }); + }) + ); + this.addTemplate('engine-event-dispatcher-singleton', '{{mount "foo"}}'); + + this.add( + 'engine:foo', + Engine.extend({ + router: null, + init() { + this._super(...arguments); + this.register( + 'template:application', + compile('

Foo Engine: {{tagless-component}}

', { + moduleName: 'my-app/templates/application.hbs' + }) + ); + this.register( + 'component:tagless-component', + Component.extend({ + tagName: '', + init() { + this._super(...arguments); + component = this; + } + }) + ); + this.register( + 'template:components/tagless-component', + compile('Tagless Component', { + moduleName: 'my-app/templates/components/tagless-component.hbs' + }) + ); + } + }) + ); + + return this.visit('/engine-event-dispatcher-singleton').then(() => { + this.assertInnerHTML('

Foo Engine: Tagless Component

'); + + let controllerOwnerEventDispatcher = getOwner(controller).lookup( + 'event_dispatcher:main' + ); + let taglessComponentOwnerEventDispatcher = getOwner(component).lookup( + 'event_dispatcher:main' + ); + + this.assert.strictEqual( + controllerOwnerEventDispatcher, + taglessComponentOwnerEventDispatcher + ); + }); + } } - -}); +); if (EMBER_ENGINES_MOUNT_PARAMS) { - moduleFor('{{mount}} params tests', class extends ApplicationTest { - constructor() { - super(); - - this.add('engine:paramEngine', Engine.extend({ - router: null, - init() { - this._super(...arguments); - this.register('template:application', compile('

Param Engine: {{model.foo}}

', { moduleName: 'my-app/templates/application.hbs' })); - } - })); - } - - ['@test it renders with static parameters']() { - this.router.map(function() { - this.route('engine-params-static'); - }); - this.addTemplate('engine-params-static', '{{mount "paramEngine" model=(hash foo="bar")}}'); + moduleFor( + '{{mount}} params tests', + class extends ApplicationTest { + constructor() { + super(); + + this.add( + 'engine:paramEngine', + Engine.extend({ + router: null, + init() { + this._super(...arguments); + this.register( + 'template:application', + compile('

Param Engine: {{model.foo}}

', { + moduleName: 'my-app/templates/application.hbs' + }) + ); + } + }) + ); + } - return this.visit('/engine-params-static').then(() => { - this.assertInnerHTML('

Param Engine: bar

'); - }); - } + ['@test it renders with static parameters']() { + this.router.map(function() { + this.route('engine-params-static'); + }); + this.addTemplate( + 'engine-params-static', + '{{mount "paramEngine" model=(hash foo="bar")}}' + ); - ['@test it renders with bound parameters']() { - this.router.map(function() { - this.route('engine-params-bound'); - }); - let controller; - this.add('controller:engine-params-bound', Controller.extend({ - boundParamValue: null, - init() { - this._super(); - controller = this; - } - })); - this.addTemplate('engine-params-bound', '{{mount "paramEngine" model=(hash foo=boundParamValue)}}'); + return this.visit('/engine-params-static').then(() => { + this.assertInnerHTML('

Param Engine: bar

'); + }); + } - return this.visit('/engine-params-bound').then(() => { - this.assertInnerHTML('

Param Engine:

'); + ['@test it renders with bound parameters']() { + this.router.map(function() { + this.route('engine-params-bound'); + }); + let controller; + this.add( + 'controller:engine-params-bound', + Controller.extend({ + boundParamValue: null, + init() { + this._super(); + controller = this; + } + }) + ); + this.addTemplate( + 'engine-params-bound', + '{{mount "paramEngine" model=(hash foo=boundParamValue)}}' + ); - this.runTask(() => set(controller, 'boundParamValue', 'bar')); + return this.visit('/engine-params-bound').then(() => { + this.assertInnerHTML('

Param Engine:

'); - this.assertInnerHTML('

Param Engine: bar

'); + this.runTask(() => set(controller, 'boundParamValue', 'bar')); - this.runTask(() => set(controller, 'boundParamValue', undefined)); + this.assertInnerHTML('

Param Engine: bar

'); - this.assertInnerHTML('

Param Engine:

'); + this.runTask(() => set(controller, 'boundParamValue', undefined)); - this.runTask(() => set(controller, 'boundParamValue', 'bar')); + this.assertInnerHTML('

Param Engine:

'); - this.assertInnerHTML('

Param Engine: bar

'); + this.runTask(() => set(controller, 'boundParamValue', 'bar')); - this.runTask(() => set(controller, 'boundParamValue', 'baz')); + this.assertInnerHTML('

Param Engine: bar

'); - this.assertInnerHTML('

Param Engine: baz

'); + this.runTask(() => set(controller, 'boundParamValue', 'baz')); - this.runTask(() => set(controller, 'boundParamValue', 'bar')); + this.assertInnerHTML('

Param Engine: baz

'); - this.assertInnerHTML('

Param Engine: bar

'); + this.runTask(() => set(controller, 'boundParamValue', 'bar')); - this.runTask(() => set(controller, 'boundParamValue', null)); + this.assertInnerHTML('

Param Engine: bar

'); - this.assertInnerHTML('

Param Engine:

'); - }); - } + this.runTask(() => set(controller, 'boundParamValue', null)); - ['@test it renders contextual components passed as parameter values']() { - this.router.map(function() { - this.route('engine-params-contextual-component'); - }); + this.assertInnerHTML('

Param Engine:

'); + }); + } - this.addComponent("foo-component", { - template: `foo-component rendered! - {{app-bar-component}}` - }); - this.addComponent('app-bar-component', { - ComponentClass: Component.extend({ tagName: "" }), - template: 'rendered app-bar-component from the app' - }); - this.add('engine:componentParamEngine', Engine.extend({ - router: null, - init() { - this._super(...arguments); - this.register('template:application', compile('{{model.foo}}', { moduleName: 'my-app/templates/application.hbs' })); - } - })); - this.addTemplate('engine-params-contextual-component', '{{mount "componentParamEngine" model=(hash foo=(component "foo-component"))}}'); + ['@test it renders contextual components passed as parameter values']() { + this.router.map(function() { + this.route('engine-params-contextual-component'); + }); - return this.visit('/engine-params-contextual-component').then(() => { - this.assertComponentElement(this.firstChild, { content: 'foo-component rendered! - rendered app-bar-component from the app' }); - }); + this.addComponent('foo-component', { + template: `foo-component rendered! - {{app-bar-component}}` + }); + this.addComponent('app-bar-component', { + ComponentClass: Component.extend({ tagName: '' }), + template: 'rendered app-bar-component from the app' + }); + this.add( + 'engine:componentParamEngine', + Engine.extend({ + router: null, + init() { + this._super(...arguments); + this.register( + 'template:application', + compile('{{model.foo}}', { + moduleName: 'my-app/templates/application.hbs' + }) + ); + } + }) + ); + this.addTemplate( + 'engine-params-contextual-component', + '{{mount "componentParamEngine" model=(hash foo=(component "foo-component"))}}' + ); + + return this.visit('/engine-params-contextual-component').then(() => { + this.assertComponentElement(this.firstChild, { + content: + 'foo-component rendered! - rendered app-bar-component from the app' + }); + }); + } } - }); + ); } diff --git a/packages/ember-glimmer/tests/integration/outlet-test.js b/packages/ember-glimmer/tests/integration/outlet-test.js index f7cc482f6a5..5ef9346831a 100644 --- a/packages/ember-glimmer/tests/integration/outlet-test.js +++ b/packages/ember-glimmer/tests/integration/outlet-test.js @@ -2,312 +2,320 @@ import { RenderingTest, moduleFor } from '../utils/test-case'; import { runAppend } from 'internal-test-helpers'; import { set } from 'ember-metal'; -moduleFor('outlet view', class extends RenderingTest { - constructor() { - super(...arguments); - - let CoreOutlet = this.owner.factoryFor('view:-outlet'); - - this.component = CoreOutlet.create(); - } - - ['@test should not error when initial rendered template is undefined']() { - let outletState = { - render: { - owner: this.owner, - into: undefined, - outlet: 'main', - name: 'application', - controller: undefined, - template: undefined - }, - - outlets: Object.create(null) - }; - - this.runTask(() => this.component.setOutletState(outletState)); - - runAppend(this.component); - - this.assertText(''); - } - - ['@test should render the outlet when set after DOM insertion']() { - let outletState = { - render: { - owner: this.owner, - into: undefined, - outlet: 'main', - name: 'application', - controller: undefined, - template: undefined - }, - - outlets: Object.create(null) - }; - - this.runTask(() => this.component.setOutletState(outletState)); - - runAppend(this.component); - - this.assertText(''); - - this.registerTemplate('application', 'HI{{outlet}}'); - outletState = { - render: { - owner: this.owner, - into: undefined, - outlet: 'main', - name: 'application', - controller: {}, - template: this.owner.lookup('template:application') - }, - outlets: Object.create(null) - }; - - this.runTask(() => this.component.setOutletState(outletState)); - - this.assertText('HI'); - - this.assertStableRerender(); - - this.registerTemplate('index', '

BYE

'); - outletState.outlets.main = { - render: { - owner: this.owner, - into: undefined, - outlet: 'main', - name: 'index', - controller: {}, - template: this.owner.lookup('template:index') - }, - outlets: Object.create(null) - }; - - this.runTask(() => this.component.setOutletState(outletState)); - - this.assertText('HIBYE'); - } - - ['@test should render the outlet when set before DOM insertion']() { - this.registerTemplate('application', 'HI{{outlet}}'); - let outletState = { - render: { - owner: this.owner, - into: undefined, - outlet: 'main', - name: 'application', - controller: {}, - template: this.owner.lookup('template:application') - }, - outlets: Object.create(null) - }; - - this.runTask(() => this.component.setOutletState(outletState)); - - runAppend(this.component); - - this.assertText('HI'); - - this.assertStableRerender(); - - this.registerTemplate('index', '

BYE

'); - outletState.outlets.main = { - render: { - owner: this.owner, - into: undefined, - outlet: 'main', - name: 'index', - controller: {}, - template: this.owner.lookup('template:index') - }, - outlets: Object.create(null) - }; - - this.runTask(() => this.component.setOutletState(outletState)); - - this.assertText('HIBYE'); - } - - ['@test should support an optional name']() { - this.registerTemplate('application', '

HI

{{outlet "special"}}'); - let outletState = { - render: { - owner: this.owner, - into: undefined, - outlet: 'main', - name: 'application', - controller: {}, - template: this.owner.lookup('template:application') - }, - outlets: Object.create(null) - }; - - this.runTask(() => this.component.setOutletState(outletState)); - - runAppend(this.component); - - this.assertText('HI'); - - this.assertStableRerender(); - - this.registerTemplate('special', '

BYE

'); - outletState.outlets.special = { - render: { - owner: this.owner, - into: undefined, - outlet: 'main', - name: 'special', - controller: {}, - template: this.owner.lookup('template:special') - }, - outlets: Object.create(null) - }; - - this.runTask(() => this.component.setOutletState(outletState)); - - this.assertText('HIBYE'); - } - - ['@test does not default outlet name when positional argument is present']() { - this.registerTemplate('application', '

HI

{{outlet someUndefinedThing}}'); - let outletState = { - render: { - owner: this.owner, - into: undefined, - outlet: 'main', - name: 'application', - controller: {}, - template: this.owner.lookup('template:application') - }, - outlets: Object.create(null) - }; - - this.runTask(() => this.component.setOutletState(outletState)); - - runAppend(this.component); - - this.assertText('HI'); - - this.assertStableRerender(); - - this.registerTemplate('special', '

BYE

'); - outletState.outlets.main = { - render: { - owner: this.owner, - into: undefined, - outlet: 'main', - name: 'special', - controller: {}, - template: this.owner.lookup('template:special') - }, - outlets: Object.create(null) - }; - - this.runTask(() => this.component.setOutletState(outletState)); - - this.assertText('HI'); - } - - ['@test should support bound outlet name']() { - let controller = { outletName: 'foo' }; - this.registerTemplate('application', '

HI

{{outlet outletName}}'); - let outletState = { - render: { - owner: this.owner, - into: undefined, - outlet: 'main', - name: 'application', - controller, - template: this.owner.lookup('template:application') - }, - outlets: Object.create(null) - }; - - this.runTask(() => this.component.setOutletState(outletState)); - - runAppend(this.component); - - this.assertText('HI'); - - this.assertStableRerender(); - - this.registerTemplate('foo', '

FOO

'); - outletState.outlets.foo = { - render: { - owner: this.owner, - into: undefined, - outlet: 'main', - name: 'foo', - controller: {}, - template: this.owner.lookup('template:foo') - }, - outlets: Object.create(null) - }; - - this.registerTemplate('bar', '

BAR

'); - outletState.outlets.bar = { - render: { - owner: this.owner, - into: undefined, - outlet: 'main', - name: 'bar', - controller: {}, - template: this.owner.lookup('template:bar') - }, - outlets: Object.create(null) - }; - - this.runTask(() => this.component.setOutletState(outletState)); - - this.assertText('HIFOO'); - - this.runTask(() => set(controller, 'outletName', 'bar')); - - this.assertText('HIBAR'); - } - - ['@test outletState can pass through user code (liquid-fire initimate API) ']() { - this.registerTemplate('outer', 'A{{#-with-dynamic-vars outletState=(identity (-get-dynamic-var "outletState"))}}B{{outlet}}D{{/-with-dynamic-vars}}E'); - this.registerTemplate('inner', 'C'); - - // This looks like it doesn't do anything, but its presence - // guarantees that the outletState gets converted from a reference - // to a value and then back to a reference. That is what we're - // testing here. - this.registerHelper('identity', ([a]) => a); - - let outletState = { - render: { - owner: this.owner, - into: undefined, - outlet: 'main', - name: 'outer', - controller: {}, - template: this.owner.lookup('template:outer') - }, - outlets: { - main: { - render: { - owner: this.owner, - into: undefined, - outlet: 'main', - name: 'inner', - controller: {}, - template: this.owner.lookup('template:inner') - }, - outlets: Object.create(null) +moduleFor( + 'outlet view', + class extends RenderingTest { + constructor() { + super(...arguments); + + let CoreOutlet = this.owner.factoryFor('view:-outlet'); + + this.component = CoreOutlet.create(); + } + + ['@test should not error when initial rendered template is undefined']() { + let outletState = { + render: { + owner: this.owner, + into: undefined, + outlet: 'main', + name: 'application', + controller: undefined, + template: undefined + }, + + outlets: Object.create(null) + }; + + this.runTask(() => this.component.setOutletState(outletState)); + + runAppend(this.component); + + this.assertText(''); + } + + ['@test should render the outlet when set after DOM insertion']() { + let outletState = { + render: { + owner: this.owner, + into: undefined, + outlet: 'main', + name: 'application', + controller: undefined, + template: undefined + }, + + outlets: Object.create(null) + }; + + this.runTask(() => this.component.setOutletState(outletState)); + + runAppend(this.component); + + this.assertText(''); + + this.registerTemplate('application', 'HI{{outlet}}'); + outletState = { + render: { + owner: this.owner, + into: undefined, + outlet: 'main', + name: 'application', + controller: {}, + template: this.owner.lookup('template:application') + }, + outlets: Object.create(null) + }; + + this.runTask(() => this.component.setOutletState(outletState)); + + this.assertText('HI'); + + this.assertStableRerender(); + + this.registerTemplate('index', '

BYE

'); + outletState.outlets.main = { + render: { + owner: this.owner, + into: undefined, + outlet: 'main', + name: 'index', + controller: {}, + template: this.owner.lookup('template:index') + }, + outlets: Object.create(null) + }; + + this.runTask(() => this.component.setOutletState(outletState)); + + this.assertText('HIBYE'); + } + + ['@test should render the outlet when set before DOM insertion']() { + this.registerTemplate('application', 'HI{{outlet}}'); + let outletState = { + render: { + owner: this.owner, + into: undefined, + outlet: 'main', + name: 'application', + controller: {}, + template: this.owner.lookup('template:application') + }, + outlets: Object.create(null) + }; + + this.runTask(() => this.component.setOutletState(outletState)); + + runAppend(this.component); + + this.assertText('HI'); + + this.assertStableRerender(); + + this.registerTemplate('index', '

BYE

'); + outletState.outlets.main = { + render: { + owner: this.owner, + into: undefined, + outlet: 'main', + name: 'index', + controller: {}, + template: this.owner.lookup('template:index') + }, + outlets: Object.create(null) + }; + + this.runTask(() => this.component.setOutletState(outletState)); + + this.assertText('HIBYE'); + } + + ['@test should support an optional name']() { + this.registerTemplate('application', '

HI

{{outlet "special"}}'); + let outletState = { + render: { + owner: this.owner, + into: undefined, + outlet: 'main', + name: 'application', + controller: {}, + template: this.owner.lookup('template:application') + }, + outlets: Object.create(null) + }; + + this.runTask(() => this.component.setOutletState(outletState)); + + runAppend(this.component); + + this.assertText('HI'); + + this.assertStableRerender(); + + this.registerTemplate('special', '

BYE

'); + outletState.outlets.special = { + render: { + owner: this.owner, + into: undefined, + outlet: 'main', + name: 'special', + controller: {}, + template: this.owner.lookup('template:special') + }, + outlets: Object.create(null) + }; + + this.runTask(() => this.component.setOutletState(outletState)); + + this.assertText('HIBYE'); + } + + ['@test does not default outlet name when positional argument is present']() { + this.registerTemplate( + 'application', + '

HI

{{outlet someUndefinedThing}}' + ); + let outletState = { + render: { + owner: this.owner, + into: undefined, + outlet: 'main', + name: 'application', + controller: {}, + template: this.owner.lookup('template:application') + }, + outlets: Object.create(null) + }; + + this.runTask(() => this.component.setOutletState(outletState)); + + runAppend(this.component); + + this.assertText('HI'); + + this.assertStableRerender(); + + this.registerTemplate('special', '

BYE

'); + outletState.outlets.main = { + render: { + owner: this.owner, + into: undefined, + outlet: 'main', + name: 'special', + controller: {}, + template: this.owner.lookup('template:special') + }, + outlets: Object.create(null) + }; + + this.runTask(() => this.component.setOutletState(outletState)); + + this.assertText('HI'); + } + + ['@test should support bound outlet name']() { + let controller = { outletName: 'foo' }; + this.registerTemplate('application', '

HI

{{outlet outletName}}'); + let outletState = { + render: { + owner: this.owner, + into: undefined, + outlet: 'main', + name: 'application', + controller, + template: this.owner.lookup('template:application') + }, + outlets: Object.create(null) + }; + + this.runTask(() => this.component.setOutletState(outletState)); + + runAppend(this.component); + + this.assertText('HI'); + + this.assertStableRerender(); + + this.registerTemplate('foo', '

FOO

'); + outletState.outlets.foo = { + render: { + owner: this.owner, + into: undefined, + outlet: 'main', + name: 'foo', + controller: {}, + template: this.owner.lookup('template:foo') + }, + outlets: Object.create(null) + }; + + this.registerTemplate('bar', '

BAR

'); + outletState.outlets.bar = { + render: { + owner: this.owner, + into: undefined, + outlet: 'main', + name: 'bar', + controller: {}, + template: this.owner.lookup('template:bar') + }, + outlets: Object.create(null) + }; + + this.runTask(() => this.component.setOutletState(outletState)); + + this.assertText('HIFOO'); + + this.runTask(() => set(controller, 'outletName', 'bar')); + + this.assertText('HIBAR'); + } + + ['@test outletState can pass through user code (liquid-fire initimate API) ']() { + this.registerTemplate( + 'outer', + 'A{{#-with-dynamic-vars outletState=(identity (-get-dynamic-var "outletState"))}}B{{outlet}}D{{/-with-dynamic-vars}}E' + ); + this.registerTemplate('inner', 'C'); + + // This looks like it doesn't do anything, but its presence + // guarantees that the outletState gets converted from a reference + // to a value and then back to a reference. That is what we're + // testing here. + this.registerHelper('identity', ([a]) => a); + + let outletState = { + render: { + owner: this.owner, + into: undefined, + outlet: 'main', + name: 'outer', + controller: {}, + template: this.owner.lookup('template:outer') + }, + outlets: { + main: { + render: { + owner: this.owner, + into: undefined, + outlet: 'main', + name: 'inner', + controller: {}, + template: this.owner.lookup('template:inner') + }, + outlets: Object.create(null) + } } - } - }; + }; - this.runTask(() => this.component.setOutletState(outletState)); + this.runTask(() => this.component.setOutletState(outletState)); - runAppend(this.component); + runAppend(this.component); - this.assertText('ABCDE'); + this.assertText('ABCDE'); - this.assertStableRerender(); + this.assertStableRerender(); + } } - -}); +); diff --git a/packages/ember-glimmer/tests/integration/refinements-test.js b/packages/ember-glimmer/tests/integration/refinements-test.js index 9a09d5a6e9f..2004cc20196 100644 --- a/packages/ember-glimmer/tests/integration/refinements-test.js +++ b/packages/ember-glimmer/tests/integration/refinements-test.js @@ -2,11 +2,14 @@ import { RenderingTest, moduleFor } from '../utils/test-case'; import { strip } from '../utils/abstract-test-case'; import { set } from 'ember-metal'; -moduleFor('syntax refinements', class extends RenderingTest { - ['@test block params should not be refined']() { - this.registerHelper('foo', () => 'bar helper'); - - this.render(strip` +moduleFor( + 'syntax refinements', + class extends RenderingTest { + ['@test block params should not be refined']() { + this.registerHelper('foo', () => 'bar helper'); + + this.render( + strip` {{#with var as |foo|}} {{foo}} {{/with}} @@ -51,17 +54,21 @@ moduleFor('syntax refinements', class extends RenderingTest { {{#with var as |-in-element|}} {{-in-element}} - {{/with}}`, { var: 'var' }); + {{/with}}`, + { var: 'var' } + ); - this.assertText('var---var---var---var---var---var---var---var'); + this.assertText('var---var---var---var---var---var---var---var'); - this.runTask(() => set(this.context, 'var', 'RARRR!!!')); + this.runTask(() => set(this.context, 'var', 'RARRR!!!')); - this.assertText('RARRR!!!---RARRR!!!---RARRR!!!---RARRR!!!---RARRR!!!---RARRR!!!---RARRR!!!---RARRR!!!'); + this.assertText( + 'RARRR!!!---RARRR!!!---RARRR!!!---RARRR!!!---RARRR!!!---RARRR!!!---RARRR!!!---RARRR!!!' + ); - this.runTask(() => set(this.context, 'var', 'var')); + this.runTask(() => set(this.context, 'var', 'var')); - this.assertText('var---var---var---var---var---var---var---var'); + this.assertText('var---var---var---var---var---var---var---var'); + } } - -}); +); diff --git a/packages/ember-glimmer/tests/integration/render-settled-test.js b/packages/ember-glimmer/tests/integration/render-settled-test.js index 18d234c7a2a..04b75a2b446 100644 --- a/packages/ember-glimmer/tests/integration/render-settled-test.js +++ b/packages/ember-glimmer/tests/integration/render-settled-test.js @@ -1,73 +1,72 @@ -import { - RenderingTestCase, - moduleFor, - strip -} from 'internal-test-helpers'; +import { RenderingTestCase, moduleFor, strip } from 'internal-test-helpers'; import { renderSettled } from 'ember-glimmer'; import { all } from 'rsvp'; import { run, schedule } from 'ember-metal'; -moduleFor('renderSettled', class extends RenderingTestCase { - ['@test resolves when no rendering is happening'](assert) { - return renderSettled().then(() => { - assert.ok(true, 'resolved even without rendering'); - }); - } +moduleFor( + 'renderSettled', + class extends RenderingTestCase { + ['@test resolves when no rendering is happening'](assert) { + return renderSettled().then(() => { + assert.ok(true, 'resolved even without rendering'); + }); + } - ['@test resolves renderers exist but no runloops are triggered'](assert) { - this.render(strip`{{foo}}`, { foo: 'bar' }); + ['@test resolves renderers exist but no runloops are triggered'](assert) { + this.render(strip`{{foo}}`, { foo: 'bar' }); - return renderSettled().then(() => { - assert.ok(true, 'resolved even without runloops'); - }); - } + return renderSettled().then(() => { + assert.ok(true, 'resolved even without runloops'); + }); + } - ['@test does not create extraneous promises'](assert) { - let first = renderSettled(); - let second = renderSettled(); + ['@test does not create extraneous promises'](assert) { + let first = renderSettled(); + let second = renderSettled(); - assert.strictEqual(first, second); + assert.strictEqual(first, second); - return all([first, second]); - } + return all([first, second]); + } - ['@test resolves when rendering has completed (after property update)']() { - this.render(strip`{{foo}}`, { foo: 'bar' }); + ['@test resolves when rendering has completed (after property update)']() { + this.render(strip`{{foo}}`, { foo: 'bar' }); - this.assertText('bar'); - this.component.set('foo', 'baz'); - this.assertText('bar'); + this.assertText('bar'); + this.component.set('foo', 'baz'); + this.assertText('bar'); - return renderSettled().then(() => { - this.assertText('baz'); - }); - } + return renderSettled().then(() => { + this.assertText('baz'); + }); + } - ['@test resolves in run loop when renderer has settled'](assert) { - assert.expect(3); + ['@test resolves in run loop when renderer has settled'](assert) { + assert.expect(3); - this.render(strip`{{foo}}`, { foo: 'bar' }); + this.render(strip`{{foo}}`, { foo: 'bar' }); - this.assertText('bar'); - let promise; + this.assertText('bar'); + let promise; - return run(() => { - schedule('actions', null, () => { - this.component.set('foo', 'set in actions'); + return run(() => { + schedule('actions', null, () => { + this.component.set('foo', 'set in actions'); - promise = renderSettled().then(() => { - this.assertText('set in afterRender'); - }); + promise = renderSettled().then(() => { + this.assertText('set in afterRender'); + }); - schedule('afterRender', null, () => { - this.component.set('foo', 'set in afterRender'); + schedule('afterRender', null, () => { + this.component.set('foo', 'set in afterRender'); + }); }); - }); - // still not updated here - this.assertText('bar'); + // still not updated here + this.assertText('bar'); - return promise; - }); + return promise; + }); + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/svg-test.js b/packages/ember-glimmer/tests/integration/svg-test.js index abf9cd76103..c33b9b3ffa3 100644 --- a/packages/ember-glimmer/tests/integration/svg-test.js +++ b/packages/ember-glimmer/tests/integration/svg-test.js @@ -2,154 +2,160 @@ import { RenderingTest, moduleFor } from '../utils/test-case'; import { set } from 'ember-metal'; import { strip } from '../utils/abstract-test-case'; -moduleFor('SVG element tests', class extends RenderingTest { - ['@test unquoted viewBox property is output'](assert) { - let viewBoxString = '0 0 100 100'; - - this.render('
', { - model: { - viewBoxString - } - }); - - this.assertInnerHTML(strip` +moduleFor( + 'SVG element tests', + class extends RenderingTest { + ['@test unquoted viewBox property is output'](assert) { + let viewBoxString = '0 0 100 100'; + + this.render('
', { + model: { + viewBoxString + } + }); + + this.assertInnerHTML(strip`
`); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertInnerHTML(strip` + this.assertInnerHTML(strip`
`); - this.runTask(() => set(this.context, 'model.viewBoxString', null)); + this.runTask(() => set(this.context, 'model.viewBoxString', null)); - assert.equal(this.firstChild.getAttribute('svg'), null); + assert.equal(this.firstChild.getAttribute('svg'), null); - this.runTask(() => set(this.context, 'model', { viewBoxString })); + this.runTask(() => set(this.context, 'model', { viewBoxString })); - this.assertInnerHTML(strip` + this.assertInnerHTML(strip`
`); - } + } - ['@test quoted viewBox property is output'](assert) { - let viewBoxString = '0 0 100 100'; + ['@test quoted viewBox property is output'](assert) { + let viewBoxString = '0 0 100 100'; - this.render('
', { - model: { - viewBoxString - } - }); + this.render('
', { + model: { + viewBoxString + } + }); - this.assertInnerHTML(strip` + this.assertInnerHTML(strip`
`); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertInnerHTML(strip` + this.assertInnerHTML(strip`
`); - this.runTask(() => set(this.context, 'model.viewBoxString', null)); + this.runTask(() => set(this.context, 'model.viewBoxString', null)); - assert.equal(this.firstChild.getAttribute('svg'), null); + assert.equal(this.firstChild.getAttribute('svg'), null); - this.runTask(() => set(this.context, 'model', { viewBoxString })); + this.runTask(() => set(this.context, 'model', { viewBoxString })); - this.assertInnerHTML(strip` + this.assertInnerHTML(strip`
`); - } + } - ['@test quoted viewBox property is concat']() { - let viewBoxString = '100 100'; + ['@test quoted viewBox property is concat']() { + let viewBoxString = '100 100'; - this.render('
', { - model: { - viewBoxString - } - }); + this.render( + '
', + { + model: { + viewBoxString + } + } + ); - this.assertInnerHTML(strip` + this.assertInnerHTML(strip`
`); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertInnerHTML(strip` + this.assertInnerHTML(strip`
`); - this.runTask(() => set(this.context, 'model.viewBoxString', '200 200')); + this.runTask(() => set(this.context, 'model.viewBoxString', '200 200')); - this.assertInnerHTML(strip` + this.assertInnerHTML(strip`
`); - this.runTask(() => set(this.context, 'model', { viewBoxString })); + this.runTask(() => set(this.context, 'model', { viewBoxString })); - this.assertInnerHTML(strip` + this.assertInnerHTML(strip`
`); - } + } - ['@test class is output']() { - this.render('
', { - model: { - color: 'blue' - } - }); + ['@test class is output']() { + this.render("
", { + model: { + color: 'blue' + } + }); - this.assertInnerHTML(strip` + this.assertInnerHTML(strip`
`); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertInnerHTML(strip` + this.assertInnerHTML(strip`
`); - this.runTask(() => set(this.context, 'model.color', 'yellow')); + this.runTask(() => set(this.context, 'model.color', 'yellow')); - this.assertInnerHTML(strip` + this.assertInnerHTML(strip`
`); - this.runTask(() => set(this.context, 'model', { color: 'blue' })); + this.runTask(() => set(this.context, 'model', { color: 'blue' })); - this.assertInnerHTML(strip` + this.assertInnerHTML(strip`
`); + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/syntax/each-in-test.js b/packages/ember-glimmer/tests/integration/syntax/each-in-test.js index 35cf375fac2..036769a3735 100644 --- a/packages/ember-glimmer/tests/integration/syntax/each-in-test.js +++ b/packages/ember-glimmer/tests/integration/syntax/each-in-test.js @@ -11,11 +11,9 @@ import { } from '../../utils/shared-conditional-tests'; class EachInTest extends TogglingSyntaxConditionalsTest { - templateFor({ cond, truthy, falsy }) { return `{{#each-in ${cond} as |key|}}${truthy}{{else}}${falsy}{{/each-in}}`; } - } function EmptyFunction() {} @@ -30,7 +28,8 @@ NonEmptyConstructor.foo = 'bar'; class BasicEachInTest extends EachInTest {} -applyMixins(BasicEachInTest, +applyMixins( + BasicEachInTest, new TruthyGenerator([ { foo: 1 }, @@ -57,45 +56,49 @@ applyMixins(BasicEachInTest, ]) ); -moduleFor('Syntax test: {{#each-in}}', class extends BasicEachInTest { +moduleFor( + 'Syntax test: {{#each-in}}', + class extends BasicEachInTest { + get truthyValue() { + return { 'Not Empty': 1 }; + } - get truthyValue() { - return { 'Not Empty': 1 }; - } + get falsyValue() { + return {}; + } - get falsyValue() { - return {}; - } - - [`@test it repeats the given block for each item in the hash`]() { - this.render(strip` + [`@test it repeats the given block for each item in the hash`]() { + this.render( + strip`
    {{#each-in categories as |category count|}}
  • {{category}}: {{count}}
  • {{/each-in}}
- `, { - categories: { - 'Smartphones': 8203, - 'JavaScript Frameworks': Infinity - } - }); + `, + { + categories: { + Smartphones: 8203, + 'JavaScript Frameworks': Infinity + } + } + ); - this.assertHTML(strip` + this.assertHTML(strip`
  • Smartphones: 8203
  • JavaScript Frameworks: Infinity
`); - this.assertStableRerender(); + this.assertStableRerender(); - this.runTask(() => { - set(this.context, 'categories.Smartphones', 100); - set(this.context, 'categories.Tweets', 443115); - }); + this.runTask(() => { + set(this.context, 'categories.Smartphones', 100); + set(this.context, 'categories.Tweets', 443115); + }); - this.assertHTML(strip` + this.assertHTML(strip`
  • Smartphones: 100
  • JavaScript Frameworks: Infinity
  • @@ -103,48 +106,55 @@ moduleFor('Syntax test: {{#each-in}}', class extends BasicEachInTest {
`); - this.runTask(() => set(this.context, 'categories', { - 'Smartphones': 8203, - 'JavaScript Frameworks': Infinity - })); + this.runTask(() => + set(this.context, 'categories', { + Smartphones: 8203, + 'JavaScript Frameworks': Infinity + }) + ); - this.assertHTML(strip` + this.assertHTML(strip`
  • Smartphones: 8203
  • JavaScript Frameworks: Infinity
`); - } + } - [`@test it can render sub-paths of each item`]() { - this.render(strip` + [`@test it can render sub-paths of each item`]() { + this.render( + strip`
    {{#each-in categories as |category data|}}
  • {{category}}: {{data.reports.unitsSold}}
  • {{/each-in}}
- `, { - categories: { - 'Smartphones': { reports: { unitsSold: 8203 } }, - 'JavaScript Frameworks': { reports: { unitsSold: Infinity } } - } - }); - - this.assertHTML(strip` + `, + { + categories: { + Smartphones: { reports: { unitsSold: 8203 } }, + 'JavaScript Frameworks': { reports: { unitsSold: Infinity } } + } + } + ); + + this.assertHTML(strip`
  • Smartphones: 8203
  • JavaScript Frameworks: Infinity
`); - this.assertStableRerender(); + this.assertStableRerender(); - this.runTask(() => { - set(this.context, 'categories.Smartphones.reports.unitsSold', 100); - set(this.context, 'categories.Tweets', { reports: { unitsSold: 443115 } }); - }); + this.runTask(() => { + set(this.context, 'categories.Smartphones.reports.unitsSold', 100); + set(this.context, 'categories.Tweets', { + reports: { unitsSold: 443115 } + }); + }); - this.assertHTML(strip` + this.assertHTML(strip`
  • Smartphones: 100
  • JavaScript Frameworks: Infinity
  • @@ -152,36 +162,41 @@ moduleFor('Syntax test: {{#each-in}}', class extends BasicEachInTest {
`); - this.runTask(() => set(this.context, 'categories', { - 'Smartphones': { reports: { unitsSold: 8203 } }, - 'JavaScript Frameworks': { reports: { unitsSold: Infinity } } - })); + this.runTask(() => + set(this.context, 'categories', { + Smartphones: { reports: { unitsSold: 8203 } }, + 'JavaScript Frameworks': { reports: { unitsSold: Infinity } } + }) + ); - this.assertHTML(strip` + this.assertHTML(strip`
  • Smartphones: 8203
  • JavaScript Frameworks: Infinity
`); - } + } - [`@test it can render duplicate items`]() { - this.render(strip` + [`@test it can render duplicate items`]() { + this.render( + strip`
    {{#each-in categories key='@identity' as |category count|}}
  • {{category}}: {{count}}
  • {{/each-in}}
- `, { - categories: { - 'Smartphones': 8203, - 'Tablets': 8203, - 'JavaScript Frameworks': Infinity, - 'Bugs': Infinity - } - }); - - this.assertHTML(strip` + `, + { + categories: { + Smartphones: 8203, + Tablets: 8203, + 'JavaScript Frameworks': Infinity, + Bugs: Infinity + } + } + ); + + this.assertHTML(strip`
  • Smartphones: 8203
  • Tablets: 8203
  • @@ -190,14 +205,14 @@ moduleFor('Syntax test: {{#each-in}}', class extends BasicEachInTest {
`); - this.assertStableRerender(); + this.assertStableRerender(); - this.runTask(() => { - set(this.context, 'categories.Smartphones', 100); - set(this.context, 'categories.Tweets', 443115); - }); + this.runTask(() => { + set(this.context, 'categories.Smartphones', 100); + set(this.context, 'categories.Tweets', 443115); + }); - this.assertHTML(strip` + this.assertHTML(strip`
  • Smartphones: 100
  • Tablets: 8203
  • @@ -207,14 +222,16 @@ moduleFor('Syntax test: {{#each-in}}', class extends BasicEachInTest {
`); - this.runTask(() => set(this.context, 'categories', { - 'Smartphones': 8203, - 'Tablets': 8203, - 'JavaScript Frameworks': Infinity, - 'Bugs': Infinity - })); + this.runTask(() => + set(this.context, 'categories', { + Smartphones: 8203, + Tablets: 8203, + 'JavaScript Frameworks': Infinity, + Bugs: Infinity + }) + ); - this.assertHTML(strip` + this.assertHTML(strip`
  • Smartphones: 8203
  • Tablets: 8203
  • @@ -222,92 +239,98 @@ moduleFor('Syntax test: {{#each-in}}', class extends BasicEachInTest {
  • Bugs: Infinity
`); - } + } - [`@test it repeats the given block when the hash is dynamic`]() { - this.render(strip` + [`@test it repeats the given block when the hash is dynamic`]() { + this.render( + strip`
    {{#each-in (get collection type) as |category count|}}
  • {{category}}: {{count}}
  • {{/each-in}}
- `, { - collection: { - categories: { - 'Smartphones': 8203, - 'JavaScript Frameworks': Infinity - }, - otherCategories: { - 'Emberinios': 533462, - 'Tweets': 7323 + `, + { + collection: { + categories: { + Smartphones: 8203, + 'JavaScript Frameworks': Infinity + }, + otherCategories: { + Emberinios: 533462, + Tweets: 7323 + } + }, + type: 'categories' } - }, - type: 'categories' - }); + ); - this.assertHTML(strip` + this.assertHTML(strip`
  • Smartphones: 8203
  • JavaScript Frameworks: Infinity
`); - this.assertStableRerender(); + this.assertStableRerender(); - this.runTask(() => { - set(this.context, 'type', 'otherCategories'); - }); + this.runTask(() => { + set(this.context, 'type', 'otherCategories'); + }); - this.assertHTML(strip` + this.assertHTML(strip`
  • Emberinios: 533462
  • Tweets: 7323
`); - this.runTask(() => set(this.context, 'type', 'categories')); + this.runTask(() => set(this.context, 'type', 'categories')); - this.assertHTML(strip` + this.assertHTML(strip`
  • Smartphones: 8203
  • JavaScript Frameworks: Infinity
`); - } + } - [`@test it only iterates over an object's own properties`]() { - let protoCategories = { - 'Smartphones': 8203, - 'JavaScript Frameworks': Infinity - }; + [`@test it only iterates over an object's own properties`]() { + let protoCategories = { + Smartphones: 8203, + 'JavaScript Frameworks': Infinity + }; - let categories = Object.create(protoCategories); - categories['Televisions'] = 183; - categories['Alarm Clocks'] = 999; + let categories = Object.create(protoCategories); + categories['Televisions'] = 183; + categories['Alarm Clocks'] = 999; - this.render(strip` + this.render( + strip`
    {{#each-in categories as |category count|}}
  • {{category}}: {{count}}
  • {{/each-in}}
- `, { categories }); + `, + { categories } + ); - this.assertHTML(strip` + this.assertHTML(strip`
  • Televisions: 183
  • Alarm Clocks: 999
`); - this.assertStableRerender(); + this.assertStableRerender(); - this.runTask(() => { - set(protoCategories, 'Robots', 666); - set(categories, 'Tweets', 443115); - }); + this.runTask(() => { + set(protoCategories, 'Robots', 666); + set(categories, 'Tweets', 443115); + }); - this.assertHTML(strip` + this.assertHTML(strip`
  • Televisions: 183
  • Alarm Clocks: 999
  • @@ -315,182 +338,192 @@ moduleFor('Syntax test: {{#each-in}}', class extends BasicEachInTest {
`); - categories = Object.create(protoCategories); - categories['Televisions'] = 183; - categories['Alarm Clocks'] = 999; + categories = Object.create(protoCategories); + categories['Televisions'] = 183; + categories['Alarm Clocks'] = 999; - this.runTask(() => set(this.context, 'categories', categories)); + this.runTask(() => set(this.context, 'categories', categories)); - this.assertHTML(strip` + this.assertHTML(strip`
  • Televisions: 183
  • Alarm Clocks: 999
`); - } + } - [`@test it does not observe direct property mutations (not going through set) on the object`]() { - this.render(strip` + [`@test it does not observe direct property mutations (not going through set) on the object`]() { + this.render( + strip`
    {{#each-in categories as |category count|}}
  • {{category}}: {{count}}
  • {{/each-in}}
- `, { - categories: { - 'Smartphones': 8203, - 'JavaScript Frameworks': Infinity - } - }); + `, + { + categories: { + Smartphones: 8203, + 'JavaScript Frameworks': Infinity + } + } + ); - this.assertHTML(strip` + this.assertHTML(strip`
  • Smartphones: 8203
  • JavaScript Frameworks: Infinity
`); - this.assertStableRerender(); + this.assertStableRerender(); - this.runTask(() => { - let categories = get(this.context, 'categories'); - delete categories.Smartphones; - }); + this.runTask(() => { + let categories = get(this.context, 'categories'); + delete categories.Smartphones; + }); - this.assertInvariants(); + this.assertInvariants(); - this.runTask(() => { - let categories = get(this.context, 'categories'); - categories['Emberinios'] = 123456; - }); + this.runTask(() => { + let categories = get(this.context, 'categories'); + categories['Emberinios'] = 123456; + }); - this.assertInvariants(); + this.assertInvariants(); - this.runTask(() => { - set(this.context, 'categories', { - Emberinios: 123456 + this.runTask(() => { + set(this.context, 'categories', { + Emberinios: 123456 + }); }); - }); - this.assertHTML(strip` + this.assertHTML(strip`
  • Emberinios: 123456
`); - this.runTask(() => { - set(this.context, 'categories', { - 'Smartphones': 8203, - 'JavaScript Frameworks': Infinity + this.runTask(() => { + set(this.context, 'categories', { + Smartphones: 8203, + 'JavaScript Frameworks': Infinity + }); }); - }); - this.assertHTML(strip` + this.assertHTML(strip`
  • Smartphones: 8203
  • JavaScript Frameworks: Infinity
`); - } + } - ['@test keying off of `undefined` does not render']() { - this.render(strip` + ['@test keying off of `undefined` does not render']() { + this.render( + strip` {{#each-in foo.bar.baz as |thing|}} {{thing}} - {{/each-in}}`, { foo: {} }); + {{/each-in}}`, + { foo: {} } + ); - this.assertText(''); + this.assertText(''); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText(''); + this.assertText(''); - this.runTask(() => set(this.context, 'foo', { bar: { baz: { 'Here!': 1 } } })); + this.runTask(() => + set(this.context, 'foo', { bar: { baz: { 'Here!': 1 } } }) + ); - this.assertText('Here!'); + this.assertText('Here!'); - this.runTask(() => set(this.context, 'foo', {})); + this.runTask(() => set(this.context, 'foo', {})); - this.assertText(''); - } + this.assertText(''); + } - ['@test it iterate over array with `in` instead of walking over elements']() { - let arr = [1, 2, 3]; - arr.foo = 'bar'; + ['@test it iterate over array with `in` instead of walking over elements']() { + let arr = [1, 2, 3]; + arr.foo = 'bar'; - this.render(strip` + this.render( + strip` {{#each-in arr as |key value|}} [{{key}}:{{value}}] - {{/each-in}}`, { arr }); + {{/each-in}}`, + { arr } + ); - this.assertText('[0:1][1:2][2:3][foo:bar]'); + this.assertText('[0:1][1:2][2:3][foo:bar]'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('[0:1][1:2][2:3][foo:bar]'); + this.assertText('[0:1][1:2][2:3][foo:bar]'); - this.runTask(() => { - set(arr, 'zomg', 'lol'); - }); + this.runTask(() => { + set(arr, 'zomg', 'lol'); + }); - this.assertText('[0:1][1:2][2:3][foo:bar][zomg:lol]'); + this.assertText('[0:1][1:2][2:3][foo:bar][zomg:lol]'); - arr = [1, 2, 3]; - arr.foo = 'bar'; + arr = [1, 2, 3]; + arr.foo = 'bar'; - this.runTask(() => set(this.context, 'arr', arr)); + this.runTask(() => set(this.context, 'arr', arr)); - this.assertText('[0:1][1:2][2:3][foo:bar]'); - } + this.assertText('[0:1][1:2][2:3][foo:bar]'); + } - ['@test it skips holes in sparse arrays']() { - let arr = []; - arr[5] = 'foo'; - arr[6] = 'bar'; + ['@test it skips holes in sparse arrays']() { + let arr = []; + arr[5] = 'foo'; + arr[6] = 'bar'; - this.render(strip` + this.render( + strip` {{#each-in arr as |key value|}} [{{key}}:{{value}}] - {{/each-in}}`, { arr }); + {{/each-in}}`, + { arr } + ); - this.assertText('[5:foo][6:bar]'); + this.assertText('[5:foo][6:bar]'); - this.assertStableRerender(); + this.assertStableRerender(); + } } - -}); +); class EachInEdgeCasesTest extends EachInTest {} -applyMixins(EachInEdgeCasesTest, - - new FalsyGenerator([ - true, - 1, - 'hello' - ]) +applyMixins( + EachInEdgeCasesTest, + new FalsyGenerator([true, 1, 'hello']) ); -moduleFor('Syntax test: {{#each-in}} edge cases', class extends EachInEdgeCasesTest { +moduleFor( + 'Syntax test: {{#each-in}} edge cases', + class extends EachInEdgeCasesTest { + get truthyValue() { + return { 'Not Empty': 1 }; + } - get truthyValue() { - return { 'Not Empty': 1 }; + get falsyValue() { + return {}; + } } - - get falsyValue() { - return {}; - } - -}); +); class EachInProxyTest extends EachInTest {} -applyMixins(EachInProxyTest, +applyMixins( + EachInProxyTest, - new TruthyGenerator([ - ObjectProxy.create({ content: { 'Not empty': 1 } }) - ]), + new TruthyGenerator([ObjectProxy.create({ content: { 'Not empty': 1 } })]), new FalsyGenerator([ ObjectProxy.create(), @@ -503,50 +536,54 @@ applyMixins(EachInProxyTest, ]) ); -moduleFor('Syntax test: {{#each-in}} with `ObjectProxy`', class extends EachInProxyTest { +moduleFor( + 'Syntax test: {{#each-in}} with `ObjectProxy`', + class extends EachInProxyTest { + get truthyValue() { + return ObjectProxy.create({ content: { 'Not Empty': 1 } }); + } - get truthyValue() { - return ObjectProxy.create({ content: { 'Not Empty': 1 } }); - } + get falsyValue() { + return ObjectProxy.create({ content: null }); + } - get falsyValue() { - return ObjectProxy.create({ content: null }); - } - - ['@test it iterates over the content, not the proxy']() { - let content = { - 'Smartphones': 8203, - 'JavaScript Frameworks': Infinity - }; + ['@test it iterates over the content, not the proxy']() { + let content = { + Smartphones: 8203, + 'JavaScript Frameworks': Infinity + }; - let proxy = ObjectProxy.create({ - content, - foo: 'bar' - }); + let proxy = ObjectProxy.create({ + content, + foo: 'bar' + }); - this.render(strip` + this.render( + strip`
    {{#each-in categories as |category count|}}
  • {{category}}: {{count}}
  • {{/each-in}}
- `, { categories: proxy }); + `, + { categories: proxy } + ); - this.assertHTML(strip` + this.assertHTML(strip`
  • Smartphones: 8203
  • JavaScript Frameworks: Infinity
`); - this.assertStableRerender(); + this.assertStableRerender(); - this.runTask(() => { - set(proxy, 'content.Smartphones', 100); - set(proxy, 'content.Tweets', 443115); - }); + this.runTask(() => { + set(proxy, 'content.Smartphones', 100); + set(proxy, 'content.Tweets', 443115); + }); - this.assertHTML(strip` + this.assertHTML(strip`
  • Smartphones: 100
  • JavaScript Frameworks: Infinity
  • @@ -554,33 +591,39 @@ moduleFor('Syntax test: {{#each-in}} with `ObjectProxy`', class extends EachInPr
`); - this.runTask(() => { - set(proxy, 'content', { - 'Smartphones': 100, - 'Tablets': 20 + this.runTask(() => { + set(proxy, 'content', { + Smartphones: 100, + Tablets: 20 + }); }); - }); - this.assertHTML(strip` + this.assertHTML(strip`
  • Smartphones: 100
  • Tablets: 20
`); - this.runTask(() => set(this.context, 'categories', ObjectProxy.create({ - content: { - 'Smartphones': 8203, - 'JavaScript Frameworks': Infinity - } - }))); - - this.assertHTML(strip` + this.runTask(() => + set( + this.context, + 'categories', + ObjectProxy.create({ + content: { + Smartphones: 8203, + 'JavaScript Frameworks': Infinity + } + }) + ) + ); + + this.assertHTML(strip`
  • Smartphones: 8203
  • JavaScript Frameworks: Infinity
`); + } } - -}); +); diff --git a/packages/ember-glimmer/tests/integration/syntax/each-test.js b/packages/ember-glimmer/tests/integration/syntax/each-test.js index bd91061e3c7..26c830fd853 100644 --- a/packages/ember-glimmer/tests/integration/syntax/each-test.js +++ b/packages/ember-glimmer/tests/integration/syntax/each-test.js @@ -96,7 +96,7 @@ class ArrayDelegate { const makeSet = (() => { // IE11 does not support `new Set(items);` - let set = new Set([1,2,3]); + let set = new Set([1, 2, 3]); if (set.size === 3) { return items => new Set(items); @@ -145,10 +145,12 @@ if (HAS_NATIVE_SYMBOL) { } class TogglingEachTest extends TogglingSyntaxConditionalsTest { - - get truthyValue() { return ['non-empty']; } - get falsyValue() { return []; } - + get truthyValue() { + return ['non-empty']; + } + get falsyValue() { + return []; + } } class BasicEachTest extends TogglingEachTest {} @@ -181,31 +183,35 @@ if (HAS_NATIVE_SYMBOL) { FALSY_CASES.push(new ArrayIterable([])); } -applyMixins(BasicEachTest, +applyMixins( + BasicEachTest, new TruthyGenerator(TRUTHY_CASES), new FalsyGenerator(FALSY_CASES), ArrayTestCases ); -moduleFor('Syntax test: toggling {{#each}}', class extends BasicEachTest { - - templateFor({ cond, truthy, falsy }) { - return `{{#each ${cond}}}${truthy}{{else}}${falsy}{{/each}}`; +moduleFor( + 'Syntax test: toggling {{#each}}', + class extends BasicEachTest { + templateFor({ cond, truthy, falsy }) { + return `{{#each ${cond}}}${truthy}{{else}}${falsy}{{/each}}`; + } } +); -}); - -moduleFor('Syntax test: toggling {{#each as}}', class extends BasicEachTest { - - templateFor({ cond, truthy, falsy }) { - return `{{#each ${cond} as |test|}}${truthy}{{else}}${falsy}{{/each}}`; +moduleFor( + 'Syntax test: toggling {{#each as}}', + class extends BasicEachTest { + templateFor({ cond, truthy, falsy }) { + return `{{#each ${cond} as |test|}}${truthy}{{else}}${falsy}{{/each}}`; + } } - -}); +); class EachEdgeCasesTest extends TogglingEachTest {} -applyMixins(EachEdgeCasesTest, +applyMixins( + EachEdgeCasesTest, new FalsyGenerator([ true, @@ -219,27 +225,27 @@ applyMixins(EachEdgeCasesTest, Object.create({}), Object.create({ foo: 'bar' }) ]) - ); -moduleFor('Syntax test: toggling {{#each}}', class extends EachEdgeCasesTest { - - templateFor({ cond, truthy, falsy }) { - return `{{#each ${cond}}}${truthy}{{else}}${falsy}{{/each}}`; +moduleFor( + 'Syntax test: toggling {{#each}}', + class extends EachEdgeCasesTest { + templateFor({ cond, truthy, falsy }) { + return `{{#each ${cond}}}${truthy}{{else}}${falsy}{{/each}}`; + } } +); -}); - -moduleFor('Syntax test: toggling {{#each as}}', class extends EachEdgeCasesTest { - - templateFor({ cond, truthy, falsy }) { - return `{{#each ${cond} as |test|}}${truthy}{{else}}${falsy}{{/each}}`; +moduleFor( + 'Syntax test: toggling {{#each as}}', + class extends EachEdgeCasesTest { + templateFor({ cond, truthy, falsy }) { + return `{{#each ${cond} as |test|}}${truthy}{{else}}${falsy}{{/each}}`; + } } - -}); +); class AbstractEachTest extends RenderingTest { - /* abstract */ createList(/* items */) { throw new Error('Not implemented: `createList`'); @@ -311,11 +317,9 @@ class AbstractEachTest extends RenderingTest { return super.render(template, context); } - } class EachTest extends AbstractEachTest { - /* single each */ ['@test it repeats the given block for each item in the array']() { @@ -386,7 +390,9 @@ class EachTest extends AbstractEachTest { ['@test it receives the index as the second parameter']() { this.makeList([{ text: 'hello' }, { text: 'world' }]); - this.render(`{{#each list as |item index|}}[{{index}}. {{item.text}}]{{/each}}`); + this.render( + `{{#each list as |item index|}}[{{index}}. {{item.text}}]{{/each}}` + ); this.assertText('[0. hello][1. world]'); @@ -476,7 +482,9 @@ class EachTest extends AbstractEachTest { ['@test it can specify @identity as the key for mixed arrays of objects and primitives']() { this.makeList([1, { id: 2 }, 3]); - this.render(`{{#each list key='@identity' as |item|}}{{if item.id item.id item}}{{/each}}`); + this.render( + `{{#each list key='@identity' as |item|}}{{if item.id item.id item}}{{/each}}` + ); this.assertText('123'); @@ -532,7 +540,10 @@ class EachTest extends AbstractEachTest { } }); - this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: '{{#if isEven}}{{item.value}}{{/if}}' }); + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: '{{#if isEven}}{{item.value}}{{/if}}' + }); this.render(strip` {{#each list as |item|}} @@ -558,7 +569,12 @@ class EachTest extends AbstractEachTest { ['@test it can render duplicate objects']() { let duplicateItem = { text: 'foo' }; - this.makeList([duplicateItem, duplicateItem, { text: 'bar' }, { text: 'baz' }]); + this.makeList([ + duplicateItem, + duplicateItem, + { text: 'bar' }, + { text: 'baz' } + ]); this.render(`{{#each list as |item|}}{{item.text}}{{/each}}`); @@ -574,7 +590,12 @@ class EachTest extends AbstractEachTest { this.assertText('foofoobarbazfoofoo'); - this.replaceList([duplicateItem, duplicateItem, { text: 'bar' }, { text: 'baz' }]); + this.replaceList([ + duplicateItem, + duplicateItem, + { text: 'bar' }, + { text: 'baz' } + ]); this.assertText('foofoobarbaz'); } @@ -656,9 +677,12 @@ class EachTest extends AbstractEachTest { ['@test context is not changed to the inner scope inside an {{#each as}} block']() { this.makeList([{ name: 'Chad' }, { name: 'Zack' }, { name: 'Asa' }]); - this.render(`{{name}}-{{#each list as |person|}}{{name}}{{/each}}-{{name}}`, { - name: 'Joel' - }); + this.render( + `{{name}}-{{#each list as |person|}}{{name}}{{/each}}-{{name}}`, + { + name: 'Joel' + } + ); this.assertText('Joel-JoelJoelJoel-Joel'); @@ -679,17 +703,28 @@ class EachTest extends AbstractEachTest { } ['@test can access the item and the original scope']() { - this.makeList([{ name: 'Tom Dale' }, { name: 'Yehuda Katz' }, { name: 'Godfrey Chan' }]); - - this.render(`{{#each list key="name" as |person|}}[{{title}}: {{person.name}}]{{/each}}`, { - title: 'Señor Engineer' - }); + this.makeList([ + { name: 'Tom Dale' }, + { name: 'Yehuda Katz' }, + { name: 'Godfrey Chan' } + ]); + + this.render( + `{{#each list key="name" as |person|}}[{{title}}: {{person.name}}]{{/each}}`, + { + title: 'Señor Engineer' + } + ); - this.assertText('[Señor Engineer: Tom Dale][Señor Engineer: Yehuda Katz][Señor Engineer: Godfrey Chan]'); + this.assertText( + '[Señor Engineer: Tom Dale][Señor Engineer: Yehuda Katz][Señor Engineer: Godfrey Chan]' + ); this.runTask(() => this.rerender()); - this.assertText('[Señor Engineer: Tom Dale][Señor Engineer: Yehuda Katz][Señor Engineer: Godfrey Chan]'); + this.assertText( + '[Señor Engineer: Tom Dale][Señor Engineer: Yehuda Katz][Señor Engineer: Godfrey Chan]' + ); this.runTask(() => { set(this.objectAt(1), 'name', 'Stefan Penner'); @@ -699,12 +734,20 @@ class EachTest extends AbstractEachTest { set(this.context, 'title', 'Principal Engineer'); }); - this.assertText('[Principal Engineer: Stefan Penner][Principal Engineer: Chad Hietala][Principal Engineer: Godfrey Chan][Principal Engineer: Tom Dale]'); + this.assertText( + '[Principal Engineer: Stefan Penner][Principal Engineer: Chad Hietala][Principal Engineer: Godfrey Chan][Principal Engineer: Tom Dale]' + ); this.runTask(() => set(this.context, 'title', 'Señor Engineer')); - this.replaceList([{ name: 'Tom Dale' }, { name: 'Yehuda Katz' }, { name: 'Godfrey Chan' }]); + this.replaceList([ + { name: 'Tom Dale' }, + { name: 'Yehuda Katz' }, + { name: 'Godfrey Chan' } + ]); - this.assertText('[Señor Engineer: Tom Dale][Señor Engineer: Yehuda Katz][Señor Engineer: Godfrey Chan]'); + this.assertText( + '[Señor Engineer: Tom Dale][Señor Engineer: Yehuda Katz][Señor Engineer: Godfrey Chan]' + ); } ['@test the scoped variable is not available outside the {{#each}} block.']() { @@ -737,9 +780,12 @@ class EachTest extends AbstractEachTest { ['@test inverse template is displayed with context']() { this.makeList([]); - this.render(`{{#each list as |thing|}}Has Thing{{else}}No Thing {{otherThing}}{{/each}}`, { - otherThing: 'bar' - }); + this.render( + `{{#each list as |thing|}}Has Thing{{else}}No Thing {{otherThing}}{{/each}}`, + { + otherThing: 'bar' + } + ); this.assertText('No Thing bar'); @@ -775,7 +821,9 @@ class EachTest extends AbstractEachTest { this.makeList([]); - this.render(`{{#x-wrapper}}{{#each list as |obj|}}[{{obj.text}}]{{/each}}{{/x-wrapper}}`); + this.render( + `{{#x-wrapper}}{{#each list as |obj|}}[{{obj.text}}]{{/each}}{{/x-wrapper}}` + ); this.assertText(''); @@ -818,10 +866,13 @@ class EachTest extends AbstractEachTest { let admins = this.createList([{ name: 'Tom Dale' }]); let users = this.createList([{ name: 'Yehuda Katz' }]); - this.render(`Admin: {{#each admins key="name" as |person|}}[{{person.name}}]{{/each}} User: {{#each users key="name" as |person|}}[{{person.name}}]{{/each}}`, { - admins: admins.list, - users: users.list - }); + this.render( + `Admin: {{#each admins key="name" as |person|}}[{{person.name}}]{{/each}} User: {{#each users key="name" as |person|}}[{{person.name}}]{{/each}}`, + { + admins: admins.list, + users: users.list + } + ); this.assertText('Admin: [Tom Dale] User: [Yehuda Katz]'); @@ -838,7 +889,11 @@ class EachTest extends AbstractEachTest { this.runTask(() => { set(this.context, 'admins', this.createList([{ name: 'Tom Dale' }]).list); - set(this.context, 'users', this.createList([{ name: 'Yehuda Katz' }]).list); + set( + this.context, + 'users', + this.createList([{ name: 'Yehuda Katz' }]).list + ); }); this.assertText('Admin: [Tom Dale] User: [Yehuda Katz]'); @@ -846,19 +901,25 @@ class EachTest extends AbstractEachTest { [`@test an outer {{#each}}'s scoped variable does not clobber an inner {{#each}}'s property if they share the same name - Issue #1315`]() { let content = this.createList(['X', 'Y']); - let options = this.createList([{ label: 'One', value: 1 }, { label: 'Two', value: 2 }]); + let options = this.createList([ + { label: 'One', value: 1 }, + { label: 'Two', value: 2 } + ]); - this.render(strip` + this.render( + strip` {{#each content as |value|}} {{value}}- {{#each options as |option|}} {{option.value}}:{{option.label}} {{/each}} {{/each}} - `, { + `, + { content: content.list, options: options.list - }); + } + ); this.assertText('X-1:One2:TwoY-1:One2:Two'); @@ -873,7 +934,14 @@ class EachTest extends AbstractEachTest { this.runTask(() => { set(this.context, 'content', this.createList(['X', 'Y']).list); - set(this.context, 'options', this.createList([{ label: 'One', value: 1 }, { label: 'Two', value: 2 }]).list); + set( + this.context, + 'options', + this.createList([ + { label: 'One', value: 1 }, + { label: 'Two', value: 2 } + ]).list + ); }); this.assertText('X-1:One2:TwoY-1:One2:Two'); @@ -884,12 +952,15 @@ class EachTest extends AbstractEachTest { let fifth = this.createList(['Wrath']); let ninth = this.createList(['Treachery']); - this.render(`{{ring}}-{{#each first as |ring|}}{{ring}}-{{#each fifth as |ring|}}{{ring}}-{{#each ninth as |ring|}}{{ring}}-{{/each}}{{ring}}-{{/each}}{{ring}}-{{/each}}{{ring}}`, { - ring: 'Greed', - first: first.list, - fifth: fifth.list, - ninth: ninth.list - }); + this.render( + `{{ring}}-{{#each first as |ring|}}{{ring}}-{{#each fifth as |ring|}}{{ring}}-{{#each ninth as |ring|}}{{ring}}-{{/each}}{{ring}}-{{/each}}{{ring}}-{{/each}}{{ring}}`, + { + ring: 'Greed', + first: first.list, + fifth: fifth.list, + ninth: ninth.list + } + ); this.assertText('Greed-Limbo-Wrath-Treachery-Wrath-Limbo-Greed'); @@ -909,7 +980,9 @@ class EachTest extends AbstractEachTest { ninth.delegate.replace(0, 1, ['K']); }); - this.assertText('O-Limbo-D-K-D-Wrath-K-Wrath-Limbo-I-D-K-D-Wrath-K-Wrath-I-O'); + this.assertText( + 'O-Limbo-D-K-D-Wrath-K-Wrath-Limbo-I-D-K-D-Wrath-K-Wrath-I-O' + ); this.runTask(() => { set(this.context, 'ring', 'Greed'); @@ -925,9 +998,12 @@ class EachTest extends AbstractEachTest { let inner = this.createList(['caterpillar']); let outer = this.createList([inner.list]); - this.render(`{{#each name key="@index" as |foo|}}{{#each foo as |bar|}}{{bar}}{{/each}}{{/each}}`, { - name: outer.list - }); + this.render( + `{{#each name key="@index" as |foo|}}{{#each foo as |bar|}}{{bar}}{{/each}}{{/each}}`, + { + name: outer.list + } + ); this.assertText('caterpillar'); @@ -942,169 +1018,207 @@ class EachTest extends AbstractEachTest { this.assertText('ladybird'); - this.runTask(() => set(this.context, 'name', this.createList([this.createList(['caterpillar']).list]).list)); + this.runTask(() => + set( + this.context, + 'name', + this.createList([this.createList(['caterpillar']).list]).list + ) + ); this.assertText('caterpillar'); } } -moduleFor('Syntax test: {{#each}} with native arrays', class extends EachTest { - - createList(items) { - return { list: items, delegate: new ArrayDelegate(items, items) }; +moduleFor( + 'Syntax test: {{#each}} with native arrays', + class extends EachTest { + createList(items) { + return { list: items, delegate: new ArrayDelegate(items, items) }; + } } +); -}); - -moduleFor('Syntax test: {{#each}} with emberA-wrapped arrays', class extends EachTest { - - createList(items) { - let wrapped = emberA(items); - return { list: wrapped, delegate: wrapped }; +moduleFor( + 'Syntax test: {{#each}} with emberA-wrapped arrays', + class extends EachTest { + createList(items) { + let wrapped = emberA(items); + return { list: wrapped, delegate: wrapped }; + } } +); -}); - -moduleFor('Syntax test: {{#each}} with native Set', class extends EachTest { - - createList(items) { - let set = makeSet(items); - return { list: set, delegate: new SetDelegate(set) }; - } +moduleFor( + 'Syntax test: {{#each}} with native Set', + class extends EachTest { + createList(items) { + let set = makeSet(items); + return { list: set, delegate: new SetDelegate(set) }; + } - ['@test it can render duplicate primitive items'](assert) { - assert.ok(true, 'not supported by Set'); - } + ['@test it can render duplicate primitive items'](assert) { + assert.ok(true, 'not supported by Set'); + } - ['@test it can render duplicate objects'](assert) { - assert.ok(true, 'not supported by Set'); + ['@test it can render duplicate objects'](assert) { + assert.ok(true, 'not supported by Set'); + } } +); -}); - -moduleFor('Syntax test: {{#each}} with array-like objects implementing forEach', class extends EachTest { - - createList(items) { - let forEachable = new ForEachable(items); - return { list: forEachable, delegate: forEachable }; +moduleFor( + 'Syntax test: {{#each}} with array-like objects implementing forEach', + class extends EachTest { + createList(items) { + let forEachable = new ForEachable(items); + return { list: forEachable, delegate: forEachable }; + } } - -}); +); if (HAS_NATIVE_SYMBOL) { - moduleFor('Syntax test: {{#each}} with array-like objects implementing Symbol.iterator', class extends EachTest { - - createList(items) { - let iterable = new ArrayIterable(items); - return { list: iterable, delegate: iterable }; + moduleFor( + 'Syntax test: {{#each}} with array-like objects implementing Symbol.iterator', + class extends EachTest { + createList(items) { + let iterable = new ArrayIterable(items); + return { list: iterable, delegate: iterable }; + } } - - }); + ); } -moduleFor('Syntax test: {{#each}} with array proxies, modifying itself', class extends EachTest { - - createList(items) { - let proxty = ArrayProxy.create({ content: emberA(items) }); - return { list: proxty, delegate: proxty }; +moduleFor( + 'Syntax test: {{#each}} with array proxies, modifying itself', + class extends EachTest { + createList(items) { + let proxty = ArrayProxy.create({ content: emberA(items) }); + return { list: proxty, delegate: proxty }; + } } +); -}); - -moduleFor('Syntax test: {{#each}} with array proxies, replacing its content', class extends EachTest { - - createList(items) { - let wrapped = emberA(items); - return { list: wrapped, delegate: ArrayProxy.create({ content: wrapped }) }; +moduleFor( + 'Syntax test: {{#each}} with array proxies, replacing its content', + class extends EachTest { + createList(items) { + let wrapped = emberA(items); + return { + list: wrapped, + delegate: ArrayProxy.create({ content: wrapped }) + }; + } } +); -}); - -moduleFor('Syntax test: {{#each as}} undefined path', class extends RenderingTest { - ['@test keying off of `undefined` does not render']() { - this.render(strip` +moduleFor( + 'Syntax test: {{#each as}} undefined path', + class extends RenderingTest { + ['@test keying off of `undefined` does not render']() { + this.render( + strip` {{#each foo.bar.baz as |thing|}} {{thing}} - {{/each}}`, { foo: {} }); + {{/each}}`, + { foo: {} } + ); - this.assertText(''); + this.assertText(''); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText(''); + this.assertText(''); - this.runTask(() => set(this.context, 'foo', { bar: { baz: ['Here!'] } })); + this.runTask(() => set(this.context, 'foo', { bar: { baz: ['Here!'] } })); - this.assertText('Here!'); + this.assertText('Here!'); - this.runTask(() => set(this.context, 'foo', {})); + this.runTask(() => set(this.context, 'foo', {})); - this.assertText(''); + this.assertText(''); + } } -}); +); -moduleFor('Syntax test: {{#each}} with sparse arrays', class extends RenderingTest { - ['@test it should itterate over holes']() { - let sparseArray = []; - sparseArray[3] = 'foo'; - sparseArray[4] = 'bar'; +moduleFor( + 'Syntax test: {{#each}} with sparse arrays', + class extends RenderingTest { + ['@test it should itterate over holes']() { + let sparseArray = []; + sparseArray[3] = 'foo'; + sparseArray[4] = 'bar'; - this.render(strip` + this.render( + strip` {{#each list as |value key|}} [{{key}}:{{value}}] - {{/each}}`, { list: emberA(sparseArray) }); + {{/each}}`, + { list: emberA(sparseArray) } + ); - this.assertText('[0:][1:][2:][3:foo][4:bar]'); + this.assertText('[0:][1:][2:][3:foo][4:bar]'); - this.assertStableRerender(); + this.assertStableRerender(); - this.runTask(() => { - let list = get(this.context, 'list'); - list.pushObject('baz'); - }); + this.runTask(() => { + let list = get(this.context, 'list'); + list.pushObject('baz'); + }); - this.assertText('[0:][1:][2:][3:foo][4:bar][5:baz]'); + this.assertText('[0:][1:][2:][3:foo][4:bar][5:baz]'); + } } -}); +); /* globals MutationObserver: false */ if (typeof MutationObserver === 'function') { - moduleFor('Syntax test: {{#each as}} DOM mutation test', class extends RenderingTest { - constructor() { - super(); - this.observer = null; - } - - observe(element) { - let observer = this.observer = new MutationObserver(function() {}); - observer.observe(element, { childList: true, characterData: true }); - } + moduleFor( + 'Syntax test: {{#each as}} DOM mutation test', + class extends RenderingTest { + constructor() { + super(); + this.observer = null; + } - teardown() { - if (this.observer) { - this.observer.disconnect(); + observe(element) { + let observer = (this.observer = new MutationObserver(function() {})); + observer.observe(element, { childList: true, characterData: true }); } - super.teardown(); - } + teardown() { + if (this.observer) { + this.observer.disconnect(); + } - assertNoMutation() { - this.assert.deepEqual(this.observer.takeRecords(), [], 'Expected no mutations'); - } + super.teardown(); + } - expectMutations() { - this.assert.ok(this.observer.takeRecords().length > 0, 'Expected some mutations'); - } + assertNoMutation() { + this.assert.deepEqual( + this.observer.takeRecords(), + [], + 'Expected no mutations' + ); + } - ['@test {{#each}} should not mutate a subtree when the array has not changed [GH #14332]']() { - let page = { title: 'Blog Posts' }; + expectMutations() { + this.assert.ok( + this.observer.takeRecords().length > 0, + 'Expected some mutations' + ); + } - let model = [ - { title: 'Rails is omakase' }, - { title: 'Ember is omakase' } - ]; + ['@test {{#each}} should not mutate a subtree when the array has not changed [GH #14332]']() { + let page = { title: 'Blog Posts' }; - this.render(strip` + let model = [ + { title: 'Rails is omakase' }, + { title: 'Ember is omakase' } + ]; + + this.render( + strip`

{{page.title}}

    @@ -1112,9 +1226,11 @@ if (typeof MutationObserver === 'function') {
  • {{post.title}}
  • {{/each}}
- `, { page, model }); + `, + { page, model } + ); - this.assertHTML(strip` + this.assertHTML(strip`

Blog Posts

    @@ -1123,17 +1239,18 @@ if (typeof MutationObserver === 'function') {
`); - this.observe(this.$('#posts')[0]); + this.observe(this.$('#posts')[0]); - // MutationObserver is async - return RSVP.Promise.resolve(() => { - this.assertStableRerender(); - }).then(() => { - this.assertNoMutation(); + // MutationObserver is async + return RSVP.Promise.resolve(() => { + this.assertStableRerender(); + }) + .then(() => { + this.assertNoMutation(); - this.runTask(() => set(this.context, 'page', { title: 'Essays' })); + this.runTask(() => set(this.context, 'page', { title: 'Essays' })); - this.assertHTML(strip` + this.assertHTML(strip`

Essays

    @@ -1141,12 +1258,15 @@ if (typeof MutationObserver === 'function') {
  • Ember is omakase
`); - }).then(() => { - this.assertNoMutation(); + }) + .then(() => { + this.assertNoMutation(); - this.runTask(() => set(this.context.page, 'title', 'Think Pieces™')); + this.runTask(() => + set(this.context.page, 'title', 'Think Pieces™') + ); - this.assertHTML(strip` + this.assertHTML(strip`

Think Pieces™

    @@ -1154,11 +1274,13 @@ if (typeof MutationObserver === 'function') {
  • Ember is omakase
`); - }).then(() => { - // The last set is localized to the `page` object, so we do not expect Glimmer - // to re-iterate the list - this.assertNoMutation(); - }); + }) + .then(() => { + // The last set is localized to the `page` object, so we do not expect Glimmer + // to re-iterate the list + this.assertNoMutation(); + }); + } } - }); + ); } diff --git a/packages/ember-glimmer/tests/integration/syntax/experimental-syntax-test.js b/packages/ember-glimmer/tests/integration/syntax/experimental-syntax-test.js index 1cf132eb61c..1f5daacad7b 100644 --- a/packages/ember-glimmer/tests/integration/syntax/experimental-syntax-test.js +++ b/packages/ember-glimmer/tests/integration/syntax/experimental-syntax-test.js @@ -2,35 +2,41 @@ import { moduleFor, RenderingTest } from '../../utils/test-case'; import { strip } from '../../utils/abstract-test-case'; import { _registerMacros, _experimentalMacros } from 'ember-glimmer'; -moduleFor('registerMacros', class extends RenderingTest { - constructor() { - let originalMacros = _experimentalMacros.slice(); +moduleFor( + 'registerMacros', + class extends RenderingTest { + constructor() { + let originalMacros = _experimentalMacros.slice(); - _registerMacros(blocks => { - blocks.add('-let', (params, hash, _default, inverse, builder) => { - builder.compileParams(params); - builder.invokeStaticBlock(_default, params.length); + _registerMacros(blocks => { + blocks.add('-let', (params, hash, _default, inverse, builder) => { + builder.compileParams(params); + builder.invokeStaticBlock(_default, params.length); + }); }); - }); - super(); - this.originalMacros = originalMacros; - } + super(); + this.originalMacros = originalMacros; + } - teardown() { - _experimentalMacros.length = 0; - this.originalMacros.forEach(macro => _experimentalMacros.push(macro)); + teardown() { + _experimentalMacros.length = 0; + this.originalMacros.forEach(macro => _experimentalMacros.push(macro)); - super.teardown(); - } + super.teardown(); + } - ['@test allows registering custom syntax via private API']() { - this.render(strip` + ['@test allows registering custom syntax via private API']() { + this.render( + strip` {{#-let obj as |bar|}} {{bar}} {{/-let}} - `, { obj: 'hello world!'}); + `, + { obj: 'hello world!' } + ); - this.assertText('hello world!'); + this.assertText('hello world!'); + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/syntax/if-unless-test.js b/packages/ember-glimmer/tests/integration/syntax/if-unless-test.js index 58e21716ad9..90bf90d52c5 100644 --- a/packages/ember-glimmer/tests/integration/syntax/if-unless-test.js +++ b/packages/ember-glimmer/tests/integration/syntax/if-unless-test.js @@ -6,91 +6,107 @@ import { strip } from '../../utils/abstract-test-case'; import { RenderingTest, moduleFor } from '../../utils/test-case'; import { IfUnlessWithSyntaxTest } from '../../utils/shared-conditional-tests'; -moduleFor('Syntax test: {{#if}} with inverse', class extends IfUnlessWithSyntaxTest { - - templateFor({ cond, truthy, falsy }) { - return `{{#if ${cond}}}${truthy}{{else}}${falsy}{{/if}}`; +moduleFor( + 'Syntax test: {{#if}} with inverse', + class extends IfUnlessWithSyntaxTest { + templateFor({ cond, truthy, falsy }) { + return `{{#if ${cond}}}${truthy}{{else}}${falsy}{{/if}}`; + } } - -}); - -moduleFor('Syntax test: {{#unless}} with inverse', class extends IfUnlessWithSyntaxTest { - - templateFor({ cond, truthy, falsy }) { - return `{{#unless ${cond}}}${falsy}{{else}}${truthy}{{/unless}}`; +); + +moduleFor( + 'Syntax test: {{#unless}} with inverse', + class extends IfUnlessWithSyntaxTest { + templateFor({ cond, truthy, falsy }) { + return `{{#unless ${cond}}}${falsy}{{else}}${truthy}{{/unless}}`; + } } - -}); - -moduleFor('Syntax test: {{#if}} and {{#unless}} without inverse', class extends IfUnlessWithSyntaxTest { - - templateFor({ cond, truthy, falsy }) { - return `{{#if ${cond}}}${truthy}{{/if}}{{#unless ${cond}}}${falsy}{{/unless}}`; +); + +moduleFor( + 'Syntax test: {{#if}} and {{#unless}} without inverse', + class extends IfUnlessWithSyntaxTest { + templateFor({ cond, truthy, falsy }) { + return `{{#if ${cond}}}${truthy}{{/if}}{{#unless ${cond}}}${falsy}{{/unless}}`; + } } - -}); - -moduleFor('Syntax test: {{#if}}', class extends RenderingTest { - - ['@test using `if` with an `{{each}}` destroys components when transitioning to and from inverse (GH #12267)'](assert) { - let destroyedChildrenCount = 0; - - this.registerComponent('foo-bar', { - template: '{{number}}', - ComponentClass: Component.extend({ - willDestroy() { - this._super(); - destroyedChildrenCount++; - } - }) - }); - - this.render(strip` +); + +moduleFor( + 'Syntax test: {{#if}}', + class extends RenderingTest { + ['@test using `if` with an `{{each}}` destroys components when transitioning to and from inverse (GH #12267)']( + assert + ) { + let destroyedChildrenCount = 0; + + this.registerComponent('foo-bar', { + template: '{{number}}', + ComponentClass: Component.extend({ + willDestroy() { + this._super(); + destroyedChildrenCount++; + } + }) + }); + + this.render( + strip` {{#if cond}} {{#each numbers as |number|}} {{foo-bar number=number}} {{/each}} {{else}} Nothing Here! - {{/if}}`, { cond: true, numbers: emberA([1, 2, 3]) }); + {{/if}}`, + { cond: true, numbers: emberA([1, 2, 3]) } + ); - this.assertText('123'); + this.assertText('123'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('123'); + this.assertText('123'); - this.runTask(() => set(this.context, 'cond', false)); + this.runTask(() => set(this.context, 'cond', false)); - this.assertText('Nothing Here!'); - assert.equal(destroyedChildrenCount, 3, 'the children were properly destroyed'); + this.assertText('Nothing Here!'); + assert.equal( + destroyedChildrenCount, + 3, + 'the children were properly destroyed' + ); - this.runTask(() => set(this.context, 'cond', true)); + this.runTask(() => set(this.context, 'cond', true)); - this.assertText('123'); - } + this.assertText('123'); + } - ['@test looking up `undefined` property defaults to false']() { - this.render(strip` + ['@test looking up `undefined` property defaults to false']() { + this.render( + strip` {{#if foo.bar.baz}} Here! {{else}} Nothing Here! - {{/if}}`, { foo: {} }); + {{/if}}`, + { foo: {} } + ); - this.assertText('Nothing Here!'); + this.assertText('Nothing Here!'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Nothing Here!'); + this.assertText('Nothing Here!'); - this.runTask(() => set(this.context, 'foo', { bar: { baz: true } })); + this.runTask(() => set(this.context, 'foo', { bar: { baz: true } })); - this.assertText('Here!'); + this.assertText('Here!'); - this.runTask(() => set(this.context, 'foo', {})); + this.runTask(() => set(this.context, 'foo', {})); - this.assertText('Nothing Here!'); + this.assertText('Nothing Here!'); + } } - -}); +); diff --git a/packages/ember-glimmer/tests/integration/syntax/in-element-test.js b/packages/ember-glimmer/tests/integration/syntax/in-element-test.js index 4399427ba9d..cf166490d2a 100644 --- a/packages/ember-glimmer/tests/integration/syntax/in-element-test.js +++ b/packages/ember-glimmer/tests/integration/syntax/in-element-test.js @@ -4,101 +4,116 @@ import { strip } from '../../utils/abstract-test-case'; import { Component } from 'ember-glimmer'; import { set } from 'ember-metal'; -moduleFor('{{-in-element}}', class extends RenderingTest { - ['@test using {{#in-element whatever}} asserts']() { - // the in-element keyword is not yet public API this test should be removed - // once https://github.com/emberjs/rfcs/pull/287 lands and is enabled - - let el = document.createElement('div'); - expectAssertion(() => { - this.render(strip`{{#in-element el}}{{/in-element}}`, { el }); - }, /The {{in-element}} helper cannot be used. \('-top-level' @ L1:C0\)/); - } - - ['@test allows rendering into an external element']() { - let someElement = document.createElement('div'); - - this.render(strip` +moduleFor( + '{{-in-element}}', + class extends RenderingTest { + ['@test using {{#in-element whatever}} asserts']() { + // the in-element keyword is not yet public API this test should be removed + // once https://github.com/emberjs/rfcs/pull/287 lands and is enabled + + let el = document.createElement('div'); + expectAssertion(() => { + this.render(strip`{{#in-element el}}{{/in-element}}`, { el }); + }, /The {{in-element}} helper cannot be used. \('-top-level' @ L1:C0\)/); + } + + ['@test allows rendering into an external element']() { + let someElement = document.createElement('div'); + + this.render( + strip` {{#-in-element someElement}} {{text}} {{/-in-element}} - `, { - someElement, - text: 'Whoop!' - }); + `, + { + someElement, + text: 'Whoop!' + } + ); - equalTokens(this.element, ''); - equalTokens(someElement, 'Whoop!'); + equalTokens(this.element, ''); + equalTokens(someElement, 'Whoop!'); - this.assertStableRerender(); + this.assertStableRerender(); - this.runTask(() => set(this.context, 'text', 'Huzzah!!')); + this.runTask(() => set(this.context, 'text', 'Huzzah!!')); - equalTokens(this.element, ''); - equalTokens(someElement, 'Huzzah!!'); + equalTokens(this.element, ''); + equalTokens(someElement, 'Huzzah!!'); - this.runTask(() => set(this.context, 'text', 'Whoop!')); + this.runTask(() => set(this.context, 'text', 'Whoop!')); - equalTokens(this.element, ''); - equalTokens(someElement, 'Whoop!'); - } + equalTokens(this.element, ''); + equalTokens(someElement, 'Whoop!'); + } - ['@test components are cleaned up properly'](assert) { - let hooks = [ ]; + ['@test components are cleaned up properly'](assert) { + let hooks = []; - let someElement = document.createElement('div'); + let someElement = document.createElement('div'); - this.registerComponent('modal-display', { - ComponentClass: Component.extend({ - didInsertElement() { - hooks.push('didInsertElement'); - }, + this.registerComponent('modal-display', { + ComponentClass: Component.extend({ + didInsertElement() { + hooks.push('didInsertElement'); + }, - willDestroyElement() { - hooks.push('willDestroyElement'); - } - }), + willDestroyElement() { + hooks.push('willDestroyElement'); + } + }), - template: `{{text}}` - }); + template: `{{text}}` + }); - this.render(strip` + this.render( + strip` {{#if showModal}} {{#-in-element someElement}} {{modal-display text=text}} {{/-in-element}} {{/if}} - `, { - someElement, - text: 'Whoop!', - showModal: false - }); + `, + { + someElement, + text: 'Whoop!', + showModal: false + } + ); - equalTokens(this.element, ''); - equalTokens(someElement, ''); + equalTokens(this.element, ''); + equalTokens(someElement, ''); - this.assertStableRerender(); + this.assertStableRerender(); - this.runTask(() => set(this.context, 'showModal', true)); + this.runTask(() => set(this.context, 'showModal', true)); - equalTokens(this.element, ''); - this.assertComponentElement(someElement.firstChild, { content: 'Whoop!' }); + equalTokens(this.element, ''); + this.assertComponentElement(someElement.firstChild, { + content: 'Whoop!' + }); - this.runTask(() => set(this.context, 'text', 'Huzzah!')); + this.runTask(() => set(this.context, 'text', 'Huzzah!')); - equalTokens(this.element, ''); - this.assertComponentElement(someElement.firstChild, { content: 'Huzzah!' }); + equalTokens(this.element, ''); + this.assertComponentElement(someElement.firstChild, { + content: 'Huzzah!' + }); - this.runTask(() => set(this.context, 'text', 'Whoop!')); + this.runTask(() => set(this.context, 'text', 'Whoop!')); - equalTokens(this.element, ''); - this.assertComponentElement(someElement.firstChild, { content: 'Whoop!' }); + equalTokens(this.element, ''); + this.assertComponentElement(someElement.firstChild, { + content: 'Whoop!' + }); - this.runTask(() => set(this.context, 'showModal', false)); + this.runTask(() => set(this.context, 'showModal', false)); - equalTokens(this.element, ''); - equalTokens(someElement, ''); + equalTokens(this.element, ''); + equalTokens(someElement, ''); - assert.deepEqual(hooks, ['didInsertElement', 'willDestroyElement']); + assert.deepEqual(hooks, ['didInsertElement', 'willDestroyElement']); + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/syntax/let-test.js b/packages/ember-glimmer/tests/integration/syntax/let-test.js index e0a4a5a76c8..911a0a99a94 100644 --- a/packages/ember-glimmer/tests/integration/syntax/let-test.js +++ b/packages/ember-glimmer/tests/integration/syntax/let-test.js @@ -5,311 +5,353 @@ import { strip } from '../../utils/abstract-test-case'; import { EMBER_TEMPLATE_BLOCK_LET_HELPER } from 'ember/features'; if (EMBER_TEMPLATE_BLOCK_LET_HELPER) { - moduleFor('Syntax test: {{#let as}}', class extends RenderingTest { - - templateFor({ cond, truthy, falsy }) { - return `{{#let ${cond} as |test|}}${truthy}{{else}}${falsy}{{/let}}`; - } - - ['@test it renders the block if `undefined` is passed as an argument']() { - this.render(strip` + moduleFor( + 'Syntax test: {{#let as}}', + class extends RenderingTest { + templateFor({ cond, truthy, falsy }) { + return `{{#let ${cond} as |test|}}${truthy}{{else}}${falsy}{{/let}}`; + } + + ['@test it renders the block if `undefined` is passed as an argument']() { + this.render( + strip` {{#let foo.bar.baz as |thing|}} value: "{{thing}}" - {{/let}}`, { foo: {} }); + {{/let}}`, + { foo: {} } + ); - this.assertText('value: ""'); + this.assertText('value: ""'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('value: ""'); + this.assertText('value: ""'); - this.runTask(() => set(this.context, 'foo', { bar: { baz: 'Here!' } })); + this.runTask(() => set(this.context, 'foo', { bar: { baz: 'Here!' } })); - this.assertText('value: "Here!"'); + this.assertText('value: "Here!"'); - this.runTask(() => set(this.context, 'foo', {})); + this.runTask(() => set(this.context, 'foo', {})); - this.assertText('value: ""'); - } + this.assertText('value: ""'); + } - ['@test it renders the block if arguments are falsey']() { - this.render(`{{#let cond1 cond2 as |cond|}}value: "{{cond1}}"{{/let}}`, { - cond1: false - }); + ['@test it renders the block if arguments are falsey']() { + this.render( + `{{#let cond1 cond2 as |cond|}}value: "{{cond1}}"{{/let}}`, + { + cond1: false + } + ); - this.assertText('value: "false"'); + this.assertText('value: "false"'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('value: "false"'); + this.assertText('value: "false"'); - this.runTask(() => set(this.context, 'cond1', '')); + this.runTask(() => set(this.context, 'cond1', '')); - this.assertText('value: ""'); + this.assertText('value: ""'); - this.runTask(() => set(this.context, 'cond1', 0)); + this.runTask(() => set(this.context, 'cond1', 0)); - this.assertText('value: "0"'); - } + this.assertText('value: "0"'); + } - ['@test it yields multiple arguments in order']() { - this.render(`{{#let foo bar baz.name as |a b c|}}{{a}} {{b}} {{c}}{{/let}}`, { - foo: "Señor Engineer", - bar: '', - baz: { name: "Dale" } - }); + ['@test it yields multiple arguments in order']() { + this.render( + `{{#let foo bar baz.name as |a b c|}}{{a}} {{b}} {{c}}{{/let}}`, + { + foo: 'Señor Engineer', + bar: '', + baz: { name: 'Dale' } + } + ); - this.assertText('Señor Engineer Dale'); + this.assertText('Señor Engineer Dale'); - this.runTask(() => set(this.context, 'bar', 'Tom')); + this.runTask(() => set(this.context, 'bar', 'Tom')); - this.assertText('Señor Engineer Tom Dale'); - } + this.assertText('Señor Engineer Tom Dale'); + } - ['@test can access alias and original scope']() { - this.render(`{{#let person as |tom|}}{{title}}: {{tom.name}}{{/let}}`, { - title: 'Señor Engineer', - person: { name: 'Tom Dale' } - }); + ['@test can access alias and original scope']() { + this.render(`{{#let person as |tom|}}{{title}}: {{tom.name}}{{/let}}`, { + title: 'Señor Engineer', + person: { name: 'Tom Dale' } + }); - this.assertText('Señor Engineer: Tom Dale'); + this.assertText('Señor Engineer: Tom Dale'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Señor Engineer: Tom Dale'); + this.assertText('Señor Engineer: Tom Dale'); - this.runTask(() => { - set(this.context, 'person.name', 'Yehuda Katz'); - set(this.context, 'title', 'Principal Engineer'); - }); + this.runTask(() => { + set(this.context, 'person.name', 'Yehuda Katz'); + set(this.context, 'title', 'Principal Engineer'); + }); - this.assertText('Principal Engineer: Yehuda Katz'); + this.assertText('Principal Engineer: Yehuda Katz'); - this.runTask(() => { - set(this.context, 'person', { name: 'Tom Dale' }); - set(this.context, 'title', 'Señor Engineer'); - }); + this.runTask(() => { + set(this.context, 'person', { name: 'Tom Dale' }); + set(this.context, 'title', 'Señor Engineer'); + }); - this.assertText('Señor Engineer: Tom Dale'); - } + this.assertText('Señor Engineer: Tom Dale'); + } - ['@test the scoped variable is not available outside the {{#let}} block.']() { - this.render(`{{name}}-{{#let other as |name|}}{{name}}{{/let}}-{{name}}`, { - name: 'Stef', - other: 'Yehuda' - }); + ['@test the scoped variable is not available outside the {{#let}} block.']() { + this.render( + `{{name}}-{{#let other as |name|}}{{name}}{{/let}}-{{name}}`, + { + name: 'Stef', + other: 'Yehuda' + } + ); - this.assertText('Stef-Yehuda-Stef'); + this.assertText('Stef-Yehuda-Stef'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Stef-Yehuda-Stef'); + this.assertText('Stef-Yehuda-Stef'); - this.runTask(() => set(this.context, 'other', 'Chad')); + this.runTask(() => set(this.context, 'other', 'Chad')); - this.assertText('Stef-Chad-Stef'); + this.assertText('Stef-Chad-Stef'); - this.runTask(() => set(this.context, 'name', 'Tom')); + this.runTask(() => set(this.context, 'name', 'Tom')); - this.assertText('Tom-Chad-Tom'); + this.assertText('Tom-Chad-Tom'); - this.runTask(() => { - set(this.context, 'name', 'Stef'); - set(this.context, 'other', 'Yehuda'); - }); + this.runTask(() => { + set(this.context, 'name', 'Stef'); + set(this.context, 'other', 'Yehuda'); + }); - this.assertText('Stef-Yehuda-Stef'); - } + this.assertText('Stef-Yehuda-Stef'); + } - ['@test can access alias of a proxy']() { - this.render(`{{#let proxy as |person|}}{{person.name}}{{/let}}`, { - proxy: ObjectProxy.create({ content: { name: 'Tom Dale' } }) - }); + ['@test can access alias of a proxy']() { + this.render(`{{#let proxy as |person|}}{{person.name}}{{/let}}`, { + proxy: ObjectProxy.create({ content: { name: 'Tom Dale' } }) + }); - this.assertText('Tom Dale'); + this.assertText('Tom Dale'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Tom Dale'); + this.assertText('Tom Dale'); - this.runTask(() => set(this.context, 'proxy.name', 'Yehuda Katz')); + this.runTask(() => set(this.context, 'proxy.name', 'Yehuda Katz')); - this.assertText('Yehuda Katz'); + this.assertText('Yehuda Katz'); - this.runTask(() => set(this.context, 'proxy.content', { name: 'Godfrey Chan' })); + this.runTask(() => + set(this.context, 'proxy.content', { name: 'Godfrey Chan' }) + ); - this.assertText('Godfrey Chan'); + this.assertText('Godfrey Chan'); - this.runTask(() => set(this.context, 'proxy.content.name', 'Stefan Penner')); + this.runTask(() => + set(this.context, 'proxy.content.name', 'Stefan Penner') + ); - this.assertText('Stefan Penner'); + this.assertText('Stefan Penner'); - this.runTask(() => set(this.context, 'proxy.content', null)); + this.runTask(() => set(this.context, 'proxy.content', null)); - this.assertText(''); + this.assertText(''); - this.runTask(() => set(this.context, 'proxy', ObjectProxy.create({ content: { name: 'Tom Dale' } }))); + this.runTask(() => + set( + this.context, + 'proxy', + ObjectProxy.create({ content: { name: 'Tom Dale' } }) + ) + ); - this.assertText('Tom Dale'); - } + this.assertText('Tom Dale'); + } - ['@test can access alias of an array']() { - this.render(`{{#let arrayThing as |words|}}{{#each words as |word|}}{{word}}{{/each}}{{/let}}`, { - arrayThing: emberA(['Hello', ' ', 'world']) - }); + ['@test can access alias of an array']() { + this.render( + `{{#let arrayThing as |words|}}{{#each words as |word|}}{{word}}{{/each}}{{/let}}`, + { + arrayThing: emberA(['Hello', ' ', 'world']) + } + ); - this.assertText('Hello world'); + this.assertText('Hello world'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Hello world'); + this.assertText('Hello world'); - this.runTask(() => { - let array = get(this.context, 'arrayThing'); - array.replace(0, 1, ['Goodbye']); - removeAt(array, 1); - array.insertAt(1, ', '); - array.pushObject('!'); - }); + this.runTask(() => { + let array = get(this.context, 'arrayThing'); + array.replace(0, 1, ['Goodbye']); + removeAt(array, 1); + array.insertAt(1, ', '); + array.pushObject('!'); + }); - this.assertText('Goodbye, world!'); + this.assertText('Goodbye, world!'); - this.runTask(() => set(this.context, 'arrayThing', ['Hello', ' ', 'world'])); + this.runTask(() => + set(this.context, 'arrayThing', ['Hello', ' ', 'world']) + ); - this.assertText('Hello world'); - } + this.assertText('Hello world'); + } - ['@test `attrs` can be used as a block param [GH#14678]']() { - this.render('{{#let hash as |attrs|}}[{{hash.foo}}-{{attrs.foo}}]{{/let}}', { - hash: { foo: 'foo' } - }); + ['@test `attrs` can be used as a block param [GH#14678]']() { + this.render( + '{{#let hash as |attrs|}}[{{hash.foo}}-{{attrs.foo}}]{{/let}}', + { + hash: { foo: 'foo' } + } + ); - this.assertText('[foo-foo]'); + this.assertText('[foo-foo]'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('[foo-foo]'); + this.assertText('[foo-foo]'); - this.runTask(() => this.context.set('hash.foo', 'FOO')); + this.runTask(() => this.context.set('hash.foo', 'FOO')); - this.assertText('[FOO-FOO]'); + this.assertText('[FOO-FOO]'); - this.runTask(() => this.context.set('hash.foo', 'foo')); + this.runTask(() => this.context.set('hash.foo', 'foo')); - this.assertText('[foo-foo]'); + this.assertText('[foo-foo]'); + } } + ); - }); + moduleFor( + 'Syntax test: Multiple {{#let as}} helpers', + class extends RenderingTest { + ['@test re-using the same variable with different {{#let}} blocks does not override each other']() { + this.render( + `Admin: {{#let admin as |person|}}{{person.name}}{{/let}} User: {{#let user as |person|}}{{person.name}}{{/let}}`, + { + admin: { name: 'Tom Dale' }, + user: { name: 'Yehuda Katz' } + } + ); - moduleFor('Syntax test: Multiple {{#let as}} helpers', class extends RenderingTest { + this.assertText('Admin: Tom Dale User: Yehuda Katz'); - ['@test re-using the same variable with different {{#let}} blocks does not override each other']() { - this.render(`Admin: {{#let admin as |person|}}{{person.name}}{{/let}} User: {{#let user as |person|}}{{person.name}}{{/let}}`, { - admin: { name: 'Tom Dale' }, - user: { name: 'Yehuda Katz' } - }); + this.runTask(() => this.rerender()); - this.assertText('Admin: Tom Dale User: Yehuda Katz'); + this.assertText('Admin: Tom Dale User: Yehuda Katz'); - this.runTask(() => this.rerender()); + this.runTask(() => { + set(this.context, 'admin.name', 'Godfrey Chan'); + set(this.context, 'user.name', 'Stefan Penner'); + }); - this.assertText('Admin: Tom Dale User: Yehuda Katz'); + this.assertText('Admin: Godfrey Chan User: Stefan Penner'); - this.runTask(() => { - set(this.context, 'admin.name', 'Godfrey Chan'); - set(this.context, 'user.name', 'Stefan Penner'); - }); + this.runTask(() => { + set(this.context, 'admin', { name: 'Tom Dale' }); + set(this.context, 'user', { name: 'Yehuda Katz' }); + }); - this.assertText('Admin: Godfrey Chan User: Stefan Penner'); + this.assertText('Admin: Tom Dale User: Yehuda Katz'); + } - this.runTask(() => { - set(this.context, 'admin', { name: 'Tom Dale' }); - set(this.context, 'user', { name: 'Yehuda Katz' }); - }); + ['@test the scoped variable is not available outside the {{#let}} block']() { + this.render( + `{{ring}}-{{#let first as |ring|}}{{ring}}-{{#let fifth as |ring|}}{{ring}}-{{#let ninth as |ring|}}{{ring}}-{{/let}}{{ring}}-{{/let}}{{ring}}-{{/let}}{{ring}}`, + { + ring: 'Greed', + first: 'Limbo', + fifth: 'Wrath', + ninth: 'Treachery' + } + ); - this.assertText('Admin: Tom Dale User: Yehuda Katz'); - } + this.assertText('Greed-Limbo-Wrath-Treachery-Wrath-Limbo-Greed'); - ['@test the scoped variable is not available outside the {{#let}} block']() { - this.render(`{{ring}}-{{#let first as |ring|}}{{ring}}-{{#let fifth as |ring|}}{{ring}}-{{#let ninth as |ring|}}{{ring}}-{{/let}}{{ring}}-{{/let}}{{ring}}-{{/let}}{{ring}}`, { - ring: 'Greed', - first: 'Limbo', - fifth: 'Wrath', - ninth: 'Treachery' - }); + this.runTask(() => this.rerender()); - this.assertText('Greed-Limbo-Wrath-Treachery-Wrath-Limbo-Greed'); + this.assertText('Greed-Limbo-Wrath-Treachery-Wrath-Limbo-Greed'); - this.runTask(() => this.rerender()); + this.runTask(() => { + set(this.context, 'ring', 'O'); + set(this.context, 'fifth', 'D'); + }); - this.assertText('Greed-Limbo-Wrath-Treachery-Wrath-Limbo-Greed'); + this.assertText('O-Limbo-D-Treachery-D-Limbo-O'); - this.runTask(() => { - set(this.context, 'ring', 'O'); - set(this.context, 'fifth', 'D'); - }); + this.runTask(() => { + set(this.context, 'first', 'I'); + set(this.context, 'ninth', 'K'); + }); - this.assertText('O-Limbo-D-Treachery-D-Limbo-O'); + this.assertText('O-I-D-K-D-I-O'); - this.runTask(() => { - set(this.context, 'first', 'I'); - set(this.context, 'ninth', 'K'); - }); + this.runTask(() => { + set(this.context, 'ring', 'Greed'); + set(this.context, 'first', 'Limbo'); + set(this.context, 'fifth', 'Wrath'); + set(this.context, 'ninth', 'Treachery'); + }); - this.assertText('O-I-D-K-D-I-O'); - - this.runTask(() => { - set(this.context, 'ring', 'Greed'); - set(this.context, 'first', 'Limbo'); - set(this.context, 'fifth', 'Wrath'); - set(this.context, 'ninth', 'Treachery'); - }); - - this.assertText('Greed-Limbo-Wrath-Treachery-Wrath-Limbo-Greed'); - } + this.assertText('Greed-Limbo-Wrath-Treachery-Wrath-Limbo-Greed'); + } - ['@test it should support {{#let name as |foo|}}, then {{#let foo as |bar|}}']() { - this.render(`{{#let name as |foo|}}{{#let foo as |bar|}}{{bar}}{{/let}}{{/let}}`, { - name: 'caterpillar' - }); + ['@test it should support {{#let name as |foo|}}, then {{#let foo as |bar|}}']() { + this.render( + `{{#let name as |foo|}}{{#let foo as |bar|}}{{bar}}{{/let}}{{/let}}`, + { + name: 'caterpillar' + } + ); - this.assertText('caterpillar'); + this.assertText('caterpillar'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('caterpillar'); + this.assertText('caterpillar'); - this.runTask(() => set(this.context, 'name', 'butterfly')); + this.runTask(() => set(this.context, 'name', 'butterfly')); - this.assertText('butterfly'); + this.assertText('butterfly'); - this.runTask(() => set(this.context, 'name', 'caterpillar')); + this.runTask(() => set(this.context, 'name', 'caterpillar')); - this.assertText('caterpillar'); - } + this.assertText('caterpillar'); + } - ['@test updating the context should update the alias']() { - this.render(`{{#let this as |person|}}{{person.name}}{{/let}}`, { - name: 'Los Pivots' - }); + ['@test updating the context should update the alias']() { + this.render(`{{#let this as |person|}}{{person.name}}{{/let}}`, { + name: 'Los Pivots' + }); - this.assertText('Los Pivots'); + this.assertText('Los Pivots'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Los Pivots'); + this.assertText('Los Pivots'); - this.runTask(() => set(this.context, 'name', 'l\'Pivots')); + this.runTask(() => set(this.context, 'name', "l'Pivots")); - this.assertText('l\'Pivots'); + this.assertText("l'Pivots"); - this.runTask(() => set(this.context, 'name', 'Los Pivots')); + this.runTask(() => set(this.context, 'name', 'Los Pivots')); - this.assertText('Los Pivots'); - } + this.assertText('Los Pivots'); + } - ['@test nested {{#let}} blocks should have access to root context']() { - this.render(strip` + ['@test nested {{#let}} blocks should have access to root context']() { + this.render( + strip` {{name}} {{#let committer1.name as |name|}} [{{name}} @@ -327,41 +369,57 @@ if (EMBER_TEMPLATE_BLOCK_LET_HELPER) { {{name}}] {{/let}} {{name}} - `, { - name: 'ebryn', - committer1: { name: 'trek' }, - committer2: { name: 'machty' } - }); - - this.assertText('ebryn[trek[machty]trek]ebryn[machty[trek]machty]ebryn'); - - this.runTask(() => this.rerender()); - - this.assertText('ebryn[trek[machty]trek]ebryn[machty[trek]machty]ebryn'); - - this.runTask(() => set(this.context, 'name', 'chancancode')); - - this.assertText('chancancode[trek[machty]trek]chancancode[machty[trek]machty]chancancode'); - - this.runTask(() => set(this.context, 'committer1', { name: 'krisselden' })); - - this.assertText('chancancode[krisselden[machty]krisselden]chancancode[machty[krisselden]machty]chancancode'); - - this.runTask(() => { - set(this.context, 'committer1.name', 'wycats'); - set(this.context, 'committer2', { name: 'rwjblue' }); - }); - - this.assertText('chancancode[wycats[rwjblue]wycats]chancancode[rwjblue[wycats]rwjblue]chancancode'); - - this.runTask(() => { - set(this.context, 'name', 'ebryn'); - set(this.context, 'committer1', { name: 'trek' }); - set(this.context, 'committer2', { name: 'machty' }); - }); - - this.assertText('ebryn[trek[machty]trek]ebryn[machty[trek]machty]ebryn'); + `, + { + name: 'ebryn', + committer1: { name: 'trek' }, + committer2: { name: 'machty' } + } + ); + + this.assertText( + 'ebryn[trek[machty]trek]ebryn[machty[trek]machty]ebryn' + ); + + this.runTask(() => this.rerender()); + + this.assertText( + 'ebryn[trek[machty]trek]ebryn[machty[trek]machty]ebryn' + ); + + this.runTask(() => set(this.context, 'name', 'chancancode')); + + this.assertText( + 'chancancode[trek[machty]trek]chancancode[machty[trek]machty]chancancode' + ); + + this.runTask(() => + set(this.context, 'committer1', { name: 'krisselden' }) + ); + + this.assertText( + 'chancancode[krisselden[machty]krisselden]chancancode[machty[krisselden]machty]chancancode' + ); + + this.runTask(() => { + set(this.context, 'committer1.name', 'wycats'); + set(this.context, 'committer2', { name: 'rwjblue' }); + }); + + this.assertText( + 'chancancode[wycats[rwjblue]wycats]chancancode[rwjblue[wycats]rwjblue]chancancode' + ); + + this.runTask(() => { + set(this.context, 'name', 'ebryn'); + set(this.context, 'committer1', { name: 'trek' }); + set(this.context, 'committer2', { name: 'machty' }); + }); + + this.assertText( + 'ebryn[trek[machty]trek]ebryn[machty[trek]machty]ebryn' + ); + } } - - }); + ); } diff --git a/packages/ember-glimmer/tests/integration/syntax/with-dynamic-var-test.js b/packages/ember-glimmer/tests/integration/syntax/with-dynamic-var-test.js index 2a9c2edfe48..3da84c80a1e 100644 --- a/packages/ember-glimmer/tests/integration/syntax/with-dynamic-var-test.js +++ b/packages/ember-glimmer/tests/integration/syntax/with-dynamic-var-test.js @@ -1,33 +1,36 @@ import { moduleFor, RenderingTest } from '../../utils/test-case'; import { strip } from '../../utils/abstract-test-case'; -moduleFor('{{-with-dynamic-var}}', class extends RenderingTest { - ['@test does not allow setting values other than outletState']() { - expectAssertion(() => { - this.render(strip` +moduleFor( + '{{-with-dynamic-var}}', + class extends RenderingTest { + ['@test does not allow setting values other than outletState']() { + expectAssertion(() => { + this.render(strip` {{#-with-dynamic-vars foo="bar"}} {{-get-dynamic-var 'foo'}} {{/-with-dynamic-vars}} `); - }, /Using `-with-dynamic-scope` is only supported for `outletState` \(you used `foo`\)./); - } + }, /Using `-with-dynamic-scope` is only supported for `outletState` \(you used `foo`\)./); + } - ['@test allows setting/getting outletState']() { - // this is simply asserting that we can write and read outletState - // the actual value being used here is not what is used in real life - // feel free to change the value being set and asserted as needed - this.render(strip` + ['@test allows setting/getting outletState']() { + // this is simply asserting that we can write and read outletState + // the actual value being used here is not what is used in real life + // feel free to change the value being set and asserted as needed + this.render(strip` {{#-with-dynamic-vars outletState="bar"}} {{-get-dynamic-var 'outletState'}} {{/-with-dynamic-vars}} `); - this.assertText('bar'); - } + this.assertText('bar'); + } - ['@test does not allow setting values other than outletState']() { - expectAssertion(() => { - this.render(`{{-get-dynamic-var 'foo'}}`); - }, /Using `-get-dynamic-scope` is only supported for `outletState` \(you used `foo`\)./); + ['@test does not allow setting values other than outletState']() { + expectAssertion(() => { + this.render(`{{-get-dynamic-var 'foo'}}`); + }, /Using `-get-dynamic-scope` is only supported for `outletState` \(you used `foo`\)./); + } } -}); +); diff --git a/packages/ember-glimmer/tests/integration/syntax/with-test.js b/packages/ember-glimmer/tests/integration/syntax/with-test.js index 5bed410483f..d72d92dd011 100644 --- a/packages/ember-glimmer/tests/integration/syntax/with-test.js +++ b/packages/ember-glimmer/tests/integration/syntax/with-test.js @@ -4,341 +4,384 @@ import { moduleFor, RenderingTest } from '../../utils/test-case'; import { IfUnlessWithSyntaxTest } from '../../utils/shared-conditional-tests'; import { strip } from '../../utils/abstract-test-case'; -moduleFor('Syntax test: {{#with}}', class extends IfUnlessWithSyntaxTest { - - templateFor({ cond, truthy, falsy }) { - return `{{#with ${cond}}}${truthy}{{else}}${falsy}{{/with}}`; - } - -}); - -moduleFor('Syntax test: {{#with as}}', class extends IfUnlessWithSyntaxTest { - - templateFor({ cond, truthy, falsy }) { - return `{{#with ${cond} as |test|}}${truthy}{{else}}${falsy}{{/with}}`; +moduleFor( + 'Syntax test: {{#with}}', + class extends IfUnlessWithSyntaxTest { + templateFor({ cond, truthy, falsy }) { + return `{{#with ${cond}}}${truthy}{{else}}${falsy}{{/with}}`; + } } - - ['@test keying off of `undefined` does not render']() { - this.render(strip` +); + +moduleFor( + 'Syntax test: {{#with as}}', + class extends IfUnlessWithSyntaxTest { + templateFor({ cond, truthy, falsy }) { + return `{{#with ${cond} as |test|}}${truthy}{{else}}${falsy}{{/with}}`; + } + + ['@test keying off of `undefined` does not render']() { + this.render( + strip` {{#with foo.bar.baz as |thing|}} {{thing}} - {{/with}}`, { foo: {} }); + {{/with}}`, + { foo: {} } + ); - this.assertText(''); + this.assertText(''); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText(''); + this.assertText(''); - this.runTask(() => set(this.context, 'foo', { bar: { baz: 'Here!' } })); + this.runTask(() => set(this.context, 'foo', { bar: { baz: 'Here!' } })); - this.assertText('Here!'); + this.assertText('Here!'); - this.runTask(() => set(this.context, 'foo', {})); + this.runTask(() => set(this.context, 'foo', {})); - this.assertText(''); - } + this.assertText(''); + } - ['@test it renders and hides the given block based on the conditional']() { - this.render(`{{#with cond1 as |cond|}}{{cond.greeting}}{{else}}False{{/with}}`, { - cond1: { greeting: 'Hello' } - }); + ['@test it renders and hides the given block based on the conditional']() { + this.render( + `{{#with cond1 as |cond|}}{{cond.greeting}}{{else}}False{{/with}}`, + { + cond1: { greeting: 'Hello' } + } + ); - this.assertText('Hello'); + this.assertText('Hello'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Hello'); + this.assertText('Hello'); - this.runTask(() => set(this.context, 'cond1.greeting', 'Hello world')); + this.runTask(() => set(this.context, 'cond1.greeting', 'Hello world')); - this.assertText('Hello world'); + this.assertText('Hello world'); - this.runTask(() => set(this.context, 'cond1', false)); + this.runTask(() => set(this.context, 'cond1', false)); - this.assertText('False'); + this.assertText('False'); - this.runTask(() => set(this.context, 'cond1', { greeting: 'Hello' })); + this.runTask(() => set(this.context, 'cond1', { greeting: 'Hello' })); - this.assertText('Hello'); - } + this.assertText('Hello'); + } - ['@test can access alias and original scope']() { - this.render(`{{#with person as |tom|}}{{title}}: {{tom.name}}{{/with}}`, { - title: 'Señor Engineer', - person: { name: 'Tom Dale' } - }); + ['@test can access alias and original scope']() { + this.render(`{{#with person as |tom|}}{{title}}: {{tom.name}}{{/with}}`, { + title: 'Señor Engineer', + person: { name: 'Tom Dale' } + }); - this.assertText('Señor Engineer: Tom Dale'); + this.assertText('Señor Engineer: Tom Dale'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Señor Engineer: Tom Dale'); + this.assertText('Señor Engineer: Tom Dale'); - this.runTask(() => { - set(this.context, 'person.name', 'Yehuda Katz'); - set(this.context, 'title', 'Principal Engineer'); - }); + this.runTask(() => { + set(this.context, 'person.name', 'Yehuda Katz'); + set(this.context, 'title', 'Principal Engineer'); + }); - this.assertText('Principal Engineer: Yehuda Katz'); + this.assertText('Principal Engineer: Yehuda Katz'); - this.runTask(() => { - set(this.context, 'person', { name: 'Tom Dale' }); - set(this.context, 'title', 'Señor Engineer'); - }); + this.runTask(() => { + set(this.context, 'person', { name: 'Tom Dale' }); + set(this.context, 'title', 'Señor Engineer'); + }); - this.assertText('Señor Engineer: Tom Dale'); - } + this.assertText('Señor Engineer: Tom Dale'); + } - ['@test the scoped variable is not available outside the {{#with}} block.']() { - this.render(`{{name}}-{{#with other as |name|}}{{name}}{{/with}}-{{name}}`, { - name: 'Stef', - other: 'Yehuda' - }); + ['@test the scoped variable is not available outside the {{#with}} block.']() { + this.render( + `{{name}}-{{#with other as |name|}}{{name}}{{/with}}-{{name}}`, + { + name: 'Stef', + other: 'Yehuda' + } + ); - this.assertText('Stef-Yehuda-Stef'); + this.assertText('Stef-Yehuda-Stef'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Stef-Yehuda-Stef'); + this.assertText('Stef-Yehuda-Stef'); - this.runTask(() => set(this.context, 'other', 'Chad')); + this.runTask(() => set(this.context, 'other', 'Chad')); - this.assertText('Stef-Chad-Stef'); + this.assertText('Stef-Chad-Stef'); - this.runTask(() => set(this.context, 'name', 'Tom')); + this.runTask(() => set(this.context, 'name', 'Tom')); - this.assertText('Tom-Chad-Tom'); + this.assertText('Tom-Chad-Tom'); - this.runTask(() => { - set(this.context, 'name', 'Stef'); - set(this.context, 'other', 'Yehuda'); - }); + this.runTask(() => { + set(this.context, 'name', 'Stef'); + set(this.context, 'other', 'Yehuda'); + }); - this.assertText('Stef-Yehuda-Stef'); - } + this.assertText('Stef-Yehuda-Stef'); + } - ['@test inverse template is displayed with context']() { - this.render(`{{#with falsyThing as |thing|}}Has Thing{{else}}No Thing {{otherThing}}{{/with}}`, { - falsyThing: null, - otherThing: 'bar' - }); + ['@test inverse template is displayed with context']() { + this.render( + `{{#with falsyThing as |thing|}}Has Thing{{else}}No Thing {{otherThing}}{{/with}}`, + { + falsyThing: null, + otherThing: 'bar' + } + ); - this.assertText('No Thing bar'); + this.assertText('No Thing bar'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('No Thing bar'); + this.assertText('No Thing bar'); - this.runTask(() => set(this.context, 'otherThing', 'biz')); + this.runTask(() => set(this.context, 'otherThing', 'biz')); - this.assertText('No Thing biz'); + this.assertText('No Thing biz'); - this.runTask(() => set(this.context, 'falsyThing', true)); + this.runTask(() => set(this.context, 'falsyThing', true)); - this.assertText('Has Thing'); + this.assertText('Has Thing'); - this.runTask(() => set(this.context, 'otherThing', 'baz')); + this.runTask(() => set(this.context, 'otherThing', 'baz')); - this.assertText('Has Thing'); + this.assertText('Has Thing'); - this.runTask(() => { - set(this.context, 'otherThing', 'bar'); - set(this.context, 'falsyThing', null); - }); + this.runTask(() => { + set(this.context, 'otherThing', 'bar'); + set(this.context, 'falsyThing', null); + }); - this.assertText('No Thing bar'); - } + this.assertText('No Thing bar'); + } - ['@test can access alias of a proxy']() { - this.render(`{{#with proxy as |person|}}{{person.name}}{{/with}}`, { - proxy: ObjectProxy.create({ content: { name: 'Tom Dale' } }) - }); + ['@test can access alias of a proxy']() { + this.render(`{{#with proxy as |person|}}{{person.name}}{{/with}}`, { + proxy: ObjectProxy.create({ content: { name: 'Tom Dale' } }) + }); - this.assertText('Tom Dale'); + this.assertText('Tom Dale'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Tom Dale'); + this.assertText('Tom Dale'); - this.runTask(() => set(this.context, 'proxy.name', 'Yehuda Katz')); + this.runTask(() => set(this.context, 'proxy.name', 'Yehuda Katz')); - this.assertText('Yehuda Katz'); + this.assertText('Yehuda Katz'); - this.runTask(() => set(this.context, 'proxy.content', { name: 'Godfrey Chan' })); + this.runTask(() => + set(this.context, 'proxy.content', { name: 'Godfrey Chan' }) + ); - this.assertText('Godfrey Chan'); + this.assertText('Godfrey Chan'); - this.runTask(() => set(this.context, 'proxy.content.name', 'Stefan Penner')); + this.runTask(() => + set(this.context, 'proxy.content.name', 'Stefan Penner') + ); - this.assertText('Stefan Penner'); + this.assertText('Stefan Penner'); - this.runTask(() => set(this.context, 'proxy.content', null)); + this.runTask(() => set(this.context, 'proxy.content', null)); - this.assertText(''); + this.assertText(''); - this.runTask(() => set(this.context, 'proxy', ObjectProxy.create({ content: { name: 'Tom Dale' } }))); + this.runTask(() => + set( + this.context, + 'proxy', + ObjectProxy.create({ content: { name: 'Tom Dale' } }) + ) + ); - this.assertText('Tom Dale'); - } + this.assertText('Tom Dale'); + } - ['@test can access alias of an array']() { - this.render(`{{#with arrayThing as |words|}}{{#each words as |word|}}{{word}}{{/each}}{{/with}}`, { - arrayThing: emberA(['Hello', ' ', 'world']) - }); + ['@test can access alias of an array']() { + this.render( + `{{#with arrayThing as |words|}}{{#each words as |word|}}{{word}}{{/each}}{{/with}}`, + { + arrayThing: emberA(['Hello', ' ', 'world']) + } + ); - this.assertText('Hello world'); + this.assertText('Hello world'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Hello world'); + this.assertText('Hello world'); - this.runTask(() => { - let array = get(this.context, 'arrayThing'); - array.replace(0, 1, ['Goodbye']); - removeAt(array, 1); - array.insertAt(1, ', '); - array.pushObject('!'); - }); + this.runTask(() => { + let array = get(this.context, 'arrayThing'); + array.replace(0, 1, ['Goodbye']); + removeAt(array, 1); + array.insertAt(1, ', '); + array.pushObject('!'); + }); - this.assertText('Goodbye, world!'); + this.assertText('Goodbye, world!'); - this.runTask(() => set(this.context, 'arrayThing', ['Hello', ' ', 'world'])); + this.runTask(() => + set(this.context, 'arrayThing', ['Hello', ' ', 'world']) + ); - this.assertText('Hello world'); - } + this.assertText('Hello world'); + } - ['@test `attrs` can be used as a block param [GH#14678]']() { - this.render('{{#with hash as |attrs|}}[{{hash.foo}}-{{attrs.foo}}]{{/with}}', { - hash: { foo: 'foo' } - }); + ['@test `attrs` can be used as a block param [GH#14678]']() { + this.render( + '{{#with hash as |attrs|}}[{{hash.foo}}-{{attrs.foo}}]{{/with}}', + { + hash: { foo: 'foo' } + } + ); - this.assertText('[foo-foo]'); + this.assertText('[foo-foo]'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('[foo-foo]'); + this.assertText('[foo-foo]'); - this.runTask(() => this.context.set('hash.foo', 'FOO')); + this.runTask(() => this.context.set('hash.foo', 'FOO')); - this.assertText('[FOO-FOO]'); + this.assertText('[FOO-FOO]'); - this.runTask(() => this.context.set('hash.foo', 'foo')); + this.runTask(() => this.context.set('hash.foo', 'foo')); - this.assertText('[foo-foo]'); + this.assertText('[foo-foo]'); + } } +); -}); - -moduleFor('Syntax test: Multiple {{#with as}} helpers', class extends RenderingTest { - - ['@test re-using the same variable with different {{#with}} blocks does not override each other']() { - this.render(`Admin: {{#with admin as |person|}}{{person.name}}{{/with}} User: {{#with user as |person|}}{{person.name}}{{/with}}`, { - admin: { name: 'Tom Dale' }, - user: { name: 'Yehuda Katz' } - }); +moduleFor( + 'Syntax test: Multiple {{#with as}} helpers', + class extends RenderingTest { + ['@test re-using the same variable with different {{#with}} blocks does not override each other']() { + this.render( + `Admin: {{#with admin as |person|}}{{person.name}}{{/with}} User: {{#with user as |person|}}{{person.name}}{{/with}}`, + { + admin: { name: 'Tom Dale' }, + user: { name: 'Yehuda Katz' } + } + ); - this.assertText('Admin: Tom Dale User: Yehuda Katz'); + this.assertText('Admin: Tom Dale User: Yehuda Katz'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Admin: Tom Dale User: Yehuda Katz'); + this.assertText('Admin: Tom Dale User: Yehuda Katz'); - this.runTask(() => { - set(this.context, 'admin.name', 'Godfrey Chan'); - set(this.context, 'user.name', 'Stefan Penner'); - }); + this.runTask(() => { + set(this.context, 'admin.name', 'Godfrey Chan'); + set(this.context, 'user.name', 'Stefan Penner'); + }); - this.assertText('Admin: Godfrey Chan User: Stefan Penner'); + this.assertText('Admin: Godfrey Chan User: Stefan Penner'); - this.runTask(() => { - set(this.context, 'admin', { name: 'Tom Dale' }); - set(this.context, 'user', { name: 'Yehuda Katz' }); - }); + this.runTask(() => { + set(this.context, 'admin', { name: 'Tom Dale' }); + set(this.context, 'user', { name: 'Yehuda Katz' }); + }); - this.assertText('Admin: Tom Dale User: Yehuda Katz'); - } + this.assertText('Admin: Tom Dale User: Yehuda Katz'); + } - ['@test the scoped variable is not available outside the {{#with}} block']() { - this.render(`{{ring}}-{{#with first as |ring|}}{{ring}}-{{#with fifth as |ring|}}{{ring}}-{{#with ninth as |ring|}}{{ring}}-{{/with}}{{ring}}-{{/with}}{{ring}}-{{/with}}{{ring}}`, { - ring: 'Greed', - first: 'Limbo', - fifth: 'Wrath', - ninth: 'Treachery' - }); + ['@test the scoped variable is not available outside the {{#with}} block']() { + this.render( + `{{ring}}-{{#with first as |ring|}}{{ring}}-{{#with fifth as |ring|}}{{ring}}-{{#with ninth as |ring|}}{{ring}}-{{/with}}{{ring}}-{{/with}}{{ring}}-{{/with}}{{ring}}`, + { + ring: 'Greed', + first: 'Limbo', + fifth: 'Wrath', + ninth: 'Treachery' + } + ); - this.assertText('Greed-Limbo-Wrath-Treachery-Wrath-Limbo-Greed'); + this.assertText('Greed-Limbo-Wrath-Treachery-Wrath-Limbo-Greed'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Greed-Limbo-Wrath-Treachery-Wrath-Limbo-Greed'); + this.assertText('Greed-Limbo-Wrath-Treachery-Wrath-Limbo-Greed'); - this.runTask(() => { - set(this.context, 'ring', 'O'); - set(this.context, 'fifth', 'D'); - }); + this.runTask(() => { + set(this.context, 'ring', 'O'); + set(this.context, 'fifth', 'D'); + }); - this.assertText('O-Limbo-D-Treachery-D-Limbo-O'); + this.assertText('O-Limbo-D-Treachery-D-Limbo-O'); - this.runTask(() => { - set(this.context, 'first', 'I'); - set(this.context, 'ninth', 'K'); - }); + this.runTask(() => { + set(this.context, 'first', 'I'); + set(this.context, 'ninth', 'K'); + }); - this.assertText('O-I-D-K-D-I-O'); + this.assertText('O-I-D-K-D-I-O'); - this.runTask(() => { - set(this.context, 'ring', 'Greed'); - set(this.context, 'first', 'Limbo'); - set(this.context, 'fifth', 'Wrath'); - set(this.context, 'ninth', 'Treachery'); - }); + this.runTask(() => { + set(this.context, 'ring', 'Greed'); + set(this.context, 'first', 'Limbo'); + set(this.context, 'fifth', 'Wrath'); + set(this.context, 'ninth', 'Treachery'); + }); - this.assertText('Greed-Limbo-Wrath-Treachery-Wrath-Limbo-Greed'); - } + this.assertText('Greed-Limbo-Wrath-Treachery-Wrath-Limbo-Greed'); + } - ['@test it should support {{#with name as |foo|}}, then {{#with foo as |bar|}}']() { - this.render(`{{#with name as |foo|}}{{#with foo as |bar|}}{{bar}}{{/with}}{{/with}}`, { - name: 'caterpillar' - }); + ['@test it should support {{#with name as |foo|}}, then {{#with foo as |bar|}}']() { + this.render( + `{{#with name as |foo|}}{{#with foo as |bar|}}{{bar}}{{/with}}{{/with}}`, + { + name: 'caterpillar' + } + ); - this.assertText('caterpillar'); + this.assertText('caterpillar'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('caterpillar'); + this.assertText('caterpillar'); - this.runTask(() => set(this.context, 'name', 'butterfly')); + this.runTask(() => set(this.context, 'name', 'butterfly')); - this.assertText('butterfly'); + this.assertText('butterfly'); - this.runTask(() => set(this.context, 'name', 'caterpillar')); + this.runTask(() => set(this.context, 'name', 'caterpillar')); - this.assertText('caterpillar'); - } + this.assertText('caterpillar'); + } - ['@test updating the context should update the alias']() { - this.render(`{{#with this as |person|}}{{person.name}}{{/with}}`, { - name: 'Los Pivots' - }); + ['@test updating the context should update the alias']() { + this.render(`{{#with this as |person|}}{{person.name}}{{/with}}`, { + name: 'Los Pivots' + }); - this.assertText('Los Pivots'); + this.assertText('Los Pivots'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('Los Pivots'); + this.assertText('Los Pivots'); - this.runTask(() => set(this.context, 'name', 'l\'Pivots')); + this.runTask(() => set(this.context, 'name', "l'Pivots")); - this.assertText('l\'Pivots'); + this.assertText("l'Pivots"); - this.runTask(() => set(this.context, 'name', 'Los Pivots')); + this.runTask(() => set(this.context, 'name', 'Los Pivots')); - this.assertText('Los Pivots'); - } + this.assertText('Los Pivots'); + } - ['@test nested {{#with}} blocks should have access to root context']() { - this.render(strip` + ['@test nested {{#with}} blocks should have access to root context']() { + this.render( + strip` {{name}} {{#with committer1.name as |name|}} [{{name}} @@ -356,40 +399,50 @@ moduleFor('Syntax test: Multiple {{#with as}} helpers', class extends RenderingT {{name}}] {{/with}} {{name}} - `, { - name: 'ebryn', - committer1: { name: 'trek' }, - committer2: { name: 'machty' } - }); + `, + { + name: 'ebryn', + committer1: { name: 'trek' }, + committer2: { name: 'machty' } + } + ); - this.assertText('ebryn[trek[machty]trek]ebryn[machty[trek]machty]ebryn'); + this.assertText('ebryn[trek[machty]trek]ebryn[machty[trek]machty]ebryn'); - this.runTask(() => this.rerender()); + this.runTask(() => this.rerender()); - this.assertText('ebryn[trek[machty]trek]ebryn[machty[trek]machty]ebryn'); + this.assertText('ebryn[trek[machty]trek]ebryn[machty[trek]machty]ebryn'); - this.runTask(() => set(this.context, 'name', 'chancancode')); + this.runTask(() => set(this.context, 'name', 'chancancode')); - this.assertText('chancancode[trek[machty]trek]chancancode[machty[trek]machty]chancancode'); + this.assertText( + 'chancancode[trek[machty]trek]chancancode[machty[trek]machty]chancancode' + ); - this.runTask(() => set(this.context, 'committer1', { name: 'krisselden' })); + this.runTask(() => + set(this.context, 'committer1', { name: 'krisselden' }) + ); - this.assertText('chancancode[krisselden[machty]krisselden]chancancode[machty[krisselden]machty]chancancode'); + this.assertText( + 'chancancode[krisselden[machty]krisselden]chancancode[machty[krisselden]machty]chancancode' + ); - this.runTask(() => { - set(this.context, 'committer1.name', 'wycats'); - set(this.context, 'committer2', { name: 'rwjblue' }); - }); + this.runTask(() => { + set(this.context, 'committer1.name', 'wycats'); + set(this.context, 'committer2', { name: 'rwjblue' }); + }); - this.assertText('chancancode[wycats[rwjblue]wycats]chancancode[rwjblue[wycats]rwjblue]chancancode'); + this.assertText( + 'chancancode[wycats[rwjblue]wycats]chancancode[rwjblue[wycats]rwjblue]chancancode' + ); - this.runTask(() => { - set(this.context, 'name', 'ebryn'); - set(this.context, 'committer1', { name: 'trek' }); - set(this.context, 'committer2', { name: 'machty' }); - }); + this.runTask(() => { + set(this.context, 'name', 'ebryn'); + set(this.context, 'committer1', { name: 'trek' }); + set(this.context, 'committer2', { name: 'machty' }); + }); - this.assertText('ebryn[trek[machty]trek]ebryn[machty[trek]machty]ebryn'); + this.assertText('ebryn[trek[machty]trek]ebryn[machty[trek]machty]ebryn'); + } } - -}); +); diff --git a/packages/ember-glimmer/tests/unit/layout-cache-test.js b/packages/ember-glimmer/tests/unit/layout-cache-test.js index 580ce257ced..4c95307909f 100644 --- a/packages/ember-glimmer/tests/unit/layout-cache-test.js +++ b/packages/ember-glimmer/tests/unit/layout-cache-test.js @@ -3,107 +3,143 @@ import { Component } from '../utils/helpers'; import { set } from 'ember-metal'; import { runDestroy, runAppend } from 'internal-test-helpers'; -moduleFor('Layout cache test', class extends RenderingTest { - - ['@test each template is only compiled once'](assert) { - // static layout - this.registerComponent('component-one', { template: 'One' }); - - // test directly import template factory onto late bound layout - let Two = Component.extend({ - layout: this.compile('Two'), - }); - this.registerComponent('component-two', { ComponentClass: Two }); - - // inject layout onto component, share layout with component-one - this.registerComponent('root-component', { ComponentClass: Component }); - this.owner.inject('component:root-component', 'layout', 'template:components/component-one'); - - // template instance shared between to template managers - let rootFactory = this.owner.factoryFor('component:root-component'); - - // assert precondition - let state = this.getCacheCounters(); - assert.deepEqual(state, { - templateCacheHits: 0, - templateCacheMisses: 0, - }, 'precondition'); - - // show component-one for the first time - this.render(` +moduleFor( + 'Layout cache test', + class extends RenderingTest { + ['@test each template is only compiled once'](assert) { + // static layout + this.registerComponent('component-one', { template: 'One' }); + + // test directly import template factory onto late bound layout + let Two = Component.extend({ + layout: this.compile('Two') + }); + this.registerComponent('component-two', { ComponentClass: Two }); + + // inject layout onto component, share layout with component-one + this.registerComponent('root-component', { ComponentClass: Component }); + this.owner.inject( + 'component:root-component', + 'layout', + 'template:components/component-one' + ); + + // template instance shared between to template managers + let rootFactory = this.owner.factoryFor('component:root-component'); + + // assert precondition + let state = this.getCacheCounters(); + assert.deepEqual( + state, + { + templateCacheHits: 0, + templateCacheMisses: 0 + }, + 'precondition' + ); + + // show component-one for the first time + this.render( + ` {{~#if cond~}} {{component-one}} {{~else~}} {{component-two}} - {{~/if}}`, { - cond: true, - }); - - this.assertText('One'); - state = this.expectCacheChanges({}, state, 'test case component and component-one no change'); - - // show component-two for the first time - this.runTask(() => set(this.context, 'cond', false)); - - this.assertText('Two'); - state = this.expectCacheChanges({ - templateCacheMisses: 1, - }, state, 'component-two first render misses template cache'); - - // show component-one again - this.runTask(() => set(this.context, 'cond', true)); - - this.assertText('One'); - state = this.expectCacheChanges({}, state, 'toggle back to component-one no change'); - - // show component-two again - this.runTask(() => set(this.context, 'cond', false)); - - this.assertText('Two'); - state = this.expectCacheChanges({ - templateCacheHits: 1, - }, state, 'toggle back to component-two hits template cache'); - - // render new root append - let root = rootFactory.create(); - try { - runAppend(root); - this.assertText('TwoOne'); - // roots have different capabilities so this will hit - state = this.expectCacheChanges({}, state, 'append root with component-one no change'); + {{~/if}}`, + { + cond: true + } + ); + + this.assertText('One'); + state = this.expectCacheChanges( + {}, + state, + 'test case component and component-one no change' + ); + + // show component-two for the first time + this.runTask(() => set(this.context, 'cond', false)); + + this.assertText('Two'); + state = this.expectCacheChanges( + { + templateCacheMisses: 1 + }, + state, + 'component-two first render misses template cache' + ); + + // show component-one again + this.runTask(() => set(this.context, 'cond', true)); + + this.assertText('One'); + state = this.expectCacheChanges( + {}, + state, + 'toggle back to component-one no change' + ); + + // show component-two again + this.runTask(() => set(this.context, 'cond', false)); + + this.assertText('Two'); + state = this.expectCacheChanges( + { + templateCacheHits: 1 + }, + state, + 'toggle back to component-two hits template cache' + ); // render new root append - let root2 = rootFactory.create(); + let root = rootFactory.create(); try { - runAppend(root2); - this.assertText('TwoOneOne'); - state = this.expectCacheChanges({}, state, 'append another root no change'); + runAppend(root); + this.assertText('TwoOne'); + // roots have different capabilities so this will hit + state = this.expectCacheChanges( + {}, + state, + 'append root with component-one no change' + ); + + // render new root append + let root2 = rootFactory.create(); + try { + runAppend(root2); + this.assertText('TwoOneOne'); + state = this.expectCacheChanges( + {}, + state, + 'append another root no change' + ); + } finally { + runDestroy(root2); + } } finally { - runDestroy(root2); + runDestroy(root); } - } finally { - runDestroy(root); } - } - getCacheCounters() { - let { runtimeResolver: { - templateCacheHits, - templateCacheMisses, - } } = this; - return { - templateCacheHits, - templateCacheMisses, - }; - } + getCacheCounters() { + let { + runtimeResolver: { templateCacheHits, templateCacheMisses } + } = this; + return { + templateCacheHits, + templateCacheMisses + }; + } - expectCacheChanges(expected, lastState, message) { - let state = this.getCacheCounters(); - let actual = diff(state, lastState); - this.assert.deepEqual(actual, expected, message); - return state; + expectCacheChanges(expected, lastState, message) { + let state = this.getCacheCounters(); + let actual = diff(state, lastState); + this.assert.deepEqual(actual, expected, message); + return state; + } } -}); +); function diff(state, lastState) { let res = {}; diff --git a/packages/ember-glimmer/tests/unit/outlet-test.js b/packages/ember-glimmer/tests/unit/outlet-test.js index 6fd4ab5f510..cb4022080a7 100644 --- a/packages/ember-glimmer/tests/unit/outlet-test.js +++ b/packages/ember-glimmer/tests/unit/outlet-test.js @@ -15,14 +15,34 @@ QUnit.test('render in the render queue', function(assert) { } }; - let outletView = new OutletView({}, renderer); + let outletView = new OutletView({}, renderer); run(() => { - assert.equal(didAppendOutletView, 0, 'appendOutletView should not yet have been called (before appendTo)'); + assert.equal( + didAppendOutletView, + 0, + 'appendOutletView should not yet have been called (before appendTo)' + ); outletView.appendTo(expectedOutlet); - assert.equal(didAppendOutletView, 0, 'appendOutletView should not yet have been called (sync after appendTo)'); + assert.equal( + didAppendOutletView, + 0, + 'appendOutletView should not yet have been called (sync after appendTo)' + ); - schedule('actions', () => assert.equal(didAppendOutletView, 0, 'appendOutletView should not yet have been called (in actions)')); - schedule('render', () => assert.equal(didAppendOutletView, 1, 'appendOutletView should be invoked in render')); + schedule('actions', () => + assert.equal( + didAppendOutletView, + 0, + 'appendOutletView should not yet have been called (in actions)' + ) + ); + schedule('render', () => + assert.equal( + didAppendOutletView, + 1, + 'appendOutletView should be invoked in render' + ) + ); }); }); diff --git a/packages/ember-glimmer/tests/unit/template-factory-test.js b/packages/ember-glimmer/tests/unit/template-factory-test.js index c56ab0f9c43..144061be8fb 100644 --- a/packages/ember-glimmer/tests/unit/template-factory-test.js +++ b/packages/ember-glimmer/tests/unit/template-factory-test.js @@ -3,62 +3,73 @@ import { template } from 'ember-glimmer'; import { RenderingTest, moduleFor } from '../utils/test-case'; import { Component } from '../utils/helpers'; -moduleFor('Template factory test', class extends RenderingTest { - ['@test the template factory returned from precompile is the same as compile'](assert) { - let { owner } = this; - let { runtimeResolver } = this; - - let templateStr = 'Hello {{name}}'; - let options = { moduleName: 'my-app/templates/some-module.hbs' }; - - let spec = precompile(templateStr, options); - let body = `exports.default = template(${spec});`; - let module = new Function('exports', 'template', body); - let exports = { }; - module(exports, template); - let Precompiled = exports['default']; - - let Compiled = compile(templateStr, options); - - assert.equal(typeof Precompiled.create, 'function', 'precompiled is a factory'); - assert.ok(Precompiled.id, 'precompiled has id'); - - assert.equal(typeof Compiled.create, 'function', 'compiled is a factory'); - assert.ok(Compiled.id, 'compiled has id'); - - assert.equal(runtimeResolver.templateCacheMisses, 0, 'misses 0'); - assert.equal(runtimeResolver.templateCacheHits, 0, 'hits 0'); - - let precompiled = runtimeResolver.createTemplate(Precompiled, owner); - - assert.equal(runtimeResolver.templateCacheMisses, 1, 'misses 1'); - assert.equal(runtimeResolver.templateCacheHits, 0, 'hits 0'); - - let compiled = runtimeResolver.createTemplate(Compiled, owner); - - assert.equal(runtimeResolver.templateCacheMisses, 2, 'misses 2'); - assert.equal(runtimeResolver.templateCacheHits, 0, 'hits 0'); - - assert.ok(typeof precompiled.spec !== 'string', 'Spec has been parsed'); - assert.ok(typeof compiled.spec !== 'string', 'Spec has been parsed'); - - this.registerComponent('x-precompiled', { - ComponentClass: Component.extend({ - layout: Precompiled - }) - }); - - this.registerComponent('x-compiled', { - ComponentClass: Component.extend({ - layout: Compiled - }) - }); - - this.render('{{x-precompiled name="precompiled"}} {{x-compiled name="compiled"}}'); - - assert.equal(runtimeResolver.templateCacheMisses, 2, 'misses 2'); - assert.equal(runtimeResolver.templateCacheHits, 2, 'hits 2'); - - this.assertText('Hello precompiled Hello compiled'); +moduleFor( + 'Template factory test', + class extends RenderingTest { + ['@test the template factory returned from precompile is the same as compile']( + assert + ) { + let { owner } = this; + let { runtimeResolver } = this; + + let templateStr = 'Hello {{name}}'; + let options = { moduleName: 'my-app/templates/some-module.hbs' }; + + let spec = precompile(templateStr, options); + let body = `exports.default = template(${spec});`; + let module = new Function('exports', 'template', body); + let exports = {}; + module(exports, template); + let Precompiled = exports['default']; + + let Compiled = compile(templateStr, options); + + assert.equal( + typeof Precompiled.create, + 'function', + 'precompiled is a factory' + ); + assert.ok(Precompiled.id, 'precompiled has id'); + + assert.equal(typeof Compiled.create, 'function', 'compiled is a factory'); + assert.ok(Compiled.id, 'compiled has id'); + + assert.equal(runtimeResolver.templateCacheMisses, 0, 'misses 0'); + assert.equal(runtimeResolver.templateCacheHits, 0, 'hits 0'); + + let precompiled = runtimeResolver.createTemplate(Precompiled, owner); + + assert.equal(runtimeResolver.templateCacheMisses, 1, 'misses 1'); + assert.equal(runtimeResolver.templateCacheHits, 0, 'hits 0'); + + let compiled = runtimeResolver.createTemplate(Compiled, owner); + + assert.equal(runtimeResolver.templateCacheMisses, 2, 'misses 2'); + assert.equal(runtimeResolver.templateCacheHits, 0, 'hits 0'); + + assert.ok(typeof precompiled.spec !== 'string', 'Spec has been parsed'); + assert.ok(typeof compiled.spec !== 'string', 'Spec has been parsed'); + + this.registerComponent('x-precompiled', { + ComponentClass: Component.extend({ + layout: Precompiled + }) + }); + + this.registerComponent('x-compiled', { + ComponentClass: Component.extend({ + layout: Compiled + }) + }); + + this.render( + '{{x-precompiled name="precompiled"}} {{x-compiled name="compiled"}}' + ); + + assert.equal(runtimeResolver.templateCacheMisses, 2, 'misses 2'); + assert.equal(runtimeResolver.templateCacheHits, 2, 'hits 2'); + + this.assertText('Hello precompiled Hello compiled'); + } } -}); +); diff --git a/packages/ember-glimmer/tests/unit/utils/debug-stack-test.js b/packages/ember-glimmer/tests/unit/utils/debug-stack-test.js index 601555e555f..b2c0f6b7b69 100644 --- a/packages/ember-glimmer/tests/unit/utils/debug-stack-test.js +++ b/packages/ember-glimmer/tests/unit/utils/debug-stack-test.js @@ -20,7 +20,10 @@ if (DEBUG) { stack.pushEngine('engine:my-engine'); stack.push('component:component-in-engine'); - assert.equal(stack.peek(), '"component:component-in-engine" (in "engine:my-engine")'); + assert.equal( + stack.peek(), + '"component:component-in-engine" (in "engine:my-engine")' + ); stack.pop(); stack.pop(); diff --git a/packages/ember-glimmer/tests/utils/helpers.js b/packages/ember-glimmer/tests/utils/helpers.js index 5176c6f49d3..a1710e35000 100644 --- a/packages/ember-glimmer/tests/utils/helpers.js +++ b/packages/ember-glimmer/tests/utils/helpers.js @@ -1,7 +1,4 @@ -export { - compile, - precompile -} from 'ember-template-compiler'; +export { compile, precompile } from 'ember-template-compiler'; export { INVOKE, diff --git a/packages/ember-glimmer/tests/utils/shared-conditional-tests.js b/packages/ember-glimmer/tests/utils/shared-conditional-tests.js index fc4fe7710c2..8acd2f3246a 100644 --- a/packages/ember-glimmer/tests/utils/shared-conditional-tests.js +++ b/packages/ember-glimmer/tests/utils/shared-conditional-tests.js @@ -12,10 +12,13 @@ import { import { Component } from './helpers'; class AbstractConditionalsTest extends RenderingTest { + get truthyValue() { + return true; + } - get truthyValue() { return true; } - - get falsyValue() { return false; } + get falsyValue() { + return false; + } wrapperFor(templates) { return templates.join(''); @@ -26,7 +29,7 @@ class AbstractConditionalsTest extends RenderingTest { } /* abstract */ - templateFor( /* { cond, truthy, falsy } */) { + templateFor(/* { cond, truthy, falsy } */) { // e.g. `{{#if ${cond}}}${truthy}{{else}}${falsy}{{/if}}` throw new Error('Not implemented: `templateFor`'); } @@ -35,11 +38,9 @@ class AbstractConditionalsTest extends RenderingTest { renderValues(/* ...values */) { throw new Error('Not implemented: `renderValues`'); } - } class AbstractGenerator { - constructor(cases) { this.cases = cases; } @@ -48,7 +49,6 @@ class AbstractGenerator { generate(/* value, idx */) { throw new Error('Not implemented: `generate`'); } - } /* @@ -62,7 +62,6 @@ class AbstractGenerator { */ export class TruthyGenerator extends AbstractGenerator { - generate(value, idx) { return { [`@test it should consider ${JSON.stringify(value)} truthy [${idx}]`]() { @@ -84,11 +83,9 @@ export class TruthyGenerator extends AbstractGenerator { } }; } - } export class FalsyGenerator extends AbstractGenerator { - generate(value, idx) { return { [`@test it should consider ${JSON.stringify(value)} falsy [${idx}]`]() { @@ -110,11 +107,9 @@ export class FalsyGenerator extends AbstractGenerator { } }; } - } export class StableTruthyGenerator extends TruthyGenerator { - generate(value, idx) { return assign(super.generate(value, idx), { [`@test it maintains DOM stability when condition changes from ${value} to another truthy value and back [${idx}]`]() { @@ -138,11 +133,9 @@ export class StableTruthyGenerator extends TruthyGenerator { } }); } - } export class StableFalsyGenerator extends FalsyGenerator { - generate(value, idx) { return assign(super.generate(value), { [`@test it maintains DOM stability when condition changes from ${value} to another falsy value and back [${idx}]`]() { @@ -166,17 +159,17 @@ export class StableFalsyGenerator extends FalsyGenerator { } }); } - } class ObjectProxyGenerator extends AbstractGenerator { - generate(value, idx) { // This is inconsistent with our usual to-bool policy, but the current proxy implementation // simply uses !!content to determine truthiness if (value) { return { - [`@test it should consider an object proxy with \`${JSON.stringify(value)}\` truthy [${idx}]`]() { + [`@test it should consider an object proxy with \`${JSON.stringify( + value + )}\` truthy [${idx}]`]() { this.renderValues(ObjectProxy.create({ content: value })); this.assertText('T1'); @@ -185,18 +178,24 @@ class ObjectProxyGenerator extends AbstractGenerator { this.assertText('T1'); - this.runTask(() => set(this.context, 'cond1.content', this.falsyValue)); + this.runTask(() => + set(this.context, 'cond1.content', this.falsyValue) + ); this.assertText('F1'); - this.runTask(() => set(this.context, 'cond1', ObjectProxy.create({ content: value }))); + this.runTask(() => + set(this.context, 'cond1', ObjectProxy.create({ content: value })) + ); this.assertText('T1'); } }; } else { return { - [`@test it should consider an object proxy with \`${JSON.stringify(value)}\` falsy [${idx}]`]() { + [`@test it should consider an object proxy with \`${JSON.stringify( + value + )}\` falsy [${idx}]`]() { this.renderValues(ObjectProxy.create({ content: value })); this.assertText('F1'); @@ -205,24 +204,26 @@ class ObjectProxyGenerator extends AbstractGenerator { this.assertText('F1'); - this.runTask(() => set(this.context, 'cond1.content', this.truthyValue)); + this.runTask(() => + set(this.context, 'cond1.content', this.truthyValue) + ); this.assertText('T1'); - this.runTask(() => set(this.context, 'cond1', ObjectProxy.create({ content: value }))); + this.runTask(() => + set(this.context, 'cond1', ObjectProxy.create({ content: value })) + ); this.assertText('F1'); } }; } } - } // Testing behaviors shared across all conditionals, i.e. {{#if}}, {{#unless}}, // {{#with}}, {{#each}}, {{#each-in}}, (if) and (unless) export class BasicConditionalsTest extends AbstractConditionalsTest { - ['@test it renders the corresponding block based on the conditional']() { this.renderValues(this.truthyValue, this.falsyValue); @@ -250,12 +251,10 @@ export class BasicConditionalsTest extends AbstractConditionalsTest { this.assertText('T1F2'); } - } // Testing behaviors related to ember objects, object proxies, etc export const ObjectTestCases = { - ['@test it considers object proxies without content falsy']() { this.renderValues( ObjectProxy.create({ content: {} }), @@ -286,23 +285,22 @@ export const ObjectTestCases = { this.runTask(() => { set(this.context, 'cond1', ObjectProxy.create({ content: {} })); - set(this.context, 'cond2', ObjectProxy.create({ content: EmberObject.create() })); + set( + this.context, + 'cond2', + ObjectProxy.create({ content: EmberObject.create() }) + ); set(this.context, 'cond3', ObjectProxy.create({ content: null })); }); this.assertText('T1T2F3'); } - }; // Testing behaviors related to arrays and array proxies export const ArrayTestCases = { - ['@test it considers empty arrays falsy']() { - this.renderValues( - emberA(['hello']), - emberA() - ); + this.renderValues(emberA(['hello']), emberA()); this.assertText('T1F2'); @@ -356,7 +354,11 @@ export const ArrayTestCases = { this.assertText('T1T2'); this.runTask(() => { - set(this.context, 'cond1', ArrayProxy.create({ content: emberA(['hello']) })); + set( + this.context, + 'cond1', + ArrayProxy.create({ content: emberA(['hello']) }) + ); set(this.context, 'cond2', ArrayProxy.create({ content: null })); }); @@ -387,17 +389,19 @@ export const ArrayTestCases = { this.assertText('T1T2'); this.runTask(() => { - set(this.context, 'cond1', ArrayProxy.create({ content: emberA(['hello']) })); + set( + this.context, + 'cond1', + ArrayProxy.create({ content: emberA(['hello']) }) + ); set(this.context, 'cond2', ArrayProxy.create({ content: emberA() })); }); this.assertText('T1F2'); } - }; const IfUnlessWithTestCases = [ - new StableTruthyGenerator([ true, ' ', @@ -472,7 +476,6 @@ const IfUnlessWithTestCases = [ ObjectTestCases, ArrayTestCases - ]; // Testing behaviors shared across the "toggling" conditionals, i.e. {{#if}}, @@ -481,13 +484,14 @@ export class TogglingConditionalsTest extends BasicConditionalsTest {} // Testing behaviors shared across the (if) and (unless) helpers export class TogglingHelperConditionalsTest extends TogglingConditionalsTest { - renderValues(...values) { let templates = []; let context = {}; for (let i = 1; i <= values.length; i++) { - templates.push(this.templateFor({ cond: `cond${i}`, truthy: `t${i}`, falsy: `f${i}` })); + templates.push( + this.templateFor({ cond: `cond${i}`, truthy: `t${i}`, falsy: `f${i}` }) + ); context[`t${i}`] = `T${i}`; context[`f${i}`] = `F${i}`; context[`cond${i}`] = values[i - 1]; @@ -503,7 +507,12 @@ export class TogglingHelperConditionalsTest extends TogglingConditionalsTest { this.templateFor({ cond: 'cond2', truthy: 'truthy', falsy: 'falsy' }) ]); - this.render(template, { cond1: this.truthyValue, cond2: this.falsyValue, truthy: 'YES', falsy: 'NO' }); + this.render(template, { + cond1: this.truthyValue, + cond2: this.falsyValue, + truthy: 'YES', + falsy: 'NO' + }); this.assertText('YESNO'); @@ -537,8 +546,16 @@ export class TogglingHelperConditionalsTest extends TogglingConditionalsTest { ['@test it does not update when the unbound helper is used']() { let template = this.wrapperFor([ - this.templateFor({ cond: '(unbound cond1)', truthy: '"T1"', falsy: '"F1"' }), - this.templateFor({ cond: '(unbound cond2)', truthy: '"T2"', falsy: '"F2"' }) + this.templateFor({ + cond: '(unbound cond1)', + truthy: '"T1"', + falsy: '"F1"' + }), + this.templateFor({ + cond: '(unbound cond2)', + truthy: '"T2"', + falsy: '"F2"' + }) ]); this.render(template, { cond1: this.truthyValue, cond2: this.falsyValue }); @@ -572,13 +589,13 @@ export class TogglingHelperConditionalsTest extends TogglingConditionalsTest { let truthyEvaluated; let falsyEvaluated; - let withoutEvaluatingTruthy = (callback) => { + let withoutEvaluatingTruthy = callback => { truthyEvaluated = false; callback(); assert.ok(!truthyEvaluated, 'x-truthy is not evaluated'); }; - let withoutEvaluatingFalsy = (callback) => { + let withoutEvaluatingFalsy = callback => { falsyEvaluated = false; callback(); assert.ok(!falsyEvaluated, 'x-falsy is not evaluated'); @@ -598,9 +615,15 @@ export class TogglingHelperConditionalsTest extends TogglingConditionalsTest { } }); - let template = this.wrappedTemplateFor({ cond: 'cond', truthy: '(x-truthy)', falsy: '(x-falsy)' }); + let template = this.wrappedTemplateFor({ + cond: 'cond', + truthy: '(x-truthy)', + falsy: '(x-falsy)' + }); - withoutEvaluatingFalsy(() => this.render(template, { cond: this.truthyValue })); + withoutEvaluatingFalsy(() => + this.render(template, { cond: this.truthyValue }) + ); this.assertText('T'); @@ -608,7 +631,9 @@ export class TogglingHelperConditionalsTest extends TogglingConditionalsTest { this.assertText('T'); - withoutEvaluatingTruthy(() => this.runTask(() => set(this.context, 'cond', this.falsyValue))); + withoutEvaluatingTruthy(() => + this.runTask(() => set(this.context, 'cond', this.falsyValue)) + ); this.assertText('F'); @@ -616,11 +641,12 @@ export class TogglingHelperConditionalsTest extends TogglingConditionalsTest { this.assertText('F'); - withoutEvaluatingFalsy(() => this.runTask(() => set(this.context, 'cond', this.truthyValue))); + withoutEvaluatingFalsy(() => + this.runTask(() => set(this.context, 'cond', this.truthyValue)) + ); this.assertText('T'); } - } export class IfUnlessHelperTest extends TogglingHelperConditionalsTest {} @@ -630,13 +656,18 @@ applyMixins(IfUnlessHelperTest, ...IfUnlessWithTestCases); // Testing behaviors shared across the "toggling" syntatical constructs, // i.e. {{#if}}, {{#unless}}, {{#with}}, {{#each}} and {{#each-in}} export class TogglingSyntaxConditionalsTest extends TogglingConditionalsTest { - renderValues(...values) { let templates = []; let context = {}; for (let i = 1; i <= values.length; i++) { - templates.push(this.templateFor({ cond: `cond${i}`, truthy: `{{t}}${i}`, falsy: `{{f}}${i}` })); + templates.push( + this.templateFor({ + cond: `cond${i}`, + truthy: `{{t}}${i}`, + falsy: `{{f}}${i}` + }) + ); context[`cond${i}`] = values[i - 1]; } @@ -645,11 +676,15 @@ export class TogglingSyntaxConditionalsTest extends TogglingConditionalsTest { } ['@test it does not update when the unbound helper is used']() { - let template = `${ - this.templateFor({ cond: '(unbound cond1)', truthy: 'T1', falsy: 'F1' }) - }${ - this.templateFor({ cond: '(unbound cond2)', truthy: 'T2', falsy: 'F2' }) - }`; + let template = `${this.templateFor({ + cond: '(unbound cond1)', + truthy: 'T1', + falsy: 'F1' + })}${this.templateFor({ + cond: '(unbound cond2)', + truthy: 'T2', + falsy: 'F2' + })}`; this.render(template, { cond1: this.truthyValue, cond2: this.falsyValue }); @@ -680,11 +715,24 @@ export class TogglingSyntaxConditionalsTest extends TogglingConditionalsTest { ['@test it has access to the outer scope from both templates']() { let template = this.wrapperFor([ - this.templateFor({ cond: 'cond1', truthy: '{{truthy}}', falsy: '{{falsy}}' }), - this.templateFor({ cond: 'cond2', truthy: '{{truthy}}', falsy: '{{falsy}}' }) + this.templateFor({ + cond: 'cond1', + truthy: '{{truthy}}', + falsy: '{{falsy}}' + }), + this.templateFor({ + cond: 'cond2', + truthy: '{{truthy}}', + falsy: '{{falsy}}' + }) ]); - this.render(template, { cond1: this.truthyValue, cond2: this.falsyValue, truthy: 'YES', falsy: 'NO' }); + this.render(template, { + cond1: this.truthyValue, + cond2: this.falsyValue, + truthy: 'YES', + falsy: 'NO' + }); this.assertText('YESNO'); @@ -718,8 +766,16 @@ export class TogglingSyntaxConditionalsTest extends TogglingConditionalsTest { ['@test it updates correctly when enclosing another conditional']() { // This tests whether the outer conditional tracks its bounds correctly as its inner bounds changes - let inner = this.templateFor({ cond: 'inner', truthy: 'T-inner', falsy: 'F-inner' }); - let template = this.wrappedTemplateFor({ cond: 'outer', truthy: inner, falsy: 'F-outer' }); + let inner = this.templateFor({ + cond: 'inner', + truthy: 'T-inner', + falsy: 'F-inner' + }); + let template = this.wrappedTemplateFor({ + cond: 'outer', + truthy: inner, + falsy: 'F-outer' + }); this.render(template, { outer: this.truthyValue, inner: this.truthyValue }); @@ -742,9 +798,16 @@ export class TogglingSyntaxConditionalsTest extends TogglingConditionalsTest { ['@test it updates correctly when enclosing #each']() { // This tests whether the outer conditional tracks its bounds correctly as its inner bounds changes - let template = this.wrappedTemplateFor({ cond: 'outer', truthy: '{{#each inner as |text|}}{{text}}{{/each}}', falsy: 'F-outer' }); + let template = this.wrappedTemplateFor({ + cond: 'outer', + truthy: '{{#each inner as |text|}}{{text}}{{/each}}', + falsy: 'F-outer' + }); - this.render(template, { outer: this.truthyValue, inner: ['inner', '-', 'before'] }); + this.render(template, { + outer: this.truthyValue, + inner: ['inner', '-', 'before'] + }); this.assertText('inner-before'); @@ -783,9 +846,16 @@ export class TogglingSyntaxConditionalsTest extends TogglingConditionalsTest { ['@test it updates correctly when enclosing triple-curlies']() { // This tests whether the outer conditional tracks its bounds correctly as its inner bounds changes - let template = this.wrappedTemplateFor({ cond: 'outer', truthy: '{{{inner}}}', falsy: 'F-outer' }); + let template = this.wrappedTemplateFor({ + cond: 'outer', + truthy: '{{{inner}}}', + falsy: 'F-outer' + }); - this.render(template, { outer: this.truthyValue, inner: 'inner-before' }); + this.render(template, { + outer: this.truthyValue, + inner: 'inner-before' + }); this.assertText('inner-before'); @@ -804,7 +874,9 @@ export class TogglingSyntaxConditionalsTest extends TogglingConditionalsTest { this.assertText('F-outer'); } - ['@test child conditional should not render children if parent conditional becomes false'](assert) { + ['@test child conditional should not render children if parent conditional becomes false']( + assert + ) { let childCreated = false; this.registerComponent('foo-bar', { @@ -817,10 +889,21 @@ export class TogglingSyntaxConditionalsTest extends TogglingConditionalsTest { }) }); - let innerTemplate = this.templateFor({ cond: 'cond2', truthy: '{{foo-bar}}', falsy: '' }); - let wrappedTemplate = this.wrappedTemplateFor({ cond: 'cond1', truthy: innerTemplate, falsy: '' }); + let innerTemplate = this.templateFor({ + cond: 'cond2', + truthy: '{{foo-bar}}', + falsy: '' + }); + let wrappedTemplate = this.wrappedTemplateFor({ + cond: 'cond1', + truthy: innerTemplate, + falsy: '' + }); - this.render(wrappedTemplate, { cond1: this.truthyValue, cond2: this.falsyValue }); + this.render(wrappedTemplate, { + cond1: this.truthyValue, + cond2: this.falsyValue + }); assert.ok(!childCreated); this.assertText(''); @@ -851,13 +934,13 @@ export class TogglingSyntaxConditionalsTest extends TogglingConditionalsTest { let truthyEvaluated; let falsyEvaluated; - let withoutEvaluatingTruthy = (callback) => { + let withoutEvaluatingTruthy = callback => { truthyEvaluated = false; callback(); assert.ok(!truthyEvaluated, 'x-truthy is not evaluated'); }; - let withoutEvaluatingFalsy = (callback) => { + let withoutEvaluatingFalsy = callback => { falsyEvaluated = false; callback(); assert.ok(!falsyEvaluated, 'x-falsy is not evaluated'); @@ -877,9 +960,15 @@ export class TogglingSyntaxConditionalsTest extends TogglingConditionalsTest { } }); - let template = this.wrappedTemplateFor({ cond: 'cond', truthy: '{{x-truthy}}', falsy: '{{x-falsy}}' }); + let template = this.wrappedTemplateFor({ + cond: 'cond', + truthy: '{{x-truthy}}', + falsy: '{{x-falsy}}' + }); - withoutEvaluatingFalsy(() => this.render(template, { cond: this.truthyValue })); + withoutEvaluatingFalsy(() => + this.render(template, { cond: this.truthyValue }) + ); this.assertText('T'); @@ -887,7 +976,9 @@ export class TogglingSyntaxConditionalsTest extends TogglingConditionalsTest { this.assertText('T'); - withoutEvaluatingTruthy(() => this.runTask(() => set(this.context, 'cond', this.falsyValue))); + withoutEvaluatingTruthy(() => + this.runTask(() => set(this.context, 'cond', this.falsyValue)) + ); this.assertText('F'); @@ -895,11 +986,12 @@ export class TogglingSyntaxConditionalsTest extends TogglingConditionalsTest { this.assertText('F'); - withoutEvaluatingFalsy(() => this.runTask(() => set(this.context, 'cond', this.truthyValue))); + withoutEvaluatingFalsy(() => + this.runTask(() => set(this.context, 'cond', this.truthyValue)) + ); this.assertText('T'); } - } export class IfUnlessWithSyntaxTest extends TogglingSyntaxConditionalsTest {} diff --git a/packages/ember-glimmer/tests/utils/string-test.js b/packages/ember-glimmer/tests/utils/string-test.js index c3fe64b1934..1673952e5bf 100644 --- a/packages/ember-glimmer/tests/utils/string-test.js +++ b/packages/ember-glimmer/tests/utils/string-test.js @@ -2,40 +2,65 @@ import { SafeString, htmlSafe, isHTMLSafe } from './helpers'; import { TestCase } from './abstract-test-case'; import { moduleFor } from './test-case'; -moduleFor('SafeString', class extends TestCase { - ['@test htmlSafe should return an instance of SafeString']() { - let safeString = htmlSafe('you need to be more bold'); +moduleFor( + 'SafeString', + class extends TestCase { + ['@test htmlSafe should return an instance of SafeString']() { + let safeString = htmlSafe('you need to be more bold'); - this.assert.ok(safeString instanceof SafeString, 'should be a SafeString'); - } + this.assert.ok( + safeString instanceof SafeString, + 'should be a SafeString' + ); + } - ['@test htmlSafe should return an empty string for null']() { - let safeString = htmlSafe(null); + ['@test htmlSafe should return an empty string for null']() { + let safeString = htmlSafe(null); - this.assert.equal(safeString instanceof SafeString, true, 'should be a SafeString'); - this.assert.equal(safeString.toString(), '', 'should return an empty string'); - } + this.assert.equal( + safeString instanceof SafeString, + true, + 'should be a SafeString' + ); + this.assert.equal( + safeString.toString(), + '', + 'should return an empty string' + ); + } - ['@test htmlSafe should return an instance of SafeString']() { - let safeString = htmlSafe(); + ['@test htmlSafe should return an instance of SafeString']() { + let safeString = htmlSafe(); - this.assert.equal(safeString instanceof SafeString, true, 'should be a SafeString'); - this.assert.equal(safeString.toString(), '', 'should return an empty string'); + this.assert.equal( + safeString instanceof SafeString, + true, + 'should be a SafeString' + ); + this.assert.equal( + safeString.toString(), + '', + 'should return an empty string' + ); + } } -}); +); -moduleFor('SafeString isHTMLSafe', class extends TestCase { - ['@test isHTMLSafe should detect SafeString']() { - let safeString = htmlSafe('Emphasize the important things.'); +moduleFor( + 'SafeString isHTMLSafe', + class extends TestCase { + ['@test isHTMLSafe should detect SafeString']() { + let safeString = htmlSafe('Emphasize the important things.'); - this.assert.ok(isHTMLSafe(safeString)); - } + this.assert.ok(isHTMLSafe(safeString)); + } - ['@test isHTMLSafe should not detect SafeString on primatives']() { - this.assert.notOk(isHTMLSafe('Hello World')); - this.assert.notOk(isHTMLSafe({})); - this.assert.notOk(isHTMLSafe([])); - this.assert.notOk(isHTMLSafe(10)); - this.assert.notOk(isHTMLSafe(null)); + ['@test isHTMLSafe should not detect SafeString on primatives']() { + this.assert.notOk(isHTMLSafe('Hello World')); + this.assert.notOk(isHTMLSafe({})); + this.assert.notOk(isHTMLSafe([])); + this.assert.notOk(isHTMLSafe(10)); + this.assert.notOk(isHTMLSafe(null)); + } } -}); +); diff --git a/packages/ember-glimmer/tests/utils/test-case.js b/packages/ember-glimmer/tests/utils/test-case.js index 1f810177bad..b21b2018069 100644 --- a/packages/ember-glimmer/tests/utils/test-case.js +++ b/packages/ember-glimmer/tests/utils/test-case.js @@ -4,4 +4,3 @@ export { RenderingTestCase as RenderingTest, moduleFor } from 'internal-test-helpers'; - diff --git a/packages/ember-metal/lib/alias.js b/packages/ember-metal/lib/alias.js index b95b1a9128e..d3030fcb119 100644 --- a/packages/ember-metal/lib/alias.js +++ b/packages/ember-metal/lib/alias.js @@ -2,16 +2,10 @@ import { inspect } from 'ember-utils'; import { assert, Error as EmberError } from 'ember-debug'; import { get } from './property_get'; import { set } from './property_set'; -import { - Descriptor, - defineProperty -} from './properties'; +import { Descriptor, defineProperty } from './properties'; import { ComputedProperty, getCacheFor } from './computed'; import { meta as metaFor } from './meta'; -import { - addDependentKeys, - removeDependentKeys -} from './dependent_keys'; +import { addDependentKeys, removeDependentKeys } from './dependent_keys'; const CONSUMED = {}; @@ -74,8 +68,11 @@ export class AliasedProperty extends Descriptor { } } -function AliasedProperty_readOnlySet(obj, keyName, value) { // eslint-disable-line no-unused-vars - throw new EmberError(`Cannot set read-only property '${keyName}' on object: ${inspect(obj)}`); +function AliasedProperty_readOnlySet(obj, keyName) { + // eslint-disable-line no-unused-vars + throw new EmberError( + `Cannot set read-only property '${keyName}' on object: ${inspect(obj)}` + ); } function AliasedProperty_oneWaySet(obj, keyName, value) { diff --git a/packages/ember-metal/lib/array.js b/packages/ember-metal/lib/array.js index 1a77ca4ef9c..a7bdd9b63a1 100644 --- a/packages/ember-metal/lib/array.js +++ b/packages/ember-metal/lib/array.js @@ -1,9 +1,12 @@ -import { notifyPropertyChange } from "./property_events"; -import { eachProxyArrayDidChange, eachProxyArrayWillChange } from "./each_proxy"; -import { peekMeta } from "./meta"; -import { sendEvent, removeListener, addListener } from "./events"; -import { peekCacheFor } from "./computed"; -import { get } from "./property_get"; +import { notifyPropertyChange } from './property_events'; +import { + eachProxyArrayDidChange, + eachProxyArrayWillChange +} from './each_proxy'; +import { peekMeta } from './meta'; +import { sendEvent, removeListener, addListener } from './events'; +import { peekCacheFor } from './computed'; +import { get } from './property_get'; const EMPTY_ARRAY = Object.freeze([]); @@ -46,7 +49,7 @@ export function replaceInNativeArray(array, start, deleteCount, items) { function arrayObserversHelper(obj, target, opts, operation, notify) { let willChange = (opts && opts.willChange) || 'arrayWillChange'; - let didChange = (opts && opts.didChange) || 'arrayDidChange'; + let didChange = (opts && opts.didChange) || 'arrayDidChange'; let hasObservers = get(obj, 'hasArrayObservers'); operation(obj, '@array:before', target, willChange); @@ -119,8 +122,8 @@ export function arrayContentDidChange(array, startIdx, removeAmt, addAmt) { let cache = peekCacheFor(array); if (cache !== undefined) { let length = get(array, 'length'); - let addedAmount = (addAmt === -1 ? 0 : addAmt); - let removedAmount = (removeAmt === -1 ? 0 : removeAmt); + let addedAmount = addAmt === -1 ? 0 : addAmt; + let removedAmount = removeAmt === -1 ? 0 : removeAmt; let delta = addedAmount - removedAmount; let previousLength = length - delta; diff --git a/packages/ember-metal/lib/cache.js b/packages/ember-metal/lib/cache.js index 1d6e54a6ab6..c106c1cbd8a 100644 --- a/packages/ember-metal/lib/cache.js +++ b/packages/ember-metal/lib/cache.js @@ -2,26 +2,26 @@ import { UNDEFINED } from './meta'; export default class Cache { constructor(limit, func, key, store) { - this.size = 0; + this.size = 0; this.misses = 0; - this.hits = 0; - this.limit = limit; - this.func = func; - this.key = key; - this.store = store || new Map(); + this.hits = 0; + this.limit = limit; + this.func = func; + this.key = key; + this.store = store || new Map(); } get(obj) { let key = this.key === undefined ? obj : this.key(obj); let value = this.store.get(key); if (value === undefined) { - this.misses ++; + this.misses++; value = this._set(key, this.func(obj)); } else if (value === UNDEFINED) { - this.hits ++; + this.hits++; value = undefined; } else { - this.hits ++; + this.hits++; // nothing to translate } @@ -35,7 +35,7 @@ export default class Cache { _set(key, value) { if (this.limit > this.size) { - this.size ++; + this.size++; if (value === undefined) { this.store.set(key, UNDEFINED); } else { @@ -48,8 +48,8 @@ export default class Cache { purge() { this.store.clear(); - this.size = 0; - this.hits = 0; + this.size = 0; + this.hits = 0; this.misses = 0; } } diff --git a/packages/ember-metal/lib/chains.js b/packages/ember-metal/lib/chains.js index ea798a9fc6e..cc68002f77e 100644 --- a/packages/ember-metal/lib/chains.js +++ b/packages/ember-metal/lib/chains.js @@ -91,7 +91,7 @@ class ChainWatchers { // we gather callbacks so we don't notify them during revalidation for (let i = 0; i < affected.length; i += 2) { - let obj = affected[i]; + let obj = affected[i]; let path = affected[i + 1]; callback(obj, path); } @@ -113,7 +113,9 @@ function addChainWatcher(obj, keyName, node) { } function removeChainWatcher(obj, keyName, node, _meta) { - if (!isObject(obj)) { return; } + if (!isObject(obj)) { + return; + } let meta = _meta === undefined ? peekMeta(obj) : _meta; @@ -135,7 +137,7 @@ function removeChainWatcher(obj, keyName, node, _meta) { class ChainNode { constructor(parent, key, value) { this._parent = parent; - this._key = key; + this._key = key; this._chains = undefined; this._object = undefined; @@ -150,7 +152,7 @@ class ChainNode { // It is false for the root of a chain (because we have no parent) // and for global paths (because the parent node is the object with // the observer on it) - let isWatching = this._isWatching = (value === undefined); + let isWatching = (this._isWatching = value === undefined); if (isWatching) { let obj = parent.value(); @@ -186,7 +188,9 @@ class ChainNode { if (paths !== undefined) { let path; for (path in paths) { - if (paths[path] > 0) { ret.add(path); } + if (paths[path] > 0) { + ret.add(path); + } } } return ret; @@ -206,7 +210,9 @@ class ChainNode { // path remove(path) { let paths = this._paths; - if (paths === undefined) { return; } + if (paths === undefined) { + return; + } if (paths[path] > 0) { paths[path]--; } @@ -317,7 +323,7 @@ function lazyGet(obj, key) { return eachProxyFor(obj); } else if (isVolatile(obj, key, meta)) { return get(obj, key); - // Otherwise attempt to get the cached value of the computed property + // Otherwise attempt to get the cached value of the computed property } else { return getCachedValueFor(obj, key); } @@ -336,9 +342,4 @@ function finishChains(meta) { } } -export { - finishChains, - makeChainNode, - removeChainWatcher, - ChainNode -}; +export { finishChains, makeChainNode, removeChainWatcher, ChainNode }; diff --git a/packages/ember-metal/lib/computed.js b/packages/ember-metal/lib/computed.js index 42c3b783c9e..d1119268b4a 100644 --- a/packages/ember-metal/lib/computed.js +++ b/packages/ember-metal/lib/computed.js @@ -4,17 +4,9 @@ import { set } from './property_set'; import { meta as metaFor, peekMeta } from './meta'; import { EMBER_METAL_TRACKED_PROPERTIES } from 'ember/features'; import expandProperties from './expand_properties'; -import { - Descriptor, - defineProperty -} from './properties'; -import { - notifyPropertyChange -} from './property_events'; -import { - addDependentKeys, - removeDependentKeys -} from './dependent_keys'; +import { Descriptor, defineProperty } from './properties'; +import { notifyPropertyChange } from './property_events'; +import { addDependentKeys, removeDependentKeys } from './dependent_keys'; import { getCurrentTracker, setCurrentTracker } from './tracked'; import { tagForProperty, update } from './tags'; @@ -142,9 +134,18 @@ class ComputedProperty extends Descriptor { if (hasGetterOnly) { this._getter = config; } else { - assert('computed expects a function or an object as last argument.', typeof config === 'object' && !Array.isArray(config)); - assert('Config object passed to computed can only contain `get` and `set` keys.', Object.keys(config).every((key)=> key === 'get' || key === 'set')); - assert('Computed properties must receive a getter or a setter, you passed none.', !!config.get || !!config.set); + assert( + 'computed expects a function or an object as last argument.', + typeof config === 'object' && !Array.isArray(config) + ); + assert( + 'Config object passed to computed can only contain `get` and `set` keys.', + Object.keys(config).every(key => key === 'get' || key === 'set') + ); + assert( + 'Computed properties must receive a getter or a setter, you passed none.', + !!config.get || !!config.set + ); this._getter = config.get || noop; this._setter = config.set; } @@ -216,7 +217,10 @@ class ComputedProperty extends Descriptor { */ readOnly() { this._readOnly = true; - assert('Computed properties that define a setter using the new syntax cannot be read-only', !(this._readOnly && this._setter && this._setter !== this._getter)); + assert( + 'Computed properties that define a setter using the new syntax cannot be read-only', + !(this._readOnly && this._setter && this._setter !== this._getter) + ); return this; } @@ -257,7 +261,7 @@ class ComputedProperty extends Descriptor { warn( `Dependent keys containing @each only work one level deep. ` + `You used the key "${property}" which is invalid. ` + - `Please create an intermediary computed property.`, + `Please create an intermediary computed property.`, DEEP_EACH_REGEX.test(property) === false, { id: 'ember-metal.computed-deep-each' } ); @@ -343,7 +347,10 @@ class ComputedProperty extends Descriptor { if (cache.has(keyName)) { // special-case for computed with no dependent keys used to // trigger cacheable behavior. - if (!this._auto && (!this._dependentKeys || this._dependentKeys.length === 0)) { + if ( + !this._auto && + (!this._dependentKeys || this._dependentKeys.length === 0) + ) { return cache.get(keyName); } @@ -406,7 +413,9 @@ class ComputedProperty extends Descriptor { } _throwReadOnlyError(obj, keyName) { - throw new EmberError(`Cannot set read-only property "${keyName}" on object: ${inspect(obj)}`); + throw new EmberError( + `Cannot set read-only property "${keyName}" on object: ${inspect(obj)}` + ); } clobberSet(obj, keyName, value) { @@ -579,7 +588,9 @@ export default function computed(...args) { } const COMPUTED_PROPERTY_CACHED_VALUES = new WeakMap(); -const COMPUTED_PROPERTY_LAST_REVISION = EMBER_METAL_TRACKED_PROPERTIES ? new WeakMap() : undefined; +const COMPUTED_PROPERTY_LAST_REVISION = EMBER_METAL_TRACKED_PROPERTIES + ? new WeakMap() + : undefined; /** Returns the cached value for a property, if one exists. @@ -640,7 +651,4 @@ export function peekCacheFor(obj) { return COMPUTED_PROPERTY_CACHED_VALUES.get(obj); } -export { - ComputedProperty, - computed -}; +export { ComputedProperty, computed }; diff --git a/packages/ember-metal/lib/core.js b/packages/ember-metal/lib/core.js index b1ee12b1af3..7396fc750b3 100644 --- a/packages/ember-metal/lib/core.js +++ b/packages/ember-metal/lib/core.js @@ -1,10 +1,13 @@ import { context } from 'ember-environment'; -const Ember = (typeof context.imports.Ember === 'object' && context.imports.Ember) || {}; +const Ember = + (typeof context.imports.Ember === 'object' && context.imports.Ember) || {}; // Make sure these are set whether Ember was already defined or not Ember.isNamespace = true; -Ember.toString = function() { return 'Ember'; }; +Ember.toString = function() { + return 'Ember'; +}; // .......................................................... // BOOTSTRAP diff --git a/packages/ember-metal/lib/dependent_keys.js b/packages/ember-metal/lib/dependent_keys.js index a1d188490b6..061a06f7fa1 100644 --- a/packages/ember-metal/lib/dependent_keys.js +++ b/packages/ember-metal/lib/dependent_keys.js @@ -1,7 +1,4 @@ -import { - watch, - unwatch -} from './watching'; +import { watch, unwatch } from './watching'; // .......................................................... // DEPENDENT KEYS diff --git a/packages/ember-metal/lib/deprecate_property.js b/packages/ember-metal/lib/deprecate_property.js index de1d4dc87cd..51c363ea11d 100644 --- a/packages/ember-metal/lib/deprecate_property.js +++ b/packages/ember-metal/lib/deprecate_property.js @@ -6,7 +6,6 @@ import { deprecate } from 'ember-debug'; import { get } from './property_get'; import { set } from './property_set'; - /** Used internally to allow changing properties in a backwards compatible way, and print a helpful deprecation warning. diff --git a/packages/ember-metal/lib/descriptor.js b/packages/ember-metal/lib/descriptor.js index b579aedec1c..47a5b546bf4 100644 --- a/packages/ember-metal/lib/descriptor.js +++ b/packages/ember-metal/lib/descriptor.js @@ -28,9 +28,8 @@ class Descriptor extends EmberDescriptor { } set(obj, key, value) { - return obj[key] = value; + return (obj[key] = value); } - teardown() { - } + teardown() {} } diff --git a/packages/ember-metal/lib/each_proxy.js b/packages/ember-metal/lib/each_proxy.js index 69952f89de2..1f5fddbd360 100644 --- a/packages/ember-metal/lib/each_proxy.js +++ b/packages/ember-metal/lib/each_proxy.js @@ -41,7 +41,8 @@ class EachProxy { // ARRAY CHANGES // Invokes whenever the content array itself changes. - arrayWillChange(content, idx, removedCnt, addedCnt) { // eslint-disable-line no-unused-vars + arrayWillChange(content, idx, removedCnt /*, addedCnt */) { + // eslint-disable-line no-unused-vars let keys = this._keys; let lim = removedCnt > 0 ? idx + removedCnt : -1; if (lim > 0) { @@ -98,7 +99,7 @@ class EachProxy { stopObservingContentKey(keyName) { let keys = this._keys; - if (keys !== undefined && (keys[keyName] > 0) && (--keys[keyName] <= 0)) { + if (keys !== undefined && keys[keyName] > 0 && --keys[keyName] <= 0) { let content = this._content; let len = get(content, 'length'); @@ -115,7 +116,12 @@ function addObserverForContentKey(content, keyName, proxy, idx, loc) { while (--loc >= idx) { let item = objectAt(content, loc); if (item) { - assert(`When using @each to observe the array \`${toString(content)}\`, the array must return an object`, typeof item === 'object'); + assert( + `When using @each to observe the array \`${toString( + content + )}\`, the array must return an object`, + typeof item === 'object' + ); addObserver(item, keyName, proxy, 'contentKeyDidChange'); } } diff --git a/packages/ember-metal/lib/events.js b/packages/ember-metal/lib/events.js index 3e759d9cc1f..e1736371a2d 100644 --- a/packages/ember-metal/lib/events.js +++ b/packages/ember-metal/lib/events.js @@ -37,7 +37,10 @@ import { meta as metaFor, peekMeta } from './meta'; @public */ export function addListener(obj, eventName, target, method, once) { - assert('You must pass at least an object and event name to addListener', !!obj && !!eventName); + assert( + 'You must pass at least an object and event name to addListener', + !!obj && !!eventName + ); if (ENV._ENABLE_DID_INIT_ATTRS_SUPPORT === true) { deprecate( @@ -46,12 +49,17 @@ export function addListener(obj, eventName, target, method, once) { { id: 'ember-views.did-init-attrs', until: '3.0.0', - url: 'https://emberjs.com/deprecations/v2.x#toc_ember-component-didinitattrs' + url: + 'https://emberjs.com/deprecations/v2.x#toc_ember-component-didinitattrs' } ); - } - else { - assert(`didInitAttrs called in ${obj && obj.toString && obj.toString()} is no longer supported.`, eventName !== 'didInitAttrs'); + } else { + assert( + `didInitAttrs called in ${obj && + obj.toString && + obj.toString()} is no longer supported.`, + eventName !== 'didInitAttrs' + ); } if (!method && 'function' === typeof target) { @@ -77,7 +85,10 @@ export function addListener(obj, eventName, target, method, once) { @public */ export function removeListener(obj, eventName, target, method) { - assert('You must pass at least an object and event name to removeListener', !!obj && !!eventName); + assert( + 'You must pass at least an object and event name to removeListener', + !!obj && !!eventName + ); if (!method && 'function' === typeof target) { method = target; @@ -107,21 +118,31 @@ export function removeListener(obj, eventName, target, method) { export function sendEvent(obj, eventName, params, actions, _meta) { if (actions === undefined) { let meta = _meta === undefined ? peekMeta(obj) : _meta; - actions = typeof meta === 'object' && + actions = + typeof meta === 'object' && meta !== null && meta.matchingListeners(eventName); } - if (actions === undefined || actions.length === 0) { return false; } + if (actions === undefined || actions.length === 0) { + return false; + } - for (let i = actions.length - 3; i >= 0; i -= 3) { // looping in reverse for once listeners + for (let i = actions.length - 3; i >= 0; i -= 3) { + // looping in reverse for once listeners let target = actions[i]; let method = actions[i + 1]; let once = actions[i + 2]; - if (!method) { continue; } - if (once) { removeListener(obj, eventName, target, method); } - if (!target) { target = obj; } + if (!method) { + continue; + } + if (once) { + removeListener(obj, eventName, target, method); + } + if (!target) { + target = obj; + } if ('string' === typeof method) { method = target[method]; } @@ -141,7 +162,9 @@ export function sendEvent(obj, eventName, params, actions, _meta) { */ export function hasListeners(obj, eventName) { let meta = peekMeta(obj); - if (meta === undefined) { return false; } + if (meta === undefined) { + return false; + } let matched = meta.matchingListeners(eventName); return matched !== undefined && matched.length > 0; } @@ -180,7 +203,10 @@ export function on(...args) { let events = args; assert('on expects function as last argument', typeof func === 'function'); - assert('on called without valid event names', events.length > 0 && events.every((p)=> typeof p === 'string' && p.length)); + assert( + 'on called without valid event names', + events.length > 0 && events.every(p => typeof p === 'string' && p.length) + ); func.__ember_listens__ = events; return func; diff --git a/packages/ember-metal/lib/expand_properties.js b/packages/ember-metal/lib/expand_properties.js index b7193fcf6b2..fafa45dc18f 100644 --- a/packages/ember-metal/lib/expand_properties.js +++ b/packages/ember-metal/lib/expand_properties.js @@ -37,7 +37,10 @@ const END_WITH_EACH_REGEX = /\.@each$/; expansion, and is passed the expansion. */ export default function expandProperties(pattern, callback) { - assert(`A computed property key must be a string, you passed ${typeof pattern} ${pattern}`, typeof pattern === 'string'); + assert( + `A computed property key must be a string, you passed ${typeof pattern} ${pattern}`, + typeof pattern === 'string' + ); assert( 'Brace expanded properties cannot contain spaces, e.g. "user.{firstName, lastName}" should be "user.{firstName,lastName}"', pattern.indexOf(' ') === -1 @@ -45,12 +48,12 @@ export default function expandProperties(pattern, callback) { // regex to look for double open, double close, or unclosed braces assert( `Brace expanded properties have to be balanced and cannot be nested, pattern: ${pattern}`, - pattern.match( /\{[^}{]*\{|\}[^}{]*\}|\{[^}]*$/g ) === null + pattern.match(/\{[^}{]*\{|\}[^}{]*\}|\{[^}]*$/g) === null ); let start = pattern.indexOf('{'); if (start < 0) { - callback( pattern.replace(END_WITH_EACH_REGEX, '.[]') ); + callback(pattern.replace(END_WITH_EACH_REGEX, '.[]')); } else { dive('', pattern, start, callback); } @@ -58,9 +61,9 @@ export default function expandProperties(pattern, callback) { function dive(prefix, pattern, start, callback) { let end = pattern.indexOf('}'), - i = 0, - newStart, - arrayLength; + i = 0, + newStart, + arrayLength; let tempArr = pattern.substring(start + 1, end).split(','); let after = pattern.substring(end + 1); prefix = prefix + pattern.substring(0, start); @@ -69,7 +72,9 @@ function dive(prefix, pattern, start, callback) { while (i < arrayLength) { newStart = after.indexOf('{'); if (newStart < 0) { - callback((prefix + tempArr[i++] + after).replace(END_WITH_EACH_REGEX, '.[]')); + callback( + (prefix + tempArr[i++] + after).replace(END_WITH_EACH_REGEX, '.[]') + ); } else { dive(prefix + tempArr[i++], after, newStart, callback); } diff --git a/packages/ember-metal/lib/index.js b/packages/ember-metal/lib/index.js index 60b909c7d3e..ddbb4bc1e36 100644 --- a/packages/ember-metal/lib/index.js +++ b/packages/ember-metal/lib/index.js @@ -71,7 +71,7 @@ export { cancel, debounce, throttle, - _globalsRun, + _globalsRun } from './run_loop'; export { beginPropertyChanges, diff --git a/packages/ember-metal/lib/injected_property.js b/packages/ember-metal/lib/injected_property.js index 887ed0ef6e0..447a664fcd1 100644 --- a/packages/ember-metal/lib/injected_property.js +++ b/packages/ember-metal/lib/injected_property.js @@ -32,7 +32,7 @@ export default class InjectedProperty extends ComputedProperty { this.name = name; this.namespace = undefined; } else { - this.name = name.slice(namespaceDelimiterOffset+2); + this.name = name.slice(namespaceDelimiterOffset + 2); this.namespace = name.slice(0, namespaceDelimiterOffset); } } else { @@ -45,9 +45,18 @@ function injectedPropertyGet(keyName) { let desc = descriptorFor(this, keyName); let owner = getOwner(this) || this.container; // fallback to `container` for backwards compat - assert(`InjectedProperties should be defined with the inject computed property macros.`, desc && desc.type); - assert(`Attempting to lookup an injected property on an object without a container, ensure that the object was instantiated via a container.`, owner); + assert( + `InjectedProperties should be defined with the inject computed property macros.`, + desc && desc.type + ); + assert( + `Attempting to lookup an injected property on an object without a container, ensure that the object was instantiated via a container.`, + owner + ); let specifier = `${desc.type}:${desc.name || keyName}`; - return owner.lookup(specifier, {source: desc.source, namespace: desc.namespace}); + return owner.lookup(specifier, { + source: desc.source, + namespace: desc.namespace + }); } diff --git a/packages/ember-metal/lib/instrumentation.js b/packages/ember-metal/lib/instrumentation.js index 80b722590fc..e0e4d67db78 100644 --- a/packages/ember-metal/lib/instrumentation.js +++ b/packages/ember-metal/lib/instrumentation.js @@ -81,9 +81,11 @@ const time = (() => { let perf = 'undefined' !== typeof window ? window.performance || {} : {}; let fn = perf.now || perf.mozNow || perf.webkitNow || perf.msNow || perf.oNow; // fn.bind will be available in all the browsers that support the advanced window.performance... ;-) - return fn ? fn.bind(perf) : () => { - return +new Date(); - }; + return fn + ? fn.bind(perf) + : () => { + return +new Date(); + }; })(); /** diff --git a/packages/ember-metal/lib/libraries.js b/packages/ember-metal/lib/libraries.js index 831e0e97839..08235744b17 100644 --- a/packages/ember-metal/lib/libraries.js +++ b/packages/ember-metal/lib/libraries.js @@ -40,7 +40,9 @@ export class Libraries { } this._registry.splice(index, 0, { name, version }); } else { - warn(`Library "${name}" is already registered with Ember.`, false, { id: 'ember-metal.libraries-register' }); + warn(`Library "${name}" is already registered with Ember.`, false, { + id: 'ember-metal.libraries-register' + }); } } diff --git a/packages/ember-metal/lib/map.js b/packages/ember-metal/lib/map.js index e8e2ebac500..e00059c3aba 100644 --- a/packages/ember-metal/lib/map.js +++ b/packages/ember-metal/lib/map.js @@ -144,7 +144,9 @@ class OrderedSet { @private */ has(obj) { - if (this.size === 0) { return false; } + if (this.size === 0) { + return false; + } let guid = guidFor(obj); let presenceSet = this.presenceSet; @@ -159,9 +161,14 @@ class OrderedSet { @private */ forEach(fn /*, ...thisArg*/) { - assert(`${Object.prototype.toString.call(fn)} is not a function`, typeof fn === 'function'); + assert( + `${Object.prototype.toString.call(fn)} is not a function`, + typeof fn === 'function' + ); - if (this.size === 0) { return; } + if (this.size === 0) { + return; + } let list = this.list; @@ -247,7 +254,9 @@ class Map { @private */ get(key) { - if (this.size === 0) { return; } + if (this.size === 0) { + return; + } let values = this._values; let guid = guidFor(key); @@ -292,7 +301,9 @@ class Map { @private */ delete(key) { - if (this.size === 0) { return false; } + if (this.size === 0) { + return false; + } // don't use ES6 "delete" because it will be annoying // to use in browsers that are not ES6 friendly; let keys = this._keys; @@ -333,10 +344,15 @@ class Map { callback. By default, `this` is the map. @private */ - forEach(callback/*, ...thisArg*/) { - assert(`${Object.prototype.toString.call(callback)} is not a function`, typeof callback === 'function'); - - if (this.size === 0) { return; } + forEach(callback /*, ...thisArg*/) { + assert( + `${Object.prototype.toString.call(callback)} is not a function`, + typeof callback === 'function' + ); + + if (this.size === 0) { + return; + } let map = this; let cb, thisArg; @@ -429,17 +445,15 @@ class MapWithDefault extends Map { */ copy() { let Constructor = this.constructor; - return copyMap(this, new Constructor({ - defaultValue: this.defaultValue - })); + return copyMap( + this, + new Constructor({ + defaultValue: this.defaultValue + }) + ); } } - export default Map; -export { - OrderedSet, - Map, - MapWithDefault -}; +export { OrderedSet, Map, MapWithDefault }; diff --git a/packages/ember-metal/lib/meta_listeners.js b/packages/ember-metal/lib/meta_listeners.js index 96d0496d3d1..ff01c96e200 100644 --- a/packages/ember-metal/lib/meta_listeners.js +++ b/packages/ember-metal/lib/meta_listeners.js @@ -11,22 +11,29 @@ */ export const protoMethods = { - addToListeners(eventName, target, method, once) { - if (this._listeners === undefined) { this._listeners = []; } + if (this._listeners === undefined) { + this._listeners = []; + } this._listeners.push(eventName, target, method, once); }, _finalizeListeners() { - if (this._listenersFinalized) { return; } - if (this._listeners === undefined) { this._listeners = []; } + if (this._listenersFinalized) { + return; + } + if (this._listeners === undefined) { + this._listeners = []; + } let pointer = this.parent; while (pointer !== undefined) { let listeners = pointer._listeners; if (listeners !== undefined) { this._listeners = this._listeners.concat(listeners); } - if (pointer._listenersFinalized) { break; } + if (pointer._listenersFinalized) { + break; + } pointer = pointer.parent; } this._listenersFinalized = true; @@ -38,7 +45,12 @@ export const protoMethods = { let listeners = pointer._listeners; if (listeners !== undefined) { for (let index = listeners.length - 4; index >= 0; index -= 4) { - if (listeners[index] === eventName && (!method || (listeners[index + 1] === target && listeners[index + 2] === method))) { + if ( + listeners[index] === eventName && + (!method || + (listeners[index + 1] === target && + listeners[index + 2] === method)) + ) { if (pointer === this) { listeners.splice(index, 4); // we are modifying our own list, so we edit directly } else { @@ -51,7 +63,9 @@ export const protoMethods = { } } } - if (pointer._listenersFinalized) { break; } + if (pointer._listenersFinalized) { + break; + } pointer = pointer.parent; } }, @@ -69,7 +83,9 @@ export const protoMethods = { } } } - if (pointer._listenersFinalized) { break; } + if (pointer._listenersFinalized) { + break; + } pointer = pointer.parent; } return result; @@ -79,8 +95,15 @@ export const protoMethods = { function pushUniqueListener(destination, source, index) { let target = source[index + 1]; let method = source[index + 2]; - for (let destinationIndex = 0; destinationIndex < destination.length; destinationIndex += 3) { - if (destination[destinationIndex] === target && destination[destinationIndex + 1] === method) { + for ( + let destinationIndex = 0; + destinationIndex < destination.length; + destinationIndex += 3 + ) { + if ( + destination[destinationIndex] === target && + destination[destinationIndex + 1] === method + ) { return; } } diff --git a/packages/ember-metal/lib/observer.js b/packages/ember-metal/lib/observer.js index 87ac4e83140..4ea655c814b 100644 --- a/packages/ember-metal/lib/observer.js +++ b/packages/ember-metal/lib/observer.js @@ -1,11 +1,5 @@ -import { - watch, - unwatch -} from './watching'; -import { - addListener, - removeListener -} from './events'; +import { watch, unwatch } from './watching'; +import { addListener, removeListener } from './events'; /** @module @ember/object */ diff --git a/packages/ember-metal/lib/properties.js b/packages/ember-metal/lib/properties.js index a336a9193ad..6519d4cc62d 100644 --- a/packages/ember-metal/lib/properties.js +++ b/packages/ember-metal/lib/properties.js @@ -4,9 +4,19 @@ import { assert } from 'ember-debug'; import { HAS_NATIVE_PROXY, HAS_NATIVE_SYMBOL } from 'ember-utils'; -import { descriptorFor, meta as metaFor, peekMeta, DESCRIPTOR, UNDEFINED } from './meta'; +import { + descriptorFor, + meta as metaFor, + peekMeta, + DESCRIPTOR, + UNDEFINED +} from './meta'; import { overrideChains } from './property_events'; -import { DESCRIPTOR_TRAP, EMBER_METAL_ES5_GETTERS, MANDATORY_SETTER } from 'ember/features'; +import { + DESCRIPTOR_TRAP, + EMBER_METAL_ES5_GETTERS, + MANDATORY_SETTER +} from 'ember/features'; // .......................................................... // DESCRIPTOR // @@ -35,7 +45,10 @@ export function MANDATORY_SETTER_FUNCTION(name) { if (!m.isInitialized(this)) { m.writeValues(name, value); } else { - assert(`You must use set() to set the \`${name}\` property (of ${this}) to \`${value}\`.`, false); + assert( + `You must use set() to set the \`${name}\` property (of ${this}) to \`${value}\`.`, + false + ); } } @@ -85,7 +98,8 @@ if (EMBER_METAL_ES5_GETTERS) { // development to aid in development asertions. Production builds of // ember strip this entire branch out. let messageFor = function(obj, keyName, property, value) { - return `You attempted to access \`${keyName}.${String(property)}\` ` + + return ( + `You attempted to access \`${keyName}.${String(property)}\` ` + `(on \`${obj}\`), but \`${keyName}\` is a computed property.\n\n` + `Due to certain internal implementation details of Ember, the ` + `\`${keyName}\` property previously contained a private "descriptor" ` + @@ -103,7 +117,8 @@ if (EMBER_METAL_ES5_GETTERS) { `to offer some help.\n\n` + `If you are an addon author and need help transitioning your code, ` + `please get in touch in the #dev-ember channel in the Ember Community ` + - `Slack.`; + `Slack.` + ); }; let trapFor; @@ -127,8 +142,8 @@ if (EMBER_METAL_ES5_GETTERS) { property === 'valueOf' || property === 'inspect' || property === 'toJSON' || - HAS_NATIVE_SYMBOL && property === Symbol.toPrimitive || - HAS_NATIVE_SYMBOL && property === Symbol.toStringTag + (HAS_NATIVE_SYMBOL && property === Symbol.toPrimitive) || + (HAS_NATIVE_SYMBOL && property === Symbol.toStringTag) ) { return () => '[COMPUTED PROPERTY]'; } @@ -149,9 +164,18 @@ if (EMBER_METAL_ES5_GETTERS) { }); trap.toString = trap.toJSON = trap.valueOf = () => '[COMPUTED PROPERTY]'; - + // Without a proxy, we can only trap the "likely" properties - ['isDescriptor', 'setup', 'teardown', 'get', '_getter', 'set', '_setter', 'meta'].forEach(property => { + [ + 'isDescriptor', + 'setup', + 'teardown', + 'get', + '_getter', + 'set', + '_setter', + 'meta' + ].forEach(property => { Object.defineProperty(trap, property, { configurable: false, enumerable: false, @@ -168,7 +192,9 @@ if (EMBER_METAL_ES5_GETTERS) { DESCRIPTOR_GETTER_FUNCTION = function(name, descriptor) { let trap; return function CPGETTER_FUNCTION() { - if (trap) { return trap; } + if (trap) { + return trap; + } trap = trapFor(this, name, descriptor); return trap; @@ -224,7 +250,9 @@ if (EMBER_METAL_ES5_GETTERS) { become the explicit value of this property. */ export function defineProperty(obj, keyName, desc, data, meta) { - if (meta === undefined) { meta = metaFor(obj); } + if (meta === undefined) { + meta = metaFor(obj); + } let watchEntry = meta.peekWatching(keyName); let watching = watchEntry !== undefined && watchEntry > 0; @@ -283,7 +311,9 @@ export function defineProperty(obj, keyName, desc, data, meta) { meta.writeDescriptors(keyName, value); } - if (typeof desc.setup === 'function') { desc.setup(obj, keyName); } + if (typeof desc.setup === 'function') { + desc.setup(obj, keyName); + } } else if (desc === undefined || desc === null) { value = data; @@ -324,11 +354,15 @@ export function defineProperty(obj, keyName, desc, data, meta) { // if key is being watched, override chains that // were initialized with the prototype - if (watching) { overrideChains(obj, keyName, meta); } + if (watching) { + overrideChains(obj, keyName, meta); + } // The `value` passed to the `didDefineProperty` hook is // either the descriptor or data, whichever was passed. - if (typeof obj.didDefineProperty === 'function') { obj.didDefineProperty(obj, keyName, value); } + if (typeof obj.didDefineProperty === 'function') { + obj.didDefineProperty(obj, keyName, value); + } return this; } diff --git a/packages/ember-metal/lib/property_events.js b/packages/ember-metal/lib/property_events.js index cc06138b45a..0a526b8c4cc 100644 --- a/packages/ember-metal/lib/property_events.js +++ b/packages/ember-metal/lib/property_events.js @@ -1,18 +1,9 @@ import { symbol } from 'ember-utils'; -import { - descriptorFor, - peekMeta -} from './meta'; -import { - sendEvent -} from './events'; -import { - markObjectAsDirty -} from './tags'; +import { descriptorFor, peekMeta } from './meta'; +import { sendEvent } from './events'; +import { markObjectAsDirty } from './tags'; import ObserverSet from './observer_set'; -import { - EMBER_GLIMMER_DETECT_BACKTRACKING_RERENDER, -} from 'ember/features'; +import { EMBER_GLIMMER_DETECT_BACKTRACKING_RERENDER } from 'ember/features'; import { deprecate } from 'ember-debug'; import { assertNotRendered } from './transaction'; import { changeEvent } from './observer'; @@ -43,7 +34,8 @@ function propertyWillChange() { { id: 'ember-metal.deprecate-propertyWillChange', until: '3.5.0', - url: 'https://emberjs.com/deprecations/v3.x/#toc_use-notifypropertychange-instead-of-propertywillchange-and-propertydidchange' + url: + 'https://emberjs.com/deprecations/v3.x/#toc_use-notifypropertychange-instead-of-propertywillchange-and-propertydidchange' } ); } @@ -60,7 +52,8 @@ function propertyDidChange(obj, keyName, _meta) { { id: 'ember-metal.deprecate-propertyDidChange', until: '3.5.0', - url: 'https://emberjs.com/deprecations/v3.x/#toc_use-notifypropertychange-instead-of-propertywillchange-and-propertydidchange' + url: + 'https://emberjs.com/deprecations/v3.x/#toc_use-notifypropertychange-instead-of-propertywillchange-and-propertydidchange' } ); @@ -87,7 +80,9 @@ function notifyPropertyChange(obj, keyName, _meta) { let meta = _meta === undefined ? peekMeta(obj) : _meta; let hasMeta = meta !== undefined; - if (hasMeta && !meta.isInitialized(obj)) { return; } + if (hasMeta && !meta.isInitialized(obj)) { + return; + } let possibleDesc = descriptorFor(obj, keyName, meta); @@ -107,7 +102,9 @@ function notifyPropertyChange(obj, keyName, _meta) { } if (hasMeta) { - if (meta.isSourceDestroying()) { return; } + if (meta.isSourceDestroying()) { + return; + } markObjectAsDirty(obj, keyName, meta); } @@ -121,7 +118,9 @@ let IS_TOP_SEEN_MAP = true; // called whenever a property has just changed to update dependent keys function dependentKeysDidChange(obj, depKey, meta) { - if (meta.isSourceDestroying() || !meta.hasDeps(depKey)) { return; } + if (meta.isSourceDestroying() || !meta.hasDeps(depKey)) { + return; + } let seen = SEEN_MAP; let isTop = IS_TOP_SEEN_MAP; @@ -145,11 +144,15 @@ function iterDeps(method, obj, depKey, seen, meta) { seen.set(obj, current); } - if (current.has(depKey)) { return; } + if (current.has(depKey)) { + return; + } let possibleDesc; meta.forEachInDeps(depKey, (key, value) => { - if (!value) { return; } + if (!value) { + return; + } possibleDesc = descriptorFor(obj, key, meta); @@ -220,7 +223,9 @@ function changeProperties(callback) { } function notifyObservers(obj, keyName, meta) { - if (meta.isSourceDestroying()) { return; } + if (meta.isSourceDestroying()) { + return; + } let eventName = changeEvent(keyName); if (deferred > 0) { diff --git a/packages/ember-metal/lib/property_get.js b/packages/ember-metal/lib/property_get.js index ea2d4d7a03c..dd678cd18df 100644 --- a/packages/ember-metal/lib/property_get.js +++ b/packages/ember-metal/lib/property_get.js @@ -4,9 +4,19 @@ import { assert, deprecate } from 'ember-debug'; import { HAS_NATIVE_PROXY, symbol } from 'ember-utils'; -import { DESCRIPTOR_TRAP, EMBER_METAL_ES5_GETTERS, EMBER_METAL_TRACKED_PROPERTIES, MANDATORY_GETTER } from 'ember/features'; +import { + DESCRIPTOR_TRAP, + EMBER_METAL_ES5_GETTERS, + EMBER_METAL_TRACKED_PROPERTIES, + MANDATORY_GETTER +} from 'ember/features'; import { isPath } from './path_cache'; -import { isDescriptor, isDescriptorTrap, DESCRIPTOR, descriptorFor } from './meta'; +import { + isDescriptor, + isDescriptorTrap, + DESCRIPTOR, + descriptorFor +} from './meta'; import { getCurrentTracker } from './tracked'; import { tagForProperty } from './tags'; @@ -32,7 +42,6 @@ export function getPossibleMandatoryProxyValue(obj, keyName) { } } - // .......................................................... // GET AND SET // @@ -72,10 +81,23 @@ export function getPossibleMandatoryProxyValue(obj, keyName) { @public */ export function get(obj, keyName) { - assert(`Get must be called with two arguments; an object and a property key`, arguments.length === 2); - assert(`Cannot call get with '${keyName}' on an undefined object.`, obj !== undefined && obj !== null); - assert(`The key provided to get must be a string or number, you passed ${keyName}`, typeof keyName === 'string' || (typeof keyName === 'number' && !isNaN(keyName))); - assert(`'this' in paths is not supported`, typeof keyName !== 'string' || keyName.lastIndexOf('this.', 0) !== 0); + assert( + `Get must be called with two arguments; an object and a property key`, + arguments.length === 2 + ); + assert( + `Cannot call get with '${keyName}' on an undefined object.`, + obj !== undefined && obj !== null + ); + assert( + `The key provided to get must be a string or number, you passed ${keyName}`, + typeof keyName === 'string' || + (typeof keyName === 'number' && !isNaN(keyName)) + ); + assert( + `'this' in paths is not supported`, + typeof keyName !== 'string' || keyName.lastIndexOf('this.', 0) !== 0 + ); assert('Cannot call `get` with an empty string', keyName !== ''); let type = typeof obj; @@ -104,12 +126,15 @@ export function get(obj, keyName) { descriptor = value[DESCRIPTOR]; } else if (isDescriptor(value)) { deprecate( - `[DEPRECATED] computed property '${keyName}' was not set on object '${obj && obj.toString && obj.toString()}' via 'defineProperty'`, + `[DEPRECATED] computed property '${keyName}' was not set on object '${obj && + obj.toString && + obj.toString()}' via 'defineProperty'`, !EMBER_METAL_ES5_GETTERS, { id: 'ember-meta.descriptor-on-object', until: '3.5.0', - url: 'https://emberjs.com/deprecations/v3.x#toc_use-defineProperty-to-define-computed-properties' + url: + 'https://emberjs.com/deprecations/v3.x#toc_use-defineProperty-to-define-computed-properties' } ); descriptor = value; @@ -125,8 +150,12 @@ export function get(obj, keyName) { if (isPath(keyName)) { return _getPath(obj, keyName); - } else if (value === undefined && isObject && !(keyName in obj) && - typeof obj.unknownProperty === 'function') { + } else if ( + value === undefined && + isObject && + !(keyName in obj) && + typeof obj.unknownProperty === 'function' + ) { return obj.unknownProperty(keyName); } else { return value; @@ -177,7 +206,9 @@ function isGettable(obj) { export function getWithDefault(root, key, defaultValue) { let value = get(root, key); - if (value === undefined) { return defaultValue; } + if (value === undefined) { + return defaultValue; + } return value; } diff --git a/packages/ember-metal/lib/property_set.js b/packages/ember-metal/lib/property_set.js index 94ba289212e..be76515a150 100644 --- a/packages/ember-metal/lib/property_set.js +++ b/packages/ember-metal/lib/property_set.js @@ -1,13 +1,12 @@ import { toString } from 'ember-utils'; import { assert, Error as EmberError } from 'ember-debug'; -import { getPossibleMandatoryProxyValue, _getPath as getPath } from './property_get'; import { - notifyPropertyChange -} from './property_events'; + getPossibleMandatoryProxyValue, + _getPath as getPath +} from './property_get'; +import { notifyPropertyChange } from './property_events'; -import { - isPath -} from './path_cache'; +import { isPath } from './path_cache'; import { isDescriptor, isDescriptorTrap, @@ -15,7 +14,11 @@ import { DESCRIPTOR, descriptorFor } from './meta'; -import { DESCRIPTOR_TRAP, EMBER_METAL_ES5_GETTERS, MANDATORY_SETTER } from 'ember/features'; +import { + DESCRIPTOR_TRAP, + EMBER_METAL_ES5_GETTERS, + MANDATORY_SETTER +} from 'ember/features'; /** @module @ember/object */ @@ -44,12 +47,27 @@ export function set(obj, keyName, value, tolerant) { `Set must be called with three or four arguments; an object, a property key, a value and tolerant true/false`, arguments.length === 3 || arguments.length === 4 ); - assert(`Cannot call set with '${keyName}' on an undefined object.`, obj && typeof obj === 'object' || typeof obj === 'function'); - assert(`The key provided to set must be a string or number, you passed ${keyName}`, typeof keyName === 'string' || (typeof keyName === 'number' && !isNaN(keyName))); - assert(`'this' in paths is not supported`, typeof keyName !== 'string' || keyName.lastIndexOf('this.', 0) !== 0); + assert( + `Cannot call set with '${keyName}' on an undefined object.`, + (obj && typeof obj === 'object') || typeof obj === 'function' + ); + assert( + `The key provided to set must be a string or number, you passed ${keyName}`, + typeof keyName === 'string' || + (typeof keyName === 'number' && !isNaN(keyName)) + ); + assert( + `'this' in paths is not supported`, + typeof keyName !== 'string' || keyName.lastIndexOf('this.', 0) !== 0 + ); if (obj.isDestroyed) { - assert(`calling set on destroyed object: ${toString(obj)}.${keyName} = ${toString(value)}`, tolerant); + assert( + `calling set on destroyed object: ${toString( + obj + )}.${keyName} = ${toString(value)}`, + tolerant + ); return; } @@ -60,7 +78,8 @@ export function set(obj, keyName, value, tolerant) { if (EMBER_METAL_ES5_GETTERS) { let possibleDesc = descriptorFor(obj, keyName); - if (possibleDesc !== undefined) { /* computed property */ + if (possibleDesc !== undefined) { + /* computed property */ possibleDesc.set(obj, keyName, value); return value; } @@ -72,12 +91,19 @@ export function set(obj, keyName, value, tolerant) { currentValue = currentValue[DESCRIPTOR]; } - if (isDescriptor(currentValue)) { /* computed property */ + if (isDescriptor(currentValue)) { + /* computed property */ currentValue.set(obj, keyName, value); - } else if (currentValue === undefined && 'object' === typeof obj && !(keyName in obj) && - typeof obj.setUnknownProperty === 'function') { /* unknown property */ + } else if ( + currentValue === undefined && + 'object' === typeof obj && + !(keyName in obj) && + typeof obj.setUnknownProperty === 'function' + ) { + /* unknown property */ obj.setUnknownProperty(keyName, value); - } else if (currentValue === value) { /* no change */ + } else if (currentValue === value) { + /* no change */ } else { let meta = peekMeta(obj); @@ -117,7 +143,10 @@ function setPath(root, path, value, tolerant) { let parts = path.split('.'); let keyName = parts.pop(); - assert('Property set failed: You passed an empty path', keyName.trim().length > 0); + assert( + 'Property set failed: You passed an empty path', + keyName.trim().length > 0 + ); let newPath = parts.join('.'); @@ -126,7 +155,9 @@ function setPath(root, path, value, tolerant) { if (newRoot) { return set(newRoot, keyName, value); } else if (!tolerant) { - throw new EmberError(`Property set failed: object in path "${newPath}" could not be found or was destroyed.`); + throw new EmberError( + `Property set failed: object in path "${newPath}" could not be found or was destroyed.` + ); } } diff --git a/packages/ember-metal/lib/run_loop.js b/packages/ember-metal/lib/run_loop.js index 4a50d8a611b..6f9c08116db 100644 --- a/packages/ember-metal/lib/run_loop.js +++ b/packages/ember-metal/lib/run_loop.js @@ -1,12 +1,7 @@ import { privatize as P } from 'container'; import { assert, deprecate, isTesting } from 'ember-debug'; -import { - onErrorTarget -} from './error_handler'; -import { - beginPropertyChanges, - endPropertyChanges -} from './property_events'; +import { onErrorTarget } from './error_handler'; +import { beginPropertyChanges, endPropertyChanges } from './property_events'; import Backburner from 'backburner'; let currentRunLoop = null; @@ -50,18 +45,16 @@ export const queues = [ P`rsvpAfter` ]; -export const backburner = new Backburner( - queues, - { - sync: { - before: beginPropertyChanges, - after: endPropertyChanges - }, - defaultQueue: 'actions', - onBegin, - onEnd, - onErrorTarget, - onErrorMethod: 'onerror' +export const backburner = new Backburner(queues, { + sync: { + before: beginPropertyChanges, + after: endPropertyChanges + }, + defaultQueue: 'actions', + onBegin, + onEnd, + onErrorTarget, + onErrorMethod: 'onerror' }); /** @@ -305,13 +298,13 @@ export function end() { export function schedule(queue /*, target, method */) { assert( `You have turned on testing mode, which disabled the run-loop's autorun. ` + - `You will need to wrap any code with asynchronous side-effects in a run`, + `You will need to wrap any code with asynchronous side-effects in a run`, currentRunLoop || !isTesting() ); deprecate( - `Scheduling into the '${queue}' run loop queue is deprecated.`, - queue !== 'sync', - { id: 'ember-metal.run.sync', until: '3.5.0' } + `Scheduling into the '${queue}' run loop queue is deprecated.`, + queue !== 'sync', + { id: 'ember-metal.run.sync', until: '3.5.0' } ); return backburner.schedule(...arguments); @@ -379,7 +372,7 @@ export function later(/*target, method*/) { export function once(...args) { assert( `You have turned on testing mode, which disabled the run-loop's autorun. ` + - `You will need to wrap any code with asynchronous side-effects in a run`, + `You will need to wrap any code with asynchronous side-effects in a run`, currentRunLoop || !isTesting() ); args.unshift('actions'); @@ -461,13 +454,13 @@ export function once(...args) { export function scheduleOnce(queue /*, target, method*/) { assert( `You have turned on testing mode, which disabled the run-loop's autorun. ` + - `You will need to wrap any code with asynchronous side-effects in a run`, + `You will need to wrap any code with asynchronous side-effects in a run`, currentRunLoop || !isTesting() ); deprecate( - `Scheduling into the '${queue}' run loop queue is deprecated.`, - queue !== 'sync', - { id: 'ember-metal.run.sync', until: '3.5.0' } + `Scheduling into the '${queue}' run loop queue is deprecated.`, + queue !== 'sync', + { id: 'ember-metal.run.sync', until: '3.5.0' } ); return backburner.scheduleOnce(...arguments); } diff --git a/packages/ember-metal/lib/set_properties.js b/packages/ember-metal/lib/set_properties.js index 89910370849..aa2d3b6ef6f 100644 --- a/packages/ember-metal/lib/set_properties.js +++ b/packages/ember-metal/lib/set_properties.js @@ -28,7 +28,9 @@ import { set } from './property_set'; @public */ export default function setProperties(obj, properties) { - if (properties === null || typeof properties !== 'object') { return properties; } + if (properties === null || typeof properties !== 'object') { + return properties; + } changeProperties(() => { let props = Object.keys(properties); let propertyName; diff --git a/packages/ember-metal/lib/tags.js b/packages/ember-metal/lib/tags.js index e765ea339f4..0785044aa2c 100644 --- a/packages/ember-metal/lib/tags.js +++ b/packages/ember-metal/lib/tags.js @@ -1,4 +1,9 @@ -import { CONSTANT_TAG, UpdatableTag, DirtyableTag, combine } from '@glimmer/reference'; +import { + CONSTANT_TAG, + UpdatableTag, + DirtyableTag, + combine +} from '@glimmer/reference'; import { EMBER_METAL_TRACKED_PROPERTIES } from 'ember/features'; import { meta as metaFor } from './meta'; import { isProxy } from './is_proxy'; @@ -14,10 +19,14 @@ function makeTag() { return DirtyableTag.create(); } -export const TRACKED_GETTERS = EMBER_METAL_TRACKED_PROPERTIES ? new WeakMap() : undefined; +export const TRACKED_GETTERS = EMBER_METAL_TRACKED_PROPERTIES + ? new WeakMap() + : undefined; export function tagForProperty(object, propertyKey, _meta) { - if (typeof object !== 'object' || object === null) { return CONSTANT_TAG; } + if (typeof object !== 'object' || object === null) { + return CONSTANT_TAG; + } let meta = _meta === undefined ? metaFor(object) : _meta; if (isProxy(object)) { @@ -26,13 +35,15 @@ export function tagForProperty(object, propertyKey, _meta) { let tags = meta.writableTags(); let tag = tags[propertyKey]; - if (tag) { return tag; } + if (tag) { + return tag; + } if (EMBER_METAL_TRACKED_PROPERTIES) { let pair = combine([makeTag(), UpdatableTag.create(CONSTANT_TAG)]); - return tags[propertyKey] = pair; + return (tags[propertyKey] = pair); } else { - return tags[propertyKey] = makeTag(); + return (tags[propertyKey] = makeTag()); } } @@ -49,7 +60,7 @@ export let dirty; export let update; if (EMBER_METAL_TRACKED_PROPERTIES) { - dirty = (tag) => { + dirty = tag => { tag.inner.first.inner.dirty(); }; @@ -57,7 +68,7 @@ if (EMBER_METAL_TRACKED_PROPERTIES) { outer.inner.second.inner.update(inner); }; } else { - dirty = (tag) => { + dirty = tag => { tag.inner.dirty(); }; } diff --git a/packages/ember-metal/lib/tracked.js b/packages/ember-metal/lib/tracked.js index 051942fba81..4d2af8f6317 100644 --- a/packages/ember-metal/lib/tracked.js +++ b/packages/ember-metal/lib/tracked.js @@ -6,30 +6,28 @@ import { tagFor, tagForProperty, dirty, update } from './tags'; @private */ class Tracker { - constructor() { - this.tags = new Set(); - this.last = null; - } - add(tag) { - this.tags.add(tag); - this.last = tag; - } - get size() { - return this.tags.size; - } - combine() { - if (this.tags.size === 0) { - return CONSTANT_TAG; - } - else if (this.tags.size === 1) { - return this.last; - } - else { - let tags = []; - this.tags.forEach(tag => tags.push(tag)); - return combine(tags); - } + constructor() { + this.tags = new Set(); + this.last = null; + } + add(tag) { + this.tags.add(tag); + this.last = tag; + } + get size() { + return this.tags.size; + } + combine() { + if (this.tags.size === 0) { + return CONSTANT_TAG; + } else if (this.tags.size === 1) { + return this.last; + } else { + let tags = []; + this.tags.forEach(tag => tags.push(tag)); + return combine(tags); } + } } /** @decorator @@ -93,12 +91,11 @@ class Tracker { @param dependencies Optional dependents to be tracked. */ export function tracked(target, key, descriptor) { - if ('value' in descriptor) { - return descriptorForDataProperty(key, descriptor); - } - else { - return descriptorForAccessor(key, descriptor); - } + if ('value' in descriptor) { + return descriptorForDataProperty(key, descriptor); + } else { + return descriptorForAccessor(key, descriptor); + } } /** @private @@ -117,42 +114,41 @@ export function tracked(target, key, descriptor) { */ let CURRENT_TRACKER = null; export function getCurrentTracker() { - return CURRENT_TRACKER; + return CURRENT_TRACKER; } export function setCurrentTracker(tracker = new Tracker()) { - return CURRENT_TRACKER = tracker; + return (CURRENT_TRACKER = tracker); } function descriptorForAccessor(key, descriptor) { - let get = descriptor.get; - let set = descriptor.set; - function getter() { - // Swap the parent tracker for a new tracker - let old = CURRENT_TRACKER; - let tracker = CURRENT_TRACKER = new Tracker(); - // Call the getter - let ret = get.call(this); - // Swap back the parent tracker - CURRENT_TRACKER = old; - // Combine the tags in the new tracker and add them to the parent tracker - let tag = tracker.combine(); - if (CURRENT_TRACKER) - CURRENT_TRACKER.add(tag); - // Update the UpdatableTag for this property with the tag for all of the - // consumed dependencies. - update(tagForProperty(this, key), tag); - return ret; - } - function setter() { - // Mark the UpdatableTag for this property with the current tag. - dirty(tagForProperty(this, key)); - set.apply(this, arguments); - } - return { - enumerable: true, - configurable: false, - get: get && getter, - set: set && setter - }; + let get = descriptor.get; + let set = descriptor.set; + function getter() { + // Swap the parent tracker for a new tracker + let old = CURRENT_TRACKER; + let tracker = (CURRENT_TRACKER = new Tracker()); + // Call the getter + let ret = get.call(this); + // Swap back the parent tracker + CURRENT_TRACKER = old; + // Combine the tags in the new tracker and add them to the parent tracker + let tag = tracker.combine(); + if (CURRENT_TRACKER) CURRENT_TRACKER.add(tag); + // Update the UpdatableTag for this property with the tag for all of the + // consumed dependencies. + update(tagForProperty(this, key), tag); + return ret; + } + function setter() { + // Mark the UpdatableTag for this property with the current tag. + dirty(tagForProperty(this, key)); + set.apply(this, arguments); + } + return { + enumerable: true, + configurable: false, + get: get && getter, + set: set && setter + }; } /** @private @@ -166,37 +162,40 @@ function descriptorForAccessor(key, descriptor) { from it. */ function descriptorForDataProperty(key, descriptor) { - let shadowKey = Symbol(key); - return { - enumerable: true, - configurable: true, - get() { - if (CURRENT_TRACKER) - CURRENT_TRACKER.add(tagForProperty(this, key)); - if (!(shadowKey in this)) { - this[shadowKey] = descriptor.value; - } - return this[shadowKey]; - }, - set(newValue) { - tagFor(this).inner.dirty(); - dirty(tagForProperty(this, key)); - this[shadowKey] = newValue; - propertyDidChange(); - } - }; + let shadowKey = Symbol(key); + return { + enumerable: true, + configurable: true, + get() { + if (CURRENT_TRACKER) CURRENT_TRACKER.add(tagForProperty(this, key)); + if (!(shadowKey in this)) { + this[shadowKey] = descriptor.value; + } + return this[shadowKey]; + }, + set(newValue) { + tagFor(this).inner.dirty(); + dirty(tagForProperty(this, key)); + this[shadowKey] = newValue; + propertyDidChange(); + } + }; } -let propertyDidChange = function () { }; +let propertyDidChange = function() {}; export function setPropertyDidChange(cb) { - propertyDidChange = cb; + propertyDidChange = cb; } export class UntrackedPropertyError extends Error { - constructor(target, key, message) { - super(message); - this.target = target; - this.key = key; - } - static for(obj, key) { - return new UntrackedPropertyError(obj, key, `The property '${key}' on ${obj} was changed after being rendered. If you want to change a property used in a template after the component has rendered, mark the property as a tracked property with the @tracked decorator.`); - } + constructor(target, key, message) { + super(message); + this.target = target; + this.key = key; + } + static for(obj, key) { + return new UntrackedPropertyError( + obj, + key, + `The property '${key}' on ${obj} was changed after being rendered. If you want to change a property used in a template after the component has rendered, mark the property as a tracked property with the @tracked decorator.` + ); + } } diff --git a/packages/ember-metal/lib/transaction.js b/packages/ember-metal/lib/transaction.js index 29b39366db2..5d897a8b8a9 100644 --- a/packages/ember-metal/lib/transaction.js +++ b/packages/ember-metal/lib/transaction.js @@ -1,14 +1,11 @@ import { assert } from 'ember-debug'; import { DEBUG } from 'ember-env-flags'; -import { - EMBER_GLIMMER_DETECT_BACKTRACKING_RERENDER, -} from 'ember/features'; +import { EMBER_GLIMMER_DETECT_BACKTRACKING_RERENDER } from 'ember/features'; let runInTransaction, didRender, assertNotRendered; // detect-backtracking-rerender by default is debug build only if (EMBER_GLIMMER_DETECT_BACKTRACKING_RERENDER) { - // there are 2 states // DEBUG @@ -42,11 +39,13 @@ if (EMBER_GLIMMER_DETECT_BACKTRACKING_RERENDER) { } didRender(object, key, reference) { - if (!this.inTransaction) { return; } + if (!this.inTransaction) { + return; + } if (DEBUG) { this.setKey(object, key, { lastRef: reference, - lastRenderedIn: this.debugStack.peek(), + lastRenderedIn: this.debugStack.peek() }); } else { this.setKey(object, key, this.transactionId); @@ -54,7 +53,9 @@ if (EMBER_GLIMMER_DETECT_BACKTRACKING_RERENDER) { } assertNotRendered(object, key) { - if (!this.inTransaction) { return; } + if (!this.inTransaction) { + return; + } if (this.hasRendered(object, key)) { if (DEBUG) { let { lastRef, lastRenderedIn } = this.getKey(object, key); @@ -74,7 +75,10 @@ if (EMBER_GLIMMER_DETECT_BACKTRACKING_RERENDER) { label = 'the same value'; } - assert(`You modified "${label}" twice on ${object} in a single render. It was rendered in ${lastRenderedIn} and modified in ${currentlyIn}. This was unreliable and slow in Ember 1.x and is no longer supported. See https://github.com/emberjs/ember.js/issues/13948 for more details.`, false); + assert( + `You modified "${label}" twice on ${object} in a single render. It was rendered in ${lastRenderedIn} and modified in ${currentlyIn}. This was unreliable and slow in Ember 1.x and is no longer supported. See https://github.com/emberjs/ember.js/issues/13948 for more details.`, + false + ); } this.shouldReflush = true; @@ -82,7 +86,9 @@ if (EMBER_GLIMMER_DETECT_BACKTRACKING_RERENDER) { } hasRendered(object, key) { - if (!this.inTransaction) { return false; } + if (!this.inTransaction) { + return false; + } if (DEBUG) { return this.getKey(object, key) !== undefined; } @@ -139,9 +145,9 @@ if (EMBER_GLIMMER_DETECT_BACKTRACKING_RERENDER) { let runner = new TransactionRunner(); - runInTransaction = runner.runInTransaction.bind(runner); - didRender = runner.didRender.bind(runner); - assertNotRendered = runner.assertNotRendered.bind(runner); + runInTransaction = runner.runInTransaction.bind(runner); + didRender = runner.didRender.bind(runner); + assertNotRendered = runner.assertNotRendered.bind(runner); } else { // in production do nothing to detect reflushes runInTransaction = (context, methodName) => { diff --git a/packages/ember-metal/lib/watch_key.js b/packages/ember-metal/lib/watch_key.js index 7b972b5a9e0..3e2ea975aca 100644 --- a/packages/ember-metal/lib/watch_key.js +++ b/packages/ember-metal/lib/watch_key.js @@ -20,7 +20,8 @@ export function watchKey(obj, keyName, _meta) { let count = meta.peekWatching(keyName) || 0; meta.writeWatching(keyName, count + 1); - if (count === 0) { // activate watching first time + if (count === 0) { + // activate watching first time let possibleDesc = descriptorFor(obj, keyName, meta); if (possibleDesc !== undefined && possibleDesc.willWatch) { @@ -38,10 +39,11 @@ export function watchKey(obj, keyName, _meta) { } } - if (MANDATORY_SETTER) { - let hasOwnProperty = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key); - let propertyIsEnumerable = (obj, key) => Object.prototype.propertyIsEnumerable.call(obj, key); + let hasOwnProperty = (obj, key) => + Object.prototype.hasOwnProperty.call(obj, key); + let propertyIsEnumerable = (obj, key) => + Object.prototype.propertyIsEnumerable.call(obj, key); // Future traveler, although this code looks scary. It merely exists in // development to aid in development asertions. Production builds of @@ -50,7 +52,9 @@ if (MANDATORY_SETTER) { let descriptor = lookupDescriptor(obj, keyName); let hasDescriptor = descriptor !== null; let possibleDesc = hasDescriptor && descriptor.value; - if (isDescriptor(possibleDesc)) { return; } + if (isDescriptor(possibleDesc)) { + return; + } let configurable = hasDescriptor ? descriptor.configurable : true; let isWritable = hasDescriptor ? descriptor.writable : true; let hasValue = hasDescriptor ? 'value' in descriptor : true; @@ -80,7 +84,9 @@ export function unwatchKey(obj, keyName, _meta) { let meta = _meta === undefined ? peekMeta(obj) : _meta; // do nothing of this object has already been destroyed - if (meta === undefined || meta.isSourceDestroyed()) { return; } + if (meta === undefined || meta.isSourceDestroyed()) { + return; + } let count = meta.peekWatching(keyName); if (count === 1) { @@ -109,8 +115,14 @@ export function unwatchKey(obj, keyName, _meta) { if (!isDescriptor && keyName in obj) { let maybeMandatoryDescriptor = lookupDescriptor(obj, keyName); - if (maybeMandatoryDescriptor.set && maybeMandatoryDescriptor.set.isMandatorySetter) { - if (maybeMandatoryDescriptor.get && maybeMandatoryDescriptor.get.isInheritingGetter) { + if ( + maybeMandatoryDescriptor.set && + maybeMandatoryDescriptor.set.isMandatorySetter + ) { + if ( + maybeMandatoryDescriptor.get && + maybeMandatoryDescriptor.get.isInheritingGetter + ) { let possibleValue = meta.readInheritedValue('values', keyName); if (possibleValue === UNDEFINED) { delete obj[keyName]; @@ -120,7 +132,10 @@ export function unwatchKey(obj, keyName, _meta) { Object.defineProperty(obj, keyName, { configurable: true, - enumerable: Object.prototype.propertyIsEnumerable.call(obj, keyName), + enumerable: Object.prototype.propertyIsEnumerable.call( + obj, + keyName + ), writable: true, value: meta.peekValues(keyName) }); diff --git a/packages/ember-metal/lib/watch_path.js b/packages/ember-metal/lib/watch_path.js index 701ccb84b34..f73fb8f4e65 100644 --- a/packages/ember-metal/lib/watch_path.js +++ b/packages/ember-metal/lib/watch_path.js @@ -1,7 +1,4 @@ -import { - meta as metaFor, - peekMeta -} from './meta'; +import { meta as metaFor, peekMeta } from './meta'; import { makeChainNode } from './chains'; export function watchPath(obj, keyPath, meta) { @@ -9,14 +6,17 @@ export function watchPath(obj, keyPath, meta) { let counter = m.peekWatching(keyPath) || 0; m.writeWatching(keyPath, counter + 1); - if (counter === 0) { // activate watching first time + if (counter === 0) { + // activate watching first time m.writableChains(makeChainNode).add(keyPath); } } export function unwatchPath(obj, keyPath, meta) { let m = meta === undefined ? peekMeta(obj) : meta; - if (m === undefined) { return; } + if (m === undefined) { + return; + } let counter = m.peekWatching(keyPath); if (counter > 0) { diff --git a/packages/ember-metal/lib/watching.js b/packages/ember-metal/lib/watching.js index 7162183298e..a38af98991d 100644 --- a/packages/ember-metal/lib/watching.js +++ b/packages/ember-metal/lib/watching.js @@ -1,20 +1,10 @@ /** @module ember */ -import { - watchKey, - unwatchKey -} from './watch_key'; -import { - watchPath, - unwatchPath -} from './watch_path'; -import { - isPath -} from './path_cache'; -import { - peekMeta -} from './meta'; +import { watchKey, unwatchKey } from './watch_key'; +import { watchPath, unwatchPath } from './watch_path'; +import { isPath } from './path_cache'; +import { peekMeta } from './meta'; /** Starts watching a property on an object. Whenever the property changes, diff --git a/packages/ember-metal/tests/accessors/get_path_test.js b/packages/ember-metal/tests/accessors/get_path_test.js index 527d4d3ff86..5a46db1adec 100644 --- a/packages/ember-metal/tests/accessors/get_path_test.js +++ b/packages/ember-metal/tests/accessors/get_path_test.js @@ -3,78 +3,80 @@ import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; let obj; -moduleFor('get with path', class extends AbstractTestCase { - constructor() { - super(); - obj = { - foo: { - bar: { - baz: { biff: 'BIFF' } - } - }, - foothis: { - bar: { - baz: { biff: 'BIFF' } - } - }, - falseValue: false, - emptyString: '', - Wuz: { - nar: 'foo' - }, - nullValue: null - }; - } +moduleFor( + 'get with path', + class extends AbstractTestCase { + constructor() { + super(); + obj = { + foo: { + bar: { + baz: { biff: 'BIFF' } + } + }, + foothis: { + bar: { + baz: { biff: 'BIFF' } + } + }, + falseValue: false, + emptyString: '', + Wuz: { + nar: 'foo' + }, + nullValue: null + }; + } - teardown() { - obj = undefined; - } + teardown() { + obj = undefined; + } - // .......................................................... - // LOCAL PATHS - // - ['@test [obj, foo] -> obj.foo'](assert) { - assert.deepEqual(get(obj, 'foo'), obj.foo); - } + // .......................................................... + // LOCAL PATHS + // + ['@test [obj, foo] -> obj.foo'](assert) { + assert.deepEqual(get(obj, 'foo'), obj.foo); + } - ['@test [obj, foo.bar] -> obj.foo.bar'](assert) { - assert.deepEqual(get(obj, 'foo.bar'), obj.foo.bar); - } + ['@test [obj, foo.bar] -> obj.foo.bar'](assert) { + assert.deepEqual(get(obj, 'foo.bar'), obj.foo.bar); + } - ['@test [obj, foothis.bar] -> obj.foothis.bar'](assert) { - assert.deepEqual(get(obj, 'foothis.bar'), obj.foothis.bar); - } + ['@test [obj, foothis.bar] -> obj.foothis.bar'](assert) { + assert.deepEqual(get(obj, 'foothis.bar'), obj.foothis.bar); + } - ['@test [obj, falseValue.notDefined] -> (undefined)'](assert) { - assert.strictEqual(get(obj, 'falseValue.notDefined'), undefined); - } + ['@test [obj, falseValue.notDefined] -> (undefined)'](assert) { + assert.strictEqual(get(obj, 'falseValue.notDefined'), undefined); + } - ['@test [obj, emptyString.length] -> 0'](assert) { - assert.strictEqual(get(obj, 'emptyString.length'), 0); - } + ['@test [obj, emptyString.length] -> 0'](assert) { + assert.strictEqual(get(obj, 'emptyString.length'), 0); + } - ['@test [obj, nullValue.notDefined] -> (undefined)'](assert) { - assert.strictEqual(get(obj, 'nullValue.notDefined'), undefined); - } + ['@test [obj, nullValue.notDefined] -> (undefined)'](assert) { + assert.strictEqual(get(obj, 'nullValue.notDefined'), undefined); + } - // .......................................................... - // GLOBAL PATHS TREATED LOCAL WITH GET - // + // .......................................................... + // GLOBAL PATHS TREATED LOCAL WITH GET + // - ['@test [obj, Wuz] -> obj.Wuz'](assert) { - assert.deepEqual(get(obj, 'Wuz'), obj.Wuz); - } + ['@test [obj, Wuz] -> obj.Wuz'](assert) { + assert.deepEqual(get(obj, 'Wuz'), obj.Wuz); + } - ['@test [obj, Wuz.nar] -> obj.Wuz.nar'](assert) { - assert.deepEqual(get(obj, 'Wuz.nar'), obj.Wuz.nar); - } + ['@test [obj, Wuz.nar] -> obj.Wuz.nar'](assert) { + assert.deepEqual(get(obj, 'Wuz.nar'), obj.Wuz.nar); + } - ['@test [obj, Foo] -> (undefined)'](assert) { - assert.strictEqual(get(obj, 'Foo'), undefined); - } + ['@test [obj, Foo] -> (undefined)'](assert) { + assert.strictEqual(get(obj, 'Foo'), undefined); + } - ['@test [obj, Foo.bar] -> (undefined)'](assert) { - assert.strictEqual(get(obj, 'Foo.bar'), undefined); + ['@test [obj, Foo.bar] -> (undefined)'](assert) { + assert.strictEqual(get(obj, 'Foo.bar'), undefined); + } } -}); - +); diff --git a/packages/ember-metal/tests/accessors/get_properties_test.js b/packages/ember-metal/tests/accessors/get_properties_test.js index 52468361189..3a77e631a2d 100644 --- a/packages/ember-metal/tests/accessors/get_properties_test.js +++ b/packages/ember-metal/tests/accessors/get_properties_test.js @@ -1,21 +1,36 @@ import { getProperties } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('getProperties', class extends AbstractTestCase { - ['@test can retrieve a hash of properties from an object via an argument list or array of property names'](assert) { - let obj = { - firstName: 'Steve', - lastName: 'Jobs', - companyName: 'Apple, Inc.' - }; +moduleFor( + 'getProperties', + class extends AbstractTestCase { + ['@test can retrieve a hash of properties from an object via an argument list or array of property names']( + assert + ) { + let obj = { + firstName: 'Steve', + lastName: 'Jobs', + companyName: 'Apple, Inc.' + }; - assert.deepEqual(getProperties(obj, 'firstName', 'lastName'), { firstName: 'Steve', lastName: 'Jobs' }); - assert.deepEqual(getProperties(obj, 'firstName', 'lastName'), { firstName: 'Steve', lastName: 'Jobs' }); - assert.deepEqual(getProperties(obj, 'lastName'), { lastName: 'Jobs' }); - assert.deepEqual(getProperties(obj), {}); - assert.deepEqual(getProperties(obj, ['firstName', 'lastName']), { firstName: 'Steve', lastName: 'Jobs' }); - assert.deepEqual(getProperties(obj, ['firstName']), { firstName: 'Steve' }); - assert.deepEqual(getProperties(obj, []), {}); + assert.deepEqual(getProperties(obj, 'firstName', 'lastName'), { + firstName: 'Steve', + lastName: 'Jobs' + }); + assert.deepEqual(getProperties(obj, 'firstName', 'lastName'), { + firstName: 'Steve', + lastName: 'Jobs' + }); + assert.deepEqual(getProperties(obj, 'lastName'), { lastName: 'Jobs' }); + assert.deepEqual(getProperties(obj), {}); + assert.deepEqual(getProperties(obj, ['firstName', 'lastName']), { + firstName: 'Steve', + lastName: 'Jobs' + }); + assert.deepEqual(getProperties(obj, ['firstName']), { + firstName: 'Steve' + }); + assert.deepEqual(getProperties(obj, []), {}); + } } -}); - +); diff --git a/packages/ember-metal/tests/accessors/get_test.js b/packages/ember-metal/tests/accessors/get_test.js index 765ff54117c..3ecbf8e668a 100644 --- a/packages/ember-metal/tests/accessors/get_test.js +++ b/packages/ember-metal/tests/accessors/get_test.js @@ -1,219 +1,253 @@ import { ENV } from 'ember-environment'; -import { - get, - getWithDefault, - Mixin, - observer, - computed, -} from '../..'; +import { get, getWithDefault, Mixin, observer, computed } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -function aget(x, y) { return x[y]; } - -moduleFor('get', class extends AbstractTestCase { - ['@test should get arbitrary properties on an object'](assert) { - let obj = { - string: 'string', - number: 23, - boolTrue: true, - boolFalse: false, - nullValue: null - }; - - for (let key in obj) { - if (!obj.hasOwnProperty(key)) { - continue; +function aget(x, y) { + return x[y]; +} + +moduleFor( + 'get', + class extends AbstractTestCase { + ['@test should get arbitrary properties on an object'](assert) { + let obj = { + string: 'string', + number: 23, + boolTrue: true, + boolFalse: false, + nullValue: null + }; + + for (let key in obj) { + if (!obj.hasOwnProperty(key)) { + continue; + } + assert.equal(get(obj, key), obj[key], key); } - assert.equal(get(obj, key), obj[key], key); } - } - ['@test implicitly computing the values of descriptors on properties is deprecated'](assert) { - let cp = computed(() => 'value'); - let obj = { - cp, - toString() { return 'myobject'; } - }; + ['@test implicitly computing the values of descriptors on properties is deprecated']( + assert + ) { + let cp = computed(() => 'value'); + let obj = { + cp, + toString() { + return 'myobject'; + } + }; - let result; + let result; - expectDeprecation(() => { - result = get(obj, 'cp'); - }, /\[DEPRECATED\] computed property 'cp' was not set on object 'myobject' via 'defineProperty'/); + expectDeprecation(() => { + result = get(obj, 'cp'); + }, /\[DEPRECATED\] computed property 'cp' was not set on object 'myobject' via 'defineProperty'/); - assert.equal(result, 'value', 'descriptor'); - } - - ['@test should retrieve a number key on an object'](assert) { - let obj = { 1: 'first' }; + assert.equal(result, 'value', 'descriptor'); + } - assert.equal(get(obj, 1), 'first'); - } + ['@test should retrieve a number key on an object'](assert) { + let obj = { 1: 'first' }; - ['@test should retrieve an array index'](assert) { - let arr = ['first', 'second']; + assert.equal(get(obj, 1), 'first'); + } - assert.equal(get(arr, 0), 'first'); - assert.equal(get(arr, 1), 'second'); - } + ['@test should retrieve an array index'](assert) { + let arr = ['first', 'second']; - ['@test should not access a property more than once'](assert) { - let count = 0; - let obj = { - get id() { return ++count; } - }; + assert.equal(get(arr, 0), 'first'); + assert.equal(get(arr, 1), 'second'); + } - get(obj, 'id'); + ['@test should not access a property more than once'](assert) { + let count = 0; + let obj = { + get id() { + return ++count; + } + }; - assert.equal(count, 1); - } + get(obj, 'id'); - ['@test should call unknownProperty on watched values if the value is undefined using getFromEmberMetal()/set()'](assert) { - let obj = { - unknownProperty(key) { - assert.equal(key, 'foo', 'should pass key'); - return 'FOO'; - } - }; - assert.equal(get(obj, 'foo'), 'FOO', 'should return value from unknown'); - } + assert.equal(count, 1); + } - ['@test should call unknownProperty on watched values if the value is undefined using accessors'](assert) { - if (ENV.USES_ACCESSORS) { + ['@test should call unknownProperty on watched values if the value is undefined using getFromEmberMetal()/set()']( + assert + ) { let obj = { unknownProperty(key) { assert.equal(key, 'foo', 'should pass key'); return 'FOO'; } }; - assert.equal(aget(obj, 'foo'), 'FOO', 'should return value from unknown'); - } else { - assert.ok('SKIPPING ACCESSORS'); + assert.equal(get(obj, 'foo'), 'FOO', 'should return value from unknown'); } - } - ['@test warn on attempts to call get with no arguments']() { - expectAssertion(function() { - get('aProperty'); - }, /Get must be called with two arguments;/i); - } - - ['@test warn on attempts to call get with only one argument']() { - expectAssertion(function() { - get('aProperty'); - }, /Get must be called with two arguments;/i); - } - - ['@test warn on attempts to call get with more then two arguments']() { - expectAssertion(function() { - get({}, 'aProperty', true); - }, /Get must be called with two arguments;/i); - } - - ['@test warn on attempts to get a property of undefined']() { - expectAssertion(function() { - get(undefined, 'aProperty'); - }, /Cannot call get with 'aProperty' on an undefined object/i); - } - - ['@test warn on attempts to get a property path of undefined']() { - expectAssertion(function() { - get(undefined, 'aProperty.on.aPath'); - }, /Cannot call get with 'aProperty.on.aPath' on an undefined object/); - } + ['@test should call unknownProperty on watched values if the value is undefined using accessors']( + assert + ) { + if (ENV.USES_ACCESSORS) { + let obj = { + unknownProperty(key) { + assert.equal(key, 'foo', 'should pass key'); + return 'FOO'; + } + }; + assert.equal( + aget(obj, 'foo'), + 'FOO', + 'should return value from unknown' + ); + } else { + assert.ok('SKIPPING ACCESSORS'); + } + } - ['@test warn on attempts to get a property of null']() { - expectAssertion(function() { - get(null, 'aProperty'); - }, /Cannot call get with 'aProperty' on an undefined object/); - } + ['@test warn on attempts to call get with no arguments']() { + expectAssertion(function() { + get('aProperty'); + }, /Get must be called with two arguments;/i); + } - ['@test warn on attempts to get a property path of null']() { - expectAssertion(function() { - get(null, 'aProperty.on.aPath'); - }, /Cannot call get with 'aProperty.on.aPath' on an undefined object/); - } + ['@test warn on attempts to call get with only one argument']() { + expectAssertion(function() { + get('aProperty'); + }, /Get must be called with two arguments;/i); + } - ['@test warn on attempts to use get with an unsupported property path']() { - let obj = {}; - expectAssertion(() => get(obj, null), /The key provided to get must be a string or number, you passed null/); - expectAssertion(() => get(obj, NaN), /The key provided to get must be a string or number, you passed NaN/); - expectAssertion(() => get(obj, undefined), /The key provided to get must be a string or number, you passed undefined/); - expectAssertion(() => get(obj, false), /The key provided to get must be a string or number, you passed false/); - expectAssertion(() => get(obj, ''), /Cannot call `get` with an empty string/); - } + ['@test warn on attempts to call get with more then two arguments']() { + expectAssertion(function() { + get({}, 'aProperty', true); + }, /Get must be called with two arguments;/i); + } - // .......................................................... - // BUGS - // + ['@test warn on attempts to get a property of undefined']() { + expectAssertion(function() { + get(undefined, 'aProperty'); + }, /Cannot call get with 'aProperty' on an undefined object/i); + } - ['@test (regression) watched properties on unmodified inherited objects should still return their original value'](assert) { - let MyMixin = Mixin.create({ - someProperty: 'foo', - propertyDidChange: observer('someProperty', () => {}) - }); + ['@test warn on attempts to get a property path of undefined']() { + expectAssertion(function() { + get(undefined, 'aProperty.on.aPath'); + }, /Cannot call get with 'aProperty.on.aPath' on an undefined object/); + } - let baseObject = MyMixin.apply({}); - let theRealObject = Object.create(baseObject); + ['@test warn on attempts to get a property of null']() { + expectAssertion(function() { + get(null, 'aProperty'); + }, /Cannot call get with 'aProperty' on an undefined object/); + } - assert.equal(get(theRealObject, 'someProperty'), 'foo', 'should return the set value, not false'); - } -}); - -moduleFor('getWithDefault', class extends AbstractTestCase { - ['@test should get arbitrary properties on an object'](assert) { - let obj = { - string: 'string', - number: 23, - boolTrue: true, - boolFalse: false, - nullValue: null - }; - - for (let key in obj) { - if (!obj.hasOwnProperty(key)) { - continue; - } - assert.equal(getWithDefault(obj, key, 'fail'), obj[key], key); + ['@test warn on attempts to get a property path of null']() { + expectAssertion(function() { + get(null, 'aProperty.on.aPath'); + }, /Cannot call get with 'aProperty.on.aPath' on an undefined object/); } - obj = { - undef: undefined - }; + ['@test warn on attempts to use get with an unsupported property path']() { + let obj = {}; + expectAssertion( + () => get(obj, null), + /The key provided to get must be a string or number, you passed null/ + ); + expectAssertion( + () => get(obj, NaN), + /The key provided to get must be a string or number, you passed NaN/ + ); + expectAssertion( + () => get(obj, undefined), + /The key provided to get must be a string or number, you passed undefined/ + ); + expectAssertion( + () => get(obj, false), + /The key provided to get must be a string or number, you passed false/ + ); + expectAssertion( + () => get(obj, ''), + /Cannot call `get` with an empty string/ + ); + } - assert.equal(getWithDefault(obj, 'undef', 'default'), 'default', 'explicit undefined retrieves the default'); - assert.equal(getWithDefault(obj, 'not-present', 'default'), 'default', 'non-present key retrieves the default'); + // .......................................................... + // BUGS + // + + ['@test (regression) watched properties on unmodified inherited objects should still return their original value']( + assert + ) { + let MyMixin = Mixin.create({ + someProperty: 'foo', + propertyDidChange: observer('someProperty', () => {}) + }); + + let baseObject = MyMixin.apply({}); + let theRealObject = Object.create(baseObject); + + assert.equal( + get(theRealObject, 'someProperty'), + 'foo', + 'should return the set value, not false' + ); + } } +); - ['@test should call unknownProperty if defined and value is undefined'](assert) { - let obj = { - count: 0, - unknownProperty(key) { - assert.equal(key, 'foo', 'should pass key'); - this.count++; - return 'FOO'; +moduleFor( + 'getWithDefault', + class extends AbstractTestCase { + ['@test should get arbitrary properties on an object'](assert) { + let obj = { + string: 'string', + number: 23, + boolTrue: true, + boolFalse: false, + nullValue: null + }; + + for (let key in obj) { + if (!obj.hasOwnProperty(key)) { + continue; + } + assert.equal(getWithDefault(obj, key, 'fail'), obj[key], key); } - }; - assert.equal(get(obj, 'foo'), 'FOO', 'should return value from unknown'); - assert.equal(obj.count, 1, 'should have invoked'); - } + obj = { + undef: undefined + }; - ['@test if unknownProperty is present, it is called using getFromEmberMetal()/set()'](assert) { - let obj = { - unknownProperty(key) { - if (key === 'foo') { + assert.equal( + getWithDefault(obj, 'undef', 'default'), + 'default', + 'explicit undefined retrieves the default' + ); + assert.equal( + getWithDefault(obj, 'not-present', 'default'), + 'default', + 'non-present key retrieves the default' + ); + } + + ['@test should call unknownProperty if defined and value is undefined']( + assert + ) { + let obj = { + count: 0, + unknownProperty(key) { assert.equal(key, 'foo', 'should pass key'); + this.count++; return 'FOO'; } - } - }; - assert.equal(getWithDefault(obj, 'foo', 'fail'), 'FOO', 'should return value from unknownProperty'); - assert.equal(getWithDefault(obj, 'bar', 'default'), 'default', 'should convert undefined from unknownProperty into default'); - } + }; + + assert.equal(get(obj, 'foo'), 'FOO', 'should return value from unknown'); + assert.equal(obj.count, 1, 'should have invoked'); + } - ['@test if unknownProperty is present, it is called using accessors'](assert) { - if (ENV.USES_ACCESSORS) { + ['@test if unknownProperty is present, it is called using getFromEmberMetal()/set()']( + assert + ) { let obj = { unknownProperty(key) { if (key === 'foo') { @@ -222,28 +256,67 @@ moduleFor('getWithDefault', class extends AbstractTestCase { } } }; - assert.equal(aget(obj, 'foo', 'fail'), 'FOO', 'should return value from unknownProperty'); - assert.equal(aget(obj, 'bar', 'default'), 'default', 'should convert undefined from unknownProperty into default'); - - } else { - assert.ok('SKIPPING ACCESSORS'); + assert.equal( + getWithDefault(obj, 'foo', 'fail'), + 'FOO', + 'should return value from unknownProperty' + ); + assert.equal( + getWithDefault(obj, 'bar', 'default'), + 'default', + 'should convert undefined from unknownProperty into default' + ); } - } - - // .......................................................... - // BUGS - // - ['@test (regression) watched properties on unmodified inherited objects should still return their original value'](assert) { - let MyMixin = Mixin.create({ - someProperty: 'foo', - propertyDidChange: observer('someProperty', () => { /* nothing to do */}) - }); - - let baseObject = MyMixin.apply({}); - let theRealObject = Object.create(baseObject); + ['@test if unknownProperty is present, it is called using accessors']( + assert + ) { + if (ENV.USES_ACCESSORS) { + let obj = { + unknownProperty(key) { + if (key === 'foo') { + assert.equal(key, 'foo', 'should pass key'); + return 'FOO'; + } + } + }; + assert.equal( + aget(obj, 'foo', 'fail'), + 'FOO', + 'should return value from unknownProperty' + ); + assert.equal( + aget(obj, 'bar', 'default'), + 'default', + 'should convert undefined from unknownProperty into default' + ); + } else { + assert.ok('SKIPPING ACCESSORS'); + } + } - assert.equal(getWithDefault(theRealObject, 'someProperty', 'fail'), 'foo', 'should return the set value, not false'); + // .......................................................... + // BUGS + // + + ['@test (regression) watched properties on unmodified inherited objects should still return their original value']( + assert + ) { + let MyMixin = Mixin.create({ + someProperty: 'foo', + propertyDidChange: observer('someProperty', () => { + /* nothing to do */ + }) + }); + + let baseObject = MyMixin.apply({}); + let theRealObject = Object.create(baseObject); + + assert.equal( + getWithDefault(theRealObject, 'someProperty', 'fail'), + 'foo', + 'should return the set value, not false' + ); + } } -}); - +); diff --git a/packages/ember-metal/tests/accessors/mandatory_setters_test.js b/packages/ember-metal/tests/accessors/mandatory_setters_test.js index 505754923d2..c611fc66c73 100644 --- a/packages/ember-metal/tests/accessors/mandatory_setters_test.js +++ b/packages/ember-metal/tests/accessors/mandatory_setters_test.js @@ -1,16 +1,13 @@ import { MANDATORY_SETTER } from 'ember/features'; -import { - get, - set, - watch, - unwatch, - meta as metaFor -} from '../..'; +import { get, set, watch, unwatch, meta as metaFor } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; function hasMandatorySetter(object, property) { try { - return Object.getOwnPropertyDescriptor(object, property).set.isMandatorySetter === true; + return ( + Object.getOwnPropertyDescriptor(object, property).set + .isMandatorySetter === true + ); } catch (e) { return false; } @@ -21,417 +18,619 @@ function hasMetaValue(object, property) { } if (MANDATORY_SETTER) { - moduleFor('mandory-setters', class extends AbstractTestCase { - ['@test does not assert if property is not being watched'](assert) { - let obj = { - someProp: null, - toString() { - return 'custom-object'; - } - }; - - obj.someProp = 'blastix'; - assert.equal(get(obj, 'someProp'), 'blastix'); - } - - ['@test should not setup mandatory-setter if property is not writable'](assert) { - assert.expect(6); - - let obj = { }; - - Object.defineProperty(obj, 'a', { value: true }); - Object.defineProperty(obj, 'b', { value: false }); - Object.defineProperty(obj, 'c', { value: undefined }); - Object.defineProperty(obj, 'd', { value: undefined, writable: false }); - Object.defineProperty(obj, 'e', { value: undefined, configurable: false }); - Object.defineProperty(obj, 'f', { value: undefined, configurable: true }); - - watch(obj, 'a'); - watch(obj, 'b'); - watch(obj, 'c'); - watch(obj, 'd'); - watch(obj, 'e'); - watch(obj, 'f'); - - assert.ok(!hasMandatorySetter(obj, 'a'), 'mandatory-setter should not be installed'); - assert.ok(!hasMandatorySetter(obj, 'b'), 'mandatory-setter should not be installed'); - assert.ok(!hasMandatorySetter(obj, 'c'), 'mandatory-setter should not be installed'); - assert.ok(!hasMandatorySetter(obj, 'd'), 'mandatory-setter should not be installed'); - assert.ok(!hasMandatorySetter(obj, 'e'), 'mandatory-setter should not be installed'); - assert.ok(!hasMandatorySetter(obj, 'f'), 'mandatory-setter should not be installed'); - } - - ['@test should not teardown non mandatory-setter descriptor'](assert) { - assert.expect(1); - - let obj = { get a() { return 'hi'; } }; - - watch(obj, 'a'); - unwatch(obj, 'a'); - - assert.equal(obj.a, 'hi'); - } - - ['@test should not confuse non descriptor watched gets'](assert) { - assert.expect(2); - - let obj = { get a() { return 'hi'; } }; - - watch(obj, 'a'); - assert.equal(get(obj, 'a'), 'hi'); - assert.equal(obj.a, 'hi'); - } - - ['@test should not setup mandatory-setter if setter is already setup on property'](assert) { - assert.expect(2); - - let obj = { someProp: null }; - - Object.defineProperty(obj, 'someProp', { - get() { - return null; - }, - - set(value) { - assert.equal(value, 'foo-bar', 'custom setter was called'); - } - }); - - watch(obj, 'someProp'); - assert.ok(!hasMandatorySetter(obj, 'someProp'), 'mandatory-setter should not be installed'); - - obj.someProp = 'foo-bar'; - } + moduleFor( + 'mandory-setters', + class extends AbstractTestCase { + ['@test does not assert if property is not being watched'](assert) { + let obj = { + someProp: null, + toString() { + return 'custom-object'; + } + }; + + obj.someProp = 'blastix'; + assert.equal(get(obj, 'someProp'), 'blastix'); + } - ['@test watched ES5 setter should not be smashed by mandatory setter'](assert) { - let value; - let obj = { - get foo() { }, - set foo(_value) { - value = _value; - } - }; + ['@test should not setup mandatory-setter if property is not writable']( + assert + ) { + assert.expect(6); + + let obj = {}; + + Object.defineProperty(obj, 'a', { value: true }); + Object.defineProperty(obj, 'b', { value: false }); + Object.defineProperty(obj, 'c', { value: undefined }); + Object.defineProperty(obj, 'd', { value: undefined, writable: false }); + Object.defineProperty(obj, 'e', { + value: undefined, + configurable: false + }); + Object.defineProperty(obj, 'f', { + value: undefined, + configurable: true + }); + + watch(obj, 'a'); + watch(obj, 'b'); + watch(obj, 'c'); + watch(obj, 'd'); + watch(obj, 'e'); + watch(obj, 'f'); + + assert.ok( + !hasMandatorySetter(obj, 'a'), + 'mandatory-setter should not be installed' + ); + assert.ok( + !hasMandatorySetter(obj, 'b'), + 'mandatory-setter should not be installed' + ); + assert.ok( + !hasMandatorySetter(obj, 'c'), + 'mandatory-setter should not be installed' + ); + assert.ok( + !hasMandatorySetter(obj, 'd'), + 'mandatory-setter should not be installed' + ); + assert.ok( + !hasMandatorySetter(obj, 'e'), + 'mandatory-setter should not be installed' + ); + assert.ok( + !hasMandatorySetter(obj, 'f'), + 'mandatory-setter should not be installed' + ); + } - watch(obj, 'foo'); + ['@test should not teardown non mandatory-setter descriptor'](assert) { + assert.expect(1); - set(obj, 'foo', 2); - assert.equal(value, 2); - } + let obj = { + get a() { + return 'hi'; + } + }; - ['@test should not setup mandatory-setter if setter is already setup on property in parent prototype'](assert) { - assert.expect(2); + watch(obj, 'a'); + unwatch(obj, 'a'); - function Foo() { } + assert.equal(obj.a, 'hi'); + } - Object.defineProperty(Foo.prototype, 'someProp', { - get() { - return null; - }, + ['@test should not confuse non descriptor watched gets'](assert) { + assert.expect(2); - set(value) { - assert.equal(value, 'foo-bar', 'custom setter was called'); - } - }); + let obj = { + get a() { + return 'hi'; + } + }; - let obj = new Foo(); + watch(obj, 'a'); + assert.equal(get(obj, 'a'), 'hi'); + assert.equal(obj.a, 'hi'); + } - watch(obj, 'someProp'); - assert.ok(!hasMandatorySetter(obj, 'someProp'), 'mandatory-setter should not be installed'); + ['@test should not setup mandatory-setter if setter is already setup on property']( + assert + ) { + assert.expect(2); - obj.someProp = 'foo-bar'; - } + let obj = { someProp: null }; - ['@test should not setup mandatory-setter if setter is already setup on property in grandparent prototype'](assert) { - assert.expect(2); + Object.defineProperty(obj, 'someProp', { + get() { + return null; + }, - function Foo() { } + set(value) { + assert.equal(value, 'foo-bar', 'custom setter was called'); + } + }); - Object.defineProperty(Foo.prototype, 'someProp', { - get() { - return null; - }, + watch(obj, 'someProp'); + assert.ok( + !hasMandatorySetter(obj, 'someProp'), + 'mandatory-setter should not be installed' + ); - set(value) { - assert.equal(value, 'foo-bar', 'custom setter was called'); - } - }); + obj.someProp = 'foo-bar'; + } - function Bar() { } - Bar.prototype = Object.create(Foo.prototype); - Bar.prototype.constructor = Bar; + ['@test watched ES5 setter should not be smashed by mandatory setter']( + assert + ) { + let value; + let obj = { + get foo() {}, + set foo(_value) { + value = _value; + } + }; + + watch(obj, 'foo'); + + set(obj, 'foo', 2); + assert.equal(value, 2); + } - let obj = new Bar(); + ['@test should not setup mandatory-setter if setter is already setup on property in parent prototype']( + assert + ) { + assert.expect(2); - watch(obj, 'someProp'); - assert.ok(!hasMandatorySetter(obj, 'someProp'), 'mandatory-setter should not be installed'); + function Foo() {} - obj.someProp = 'foo-bar'; - } + Object.defineProperty(Foo.prototype, 'someProp', { + get() { + return null; + }, - ['@test should not setup mandatory-setter if setter is already setup on property in great grandparent prototype'](assert) { - assert.expect(2); + set(value) { + assert.equal(value, 'foo-bar', 'custom setter was called'); + } + }); - function Foo() { } + let obj = new Foo(); - Object.defineProperty(Foo.prototype, 'someProp', { - get() { - return null; - }, + watch(obj, 'someProp'); + assert.ok( + !hasMandatorySetter(obj, 'someProp'), + 'mandatory-setter should not be installed' + ); - set(value) { - assert.equal(value, 'foo-bar', 'custom setter was called'); - } - }); + obj.someProp = 'foo-bar'; + } - function Bar() { } - Bar.prototype = Object.create(Foo.prototype); - Bar.prototype.constructor = Bar; + ['@test should not setup mandatory-setter if setter is already setup on property in grandparent prototype']( + assert + ) { + assert.expect(2); - function Qux() { } - Qux.prototype = Object.create(Bar.prototype); - Qux.prototype.constructor = Qux; + function Foo() {} - let obj = new Qux(); + Object.defineProperty(Foo.prototype, 'someProp', { + get() { + return null; + }, - watch(obj, 'someProp'); - assert.ok(!hasMandatorySetter(obj, 'someProp'), 'mandatory-setter should not be installed'); + set(value) { + assert.equal(value, 'foo-bar', 'custom setter was called'); + } + }); - obj.someProp = 'foo-bar'; - } + function Bar() {} + Bar.prototype = Object.create(Foo.prototype); + Bar.prototype.constructor = Bar; - ['@test should assert if set without set when property is being watched']() { - let obj = { - someProp: null, - toString() { - return 'custom-object'; - } - }; + let obj = new Bar(); - watch(obj, 'someProp'); + watch(obj, 'someProp'); + assert.ok( + !hasMandatorySetter(obj, 'someProp'), + 'mandatory-setter should not be installed' + ); - expectAssertion(function() { obj.someProp = 'foo-bar'; - }, 'You must use set() to set the `someProp` property (of custom-object) to `foo-bar`.'); - } - - ['@test should not assert if set with set when property is being watched'](assert) { - let obj = { - someProp: null, - toString() { - return 'custom-object'; - } - }; - - watch(obj, 'someProp'); - set(obj, 'someProp', 'foo-bar'); + } - assert.equal(get(obj, 'someProp'), 'foo-bar'); - } + ['@test should not setup mandatory-setter if setter is already setup on property in great grandparent prototype']( + assert + ) { + assert.expect(2); - ['@test does not setup mandatory-setter if non-configurable'](assert) { - let obj = { - someProp: null, - toString() { - return 'custom-object'; - } - }; + function Foo() {} - Object.defineProperty(obj, 'someProp', { - configurable: false, - enumerable: true, - value: 'blastix' - }); + Object.defineProperty(Foo.prototype, 'someProp', { + get() { + return null; + }, - watch(obj, 'someProp'); - assert.ok(!(hasMandatorySetter(obj, 'someProp')), 'blastix'); - } + set(value) { + assert.equal(value, 'foo-bar', 'custom setter was called'); + } + }); - ['@test ensure after watch the property is restored (and the value is no-longer stored in meta) [non-enumerable]'](assert) { - let obj = { - someProp: null, - toString() { - return 'custom-object'; - } - }; + function Bar() {} + Bar.prototype = Object.create(Foo.prototype); + Bar.prototype.constructor = Bar; - Object.defineProperty(obj, 'someProp', { - configurable: true, - enumerable: false, - value: 'blastix' - }); + function Qux() {} + Qux.prototype = Object.create(Bar.prototype); + Qux.prototype.constructor = Qux; - watch(obj, 'someProp'); - assert.equal(hasMandatorySetter(obj, 'someProp'), true, 'should have a mandatory setter'); + let obj = new Qux(); - let descriptor = Object.getOwnPropertyDescriptor(obj, 'someProp'); + watch(obj, 'someProp'); + assert.ok( + !hasMandatorySetter(obj, 'someProp'), + 'mandatory-setter should not be installed' + ); - assert.equal(descriptor.enumerable, false, 'property should remain non-enumerable'); - assert.equal(descriptor.configurable, true, 'property should remain configurable'); - assert.equal(obj.someProp, 'blastix', 'expected value to be the getter'); + obj.someProp = 'foo-bar'; + } - assert.equal(descriptor.value, undefined, 'expected existing value to NOT remain'); + ['@test should assert if set without set when property is being watched']() { + let obj = { + someProp: null, + toString() { + return 'custom-object'; + } + }; - assert.ok(hasMetaValue(obj, 'someProp'), 'someProp is stored in meta.values'); + watch(obj, 'someProp'); - unwatch(obj, 'someProp'); + expectAssertion(function() { + obj.someProp = 'foo-bar'; + }, 'You must use set() to set the `someProp` property (of custom-object) to `foo-bar`.'); + } - assert.ok(!hasMetaValue(obj, 'someProp'), 'someProp is no longer stored in meta.values'); + ['@test should not assert if set with set when property is being watched']( + assert + ) { + let obj = { + someProp: null, + toString() { + return 'custom-object'; + } + }; - descriptor = Object.getOwnPropertyDescriptor(obj, 'someProp'); + watch(obj, 'someProp'); + set(obj, 'someProp', 'foo-bar'); - assert.equal(hasMandatorySetter(obj, 'someProp'), false, 'should no longer have a mandatory setter'); + assert.equal(get(obj, 'someProp'), 'foo-bar'); + } - assert.equal(descriptor.enumerable, false, 'property should remain non-enumerable'); - assert.equal(descriptor.configurable, true, 'property should remain configurable'); - assert.equal(obj.someProp, 'blastix', 'expected value to be the getter'); - assert.equal(descriptor.value, 'blastix', 'expected existing value to remain'); + ['@test does not setup mandatory-setter if non-configurable'](assert) { + let obj = { + someProp: null, + toString() { + return 'custom-object'; + } + }; + + Object.defineProperty(obj, 'someProp', { + configurable: false, + enumerable: true, + value: 'blastix' + }); + + watch(obj, 'someProp'); + assert.ok(!hasMandatorySetter(obj, 'someProp'), 'blastix'); + } - obj.someProp = 'new value'; + ['@test ensure after watch the property is restored (and the value is no-longer stored in meta) [non-enumerable]']( + assert + ) { + let obj = { + someProp: null, + toString() { + return 'custom-object'; + } + }; + + Object.defineProperty(obj, 'someProp', { + configurable: true, + enumerable: false, + value: 'blastix' + }); + + watch(obj, 'someProp'); + assert.equal( + hasMandatorySetter(obj, 'someProp'), + true, + 'should have a mandatory setter' + ); + + let descriptor = Object.getOwnPropertyDescriptor(obj, 'someProp'); + + assert.equal( + descriptor.enumerable, + false, + 'property should remain non-enumerable' + ); + assert.equal( + descriptor.configurable, + true, + 'property should remain configurable' + ); + assert.equal( + obj.someProp, + 'blastix', + 'expected value to be the getter' + ); + + assert.equal( + descriptor.value, + undefined, + 'expected existing value to NOT remain' + ); + + assert.ok( + hasMetaValue(obj, 'someProp'), + 'someProp is stored in meta.values' + ); + + unwatch(obj, 'someProp'); + + assert.ok( + !hasMetaValue(obj, 'someProp'), + 'someProp is no longer stored in meta.values' + ); + + descriptor = Object.getOwnPropertyDescriptor(obj, 'someProp'); + + assert.equal( + hasMandatorySetter(obj, 'someProp'), + false, + 'should no longer have a mandatory setter' + ); + + assert.equal( + descriptor.enumerable, + false, + 'property should remain non-enumerable' + ); + assert.equal( + descriptor.configurable, + true, + 'property should remain configurable' + ); + assert.equal( + obj.someProp, + 'blastix', + 'expected value to be the getter' + ); + assert.equal( + descriptor.value, + 'blastix', + 'expected existing value to remain' + ); + + obj.someProp = 'new value'; + + // make sure the descriptor remains correct (nothing funky, like a redefined, happened in the setter); + descriptor = Object.getOwnPropertyDescriptor(obj, 'someProp'); + + assert.equal( + descriptor.enumerable, + false, + 'property should remain non-enumerable' + ); + assert.equal( + descriptor.configurable, + true, + 'property should remain configurable' + ); + assert.equal( + descriptor.value, + 'new value', + 'expected existing value to NOT remain' + ); + assert.equal( + obj.someProp, + 'new value', + 'expected value to be the getter' + ); + assert.equal(obj.someProp, 'new value'); + } - // make sure the descriptor remains correct (nothing funky, like a redefined, happened in the setter); - descriptor = Object.getOwnPropertyDescriptor(obj, 'someProp'); + ['@test ensure after watch the property is restored (and the value is no-longer stored in meta) [enumerable]']( + assert + ) { + let obj = { + someProp: null, + toString() { + return 'custom-object'; + } + }; + + Object.defineProperty(obj, 'someProp', { + configurable: true, + enumerable: true, + value: 'blastix' + }); + + watch(obj, 'someProp'); + assert.equal( + hasMandatorySetter(obj, 'someProp'), + true, + 'should have a mandatory setter' + ); + + let descriptor = Object.getOwnPropertyDescriptor(obj, 'someProp'); + + assert.equal( + descriptor.enumerable, + true, + 'property should remain enumerable' + ); + assert.equal( + descriptor.configurable, + true, + 'property should remain configurable' + ); + assert.equal( + obj.someProp, + 'blastix', + 'expected value to be the getter' + ); + + assert.equal( + descriptor.value, + undefined, + 'expected existing value to NOT remain' + ); + + assert.ok( + hasMetaValue(obj, 'someProp'), + 'someProp is stored in meta.values' + ); + + unwatch(obj, 'someProp'); + + assert.ok( + !hasMetaValue(obj, 'someProp'), + 'someProp is no longer stored in meta.values' + ); + + descriptor = Object.getOwnPropertyDescriptor(obj, 'someProp'); + + assert.equal( + hasMandatorySetter(obj, 'someProp'), + false, + 'should no longer have a mandatory setter' + ); + + assert.equal( + descriptor.enumerable, + true, + 'property should remain enumerable' + ); + assert.equal( + descriptor.configurable, + true, + 'property should remain configurable' + ); + assert.equal( + obj.someProp, + 'blastix', + 'expected value to be the getter' + ); + assert.equal( + descriptor.value, + 'blastix', + 'expected existing value to remain' + ); + + obj.someProp = 'new value'; + + // make sure the descriptor remains correct (nothing funky, like a redefined, happened in the setter); + descriptor = Object.getOwnPropertyDescriptor(obj, 'someProp'); + + assert.equal( + descriptor.enumerable, + true, + 'property should remain enumerable' + ); + assert.equal( + descriptor.configurable, + true, + 'property should remain configurable' + ); + assert.equal( + descriptor.value, + 'new value', + 'expected existing value to NOT remain' + ); + assert.equal(obj.someProp, 'new value'); + } - assert.equal(descriptor.enumerable, false, 'property should remain non-enumerable'); - assert.equal(descriptor.configurable, true, 'property should remain configurable'); - assert.equal(descriptor.value, 'new value', 'expected existing value to NOT remain'); - assert.equal(obj.someProp, 'new value', 'expected value to be the getter'); - assert.equal(obj.someProp, 'new value'); - } + ['@test sets up mandatory-setter if property comes from prototype']( + assert + ) { + assert.expect(2); - ['@test ensure after watch the property is restored (and the value is no-longer stored in meta) [enumerable]'](assert) { - let obj = { - someProp: null, - toString() { - return 'custom-object'; - } - }; + let obj = { + someProp: null, + toString() { + return 'custom-object'; + } + }; - Object.defineProperty(obj, 'someProp', { - configurable: true, - enumerable: true, - value: 'blastix' - }); + let obj2 = Object.create(obj); - watch(obj, 'someProp'); - assert.equal(hasMandatorySetter(obj, 'someProp'), true, 'should have a mandatory setter'); + watch(obj2, 'someProp'); - let descriptor = Object.getOwnPropertyDescriptor(obj, 'someProp'); + assert.ok( + hasMandatorySetter(obj2, 'someProp'), + 'mandatory setter has been setup' + ); - assert.equal(descriptor.enumerable, true, 'property should remain enumerable'); - assert.equal(descriptor.configurable, true, 'property should remain configurable'); - assert.equal(obj.someProp, 'blastix', 'expected value to be the getter'); + expectAssertion(function() { + obj2.someProp = 'foo-bar'; + }, 'You must use set() to set the `someProp` property (of custom-object) to `foo-bar`.'); + } - assert.equal(descriptor.value, undefined, 'expected existing value to NOT remain'); + ['@test inheritance remains live'](assert) { + function Parent() {} + Parent.prototype.food = 'chips'; - assert.ok(hasMetaValue(obj, 'someProp'), 'someProp is stored in meta.values'); + let child = new Parent(); - unwatch(obj, 'someProp'); + assert.equal(child.food, 'chips'); - assert.ok(!hasMetaValue(obj, 'someProp'), 'someProp is no longer stored in meta.values'); + watch(child, 'food'); - descriptor = Object.getOwnPropertyDescriptor(obj, 'someProp'); + assert.equal(child.food, 'chips'); - assert.equal(hasMandatorySetter(obj, 'someProp'), false, 'should no longer have a mandatory setter'); + Parent.prototype.food = 'icecreame'; - assert.equal(descriptor.enumerable, true, 'property should remain enumerable'); - assert.equal(descriptor.configurable, true, 'property should remain configurable'); - assert.equal(obj.someProp, 'blastix', 'expected value to be the getter'); - assert.equal(descriptor.value, 'blastix', 'expected existing value to remain'); + assert.equal(child.food, 'icecreame'); - obj.someProp = 'new value'; + unwatch(child, 'food'); - // make sure the descriptor remains correct (nothing funky, like a redefined, happened in the setter); - descriptor = Object.getOwnPropertyDescriptor(obj, 'someProp'); + assert.equal(child.food, 'icecreame'); - assert.equal(descriptor.enumerable, true, 'property should remain enumerable'); - assert.equal(descriptor.configurable, true, 'property should remain configurable'); - assert.equal(descriptor.value, 'new value', 'expected existing value to NOT remain'); - assert.equal(obj.someProp, 'new value'); - } + Parent.prototype.food = 'chips'; - ['@test sets up mandatory-setter if property comes from prototype'](assert) { - assert.expect(2); + assert.equal(child.food, 'chips'); + } - let obj = { - someProp: null, - toString() { - return 'custom-object'; + ['@test inheritance remains live and preserves this'](assert) { + function Parent(food) { + this._food = food; } - }; - - let obj2 = Object.create(obj); - - watch(obj2, 'someProp'); - - assert.ok(hasMandatorySetter(obj2, 'someProp'), 'mandatory setter has been setup'); - - expectAssertion(function() { - obj2.someProp = 'foo-bar'; - }, 'You must use set() to set the `someProp` property (of custom-object) to `foo-bar`.'); - } - ['@test inheritance remains live'](assert) { - function Parent() {} - Parent.prototype.food = 'chips'; + Object.defineProperty(Parent.prototype, 'food', { + get() { + return this._food; + } + }); - let child = new Parent(); + let child = new Parent('chips'); - assert.equal(child.food, 'chips'); + assert.equal(child.food, 'chips'); - watch(child, 'food'); + watch(child, 'food'); - assert.equal(child.food, 'chips'); + assert.equal(child.food, 'chips'); - Parent.prototype.food = 'icecreame'; + child._food = 'icecreame'; - assert.equal(child.food, 'icecreame'); + assert.equal(child.food, 'icecreame'); - unwatch(child, 'food'); + unwatch(child, 'food'); - assert.equal(child.food, 'icecreame'); + assert.equal(child.food, 'icecreame'); - Parent.prototype.food = 'chips'; + let foodDesc = Object.getOwnPropertyDescriptor( + Parent.prototype, + 'food' + ); + assert.ok( + !foodDesc.configurable, + 'Parent.prototype.food desc should be non configable' + ); + assert.ok( + !foodDesc.enumerable, + 'Parent.prototype.food desc should be non enumerable' + ); - assert.equal(child.food, 'chips'); - } + assert.equal( + foodDesc.get.call({ + _food: 'hi' + }), + 'hi' + ); + assert.equal(foodDesc.set, undefined); - ['@test inheritance remains live and preserves this'](assert) { - function Parent(food) { - this._food = food; + assert.equal(child.food, 'icecreame'); } - - Object.defineProperty(Parent.prototype, 'food', { - get() { - return this._food; - } - }); - - let child = new Parent('chips'); - - assert.equal(child.food, 'chips'); - - watch(child, 'food'); - - assert.equal(child.food, 'chips'); - - child._food = 'icecreame'; - - assert.equal(child.food, 'icecreame'); - - unwatch(child, 'food'); - - assert.equal(child.food, 'icecreame'); - - let foodDesc = Object.getOwnPropertyDescriptor(Parent.prototype, 'food'); - assert.ok(!foodDesc.configurable, 'Parent.prototype.food desc should be non configable'); - assert.ok(!foodDesc.enumerable, 'Parent.prototype.food desc should be non enumerable'); - - assert.equal(foodDesc.get.call({ - _food: 'hi' - }), 'hi'); - assert.equal(foodDesc.set, undefined); - - assert.equal(child.food, 'icecreame'); } - }); + ); } diff --git a/packages/ember-metal/tests/accessors/set_path_test.js b/packages/ember-metal/tests/accessors/set_path_test.js index ae04193517b..4300826aef8 100644 --- a/packages/ember-metal/tests/accessors/set_path_test.js +++ b/packages/ember-metal/tests/accessors/set_path_test.js @@ -1,9 +1,5 @@ import { context } from 'ember-environment'; -import { - set, - trySet, - get -} from '../..'; +import { set, trySet, get } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; let originalLookup = context.lookup; @@ -26,66 +22,77 @@ function commonTeardown() { obj = null; } -moduleFor('set with path', class extends AbstractTestCase { - constructor() { - super(); - commonSetup(); - } +moduleFor( + 'set with path', + class extends AbstractTestCase { + constructor() { + super(); + commonSetup(); + } - teardown() { - commonTeardown(); - } + teardown() { + commonTeardown(); + } - ['@test [Foo, bar] -> Foo.bar'](assert) { - lookup.Foo = { toString() { return 'Foo'; } }; // Behave like an Ember.Namespace + ['@test [Foo, bar] -> Foo.bar'](assert) { + lookup.Foo = { + toString() { + return 'Foo'; + } + }; // Behave like an Ember.Namespace - set(lookup.Foo, 'bar', 'baz'); - assert.equal(get(lookup.Foo, 'bar'), 'baz'); - } + set(lookup.Foo, 'bar', 'baz'); + assert.equal(get(lookup.Foo, 'bar'), 'baz'); + } - // .......................................................... - // - // LOCAL PATHS + // .......................................................... + // + // LOCAL PATHS - ['@test [obj, foo] -> obj.foo'](assert) { - set(obj, 'foo', 'BAM'); - assert.equal(get(obj, 'foo'), 'BAM'); - } + ['@test [obj, foo] -> obj.foo'](assert) { + set(obj, 'foo', 'BAM'); + assert.equal(get(obj, 'foo'), 'BAM'); + } - ['@test [obj, foo.bar] -> obj.foo.bar'](assert) { - set(obj, 'foo.bar', 'BAM'); - assert.equal(get(obj, 'foo.bar'), 'BAM'); + ['@test [obj, foo.bar] -> obj.foo.bar'](assert) { + set(obj, 'foo.bar', 'BAM'); + assert.equal(get(obj, 'foo.bar'), 'BAM'); + } } -}); +); -moduleFor('set with path - deprecated', class extends AbstractTestCase { - constructor() { - super(); - commonSetup(); - } +moduleFor( + 'set with path - deprecated', + class extends AbstractTestCase { + constructor() { + super(); + commonSetup(); + } - teardown() { - commonTeardown(); - } + teardown() { + commonTeardown(); + } - // .......................................................... - // DEPRECATED - // - ['@test [obj, bla.bla] gives a proper exception message'](assert) { - let exceptionMessage = 'Property set failed: object in path \"bla\" could not be found or was destroyed.'; - try { - set(obj, 'bla.bla', 'BAM'); - } catch (ex) { - assert.equal(ex.message, exceptionMessage); + // .......................................................... + // DEPRECATED + // + ['@test [obj, bla.bla] gives a proper exception message'](assert) { + let exceptionMessage = + 'Property set failed: object in path "bla" could not be found or was destroyed.'; + try { + set(obj, 'bla.bla', 'BAM'); + } catch (ex) { + assert.equal(ex.message, exceptionMessage); + } } - } - ['@test [obj, foo.baz.bat] -> EXCEPTION'](assert) { - assert.throws(() => set(obj, 'foo.baz.bat', 'BAM')); - } + ['@test [obj, foo.baz.bat] -> EXCEPTION'](assert) { + assert.throws(() => set(obj, 'foo.baz.bat', 'BAM')); + } - ['@test [obj, foo.baz.bat] -> EXCEPTION'](assert) { - trySet(obj, 'foo.baz.bat', 'BAM'); - assert.ok(true, 'does not raise'); + ['@test [obj, foo.baz.bat] -> EXCEPTION'](assert) { + trySet(obj, 'foo.baz.bat', 'BAM'); + assert.ok(true, 'does not raise'); + } } -}); +); diff --git a/packages/ember-metal/tests/accessors/set_test.js b/packages/ember-metal/tests/accessors/set_test.js index ce8b1e09667..cae57aeb723 100644 --- a/packages/ember-metal/tests/accessors/set_test.js +++ b/packages/ember-metal/tests/accessors/set_test.js @@ -1,110 +1,145 @@ -import { - get, - set, - trySet, - setHasViews -} from '../..'; +import { get, set, trySet, setHasViews } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('set', class extends AbstractTestCase { - teardown() { - setHasViews(() => false); - } +moduleFor( + 'set', + class extends AbstractTestCase { + teardown() { + setHasViews(() => false); + } - ['@test should set arbitrary properties on an object'](assert) { - let obj = { - string: 'string', - number: 23, - boolTrue: true, - boolFalse: false, - nullValue: null, - undefinedValue: undefined - }; - - let newObj = { - undefinedValue: 'emberjs' - }; - - for (let key in obj) { - if (!obj.hasOwnProperty(key)) { - continue; + ['@test should set arbitrary properties on an object'](assert) { + let obj = { + string: 'string', + number: 23, + boolTrue: true, + boolFalse: false, + nullValue: null, + undefinedValue: undefined + }; + + let newObj = { + undefinedValue: 'emberjs' + }; + + for (let key in obj) { + if (!obj.hasOwnProperty(key)) { + continue; + } + + assert.equal( + set(newObj, key, obj[key]), + obj[key], + 'should return value' + ); + assert.equal(get(newObj, key), obj[key], 'should set value'); } - - assert.equal(set(newObj, key, obj[key]), obj[key], 'should return value'); - assert.equal(get(newObj, key), obj[key], 'should set value'); } - } - - ['@test should set a number key on an object'](assert) { - let obj = { }; - - set(obj, 1, 'first'); - assert.equal(obj[1], 'first'); - } - ['@test should set an array index'](assert) { - let arr = ['first', 'second']; + ['@test should set a number key on an object'](assert) { + let obj = {}; - set(arr, 1, 'lol'); - assert.deepEqual(arr, ['first', 'lol']); - } - - ['@test should call setUnknownProperty if defined and value is undefined'](assert) { - let obj = { - count: 0, + set(obj, 1, 'first'); + assert.equal(obj[1], 'first'); + } - unknownProperty() { - assert.ok(false, 'should not invoke unknownProperty if setUnknownProperty is defined'); - }, + ['@test should set an array index'](assert) { + let arr = ['first', 'second']; - setUnknownProperty(key, value) { - assert.equal(key, 'foo', 'should pass key'); - assert.equal(value, 'BAR', 'should pass key'); - this.count++; - return 'FOO'; - } - }; - - assert.equal(set(obj, 'foo', 'BAR'), 'BAR', 'should return set value'); - assert.equal(obj.count, 1, 'should have invoked'); - } + set(arr, 1, 'lol'); + assert.deepEqual(arr, ['first', 'lol']); + } - ['@test warn on attempts to call set with undefined as object']() { - expectAssertion(() => set(undefined, 'aProperty', 'BAM'), /Cannot call set with 'aProperty' on an undefined object./); - } + ['@test should call setUnknownProperty if defined and value is undefined']( + assert + ) { + let obj = { + count: 0, + + unknownProperty() { + assert.ok( + false, + 'should not invoke unknownProperty if setUnknownProperty is defined' + ); + }, + + setUnknownProperty(key, value) { + assert.equal(key, 'foo', 'should pass key'); + assert.equal(value, 'BAR', 'should pass key'); + this.count++; + return 'FOO'; + } + }; + + assert.equal(set(obj, 'foo', 'BAR'), 'BAR', 'should return set value'); + assert.equal(obj.count, 1, 'should have invoked'); + } - ['@test warn on attempts to call set with null as object']() { - expectAssertion(() => set(null, 'aProperty', 'BAM'), /Cannot call set with 'aProperty' on an undefined object./); - } + ['@test warn on attempts to call set with undefined as object']() { + expectAssertion( + () => set(undefined, 'aProperty', 'BAM'), + /Cannot call set with 'aProperty' on an undefined object./ + ); + } - ['@test warn on attempts to use set with an unsupported property path']() { - let obj = {}; - expectAssertion(() => set(obj, null, 42), /The key provided to set must be a string or number, you passed null/); - expectAssertion(() => set(obj, NaN, 42), /The key provided to set must be a string or number, you passed NaN/); - expectAssertion(() => set(obj, undefined, 42), /The key provided to set must be a string or number, you passed undefined/); - expectAssertion(() => set(obj, false, 42), /The key provided to set must be a string or number, you passed false/); - } + ['@test warn on attempts to call set with null as object']() { + expectAssertion( + () => set(null, 'aProperty', 'BAM'), + /Cannot call set with 'aProperty' on an undefined object./ + ); + } - ['@test warn on attempts of calling set on a destroyed object']() { - let obj = { isDestroyed: true }; + ['@test warn on attempts to use set with an unsupported property path']() { + let obj = {}; + expectAssertion( + () => set(obj, null, 42), + /The key provided to set must be a string or number, you passed null/ + ); + expectAssertion( + () => set(obj, NaN, 42), + /The key provided to set must be a string or number, you passed NaN/ + ); + expectAssertion( + () => set(obj, undefined, 42), + /The key provided to set must be a string or number, you passed undefined/ + ); + expectAssertion( + () => set(obj, false, 42), + /The key provided to set must be a string or number, you passed false/ + ); + } - expectAssertion(() => set(obj, 'favoriteFood', 'hot dogs'), 'calling set on destroyed object: [object Object].favoriteFood = hot dogs'); - } + ['@test warn on attempts of calling set on a destroyed object']() { + let obj = { isDestroyed: true }; - ['@test does not trigger auto-run assertion for objects that have not been tagged'](assert) { - setHasViews(() => true); - let obj = {}; + expectAssertion( + () => set(obj, 'favoriteFood', 'hot dogs'), + 'calling set on destroyed object: [object Object].favoriteFood = hot dogs' + ); + } - set(obj, 'foo', 'bar'); + ['@test does not trigger auto-run assertion for objects that have not been tagged']( + assert + ) { + setHasViews(() => true); + let obj = {}; - assert.equal(obj.foo, 'bar'); - } + set(obj, 'foo', 'bar'); - ['@test does not warn on attempts of calling set on a destroyed object with `trySet`'](assert) { - let obj = { isDestroyed: true }; + assert.equal(obj.foo, 'bar'); + } - trySet(obj, 'favoriteFood', 'hot dogs'); - assert.equal(obj.favoriteFood, undefined, 'does not set and does not error'); + ['@test does not warn on attempts of calling set on a destroyed object with `trySet`']( + assert + ) { + let obj = { isDestroyed: true }; + + trySet(obj, 'favoriteFood', 'hot dogs'); + assert.equal( + obj.favoriteFood, + undefined, + 'does not set and does not error' + ); + } } -}); - +); diff --git a/packages/ember-metal/tests/alias_test.js b/packages/ember-metal/tests/alias_test.js index 9d4c592ba95..19021e23d77 100644 --- a/packages/ember-metal/tests/alias_test.js +++ b/packages/ember-metal/tests/alias_test.js @@ -17,97 +17,111 @@ function incrementCount() { count++; } -moduleFor('ember-metal/alias', class extends AbstractTestCase { - beforeEach() { - obj = { foo: { faz: 'FOO' } }; - count = 0; - } - - afterEach() { - obj = null; - } - - ['@test should proxy get to alt key'](assert) { - defineProperty(obj, 'bar', alias('foo.faz')); - assert.equal(get(obj, 'bar'), 'FOO'); - } - - ['@test should proxy set to alt key'](assert) { - defineProperty(obj, 'bar', alias('foo.faz')); - set(obj, 'bar', 'BAR'); - assert.equal(get(obj, 'foo.faz'), 'BAR'); - } - - ['@test old dependent keys should not trigger property changes'](assert) { - let obj1 = Object.create(null); - defineProperty(obj1, 'foo', null, null); - defineProperty(obj1, 'bar', alias('foo')); - defineProperty(obj1, 'baz', alias('foo')); - defineProperty(obj1, 'baz', alias('bar')); // redefine baz - addObserver(obj1, 'baz', incrementCount); - - set(obj1, 'foo', 'FOO'); - assert.equal(count, 1); - - removeObserver(obj1, 'baz', incrementCount); - - set(obj1, 'foo', 'OOF'); - assert.equal(count, 1); - } - - [`@test inheriting an observer of the alias from the prototype then +moduleFor( + 'ember-metal/alias', + class extends AbstractTestCase { + beforeEach() { + obj = { foo: { faz: 'FOO' } }; + count = 0; + } + + afterEach() { + obj = null; + } + + ['@test should proxy get to alt key'](assert) { + defineProperty(obj, 'bar', alias('foo.faz')); + assert.equal(get(obj, 'bar'), 'FOO'); + } + + ['@test should proxy set to alt key'](assert) { + defineProperty(obj, 'bar', alias('foo.faz')); + set(obj, 'bar', 'BAR'); + assert.equal(get(obj, 'foo.faz'), 'BAR'); + } + + ['@test old dependent keys should not trigger property changes'](assert) { + let obj1 = Object.create(null); + defineProperty(obj1, 'foo', null, null); + defineProperty(obj1, 'bar', alias('foo')); + defineProperty(obj1, 'baz', alias('foo')); + defineProperty(obj1, 'baz', alias('bar')); // redefine baz + addObserver(obj1, 'baz', incrementCount); + + set(obj1, 'foo', 'FOO'); + assert.equal(count, 1); + + removeObserver(obj1, 'baz', incrementCount); + + set(obj1, 'foo', 'OOF'); + assert.equal(count, 1); + } + + [`@test inheriting an observer of the alias from the prototype then redefining the alias on the instance to another property dependent on same key does not call the observer twice`](assert) { - let obj1 = Object.create(null); - - meta(obj1).proto = obj1; - - defineProperty(obj1, 'foo', null, null); - defineProperty(obj1, 'bar', alias('foo')); - defineProperty(obj1, 'baz', alias('foo')); - addObserver(obj1, 'baz', incrementCount); - - let obj2 = Object.create(obj1); - defineProperty(obj2, 'baz', alias('bar')); // override baz - - set(obj2, 'foo', 'FOO'); - assert.equal(count, 1); - - removeObserver(obj2, 'baz', incrementCount); - - set(obj2, 'foo', 'OOF'); - assert.equal(count, 1); - } - - ['@test an observer of the alias works if added after defining the alias'](assert) { - defineProperty(obj, 'bar', alias('foo.faz')); - addObserver(obj, 'bar', incrementCount); - assert.ok(isWatching(obj, 'foo.faz')); - set(obj, 'foo.faz', 'BAR'); - assert.equal(count, 1); - } - - ['@test an observer of the alias works if added before defining the alias'](assert) { - addObserver(obj, 'bar', incrementCount); - defineProperty(obj, 'bar', alias('foo.faz')); - assert.ok(isWatching(obj, 'foo.faz')); - set(obj, 'foo.faz', 'BAR'); - assert.equal(count, 1); + let obj1 = Object.create(null); + + meta(obj1).proto = obj1; + + defineProperty(obj1, 'foo', null, null); + defineProperty(obj1, 'bar', alias('foo')); + defineProperty(obj1, 'baz', alias('foo')); + addObserver(obj1, 'baz', incrementCount); + + let obj2 = Object.create(obj1); + defineProperty(obj2, 'baz', alias('bar')); // override baz + + set(obj2, 'foo', 'FOO'); + assert.equal(count, 1); + + removeObserver(obj2, 'baz', incrementCount); + + set(obj2, 'foo', 'OOF'); + assert.equal(count, 1); + } + + ['@test an observer of the alias works if added after defining the alias']( + assert + ) { + defineProperty(obj, 'bar', alias('foo.faz')); + addObserver(obj, 'bar', incrementCount); + assert.ok(isWatching(obj, 'foo.faz')); + set(obj, 'foo.faz', 'BAR'); + assert.equal(count, 1); + } + + ['@test an observer of the alias works if added before defining the alias']( + assert + ) { + addObserver(obj, 'bar', incrementCount); + defineProperty(obj, 'bar', alias('foo.faz')); + assert.ok(isWatching(obj, 'foo.faz')); + set(obj, 'foo.faz', 'BAR'); + assert.equal(count, 1); + } + + ['@test object with alias is dirtied if interior object of alias is set after consumption']( + assert + ) { + defineProperty(obj, 'bar', alias('foo.faz')); + get(obj, 'bar'); + + let tag = tagFor(obj); + let tagValue = tag.value(); + set(obj, 'foo.faz', 'BAR'); + + assert.ok( + !tag.validate(tagValue), + 'setting the aliased key should dirty the object' + ); + } + + ['@test setting alias on self should fail assertion']() { + expectAssertion( + () => defineProperty(obj, 'bar', alias('bar')), + "Setting alias 'bar' on self" + ); + } } - - ['@test object with alias is dirtied if interior object of alias is set after consumption'](assert) { - defineProperty(obj, 'bar', alias('foo.faz')); - get(obj, 'bar'); - - let tag = tagFor(obj); - let tagValue = tag.value(); - set(obj, 'foo.faz', 'BAR'); - - assert.ok(!tag.validate(tagValue), 'setting the aliased key should dirty the object'); - } - - ['@test setting alias on self should fail assertion']() { - expectAssertion(() => defineProperty(obj, 'bar', alias('bar')), 'Setting alias \'bar\' on self'); - } -}); - +); diff --git a/packages/ember-metal/tests/cache_test.js b/packages/ember-metal/tests/cache_test.js index 396e32d6286..f2d7c90fb56 100644 --- a/packages/ember-metal/tests/cache_test.js +++ b/packages/ember-metal/tests/cache_test.js @@ -1,95 +1,99 @@ import { Cache } from '..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('Cache', class extends AbstractTestCase { - ['@test basic'](assert) { - let cache = new Cache(100, key => key.toUpperCase()); +moduleFor( + 'Cache', + class extends AbstractTestCase { + ['@test basic'](assert) { + let cache = new Cache(100, key => key.toUpperCase()); - assert.equal(cache.get('foo'), 'FOO'); - assert.equal(cache.get('bar'), 'BAR'); - assert.equal(cache.get('foo'), 'FOO'); - } - - ['@test explicit sets'](assert) { - let cache = new Cache(100, key => key.toUpperCase()); + assert.equal(cache.get('foo'), 'FOO'); + assert.equal(cache.get('bar'), 'BAR'); + assert.equal(cache.get('foo'), 'FOO'); + } - assert.equal(cache.get('foo'), 'FOO'); + ['@test explicit sets'](assert) { + let cache = new Cache(100, key => key.toUpperCase()); - assert.equal(cache.set('foo', 'FOO!!!'), 'FOO!!!'); + assert.equal(cache.get('foo'), 'FOO'); - assert.equal(cache.get('foo'), 'FOO!!!'); + assert.equal(cache.set('foo', 'FOO!!!'), 'FOO!!!'); - assert.strictEqual(cache.set('foo', undefined), undefined); + assert.equal(cache.get('foo'), 'FOO!!!'); - assert.strictEqual(cache.get('foo'), undefined); - } + assert.strictEqual(cache.set('foo', undefined), undefined); - ['@test caches computation correctly'](assert) { - let count = 0; - let cache = new Cache(100, key => { - count++; - return key.toUpperCase(); - }); - - assert.equal(count, 0); - cache.get('foo'); - assert.equal(count, 1); - cache.get('bar'); - assert.equal(count, 2); - cache.get('bar'); - assert.equal(count, 2); - cache.get('foo'); - assert.equal(count, 2); - } + assert.strictEqual(cache.get('foo'), undefined); + } - ['@test caches computation correctly with custom cache keys'](assert) { - let count = 0; - let cache = new Cache( - 100, - obj => { + ['@test caches computation correctly'](assert) { + let count = 0; + let cache = new Cache(100, key => { count++; - return obj.value.toUpperCase(); - }, - obj => obj.key - ); - - assert.equal(count, 0); - cache.get({ key: 'foo', value: 'foo' }); - assert.equal(count, 1); - cache.get({ key: 'bar', value: 'bar' }); - assert.equal(count, 2); - cache.get({ key: 'bar', value: 'bar' }); - assert.equal(count, 2); - cache.get({ key: 'foo', value: 'foo' }); - assert.equal(count, 2); - } - - ['@test handles undefined value correctly'](assert) { - let count = 0; - let cache = new Cache(100, () => { count++; }); - - assert.equal(count, 0); - assert.strictEqual(cache.get('foo'), undefined); - assert.equal(count, 1); - assert.strictEqual(cache.get('bar'), undefined); - assert.equal(count, 2); - assert.strictEqual(cache.get('bar'), undefined); - assert.equal(count, 2); - assert.strictEqual(cache.get('foo'), undefined); - assert.equal(count, 2); - } - - ['@test continues working after reaching cache limit'](assert) { - let cache = new Cache(3, key => key.toUpperCase()); - - cache.get('a'); - cache.get('b'); - cache.get('c'); - - assert.equal(cache.get('d'), 'D'); - assert.equal(cache.get('a'), 'A'); - assert.equal(cache.get('b'), 'B'); - assert.equal(cache.get('c'), 'C'); + return key.toUpperCase(); + }); + + assert.equal(count, 0); + cache.get('foo'); + assert.equal(count, 1); + cache.get('bar'); + assert.equal(count, 2); + cache.get('bar'); + assert.equal(count, 2); + cache.get('foo'); + assert.equal(count, 2); + } + + ['@test caches computation correctly with custom cache keys'](assert) { + let count = 0; + let cache = new Cache( + 100, + obj => { + count++; + return obj.value.toUpperCase(); + }, + obj => obj.key + ); + + assert.equal(count, 0); + cache.get({ key: 'foo', value: 'foo' }); + assert.equal(count, 1); + cache.get({ key: 'bar', value: 'bar' }); + assert.equal(count, 2); + cache.get({ key: 'bar', value: 'bar' }); + assert.equal(count, 2); + cache.get({ key: 'foo', value: 'foo' }); + assert.equal(count, 2); + } + + ['@test handles undefined value correctly'](assert) { + let count = 0; + let cache = new Cache(100, () => { + count++; + }); + + assert.equal(count, 0); + assert.strictEqual(cache.get('foo'), undefined); + assert.equal(count, 1); + assert.strictEqual(cache.get('bar'), undefined); + assert.equal(count, 2); + assert.strictEqual(cache.get('bar'), undefined); + assert.equal(count, 2); + assert.strictEqual(cache.get('foo'), undefined); + assert.equal(count, 2); + } + + ['@test continues working after reaching cache limit'](assert) { + let cache = new Cache(3, key => key.toUpperCase()); + + cache.get('a'); + cache.get('b'); + cache.get('c'); + + assert.equal(cache.get('d'), 'D'); + assert.equal(cache.get('a'), 'A'); + assert.equal(cache.get('b'), 'B'); + assert.equal(cache.get('c'), 'C'); + } } -}); - +); diff --git a/packages/ember-metal/tests/chains_test.js b/packages/ember-metal/tests/chains_test.js index 3dd25e6be8a..66f10bf98d4 100644 --- a/packages/ember-metal/tests/chains_test.js +++ b/packages/ember-metal/tests/chains_test.js @@ -14,47 +14,53 @@ import { } from '..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('Chains', class extends AbstractTestCase { - ['@test finishChains should properly copy chains from prototypes to instances'](assert) { - function didChange() {} +moduleFor( + 'Chains', + class extends AbstractTestCase { + ['@test finishChains should properly copy chains from prototypes to instances']( + assert + ) { + function didChange() {} - let obj = {}; - addObserver(obj, 'foo.bar', null, didChange); + let obj = {}; + addObserver(obj, 'foo.bar', null, didChange); - let childObj = Object.create(obj); + let childObj = Object.create(obj); - let parentMeta = meta(obj); - let childMeta = meta(childObj); + let parentMeta = meta(obj); + let childMeta = meta(childObj); - finishChains(childMeta); + finishChains(childMeta); - assert.ok(parentMeta.readableChains() !== childMeta.readableChains(), 'The chains object is copied'); - } - - ['@test does not observe primitive values'](assert) { - let obj = { - foo: { bar: 'STRING' } - }; + assert.ok( + parentMeta.readableChains() !== childMeta.readableChains(), + 'The chains object is copied' + ); + } - addObserver(obj, 'foo.bar.baz', null, function() {}); - let meta = peekMeta(obj); - assert.notOk(meta._object); - } + ['@test does not observe primitive values'](assert) { + let obj = { + foo: { bar: 'STRING' } + }; + addObserver(obj, 'foo.bar.baz', null, function() {}); + let meta = peekMeta(obj); + assert.notOk(meta._object); + } - ['@test observer and CP chains'](assert) { - let obj = { }; + ['@test observer and CP chains'](assert) { + let obj = {}; - defineProperty(obj, 'foo', computed('qux.[]', function() { })); - defineProperty(obj, 'qux', computed(function() { })); + defineProperty(obj, 'foo', computed('qux.[]', function() {})); + defineProperty(obj, 'qux', computed(function() {})); - // create DK chains - get(obj, 'foo'); + // create DK chains + get(obj, 'foo'); - // create observer chain - addObserver(obj, 'qux.length', function() { }); + // create observer chain + addObserver(obj, 'qux.length', function() {}); - /* + /* +-----+ | qux | root CP +-----+ @@ -67,12 +73,12 @@ moduleFor('Chains', class extends AbstractTestCase { observer CP(foo, 'qux.[]') */ - // invalidate qux - notifyPropertyChange(obj, 'qux'); + // invalidate qux + notifyPropertyChange(obj, 'qux'); - // CP chain is blown away + // CP chain is blown away - /* + /* +-----+ | qux | root CP +-----+ @@ -85,63 +91,69 @@ moduleFor('Chains', class extends AbstractTestCase { observer CP(foo, 'qux.[]') */ - get(obj, 'qux'); // CP chain re-recreated - assert.ok(true, 'no crash'); - } - - ['@test checks cache correctly'](assert) { - let obj = {}; - let parentChainNode = new ChainNode(null, null, obj); - let chainNode = new ChainNode(parentChainNode, 'foo'); - - defineProperty(obj, 'foo', computed(function() { return undefined; })); - get(obj, 'foo'); - - assert.strictEqual(chainNode.value(), undefined); - } - - ['@test chains are watched correctly'](assert) { - let obj = { foo: { bar: { baz: 1 } } }; - - watch(obj, 'foo.bar.baz'); - - assert.equal(watcherCount(obj, 'foo'), 1); - assert.equal(watcherCount(obj, 'foo.bar'), 0); - assert.equal(watcherCount(obj, 'foo.bar.baz'), 1); - assert.equal(watcherCount(obj.foo, 'bar'), 1); - assert.equal(watcherCount(obj.foo, 'bar.baz'), 0); - assert.equal(watcherCount(obj.foo.bar, 'baz'), 1); - - unwatch(obj, 'foo.bar.baz'); - - assert.equal(watcherCount(obj, 'foo'), 0); - assert.equal(watcherCount(obj, 'foo.bar'), 0); - assert.equal(watcherCount(obj, 'foo.bar.baz'), 0); - assert.equal(watcherCount(obj.foo, 'bar'), 0); - assert.equal(watcherCount(obj.foo, 'bar.baz'), 0); - assert.equal(watcherCount(obj.foo.bar, 'baz'), 0); - } - - ['@test chains with single character keys are watched correctly'](assert) { - let obj = { a: { b: { c: 1 } } }; - - watch(obj, 'a.b.c'); - - assert.equal(watcherCount(obj, 'a'), 1); - assert.equal(watcherCount(obj, 'a.b'), 0); - assert.equal(watcherCount(obj, 'a.b.c'), 1); - assert.equal(watcherCount(obj.a, 'b'), 1); - assert.equal(watcherCount(obj.a, 'b.c'), 0); - assert.equal(watcherCount(obj.a.b, 'c'), 1); - - unwatch(obj, 'a.b.c'); - - assert.equal(watcherCount(obj, 'a'), 0); - assert.equal(watcherCount(obj, 'a.b'), 0); - assert.equal(watcherCount(obj, 'a.b.c'), 0); - assert.equal(watcherCount(obj.a, 'b'), 0); - assert.equal(watcherCount(obj.a, 'b.c'), 0); - assert.equal(watcherCount(obj.a.b, 'c'), 0); + get(obj, 'qux'); // CP chain re-recreated + assert.ok(true, 'no crash'); + } + + ['@test checks cache correctly'](assert) { + let obj = {}; + let parentChainNode = new ChainNode(null, null, obj); + let chainNode = new ChainNode(parentChainNode, 'foo'); + + defineProperty( + obj, + 'foo', + computed(function() { + return undefined; + }) + ); + get(obj, 'foo'); + + assert.strictEqual(chainNode.value(), undefined); + } + + ['@test chains are watched correctly'](assert) { + let obj = { foo: { bar: { baz: 1 } } }; + + watch(obj, 'foo.bar.baz'); + + assert.equal(watcherCount(obj, 'foo'), 1); + assert.equal(watcherCount(obj, 'foo.bar'), 0); + assert.equal(watcherCount(obj, 'foo.bar.baz'), 1); + assert.equal(watcherCount(obj.foo, 'bar'), 1); + assert.equal(watcherCount(obj.foo, 'bar.baz'), 0); + assert.equal(watcherCount(obj.foo.bar, 'baz'), 1); + + unwatch(obj, 'foo.bar.baz'); + + assert.equal(watcherCount(obj, 'foo'), 0); + assert.equal(watcherCount(obj, 'foo.bar'), 0); + assert.equal(watcherCount(obj, 'foo.bar.baz'), 0); + assert.equal(watcherCount(obj.foo, 'bar'), 0); + assert.equal(watcherCount(obj.foo, 'bar.baz'), 0); + assert.equal(watcherCount(obj.foo.bar, 'baz'), 0); + } + + ['@test chains with single character keys are watched correctly'](assert) { + let obj = { a: { b: { c: 1 } } }; + + watch(obj, 'a.b.c'); + + assert.equal(watcherCount(obj, 'a'), 1); + assert.equal(watcherCount(obj, 'a.b'), 0); + assert.equal(watcherCount(obj, 'a.b.c'), 1); + assert.equal(watcherCount(obj.a, 'b'), 1); + assert.equal(watcherCount(obj.a, 'b.c'), 0); + assert.equal(watcherCount(obj.a.b, 'c'), 1); + + unwatch(obj, 'a.b.c'); + + assert.equal(watcherCount(obj, 'a'), 0); + assert.equal(watcherCount(obj, 'a.b'), 0); + assert.equal(watcherCount(obj, 'a.b.c'), 0); + assert.equal(watcherCount(obj.a, 'b'), 0); + assert.equal(watcherCount(obj.a, 'b.c'), 0); + assert.equal(watcherCount(obj.a.b, 'c'), 0); + } } -}); - +); diff --git a/packages/ember-metal/tests/computed_test.js b/packages/ember-metal/tests/computed_test.js index 339c3ae705a..7d01b5cc0fc 100644 --- a/packages/ember-metal/tests/computed_test.js +++ b/packages/ember-metal/tests/computed_test.js @@ -16,517 +16,734 @@ import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; let obj, count; -moduleFor('computed', class extends AbstractTestCase { - ['@test computed property should be an instance of descriptor'](assert) { - assert.ok(computed(function() {}) instanceof Descriptor); - } +moduleFor( + 'computed', + class extends AbstractTestCase { + ['@test computed property should be an instance of descriptor'](assert) { + assert.ok(computed(function() {}) instanceof Descriptor); + } - ['@test computed properties assert the presence of a getter or setter function']() { - expectAssertion(function() { - computed('nogetternorsetter', {}); - }, 'Computed properties must receive a getter or a setter, you passed none.'); - } + ['@test computed properties assert the presence of a getter or setter function']() { + expectAssertion(function() { + computed('nogetternorsetter', {}); + }, 'Computed properties must receive a getter or a setter, you passed none.'); + } - ['@test computed properties check for the presence of a function or configuration object']() { - expectAssertion(function() { - computed('nolastargument'); - }, 'computed expects a function or an object as last argument.'); - } + ['@test computed properties check for the presence of a function or configuration object']() { + expectAssertion(function() { + computed('nolastargument'); + }, 'computed expects a function or an object as last argument.'); + } - ['@test computed properties defined with an object only allow `get` and `set` keys']() { - expectAssertion(function() { - computed({ - get() {}, - set() {}, - other() {} - }); - }, 'Config object passed to computed can only contain `get` and `set` keys.'); - } + ['@test computed properties defined with an object only allow `get` and `set` keys']() { + expectAssertion(function() { + computed({ + get() {}, + set() {}, + other() {} + }); + }, 'Config object passed to computed can only contain `get` and `set` keys.'); + } + + ['@test computed property can be accessed without `get`'](assert) { + if (EMBER_METAL_ES5_GETTERS) { + let obj = {}; + let count = 0; + defineProperty( + obj, + 'foo', + computed(function(key) { + count++; + return 'computed ' + key; + }) + ); + + assert.equal(obj.foo, 'computed foo', 'should return value'); + assert.equal(count, 1, 'should have invoked computed property'); + } else { + assert.expect(0); + } + } - ['@test computed property can be accessed without `get`'](assert) { - if (EMBER_METAL_ES5_GETTERS) { + ['@test accessing computed property descriptor through the object triggers an assertion']( + assert + ) { + if (!EMBER_METAL_ES5_GETTERS && DESCRIPTOR_TRAP) { + let obj = { + toString() { + return 'obj'; + } + }; + let count = 0; + defineProperty( + obj, + 'foo', + computed(function(key) { + count++; + return 'computed ' + key; + }) + ); + + expectAssertion( + () => obj.foo.isDescriptor, + /You attempted to access `foo\.isDescriptor` \(on `obj`\)/ + ); + expectAssertion( + () => obj.foo.get(), + /You attempted to access `foo\.get` \(on `obj`\)/ + ); + assert.strictEqual( + count, + 0, + 'should not have invoked computed property' + ); + } else { + assert.expect(0); + } + } + + ['@test defining computed property should invoke property on get'](assert) { let obj = {}; let count = 0; - defineProperty(obj, 'foo', computed(function(key) { - count++; - return 'computed ' + key; - })); - - assert.equal(obj.foo, 'computed foo', 'should return value'); + defineProperty( + obj, + 'foo', + computed(function(key) { + count++; + return 'computed ' + key; + }) + ); + + assert.equal(get(obj, 'foo'), 'computed foo', 'should return value'); assert.equal(count, 1, 'should have invoked computed property'); - } else { - assert.expect(0); } - } - ['@test accessing computed property descriptor through the object triggers an assertion'](assert) { - if (!EMBER_METAL_ES5_GETTERS && DESCRIPTOR_TRAP) { - let obj = { toString() { return 'obj'; } }; + ['@test defining computed property should invoke property on set'](assert) { + let obj = {}; let count = 0; - defineProperty(obj, 'foo', computed(function(key) { - count++; - return 'computed ' + key; - })); + defineProperty( + obj, + 'foo', + computed({ + get(key) { + return this['__' + key]; + }, + set(key, value) { + count++; + this['__' + key] = 'computed ' + value; + return this['__' + key]; + } + }) + ); - expectAssertion(() => obj.foo.isDescriptor, /You attempted to access `foo\.isDescriptor` \(on `obj`\)/); - expectAssertion(() => obj.foo.get(), /You attempted to access `foo\.get` \(on `obj`\)/); - assert.strictEqual(count, 0, 'should not have invoked computed property'); - } else { - assert.expect(0); + assert.equal(set(obj, 'foo', 'bar'), 'bar', 'should return set value'); + assert.equal(count, 1, 'should have invoked computed property'); + assert.equal(get(obj, 'foo'), 'computed bar', 'should return new value'); } - } - ['@test defining computed property should invoke property on get'](assert) { - let obj = {}; - let count = 0; - defineProperty(obj, 'foo', computed(function(key) { - count++; - return 'computed ' + key; - })); + ['@test defining a computed property with a dependent key ending with @each is expanded to []']( + assert + ) { + let cp = computed('blazo.@each', function() {}); - assert.equal(get(obj, 'foo'), 'computed foo', 'should return value'); - assert.equal(count, 1, 'should have invoked computed property'); - } - - ['@test defining computed property should invoke property on set'](assert) { - let obj = {}; - let count = 0; - defineProperty(obj, 'foo', computed({ - get(key) { return this['__' + key]; }, - set(key, value) { - count++; - this['__' + key] = 'computed ' + value; - return this['__' + key]; - } - })); - - assert.equal(set(obj, 'foo', 'bar'), 'bar', 'should return set value'); - assert.equal(count, 1, 'should have invoked computed property'); - assert.equal(get(obj, 'foo'), 'computed bar', 'should return new value'); - } + assert.deepEqual(cp._dependentKeys, ['blazo.[]']); - ['@test defining a computed property with a dependent key ending with @each is expanded to []'](assert) { - let cp = computed('blazo.@each', function() { }); + cp = computed('qux', 'zoopa.@each', function() {}); - assert.deepEqual(cp._dependentKeys, ['blazo.[]']); - - cp = computed('qux', 'zoopa.@each', function() { }); - - assert.deepEqual(cp._dependentKeys, ['qux', 'zoopa.[]']); - } + assert.deepEqual(cp._dependentKeys, ['qux', 'zoopa.[]']); + } - ['@test defining a computed property with a dependent key more than one level deep beyond @each is not supported']() { - expectNoWarning(() => { - computed('todos', () => {}); - }); + ['@test defining a computed property with a dependent key more than one level deep beyond @each is not supported']() { + expectNoWarning(() => { + computed('todos', () => {}); + }); - expectNoWarning(() => { - computed('todos.@each.owner', () => {}); - }); + expectNoWarning(() => { + computed('todos.@each.owner', () => {}); + }); - expectWarning(() => { - computed('todos.@each.owner.name', () => {}); - }, /You used the key "todos\.@each\.owner\.name" which is invalid\. /); + expectWarning(() => { + computed('todos.@each.owner.name', () => {}); + }, /You used the key "todos\.@each\.owner\.name" which is invalid\. /); - expectWarning(() => { - computed('todos.@each.owner.@each.name', () => {}); - }, /You used the key "todos\.@each\.owner\.@each\.name" which is invalid\. /); + expectWarning(() => { + computed('todos.@each.owner.@each.name', () => {}); + }, /You used the key "todos\.@each\.owner\.@each\.name" which is invalid\. /); + } } -}); +); let objA, objB; -moduleFor('computed should inherit through prototype', class extends AbstractTestCase { - beforeEach() { - objA = { __foo: 'FOO' }; - defineProperty(objA, 'foo', computed({ - get(key) { - return this['__' + key]; - }, - set(key, value) { - this['__' + key] = 'computed ' + value; - return this['__' + key]; - } - })); - - objB = Object.create(objA); - objB.__foo = 'FOO'; // make a copy; - } +moduleFor( + 'computed should inherit through prototype', + class extends AbstractTestCase { + beforeEach() { + objA = { __foo: 'FOO' }; + defineProperty( + objA, + 'foo', + computed({ + get(key) { + return this['__' + key]; + }, + set(key, value) { + this['__' + key] = 'computed ' + value; + return this['__' + key]; + } + }) + ); - afterEach() { - objA = objB = null; - } + objB = Object.create(objA); + objB.__foo = 'FOO'; // make a copy; + } - ['@test using get() and set()'](assert) { - assert.equal(get(objA, 'foo'), 'FOO', 'should get FOO from A'); - assert.equal(get(objB, 'foo'), 'FOO', 'should get FOO from B'); + afterEach() { + objA = objB = null; + } - set(objA, 'foo', 'BIFF'); - assert.equal(get(objA, 'foo'), 'computed BIFF', 'should change A'); - assert.equal(get(objB, 'foo'), 'FOO', 'should NOT change B'); + ['@test using get() and set()'](assert) { + assert.equal(get(objA, 'foo'), 'FOO', 'should get FOO from A'); + assert.equal(get(objB, 'foo'), 'FOO', 'should get FOO from B'); - set(objB, 'foo', 'bar'); - assert.equal(get(objB, 'foo'), 'computed bar', 'should change B'); - assert.equal(get(objA, 'foo'), 'computed BIFF', 'should NOT change A'); + set(objA, 'foo', 'BIFF'); + assert.equal(get(objA, 'foo'), 'computed BIFF', 'should change A'); + assert.equal(get(objB, 'foo'), 'FOO', 'should NOT change B'); - set(objA, 'foo', 'BAZ'); - assert.equal(get(objA, 'foo'), 'computed BAZ', 'should change A'); - assert.equal(get(objB, 'foo'), 'computed bar', 'should NOT change B'); - } -}); - -moduleFor('redefining computed property to normal', class extends AbstractTestCase { - beforeEach() { - objA = { __foo: 'FOO' }; - defineProperty(objA, 'foo', computed({ - get(key) { - return this['__' + key]; - }, - set(key, value) { - this['__' + key] = 'computed ' + value; - return this['__' + key]; - } - })); + set(objB, 'foo', 'bar'); + assert.equal(get(objB, 'foo'), 'computed bar', 'should change B'); + assert.equal(get(objA, 'foo'), 'computed BIFF', 'should NOT change A'); - objB = Object.create(objA); - defineProperty(objB, 'foo'); // make this just a normal property. + set(objA, 'foo', 'BAZ'); + assert.equal(get(objA, 'foo'), 'computed BAZ', 'should change A'); + assert.equal(get(objB, 'foo'), 'computed bar', 'should NOT change B'); + } } +); + +moduleFor( + 'redefining computed property to normal', + class extends AbstractTestCase { + beforeEach() { + objA = { __foo: 'FOO' }; + defineProperty( + objA, + 'foo', + computed({ + get(key) { + return this['__' + key]; + }, + set(key, value) { + this['__' + key] = 'computed ' + value; + return this['__' + key]; + } + }) + ); - afterEach() { - objA = objB = null; - } + objB = Object.create(objA); + defineProperty(objB, 'foo'); // make this just a normal property. + } - ['@test using get() and set()'](assert) { - assert.equal(get(objA, 'foo'), 'FOO', 'should get FOO from A'); - assert.equal(get(objB, 'foo'), undefined, 'should get undefined from B'); + afterEach() { + objA = objB = null; + } - set(objA, 'foo', 'BIFF'); - assert.equal(get(objA, 'foo'), 'computed BIFF', 'should change A'); - assert.equal(get(objB, 'foo'), undefined, 'should NOT change B'); + ['@test using get() and set()'](assert) { + assert.equal(get(objA, 'foo'), 'FOO', 'should get FOO from A'); + assert.equal(get(objB, 'foo'), undefined, 'should get undefined from B'); - set(objB, 'foo', 'bar'); - assert.equal(get(objB, 'foo'), 'bar', 'should change B'); - assert.equal(get(objA, 'foo'), 'computed BIFF', 'should NOT change A'); + set(objA, 'foo', 'BIFF'); + assert.equal(get(objA, 'foo'), 'computed BIFF', 'should change A'); + assert.equal(get(objB, 'foo'), undefined, 'should NOT change B'); - set(objA, 'foo', 'BAZ'); - assert.equal(get(objA, 'foo'), 'computed BAZ', 'should change A'); - assert.equal(get(objB, 'foo'), 'bar', 'should NOT change B'); - } -}); - -moduleFor('redefining computed property to another property', class extends AbstractTestCase { - beforeEach() { - objA = { __foo: 'FOO' }; - defineProperty(objA, 'foo', computed({ - get(key) { - return this['__' + key]; - }, - set(key, value) { - this['__' + key] = 'A ' + value; - return this['__' + key]; - } - })); - - objB = Object.create(objA); - objB.__foo = 'FOO'; - defineProperty(objB, 'foo', computed({ - get(key) { return this['__' + key]; }, - set(key, value) { - this['__' + key] = 'B ' + value; - return this['__' + key]; - } - })); - } + set(objB, 'foo', 'bar'); + assert.equal(get(objB, 'foo'), 'bar', 'should change B'); + assert.equal(get(objA, 'foo'), 'computed BIFF', 'should NOT change A'); - afterEach() { - objA = objB = null; + set(objA, 'foo', 'BAZ'); + assert.equal(get(objA, 'foo'), 'computed BAZ', 'should change A'); + assert.equal(get(objB, 'foo'), 'bar', 'should NOT change B'); + } } +); + +moduleFor( + 'redefining computed property to another property', + class extends AbstractTestCase { + beforeEach() { + objA = { __foo: 'FOO' }; + defineProperty( + objA, + 'foo', + computed({ + get(key) { + return this['__' + key]; + }, + set(key, value) { + this['__' + key] = 'A ' + value; + return this['__' + key]; + } + }) + ); + + objB = Object.create(objA); + objB.__foo = 'FOO'; + defineProperty( + objB, + 'foo', + computed({ + get(key) { + return this['__' + key]; + }, + set(key, value) { + this['__' + key] = 'B ' + value; + return this['__' + key]; + } + }) + ); + } - ['@test using get() and set()'](assert) { - assert.equal(get(objA, 'foo'), 'FOO', 'should get FOO from A'); - assert.equal(get(objB, 'foo'), 'FOO', 'should get FOO from B'); - - set(objA, 'foo', 'BIFF'); - assert.equal(get(objA, 'foo'), 'A BIFF', 'should change A'); - assert.equal(get(objB, 'foo'), 'FOO', 'should NOT change B'); + afterEach() { + objA = objB = null; + } - set(objB, 'foo', 'bar'); - assert.equal(get(objB, 'foo'), 'B bar', 'should change B'); - assert.equal(get(objA, 'foo'), 'A BIFF', 'should NOT change A'); + ['@test using get() and set()'](assert) { + assert.equal(get(objA, 'foo'), 'FOO', 'should get FOO from A'); + assert.equal(get(objB, 'foo'), 'FOO', 'should get FOO from B'); - set(objA, 'foo', 'BAZ'); - assert.equal(get(objA, 'foo'), 'A BAZ', 'should change A'); - assert.equal(get(objB, 'foo'), 'B bar', 'should NOT change B'); - } -}); + set(objA, 'foo', 'BIFF'); + assert.equal(get(objA, 'foo'), 'A BIFF', 'should change A'); + assert.equal(get(objB, 'foo'), 'FOO', 'should NOT change B'); -moduleFor('computed - metadata', class extends AbstractTestCase { - ['@test can set metadata on a computed property'](assert) { - let computedProperty = computed(function() { }); - computedProperty.meta({ key: 'keyValue' }); + set(objB, 'foo', 'bar'); + assert.equal(get(objB, 'foo'), 'B bar', 'should change B'); + assert.equal(get(objA, 'foo'), 'A BIFF', 'should NOT change A'); - assert.equal(computedProperty.meta().key, 'keyValue', 'saves passed meta hash to the _meta property'); + set(objA, 'foo', 'BAZ'); + assert.equal(get(objA, 'foo'), 'A BAZ', 'should change A'); + assert.equal(get(objB, 'foo'), 'B bar', 'should NOT change B'); + } } +); + +moduleFor( + 'computed - metadata', + class extends AbstractTestCase { + ['@test can set metadata on a computed property'](assert) { + let computedProperty = computed(function() {}); + computedProperty.meta({ key: 'keyValue' }); + + assert.equal( + computedProperty.meta().key, + 'keyValue', + 'saves passed meta hash to the _meta property' + ); + } - ['@test meta should return an empty hash if no meta is set'](assert) { - let computedProperty = computed(function() { }); - assert.deepEqual(computedProperty.meta(), {}, 'returned value is an empty hash'); + ['@test meta should return an empty hash if no meta is set'](assert) { + let computedProperty = computed(function() {}); + assert.deepEqual( + computedProperty.meta(), + {}, + 'returned value is an empty hash' + ); + } } -}); +); // .......................................................... // CACHEABLE // -moduleFor('computed - cacheable', class extends AbstractTestCase { - beforeEach() { - obj = {}; - count = 0; - let func = function() { - count++; - return 'bar ' + count; - }; - defineProperty(obj, 'foo', computed({ get: func, set: func })); - } - - afterEach() { - obj = count = null; - } - ['@test cacheable should cache'](assert) { - assert.equal(get(obj, 'foo'), 'bar 1', 'first get'); - assert.equal(get(obj, 'foo'), 'bar 1', 'second get'); - assert.equal(count, 1, 'should only invoke once'); - } - - ['@test modifying a cacheable property should update cache'](assert) { - assert.equal(get(obj, 'foo'), 'bar 1', 'first get'); - assert.equal(get(obj, 'foo'), 'bar 1', 'second get'); - - assert.equal(set(obj, 'foo', 'baz'), 'baz', 'setting'); - assert.equal(get(obj, 'foo'), 'bar 2', 'third get'); - assert.equal(count, 2, 'should not invoke again'); - } - - ['@test inherited property should not pick up cache'](assert) { - let objB = Object.create(obj); - - assert.equal(get(obj, 'foo'), 'bar 1', 'obj first get'); - assert.equal(get(objB, 'foo'), 'bar 2', 'objB first get'); +moduleFor( + 'computed - cacheable', + class extends AbstractTestCase { + beforeEach() { + obj = {}; + count = 0; + let func = function() { + count++; + return 'bar ' + count; + }; + defineProperty(obj, 'foo', computed({ get: func, set: func })); + } - assert.equal(get(obj, 'foo'), 'bar 1', 'obj second get'); - assert.equal(get(objB, 'foo'), 'bar 2', 'objB second get'); + afterEach() { + obj = count = null; + } + ['@test cacheable should cache'](assert) { + assert.equal(get(obj, 'foo'), 'bar 1', 'first get'); + assert.equal(get(obj, 'foo'), 'bar 1', 'second get'); + assert.equal(count, 1, 'should only invoke once'); + } - set(obj, 'foo', 'baz'); // modify A - assert.equal(get(obj, 'foo'), 'bar 3', 'obj third get'); - assert.equal(get(objB, 'foo'), 'bar 2', 'objB third get'); - } + ['@test modifying a cacheable property should update cache'](assert) { + assert.equal(get(obj, 'foo'), 'bar 1', 'first get'); + assert.equal(get(obj, 'foo'), 'bar 1', 'second get'); - ['@test getCachedValueFor should return the cached value'](assert) { - assert.equal(getCachedValueFor(obj, 'foo'), undefined, 'should not yet be a cached value'); + assert.equal(set(obj, 'foo', 'baz'), 'baz', 'setting'); + assert.equal(get(obj, 'foo'), 'bar 2', 'third get'); + assert.equal(count, 2, 'should not invoke again'); + } - get(obj, 'foo'); + ['@test inherited property should not pick up cache'](assert) { + let objB = Object.create(obj); - assert.equal(getCachedValueFor(obj, 'foo'), 'bar 1', 'should retrieve cached value'); - } + assert.equal(get(obj, 'foo'), 'bar 1', 'obj first get'); + assert.equal(get(objB, 'foo'), 'bar 2', 'objB first get'); - ['@test getCachedValueFor should return falsy cached values'](assert) { - defineProperty(obj, 'falsy', computed(function() { - return false; - })); + assert.equal(get(obj, 'foo'), 'bar 1', 'obj second get'); + assert.equal(get(objB, 'foo'), 'bar 2', 'objB second get'); - assert.equal(getCachedValueFor(obj, 'falsy'), undefined, 'should not yet be a cached value'); + set(obj, 'foo', 'baz'); // modify A + assert.equal(get(obj, 'foo'), 'bar 3', 'obj third get'); + assert.equal(get(objB, 'foo'), 'bar 2', 'objB third get'); + } - get(obj, 'falsy'); + ['@test getCachedValueFor should return the cached value'](assert) { + assert.equal( + getCachedValueFor(obj, 'foo'), + undefined, + 'should not yet be a cached value' + ); - assert.equal(getCachedValueFor(obj, 'falsy'), false, 'should retrieve cached value'); - } + get(obj, 'foo'); - ['@test setting a cached computed property passes the old value as the third argument'](assert) { - let obj = { - foo: 0 - }; + assert.equal( + getCachedValueFor(obj, 'foo'), + 'bar 1', + 'should retrieve cached value' + ); + } - let receivedOldValue; + ['@test getCachedValueFor should return falsy cached values'](assert) { + defineProperty( + obj, + 'falsy', + computed(function() { + return false; + }) + ); + + assert.equal( + getCachedValueFor(obj, 'falsy'), + undefined, + 'should not yet be a cached value' + ); + + get(obj, 'falsy'); + + assert.equal( + getCachedValueFor(obj, 'falsy'), + false, + 'should retrieve cached value' + ); + } - defineProperty(obj, 'plusOne', computed({ - get() {}, - set(key, value, oldValue) { - receivedOldValue = oldValue; - return value; - } }).property('foo') - ); + ['@test setting a cached computed property passes the old value as the third argument']( + assert + ) { + let obj = { + foo: 0 + }; + + let receivedOldValue; + + defineProperty( + obj, + 'plusOne', + computed({ + get() {}, + set(key, value, oldValue) { + receivedOldValue = oldValue; + return value; + } + }).property('foo') + ); - set(obj, 'plusOne', 1); - assert.strictEqual(receivedOldValue, undefined, 'oldValue should be undefined'); + set(obj, 'plusOne', 1); + assert.strictEqual( + receivedOldValue, + undefined, + 'oldValue should be undefined' + ); - set(obj, 'plusOne', 2); - assert.strictEqual(receivedOldValue, 1, 'oldValue should be 1'); + set(obj, 'plusOne', 2); + assert.strictEqual(receivedOldValue, 1, 'oldValue should be 1'); - set(obj, 'plusOne', 3); - assert.strictEqual(receivedOldValue, 2, 'oldValue should be 2'); + set(obj, 'plusOne', 3); + assert.strictEqual(receivedOldValue, 2, 'oldValue should be 2'); + } } -}); +); // .......................................................... // DEPENDENT KEYS // -moduleFor('computed - dependentkey', class extends AbstractTestCase { - beforeEach() { - obj = { bar: 'baz' }; - count = 0; - let getterAndSetter = function() { - count++; - get(this, 'bar'); - return 'bar ' + count; - }; - defineProperty(obj, 'foo', computed({ - get: getterAndSetter, - set: getterAndSetter - }).property('bar')); - } - - afterEach() { - obj = count = null; - } - - ['@test should lazily watch dependent keys on set'](assert) { - assert.equal(isWatching(obj, 'bar'), false, 'precond not watching dependent key'); - set(obj, 'foo', 'bar'); - assert.equal(isWatching(obj, 'bar'), true, 'lazily watching dependent key'); - } - - ['@test should lazily watch dependent keys on get'](assert) { - assert.equal(isWatching(obj, 'bar'), false, 'precond not watching dependent key'); - get(obj, 'foo'); - assert.equal(isWatching(obj, 'bar'), true, 'lazily watching dependent key'); - } - - ['@test local dependent key should invalidate cache'](assert) { - assert.equal(isWatching(obj, 'bar'), false, 'precond not watching dependent key'); - assert.equal(get(obj, 'foo'), 'bar 1', 'get once'); - assert.equal(isWatching(obj, 'bar'), true, 'lazily setup watching dependent key'); - assert.equal(get(obj, 'foo'), 'bar 1', 'cached retrieve'); - - set(obj, 'bar', 'BIFF'); // should invalidate foo - - assert.equal(get(obj, 'foo'), 'bar 2', 'should recache'); - assert.equal(get(obj, 'foo'), 'bar 2', 'cached retrieve'); - } - - ['@test should invalidate multiple nested dependent keys'](assert) { - let count = 0; - defineProperty(obj, 'bar', computed(function() { - count++; - get(this, 'baz'); - return 'baz ' + count; - }).property('baz')); - - assert.equal(isWatching(obj, 'bar'), false, 'precond not watching dependent key'); - assert.equal(isWatching(obj, 'baz'), false, 'precond not watching dependent key'); - assert.equal(get(obj, 'foo'), 'bar 1', 'get once'); - assert.equal(isWatching(obj, 'bar'), true, 'lazily setup watching dependent key'); - assert.equal(isWatching(obj, 'baz'), true, 'lazily setup watching dependent key'); - assert.equal(get(obj, 'foo'), 'bar 1', 'cached retrieve'); - - set(obj, 'baz', 'BIFF'); // should invalidate bar -> foo - assert.equal(isWatching(obj, 'bar'), false, 'should not be watching dependent key after cache cleared'); - assert.equal(isWatching(obj, 'baz'), false, 'should not be watching dependent key after cache cleared'); - - assert.equal(get(obj, 'foo'), 'bar 2', 'should recache'); - assert.equal(get(obj, 'foo'), 'bar 2', 'cached retrieve'); - assert.equal(isWatching(obj, 'bar'), true, 'lazily setup watching dependent key'); - assert.equal(isWatching(obj, 'baz'), true, 'lazily setup watching dependent key'); - } - - ['@test circular keys should not blow up'](assert) { - let func = function() { - count++; - return 'bar ' + count; - }; - defineProperty(obj, 'bar', computed({ get: func, set: func }).property('foo')); - - defineProperty(obj, 'foo', computed(function() { - count++; - return 'foo ' + count; - }).property('bar')); - - assert.equal(get(obj, 'foo'), 'foo 1', 'get once'); - assert.equal(get(obj, 'foo'), 'foo 1', 'cached retrieve'); - - set(obj, 'bar', 'BIFF'); // should invalidate bar -> foo -> bar +moduleFor( + 'computed - dependentkey', + class extends AbstractTestCase { + beforeEach() { + obj = { bar: 'baz' }; + count = 0; + let getterAndSetter = function() { + count++; + get(this, 'bar'); + return 'bar ' + count; + }; + defineProperty( + obj, + 'foo', + computed({ + get: getterAndSetter, + set: getterAndSetter + }).property('bar') + ); + } - assert.equal(get(obj, 'foo'), 'foo 3', 'should recache'); - assert.equal(get(obj, 'foo'), 'foo 3', 'cached retrieve'); - } + afterEach() { + obj = count = null; + } - ['@test redefining a property should undo old dependent keys'](assert) { - assert.equal(isWatching(obj, 'bar'), false, 'precond not watching dependent key'); - assert.equal(get(obj, 'foo'), 'bar 1'); - assert.equal(isWatching(obj, 'bar'), true, 'lazily watching dependent key'); + ['@test should lazily watch dependent keys on set'](assert) { + assert.equal( + isWatching(obj, 'bar'), + false, + 'precond not watching dependent key' + ); + set(obj, 'foo', 'bar'); + assert.equal( + isWatching(obj, 'bar'), + true, + 'lazily watching dependent key' + ); + } - defineProperty(obj, 'foo', computed(function() { - count++; - return 'baz ' + count; - }).property('baz')); + ['@test should lazily watch dependent keys on get'](assert) { + assert.equal( + isWatching(obj, 'bar'), + false, + 'precond not watching dependent key' + ); + get(obj, 'foo'); + assert.equal( + isWatching(obj, 'bar'), + true, + 'lazily watching dependent key' + ); + } - assert.equal(isWatching(obj, 'bar'), false, 'after redefining should not be watching dependent key'); + ['@test local dependent key should invalidate cache'](assert) { + assert.equal( + isWatching(obj, 'bar'), + false, + 'precond not watching dependent key' + ); + assert.equal(get(obj, 'foo'), 'bar 1', 'get once'); + assert.equal( + isWatching(obj, 'bar'), + true, + 'lazily setup watching dependent key' + ); + assert.equal(get(obj, 'foo'), 'bar 1', 'cached retrieve'); + + set(obj, 'bar', 'BIFF'); // should invalidate foo + + assert.equal(get(obj, 'foo'), 'bar 2', 'should recache'); + assert.equal(get(obj, 'foo'), 'bar 2', 'cached retrieve'); + } - assert.equal(get(obj, 'foo'), 'baz 2'); + ['@test should invalidate multiple nested dependent keys'](assert) { + let count = 0; + defineProperty( + obj, + 'bar', + computed(function() { + count++; + get(this, 'baz'); + return 'baz ' + count; + }).property('baz') + ); + + assert.equal( + isWatching(obj, 'bar'), + false, + 'precond not watching dependent key' + ); + assert.equal( + isWatching(obj, 'baz'), + false, + 'precond not watching dependent key' + ); + assert.equal(get(obj, 'foo'), 'bar 1', 'get once'); + assert.equal( + isWatching(obj, 'bar'), + true, + 'lazily setup watching dependent key' + ); + assert.equal( + isWatching(obj, 'baz'), + true, + 'lazily setup watching dependent key' + ); + assert.equal(get(obj, 'foo'), 'bar 1', 'cached retrieve'); + + set(obj, 'baz', 'BIFF'); // should invalidate bar -> foo + assert.equal( + isWatching(obj, 'bar'), + false, + 'should not be watching dependent key after cache cleared' + ); + assert.equal( + isWatching(obj, 'baz'), + false, + 'should not be watching dependent key after cache cleared' + ); + + assert.equal(get(obj, 'foo'), 'bar 2', 'should recache'); + assert.equal(get(obj, 'foo'), 'bar 2', 'cached retrieve'); + assert.equal( + isWatching(obj, 'bar'), + true, + 'lazily setup watching dependent key' + ); + assert.equal( + isWatching(obj, 'baz'), + true, + 'lazily setup watching dependent key' + ); + } - set(obj, 'bar', 'BIFF'); // should not kill cache - assert.equal(get(obj, 'foo'), 'baz 2'); + ['@test circular keys should not blow up'](assert) { + let func = function() { + count++; + return 'bar ' + count; + }; + defineProperty( + obj, + 'bar', + computed({ get: func, set: func }).property('foo') + ); + + defineProperty( + obj, + 'foo', + computed(function() { + count++; + return 'foo ' + count; + }).property('bar') + ); + + assert.equal(get(obj, 'foo'), 'foo 1', 'get once'); + assert.equal(get(obj, 'foo'), 'foo 1', 'cached retrieve'); + + set(obj, 'bar', 'BIFF'); // should invalidate bar -> foo -> bar + + assert.equal(get(obj, 'foo'), 'foo 3', 'should recache'); + assert.equal(get(obj, 'foo'), 'foo 3', 'cached retrieve'); + } - set(obj, 'baz', 'BOP'); - assert.equal(get(obj, 'foo'), 'baz 3'); - } + ['@test redefining a property should undo old dependent keys'](assert) { + assert.equal( + isWatching(obj, 'bar'), + false, + 'precond not watching dependent key' + ); + assert.equal(get(obj, 'foo'), 'bar 1'); + assert.equal( + isWatching(obj, 'bar'), + true, + 'lazily watching dependent key' + ); + + defineProperty( + obj, + 'foo', + computed(function() { + count++; + return 'baz ' + count; + }).property('baz') + ); + + assert.equal( + isWatching(obj, 'bar'), + false, + 'after redefining should not be watching dependent key' + ); + + assert.equal(get(obj, 'foo'), 'baz 2'); + + set(obj, 'bar', 'BIFF'); // should not kill cache + assert.equal(get(obj, 'foo'), 'baz 2'); + + set(obj, 'baz', 'BOP'); + assert.equal(get(obj, 'foo'), 'baz 3'); + } - ['@test can watch multiple dependent keys specified declaratively via brace expansion'](assert) { - defineProperty(obj, 'foo', computed(function() { - count++; - return 'foo ' + count; - }).property('qux.{bar,baz}')); + ['@test can watch multiple dependent keys specified declaratively via brace expansion']( + assert + ) { + defineProperty( + obj, + 'foo', + computed(function() { + count++; + return 'foo ' + count; + }).property('qux.{bar,baz}') + ); - assert.equal(get(obj, 'foo'), 'foo 1', 'get once'); - assert.equal(get(obj, 'foo'), 'foo 1', 'cached retrieve'); + assert.equal(get(obj, 'foo'), 'foo 1', 'get once'); + assert.equal(get(obj, 'foo'), 'foo 1', 'cached retrieve'); - set(obj, 'qux', {}); - set(obj, 'qux.bar', 'bar'); // invalidate foo + set(obj, 'qux', {}); + set(obj, 'qux.bar', 'bar'); // invalidate foo - assert.equal(get(obj, 'foo'), 'foo 2', 'foo invalidated from bar'); + assert.equal(get(obj, 'foo'), 'foo 2', 'foo invalidated from bar'); - set(obj, 'qux.baz', 'baz'); // invalidate foo + set(obj, 'qux.baz', 'baz'); // invalidate foo - assert.equal(get(obj, 'foo'), 'foo 3', 'foo invalidated from baz'); + assert.equal(get(obj, 'foo'), 'foo 3', 'foo invalidated from baz'); - set(obj, 'qux.quux', 'quux'); // do not invalidate foo + set(obj, 'qux.quux', 'quux'); // do not invalidate foo - assert.equal(get(obj, 'foo'), 'foo 3', 'foo not invalidated by quux'); - } + assert.equal(get(obj, 'foo'), 'foo 3', 'foo not invalidated by quux'); + } - ['@test throws assertion if brace expansion notation has spaces']() { - expectAssertion(function () { - defineProperty(obj, 'roo', computed(function () { - count++; - return 'roo ' + count; - }).property('fee.{bar, baz,bop , }')); - }, /cannot contain spaces/); - } + ['@test throws assertion if brace expansion notation has spaces']() { + expectAssertion(function() { + defineProperty( + obj, + 'roo', + computed(function() { + count++; + return 'roo ' + count; + }).property('fee.{bar, baz,bop , }') + ); + }, /cannot contain spaces/); + } - ['@test throws an assertion if an uncached `get` is called after object is destroyed'](assert) { - assert.equal(isWatching(obj, 'bar'), false, 'precond not watching dependent key'); + ['@test throws an assertion if an uncached `get` is called after object is destroyed']( + assert + ) { + assert.equal( + isWatching(obj, 'bar'), + false, + 'precond not watching dependent key' + ); - let meta = metaFor(obj); - meta.destroy(); + let meta = metaFor(obj); + meta.destroy(); - obj.toString = () => ''; + obj.toString = () => ''; - expectAssertion(() => { - get(obj, 'foo'); - }, 'Cannot modify dependent keys for `foo` on `` after it has been destroyed.'); + expectAssertion(() => { + get(obj, 'foo'); + }, 'Cannot modify dependent keys for `foo` on `` after it has been destroyed.'); - assert.equal(isWatching(obj, 'bar'), false, 'deps were not updated'); + assert.equal(isWatching(obj, 'bar'), false, 'deps were not updated'); + } } -}); +); // .......................................................... // CHAINED DEPENDENT KEYS @@ -534,329 +751,390 @@ moduleFor('computed - dependentkey', class extends AbstractTestCase { let func; -moduleFor('computed - dependentkey with chained properties', class extends AbstractTestCase { - beforeEach() { - obj = { - foo: { - bar: { - baz: { - biff: 'BIFF' +moduleFor( + 'computed - dependentkey with chained properties', + class extends AbstractTestCase { + beforeEach() { + obj = { + foo: { + bar: { + baz: { + biff: 'BIFF' + } } } - } - }; + }; - count = 0; - func = function() { - count++; - return get(obj, 'foo.bar.baz.biff') + ' ' + count; - }; - } + count = 0; + func = function() { + count++; + return get(obj, 'foo.bar.baz.biff') + ' ' + count; + }; + } - afterEach() { - obj = count = func = null; - } + afterEach() { + obj = count = func = null; + } - ['@test depending on simple chain'](assert) { - // assign computed property - defineProperty(obj, 'prop', - computed(func).property('foo.bar.baz.biff')); + ['@test depending on simple chain'](assert) { + // assign computed property + defineProperty(obj, 'prop', computed(func).property('foo.bar.baz.biff')); - assert.equal(get(obj, 'prop'), 'BIFF 1'); + assert.equal(get(obj, 'prop'), 'BIFF 1'); - set(get(obj, 'foo.bar.baz'), 'biff', 'BUZZ'); - assert.equal(get(obj, 'prop'), 'BUZZ 2'); - assert.equal(get(obj, 'prop'), 'BUZZ 2'); + set(get(obj, 'foo.bar.baz'), 'biff', 'BUZZ'); + assert.equal(get(obj, 'prop'), 'BUZZ 2'); + assert.equal(get(obj, 'prop'), 'BUZZ 2'); - set(get(obj, 'foo.bar'), 'baz', { biff: 'BLOB' }); - assert.equal(get(obj, 'prop'), 'BLOB 3'); - assert.equal(get(obj, 'prop'), 'BLOB 3'); + set(get(obj, 'foo.bar'), 'baz', { biff: 'BLOB' }); + assert.equal(get(obj, 'prop'), 'BLOB 3'); + assert.equal(get(obj, 'prop'), 'BLOB 3'); - set(get(obj, 'foo.bar.baz'), 'biff', 'BUZZ'); - assert.equal(get(obj, 'prop'), 'BUZZ 4'); - assert.equal(get(obj, 'prop'), 'BUZZ 4'); + set(get(obj, 'foo.bar.baz'), 'biff', 'BUZZ'); + assert.equal(get(obj, 'prop'), 'BUZZ 4'); + assert.equal(get(obj, 'prop'), 'BUZZ 4'); - set(get(obj, 'foo'), 'bar', { baz: { biff: 'BOOM' } }); - assert.equal(get(obj, 'prop'), 'BOOM 5'); - assert.equal(get(obj, 'prop'), 'BOOM 5'); + set(get(obj, 'foo'), 'bar', { baz: { biff: 'BOOM' } }); + assert.equal(get(obj, 'prop'), 'BOOM 5'); + assert.equal(get(obj, 'prop'), 'BOOM 5'); - set(get(obj, 'foo.bar.baz'), 'biff', 'BUZZ'); - assert.equal(get(obj, 'prop'), 'BUZZ 6'); - assert.equal(get(obj, 'prop'), 'BUZZ 6'); + set(get(obj, 'foo.bar.baz'), 'biff', 'BUZZ'); + assert.equal(get(obj, 'prop'), 'BUZZ 6'); + assert.equal(get(obj, 'prop'), 'BUZZ 6'); - set(obj, 'foo', { bar: { baz: { biff: 'BLARG' } } }); - assert.equal(get(obj, 'prop'), 'BLARG 7'); - assert.equal(get(obj, 'prop'), 'BLARG 7'); + set(obj, 'foo', { bar: { baz: { biff: 'BLARG' } } }); + assert.equal(get(obj, 'prop'), 'BLARG 7'); + assert.equal(get(obj, 'prop'), 'BLARG 7'); - set(get(obj, 'foo.bar.baz'), 'biff', 'BUZZ'); - assert.equal(get(obj, 'prop'), 'BUZZ 8'); - assert.equal(get(obj, 'prop'), 'BUZZ 8'); + set(get(obj, 'foo.bar.baz'), 'biff', 'BUZZ'); + assert.equal(get(obj, 'prop'), 'BUZZ 8'); + assert.equal(get(obj, 'prop'), 'BUZZ 8'); - defineProperty(obj, 'prop'); - set(obj, 'prop', 'NONE'); - assert.equal(get(obj, 'prop'), 'NONE'); + defineProperty(obj, 'prop'); + set(obj, 'prop', 'NONE'); + assert.equal(get(obj, 'prop'), 'NONE'); - set(obj, 'foo', { bar: { baz: { biff: 'BLARG' } } }); - assert.equal(get(obj, 'prop'), 'NONE'); // should do nothing - assert.equal(count, 8, 'should be not have invoked computed again'); - } + set(obj, 'foo', { bar: { baz: { biff: 'BLARG' } } }); + assert.equal(get(obj, 'prop'), 'NONE'); // should do nothing + assert.equal(count, 8, 'should be not have invoked computed again'); + } - ['@test chained dependent keys should evaluate computed properties lazily'](assert) { - defineProperty(obj.foo.bar, 'b', computed(func)); - defineProperty(obj.foo, 'c', computed(function() {}).property('bar.b')); - assert.equal(count, 0, 'b should not run'); + ['@test chained dependent keys should evaluate computed properties lazily']( + assert + ) { + defineProperty(obj.foo.bar, 'b', computed(func)); + defineProperty(obj.foo, 'c', computed(function() {}).property('bar.b')); + assert.equal(count, 0, 'b should not run'); + } } - -}); +); // .......................................................... // improved-cp-syntax // -moduleFor('computed - improved cp syntax', class extends AbstractTestCase { - ['@test setter and getters are passed using an object'](assert) { - let testObj = EmberObject.extend({ - a: '1', - b: '2', - aInt: computed('a', { - get(keyName) { - assert.equal(keyName, 'aInt', 'getter receives the keyName'); - return parseInt(this.get('a')); - }, - set(keyName, value, oldValue) { - assert.equal(keyName, 'aInt', 'setter receives the keyName'); - assert.equal(value, 123, 'setter receives the new value'); - assert.equal(oldValue, 1, 'setter receives the old value'); - this.set('a', '' + value); // side effect - return parseInt(this.get('a')); - } - }) - }).create(); - - assert.ok(testObj.get('aInt') === 1, 'getter works'); - testObj.set('aInt', 123); - assert.ok(testObj.get('a') === '123', 'setter works'); - assert.ok(testObj.get('aInt') === 123, 'cp has been updated too'); - } +moduleFor( + 'computed - improved cp syntax', + class extends AbstractTestCase { + ['@test setter and getters are passed using an object'](assert) { + let testObj = EmberObject.extend({ + a: '1', + b: '2', + aInt: computed('a', { + get(keyName) { + assert.equal(keyName, 'aInt', 'getter receives the keyName'); + return parseInt(this.get('a')); + }, + set(keyName, value, oldValue) { + assert.equal(keyName, 'aInt', 'setter receives the keyName'); + assert.equal(value, 123, 'setter receives the new value'); + assert.equal(oldValue, 1, 'setter receives the old value'); + this.set('a', '' + value); // side effect + return parseInt(this.get('a')); + } + }) + }).create(); - ['@test setter can be omited'](assert) { - let testObj = EmberObject.extend({ - a: '1', - b: '2', - aInt: computed('a', { - get(keyName) { - assert.equal(keyName, 'aInt', 'getter receives the keyName'); - return parseInt(this.get('a')); - } - }) - }).create(); + assert.ok(testObj.get('aInt') === 1, 'getter works'); + testObj.set('aInt', 123); + assert.ok(testObj.get('a') === '123', 'setter works'); + assert.ok(testObj.get('aInt') === 123, 'cp has been updated too'); + } - assert.ok(testObj.get('aInt') === 1, 'getter works'); - assert.ok(testObj.get('a') === '1'); - testObj.set('aInt', '123'); - assert.ok(testObj.get('aInt') === '123', 'cp has been updated too'); - } + ['@test setter can be omited'](assert) { + let testObj = EmberObject.extend({ + a: '1', + b: '2', + aInt: computed('a', { + get(keyName) { + assert.equal(keyName, 'aInt', 'getter receives the keyName'); + return parseInt(this.get('a')); + } + }) + }).create(); - ['@test getter can be omited'](assert) { - let testObj = EmberObject.extend({ - com: computed({ - set(key, value) { - return value; - } - }) - }).create(); + assert.ok(testObj.get('aInt') === 1, 'getter works'); + assert.ok(testObj.get('a') === '1'); + testObj.set('aInt', '123'); + assert.ok(testObj.get('aInt') === '123', 'cp has been updated too'); + } - assert.ok(testObj.get('com') === undefined); - testObj.set('com', '123'); - assert.ok(testObj.get('com') === '123', 'cp has been updated'); - } + ['@test getter can be omited'](assert) { + let testObj = EmberObject.extend({ + com: computed({ + set(key, value) { + return value; + } + }) + }).create(); - ['@test the return value of the setter gets cached'](assert) { - let testObj = EmberObject.extend({ - a: '1', - sampleCP: computed('a', { - get() { - assert.ok(false, 'The getter should not be invoked'); - return 'get-value'; - }, - set() { - return 'set-value'; - } - }) - }).create(); + assert.ok(testObj.get('com') === undefined); + testObj.set('com', '123'); + assert.ok(testObj.get('com') === '123', 'cp has been updated'); + } - testObj.set('sampleCP', 'abcd'); - assert.ok(testObj.get('sampleCP') === 'set-value', 'The return value of the CP was cached'); + ['@test the return value of the setter gets cached'](assert) { + let testObj = EmberObject.extend({ + a: '1', + sampleCP: computed('a', { + get() { + assert.ok(false, 'The getter should not be invoked'); + return 'get-value'; + }, + set() { + return 'set-value'; + } + }) + }).create(); + + testObj.set('sampleCP', 'abcd'); + assert.ok( + testObj.get('sampleCP') === 'set-value', + 'The return value of the CP was cached' + ); + } } -}); - +); // .......................................................... // BUGS // -moduleFor('computed edge cases', class extends AbstractTestCase { - ['@test adding a computed property should show up in key iteration'](assert) { - let obj = {}; - defineProperty(obj, 'foo', computed(function() {})); +moduleFor( + 'computed edge cases', + class extends AbstractTestCase { + ['@test adding a computed property should show up in key iteration']( + assert + ) { + let obj = {}; + defineProperty(obj, 'foo', computed(function() {})); - let found = []; - for (let key in obj) { - found.push(key); + let found = []; + for (let key in obj) { + found.push(key); + } + assert.ok( + found.indexOf('foo') >= 0, + 'should find computed property in iteration found=' + found + ); + assert.ok('foo' in obj, 'foo in obj should pass'); } - assert.ok(found.indexOf('foo') >= 0, 'should find computed property in iteration found=' + found); - assert.ok('foo' in obj, 'foo in obj should pass'); - } - - ['@test when setting a value after it had been retrieved empty don\'t pass function UNDEFINED as oldValue'](assert) { - let obj = {}; - let oldValueIsNoFunction = true; - defineProperty(obj, 'foo', computed({ - get() { }, - set(key, value, oldValue) { - if (typeof oldValue === 'function') { - oldValueIsNoFunction = false; - } - return undefined; - } - })); + ["@test when setting a value after it had been retrieved empty don't pass function UNDEFINED as oldValue"]( + assert + ) { + let obj = {}; + let oldValueIsNoFunction = true; + + defineProperty( + obj, + 'foo', + computed({ + get() {}, + set(key, value, oldValue) { + if (typeof oldValue === 'function') { + oldValueIsNoFunction = false; + } + return undefined; + } + }) + ); - get(obj, 'foo'); - set(obj, 'foo', undefined); + get(obj, 'foo'); + set(obj, 'foo', undefined); - assert.ok(oldValueIsNoFunction); - } -}); - -moduleFor('computed - setter', class extends AbstractTestCase { - ['@test setting a watched computed property'](assert) { - let obj = { - firstName: 'Yehuda', - lastName: 'Katz' - }; - - defineProperty(obj, 'fullName', computed({ - get() { return get(this, 'firstName') + ' ' + get(this, 'lastName'); }, - set(key, value) { - let values = value.split(' '); - set(this, 'firstName', values[0]); - set(this, 'lastName', values[1]); - return value; - } - }).property('firstName', 'lastName')); - - let fullNameDidChange = 0; - let firstNameDidChange = 0; - let lastNameDidChange = 0; - addObserver(obj, 'fullName', function () { - fullNameDidChange++; - }); - addObserver(obj, 'firstName', function () { - firstNameDidChange++; - }); - addObserver(obj, 'lastName', function () { - lastNameDidChange++; - }); - - assert.equal(get(obj, 'fullName'), 'Yehuda Katz'); - - set(obj, 'fullName', 'Yehuda Katz'); - - set(obj, 'fullName', 'Kris Selden'); - - assert.equal(get(obj, 'fullName'), 'Kris Selden'); - assert.equal(get(obj, 'firstName'), 'Kris'); - assert.equal(get(obj, 'lastName'), 'Selden'); - - assert.equal(fullNameDidChange, 1); - assert.equal(firstNameDidChange, 1); - assert.equal(lastNameDidChange, 1); + assert.ok(oldValueIsNoFunction); + } } +); + +moduleFor( + 'computed - setter', + class extends AbstractTestCase { + ['@test setting a watched computed property'](assert) { + let obj = { + firstName: 'Yehuda', + lastName: 'Katz' + }; + + defineProperty( + obj, + 'fullName', + computed({ + get() { + return get(this, 'firstName') + ' ' + get(this, 'lastName'); + }, + set(key, value) { + let values = value.split(' '); + set(this, 'firstName', values[0]); + set(this, 'lastName', values[1]); + return value; + } + }).property('firstName', 'lastName') + ); + + let fullNameDidChange = 0; + let firstNameDidChange = 0; + let lastNameDidChange = 0; + addObserver(obj, 'fullName', function() { + fullNameDidChange++; + }); + addObserver(obj, 'firstName', function() { + firstNameDidChange++; + }); + addObserver(obj, 'lastName', function() { + lastNameDidChange++; + }); - ['@test setting a cached computed property that modifies the value you give it'](assert) { - let obj = { - foo: 0 - }; - - defineProperty(obj, 'plusOne', computed({ - get() { return get(this, 'foo') + 1; }, - set(key, value) { - set(this, 'foo', value); - return value + 1; - } - }).property('foo')); + assert.equal(get(obj, 'fullName'), 'Yehuda Katz'); - let plusOneDidChange = 0; - addObserver(obj, 'plusOne', function () { - plusOneDidChange++; - }); + set(obj, 'fullName', 'Yehuda Katz'); - assert.equal(get(obj, 'plusOne'), 1); - set(obj, 'plusOne', 1); - assert.equal(get(obj, 'plusOne'), 2); - set(obj, 'plusOne', 1); - assert.equal(get(obj, 'plusOne'), 2); + set(obj, 'fullName', 'Kris Selden'); - assert.equal(plusOneDidChange, 1); + assert.equal(get(obj, 'fullName'), 'Kris Selden'); + assert.equal(get(obj, 'firstName'), 'Kris'); + assert.equal(get(obj, 'lastName'), 'Selden'); - set(obj, 'foo', 5); - assert.equal(get(obj, 'plusOne'), 6); + assert.equal(fullNameDidChange, 1); + assert.equal(firstNameDidChange, 1); + assert.equal(lastNameDidChange, 1); + } - assert.equal(plusOneDidChange, 2); - } -}); + ['@test setting a cached computed property that modifies the value you give it']( + assert + ) { + let obj = { + foo: 0 + }; + + defineProperty( + obj, + 'plusOne', + computed({ + get() { + return get(this, 'foo') + 1; + }, + set(key, value) { + set(this, 'foo', value); + return value + 1; + } + }).property('foo') + ); -moduleFor('computed - default setter', class extends AbstractTestCase { - ['@test when setting a value on a computed property that doesn\'t handle sets'](assert) { - let obj = {}; - let observerFired = false; + let plusOneDidChange = 0; + addObserver(obj, 'plusOne', function() { + plusOneDidChange++; + }); - defineProperty(obj, 'foo', computed(function() { - return 'foo'; - })); + assert.equal(get(obj, 'plusOne'), 1); + set(obj, 'plusOne', 1); + assert.equal(get(obj, 'plusOne'), 2); + set(obj, 'plusOne', 1); + assert.equal(get(obj, 'plusOne'), 2); - addObserver(obj, 'foo', null, () => observerFired = true); + assert.equal(plusOneDidChange, 1); - set(obj, 'foo', 'bar'); + set(obj, 'foo', 5); + assert.equal(get(obj, 'plusOne'), 6); - assert.equal(get(obj, 'foo'), 'bar', 'The set value is properly returned'); - assert.ok(typeof obj.foo === 'string', 'The computed property was removed'); - assert.ok(observerFired, 'The observer was still notified'); + assert.equal(plusOneDidChange, 2); + } + } +); + +moduleFor( + 'computed - default setter', + class extends AbstractTestCase { + ["@test when setting a value on a computed property that doesn't handle sets"]( + assert + ) { + let obj = {}; + let observerFired = false; + + defineProperty( + obj, + 'foo', + computed(function() { + return 'foo'; + }) + ); + + addObserver(obj, 'foo', null, () => (observerFired = true)); + + set(obj, 'foo', 'bar'); + + assert.equal( + get(obj, 'foo'), + 'bar', + 'The set value is properly returned' + ); + assert.ok( + typeof obj.foo === 'string', + 'The computed property was removed' + ); + assert.ok(observerFired, 'The observer was still notified'); + } } -}); +); -moduleFor('computed - readOnly', class extends AbstractTestCase { - ['@test is chainable'](assert) { - let cp = computed(function() {}).readOnly(); +moduleFor( + 'computed - readOnly', + class extends AbstractTestCase { + ['@test is chainable'](assert) { + let cp = computed(function() {}).readOnly(); - assert.ok(cp instanceof Descriptor); - assert.ok(cp instanceof ComputedProperty); - } + assert.ok(cp instanceof Descriptor); + assert.ok(cp instanceof ComputedProperty); + } - ['@test throws assertion if called over a CP with a setter defined with the new syntax']() { - expectAssertion(() => { - computed({ - get() { }, - set() { } - }).readOnly(); - }, /Computed properties that define a setter using the new syntax cannot be read-only/); - } + ['@test throws assertion if called over a CP with a setter defined with the new syntax']() { + expectAssertion(() => { + computed({ + get() {}, + set() {} + }).readOnly(); + }, /Computed properties that define a setter using the new syntax cannot be read-only/); + } - ['@test protects against setting'](assert) { - let obj = { }; + ['@test protects against setting'](assert) { + let obj = {}; - defineProperty(obj, 'bar', computed(function() { - return 'barValue'; - }).readOnly()); + defineProperty( + obj, + 'bar', + computed(function() { + return 'barValue'; + }).readOnly() + ); - assert.equal(get(obj, 'bar'), 'barValue'); + assert.equal(get(obj, 'bar'), 'barValue'); - assert.throws(() => { - set(obj, 'bar', 'newBar'); - }, /Cannot set read\-only property "bar" on object:/); + assert.throws(() => { + set(obj, 'bar', 'newBar'); + }, /Cannot set read\-only property "bar" on object:/); - assert.equal(get(obj, 'bar'), 'barValue'); + assert.equal(get(obj, 'bar'), 'barValue'); + } } -}); - +); diff --git a/packages/ember-metal/tests/descriptor_test.js b/packages/ember-metal/tests/descriptor_test.js index abce1c37883..8af78673ef7 100644 --- a/packages/ember-metal/tests/descriptor_test.js +++ b/packages/ember-metal/tests/descriptor_test.js @@ -1,13 +1,7 @@ import { Object as EmberObject } from 'ember-runtime'; -import { - Mixin, - defineProperty, - descriptor -} from '..'; - +import { Mixin, defineProperty, descriptor } from '..'; class DescriptorTest { - /* abstract static module(title: string); */ static test(title, callback) { @@ -28,7 +22,6 @@ class DescriptorTest { } let classes = [ - class extends DescriptorTest { static module(title) { QUnit.module(`${title}: using defineProperty on an object directly`); @@ -177,7 +170,6 @@ let classes = [ return this.superklass.prototype; } } - ]; classes.forEach(TestClass => { @@ -201,7 +193,10 @@ classes.forEach(TestClass => { assert.equal(obj.foo, 'baz'); }); - TestClass.test('defining a non-configurable property', function(assert, factory) { + TestClass.test('defining a non-configurable property', function( + assert, + factory + ) { factory.install('foo', descriptor({ configurable: false, value: 'bar' })); let obj = factory.finalize(); @@ -212,7 +207,14 @@ classes.forEach(TestClass => { assert.throws(() => delete source.foo, TypeError); - assert.throws(() => Object.defineProperty(source, 'foo', { configurable: true, value: 'baz' }), TypeError); + assert.throws( + () => + Object.defineProperty(source, 'foo', { + configurable: true, + value: 'baz' + }), + TypeError + ); assert.equal(obj.foo, 'bar'); }); @@ -229,7 +231,10 @@ classes.forEach(TestClass => { assert.ok(Object.keys(source).indexOf('foo') !== -1); }); - TestClass.test('defining a non-enumerable property', function(assert, factory) { + TestClass.test('defining a non-enumerable property', function( + assert, + factory + ) { factory.install('foo', descriptor({ enumerable: false, value: 'bar' })); let obj = factory.finalize(); @@ -268,18 +273,21 @@ classes.forEach(TestClass => { let source = factory.source(); - assert.throws(() => source.foo = 'baz', TypeError); - assert.throws(() => obj.foo = 'baz', TypeError); + assert.throws(() => (source.foo = 'baz'), TypeError); + assert.throws(() => (obj.foo = 'baz'), TypeError); assert.equal(obj.foo, 'bar'); }); TestClass.test('defining a getter', function(assert, factory) { - factory.install('foo', descriptor({ - get: function() { - return this.__foo__; - } - })); + factory.install( + 'foo', + descriptor({ + get: function() { + return this.__foo__; + } + }) + ); factory.set('__foo__', 'bar'); @@ -293,11 +301,14 @@ classes.forEach(TestClass => { }); TestClass.test('defining a setter', function(assert, factory) { - factory.install('foo', descriptor({ - set: function(value) { - this.__foo__ = value; - } - })); + factory.install( + 'foo', + descriptor({ + set: function(value) { + this.__foo__ = value; + } + }) + ); factory.set('__foo__', 'bar'); @@ -310,36 +321,48 @@ classes.forEach(TestClass => { assert.equal(obj.__foo__, 'baz'); }); - TestClass.test('combining multiple setter and getters', function(assert, factory) { - factory.install('foo', descriptor({ - get: function() { - return this.__foo__; - }, - - set: function(value) { - this.__foo__ = value; - } - })); + TestClass.test('combining multiple setter and getters', function( + assert, + factory + ) { + factory.install( + 'foo', + descriptor({ + get: function() { + return this.__foo__; + }, + + set: function(value) { + this.__foo__ = value; + } + }) + ); factory.set('__foo__', 'foo'); - factory.install('bar', descriptor({ - get: function() { - return this.__bar__; - }, + factory.install( + 'bar', + descriptor({ + get: function() { + return this.__bar__; + }, - set: function(value) { - this.__bar__ = value; - } - })); + set: function(value) { + this.__bar__ = value; + } + }) + ); factory.set('__bar__', 'bar'); - factory.install('fooBar', descriptor({ - get: function() { - return this.foo + '-' + this.bar; - } - })); + factory.install( + 'fooBar', + descriptor({ + get: function() { + return this.foo + '-' + this.bar; + } + }) + ); let obj = factory.finalize(); @@ -353,7 +376,7 @@ classes.forEach(TestClass => { assert.equal(obj.fooBar, 'FOO-BAR'); - assert.throws(() => obj.fooBar = 'foobar', TypeError); + assert.throws(() => (obj.fooBar = 'foobar'), TypeError); assert.equal(obj.fooBar, 'FOO-BAR'); }); diff --git a/packages/ember-metal/tests/events_test.js b/packages/ember-metal/tests/events_test.js index 85f511870a9..ae4114e1446 100644 --- a/packages/ember-metal/tests/events_test.js +++ b/packages/ember-metal/tests/events_test.js @@ -8,199 +8,220 @@ import { } from '..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('system/props/events_test', class extends AbstractTestCase { - ['@test listener should receive event - removing should remove'](assert) { - let obj = {}; - let count = 0; - - function F() { count++; } - - addListener(obj, 'event!', F); - assert.equal(count, 0, 'nothing yet'); - - sendEvent(obj, 'event!'); - assert.equal(count, 1, 'received event'); - - removeListener(obj, 'event!', F); - - count = 0; - sendEvent(obj, 'event!'); - assert.equal(count, 0, 'received event'); - } - - ['@test listeners should be inherited'](assert) { - let obj = {}; - let count = 0; - let F = function() { count++; }; - - addListener(obj, 'event!', F); - - let obj2 = Object.create(obj); - - assert.equal(count, 0, 'nothing yet'); - - sendEvent(obj2, 'event!'); - assert.equal(count, 1, 'received event'); - - removeListener(obj2, 'event!', F); - - count = 0; - sendEvent(obj2, 'event!'); - assert.equal(count, 0, 'did not receive event'); - - sendEvent(obj, 'event!'); - assert.equal(count, 1, 'should still invoke on parent'); - } - - - ['@test adding a listener more than once should only invoke once'](assert) { - let obj = {}; - let count = 0; - function F() { count++; } - addListener(obj, 'event!', F); - addListener(obj, 'event!', F); - - sendEvent(obj, 'event!'); - assert.equal(count, 1, 'should only invoke once'); - } - - ['@test adding a listener with a target should invoke with target'](assert) { - let obj = {}; - let target; - - target = { - count: 0, - method() { this.count++; } - }; - - addListener(obj, 'event!', target, target.method); - sendEvent(obj, 'event!'); - assert.equal(target.count, 1, 'should invoke'); - } - - ['@test adding a listener with string method should lookup method on event delivery'](assert) { - let obj = {}; - let target; - - target = { - count: 0, - method() {} - }; - - addListener(obj, 'event!', target, 'method'); - sendEvent(obj, 'event!'); - assert.equal(target.count, 0, 'should invoke but do nothing'); - - target.method = function() { this.count++; }; - sendEvent(obj, 'event!'); - assert.equal(target.count, 1, 'should invoke now'); - } - - ['@test calling sendEvent with extra params should be passed to listeners'](assert) { - let obj = {}; - let params = null; - addListener(obj, 'event!', function() { - params = Array.prototype.slice.call(arguments); - }); - - sendEvent(obj, 'event!', ['foo', 'bar']); - assert.deepEqual(params, ['foo', 'bar'], 'params should be saved'); - } - - ['@test hasListeners tells you if there are listeners for a given event'](assert) { - let obj = {}; +moduleFor( + 'system/props/events_test', + class extends AbstractTestCase { + ['@test listener should receive event - removing should remove'](assert) { + let obj = {}; + let count = 0; + + function F() { + count++; + } + + addListener(obj, 'event!', F); + assert.equal(count, 0, 'nothing yet'); + + sendEvent(obj, 'event!'); + assert.equal(count, 1, 'received event'); + + removeListener(obj, 'event!', F); + + count = 0; + sendEvent(obj, 'event!'); + assert.equal(count, 0, 'received event'); + } + + ['@test listeners should be inherited'](assert) { + let obj = {}; + let count = 0; + let F = function() { + count++; + }; + + addListener(obj, 'event!', F); + + let obj2 = Object.create(obj); + + assert.equal(count, 0, 'nothing yet'); + + sendEvent(obj2, 'event!'); + assert.equal(count, 1, 'received event'); + + removeListener(obj2, 'event!', F); + + count = 0; + sendEvent(obj2, 'event!'); + assert.equal(count, 0, 'did not receive event'); + + sendEvent(obj, 'event!'); + assert.equal(count, 1, 'should still invoke on parent'); + } + + ['@test adding a listener more than once should only invoke once'](assert) { + let obj = {}; + let count = 0; + function F() { + count++; + } + addListener(obj, 'event!', F); + addListener(obj, 'event!', F); + + sendEvent(obj, 'event!'); + assert.equal(count, 1, 'should only invoke once'); + } + + ['@test adding a listener with a target should invoke with target']( + assert + ) { + let obj = {}; + let target; + + target = { + count: 0, + method() { + this.count++; + } + }; + + addListener(obj, 'event!', target, target.method); + sendEvent(obj, 'event!'); + assert.equal(target.count, 1, 'should invoke'); + } + + ['@test adding a listener with string method should lookup method on event delivery']( + assert + ) { + let obj = {}; + let target; + + target = { + count: 0, + method() {} + }; + + addListener(obj, 'event!', target, 'method'); + sendEvent(obj, 'event!'); + assert.equal(target.count, 0, 'should invoke but do nothing'); + + target.method = function() { + this.count++; + }; + sendEvent(obj, 'event!'); + assert.equal(target.count, 1, 'should invoke now'); + } + + ['@test calling sendEvent with extra params should be passed to listeners']( + assert + ) { + let obj = {}; + let params = null; + addListener(obj, 'event!', function() { + params = Array.prototype.slice.call(arguments); + }); - function F() {} - function F2() {} + sendEvent(obj, 'event!', ['foo', 'bar']); + assert.deepEqual(params, ['foo', 'bar'], 'params should be saved'); + } - assert.equal(hasListeners(obj, 'event!'), false, 'no listeners at first'); + ['@test hasListeners tells you if there are listeners for a given event']( + assert + ) { + let obj = {}; - addListener(obj, 'event!', F); - addListener(obj, 'event!', F2); + function F() {} + function F2() {} - assert.equal(hasListeners(obj, 'event!'), true, 'has listeners'); + assert.equal(hasListeners(obj, 'event!'), false, 'no listeners at first'); - removeListener(obj, 'event!', F); - assert.equal(hasListeners(obj, 'event!'), true, 'has listeners'); + addListener(obj, 'event!', F); + addListener(obj, 'event!', F2); - removeListener(obj, 'event!', F2); - assert.equal(hasListeners(obj, 'event!'), false, 'has no more listeners'); + assert.equal(hasListeners(obj, 'event!'), true, 'has listeners'); - addListener(obj, 'event!', F); - assert.equal(hasListeners(obj, 'event!'), true, 'has listeners'); - } + removeListener(obj, 'event!', F); + assert.equal(hasListeners(obj, 'event!'), true, 'has listeners'); - ['@test calling removeListener without method should remove all listeners'](assert) { - let obj = {}; - function F() {} - function F2() {} + removeListener(obj, 'event!', F2); + assert.equal(hasListeners(obj, 'event!'), false, 'has no more listeners'); - assert.equal(hasListeners(obj, 'event!'), false, 'no listeners at first'); + addListener(obj, 'event!', F); + assert.equal(hasListeners(obj, 'event!'), true, 'has listeners'); + } - addListener(obj, 'event!', F); - addListener(obj, 'event!', F2); + ['@test calling removeListener without method should remove all listeners']( + assert + ) { + let obj = {}; + function F() {} + function F2() {} - assert.equal(hasListeners(obj, 'event!'), true, 'has listeners'); - removeListener(obj, 'event!'); + assert.equal(hasListeners(obj, 'event!'), false, 'no listeners at first'); - assert.equal(hasListeners(obj, 'event!'), false, 'has no more listeners'); - } + addListener(obj, 'event!', F); + addListener(obj, 'event!', F2); - ['@test a listener can be added as part of a mixin'](assert) { - let triggered = 0; - let MyMixin = Mixin.create({ - foo1: on('bar', function() { - triggered++; - }), + assert.equal(hasListeners(obj, 'event!'), true, 'has listeners'); + removeListener(obj, 'event!'); - foo2: on('bar', function() { - triggered++; - }) - }); + assert.equal(hasListeners(obj, 'event!'), false, 'has no more listeners'); + } - let obj = {}; - MyMixin.apply(obj); - - sendEvent(obj, 'bar'); - assert.equal(triggered, 2, 'should invoke listeners'); - } + ['@test a listener can be added as part of a mixin'](assert) { + let triggered = 0; + let MyMixin = Mixin.create({ + foo1: on('bar', function() { + triggered++; + }), - [`@test 'on' asserts for invalid arguments`]() { - expectAssertion(()=> { - Mixin.create({ - foo1: on('bar'), + foo2: on('bar', function() { + triggered++; + }) }); - }, 'on expects function as last argument'); - expectAssertion(()=> { - Mixin.create({ - foo1: on(function(){}), + let obj = {}; + MyMixin.apply(obj); + + sendEvent(obj, 'bar'); + assert.equal(triggered, 2, 'should invoke listeners'); + } + + [`@test 'on' asserts for invalid arguments`]() { + expectAssertion(() => { + Mixin.create({ + foo1: on('bar') + }); + }, 'on expects function as last argument'); + + expectAssertion(() => { + Mixin.create({ + foo1: on(function() {}) + }); + }, 'on called without valid event names'); + } + + ['@test a listener added as part of a mixin may be overridden'](assert) { + let triggered = 0; + let FirstMixin = Mixin.create({ + foo: on('bar', function() { + triggered++; + }) + }); + let SecondMixin = Mixin.create({ + foo: on('baz', function() { + triggered++; + }) }); - }, 'on called without valid event names'); - } - ['@test a listener added as part of a mixin may be overridden'](assert) { - let triggered = 0; - let FirstMixin = Mixin.create({ - foo: on('bar', function() { - triggered++; - }) - }); - let SecondMixin = Mixin.create({ - foo: on('baz', function() { - triggered++; - }) - }); - - let obj = {}; - FirstMixin.apply(obj); - SecondMixin.apply(obj); - - sendEvent(obj, 'bar'); - assert.equal(triggered, 0, 'should not invoke from overridden property'); - - sendEvent(obj, 'baz'); - assert.equal(triggered, 1, 'should invoke from subclass property'); - } -}); + let obj = {}; + FirstMixin.apply(obj); + SecondMixin.apply(obj); + sendEvent(obj, 'bar'); + assert.equal(triggered, 0, 'should not invoke from overridden property'); + + sendEvent(obj, 'baz'); + assert.equal(triggered, 1, 'should invoke from subclass property'); + } + } +); diff --git a/packages/ember-metal/tests/expand_properties_test.js b/packages/ember-metal/tests/expand_properties_test.js index 4a202659aed..f8c455439b9 100644 --- a/packages/ember-metal/tests/expand_properties_test.js +++ b/packages/ember-metal/tests/expand_properties_test.js @@ -7,111 +7,123 @@ function addProperty(property) { foundProperties.push(property); } -moduleFor('Property Brace Expansion Test', class extends AbstractTestCase { - beforeEach() { - foundProperties = []; - } +moduleFor( + 'Property Brace Expansion Test', + class extends AbstractTestCase { + beforeEach() { + foundProperties = []; + } - ['@test Properties without expansions are unaffected'](assert) { - assert.expect(1); + ['@test Properties without expansions are unaffected'](assert) { + assert.expect(1); - expandProperties('a', addProperty); - expandProperties('a.b', addProperty); - expandProperties('a.b.[]', addProperty); - expandProperties('a.b.@each.c', addProperty); + expandProperties('a', addProperty); + expandProperties('a.b', addProperty); + expandProperties('a.b.[]', addProperty); + expandProperties('a.b.@each.c', addProperty); - assert.deepEqual(['a', 'a.b', 'a.b.[]', 'a.b.@each.c'].sort(), foundProperties.sort()); - } + assert.deepEqual( + ['a', 'a.b', 'a.b.[]', 'a.b.@each.c'].sort(), + foundProperties.sort() + ); + } - ['@test A single expansion at the end expands properly'](assert) { - assert.expect(1); + ['@test A single expansion at the end expands properly'](assert) { + assert.expect(1); - expandProperties('a.b.{c,d}', addProperty); + expandProperties('a.b.{c,d}', addProperty); - assert.deepEqual(['a.b.c', 'a.b.d'].sort(), foundProperties.sort()); - } + assert.deepEqual(['a.b.c', 'a.b.d'].sort(), foundProperties.sort()); + } - ['@test A property with only a brace expansion expands correctly'](assert) { - assert.expect(1); + ['@test A property with only a brace expansion expands correctly'](assert) { + assert.expect(1); - expandProperties('{a,b,c}', addProperty); + expandProperties('{a,b,c}', addProperty); - let expected = ['a', 'b', 'c']; - assert.deepEqual(expected.sort(), foundProperties.sort()); - } + let expected = ['a', 'b', 'c']; + assert.deepEqual(expected.sort(), foundProperties.sort()); + } - ['@test Expansions with single properties only expand once'](assert) { - assert.expect(1); + ['@test Expansions with single properties only expand once'](assert) { + assert.expect(1); - expandProperties('a.b.{c}.d.{e}', addProperty); + expandProperties('a.b.{c}.d.{e}', addProperty); - assert.deepEqual(['a.b.c.d.e'], foundProperties); - } + assert.deepEqual(['a.b.c.d.e'], foundProperties); + } - ['@test A single brace expansion expands correctly'](assert) { - assert.expect(1); + ['@test A single brace expansion expands correctly'](assert) { + assert.expect(1); - expandProperties('a.{b,c,d}.e', addProperty); + expandProperties('a.{b,c,d}.e', addProperty); - let expected = ['a.b.e', 'a.c.e', 'a.d.e']; - assert.deepEqual(expected.sort(), foundProperties.sort()); - } + let expected = ['a.b.e', 'a.c.e', 'a.d.e']; + assert.deepEqual(expected.sort(), foundProperties.sort()); + } - ['@test Multiple brace expansions work correctly'](assert) { - assert.expect(1); + ['@test Multiple brace expansions work correctly'](assert) { + assert.expect(1); - expandProperties('{a,b,c}.d.{e,f}.g', addProperty); + expandProperties('{a,b,c}.d.{e,f}.g', addProperty); - let expected = ['a.d.e.g', 'a.d.f.g', 'b.d.e.g', 'b.d.f.g', 'c.d.e.g', 'c.d.f.g']; - assert.deepEqual(expected.sort(), foundProperties.sort()); - } + let expected = [ + 'a.d.e.g', + 'a.d.f.g', + 'b.d.e.g', + 'b.d.f.g', + 'c.d.e.g', + 'c.d.f.g' + ]; + assert.deepEqual(expected.sort(), foundProperties.sort()); + } - ['@test A property with only brace expansions expands correctly'](assert) { - assert.expect(1); + ['@test A property with only brace expansions expands correctly'](assert) { + assert.expect(1); - expandProperties('{a,b,c}.{d}.{e,f}', addProperty); + expandProperties('{a,b,c}.{d}.{e,f}', addProperty); - let expected = ['a.d.e', 'a.d.f', 'b.d.e', 'b.d.f', 'c.d.e', 'c.d.f']; - assert.deepEqual(expected.sort(), foundProperties.sort()); - } + let expected = ['a.d.e', 'a.d.f', 'b.d.e', 'b.d.f', 'c.d.e', 'c.d.f']; + assert.deepEqual(expected.sort(), foundProperties.sort()); + } - ['@test Nested brace expansions are not allowed']() { - let nestedBraceProperties = [ - 'a.{b.{c,d}}', - 'a.{{b}.c}', - 'a.{b,c}.{d.{e,f}.g', - 'a.{b.{c}', - 'a.{b,c}}', - 'model.{bar,baz' - ]; - - nestedBraceProperties.forEach((invalidProperties) => { - expectAssertion(() => expandProperties(invalidProperties, addProperty)); - }, /Brace expanded properties have to be balanced and cannot be nested/); - } + ['@test Nested brace expansions are not allowed']() { + let nestedBraceProperties = [ + 'a.{b.{c,d}}', + 'a.{{b}.c}', + 'a.{b,c}.{d.{e,f}.g', + 'a.{b.{c}', + 'a.{b,c}}', + 'model.{bar,baz' + ]; - ['@test A property with no braces does not expand'](assert) { - assert.expect(1); + nestedBraceProperties.forEach(invalidProperties => { + expectAssertion(() => expandProperties(invalidProperties, addProperty)); + }, /Brace expanded properties have to be balanced and cannot be nested/); + } - expandProperties('a,b,c.d.e,f', addProperty); + ['@test A property with no braces does not expand'](assert) { + assert.expect(1); - assert.deepEqual(foundProperties, ['a,b,c.d.e,f']); - } + expandProperties('a,b,c.d.e,f', addProperty); - ['@test A pattern must be a string'](assert) { - assert.expect(1); + assert.deepEqual(foundProperties, ['a,b,c.d.e,f']); + } - expectAssertion(() => { - expandProperties([1, 2], addProperty); - }, /A computed property key must be a string/); - } + ['@test A pattern must be a string'](assert) { + assert.expect(1); - ['@test A pattern must not contain a space'](assert) { - assert.expect(1); + expectAssertion(() => { + expandProperties([1, 2], addProperty); + }, /A computed property key must be a string/); + } - expectAssertion(function() { - expandProperties('{a, b}', addProperty); - }, /Brace expanded properties cannot contain spaces, e.g. "user.{firstName, lastName}" should be "user.{firstName,lastName}"/); - } -}); + ['@test A pattern must not contain a space'](assert) { + assert.expect(1); + expectAssertion(function() { + expandProperties('{a, b}', addProperty); + }, /Brace expanded properties cannot contain spaces, e.g. "user.{firstName, lastName}" should be "user.{firstName,lastName}"/); + } + } +); diff --git a/packages/ember-metal/tests/injected_property_test.js b/packages/ember-metal/tests/injected_property_test.js index 75eca609eea..06d165431b5 100644 --- a/packages/ember-metal/tests/injected_property_test.js +++ b/packages/ember-metal/tests/injected_property_test.js @@ -1,80 +1,96 @@ import { setOwner } from 'ember-utils'; -import { - Descriptor, - defineProperty, - get, - set, - InjectedProperty -} from '..'; +import { Descriptor, defineProperty, get, set, InjectedProperty } from '..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('InjectedProperty', class extends AbstractTestCase { - ['@test injected properties should be descriptors'](assert) { - assert.ok(new InjectedProperty() instanceof Descriptor); - } - - ['@test injected properties should be overridable'](assert) { - let obj = {}; - defineProperty(obj, 'foo', new InjectedProperty()); +moduleFor( + 'InjectedProperty', + class extends AbstractTestCase { + ['@test injected properties should be descriptors'](assert) { + assert.ok(new InjectedProperty() instanceof Descriptor); + } + + ['@test injected properties should be overridable'](assert) { + let obj = {}; + defineProperty(obj, 'foo', new InjectedProperty()); + + set(obj, 'foo', 'bar'); + + assert.equal( + get(obj, 'foo'), + 'bar', + 'should return the overridden value' + ); + } + + ['@test getting on an object without an owner or container should fail assertion']() { + let obj = {}; + defineProperty(obj, 'foo', new InjectedProperty('type', 'name')); + + expectAssertion(function() { + get(obj, 'foo'); + }, /Attempting to lookup an injected property on an object without a container, ensure that the object was instantiated via a container./); + } + + ['@test getting on an object without an owner but with a container should not fail']( + assert + ) { + let obj = { + container: { + lookup(key) { + assert.ok(true, 'should call container.lookup'); + return key; + } + } + }; - set(obj, 'foo', 'bar'); + defineProperty(obj, 'foo', new InjectedProperty('type', 'name')); - assert.equal(get(obj, 'foo'), 'bar', 'should return the overridden value'); - } + assert.equal( + get(obj, 'foo'), + 'type:name', + 'should return the value of container.lookup' + ); + } - ['@test getting on an object without an owner or container should fail assertion']() { - let obj = {}; - defineProperty(obj, 'foo', new InjectedProperty('type', 'name')); + ['@test getting should return a lookup on the container'](assert) { + assert.expect(2); - expectAssertion(function() { - get(obj, 'foo'); - }, /Attempting to lookup an injected property on an object without a container, ensure that the object was instantiated via a container./); - } + let obj = {}; - ['@test getting on an object without an owner but with a container should not fail'](assert) { - let obj = { - container: { + setOwner(obj, { lookup(key) { assert.ok(true, 'should call container.lookup'); return key; } - } - }; - - defineProperty(obj, 'foo', new InjectedProperty('type', 'name')); - - assert.equal(get(obj, 'foo'), 'type:name', 'should return the value of container.lookup'); - } + }); - ['@test getting should return a lookup on the container'](assert) { - assert.expect(2); + defineProperty(obj, 'foo', new InjectedProperty('type', 'name')); - let obj = {}; + assert.equal( + get(obj, 'foo'), + 'type:name', + 'should return the value of container.lookup' + ); + } - setOwner(obj, { - lookup(key) { - assert.ok(true, 'should call container.lookup'); - return key; - } - }); + ['@test omitting the lookup name should default to the property name']( + assert + ) { + let obj = {}; - defineProperty(obj, 'foo', new InjectedProperty('type', 'name')); - - assert.equal(get(obj, 'foo'), 'type:name', 'should return the value of container.lookup'); - } - - ['@test omitting the lookup name should default to the property name'](assert) { - let obj = {}; - - setOwner(obj, { - lookup(key) { - return key; - } - }); + setOwner(obj, { + lookup(key) { + return key; + } + }); - defineProperty(obj, 'foo', new InjectedProperty('type')); + defineProperty(obj, 'foo', new InjectedProperty('type')); - assert.equal(get(obj, 'foo'), 'type:foo', 'should lookup the type using the property name'); + assert.equal( + get(obj, 'foo'), + 'type:foo', + 'should lookup the type using the property name' + ); + } } -}); - +); diff --git a/packages/ember-metal/tests/instrumentation_test.js b/packages/ember-metal/tests/instrumentation_test.js index dfedcf6cff0..334c59c41d6 100644 --- a/packages/ember-metal/tests/instrumentation_test.js +++ b/packages/ember-metal/tests/instrumentation_test.js @@ -6,205 +6,226 @@ import { } from '..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('Ember Instrumentation', class extends AbstractTestCase { - afterEach() { - reset(); - } - - ['@test execute block even if no listeners'](assert) { - let result = instrument('render', {}, function() { - return 'hello'; - }); - assert.equal(result, 'hello', 'called block'); - } - - ['@test subscribing to a simple path receives the listener'](assert) { - assert.expect(12); - - let sentPayload = {}; - let count = 0; - - subscribe('render', { - before(name, timestamp, payload) { - if (count === 0) { - assert.strictEqual(name, 'render'); - } else { - assert.strictEqual(name, 'render.handlebars'); +moduleFor( + 'Ember Instrumentation', + class extends AbstractTestCase { + afterEach() { + reset(); + } + + ['@test execute block even if no listeners'](assert) { + let result = instrument('render', {}, function() { + return 'hello'; + }); + assert.equal(result, 'hello', 'called block'); + } + + ['@test subscribing to a simple path receives the listener'](assert) { + assert.expect(12); + + let sentPayload = {}; + let count = 0; + + subscribe('render', { + before(name, timestamp, payload) { + if (count === 0) { + assert.strictEqual(name, 'render'); + } else { + assert.strictEqual(name, 'render.handlebars'); + } + + assert.ok(typeof timestamp === 'number'); + assert.strictEqual(payload, sentPayload); + }, + + after(name, timestamp, payload) { + if (count === 0) { + assert.strictEqual(name, 'render'); + } else { + assert.strictEqual(name, 'render.handlebars'); + } + + assert.ok(typeof timestamp === 'number'); + assert.strictEqual(payload, sentPayload); + + count++; } + }); - assert.ok(typeof timestamp === 'number'); - assert.strictEqual(payload, sentPayload); - }, - - after(name, timestamp, payload) { - if (count === 0) { - assert.strictEqual(name, 'render'); - } else { - assert.strictEqual(name, 'render.handlebars'); - } - - assert.ok(typeof timestamp === 'number'); - assert.strictEqual(payload, sentPayload); - - count++; - } - }); - - instrument('render', sentPayload, function() {}); - - instrument('render.handlebars', sentPayload, function() {}); - } - - ['@test returning a value from the before callback passes it to the after callback'](assert) { - assert.expect(2); - - let passthru1 = {}; - let passthru2 = {}; - - subscribe('render', { - before() { - return passthru1; - }, - after(name, timestamp, payload, beforeValue) { - assert.strictEqual(beforeValue, passthru1); - } - }); - - subscribe('render', { - before() { - return passthru2; - }, - after(name, timestamp, payload, beforeValue) { - assert.strictEqual(beforeValue, passthru2); - } - }); - - instrument('render', null, function() {}); - } - - ['@test instrument with 2 args (name, callback) no payload'](assert) { - assert.expect(1); - - subscribe('render', { - before(name, timestamp, payload) { - assert.deepEqual(payload, {}); - }, - after() {} - }); - - instrument('render', function() {}); - } - - ['@test instrument with 3 args (name, callback, binding) no payload'](assert) { - assert.expect(2); - - let binding = {}; - subscribe('render', { - before(name, timestamp, payload) { - assert.deepEqual(payload, {}); - }, - after() {} - }); + instrument('render', sentPayload, function() {}); - instrument('render', function() { - assert.deepEqual(this, binding); - }, binding); - } - - - ['@test instrument with 3 args (name, payload, callback) with payload'](assert) { - assert.expect(1); - - let expectedPayload = { hi: 1 }; - subscribe('render', { - before(name, timestamp, payload) { - assert.deepEqual(payload, expectedPayload); - }, - after() {} - }); - - instrument('render', expectedPayload, function() {}); - } - - ['@test instrument with 4 args (name, payload, callback, binding) with payload'](assert) { - assert.expect(2); - - let expectedPayload = { hi: 1 }; - let binding = {}; - subscribe('render', { - before(name, timestamp, payload) { - assert.deepEqual(payload, expectedPayload); - }, - after() {} - }); - - instrument('render', expectedPayload, function() { - assert.deepEqual(this, binding); - }, binding); - } - - - ['@test raising an exception in the instrumentation attaches it to the payload'](assert) { - assert.expect(2); - - let error = new Error('Instrumentation'); + instrument('render.handlebars', sentPayload, function() {}); + } - subscribe('render', { - before() {}, - after(name, timestamp, payload) { - assert.strictEqual(payload.exception, error); - } - }); + ['@test returning a value from the before callback passes it to the after callback']( + assert + ) { + assert.expect(2); - subscribe('render', { - before() {}, - after(name, timestamp, payload) { - assert.strictEqual(payload.exception, error); - } - }); + let passthru1 = {}; + let passthru2 = {}; - instrument('render.handlebars', null, function() { - throw error; - }); - } - - ['@test it is possible to add a new subscriber after the first instrument'](assert) { - instrument('render.handlebars', null, function() {}); + subscribe('render', { + before() { + return passthru1; + }, + after(name, timestamp, payload, beforeValue) { + assert.strictEqual(beforeValue, passthru1); + } + }); + + subscribe('render', { + before() { + return passthru2; + }, + after(name, timestamp, payload, beforeValue) { + assert.strictEqual(beforeValue, passthru2); + } + }); + + instrument('render', null, function() {}); + } + + ['@test instrument with 2 args (name, callback) no payload'](assert) { + assert.expect(1); + + subscribe('render', { + before(name, timestamp, payload) { + assert.deepEqual(payload, {}); + }, + after() {} + }); + + instrument('render', function() {}); + } + + ['@test instrument with 3 args (name, callback, binding) no payload']( + assert + ) { + assert.expect(2); + + let binding = {}; + subscribe('render', { + before(name, timestamp, payload) { + assert.deepEqual(payload, {}); + }, + after() {} + }); + + instrument( + 'render', + function() { + assert.deepEqual(this, binding); + }, + binding + ); + } + + ['@test instrument with 3 args (name, payload, callback) with payload']( + assert + ) { + assert.expect(1); + + let expectedPayload = { hi: 1 }; + subscribe('render', { + before(name, timestamp, payload) { + assert.deepEqual(payload, expectedPayload); + }, + after() {} + }); + + instrument('render', expectedPayload, function() {}); + } + + ['@test instrument with 4 args (name, payload, callback, binding) with payload']( + assert + ) { + assert.expect(2); + + let expectedPayload = { hi: 1 }; + let binding = {}; + subscribe('render', { + before(name, timestamp, payload) { + assert.deepEqual(payload, expectedPayload); + }, + after() {} + }); + + instrument( + 'render', + expectedPayload, + function() { + assert.deepEqual(this, binding); + }, + binding + ); + } + + ['@test raising an exception in the instrumentation attaches it to the payload']( + assert + ) { + assert.expect(2); + + let error = new Error('Instrumentation'); + + subscribe('render', { + before() {}, + after(name, timestamp, payload) { + assert.strictEqual(payload.exception, error); + } + }); - subscribe('render', { - before() { - assert.ok(true, 'Before callback was called'); - }, - after() { - assert.ok(true, 'After callback was called'); - } - }); + subscribe('render', { + before() {}, + after(name, timestamp, payload) { + assert.strictEqual(payload.exception, error); + } + }); + + instrument('render.handlebars', null, function() { + throw error; + }); + } + + ['@test it is possible to add a new subscriber after the first instrument']( + assert + ) { + instrument('render.handlebars', null, function() {}); + + subscribe('render', { + before() { + assert.ok(true, 'Before callback was called'); + }, + after() { + assert.ok(true, 'After callback was called'); + } + }); - instrument('render.handlebars', null, function() {}); - } + instrument('render.handlebars', null, function() {}); + } - ['@test it is possible to remove a subscriber'](assert) { - assert.expect(4); + ['@test it is possible to remove a subscriber'](assert) { + assert.expect(4); - let count = 0; + let count = 0; - let subscriber = subscribe('render', { - before() { - assert.equal(count, 0); - assert.ok(true, 'Before callback was called'); - }, - after() { - assert.equal(count, 0); - assert.ok(true, 'After callback was called'); - count++; - } - }); + let subscriber = subscribe('render', { + before() { + assert.equal(count, 0); + assert.ok(true, 'Before callback was called'); + }, + after() { + assert.equal(count, 0); + assert.ok(true, 'After callback was called'); + count++; + } + }); - instrument('render.handlebars', null, function() {}); + instrument('render.handlebars', null, function() {}); - unsubscribe(subscriber); + unsubscribe(subscriber); - instrument('render.handlebars', null, function() {}); + instrument('render.handlebars', null, function() {}); + } } -}); - +); diff --git a/packages/ember-metal/tests/is_blank_test.js b/packages/ember-metal/tests/is_blank_test.js index 535b2420dd3..28d87e4655f 100644 --- a/packages/ember-metal/tests/is_blank_test.js +++ b/packages/ember-metal/tests/is_blank_test.js @@ -1,27 +1,33 @@ import { isBlank } from '..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('isBlank', class extends AbstractTestCase { - ['@test isBlank'](assert) { - let string = 'string'; - let fn = function() {}; - let object = { length: 0 }; +moduleFor( + 'isBlank', + class extends AbstractTestCase { + ['@test isBlank'](assert) { + let string = 'string'; + let fn = function() {}; + let object = { length: 0 }; - assert.equal(true, isBlank(null), 'for null'); - assert.equal(true, isBlank(undefined), 'for undefined'); - assert.equal(true, isBlank(''), 'for an empty String'); - assert.equal(true, isBlank(' '), 'for a whitespace String'); - assert.equal(true, isBlank('\n\t'), 'for another whitespace String'); - assert.equal(false, isBlank('\n\t Hi'), 'for a String with whitespaces'); - assert.equal(false, isBlank(true), 'for true'); - assert.equal(false, isBlank(false), 'for false'); - assert.equal(false, isBlank(string), 'for a String'); - assert.equal(false, isBlank(fn), 'for a Function'); - assert.equal(false, isBlank(0), 'for 0'); - assert.equal(true, isBlank([]), 'for an empty Array'); - assert.equal(false, isBlank({}), 'for an empty Object'); - assert.equal(true, isBlank(object), 'for an Object that has zero \'length\''); - assert.equal(false, isBlank([1, 2, 3]), 'for a non-empty array'); + assert.equal(true, isBlank(null), 'for null'); + assert.equal(true, isBlank(undefined), 'for undefined'); + assert.equal(true, isBlank(''), 'for an empty String'); + assert.equal(true, isBlank(' '), 'for a whitespace String'); + assert.equal(true, isBlank('\n\t'), 'for another whitespace String'); + assert.equal(false, isBlank('\n\t Hi'), 'for a String with whitespaces'); + assert.equal(false, isBlank(true), 'for true'); + assert.equal(false, isBlank(false), 'for false'); + assert.equal(false, isBlank(string), 'for a String'); + assert.equal(false, isBlank(fn), 'for a Function'); + assert.equal(false, isBlank(0), 'for 0'); + assert.equal(true, isBlank([]), 'for an empty Array'); + assert.equal(false, isBlank({}), 'for an empty Object'); + assert.equal( + true, + isBlank(object), + "for an Object that has zero 'length'" + ); + assert.equal(false, isBlank([1, 2, 3]), 'for a non-empty array'); + } } -}); - +); diff --git a/packages/ember-metal/tests/is_empty_test.js b/packages/ember-metal/tests/is_empty_test.js index d28e46e76f9..bc7c04e77d0 100644 --- a/packages/ember-metal/tests/is_empty_test.js +++ b/packages/ember-metal/tests/is_empty_test.js @@ -1,43 +1,45 @@ -import { - isEmpty, - Map, - OrderedSet -} from '..'; +import { isEmpty, Map, OrderedSet } from '..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('isEmpty', class extends AbstractTestCase { - ['@test isEmpty'](assert) { - let string = 'string'; - let fn = function() {}; - let object = { length: 0 }; +moduleFor( + 'isEmpty', + class extends AbstractTestCase { + ['@test isEmpty'](assert) { + let string = 'string'; + let fn = function() {}; + let object = { length: 0 }; - assert.equal(true, isEmpty(null), 'for null'); - assert.equal(true, isEmpty(undefined), 'for undefined'); - assert.equal(true, isEmpty(''), 'for an empty String'); - assert.equal(false, isEmpty(' '), 'for a whitespace String'); - assert.equal(false, isEmpty('\n\t'), 'for another whitespace String'); - assert.equal(false, isEmpty(true), 'for true'); - assert.equal(false, isEmpty(false), 'for false'); - assert.equal(false, isEmpty(string), 'for a String'); - assert.equal(false, isEmpty(fn), 'for a Function'); - assert.equal(false, isEmpty(0), 'for 0'); - assert.equal(true, isEmpty([]), 'for an empty Array'); - assert.equal(false, isEmpty({}), 'for an empty Object'); - assert.equal(true, isEmpty(object), 'for an Object that has zero \'length\''); - } + assert.equal(true, isEmpty(null), 'for null'); + assert.equal(true, isEmpty(undefined), 'for undefined'); + assert.equal(true, isEmpty(''), 'for an empty String'); + assert.equal(false, isEmpty(' '), 'for a whitespace String'); + assert.equal(false, isEmpty('\n\t'), 'for another whitespace String'); + assert.equal(false, isEmpty(true), 'for true'); + assert.equal(false, isEmpty(false), 'for false'); + assert.equal(false, isEmpty(string), 'for a String'); + assert.equal(false, isEmpty(fn), 'for a Function'); + assert.equal(false, isEmpty(0), 'for 0'); + assert.equal(true, isEmpty([]), 'for an empty Array'); + assert.equal(false, isEmpty({}), 'for an empty Object'); + assert.equal( + true, + isEmpty(object), + "for an Object that has zero 'length'" + ); + } - ['@test isEmpty Map'](assert) { - let map = new Map(); - assert.equal(true, isEmpty(map), 'Empty map is empty'); - map.set('foo', 'bar'); - assert.equal(false, isEmpty(map), 'Map is not empty'); - } + ['@test isEmpty Map'](assert) { + let map = new Map(); + assert.equal(true, isEmpty(map), 'Empty map is empty'); + map.set('foo', 'bar'); + assert.equal(false, isEmpty(map), 'Map is not empty'); + } - ['@test isEmpty Ember.OrderedSet'](assert) { - let orderedSet = new OrderedSet(); - assert.equal(true, isEmpty(orderedSet), 'Empty ordered set is empty'); - orderedSet.add('foo'); - assert.equal(false, isEmpty(orderedSet), 'Ordered set is not empty'); + ['@test isEmpty Ember.OrderedSet'](assert) { + let orderedSet = new OrderedSet(); + assert.equal(true, isEmpty(orderedSet), 'Empty ordered set is empty'); + orderedSet.add('foo'); + assert.equal(false, isEmpty(orderedSet), 'Ordered set is not empty'); + } } -}); - +); diff --git a/packages/ember-metal/tests/is_none_test.js b/packages/ember-metal/tests/is_none_test.js index c92723461d1..1412ed38df2 100644 --- a/packages/ember-metal/tests/is_none_test.js +++ b/packages/ember-metal/tests/is_none_test.js @@ -1,21 +1,23 @@ import { isNone } from '..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('isNone', class extends AbstractTestCase { - ['@test isNone'](assert) { - let string = 'string'; - let fn = function() {}; +moduleFor( + 'isNone', + class extends AbstractTestCase { + ['@test isNone'](assert) { + let string = 'string'; + let fn = function() {}; - assert.equal(true, isNone(null), 'for null'); - assert.equal(true, isNone(undefined), 'for undefined'); - assert.equal(false, isNone(''), 'for an empty String'); - assert.equal(false, isNone(true), 'for true'); - assert.equal(false, isNone(false), 'for false'); - assert.equal(false, isNone(string), 'for a String'); - assert.equal(false, isNone(fn), 'for a Function'); - assert.equal(false, isNone(0), 'for 0'); - assert.equal(false, isNone([]), 'for an empty Array'); - assert.equal(false, isNone({}), 'for an empty Object'); + assert.equal(true, isNone(null), 'for null'); + assert.equal(true, isNone(undefined), 'for undefined'); + assert.equal(false, isNone(''), 'for an empty String'); + assert.equal(false, isNone(true), 'for true'); + assert.equal(false, isNone(false), 'for false'); + assert.equal(false, isNone(string), 'for a String'); + assert.equal(false, isNone(fn), 'for a Function'); + assert.equal(false, isNone(0), 'for 0'); + assert.equal(false, isNone([]), 'for an empty Array'); + assert.equal(false, isNone({}), 'for an empty Object'); + } } -}); - +); diff --git a/packages/ember-metal/tests/is_present_test.js b/packages/ember-metal/tests/is_present_test.js index 2a1e052f33d..00a6e0246c4 100644 --- a/packages/ember-metal/tests/is_present_test.js +++ b/packages/ember-metal/tests/is_present_test.js @@ -1,28 +1,34 @@ import { isPresent } from '..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('isPresent', class extends AbstractTestCase { - ['@test isPresent'](assert) { - let string = 'string'; - let fn = function() {}; - let object = { length: 0 }; +moduleFor( + 'isPresent', + class extends AbstractTestCase { + ['@test isPresent'](assert) { + let string = 'string'; + let fn = function() {}; + let object = { length: 0 }; - assert.equal(false, isPresent(), 'for no params'); - assert.equal(false, isPresent(null), 'for null'); - assert.equal(false, isPresent(undefined), 'for undefined'); - assert.equal(false, isPresent(''), 'for an empty String'); - assert.equal(false, isPresent(' '), 'for a whitespace String'); - assert.equal(false, isPresent('\n\t'), 'for another whitespace String'); - assert.equal(true, isPresent('\n\t Hi'), 'for a String with whitespaces'); - assert.equal(true, isPresent(true), 'for true'); - assert.equal(true, isPresent(false), 'for false'); - assert.equal(true, isPresent(string), 'for a String'); - assert.equal(true, isPresent(fn), 'for a Function'); - assert.equal(true, isPresent(0), 'for 0'); - assert.equal(false, isPresent([]), 'for an empty Array'); - assert.equal(true, isPresent({}), 'for an empty Object'); - assert.equal(false, isPresent(object), 'for an Object that has zero \'length\''); - assert.equal(true, isPresent([1, 2, 3]), 'for a non-empty array'); + assert.equal(false, isPresent(), 'for no params'); + assert.equal(false, isPresent(null), 'for null'); + assert.equal(false, isPresent(undefined), 'for undefined'); + assert.equal(false, isPresent(''), 'for an empty String'); + assert.equal(false, isPresent(' '), 'for a whitespace String'); + assert.equal(false, isPresent('\n\t'), 'for another whitespace String'); + assert.equal(true, isPresent('\n\t Hi'), 'for a String with whitespaces'); + assert.equal(true, isPresent(true), 'for true'); + assert.equal(true, isPresent(false), 'for false'); + assert.equal(true, isPresent(string), 'for a String'); + assert.equal(true, isPresent(fn), 'for a Function'); + assert.equal(true, isPresent(0), 'for 0'); + assert.equal(false, isPresent([]), 'for an empty Array'); + assert.equal(true, isPresent({}), 'for an empty Object'); + assert.equal( + false, + isPresent(object), + "for an Object that has zero 'length'" + ); + assert.equal(true, isPresent([1, 2, 3]), 'for a non-empty array'); + } } -}); - +); diff --git a/packages/ember-metal/tests/libraries_test.js b/packages/ember-metal/tests/libraries_test.js index 90c283a49e9..37be0ed9ef9 100644 --- a/packages/ember-metal/tests/libraries_test.js +++ b/packages/ember-metal/tests/libraries_test.js @@ -8,90 +8,97 @@ let libs, registry; let originalWarn = getDebugFunction('warn'); function noop() {} -moduleFor('Libraries registry', class extends AbstractTestCase { - beforeEach() { - libs = new Libraries(); - registry = libs._registry; - } - - afterEach() { - libs = null; - registry = null; - - setDebugFunction('warn', originalWarn); - } - - ['@test core libraries come before other libraries'](assert) { - assert.expect(2); +moduleFor( + 'Libraries registry', + class extends AbstractTestCase { + beforeEach() { + libs = new Libraries(); + registry = libs._registry; + } - libs.register('my-lib', '2.0.0a'); - libs.registerCoreLibrary('DS', '1.0.0-beta.2'); + afterEach() { + libs = null; + registry = null; - assert.equal(registry[0].name, 'DS'); - assert.equal(registry[1].name, 'my-lib'); - } + setDebugFunction('warn', originalWarn); + } - ['@test only the first registration of a library is stored'](assert) { - assert.expect(3); + ['@test core libraries come before other libraries'](assert) { + assert.expect(2); - // overwrite warn to supress the double registration warning (see https://github.com/emberjs/ember.js/issues/16391) - setDebugFunction('warn', noop); - libs.register('magic', 1.23); - libs.register('magic', 2.23); + libs.register('my-lib', '2.0.0a'); + libs.registerCoreLibrary('DS', '1.0.0-beta.2'); - assert.equal(registry[0].name, 'magic'); - assert.equal(registry[0].version, 1.23); - assert.equal(registry.length, 1); - } + assert.equal(registry[0].name, 'DS'); + assert.equal(registry[1].name, 'my-lib'); + } - ['@test isRegistered returns correct value'](assert) { - if (EMBER_LIBRARIES_ISREGISTERED) { + ['@test only the first registration of a library is stored'](assert) { assert.expect(3); - assert.equal(libs.isRegistered('magic'), false); - + // overwrite warn to supress the double registration warning (see https://github.com/emberjs/ember.js/issues/16391) + setDebugFunction('warn', noop); libs.register('magic', 1.23); - assert.equal(libs.isRegistered('magic'), true); + libs.register('magic', 2.23); - libs.deRegister('magic'); - assert.equal(libs.isRegistered('magic'), false); - } else { - assert.expect(0); + assert.equal(registry[0].name, 'magic'); + assert.equal(registry[0].version, 1.23); + assert.equal(registry.length, 1); } - } - ['@test attempting to register a library that is already registered warns you'](assert) { - if (EmberDev && EmberDev.runningProdBuild) { - assert.ok(true, 'Logging does not occur in production builds'); - return; - } + ['@test isRegistered returns correct value'](assert) { + if (EMBER_LIBRARIES_ISREGISTERED) { + assert.expect(3); - assert.expect(1); + assert.equal(libs.isRegistered('magic'), false); - libs.register('magic', 1.23); + libs.register('magic', 1.23); + assert.equal(libs.isRegistered('magic'), true); - setDebugFunction('warn', function(msg, test) { - if (!test) { - assert.equal(msg, 'Library "magic" is already registered with Ember.'); + libs.deRegister('magic'); + assert.equal(libs.isRegistered('magic'), false); + } else { + assert.expect(0); } - }); + } - // Should warn us - libs.register('magic', 2.23); - } + ['@test attempting to register a library that is already registered warns you']( + assert + ) { + if (EmberDev && EmberDev.runningProdBuild) { + assert.ok(true, 'Logging does not occur in production builds'); + return; + } - ['@test libraries can be de-registered'](assert) { - assert.expect(2); + assert.expect(1); - libs.register('lib1', '1.0.0b'); - libs.register('lib2', '1.0.0b'); - libs.register('lib3', '1.0.0b'); + libs.register('magic', 1.23); - libs.deRegister('lib1'); - libs.deRegister('lib3'); + setDebugFunction('warn', function(msg, test) { + if (!test) { + assert.equal( + msg, + 'Library "magic" is already registered with Ember.' + ); + } + }); + + // Should warn us + libs.register('magic', 2.23); + } - assert.equal(registry[0].name, 'lib2'); - assert.equal(registry.length, 1); - } -}); + ['@test libraries can be de-registered'](assert) { + assert.expect(2); + + libs.register('lib1', '1.0.0b'); + libs.register('lib2', '1.0.0b'); + libs.register('lib3', '1.0.0b'); + + libs.deRegister('lib1'); + libs.deRegister('lib3'); + assert.equal(registry[0].name, 'lib2'); + assert.equal(registry.length, 1); + } + } +); diff --git a/packages/ember-metal/tests/main_test.js b/packages/ember-metal/tests/main_test.js index 0ffa3df4fc2..90955980180 100644 --- a/packages/ember-metal/tests/main_test.js +++ b/packages/ember-metal/tests/main_test.js @@ -4,26 +4,33 @@ import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; // From https://github.com/semver/semver.org/issues/59 & https://regex101.com/r/vW1jA8/6 const SEMVER_REGEX = /^((?:0|(?:[1-9]\d*)))\.((?:0|(?:[1-9]\d*)))\.((?:0|(?:[1-9]\d*)))(?:-([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?$/; -moduleFor('ember-metal/core/main', class extends AbstractTestCase { - ['@test Ember.VERSION is in alignment with SemVer v2.0.0'](assert) { - assert.ok(SEMVER_REGEX.test(Ember.VERSION), `Ember.VERSION (${Ember.VERSION})is valid SemVer v2.0.0`); - } - - ['@test SEMVER_REGEX properly validates and invalidates version numbers'](assert) { - function validateVersionString(versionString, expectedResult) { - assert.equal(SEMVER_REGEX.test(versionString), expectedResult); +moduleFor( + 'ember-metal/core/main', + class extends AbstractTestCase { + ['@test Ember.VERSION is in alignment with SemVer v2.0.0'](assert) { + assert.ok( + SEMVER_REGEX.test(Ember.VERSION), + `Ember.VERSION (${Ember.VERSION})is valid SemVer v2.0.0` + ); } - // Positive test cases - validateVersionString('1.11.3', true); - validateVersionString('1.0.0-beta.16.1', true); - validateVersionString('1.12.1+canary.aba1412', true); - validateVersionString('2.0.0-beta.1+canary.bb344775', true); - validateVersionString('3.1.0-foobarBaz+30d70bd3', true); + ['@test SEMVER_REGEX properly validates and invalidates version numbers']( + assert + ) { + function validateVersionString(versionString, expectedResult) { + assert.equal(SEMVER_REGEX.test(versionString), expectedResult); + } - // Negative test cases - validateVersionString('1.11.3.aba18a', false); - validateVersionString('1.11', false); - } -}); + // Positive test cases + validateVersionString('1.11.3', true); + validateVersionString('1.0.0-beta.16.1', true); + validateVersionString('1.12.1+canary.aba1412', true); + validateVersionString('2.0.0-beta.1+canary.bb344775', true); + validateVersionString('3.1.0-foobarBaz+30d70bd3', true); + // Negative test cases + validateVersionString('1.11.3.aba18a', false); + validateVersionString('1.11', false); + } + } +); diff --git a/packages/ember-metal/tests/map_test.js b/packages/ember-metal/tests/map_test.js index ad6ae14253c..b286e3908b5 100644 --- a/packages/ember-metal/tests/map_test.js +++ b/packages/ember-metal/tests/map_test.js @@ -1,8 +1,4 @@ -import { - Map, - MapWithDefault, - OrderedSet -} from '..'; +import { Map, MapWithDefault, OrderedSet } from '..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; let object, number, string, map, variety; @@ -11,410 +7,477 @@ const varieties = [['Map', Map], ['MapWithDefault', MapWithDefault]]; function testMap(nameAndFunc) { variety = nameAndFunc[0]; - moduleFor('Ember.' + variety + ' (forEach and get are implicitly tested)', class extends AbstractTestCase { - beforeEach() { - object = {}; - number = 42; - string = 'foo'; - - map = nameAndFunc[1].create(); - } - - ['@test set'](assert) { - map.set(object, 'winning'); - map.set(number, 'winning'); - map.set(string, 'winning'); - - mapHasEntries(assert, [ - [object, 'winning'], - [number, 'winning'], - [string, 'winning'] - ]); - - map.set(object, 'losing'); - map.set(number, 'losing'); - map.set(string, 'losing'); - - mapHasEntries(assert, [ - [object, 'losing'], - [number, 'losing'], - [string, 'losing'] - ]); - - assert.equal(map.has('nope'), false, 'expected the key `nope` to not be present'); - assert.equal(map.has({}), false, 'expected they key `{}` to not be present'); - } - - ['@test set chaining'](assert) { - map.set(object, 'winning'). - set(number, 'winning'). - set(string, 'winning'); - - mapHasEntries(assert, [ - [object, 'winning'], - [number, 'winning'], - [string, 'winning'] - ]); - - map.set(object, 'losing'). - set(number, 'losing'). - set(string, 'losing'); - - mapHasEntries(assert, [ - [object, 'losing'], - [number, 'losing'], - [string, 'losing'] - ]); - - assert.equal(map.has('nope'), false, 'expected the key `nope` to not be present'); - assert.equal(map.has({}), false, 'expected they key `{}` to not be present'); - } - - ['@test with key with undefined value'](assert) { - map.set('foo', undefined); - - map.forEach(function(value, key) { - assert.equal(value, undefined); - assert.equal(key, 'foo'); - }); - - assert.ok(map.has('foo'), 'has key foo, even with undefined value'); + moduleFor( + 'Ember.' + variety + ' (forEach and get are implicitly tested)', + class extends AbstractTestCase { + beforeEach() { + object = {}; + number = 42; + string = 'foo'; - assert.equal(map.size, 1); - } - - ['@test arity of forEach is 1 – es6 23.1.3.5'](assert) { - assert.equal(map.forEach.length, 1, 'expected arity for map.forEach is 1'); - } - - ['@test forEach throws without a callback as the first argument'](assert) { - assert.equal(map.forEach.length, 1, 'expected arity for map.forEach is 1'); - } - - ['@test has empty collection'](assert) { - assert.equal(map.has('foo'), false); - assert.equal(map.has(), false); - } - - ['@test delete'](assert) { - expectNoDeprecation(); - - map.set(object, 'winning'); - map.set(number, 'winning'); - map.set(string, 'winning'); - - map.delete(object); - map.delete(number); - map.delete(string); - - // doesn't explode - map.delete({}); - - mapHasEntries(assert, []); - } - - ['@test copy and then update'](assert) { - map.set(object, 'winning'); - map.set(number, 'winning'); - map.set(string, 'winning'); - - let map2 = map.copy(); - - map2.set(object, 'losing'); - map2.set(number, 'losing'); - map2.set(string, 'losing'); - - mapHasEntries(assert, [ - [object, 'winning'], - [number, 'winning'], - [string, 'winning'] - ]); - - mapHasEntries(assert, [ - [object, 'losing'], - [number, 'losing'], - [string, 'losing'] - ], map2); - } - - ['@test copy and then delete'](assert) { - map.set(object, 'winning'); - map.set(number, 'winning'); - map.set(string, 'winning'); - - let map2 = map.copy(); - - map2.delete(object); - map2.delete(number); - map2.delete(string); - - mapHasEntries(assert, [ - [object, 'winning'], - [number, 'winning'], - [string, 'winning'] - ]); - - mapHasEntries(assert, [], map2); - } - - ['@test size'](assert) { - //Add a key twice - assert.equal(map.size, 0); - map.set(string, 'a string'); - assert.equal(map.size, 1); - map.set(string, 'the same string'); - assert.equal(map.size, 1); - - //Add another - map.set(number, 'a number'); - assert.equal(map.size, 2); - - //Remove one that doesn't exist - map.delete('does not exist'); - assert.equal(map.size, 2); - - //Check copy - let copy = map.copy(); - assert.equal(copy.size, 2); - - //Remove a key twice - map.delete(number); - assert.equal(map.size, 1); - map.delete(number); - assert.equal(map.size, 1); - - //Remove the last key - map.delete(string); - assert.equal(map.size, 0); - map.delete(string); - assert.equal(map.size, 0); - } - - ['@test forEach without proper callback'](assert) { - expectAssertion(function() { - map.forEach(); - }, '[object Undefined] is not a function'); - - expectAssertion(function() { - map.forEach(undefined); - }, '[object Undefined] is not a function'); - - expectAssertion(function() { - map.forEach(1); - }, '[object Number] is not a function'); + map = nameAndFunc[1].create(); + } - expectAssertion(function() { - map.forEach({}); - }, '[object Object] is not a function'); + ['@test set'](assert) { + map.set(object, 'winning'); + map.set(number, 'winning'); + map.set(string, 'winning'); + + mapHasEntries(assert, [ + [object, 'winning'], + [number, 'winning'], + [string, 'winning'] + ]); + + map.set(object, 'losing'); + map.set(number, 'losing'); + map.set(string, 'losing'); + + mapHasEntries(assert, [ + [object, 'losing'], + [number, 'losing'], + [string, 'losing'] + ]); + + assert.equal( + map.has('nope'), + false, + 'expected the key `nope` to not be present' + ); + assert.equal( + map.has({}), + false, + 'expected they key `{}` to not be present' + ); + } - map.forEach(function(value, key) { - map.delete(key); - }); - // ensure the error happens even if no data is present - assert.equal(map.size, 0); - expectAssertion(function() { - map.forEach({}); - }, '[object Object] is not a function'); - } + ['@test set chaining'](assert) { + map + .set(object, 'winning') + .set(number, 'winning') + .set(string, 'winning'); + + mapHasEntries(assert, [ + [object, 'winning'], + [number, 'winning'], + [string, 'winning'] + ]); + + map + .set(object, 'losing') + .set(number, 'losing') + .set(string, 'losing'); + + mapHasEntries(assert, [ + [object, 'losing'], + [number, 'losing'], + [string, 'losing'] + ]); + + assert.equal( + map.has('nope'), + false, + 'expected the key `nope` to not be present' + ); + assert.equal( + map.has({}), + false, + 'expected they key `{}` to not be present' + ); + } - ['@test forEach basic'](assert) { - map.set('a', 1); - map.set('b', 2); - map.set('c', 3); + ['@test with key with undefined value'](assert) { + map.set('foo', undefined); - let iteration = 0; + map.forEach(function(value, key) { + assert.equal(value, undefined); + assert.equal(key, 'foo'); + }); - let expectations = [ - { value: 1, key: 'a', context: unboundThis }, - { value: 2, key: 'b', context: unboundThis }, - { value: 3, key: 'c', context: unboundThis } - ]; + assert.ok(map.has('foo'), 'has key foo, even with undefined value'); - map.forEach(function(value, key, theMap) { - let expectation = expectations[iteration]; + assert.equal(map.size, 1); + } - assert.equal(value, expectation.value, 'value should be correct'); - assert.equal(key, expectation.key, 'key should be correct'); - assert.equal(this, expectation.context, 'context should be as if it was unbound'); - assert.equal(map, theMap, 'map being iterated over should be passed in'); + ['@test arity of forEach is 1 – es6 23.1.3.5'](assert) { + assert.equal( + map.forEach.length, + 1, + 'expected arity for map.forEach is 1' + ); + } - iteration++; - }); + ['@test forEach throws without a callback as the first argument']( + assert + ) { + assert.equal( + map.forEach.length, + 1, + 'expected arity for map.forEach is 1' + ); + } - assert.equal(iteration, 3, 'expected 3 iterations'); - } + ['@test has empty collection'](assert) { + assert.equal(map.has('foo'), false); + assert.equal(map.has(), false); + } - ['@test forEach basic /w context'](assert) { - map.set('a', 1); - map.set('b', 2); - map.set('c', 3); + ['@test delete'](assert) { + expectNoDeprecation(); - let iteration = 0; - let context = {}; - let expectations = [ - { value: 1, key: 'a', context: context }, - { value: 2, key: 'b', context: context }, - { value: 3, key: 'c', context: context } - ]; + map.set(object, 'winning'); + map.set(number, 'winning'); + map.set(string, 'winning'); - map.forEach(function(value, key, theMap) { - let expectation = expectations[iteration]; + map.delete(object); + map.delete(number); + map.delete(string); - assert.equal(value, expectation.value, 'value should be correct'); - assert.equal(key, expectation.key, 'key should be correct'); - assert.equal(this, expectation.context, 'context should be as if it was unbound'); - assert.equal(map, theMap, 'map being iterated over should be passed in'); + // doesn't explode + map.delete({}); - iteration++; - }, context); + mapHasEntries(assert, []); + } - assert.equal(iteration, 3, 'expected 3 iterations'); - } + ['@test copy and then update'](assert) { + map.set(object, 'winning'); + map.set(number, 'winning'); + map.set(string, 'winning'); - ['@test forEach basic /w deletion while enumerating'](assert) { - map.set('a', 1); - map.set('b', 2); - map.set('c', 3); + let map2 = map.copy(); - let iteration = 0; + map2.set(object, 'losing'); + map2.set(number, 'losing'); + map2.set(string, 'losing'); - let expectations = [ - { value: 1, key: 'a', context: unboundThis }, - { value: 2, key: 'b', context: unboundThis } - ]; + mapHasEntries(assert, [ + [object, 'winning'], + [number, 'winning'], + [string, 'winning'] + ]); - map.forEach(function(value, key, theMap) { - if (iteration === 0) { - map.delete('c'); + mapHasEntries( + assert, + [[object, 'losing'], [number, 'losing'], [string, 'losing']], + map2 + ); } - let expectation = expectations[iteration]; + ['@test copy and then delete'](assert) { + map.set(object, 'winning'); + map.set(number, 'winning'); + map.set(string, 'winning'); - assert.equal(value, expectation.value, 'value should be correct'); - assert.equal(key, expectation.key, 'key should be correct'); - assert.equal(this, expectation.context, 'context should be as if it was unbound'); - assert.equal(map, theMap, 'map being iterated over should be passed in'); + let map2 = map.copy(); - iteration++; - }); - - assert.equal(iteration, 2, 'expected 3 iterations'); - } + map2.delete(object); + map2.delete(number); + map2.delete(string); - ['@test forEach basic /w addition while enumerating'](assert) { - map.set('a', 1); - map.set('b', 2); - map.set('c', 3); + mapHasEntries(assert, [ + [object, 'winning'], + [number, 'winning'], + [string, 'winning'] + ]); - let iteration = 0; + mapHasEntries(assert, [], map2); + } - let expectations = [ - { value: 1, key: 'a', context: unboundThis }, - { value: 2, key: 'b', context: unboundThis }, - { value: 3, key: 'c', context: unboundThis }, - { value: 4, key: 'd', context: unboundThis } - ]; + ['@test size'](assert) { + //Add a key twice + assert.equal(map.size, 0); + map.set(string, 'a string'); + assert.equal(map.size, 1); + map.set(string, 'the same string'); + assert.equal(map.size, 1); + + //Add another + map.set(number, 'a number'); + assert.equal(map.size, 2); + + //Remove one that doesn't exist + map.delete('does not exist'); + assert.equal(map.size, 2); + + //Check copy + let copy = map.copy(); + assert.equal(copy.size, 2); + + //Remove a key twice + map.delete(number); + assert.equal(map.size, 1); + map.delete(number); + assert.equal(map.size, 1); + + //Remove the last key + map.delete(string); + assert.equal(map.size, 0); + map.delete(string); + assert.equal(map.size, 0); + } - map.forEach(function(value, key, theMap) { - if (iteration === 0) { - map.set('d', 4); + ['@test forEach without proper callback'](assert) { + expectAssertion(function() { + map.forEach(); + }, '[object Undefined] is not a function'); + + expectAssertion(function() { + map.forEach(undefined); + }, '[object Undefined] is not a function'); + + expectAssertion(function() { + map.forEach(1); + }, '[object Number] is not a function'); + + expectAssertion(function() { + map.forEach({}); + }, '[object Object] is not a function'); + + map.forEach(function(value, key) { + map.delete(key); + }); + // ensure the error happens even if no data is present + assert.equal(map.size, 0); + expectAssertion(function() { + map.forEach({}); + }, '[object Object] is not a function'); } - let expectation = expectations[iteration]; + ['@test forEach basic'](assert) { + map.set('a', 1); + map.set('b', 2); + map.set('c', 3); + + let iteration = 0; + + let expectations = [ + { value: 1, key: 'a', context: unboundThis }, + { value: 2, key: 'b', context: unboundThis }, + { value: 3, key: 'c', context: unboundThis } + ]; + + map.forEach(function(value, key, theMap) { + let expectation = expectations[iteration]; + + assert.equal(value, expectation.value, 'value should be correct'); + assert.equal(key, expectation.key, 'key should be correct'); + assert.equal( + this, + expectation.context, + 'context should be as if it was unbound' + ); + assert.equal( + map, + theMap, + 'map being iterated over should be passed in' + ); + + iteration++; + }); + + assert.equal(iteration, 3, 'expected 3 iterations'); + } - assert.equal(value, expectation.value, 'value should be correct'); - assert.equal(key, expectation.key, 'key should be correct'); - assert.equal(this, expectation.context, 'context should be as if it was unbound'); - assert.equal(map, theMap, 'map being iterated over should be passed in'); + ['@test forEach basic /w context'](assert) { + map.set('a', 1); + map.set('b', 2); + map.set('c', 3); + + let iteration = 0; + let context = {}; + let expectations = [ + { value: 1, key: 'a', context: context }, + { value: 2, key: 'b', context: context }, + { value: 3, key: 'c', context: context } + ]; + + map.forEach(function(value, key, theMap) { + let expectation = expectations[iteration]; + + assert.equal(value, expectation.value, 'value should be correct'); + assert.equal(key, expectation.key, 'key should be correct'); + assert.equal( + this, + expectation.context, + 'context should be as if it was unbound' + ); + assert.equal( + map, + theMap, + 'map being iterated over should be passed in' + ); + + iteration++; + }, context); + + assert.equal(iteration, 3, 'expected 3 iterations'); + } - iteration++; - }); + ['@test forEach basic /w deletion while enumerating'](assert) { + map.set('a', 1); + map.set('b', 2); + map.set('c', 3); + + let iteration = 0; + + let expectations = [ + { value: 1, key: 'a', context: unboundThis }, + { value: 2, key: 'b', context: unboundThis } + ]; + + map.forEach(function(value, key, theMap) { + if (iteration === 0) { + map.delete('c'); + } + + let expectation = expectations[iteration]; + + assert.equal(value, expectation.value, 'value should be correct'); + assert.equal(key, expectation.key, 'key should be correct'); + assert.equal( + this, + expectation.context, + 'context should be as if it was unbound' + ); + assert.equal( + map, + theMap, + 'map being iterated over should be passed in' + ); + + iteration++; + }); + + assert.equal(iteration, 2, 'expected 3 iterations'); + } - assert.equal(iteration, 4, 'expected 3 iterations'); - } + ['@test forEach basic /w addition while enumerating'](assert) { + map.set('a', 1); + map.set('b', 2); + map.set('c', 3); + + let iteration = 0; + + let expectations = [ + { value: 1, key: 'a', context: unboundThis }, + { value: 2, key: 'b', context: unboundThis }, + { value: 3, key: 'c', context: unboundThis }, + { value: 4, key: 'd', context: unboundThis } + ]; + + map.forEach(function(value, key, theMap) { + if (iteration === 0) { + map.set('d', 4); + } + + let expectation = expectations[iteration]; + + assert.equal(value, expectation.value, 'value should be correct'); + assert.equal(key, expectation.key, 'key should be correct'); + assert.equal( + this, + expectation.context, + 'context should be as if it was unbound' + ); + assert.equal( + map, + theMap, + 'map being iterated over should be passed in' + ); + + iteration++; + }); + + assert.equal(iteration, 4, 'expected 3 iterations'); + } - ['@test clear'](assert) { - let iterations = 0; + ['@test clear'](assert) { + let iterations = 0; - map.set('a', 1); - map.set('b', 2); - map.set('c', 3); - map.set('d', 4); + map.set('a', 1); + map.set('b', 2); + map.set('c', 3); + map.set('d', 4); - assert.equal(map.size, 4); + assert.equal(map.size, 4); - map.forEach(function() { - iterations++; - }); - assert.equal(iterations, 4); + map.forEach(function() { + iterations++; + }); + assert.equal(iterations, 4); - map.clear(); - assert.equal(map.size, 0); - iterations = 0; - map.forEach(function() { - iterations++; - }); - assert.equal(iterations, 0); - } + map.clear(); + assert.equal(map.size, 0); + iterations = 0; + map.forEach(function() { + iterations++; + }); + assert.equal(iterations, 0); + } - ['@skip -0'](assert) { - assert.equal(map.has(-0), false); - assert.equal(map.has(0), false); + ['@skip -0'](assert) { + assert.equal(map.has(-0), false); + assert.equal(map.has(0), false); - map.set(-0, 'zero'); + map.set(-0, 'zero'); - assert.equal(map.has(-0), true); - assert.equal(map.has(0), true); + assert.equal(map.has(-0), true); + assert.equal(map.has(0), true); - assert.equal(map.get(0), 'zero'); - assert.equal(map.get(-0), 'zero'); + assert.equal(map.get(0), 'zero'); + assert.equal(map.get(-0), 'zero'); - map.forEach(function(value, key) { - assert.equal(1 / key, Infinity, 'spec says key should be positive zero'); - }); - } + map.forEach(function(value, key) { + assert.equal( + 1 / key, + Infinity, + 'spec says key should be positive zero' + ); + }); + } - ['@test NaN'](assert) { - assert.equal(map.has(NaN), false); + ['@test NaN'](assert) { + assert.equal(map.has(NaN), false); - map.set(NaN, 'not-a-number'); + map.set(NaN, 'not-a-number'); - assert.equal(map.has(NaN), true); + assert.equal(map.has(NaN), true); - assert.equal(map.get(NaN), 'not-a-number'); - } + assert.equal(map.get(NaN), 'not-a-number'); + } - ['@test NaN Boxed'](assert) { - //jshint -W053 - let boxed = new Number(NaN); - assert.equal(map.has(boxed), false); + ['@test NaN Boxed'](assert) { + //jshint -W053 + let boxed = new Number(NaN); + assert.equal(map.has(boxed), false); - map.set(boxed, 'not-a-number'); + map.set(boxed, 'not-a-number'); - assert.equal(map.has(boxed), true); - assert.equal(map.has(NaN), false); + assert.equal(map.has(boxed), true); + assert.equal(map.has(NaN), false); - assert.equal(map.get(NaN), undefined); - assert.equal(map.get(boxed), 'not-a-number'); - } + assert.equal(map.get(NaN), undefined); + assert.equal(map.get(boxed), 'not-a-number'); + } - ['@test 0 value'](assert) { - let obj = {}; - assert.equal(map.has(obj), false); + ['@test 0 value'](assert) { + let obj = {}; + assert.equal(map.has(obj), false); - assert.equal(map.size, 0); - map.set(obj, 0); - assert.equal(map.size, 1); + assert.equal(map.size, 0); + map.set(obj, 0); + assert.equal(map.size, 1); - assert.equal(map.has(obj), true); - assert.equal(map.get(obj), 0); + assert.equal(map.has(obj), true); + assert.equal(map.get(obj), 0); - map.delete(obj); - assert.equal(map.has(obj), false); - assert.equal(map.get(obj), undefined); - assert.equal(map.size, 0); - } - }); + map.delete(obj); + assert.equal(map.has(obj), false); + assert.equal(map.get(obj), undefined); + assert.equal(map.size, 0); + } + } + ); let mapHasLength = function(assert, expected, theMap) { theMap = theMap || map; @@ -442,80 +505,89 @@ function testMap(nameAndFunc) { (function() { unboundThis = this; - }()); + })(); } -for (let i = 0; i < varieties.length; i++) { +for (let i = 0; i < varieties.length; i++) { testMap(varieties[i]); } -moduleFor('MapWithDefault - default values', class extends AbstractTestCase { - ['@test Retrieving a value that has not been set returns and sets a default value'](assert) { - let map = MapWithDefault.create({ - defaultValue(key) { - return [key]; - } - }); - - let value = map.get('ohai'); - assert.deepEqual(value, ['ohai']); - - assert.strictEqual(value, map.get('ohai')); - } +moduleFor( + 'MapWithDefault - default values', + class extends AbstractTestCase { + ['@test Retrieving a value that has not been set returns and sets a default value']( + assert + ) { + let map = MapWithDefault.create({ + defaultValue(key) { + return [key]; + } + }); + + let value = map.get('ohai'); + assert.deepEqual(value, ['ohai']); + + assert.strictEqual(value, map.get('ohai')); + } - ['@test Map.prototype.constructor'](assert) { - let map = new Map(); - assert.equal(map.constructor, Map); - } + ['@test Map.prototype.constructor'](assert) { + let map = new Map(); + assert.equal(map.constructor, Map); + } - ['@test MapWithDefault.prototype.constructor'](assert) { - let map = new MapWithDefault({ - defaultValue(key) { return key; } - }); - assert.equal(map.constructor, MapWithDefault); - } + ['@test MapWithDefault.prototype.constructor'](assert) { + let map = new MapWithDefault({ + defaultValue(key) { + return key; + } + }); + assert.equal(map.constructor, MapWithDefault); + } - ['@test Copying a MapWithDefault copies the default value'](assert) { - let map = MapWithDefault.create({ - defaultValue(key) { - return [key]; - } - }); + ['@test Copying a MapWithDefault copies the default value'](assert) { + let map = MapWithDefault.create({ + defaultValue(key) { + return [key]; + } + }); - map.set('ohai', 1); - map.get('bai'); + map.set('ohai', 1); + map.get('bai'); - let map2 = map.copy(); + let map2 = map.copy(); - assert.equal(map2.get('ohai'), 1); - assert.deepEqual(map2.get('bai'), ['bai']); + assert.equal(map2.get('ohai'), 1); + assert.deepEqual(map2.get('bai'), ['bai']); - map2.set('kthx', 3); + map2.set('kthx', 3); - assert.deepEqual(map.get('kthx'), ['kthx']); - assert.equal(map2.get('kthx'), 3); + assert.deepEqual(map.get('kthx'), ['kthx']); + assert.equal(map2.get('kthx'), 3); - assert.deepEqual(map2.get('default'), ['default']); + assert.deepEqual(map2.get('default'), ['default']); - map2.defaultValue = key => ['tom is on', key]; + map2.defaultValue = key => ['tom is on', key]; - assert.deepEqual(map2.get('drugs'), ['tom is on', 'drugs']); + assert.deepEqual(map2.get('drugs'), ['tom is on', 'drugs']); + } } -}); +); -moduleFor('OrderedSet', class extends AbstractTestCase { - beforeEach() { - object = {}; - number = 42; - string = 'foo'; +moduleFor( + 'OrderedSet', + class extends AbstractTestCase { + beforeEach() { + object = {}; + number = 42; + string = 'foo'; - map = OrderedSet.create(); - } + map = OrderedSet.create(); + } - ['@test add returns the set'](assert) { - let obj = {}; - assert.equal(map.add(obj), map); - assert.equal(map.add(obj), map, 'when it is already in the set'); + ['@test add returns the set'](assert) { + let obj = {}; + assert.equal(map.add(obj), map); + assert.equal(map.add(obj), map, 'when it is already in the set'); + } } -}); - +); diff --git a/packages/ember-metal/tests/meta_test.js b/packages/ember-metal/tests/meta_test.js index 65ac0d9d877..3be53f40c70 100644 --- a/packages/ember-metal/tests/meta_test.js +++ b/packages/ember-metal/tests/meta_test.js @@ -1,155 +1,173 @@ import { meta } from '..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('Ember.meta', class extends AbstractTestCase { - ['@test should return the same hash for an object'](assert) { - let obj = {}; - - meta(obj).foo = 'bar'; - - assert.equal(meta(obj).foo, 'bar', 'returns same hash with multiple calls to Ember.meta()'); - } - - ['@test meta is not enumerable'](assert) { - let proto, obj, props, prop; - proto = { foo: 'bar' }; - meta(proto); - obj = Object.create(proto); - meta(obj); - obj.bar = 'baz'; - props = []; - for (prop in obj) { - props.push(prop); +moduleFor( + 'Ember.meta', + class extends AbstractTestCase { + ['@test should return the same hash for an object'](assert) { + let obj = {}; + + meta(obj).foo = 'bar'; + + assert.equal( + meta(obj).foo, + 'bar', + 'returns same hash with multiple calls to Ember.meta()' + ); } - assert.deepEqual(props.sort(), ['bar', 'foo']); - if (typeof JSON !== 'undefined' && 'stringify' in JSON) { - try { - JSON.stringify(obj); - } catch (e) { - assert.ok(false, 'meta should not fail JSON.stringify'); + + ['@test meta is not enumerable'](assert) { + let proto, obj, props, prop; + proto = { foo: 'bar' }; + meta(proto); + obj = Object.create(proto); + meta(obj); + obj.bar = 'baz'; + props = []; + for (prop in obj) { + props.push(prop); + } + assert.deepEqual(props.sort(), ['bar', 'foo']); + if (typeof JSON !== 'undefined' && 'stringify' in JSON) { + try { + JSON.stringify(obj); + } catch (e) { + assert.ok(false, 'meta should not fail JSON.stringify'); + } } } - } - ['@test meta.listeners basics'](assert) { - let t = {}; - let m = meta({}); - m.addToListeners('hello', t, 'm', 0); - let matching = m.matchingListeners('hello'); - assert.equal(matching.length, 3); - assert.equal(matching[0], t); - m.removeFromListeners('hello', t, 'm'); - matching = m.matchingListeners('hello'); - assert.equal(matching, undefined); - } + ['@test meta.listeners basics'](assert) { + let t = {}; + let m = meta({}); + m.addToListeners('hello', t, 'm', 0); + let matching = m.matchingListeners('hello'); + assert.equal(matching.length, 3); + assert.equal(matching[0], t); + m.removeFromListeners('hello', t, 'm'); + matching = m.matchingListeners('hello'); + assert.equal(matching, undefined); + } - ['@test meta.listeners inheritance'](assert) { - let target = {}; - let parent = {}; - let parentMeta = meta(parent); - parentMeta.addToListeners('hello', target, 'm', 0); - - let child = Object.create(parent); - let m = meta(child); - - let matching = m.matchingListeners('hello'); - assert.equal(matching.length, 3); - assert.equal(matching[0], target); - assert.equal(matching[1], 'm'); - assert.equal(matching[2], 0); - m.removeFromListeners('hello', target, 'm'); - matching = m.matchingListeners('hello'); - assert.equal(matching, undefined); - matching = parentMeta.matchingListeners('hello'); - assert.equal(matching.length, 3); - } + ['@test meta.listeners inheritance'](assert) { + let target = {}; + let parent = {}; + let parentMeta = meta(parent); + parentMeta.addToListeners('hello', target, 'm', 0); + + let child = Object.create(parent); + let m = meta(child); + + let matching = m.matchingListeners('hello'); + assert.equal(matching.length, 3); + assert.equal(matching[0], target); + assert.equal(matching[1], 'm'); + assert.equal(matching[2], 0); + m.removeFromListeners('hello', target, 'm'); + matching = m.matchingListeners('hello'); + assert.equal(matching, undefined); + matching = parentMeta.matchingListeners('hello'); + assert.equal(matching.length, 3); + } - ['@test meta.listeners deduplication'](assert) { - let t = {}; - let m = meta({}); - m.addToListeners('hello', t, 'm', 0); - m.addToListeners('hello', t, 'm', 0); - let matching = m.matchingListeners('hello'); - assert.equal(matching.length, 3); - assert.equal(matching[0], t); - } + ['@test meta.listeners deduplication'](assert) { + let t = {}; + let m = meta({}); + m.addToListeners('hello', t, 'm', 0); + m.addToListeners('hello', t, 'm', 0); + let matching = m.matchingListeners('hello'); + assert.equal(matching.length, 3); + assert.equal(matching[0], t); + } - ['@test meta.writeWatching issues useful error after destroy']() { - let target = { - toString() { return ''; } - }; - let targetMeta = meta(target); + ['@test meta.writeWatching issues useful error after destroy']() { + let target = { + toString() { + return ''; + } + }; + let targetMeta = meta(target); - targetMeta.destroy(); + targetMeta.destroy(); - expectAssertion(() => { - targetMeta.writeWatching('hello', 1); - }, 'Cannot update watchers for `hello` on `` after it has been destroyed.'); - } + expectAssertion(() => { + targetMeta.writeWatching('hello', 1); + }, 'Cannot update watchers for `hello` on `` after it has been destroyed.'); + } - ['@test meta.writableTag issues useful error after destroy']() { - let target = { - toString() { return ''; } - }; - let targetMeta = meta(target); + ['@test meta.writableTag issues useful error after destroy']() { + let target = { + toString() { + return ''; + } + }; + let targetMeta = meta(target); - targetMeta.destroy(); + targetMeta.destroy(); - expectAssertion(() => { - targetMeta.writableTag(() => {}); - }, 'Cannot create a new tag for `` after it has been destroyed.'); - } + expectAssertion(() => { + targetMeta.writableTag(() => {}); + }, 'Cannot create a new tag for `` after it has been destroyed.'); + } - ['@test meta.writableChainWatchers issues useful error after destroy']() { - let target = { - toString() { return ''; } - }; - let targetMeta = meta(target); + ['@test meta.writableChainWatchers issues useful error after destroy']() { + let target = { + toString() { + return ''; + } + }; + let targetMeta = meta(target); - targetMeta.destroy(); + targetMeta.destroy(); - expectAssertion(() => { - targetMeta.writableChainWatchers(() => {}); - }, 'Cannot create a new chain watcher for `` after it has been destroyed.'); - } + expectAssertion(() => { + targetMeta.writableChainWatchers(() => {}); + }, 'Cannot create a new chain watcher for `` after it has been destroyed.'); + } - ['@test meta.writableChains issues useful error after destroy']() { - let target = { - toString() { return ''; } - }; - let targetMeta = meta(target); + ['@test meta.writableChains issues useful error after destroy']() { + let target = { + toString() { + return ''; + } + }; + let targetMeta = meta(target); - targetMeta.destroy(); + targetMeta.destroy(); - expectAssertion(() => { - targetMeta.writableChains(() => {}); - }, 'Cannot create a new chains for `` after it has been destroyed.'); - } + expectAssertion(() => { + targetMeta.writableChains(() => {}); + }, 'Cannot create a new chains for `` after it has been destroyed.'); + } - ['@test meta.writeValues issues useful error after destroy']() { - let target = { - toString() { return ''; } - }; - let targetMeta = meta(target); + ['@test meta.writeValues issues useful error after destroy']() { + let target = { + toString() { + return ''; + } + }; + let targetMeta = meta(target); - targetMeta.destroy(); + targetMeta.destroy(); - expectAssertion(() => { - targetMeta.writeValues('derp', 'ohai'); - }, 'Cannot set the value of `derp` on `` after it has been destroyed.'); - } + expectAssertion(() => { + targetMeta.writeValues('derp', 'ohai'); + }, 'Cannot set the value of `derp` on `` after it has been destroyed.'); + } - ['@test meta.writeDeps issues useful error after destroy']() { - let target = { - toString() { return ''; } - }; - let targetMeta = meta(target); + ['@test meta.writeDeps issues useful error after destroy']() { + let target = { + toString() { + return ''; + } + }; + let targetMeta = meta(target); - targetMeta.destroy(); + targetMeta.destroy(); - expectAssertion(() => { - targetMeta.writeDeps('derp', 'ohai', 1); - }, 'Cannot modify dependent keys for `ohai` on `` after it has been destroyed.'); + expectAssertion(() => { + targetMeta.writeDeps('derp', 'ohai', 1); + }, 'Cannot modify dependent keys for `ohai` on `` after it has been destroyed.'); + } } -}); - +); diff --git a/packages/ember-metal/tests/mixin/alias_method_test.js b/packages/ember-metal/tests/mixin/alias_method_test.js index 5bb59bda7e7..a58536cab85 100644 --- a/packages/ember-metal/tests/mixin/alias_method_test.js +++ b/packages/ember-metal/tests/mixin/alias_method_test.js @@ -1,9 +1,4 @@ -import { - get, - Mixin, - mixin, - aliasMethod -} from '../..'; +import { get, Mixin, mixin, aliasMethod } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; function validateAliasMethod(assert, obj) { @@ -11,72 +6,96 @@ function validateAliasMethod(assert, obj) { assert.equal(obj.barMethod(), 'FOO', 'obj.barMethod should be a copy of foo'); } -moduleFor('aliasMethod', class extends AbstractTestCase { - ['@test methods of another name are aliased when the mixin is applied'](assert) { - let MyMixin = Mixin.create({ - fooMethod() { return 'FOO'; }, - barMethod: aliasMethod('fooMethod') - }); - - let obj = MyMixin.apply({}); - validateAliasMethod(assert, obj); - } - - ['@test should follow aliasMethods all the way down'](assert) { - let MyMixin = Mixin.create({ - bar: aliasMethod('foo'), // put first to break ordered iteration - baz() { return 'baz'; }, - foo: aliasMethod('baz') - }); - - let obj = MyMixin.apply({}); - assert.equal(get(obj, 'bar')(), 'baz', 'should have followed aliasMethods'); - } - - ['@test should alias methods from other dependent mixins'](assert) { - let BaseMixin = Mixin.create({ - fooMethod() { return 'FOO'; } - }); - - let MyMixin = Mixin.create(BaseMixin, { - barMethod: aliasMethod('fooMethod') - }); - - let obj = MyMixin.apply({}); - validateAliasMethod(assert, obj); +moduleFor( + 'aliasMethod', + class extends AbstractTestCase { + ['@test methods of another name are aliased when the mixin is applied']( + assert + ) { + let MyMixin = Mixin.create({ + fooMethod() { + return 'FOO'; + }, + barMethod: aliasMethod('fooMethod') + }); + + let obj = MyMixin.apply({}); + validateAliasMethod(assert, obj); + } + + ['@test should follow aliasMethods all the way down'](assert) { + let MyMixin = Mixin.create({ + bar: aliasMethod('foo'), // put first to break ordered iteration + baz() { + return 'baz'; + }, + foo: aliasMethod('baz') + }); + + let obj = MyMixin.apply({}); + assert.equal( + get(obj, 'bar')(), + 'baz', + 'should have followed aliasMethods' + ); + } + + ['@test should alias methods from other dependent mixins'](assert) { + let BaseMixin = Mixin.create({ + fooMethod() { + return 'FOO'; + } + }); + + let MyMixin = Mixin.create(BaseMixin, { + barMethod: aliasMethod('fooMethod') + }); + + let obj = MyMixin.apply({}); + validateAliasMethod(assert, obj); + } + + ['@test should alias methods from other mixins applied at same time']( + assert + ) { + let BaseMixin = Mixin.create({ + fooMethod() { + return 'FOO'; + } + }); + + let MyMixin = Mixin.create({ + barMethod: aliasMethod('fooMethod') + }); + + let obj = mixin({}, BaseMixin, MyMixin); + validateAliasMethod(assert, obj); + } + + ['@test should alias methods from mixins already applied on object']( + assert + ) { + let BaseMixin = Mixin.create({ + quxMethod() { + return 'qux'; + } + }); + + let MyMixin = Mixin.create({ + bar: aliasMethod('foo'), + barMethod: aliasMethod('fooMethod') + }); + + let obj = { + fooMethod() { + return 'FOO'; + } + }; + + BaseMixin.apply(obj); + MyMixin.apply(obj); + + validateAliasMethod(assert, obj); + } } - - ['@test should alias methods from other mixins applied at same time'](assert) { - let BaseMixin = Mixin.create({ - fooMethod() { return 'FOO'; } - }); - - let MyMixin = Mixin.create({ - barMethod: aliasMethod('fooMethod') - }); - - let obj = mixin({}, BaseMixin, MyMixin); - validateAliasMethod(assert, obj); - } - - ['@test should alias methods from mixins already applied on object'](assert) { - let BaseMixin = Mixin.create({ - quxMethod() { return 'qux'; } - }); - - let MyMixin = Mixin.create({ - bar: aliasMethod('foo'), - barMethod: aliasMethod('fooMethod') - }); - - let obj = { - fooMethod() { return 'FOO'; } - }; - - BaseMixin.apply(obj); - MyMixin.apply(obj); - - validateAliasMethod(assert, obj); - } -}); - +); diff --git a/packages/ember-metal/tests/mixin/apply_test.js b/packages/ember-metal/tests/mixin/apply_test.js index 921d129009d..eb9e2b3df39 100644 --- a/packages/ember-metal/tests/mixin/apply_test.js +++ b/packages/ember-metal/tests/mixin/apply_test.js @@ -1,42 +1,40 @@ -import { - get, - Mixin, - mixin -} from '../..'; +import { get, Mixin, mixin } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; function K() {} -moduleFor('Mixin.apply', class extends AbstractTestCase { - ['@test using apply() should apply properties'](assert) { - let MixinA = Mixin.create({ foo: 'FOO', baz: K }); - let obj = {}; - mixin(obj, MixinA); - - assert.equal(get(obj, 'foo'), 'FOO', 'should apply foo'); - assert.equal(get(obj, 'baz'), K, 'should apply foo'); - } - - ['@test applying anonymous properties'](assert) { - let obj = {}; - mixin(obj, { - foo: 'FOO', - baz: K - }); - - assert.equal(get(obj, 'foo'), 'FOO', 'should apply foo'); - assert.equal(get(obj, 'baz'), K, 'should apply foo'); - } - - ['@test applying null values']() { - expectAssertion(() => mixin({}, null)); +moduleFor( + 'Mixin.apply', + class extends AbstractTestCase { + ['@test using apply() should apply properties'](assert) { + let MixinA = Mixin.create({ foo: 'FOO', baz: K }); + let obj = {}; + mixin(obj, MixinA); + + assert.equal(get(obj, 'foo'), 'FOO', 'should apply foo'); + assert.equal(get(obj, 'baz'), K, 'should apply foo'); + } + + ['@test applying anonymous properties'](assert) { + let obj = {}; + mixin(obj, { + foo: 'FOO', + baz: K + }); + + assert.equal(get(obj, 'foo'), 'FOO', 'should apply foo'); + assert.equal(get(obj, 'baz'), K, 'should apply foo'); + } + + ['@test applying null values']() { + expectAssertion(() => mixin({}, null)); + } + + ['@test applying a property with an undefined value'](assert) { + let obj = { tagName: '' }; + mixin(obj, { tagName: undefined }); + + assert.strictEqual(get(obj, 'tagName'), ''); + } } - - ['@test applying a property with an undefined value'](assert) { - let obj = { tagName: '' }; - mixin(obj, { tagName: undefined }); - - assert.strictEqual(get(obj, 'tagName'), ''); - } -}); - +); diff --git a/packages/ember-metal/tests/mixin/computed_test.js b/packages/ember-metal/tests/mixin/computed_test.js index 02e61ae85af..58def1ae39c 100644 --- a/packages/ember-metal/tests/mixin/computed_test.js +++ b/packages/ember-metal/tests/mixin/computed_test.js @@ -1,145 +1,178 @@ -import { - get, - set, - Mixin, - computed, - defineProperty -} from '../..'; +import { get, set, Mixin, computed, defineProperty } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -function K() { return this; } - -moduleFor('Mixin Computed Properties', class extends AbstractTestCase { - ['@test overriding computed properties'](assert) { - let MixinA, MixinB, MixinC, MixinD; - let obj; - - MixinA = Mixin.create({ - aProp: computed(function() { - return 'A'; - }) - }); - - MixinB = Mixin.create(MixinA, { - aProp: computed(function() { - return this._super(...arguments) + 'B'; - }) - }); - - MixinC = Mixin.create(MixinA, { - aProp: computed(function() { - return this._super(...arguments) + 'C'; - }) - }); - - MixinD = Mixin.create({ - aProp: computed(function() { - return this._super(...arguments) + 'D'; - }) - }); - - obj = {}; - MixinB.apply(obj); - assert.equal(get(obj, 'aProp'), 'AB', 'should expose super for B'); - - obj = {}; - MixinC.apply(obj); - assert.equal(get(obj, 'aProp'), 'AC', 'should expose super for C'); - - obj = {}; - - MixinA.apply(obj); - MixinD.apply(obj); - assert.equal(get(obj, 'aProp'), 'AD', 'should define super for D'); - - obj = { }; - defineProperty(obj, 'aProp', computed(function() { - return 'obj'; - })); - MixinD.apply(obj); - assert.equal(get(obj, 'aProp'), 'objD', 'should preserve original computed property'); +function K() { + return this; +} + +moduleFor( + 'Mixin Computed Properties', + class extends AbstractTestCase { + ['@test overriding computed properties'](assert) { + let MixinA, MixinB, MixinC, MixinD; + let obj; + + MixinA = Mixin.create({ + aProp: computed(function() { + return 'A'; + }) + }); + + MixinB = Mixin.create(MixinA, { + aProp: computed(function() { + return this._super(...arguments) + 'B'; + }) + }); + + MixinC = Mixin.create(MixinA, { + aProp: computed(function() { + return this._super(...arguments) + 'C'; + }) + }); + + MixinD = Mixin.create({ + aProp: computed(function() { + return this._super(...arguments) + 'D'; + }) + }); + + obj = {}; + MixinB.apply(obj); + assert.equal(get(obj, 'aProp'), 'AB', 'should expose super for B'); + + obj = {}; + MixinC.apply(obj); + assert.equal(get(obj, 'aProp'), 'AC', 'should expose super for C'); + + obj = {}; + + MixinA.apply(obj); + MixinD.apply(obj); + assert.equal(get(obj, 'aProp'), 'AD', 'should define super for D'); + + obj = {}; + defineProperty( + obj, + 'aProp', + computed(function() { + return 'obj'; + }) + ); + MixinD.apply(obj); + assert.equal( + get(obj, 'aProp'), + 'objD', + 'should preserve original computed property' + ); + } + + ['@test calling set on overridden computed properties'](assert) { + let SuperMixin, SubMixin; + let obj; + + let superGetOccurred = false; + let superSetOccurred = false; + + SuperMixin = Mixin.create({ + aProp: computed({ + get() { + superGetOccurred = true; + }, + set() { + superSetOccurred = true; + } + }) + }); + + SubMixin = Mixin.create(SuperMixin, { + aProp: computed({ + get() { + return this._super(...arguments); + }, + set() { + return this._super(...arguments); + } + }) + }); + + obj = {}; + SubMixin.apply(obj); + + set(obj, 'aProp', 'set thyself'); + assert.ok(superSetOccurred, 'should pass set to _super'); + + superSetOccurred = false; // reset the set assertion + + obj = {}; + SubMixin.apply(obj); + + get(obj, 'aProp'); + assert.ok(superGetOccurred, 'should pass get to _super'); + + set(obj, 'aProp', 'set thyself'); + assert.ok(superSetOccurred, 'should pass set to _super after getting'); + } + + ['@test setter behavior works properly when overriding computed properties']( + assert + ) { + let obj = {}; + + let MixinA = Mixin.create({ + cpWithSetter2: computed(K), + cpWithSetter3: computed(K), + cpWithoutSetter: computed(K) + }); + + let cpWasCalled = false; + + let MixinB = Mixin.create({ + cpWithSetter2: computed({ + get: K, + set() { + cpWasCalled = true; + } + }), + + cpWithSetter3: computed({ + get: K, + set() { + cpWasCalled = true; + } + }), + + cpWithoutSetter: computed(function() { + cpWasCalled = true; + }) + }); + + MixinA.apply(obj); + MixinB.apply(obj); + + set(obj, 'cpWithSetter2', 'test'); + assert.ok( + cpWasCalled, + 'The computed property setter was called when defined with two args' + ); + cpWasCalled = false; + + set(obj, 'cpWithSetter3', 'test'); + assert.ok( + cpWasCalled, + 'The computed property setter was called when defined with three args' + ); + cpWasCalled = false; + + set(obj, 'cpWithoutSetter', 'test'); + assert.equal( + get(obj, 'cpWithoutSetter'), + 'test', + 'The default setter was called, the value is correct' + ); + assert.ok( + !cpWasCalled, + 'The default setter was called, not the CP itself' + ); + } } - - ['@test calling set on overridden computed properties'](assert) { - let SuperMixin, SubMixin; - let obj; - - let superGetOccurred = false; - let superSetOccurred = false; - - SuperMixin = Mixin.create({ - aProp: computed({ - get() { superGetOccurred = true; }, - set() { superSetOccurred = true; } - }) - }); - - SubMixin = Mixin.create(SuperMixin, { - aProp: computed({ - get() { return this._super(...arguments); }, - set() { return this._super(...arguments); } - }) - }); - - obj = {}; - SubMixin.apply(obj); - - set(obj, 'aProp', 'set thyself'); - assert.ok(superSetOccurred, 'should pass set to _super'); - - superSetOccurred = false; // reset the set assertion - - obj = {}; - SubMixin.apply(obj); - - get(obj, 'aProp'); - assert.ok(superGetOccurred, 'should pass get to _super'); - - set(obj, 'aProp', 'set thyself'); - assert.ok(superSetOccurred, 'should pass set to _super after getting'); - } - - ['@test setter behavior works properly when overriding computed properties'](assert) { - let obj = {}; - - let MixinA = Mixin.create({ - cpWithSetter2: computed(K), - cpWithSetter3: computed(K), - cpWithoutSetter: computed(K) - }); - - let cpWasCalled = false; - - let MixinB = Mixin.create({ - cpWithSetter2: computed({ - get: K, - set() { cpWasCalled = true; } - }), - - cpWithSetter3: computed({ - get: K, - set() { cpWasCalled = true; } - }), - - cpWithoutSetter: computed(function() { - cpWasCalled = true; - }) - }); - - MixinA.apply(obj); - MixinB.apply(obj); - - set(obj, 'cpWithSetter2', 'test'); - assert.ok(cpWasCalled, 'The computed property setter was called when defined with two args'); - cpWasCalled = false; - - set(obj, 'cpWithSetter3', 'test'); - assert.ok(cpWasCalled, 'The computed property setter was called when defined with three args'); - cpWasCalled = false; - - set(obj, 'cpWithoutSetter', 'test'); - assert.equal(get(obj, 'cpWithoutSetter'), 'test', 'The default setter was called, the value is correct'); - assert.ok(!cpWasCalled, 'The default setter was called, not the CP itself'); - } -}); - +); diff --git a/packages/ember-metal/tests/mixin/concatenated_properties_test.js b/packages/ember-metal/tests/mixin/concatenated_properties_test.js index 9231043aed8..ef70f5106f7 100644 --- a/packages/ember-metal/tests/mixin/concatenated_properties_test.js +++ b/packages/ember-metal/tests/mixin/concatenated_properties_test.js @@ -1,110 +1,125 @@ -import { - Mixin, - mixin, - get -} from '../..'; +import { Mixin, mixin, get } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('Mixin concatenatedProperties', class extends AbstractTestCase { - ['@test defining concatenated properties should concat future version'](assert) { - let MixinA = Mixin.create({ - concatenatedProperties: ['foo'], - foo: ['a', 'b', 'c'] - }); - - let MixinB = Mixin.create({ - foo: ['d', 'e', 'f'] - }); - - let obj = mixin({}, MixinA, MixinB); - assert.deepEqual(get(obj, 'foo'), ['a', 'b', 'c', 'd', 'e', 'f']); - } - - ['@test defining concatenated properties should concat future version'](assert) { - let MixinA = Mixin.create({ - concatenatedProperties: null - }); - - let MixinB = Mixin.create({ - concatenatedProperties: null - }); - - let obj = mixin({}, MixinA, MixinB); - - assert.deepEqual(obj.concatenatedProperties, []); - } - - ['@test concatenatedProperties should be concatenated'](assert) { - let MixinA = Mixin.create({ - concatenatedProperties: ['foo'], - foo: ['a', 'b', 'c'] - }); - - let MixinB = Mixin.create({ - concatenatedProperties: 'bar', - foo: ['d', 'e', 'f'], - bar: [1, 2, 3] - }); - - let MixinC = Mixin.create({ - bar: [4, 5, 6] - }); - - let obj = mixin({}, MixinA, MixinB, MixinC); - assert.deepEqual(get(obj, 'concatenatedProperties'), ['foo', 'bar'], 'get concatenatedProperties'); - assert.deepEqual(get(obj, 'foo'), ['a', 'b', 'c', 'd', 'e', 'f'], 'get foo'); - assert.deepEqual(get(obj, 'bar'), [1, 2, 3, 4, 5, 6], 'get bar'); - } - - ['@test adding a prop that is not an array should make array'](assert) { - let MixinA = Mixin.create({ - concatenatedProperties: ['foo'], - foo: [1, 2, 3] - }); - - let MixinB = Mixin.create({ - foo: 4 - }); - - let obj = mixin({}, MixinA, MixinB); - assert.deepEqual(get(obj, 'foo'), [1, 2, 3, 4]); - } - - ['@test adding a prop that is not an array should make array'](assert) { - let MixinA = Mixin.create({ - concatenatedProperties: ['foo'], - foo: 'bar' - }); - - let obj = mixin({}, MixinA); - assert.deepEqual(get(obj, 'foo'), ['bar']); - } - - ['@test adding a non-concatenable property that already has a defined value should result in an array with both values'](assert) { - let mixinA = Mixin.create({ - foo: 1 - }); - - let mixinB = Mixin.create({ - concatenatedProperties: ['foo'], - foo: 2 - }); - - let obj = mixin({}, mixinA, mixinB); - assert.deepEqual(get(obj, 'foo'), [1, 2]); - } - - ['@test adding a concatenable property that already has a defined value should result in a concatenated value'](assert) { - let mixinA = Mixin.create({ - foobar: 'foo' - }); - - let mixinB = Mixin.create({ - concatenatedProperties: ['foobar'], - foobar: 'bar' - }); - - let obj = mixin({}, mixinA, mixinB); - assert.deepEqual(get(obj, 'foobar'), ['foo', 'bar']); +moduleFor( + 'Mixin concatenatedProperties', + class extends AbstractTestCase { + ['@test defining concatenated properties should concat future version']( + assert + ) { + let MixinA = Mixin.create({ + concatenatedProperties: ['foo'], + foo: ['a', 'b', 'c'] + }); + + let MixinB = Mixin.create({ + foo: ['d', 'e', 'f'] + }); + + let obj = mixin({}, MixinA, MixinB); + assert.deepEqual(get(obj, 'foo'), ['a', 'b', 'c', 'd', 'e', 'f']); + } + + ['@test defining concatenated properties should concat future version']( + assert + ) { + let MixinA = Mixin.create({ + concatenatedProperties: null + }); + + let MixinB = Mixin.create({ + concatenatedProperties: null + }); + + let obj = mixin({}, MixinA, MixinB); + + assert.deepEqual(obj.concatenatedProperties, []); + } + + ['@test concatenatedProperties should be concatenated'](assert) { + let MixinA = Mixin.create({ + concatenatedProperties: ['foo'], + foo: ['a', 'b', 'c'] + }); + + let MixinB = Mixin.create({ + concatenatedProperties: 'bar', + foo: ['d', 'e', 'f'], + bar: [1, 2, 3] + }); + + let MixinC = Mixin.create({ + bar: [4, 5, 6] + }); + + let obj = mixin({}, MixinA, MixinB, MixinC); + assert.deepEqual( + get(obj, 'concatenatedProperties'), + ['foo', 'bar'], + 'get concatenatedProperties' + ); + assert.deepEqual( + get(obj, 'foo'), + ['a', 'b', 'c', 'd', 'e', 'f'], + 'get foo' + ); + assert.deepEqual(get(obj, 'bar'), [1, 2, 3, 4, 5, 6], 'get bar'); + } + + ['@test adding a prop that is not an array should make array'](assert) { + let MixinA = Mixin.create({ + concatenatedProperties: ['foo'], + foo: [1, 2, 3] + }); + + let MixinB = Mixin.create({ + foo: 4 + }); + + let obj = mixin({}, MixinA, MixinB); + assert.deepEqual(get(obj, 'foo'), [1, 2, 3, 4]); + } + + ['@test adding a prop that is not an array should make array'](assert) { + let MixinA = Mixin.create({ + concatenatedProperties: ['foo'], + foo: 'bar' + }); + + let obj = mixin({}, MixinA); + assert.deepEqual(get(obj, 'foo'), ['bar']); + } + + ['@test adding a non-concatenable property that already has a defined value should result in an array with both values']( + assert + ) { + let mixinA = Mixin.create({ + foo: 1 + }); + + let mixinB = Mixin.create({ + concatenatedProperties: ['foo'], + foo: 2 + }); + + let obj = mixin({}, mixinA, mixinB); + assert.deepEqual(get(obj, 'foo'), [1, 2]); + } + + ['@test adding a concatenable property that already has a defined value should result in a concatenated value']( + assert + ) { + let mixinA = Mixin.create({ + foobar: 'foo' + }); + + let mixinB = Mixin.create({ + concatenatedProperties: ['foobar'], + foobar: 'bar' + }); + + let obj = mixin({}, mixinA, mixinB); + assert.deepEqual(get(obj, 'foobar'), ['foo', 'bar']); + } } -}); +); diff --git a/packages/ember-metal/tests/mixin/detect_test.js b/packages/ember-metal/tests/mixin/detect_test.js index 02dec760ce3..de85cae39ba 100644 --- a/packages/ember-metal/tests/mixin/detect_test.js +++ b/packages/ember-metal/tests/mixin/detect_test.js @@ -1,38 +1,60 @@ import { Mixin } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('Mixin.detect', class extends AbstractTestCase { - ['@test detect() finds a directly applied mixin'](assert) { - let MixinA = Mixin.create(); - let obj = {}; - - assert.equal(MixinA.detect(obj), false, 'MixinA.detect(obj) before apply()'); - - MixinA.apply(obj); - assert.equal(MixinA.detect(obj), true, 'MixinA.detect(obj) after apply()'); - } - - ['@test detect() finds nested mixins'](assert) { - let MixinA = Mixin.create({}); - let MixinB = Mixin.create(MixinA); - let obj = {}; - - assert.equal(MixinA.detect(obj), false, 'MixinA.detect(obj) before apply()'); - - MixinB.apply(obj); - assert.equal(MixinA.detect(obj), true, 'MixinA.detect(obj) after apply()'); +moduleFor( + 'Mixin.detect', + class extends AbstractTestCase { + ['@test detect() finds a directly applied mixin'](assert) { + let MixinA = Mixin.create(); + let obj = {}; + + assert.equal( + MixinA.detect(obj), + false, + 'MixinA.detect(obj) before apply()' + ); + + MixinA.apply(obj); + assert.equal( + MixinA.detect(obj), + true, + 'MixinA.detect(obj) after apply()' + ); + } + + ['@test detect() finds nested mixins'](assert) { + let MixinA = Mixin.create({}); + let MixinB = Mixin.create(MixinA); + let obj = {}; + + assert.equal( + MixinA.detect(obj), + false, + 'MixinA.detect(obj) before apply()' + ); + + MixinB.apply(obj); + assert.equal( + MixinA.detect(obj), + true, + 'MixinA.detect(obj) after apply()' + ); + } + + ['@test detect() finds mixins on other mixins'](assert) { + let MixinA = Mixin.create({}); + let MixinB = Mixin.create(MixinA); + assert.equal(MixinA.detect(MixinB), true, 'MixinA is part of MixinB'); + assert.equal( + MixinB.detect(MixinA), + false, + 'MixinB is not part of MixinA' + ); + } + + ['@test detect handles null values'](assert) { + let MixinA = Mixin.create(); + assert.equal(MixinA.detect(null), false); + } } - - ['@test detect() finds mixins on other mixins'](assert) { - let MixinA = Mixin.create({}); - let MixinB = Mixin.create(MixinA); - assert.equal(MixinA.detect(MixinB), true, 'MixinA is part of MixinB'); - assert.equal(MixinB.detect(MixinA), false, 'MixinB is not part of MixinA'); - } - - ['@test detect handles null values'](assert) { - let MixinA = Mixin.create(); - assert.equal(MixinA.detect(null), false); - } -}); - +); diff --git a/packages/ember-metal/tests/mixin/introspection_test.js b/packages/ember-metal/tests/mixin/introspection_test.js index 9be7db42b1e..8edca85c0c6 100644 --- a/packages/ember-metal/tests/mixin/introspection_test.js +++ b/packages/ember-metal/tests/mixin/introspection_test.js @@ -3,10 +3,7 @@ // current impl doesn't care about the differences as much... import { guidFor } from 'ember-utils'; -import { - mixin, - Mixin -} from '../..'; +import { mixin, Mixin } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; const PrivateProperty = Mixin.create({ @@ -34,18 +31,39 @@ const Combined = Mixin.create(BarProperties, BarMethods); let obj; -moduleFor('Basic introspection', class extends AbstractTestCase { - beforeEach() { - obj = {}; - mixin(obj, PrivateProperty, PublicProperty, PrivateMethod, PublicMethod, Combined); - } - - ['@test Ember.mixins()'](assert) { - function mapGuids(ary) { - return ary.map(x => guidFor(x)); +moduleFor( + 'Basic introspection', + class extends AbstractTestCase { + beforeEach() { + obj = {}; + mixin( + obj, + PrivateProperty, + PublicProperty, + PrivateMethod, + PublicMethod, + Combined + ); } - assert.deepEqual(mapGuids(Mixin.mixins(obj)), mapGuids([PrivateProperty, PublicProperty, PrivateMethod, PublicMethod, Combined, BarProperties, BarMethods]), 'should return included mixins'); - } -}); + ['@test Ember.mixins()'](assert) { + function mapGuids(ary) { + return ary.map(x => guidFor(x)); + } + assert.deepEqual( + mapGuids(Mixin.mixins(obj)), + mapGuids([ + PrivateProperty, + PublicProperty, + PrivateMethod, + PublicMethod, + Combined, + BarProperties, + BarMethods + ]), + 'should return included mixins' + ); + } + } +); diff --git a/packages/ember-metal/tests/mixin/merged_properties_test.js b/packages/ember-metal/tests/mixin/merged_properties_test.js index 579457f6d56..26a86fc49b9 100644 --- a/packages/ember-metal/tests/mixin/merged_properties_test.js +++ b/packages/ember-metal/tests/mixin/merged_properties_test.js @@ -1,185 +1,220 @@ import { Object as EmberObject } from 'ember-runtime'; -import { - get, - mixin, - Mixin -} from '../..'; +import { get, mixin, Mixin } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('Mixin mergedProperties', class extends AbstractTestCase { - ['@test defining mergedProperties should merge future version'](assert) { - let MixinA = Mixin.create({ - mergedProperties: ['foo'], - foo: { a: true, b: true, c: true } - }); - - let MixinB = Mixin.create({ - foo: { d: true, e: true, f: true } - }); - - let obj = mixin({}, MixinA, MixinB); - assert.deepEqual(get(obj, 'foo'), - { a: true, b: true, c: true, d: true, e: true, f: true }); - } - - ['@test defining mergedProperties on future mixin should merged into past'](assert) { - let MixinA = Mixin.create({ - foo: { a: true, b: true, c: true } - }); - - let MixinB = Mixin.create({ - mergedProperties: ['foo'], - foo: { d: true, e: true, f: true } - }); - - let obj = mixin({}, MixinA, MixinB); - assert.deepEqual(get(obj, 'foo'), - { a: true, b: true, c: true, d: true, e: true, f: true }); - } - - ['@test defining mergedProperties with null properties should keep properties null'](assert) { - let MixinA = Mixin.create({ - mergedProperties: ['foo'], - foo: null - }); - - let MixinB = Mixin.create({ - foo: null - }); - - let obj = mixin({}, MixinA, MixinB); - assert.equal(get(obj, 'foo'), null); - } - - ['@test mergedProperties\' properties can get overwritten'](assert) { - let MixinA = Mixin.create({ - mergedProperties: ['foo'], - foo: { a: 1 } - }); - - let MixinB = Mixin.create({ - foo: { a: 2 } - }); - - let obj = mixin({}, MixinA, MixinB); - assert.deepEqual(get(obj, 'foo'), { a: 2 }); - } - - ['@test mergedProperties should be concatenated'](assert) { - let MixinA = Mixin.create({ - mergedProperties: ['foo'], - foo: { a: true, b: true, c: true } - }); - - let MixinB = Mixin.create({ - mergedProperties: 'bar', - foo: { d: true, e: true, f: true }, - bar: { a: true, l: true } - }); - - let MixinC = Mixin.create({ - bar: { e: true, x: true } - }); - - let obj = mixin({}, MixinA, MixinB, MixinC); - assert.deepEqual(get(obj, 'mergedProperties'), ['foo', 'bar'], 'get mergedProperties'); - assert.deepEqual(get(obj, 'foo'), { a: true, b: true, c: true, d: true, e: true, f: true }, 'get foo'); - assert.deepEqual(get(obj, 'bar'), { a: true, l: true, e: true, x: true }, 'get bar'); - } - - ['@test mergedProperties should exist even if not explicitly set on create'](assert) { - let AnObj = EmberObject.extend({ - mergedProperties: ['options'], - options: { - a: 'a', - b: { - c: 'ccc' +moduleFor( + 'Mixin mergedProperties', + class extends AbstractTestCase { + ['@test defining mergedProperties should merge future version'](assert) { + let MixinA = Mixin.create({ + mergedProperties: ['foo'], + foo: { a: true, b: true, c: true } + }); + + let MixinB = Mixin.create({ + foo: { d: true, e: true, f: true } + }); + + let obj = mixin({}, MixinA, MixinB); + assert.deepEqual(get(obj, 'foo'), { + a: true, + b: true, + c: true, + d: true, + e: true, + f: true + }); + } + + ['@test defining mergedProperties on future mixin should merged into past']( + assert + ) { + let MixinA = Mixin.create({ + foo: { a: true, b: true, c: true } + }); + + let MixinB = Mixin.create({ + mergedProperties: ['foo'], + foo: { d: true, e: true, f: true } + }); + + let obj = mixin({}, MixinA, MixinB); + assert.deepEqual(get(obj, 'foo'), { + a: true, + b: true, + c: true, + d: true, + e: true, + f: true + }); + } + + ['@test defining mergedProperties with null properties should keep properties null']( + assert + ) { + let MixinA = Mixin.create({ + mergedProperties: ['foo'], + foo: null + }); + + let MixinB = Mixin.create({ + foo: null + }); + + let obj = mixin({}, MixinA, MixinB); + assert.equal(get(obj, 'foo'), null); + } + + ["@test mergedProperties' properties can get overwritten"](assert) { + let MixinA = Mixin.create({ + mergedProperties: ['foo'], + foo: { a: 1 } + }); + + let MixinB = Mixin.create({ + foo: { a: 2 } + }); + + let obj = mixin({}, MixinA, MixinB); + assert.deepEqual(get(obj, 'foo'), { a: 2 }); + } + + ['@test mergedProperties should be concatenated'](assert) { + let MixinA = Mixin.create({ + mergedProperties: ['foo'], + foo: { a: true, b: true, c: true } + }); + + let MixinB = Mixin.create({ + mergedProperties: 'bar', + foo: { d: true, e: true, f: true }, + bar: { a: true, l: true } + }); + + let MixinC = Mixin.create({ + bar: { e: true, x: true } + }); + + let obj = mixin({}, MixinA, MixinB, MixinC); + assert.deepEqual( + get(obj, 'mergedProperties'), + ['foo', 'bar'], + 'get mergedProperties' + ); + assert.deepEqual( + get(obj, 'foo'), + { a: true, b: true, c: true, d: true, e: true, f: true }, + 'get foo' + ); + assert.deepEqual( + get(obj, 'bar'), + { a: true, l: true, e: true, x: true }, + 'get bar' + ); + } + + ['@test mergedProperties should exist even if not explicitly set on create']( + assert + ) { + let AnObj = EmberObject.extend({ + mergedProperties: ['options'], + options: { + a: 'a', + b: { + c: 'ccc' + } } - } - }); - - let obj = AnObj.create({ - options: { - a: 'A' - } - }); - - assert.equal(get(obj, 'options').a, 'A'); - assert.equal(get(obj, 'options').b.c, 'ccc'); - } + }); - ['@test defining mergedProperties at create time should not modify the prototype'](assert) { - let AnObj = EmberObject.extend({ - mergedProperties: ['options'], - options: { - a: 1 - } - }); - - let objA = AnObj.create({ - options: { - a: 2 - } - }); - let objB = AnObj.create({ - options: { - a: 3 - } - }); - - assert.equal(get(objA, 'options').a, 2); - assert.equal(get(objB, 'options').a, 3); - } - - ['@test mergedProperties\' overwriting methods can call _super'](assert) { - assert.expect(4); + let obj = AnObj.create({ + options: { + a: 'A' + } + }); + + assert.equal(get(obj, 'options').a, 'A'); + assert.equal(get(obj, 'options').b.c, 'ccc'); + } + + ['@test defining mergedProperties at create time should not modify the prototype']( + assert + ) { + let AnObj = EmberObject.extend({ + mergedProperties: ['options'], + options: { + a: 1 + } + }); - let MixinA = Mixin.create({ - mergedProperties: ['foo'], - foo: { - meth(a) { - assert.equal(a, 'WOOT', '_super successfully called MixinA\'s `foo.meth` method'); - return 'WAT'; + let objA = AnObj.create({ + options: { + a: 2 } - } - }); - - let MixinB = Mixin.create({ - foo: { - meth() { - assert.ok(true, 'MixinB\'s `foo.meth` method called'); - return this._super(...arguments); + }); + let objB = AnObj.create({ + options: { + a: 3 } - } - }); - - let MixinC = Mixin.create({ - foo: { - meth(a) { - assert.ok(true, 'MixinC\'s `foo.meth` method called'); - return this._super(a); + }); + + assert.equal(get(objA, 'options').a, 2); + assert.equal(get(objB, 'options').a, 3); + } + + ["@test mergedProperties' overwriting methods can call _super"](assert) { + assert.expect(4); + + let MixinA = Mixin.create({ + mergedProperties: ['foo'], + foo: { + meth(a) { + assert.equal( + a, + 'WOOT', + "_super successfully called MixinA's `foo.meth` method" + ); + return 'WAT'; + } } - } - }); + }); + + let MixinB = Mixin.create({ + foo: { + meth() { + assert.ok(true, "MixinB's `foo.meth` method called"); + return this._super(...arguments); + } + } + }); + + let MixinC = Mixin.create({ + foo: { + meth(a) { + assert.ok(true, "MixinC's `foo.meth` method called"); + return this._super(a); + } + } + }); - let obj = mixin({}, MixinA, MixinB, MixinC); - assert.equal(obj.foo.meth('WOOT'), 'WAT'); - } + let obj = mixin({}, MixinA, MixinB, MixinC); + assert.equal(obj.foo.meth('WOOT'), 'WAT'); + } - ['@test Merging an Array should raise an error'](assert) { - assert.expect(1); + ['@test Merging an Array should raise an error'](assert) { + assert.expect(1); - let MixinA = Mixin.create({ - mergedProperties: ['foo'], - foo: { a: true, b: true, c: true } - }); + let MixinA = Mixin.create({ + mergedProperties: ['foo'], + foo: { a: true, b: true, c: true } + }); - let MixinB = Mixin.create({ - foo: ['a'] - }); + let MixinB = Mixin.create({ + foo: ['a'] + }); - expectAssertion(() => { - mixin({}, MixinA, MixinB); - }, 'You passed in `["a"]` as the value for `foo` but `foo` cannot be an Array'); + expectAssertion(() => { + mixin({}, MixinA, MixinB); + }, 'You passed in `["a"]` as the value for `foo` but `foo` cannot be an Array'); + } } -}); +); diff --git a/packages/ember-metal/tests/mixin/method_test.js b/packages/ember-metal/tests/mixin/method_test.js index 1a908418086..41eb32a5b01 100644 --- a/packages/ember-metal/tests/mixin/method_test.js +++ b/packages/ember-metal/tests/mixin/method_test.js @@ -1,209 +1,266 @@ -import { - mixin, - Mixin -} from '../..'; +import { mixin, Mixin } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('Mixin Methods', class extends AbstractTestCase { - ['@test defining simple methods'](assert) { - let MixinA, obj, props; - - props = { - publicMethod() { return 'publicMethod'; }, - _privateMethod() { return 'privateMethod'; } - }; - - MixinA = Mixin.create(props); - obj = {}; - MixinA.apply(obj); - - // but should be defined - assert.equal(props.publicMethod(), 'publicMethod', 'publicMethod is func'); - assert.equal(props._privateMethod(), 'privateMethod', 'privateMethod is func'); - } - - ['@test overriding public methods'](assert) { - let MixinA, MixinB, MixinD, MixinF, obj; - - MixinA = Mixin.create({ - publicMethod() { return 'A'; } - }); - - MixinB = Mixin.create(MixinA, { - publicMethod() { return this._super(...arguments) + 'B'; } - }); - - MixinD = Mixin.create(MixinA, { - publicMethod() { return this._super(...arguments) + 'D'; } - }); - - MixinF = Mixin.create({ - publicMethod() { return this._super(...arguments) + 'F'; } - }); - - obj = {}; - MixinB.apply(obj); - assert.equal(obj.publicMethod(), 'AB', 'should define super for A and B'); - - obj = {}; - MixinD.apply(obj); - assert.equal(obj.publicMethod(), 'AD', 'should define super for A and B'); - - obj = {}; - MixinA.apply(obj); - MixinF.apply(obj); - assert.equal(obj.publicMethod(), 'AF', 'should define super for A and F'); - - obj = { publicMethod() { return 'obj'; } }; - MixinF.apply(obj); - assert.equal(obj.publicMethod(), 'objF', 'should define super for F'); - } - - - ['@test overriding inherited objects'](assert) { - let cnt = 0; - let MixinA = Mixin.create({ - foo() { cnt++; } - }); - - let MixinB = Mixin.create({ - foo() { - this._super(...arguments); - cnt++; - } - }); +moduleFor( + 'Mixin Methods', + class extends AbstractTestCase { + ['@test defining simple methods'](assert) { + let MixinA, obj, props; + + props = { + publicMethod() { + return 'publicMethod'; + }, + _privateMethod() { + return 'privateMethod'; + } + }; + + MixinA = Mixin.create(props); + obj = {}; + MixinA.apply(obj); + + // but should be defined + assert.equal( + props.publicMethod(), + 'publicMethod', + 'publicMethod is func' + ); + assert.equal( + props._privateMethod(), + 'privateMethod', + 'privateMethod is func' + ); + } + + ['@test overriding public methods'](assert) { + let MixinA, MixinB, MixinD, MixinF, obj; + + MixinA = Mixin.create({ + publicMethod() { + return 'A'; + } + }); - let objA = {}; - MixinA.apply(objA); + MixinB = Mixin.create(MixinA, { + publicMethod() { + return this._super(...arguments) + 'B'; + } + }); - let objB = Object.create(objA); - MixinB.apply(objB); + MixinD = Mixin.create(MixinA, { + publicMethod() { + return this._super(...arguments) + 'D'; + } + }); - cnt = 0; - objB.foo(); - assert.equal(cnt, 2, 'should invoke both methods'); + MixinF = Mixin.create({ + publicMethod() { + return this._super(...arguments) + 'F'; + } + }); - cnt = 0; - objA.foo(); - assert.equal(cnt, 1, 'should not screw w/ parent obj'); - } + obj = {}; + MixinB.apply(obj); + assert.equal(obj.publicMethod(), 'AB', 'should define super for A and B'); - ['@test Including the same mixin more than once will only run once'](assert) { - let cnt = 0; - let MixinA = Mixin.create({ - foo() { cnt++; } - }); + obj = {}; + MixinD.apply(obj); + assert.equal(obj.publicMethod(), 'AD', 'should define super for A and B'); - let MixinB = Mixin.create(MixinA, { - foo() { this._super(...arguments); } - }); + obj = {}; + MixinA.apply(obj); + MixinF.apply(obj); + assert.equal(obj.publicMethod(), 'AF', 'should define super for A and F'); - let MixinC = Mixin.create(MixinA, { - foo() { this._super(...arguments); } - }); + obj = { + publicMethod() { + return 'obj'; + } + }; + MixinF.apply(obj); + assert.equal(obj.publicMethod(), 'objF', 'should define super for F'); + } + + ['@test overriding inherited objects'](assert) { + let cnt = 0; + let MixinA = Mixin.create({ + foo() { + cnt++; + } + }); - let MixinD = Mixin.create(MixinB, MixinC, MixinA, { - foo() { this._super(...arguments); } - }); + let MixinB = Mixin.create({ + foo() { + this._super(...arguments); + cnt++; + } + }); + + let objA = {}; + MixinA.apply(objA); + + let objB = Object.create(objA); + MixinB.apply(objB); + + cnt = 0; + objB.foo(); + assert.equal(cnt, 2, 'should invoke both methods'); + + cnt = 0; + objA.foo(); + assert.equal(cnt, 1, 'should not screw w/ parent obj'); + } + + ['@test Including the same mixin more than once will only run once']( + assert + ) { + let cnt = 0; + let MixinA = Mixin.create({ + foo() { + cnt++; + } + }); - let obj = {}; - MixinD.apply(obj); - MixinA.apply(obj); // try to apply again.. + let MixinB = Mixin.create(MixinA, { + foo() { + this._super(...arguments); + } + }); - cnt = 0; - obj.foo(); + let MixinC = Mixin.create(MixinA, { + foo() { + this._super(...arguments); + } + }); - assert.equal(cnt, 1, 'should invoke MixinA.foo one time'); - } + let MixinD = Mixin.create(MixinB, MixinC, MixinA, { + foo() { + this._super(...arguments); + } + }); - ['@test _super from a single mixin with no superclass does not error'](assert) { - let MixinA = Mixin.create({ - foo() { - this._super(...arguments); - } - }); + let obj = {}; + MixinD.apply(obj); + MixinA.apply(obj); // try to apply again.. - let obj = {}; - MixinA.apply(obj); + cnt = 0; + obj.foo(); - obj.foo(); - assert.ok(true); - } + assert.equal(cnt, 1, 'should invoke MixinA.foo one time'); + } - ['@test _super from a first-of-two mixins with no superclass function does not error'](assert) { - // _super was previously calling itself in the second assertion. - // Use remaining count of calls to ensure it doesn't loop indefinitely. - let remaining = 3; - let MixinA = Mixin.create({ - foo() { - if (remaining-- > 0) { + ['@test _super from a single mixin with no superclass does not error']( + assert + ) { + let MixinA = Mixin.create({ + foo() { this._super(...arguments); } - } - }); + }); + + let obj = {}; + MixinA.apply(obj); + + obj.foo(); + assert.ok(true); + } + + ['@test _super from a first-of-two mixins with no superclass function does not error']( + assert + ) { + // _super was previously calling itself in the second assertion. + // Use remaining count of calls to ensure it doesn't loop indefinitely. + let remaining = 3; + let MixinA = Mixin.create({ + foo() { + if (remaining-- > 0) { + this._super(...arguments); + } + } + }); - let MixinB = Mixin.create({ - foo() { this._super(...arguments); } - }); + let MixinB = Mixin.create({ + foo() { + this._super(...arguments); + } + }); - let obj = {}; - MixinA.apply(obj); - MixinB.apply(obj); + let obj = {}; + MixinA.apply(obj); + MixinB.apply(obj); - obj.foo(); - assert.ok(true); + obj.foo(); + assert.ok(true); + } } -}); +); // .......................................................... // CONFLICTS // -moduleFor('Method Conflicts', class extends AbstractTestCase { - ['@test overriding toString'](assert) { - let MixinA = Mixin.create({ - toString() { return 'FOO'; } - }); - - let obj = {}; - MixinA.apply(obj); - assert.equal(obj.toString(), 'FOO', 'should override toString w/o error'); - - obj = {}; - mixin(obj, { toString() { return 'FOO'; } }); - assert.equal(obj.toString(), 'FOO', 'should override toString w/o error'); +moduleFor( + 'Method Conflicts', + class extends AbstractTestCase { + ['@test overriding toString'](assert) { + let MixinA = Mixin.create({ + toString() { + return 'FOO'; + } + }); + + let obj = {}; + MixinA.apply(obj); + assert.equal(obj.toString(), 'FOO', 'should override toString w/o error'); + + obj = {}; + mixin(obj, { + toString() { + return 'FOO'; + } + }); + assert.equal(obj.toString(), 'FOO', 'should override toString w/o error'); + } } -}); +); // .......................................................... // BUGS // -moduleFor('system/mixin/method_test BUGS', class extends AbstractTestCase { - ['@test applying several mixins at once with sup already defined causes infinite loop'](assert) { - let cnt = 0; - let MixinA = Mixin.create({ - foo() { cnt++; } - }); - - let MixinB = Mixin.create({ - foo() { - this._super(...arguments); - cnt++; - } - }); - - let MixinC = Mixin.create({ - foo() { - this._super(...arguments); - cnt++; - } - }); - - let obj = {}; - mixin(obj, MixinA); // sup already exists - mixin(obj, MixinB, MixinC); // must be more than one mixin - - cnt = 0; - obj.foo(); - assert.equal(cnt, 3, 'should invoke all 3 methods'); +moduleFor( + 'system/mixin/method_test BUGS', + class extends AbstractTestCase { + ['@test applying several mixins at once with sup already defined causes infinite loop']( + assert + ) { + let cnt = 0; + let MixinA = Mixin.create({ + foo() { + cnt++; + } + }); + + let MixinB = Mixin.create({ + foo() { + this._super(...arguments); + cnt++; + } + }); + + let MixinC = Mixin.create({ + foo() { + this._super(...arguments); + cnt++; + } + }); + + let obj = {}; + mixin(obj, MixinA); // sup already exists + mixin(obj, MixinB, MixinC); // must be more than one mixin + + cnt = 0; + obj.foo(); + assert.equal(cnt, 3, 'should invoke all 3 methods'); + } } -}); +); diff --git a/packages/ember-metal/tests/mixin/observer_test.js b/packages/ember-metal/tests/mixin/observer_test.js index 29d989d9e6d..3e3949f515b 100644 --- a/packages/ember-metal/tests/mixin/observer_test.js +++ b/packages/ember-metal/tests/mixin/observer_test.js @@ -1,213 +1,262 @@ -import { - set, - get, - observer, - mixin, - Mixin, - isWatching -} from '../..'; +import { set, get, observer, mixin, Mixin, isWatching } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('Mixin observer', class extends AbstractTestCase { - ['@test global observer helper'](assert) { - let MyMixin = Mixin.create({ - - count: 0, - - foo: observer('bar', function() { - set(this, 'count', get(this, 'count') + 1); - }) - - }); - - let obj = mixin({}, MyMixin); - assert.equal(get(obj, 'count'), 0, 'should not invoke observer immediately'); - - set(obj, 'bar', 'BAZ'); - assert.equal(get(obj, 'count'), 1, 'should invoke observer after change'); - } - - ['@test global observer helper takes multiple params'](assert) { - let MyMixin = Mixin.create({ - - count: 0, - - foo: observer('bar', 'baz', function() { - set(this, 'count', get(this, 'count') + 1); - }) - - }); - - let obj = mixin({}, MyMixin); - assert.equal(get(obj, 'count'), 0, 'should not invoke observer immediately'); - - set(obj, 'bar', 'BAZ'); - set(obj, 'baz', 'BAZ'); - assert.equal(get(obj, 'count'), 2, 'should invoke observer after change'); - } - - ['@test replacing observer should remove old observer'](assert) { - let MyMixin = Mixin.create({ - - count: 0, - - foo: observer('bar', function() { - set(this, 'count', get(this, 'count') + 1); - }) - - }); - - let Mixin2 = Mixin.create({ - foo: observer('baz', function() { - set(this, 'count', get(this, 'count') + 10); - }) - }); - - let obj = mixin({}, MyMixin, Mixin2); - assert.equal(get(obj, 'count'), 0, 'should not invoke observer immediately'); - - set(obj, 'bar', 'BAZ'); - assert.equal(get(obj, 'count'), 0, 'should not invoke observer after change'); - - set(obj, 'baz', 'BAZ'); - assert.equal(get(obj, 'count'), 10, 'should invoke observer after change'); - } - - ['@test observing chain with property before'](assert) { - let obj2 = { baz: 'baz' }; - - let MyMixin = Mixin.create({ - count: 0, - bar: obj2, - foo: observer('bar.baz', function() { - set(this, 'count', get(this, 'count') + 1); - }) - }); - - let obj = mixin({}, MyMixin); - assert.equal(get(obj, 'count'), 0, 'should not invoke observer immediately'); - - set(obj2, 'baz', 'BAZ'); - assert.equal(get(obj, 'count'), 1, 'should invoke observer after change'); - } - - ['@test observing chain with property after'](assert) { - let obj2 = { baz: 'baz' }; - - let MyMixin = Mixin.create({ - count: 0, - foo: observer('bar.baz', function() { - set(this, 'count', get(this, 'count') + 1); - }), - bar: obj2 - }); - - let obj = mixin({}, MyMixin); - assert.equal(get(obj, 'count'), 0, 'should not invoke observer immediately'); - - set(obj2, 'baz', 'BAZ'); - assert.equal(get(obj, 'count'), 1, 'should invoke observer after change'); - } - - ['@test observing chain with property in mixin applied later'](assert) { - let obj2 = { baz: 'baz' }; - - let MyMixin = Mixin.create({ - - count: 0, - foo: observer('bar.baz', function() { - set(this, 'count', get(this, 'count') + 1); - }) - }); - - let MyMixin2 = Mixin.create({ bar: obj2 }); - - let obj = mixin({}, MyMixin); - assert.equal(get(obj, 'count'), 0, 'should not invoke observer immediately'); - - MyMixin2.apply(obj); - assert.equal(get(obj, 'count'), 0, 'should not invoke observer immediately'); - - set(obj2, 'baz', 'BAZ'); - assert.equal(get(obj, 'count'), 1, 'should invoke observer after change'); - } - - ['@test observing chain with existing property'](assert) { - let obj2 = { baz: 'baz' }; - - let MyMixin = Mixin.create({ - count: 0, - foo: observer('bar.baz', function() { - set(this, 'count', get(this, 'count') + 1); - }) - }); - - let obj = mixin({ bar: obj2 }, MyMixin); - assert.equal(get(obj, 'count'), 0, 'should not invoke observer immediately'); - - set(obj2, 'baz', 'BAZ'); - assert.equal(get(obj, 'count'), 1, 'should invoke observer after change'); - } - - ['@test observing chain with property in mixin before'](assert) { - let obj2 = { baz: 'baz' }; - let MyMixin2 = Mixin.create({ bar: obj2 }); - - let MyMixin = Mixin.create({ - count: 0, - foo: observer('bar.baz', function() { - set(this, 'count', get(this, 'count') + 1); - }) - }); - - let obj = mixin({}, MyMixin2, MyMixin); - assert.equal(get(obj, 'count'), 0, 'should not invoke observer immediately'); - - set(obj2, 'baz', 'BAZ'); - assert.equal(get(obj, 'count'), 1, 'should invoke observer after change'); - } - - ['@test observing chain with property in mixin after'](assert) { - let obj2 = { baz: 'baz' }; - let MyMixin2 = Mixin.create({ bar: obj2 }); - - let MyMixin = Mixin.create({ - count: 0, - foo: observer('bar.baz', function() { - set(this, 'count', get(this, 'count') + 1); - }) - }); - - let obj = mixin({}, MyMixin, MyMixin2); - assert.equal(get(obj, 'count'), 0, 'should not invoke observer immediately'); - - set(obj2, 'baz', 'BAZ'); - assert.equal(get(obj, 'count'), 1, 'should invoke observer after change'); - } - - ['@test observing chain with overridden property'](assert) { - let obj2 = { baz: 'baz' }; - let obj3 = { baz: 'foo' }; - - let MyMixin2 = Mixin.create({ bar: obj3 }); - - let MyMixin = Mixin.create({ - count: 0, - foo: observer('bar.baz', function() { - set(this, 'count', get(this, 'count') + 1); - }) - }); - - let obj = mixin({ bar: obj2 }, MyMixin, MyMixin2); - assert.equal(get(obj, 'count'), 0, 'should not invoke observer immediately'); - - assert.equal(isWatching(obj2, 'baz'), false, 'should not be watching baz'); - assert.equal(isWatching(obj3, 'baz'), true, 'should be watching baz'); - - set(obj2, 'baz', 'BAZ'); - assert.equal(get(obj, 'count'), 0, 'should not invoke observer after change'); - - set(obj3, 'baz', 'BEAR'); - assert.equal(get(obj, 'count'), 1, 'should invoke observer after change'); +moduleFor( + 'Mixin observer', + class extends AbstractTestCase { + ['@test global observer helper'](assert) { + let MyMixin = Mixin.create({ + count: 0, + + foo: observer('bar', function() { + set(this, 'count', get(this, 'count') + 1); + }) + }); + + let obj = mixin({}, MyMixin); + assert.equal( + get(obj, 'count'), + 0, + 'should not invoke observer immediately' + ); + + set(obj, 'bar', 'BAZ'); + assert.equal(get(obj, 'count'), 1, 'should invoke observer after change'); + } + + ['@test global observer helper takes multiple params'](assert) { + let MyMixin = Mixin.create({ + count: 0, + + foo: observer('bar', 'baz', function() { + set(this, 'count', get(this, 'count') + 1); + }) + }); + + let obj = mixin({}, MyMixin); + assert.equal( + get(obj, 'count'), + 0, + 'should not invoke observer immediately' + ); + + set(obj, 'bar', 'BAZ'); + set(obj, 'baz', 'BAZ'); + assert.equal(get(obj, 'count'), 2, 'should invoke observer after change'); + } + + ['@test replacing observer should remove old observer'](assert) { + let MyMixin = Mixin.create({ + count: 0, + + foo: observer('bar', function() { + set(this, 'count', get(this, 'count') + 1); + }) + }); + + let Mixin2 = Mixin.create({ + foo: observer('baz', function() { + set(this, 'count', get(this, 'count') + 10); + }) + }); + + let obj = mixin({}, MyMixin, Mixin2); + assert.equal( + get(obj, 'count'), + 0, + 'should not invoke observer immediately' + ); + + set(obj, 'bar', 'BAZ'); + assert.equal( + get(obj, 'count'), + 0, + 'should not invoke observer after change' + ); + + set(obj, 'baz', 'BAZ'); + assert.equal( + get(obj, 'count'), + 10, + 'should invoke observer after change' + ); + } + + ['@test observing chain with property before'](assert) { + let obj2 = { baz: 'baz' }; + + let MyMixin = Mixin.create({ + count: 0, + bar: obj2, + foo: observer('bar.baz', function() { + set(this, 'count', get(this, 'count') + 1); + }) + }); + + let obj = mixin({}, MyMixin); + assert.equal( + get(obj, 'count'), + 0, + 'should not invoke observer immediately' + ); + + set(obj2, 'baz', 'BAZ'); + assert.equal(get(obj, 'count'), 1, 'should invoke observer after change'); + } + + ['@test observing chain with property after'](assert) { + let obj2 = { baz: 'baz' }; + + let MyMixin = Mixin.create({ + count: 0, + foo: observer('bar.baz', function() { + set(this, 'count', get(this, 'count') + 1); + }), + bar: obj2 + }); + + let obj = mixin({}, MyMixin); + assert.equal( + get(obj, 'count'), + 0, + 'should not invoke observer immediately' + ); + + set(obj2, 'baz', 'BAZ'); + assert.equal(get(obj, 'count'), 1, 'should invoke observer after change'); + } + + ['@test observing chain with property in mixin applied later'](assert) { + let obj2 = { baz: 'baz' }; + + let MyMixin = Mixin.create({ + count: 0, + foo: observer('bar.baz', function() { + set(this, 'count', get(this, 'count') + 1); + }) + }); + + let MyMixin2 = Mixin.create({ bar: obj2 }); + + let obj = mixin({}, MyMixin); + assert.equal( + get(obj, 'count'), + 0, + 'should not invoke observer immediately' + ); + + MyMixin2.apply(obj); + assert.equal( + get(obj, 'count'), + 0, + 'should not invoke observer immediately' + ); + + set(obj2, 'baz', 'BAZ'); + assert.equal(get(obj, 'count'), 1, 'should invoke observer after change'); + } + + ['@test observing chain with existing property'](assert) { + let obj2 = { baz: 'baz' }; + + let MyMixin = Mixin.create({ + count: 0, + foo: observer('bar.baz', function() { + set(this, 'count', get(this, 'count') + 1); + }) + }); + + let obj = mixin({ bar: obj2 }, MyMixin); + assert.equal( + get(obj, 'count'), + 0, + 'should not invoke observer immediately' + ); + + set(obj2, 'baz', 'BAZ'); + assert.equal(get(obj, 'count'), 1, 'should invoke observer after change'); + } + + ['@test observing chain with property in mixin before'](assert) { + let obj2 = { baz: 'baz' }; + let MyMixin2 = Mixin.create({ bar: obj2 }); + + let MyMixin = Mixin.create({ + count: 0, + foo: observer('bar.baz', function() { + set(this, 'count', get(this, 'count') + 1); + }) + }); + + let obj = mixin({}, MyMixin2, MyMixin); + assert.equal( + get(obj, 'count'), + 0, + 'should not invoke observer immediately' + ); + + set(obj2, 'baz', 'BAZ'); + assert.equal(get(obj, 'count'), 1, 'should invoke observer after change'); + } + + ['@test observing chain with property in mixin after'](assert) { + let obj2 = { baz: 'baz' }; + let MyMixin2 = Mixin.create({ bar: obj2 }); + + let MyMixin = Mixin.create({ + count: 0, + foo: observer('bar.baz', function() { + set(this, 'count', get(this, 'count') + 1); + }) + }); + + let obj = mixin({}, MyMixin, MyMixin2); + assert.equal( + get(obj, 'count'), + 0, + 'should not invoke observer immediately' + ); + + set(obj2, 'baz', 'BAZ'); + assert.equal(get(obj, 'count'), 1, 'should invoke observer after change'); + } + + ['@test observing chain with overridden property'](assert) { + let obj2 = { baz: 'baz' }; + let obj3 = { baz: 'foo' }; + + let MyMixin2 = Mixin.create({ bar: obj3 }); + + let MyMixin = Mixin.create({ + count: 0, + foo: observer('bar.baz', function() { + set(this, 'count', get(this, 'count') + 1); + }) + }); + + let obj = mixin({ bar: obj2 }, MyMixin, MyMixin2); + assert.equal( + get(obj, 'count'), + 0, + 'should not invoke observer immediately' + ); + + assert.equal( + isWatching(obj2, 'baz'), + false, + 'should not be watching baz' + ); + assert.equal(isWatching(obj3, 'baz'), true, 'should be watching baz'); + + set(obj2, 'baz', 'BAZ'); + assert.equal( + get(obj, 'count'), + 0, + 'should not invoke observer after change' + ); + + set(obj3, 'baz', 'BEAR'); + assert.equal(get(obj, 'count'), 1, 'should invoke observer after change'); + } } -}); +); diff --git a/packages/ember-metal/tests/mixin/reopen_test.js b/packages/ember-metal/tests/mixin/reopen_test.js index 538526db07b..2de1f7a1485 100644 --- a/packages/ember-metal/tests/mixin/reopen_test.js +++ b/packages/ember-metal/tests/mixin/reopen_test.js @@ -1,51 +1,52 @@ import { Object as EmberObject } from 'ember-runtime'; -import { - run, - get, - Mixin -} from '../..'; +import { run, get, Mixin } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('Mixin#reopen', class extends AbstractTestCase { - ['@test using reopen() to add more properties to a simple'](assert) { - let MixinA = Mixin.create({ foo: 'FOO', baz: 'BAZ' }); - MixinA.reopen({ bar: 'BAR', foo: 'FOO2' }); - let obj = {}; - MixinA.apply(obj); +moduleFor( + 'Mixin#reopen', + class extends AbstractTestCase { + ['@test using reopen() to add more properties to a simple'](assert) { + let MixinA = Mixin.create({ foo: 'FOO', baz: 'BAZ' }); + MixinA.reopen({ bar: 'BAR', foo: 'FOO2' }); + let obj = {}; + MixinA.apply(obj); - assert.equal(get(obj, 'foo'), 'FOO2', 'mixin() should override'); - assert.equal(get(obj, 'baz'), 'BAZ', 'preserve MixinA props'); - assert.equal(get(obj, 'bar'), 'BAR', 'include MixinB props'); - } + assert.equal(get(obj, 'foo'), 'FOO2', 'mixin() should override'); + assert.equal(get(obj, 'baz'), 'BAZ', 'preserve MixinA props'); + assert.equal(get(obj, 'bar'), 'BAR', 'include MixinB props'); + } - ['@test using reopen() and calling _super where there is not a super function does not cause infinite recursion'](assert) { - let Taco = EmberObject.extend({ - createBreakfast() { - // There is no original createBreakfast function. - // Calling the wrapped _super function here - // used to end in an infinite call loop - this._super(...arguments); - return 'Breakfast!'; - } - }); + ['@test using reopen() and calling _super where there is not a super function does not cause infinite recursion']( + assert + ) { + let Taco = EmberObject.extend({ + createBreakfast() { + // There is no original createBreakfast function. + // Calling the wrapped _super function here + // used to end in an infinite call loop + this._super(...arguments); + return 'Breakfast!'; + } + }); - Taco.reopen({ - createBreakfast() { - return this._super(...arguments); - } - }); + Taco.reopen({ + createBreakfast() { + return this._super(...arguments); + } + }); - let taco = Taco.create(); + let taco = Taco.create(); - let result; - run(() => { - try { - result = taco.createBreakfast(); - } catch (e) { - result = 'Your breakfast was interrupted by an infinite stack error.'; - } - }); + let result; + run(() => { + try { + result = taco.createBreakfast(); + } catch (e) { + result = 'Your breakfast was interrupted by an infinite stack error.'; + } + }); - assert.equal(result, 'Breakfast!'); + assert.equal(result, 'Breakfast!'); + } } -}); +); diff --git a/packages/ember-metal/tests/mixin/required_test.js b/packages/ember-metal/tests/mixin/required_test.js index c140b0ad6cf..5d8fe8c732e 100644 --- a/packages/ember-metal/tests/mixin/required_test.js +++ b/packages/ember-metal/tests/mixin/required_test.js @@ -1,62 +1,60 @@ -import { - mixin, - Mixin, - required, - get -} from '../..'; +import { mixin, Mixin, required, get } from '../..'; import { ENV } from 'ember-environment'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; let PartialMixin, FinalMixin, obj; let originalEnvVal; -moduleFor('Module.required', class extends AbstractTestCase { - beforeEach() { - originalEnvVal = ENV._ENABLE_PROPERTY_REQUIRED_SUPPORT; - ENV._ENABLE_PROPERTY_REQUIRED_SUPPORT = true; - expectDeprecation(() => { - PartialMixin = Mixin.create({ - foo: required(), - bar: 'BAR' +moduleFor( + 'Module.required', + class extends AbstractTestCase { + beforeEach() { + originalEnvVal = ENV._ENABLE_PROPERTY_REQUIRED_SUPPORT; + ENV._ENABLE_PROPERTY_REQUIRED_SUPPORT = true; + expectDeprecation(() => { + PartialMixin = Mixin.create({ + foo: required(), + bar: 'BAR' + }); + }, 'Ember.required is deprecated as its behavior is inconsistent and unreliable.'); + + FinalMixin = Mixin.create({ + foo: 'FOO' }); - }, 'Ember.required is deprecated as its behavior is inconsistent and unreliable.'); - FinalMixin = Mixin.create({ - foo: 'FOO' - }); - - obj = {}; - } - - afterEach() { - PartialMixin = FinalMixin = obj = null; - ENV._ENABLE_PROPERTY_REQUIRED_SUPPORT = originalEnvVal; - } - - ['@test applying a mixin to meet requirement'](assert) { - FinalMixin.apply(obj); - PartialMixin.apply(obj); - assert.equal(get(obj, 'foo'), 'FOO', 'should now be defined'); - } - - ['@test combined mixins to meet requirement'](assert) { - Mixin.create(PartialMixin, FinalMixin).apply(obj); - assert.equal(get(obj, 'foo'), 'FOO', 'should now be defined'); - } - - ['@test merged mixin'](assert) { - Mixin.create(PartialMixin, { foo: 'FOO' }).apply(obj); - assert.equal(get(obj, 'foo'), 'FOO', 'should now be defined'); - } - - ['@test define property on source object'](assert) { - obj.foo = 'FOO'; - PartialMixin.apply(obj); - assert.equal(get(obj, 'foo'), 'FOO', 'should now be defined'); - } - - ['@test using apply'](assert) { - mixin(obj, PartialMixin, { foo: 'FOO' }); - assert.equal(get(obj, 'foo'), 'FOO', 'should now be defined'); + obj = {}; + } + + afterEach() { + PartialMixin = FinalMixin = obj = null; + ENV._ENABLE_PROPERTY_REQUIRED_SUPPORT = originalEnvVal; + } + + ['@test applying a mixin to meet requirement'](assert) { + FinalMixin.apply(obj); + PartialMixin.apply(obj); + assert.equal(get(obj, 'foo'), 'FOO', 'should now be defined'); + } + + ['@test combined mixins to meet requirement'](assert) { + Mixin.create(PartialMixin, FinalMixin).apply(obj); + assert.equal(get(obj, 'foo'), 'FOO', 'should now be defined'); + } + + ['@test merged mixin'](assert) { + Mixin.create(PartialMixin, { foo: 'FOO' }).apply(obj); + assert.equal(get(obj, 'foo'), 'FOO', 'should now be defined'); + } + + ['@test define property on source object'](assert) { + obj.foo = 'FOO'; + PartialMixin.apply(obj); + assert.equal(get(obj, 'foo'), 'FOO', 'should now be defined'); + } + + ['@test using apply'](assert) { + mixin(obj, PartialMixin, { foo: 'FOO' }); + assert.equal(get(obj, 'foo'), 'FOO', 'should now be defined'); + } } -}); +); diff --git a/packages/ember-metal/tests/mixin/without_test.js b/packages/ember-metal/tests/mixin/without_test.js index ad8940c4c74..337a393bb53 100644 --- a/packages/ember-metal/tests/mixin/without_test.js +++ b/packages/ember-metal/tests/mixin/without_test.js @@ -1,19 +1,24 @@ import { Mixin } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('without', class extends AbstractTestCase { - ['@test without should create a new mixin excluding named properties'](assert) { - let MixinA = Mixin.create({ - foo: 'FOO', - bar: 'BAR' - }); +moduleFor( + 'without', + class extends AbstractTestCase { + ['@test without should create a new mixin excluding named properties']( + assert + ) { + let MixinA = Mixin.create({ + foo: 'FOO', + bar: 'BAR' + }); - let MixinB = MixinA.without('bar'); + let MixinB = MixinA.without('bar'); - let obj = {}; - MixinB.apply(obj); + let obj = {}; + MixinB.apply(obj); - assert.equal(obj.foo, 'FOO', 'should defined foo'); - assert.equal(obj.bar, undefined, 'should not define bar'); + assert.equal(obj.foo, 'FOO', 'should defined foo'); + assert.equal(obj.bar, undefined, 'should not define bar'); + } } -}); +); diff --git a/packages/ember-metal/tests/observer_test.js b/packages/ember-metal/tests/observer_test.js index 90281ef4d77..ec22732ea7e 100644 --- a/packages/ember-metal/tests/observer_test.js +++ b/packages/ember-metal/tests/observer_test.js @@ -23,428 +23,534 @@ function K() {} // ADD OBSERVER // -moduleFor('addObserver', class extends AbstractTestCase { - ['@test observer should assert to invalid input']() { - expectAssertion(()=> { - observer(()=>{}); - }, 'observer called without valid path'); - - expectAssertion(()=> { - observer(null); - }, 'observer called without a function'); - } +moduleFor( + 'addObserver', + class extends AbstractTestCase { + ['@test observer should assert to invalid input']() { + expectAssertion(() => { + observer(() => {}); + }, 'observer called without valid path'); + + expectAssertion(() => { + observer(null); + }, 'observer called without a function'); + } - ['@test observer should fire when property is modified'](assert) { - let obj = {}; - let count = 0; + ['@test observer should fire when property is modified'](assert) { + let obj = {}; + let count = 0; - addObserver(obj, 'foo', function() { - assert.equal(get(obj, 'foo'), 'bar', 'should invoke AFTER value changed'); - count++; - }); + addObserver(obj, 'foo', function() { + assert.equal( + get(obj, 'foo'), + 'bar', + 'should invoke AFTER value changed' + ); + count++; + }); - set(obj, 'foo', 'bar'); - assert.equal(count, 1, 'should have invoked observer'); - } + set(obj, 'foo', 'bar'); + assert.equal(count, 1, 'should have invoked observer'); + } - ['@test observer should fire when dependent property is modified'](assert) { - let obj = { bar: 'bar' }; - defineProperty(obj, 'foo', computed(function() { - return get(this, 'bar').toUpperCase(); - }).property('bar')); + ['@test observer should fire when dependent property is modified'](assert) { + let obj = { bar: 'bar' }; + defineProperty( + obj, + 'foo', + computed(function() { + return get(this, 'bar').toUpperCase(); + }).property('bar') + ); - get(obj, 'foo'); + get(obj, 'foo'); - let count = 0; - addObserver(obj, 'foo', function() { - assert.equal(get(obj, 'foo'), 'BAZ', 'should have invoked after prop change'); - count++; - }); + let count = 0; + addObserver(obj, 'foo', function() { + assert.equal( + get(obj, 'foo'), + 'BAZ', + 'should have invoked after prop change' + ); + count++; + }); - set(obj, 'bar', 'baz'); - assert.equal(count, 1, 'should have invoked observer'); - } + set(obj, 'bar', 'baz'); + assert.equal(count, 1, 'should have invoked observer'); + } - ['@test observer should continue to fire after dependent properties are accessed'](assert) { - let observerCount = 0; - let obj = {}; + ['@test observer should continue to fire after dependent properties are accessed']( + assert + ) { + let observerCount = 0; + let obj = {}; + + defineProperty( + obj, + 'prop', + computed(function() { + return Math.random(); + }) + ); + defineProperty( + obj, + 'anotherProp', + computed('prop', function() { + return get(this, 'prop') + Math.random(); + }) + ); + + addObserver(obj, 'prop', function() { + observerCount++; + }); - defineProperty(obj, 'prop', computed(function () { return Math.random(); })); - defineProperty(obj, 'anotherProp', computed('prop', function () { return get(this, 'prop') + Math.random(); })); + get(obj, 'anotherProp'); - addObserver(obj, 'prop', function () { observerCount++; }); + for (let i = 0; i < 10; i++) { + notifyPropertyChange(obj, 'prop'); + } - get(obj, 'anotherProp'); + assert.equal(observerCount, 10, 'should continue to fire indefinitely'); + } - for (let i = 0; i < 10; i++) { - notifyPropertyChange(obj, 'prop'); + ['@test observer added declaratively via brace expansion should fire when property changes']( + assert + ) { + if (ENV.EXTEND_PROTOTYPES.Function) { + let obj = {}; + let count = 0; + + mixin(obj, { + observeFooAndBar: function() { + count++; + }.observes('{foo,bar}') + }); + + set(obj, 'foo', 'foo'); + assert.equal( + count, + 1, + 'observer specified via brace expansion invoked on property change' + ); + + set(obj, 'bar', 'bar'); + assert.equal( + count, + 2, + 'observer specified via brace expansion invoked on property change' + ); + + set(obj, 'baz', 'baz'); + assert.equal(count, 2, 'observer not invoked on unspecified property'); + } else { + assert.expect(0); + } } - assert.equal(observerCount, 10, 'should continue to fire indefinitely'); - } + ['@test observer specified declaratively via brace expansion should fire when dependent property changes']( + assert + ) { + if (ENV.EXTEND_PROTOTYPES.Function) { + let obj = { baz: 'Initial' }; + let count = 0; + + defineProperty( + obj, + 'foo', + computed(function() { + return get(this, 'bar').toLowerCase(); + }).property('bar') + ); + + defineProperty( + obj, + 'bar', + computed(function() { + return get(this, 'baz').toUpperCase(); + }).property('baz') + ); + + mixin(obj, { + fooAndBarWatcher: function() { + count++; + }.observes('{foo,bar}') + }); + + get(obj, 'foo'); + set(obj, 'baz', 'Baz'); + // fire once for foo, once for bar + assert.equal( + count, + 2, + 'observer specified via brace expansion invoked on dependent property change' + ); + + set(obj, 'quux', 'Quux'); + assert.equal(count, 2, 'observer not fired on unspecified property'); + } else { + assert.expect(0); + } + } - ['@test observer added declaratively via brace expansion should fire when property changes'](assert) { - if (ENV.EXTEND_PROTOTYPES.Function) { - let obj = { }; + ['@test observers watching multiple properties via brace expansion should fire when the properties change']( + assert + ) { + let obj = {}; let count = 0; mixin(obj, { - observeFooAndBar: function () { + observeFooAndBar: observer('{foo,bar}', function() { count++; - }.observes('{foo,bar}') + }) }); set(obj, 'foo', 'foo'); - assert.equal(count, 1, 'observer specified via brace expansion invoked on property change'); + assert.equal( + count, + 1, + 'observer specified via brace expansion invoked on property change' + ); set(obj, 'bar', 'bar'); - assert.equal(count, 2, 'observer specified via brace expansion invoked on property change'); + assert.equal( + count, + 2, + 'observer specified via brace expansion invoked on property change' + ); set(obj, 'baz', 'baz'); assert.equal(count, 2, 'observer not invoked on unspecified property'); - } else { - assert.expect(0); } - } - ['@test observer specified declaratively via brace expansion should fire when dependent property changes'](assert) { - if (ENV.EXTEND_PROTOTYPES.Function) { + ['@test observers watching multiple properties via brace expansion should fire when dependent properties change']( + assert + ) { let obj = { baz: 'Initial' }; let count = 0; - defineProperty(obj, 'foo', computed(function() { - return get(this, 'bar').toLowerCase(); - }).property('bar')); - - defineProperty(obj, 'bar', computed(function() { - return get(this, 'baz').toUpperCase(); - }).property('baz')); + defineProperty( + obj, + 'foo', + computed(function() { + return get(this, 'bar').toLowerCase(); + }).property('bar') + ); + + defineProperty( + obj, + 'bar', + computed(function() { + return get(this, 'baz').toUpperCase(); + }).property('baz') + ); mixin(obj, { - fooAndBarWatcher: function () { + fooAndBarWatcher: observer('{foo,bar}', function() { count++; - }.observes('{foo,bar}') + }) }); get(obj, 'foo'); set(obj, 'baz', 'Baz'); // fire once for foo, once for bar - assert.equal(count, 2, 'observer specified via brace expansion invoked on dependent property change'); + assert.equal( + count, + 2, + 'observer specified via brace expansion invoked on dependent property change' + ); set(obj, 'quux', 'Quux'); assert.equal(count, 2, 'observer not fired on unspecified property'); - } else { - assert.expect(0); } - } - - ['@test observers watching multiple properties via brace expansion should fire when the properties change'](assert) { - let obj = { }; - let count = 0; - mixin(obj, { - observeFooAndBar: observer('{foo,bar}', function () { - count++; - }) - }); - - set(obj, 'foo', 'foo'); - assert.equal(count, 1, 'observer specified via brace expansion invoked on property change'); - - set(obj, 'bar', 'bar'); - assert.equal(count, 2, 'observer specified via brace expansion invoked on property change'); + ['@test nested observers should fire in order'](assert) { + let obj = { foo: 'foo', bar: 'bar' }; + let fooCount = 0; + let barCount = 0; - set(obj, 'baz', 'baz'); - assert.equal(count, 2, 'observer not invoked on unspecified property'); - } + addObserver(obj, 'foo', function() { + fooCount++; + }); + addObserver(obj, 'bar', function() { + set(obj, 'foo', 'BAZ'); + assert.equal(fooCount, 1, 'fooCount should have fired already'); + barCount++; + }); - ['@test observers watching multiple properties via brace expansion should fire when dependent properties change'](assert) { - let obj = { baz: 'Initial' }; - let count = 0; + set(obj, 'bar', 'BIFF'); + assert.equal(barCount, 1, 'barCount should have fired'); + assert.equal(fooCount, 1, 'foo should have fired'); + } - defineProperty(obj, 'foo', computed(function() { - return get(this, 'bar').toLowerCase(); - }).property('bar')); + ['@test removing an chain observer on change should not fail'](assert) { + let foo = { bar: 'bar' }; + let obj1 = { foo: foo }; + let obj2 = { foo: foo }; + let obj3 = { foo: foo }; + let obj4 = { foo: foo }; + let count1 = 0; + let count2 = 0; + let count3 = 0; + let count4 = 0; + + function observer1() { + count1++; + } + function observer2() { + count2++; + } + function observer3() { + count3++; + removeObserver(obj1, 'foo.bar', observer1); + removeObserver(obj2, 'foo.bar', observer2); + removeObserver(obj4, 'foo.bar', observer4); + } + function observer4() { + count4++; + } - defineProperty(obj, 'bar', computed(function() { - return get(this, 'baz').toUpperCase(); - }).property('baz')); + addObserver(obj1, 'foo.bar', observer1); + addObserver(obj2, 'foo.bar', observer2); + addObserver(obj3, 'foo.bar', observer3); + addObserver(obj4, 'foo.bar', observer4); - mixin(obj, { - fooAndBarWatcher: observer('{foo,bar}', function () { - count++; - }) - }); + set(foo, 'bar', 'baz'); - get(obj, 'foo'); - set(obj, 'baz', 'Baz'); - // fire once for foo, once for bar - assert.equal(count, 2, 'observer specified via brace expansion invoked on dependent property change'); + assert.equal(count1, 1, 'observer1 fired'); + assert.equal(count2, 1, 'observer2 fired'); + assert.equal(count3, 1, 'observer3 fired'); + assert.equal(count4, 0, 'observer4 did not fire'); + } - set(obj, 'quux', 'Quux'); - assert.equal(count, 2, 'observer not fired on unspecified property'); - } + ['@test deferring property change notifications'](assert) { + let obj = { foo: 'foo' }; + let fooCount = 0; - ['@test nested observers should fire in order'](assert) { - let obj = { foo: 'foo', bar: 'bar' }; - let fooCount = 0; - let barCount = 0; + addObserver(obj, 'foo', function() { + fooCount++; + }); - addObserver(obj, 'foo', function() { fooCount++; }); - addObserver(obj, 'bar', function() { + beginPropertyChanges(obj); + set(obj, 'foo', 'BIFF'); set(obj, 'foo', 'BAZ'); - assert.equal(fooCount, 1, 'fooCount should have fired already'); - barCount++; - }); - - set(obj, 'bar', 'BIFF'); - assert.equal(barCount, 1, 'barCount should have fired'); - assert.equal(fooCount, 1, 'foo should have fired'); - } - - ['@test removing an chain observer on change should not fail'](assert) { - let foo = { bar: 'bar' }; - let obj1 = { foo: foo }; - let obj2 = { foo: foo }; - let obj3 = { foo: foo }; - let obj4 = { foo: foo }; - let count1 = 0; - let count2 = 0; - let count3 = 0; - let count4 = 0; - - function observer1() { count1++; } - function observer2() { count2++; } - function observer3() { - count3++; - removeObserver(obj1, 'foo.bar', observer1); - removeObserver(obj2, 'foo.bar', observer2); - removeObserver(obj4, 'foo.bar', observer4); - } - function observer4() { count4++; } - - addObserver(obj1, 'foo.bar', observer1); - addObserver(obj2, 'foo.bar', observer2); - addObserver(obj3, 'foo.bar', observer3); - addObserver(obj4, 'foo.bar', observer4); - - set(foo, 'bar', 'baz'); - - assert.equal(count1, 1, 'observer1 fired'); - assert.equal(count2, 1, 'observer2 fired'); - assert.equal(count3, 1, 'observer3 fired'); - assert.equal(count4, 0, 'observer4 did not fire'); - } - - ['@test deferring property change notifications'](assert) { - let obj = { foo: 'foo' }; - let fooCount = 0; + endPropertyChanges(obj); - addObserver(obj, 'foo', function() { fooCount++; }); + assert.equal(fooCount, 1, 'foo should have fired once'); + } - beginPropertyChanges(obj); - set(obj, 'foo', 'BIFF'); - set(obj, 'foo', 'BAZ'); - endPropertyChanges(obj); + ['@test deferring property change notifications safely despite exceptions']( + assert + ) { + let obj = { foo: 'foo' }; + let fooCount = 0; + let exc = new Error('Something unexpected happened!'); - assert.equal(fooCount, 1, 'foo should have fired once'); - } + assert.expect(2); + addObserver(obj, 'foo', function() { + fooCount++; + }); - ['@test deferring property change notifications safely despite exceptions'](assert) { - let obj = { foo: 'foo' }; - let fooCount = 0; - let exc = new Error('Something unexpected happened!'); + try { + changeProperties(function() { + set(obj, 'foo', 'BIFF'); + set(obj, 'foo', 'BAZ'); + throw exc; + }); + } catch (err) { + if (err !== exc) { + throw err; + } + } - assert.expect(2); - addObserver(obj, 'foo', function() { fooCount++; }); + assert.equal(fooCount, 1, 'foo should have fired once'); - try { changeProperties(function() { - set(obj, 'foo', 'BIFF'); - set(obj, 'foo', 'BAZ'); - throw exc; + set(obj, 'foo', 'BIFF2'); + set(obj, 'foo', 'BAZ2'); }); - } catch (err) { - if (err !== exc) { - throw err; - } - } - - assert.equal(fooCount, 1, 'foo should have fired once'); - - changeProperties(function() { - set(obj, 'foo', 'BIFF2'); - set(obj, 'foo', 'BAZ2'); - }); - - assert.equal(fooCount, 2, 'foo should have fired again once'); - } - ['@test addObserver should propagate through prototype'](assert) { - let obj = { foo: 'foo', count: 0 }; - let obj2; - - addObserver(obj, 'foo', function() { this.count++; }); - obj2 = Object.create(obj); + assert.equal(fooCount, 2, 'foo should have fired again once'); + } - set(obj2, 'foo', 'bar'); + ['@test addObserver should propagate through prototype'](assert) { + let obj = { foo: 'foo', count: 0 }; + let obj2; - assert.equal(obj2.count, 1, 'should have invoked observer on inherited'); - assert.equal(obj.count, 0, 'should not have invoked observer on parent'); + addObserver(obj, 'foo', function() { + this.count++; + }); + obj2 = Object.create(obj); - obj2.count = 0; - set(obj, 'foo', 'baz'); - assert.equal(obj.count, 1, 'should have invoked observer on parent'); - assert.equal(obj2.count, 0, 'should not have invoked observer on inherited'); - } + set(obj2, 'foo', 'bar'); - ['@test addObserver should respect targets with methods'](assert) { - let observed = { foo: 'foo' }; + assert.equal(obj2.count, 1, 'should have invoked observer on inherited'); + assert.equal(obj.count, 0, 'should not have invoked observer on parent'); - let target1 = { - count: 0, + obj2.count = 0; + set(obj, 'foo', 'baz'); + assert.equal(obj.count, 1, 'should have invoked observer on parent'); + assert.equal( + obj2.count, + 0, + 'should not have invoked observer on inherited' + ); + } - didChange(obj, keyName) { - let value = get(obj, keyName); - assert.equal(this, target1, 'should invoke with this'); - assert.equal(obj, observed, 'param1 should be observed object'); - assert.equal(keyName, 'foo', 'param2 should be keyName'); - assert.equal(value, 'BAZ', 'param3 should new value'); - this.count++; - } - }; + ['@test addObserver should respect targets with methods'](assert) { + let observed = { foo: 'foo' }; - let target2 = { - count: 0, + let target1 = { + count: 0, - didChange(obj, keyName) { - let value = get(obj, keyName); - assert.equal(this, target2, 'should invoke with this'); - assert.equal(obj, observed, 'param1 should be observed object'); - assert.equal(keyName, 'foo', 'param2 should be keyName'); - assert.equal(value, 'BAZ', 'param3 should new value'); - this.count++; - } - }; + didChange(obj, keyName) { + let value = get(obj, keyName); + assert.equal(this, target1, 'should invoke with this'); + assert.equal(obj, observed, 'param1 should be observed object'); + assert.equal(keyName, 'foo', 'param2 should be keyName'); + assert.equal(value, 'BAZ', 'param3 should new value'); + this.count++; + } + }; + + let target2 = { + count: 0, + + didChange(obj, keyName) { + let value = get(obj, keyName); + assert.equal(this, target2, 'should invoke with this'); + assert.equal(obj, observed, 'param1 should be observed object'); + assert.equal(keyName, 'foo', 'param2 should be keyName'); + assert.equal(value, 'BAZ', 'param3 should new value'); + this.count++; + } + }; - addObserver(observed, 'foo', target1, 'didChange'); - addObserver(observed, 'foo', target2, target2.didChange); + addObserver(observed, 'foo', target1, 'didChange'); + addObserver(observed, 'foo', target2, target2.didChange); - set(observed, 'foo', 'BAZ'); - assert.equal(target1.count, 1, 'target1 observer should have fired'); - assert.equal(target2.count, 1, 'target2 observer should have fired'); - } + set(observed, 'foo', 'BAZ'); + assert.equal(target1.count, 1, 'target1 observer should have fired'); + assert.equal(target2.count, 1, 'target2 observer should have fired'); + } - ['@test addObserver should allow multiple objects to observe a property'](assert) { - let observed = { foo: 'foo' }; + ['@test addObserver should allow multiple objects to observe a property']( + assert + ) { + let observed = { foo: 'foo' }; - let target1 = { - count: 0, + let target1 = { + count: 0, - didChange() { - this.count++; - } - }; + didChange() { + this.count++; + } + }; - let target2 = { - count: 0, + let target2 = { + count: 0, - didChange() { - this.count++; - } - }; + didChange() { + this.count++; + } + }; - addObserver(observed, 'foo', target1, 'didChange'); - addObserver(observed, 'foo', target2, 'didChange'); + addObserver(observed, 'foo', target1, 'didChange'); + addObserver(observed, 'foo', target2, 'didChange'); - set(observed, 'foo', 'BAZ'); - assert.equal(target1.count, 1, 'target1 observer should have fired'); - assert.equal(target2.count, 1, 'target2 observer should have fired'); + set(observed, 'foo', 'BAZ'); + assert.equal(target1.count, 1, 'target1 observer should have fired'); + assert.equal(target2.count, 1, 'target2 observer should have fired'); + } } -}); +); // .......................................................... // REMOVE OBSERVER // -moduleFor('removeObserver', class extends AbstractTestCase { - ['@test removing observer should stop firing'](assert) { - let obj = {}; - let count = 0; - function F() { count++; } - addObserver(obj, 'foo', F); +moduleFor( + 'removeObserver', + class extends AbstractTestCase { + ['@test removing observer should stop firing'](assert) { + let obj = {}; + let count = 0; + function F() { + count++; + } + addObserver(obj, 'foo', F); - set(obj, 'foo', 'bar'); - assert.equal(count, 1, 'should have invoked observer'); + set(obj, 'foo', 'bar'); + assert.equal(count, 1, 'should have invoked observer'); - removeObserver(obj, 'foo', F); + removeObserver(obj, 'foo', F); - set(obj, 'foo', 'baz'); - assert.equal(count, 1, 'removed observer shouldn\'t fire'); - } + set(obj, 'foo', 'baz'); + assert.equal(count, 1, "removed observer shouldn't fire"); + } - ['@test local observers can be removed'](assert) { - let barObserved = 0; + ['@test local observers can be removed'](assert) { + let barObserved = 0; - let MyMixin = Mixin.create({ - foo1: observer('bar', function() { - barObserved++; - }), + let MyMixin = Mixin.create({ + foo1: observer('bar', function() { + barObserved++; + }), - foo2: observer('bar', function() { - barObserved++; - }) - }); + foo2: observer('bar', function() { + barObserved++; + }) + }); - let obj = {}; - MyMixin.apply(obj); + let obj = {}; + MyMixin.apply(obj); - set(obj, 'bar', 'HI!'); - assert.equal(barObserved, 2, 'precond - observers should be fired'); + set(obj, 'bar', 'HI!'); + assert.equal(barObserved, 2, 'precond - observers should be fired'); - removeObserver(obj, 'bar', null, 'foo1'); + removeObserver(obj, 'bar', null, 'foo1'); - barObserved = 0; - set(obj, 'bar', 'HI AGAIN!'); + barObserved = 0; + set(obj, 'bar', 'HI AGAIN!'); - assert.equal(barObserved, 1, 'removed observers should not be called'); - } + assert.equal(barObserved, 1, 'removed observers should not be called'); + } - ['@test removeObserver should respect targets with methods'](assert) { - let observed = { foo: 'foo' }; + ['@test removeObserver should respect targets with methods'](assert) { + let observed = { foo: 'foo' }; - let target1 = { - count: 0, + let target1 = { + count: 0, - didChange() { - this.count++; - } - }; + didChange() { + this.count++; + } + }; - let target2 = { - count: 0, + let target2 = { + count: 0, - didChange() { - this.count++; - } - }; + didChange() { + this.count++; + } + }; - addObserver(observed, 'foo', target1, 'didChange'); - addObserver(observed, 'foo', target2, target2.didChange); + addObserver(observed, 'foo', target1, 'didChange'); + addObserver(observed, 'foo', target2, target2.didChange); - set(observed, 'foo', 'BAZ'); - assert.equal(target1.count, 1, 'target1 observer should have fired'); - assert.equal(target2.count, 1, 'target2 observer should have fired'); + set(observed, 'foo', 'BAZ'); + assert.equal(target1.count, 1, 'target1 observer should have fired'); + assert.equal(target2.count, 1, 'target2 observer should have fired'); - removeObserver(observed, 'foo', target1, 'didChange'); - removeObserver(observed, 'foo', target2, target2.didChange); + removeObserver(observed, 'foo', target1, 'didChange'); + removeObserver(observed, 'foo', target2, target2.didChange); - target1.count = target2.count = 0; - set(observed, 'foo', 'BAZ'); - assert.equal(target1.count, 0, 'target1 observer should not fire again'); - assert.equal(target2.count, 0, 'target2 observer should not fire again'); + target1.count = target2.count = 0; + set(observed, 'foo', 'BAZ'); + assert.equal(target1.count, 0, 'target1 observer should not fire again'); + assert.equal(target2.count, 0, 'target2 observer should not fire again'); + } } -}); +); // .......................................................... // CHAINED OBSERVERS @@ -452,363 +558,452 @@ moduleFor('removeObserver', class extends AbstractTestCase { let obj, count; -moduleFor('addObserver - dependentkey with chained properties', class extends AbstractTestCase { - beforeEach() { - obj = { - foo: { - bar: { - baz: { - biff: 'BIFF' - } - } - }, - Capital: { +moduleFor( + 'addObserver - dependentkey with chained properties', + class extends AbstractTestCase { + beforeEach() { + obj = { foo: { bar: { baz: { biff: 'BIFF' } } + }, + Capital: { + foo: { + bar: { + baz: { + biff: 'BIFF' + } + } + } } - } - }; - - count = 0; - } + }; - afterEach() { - obj = count = null; - } + count = 0; + } - ['@test depending on a chain with a computed property'](assert) { - defineProperty(obj, 'computed', computed(function () { - return { foo: 'bar' }; - })); + afterEach() { + obj = count = null; + } - let changed = 0; - addObserver(obj, 'computed.foo', function () { - changed++; - }); + ['@test depending on a chain with a computed property'](assert) { + defineProperty( + obj, + 'computed', + computed(function() { + return { foo: 'bar' }; + }) + ); + + let changed = 0; + addObserver(obj, 'computed.foo', function() { + changed++; + }); - assert.equal(getCachedValueFor(obj, 'computed'), undefined, 'addObserver should not compute CP'); + assert.equal( + getCachedValueFor(obj, 'computed'), + undefined, + 'addObserver should not compute CP' + ); - set(obj, 'computed.foo', 'baz'); + set(obj, 'computed.foo', 'baz'); - assert.equal(changed, 1, 'should fire observer'); - } + assert.equal(changed, 1, 'should fire observer'); + } - ['@test depending on a simple chain'](assert) { - let val; - addObserver(obj, 'foo.bar.baz.biff', function(target, key) { - val = get(target, key); - count++; - }); + ['@test depending on a simple chain'](assert) { + let val; + addObserver(obj, 'foo.bar.baz.biff', function(target, key) { + val = get(target, key); + count++; + }); - set(get(obj, 'foo.bar.baz'), 'biff', 'BUZZ'); - assert.equal(val, 'BUZZ'); - assert.equal(count, 1); + set(get(obj, 'foo.bar.baz'), 'biff', 'BUZZ'); + assert.equal(val, 'BUZZ'); + assert.equal(count, 1); - set(get(obj, 'foo.bar'), 'baz', { biff: 'BLARG' }); - assert.equal(val, 'BLARG'); - assert.equal(count, 2); + set(get(obj, 'foo.bar'), 'baz', { biff: 'BLARG' }); + assert.equal(val, 'BLARG'); + assert.equal(count, 2); - set(get(obj, 'foo'), 'bar', { baz: { biff: 'BOOM' } }); - assert.equal(val, 'BOOM'); - assert.equal(count, 3); + set(get(obj, 'foo'), 'bar', { baz: { biff: 'BOOM' } }); + assert.equal(val, 'BOOM'); + assert.equal(count, 3); - set(obj, 'foo', { bar: { baz: { biff: 'BLARG' } } }); - assert.equal(val, 'BLARG'); - assert.equal(count, 4); + set(obj, 'foo', { bar: { baz: { biff: 'BLARG' } } }); + assert.equal(val, 'BLARG'); + assert.equal(count, 4); - set(get(obj, 'foo.bar.baz'), 'biff', 'BUZZ'); - assert.equal(val, 'BUZZ'); - assert.equal(count, 5); + set(get(obj, 'foo.bar.baz'), 'biff', 'BUZZ'); + assert.equal(val, 'BUZZ'); + assert.equal(count, 5); - let foo = get(obj, 'foo'); + let foo = get(obj, 'foo'); - set(obj, 'foo', 'BOO'); - assert.equal(val, undefined); - assert.equal(count, 6); + set(obj, 'foo', 'BOO'); + assert.equal(val, undefined); + assert.equal(count, 6); - set(foo.bar.baz, 'biff', 'BOOM'); - assert.equal(count, 6, 'should be not have invoked observer'); - } + set(foo.bar.baz, 'biff', 'BOOM'); + assert.equal(count, 6, 'should be not have invoked observer'); + } - ['@test depending on a chain with a capitalized first key'](assert) { - let val; + ['@test depending on a chain with a capitalized first key'](assert) { + let val; - addObserver(obj, 'Capital.foo.bar.baz.biff', function(target, key) { - val = get(obj, key); - count++; - }); + addObserver(obj, 'Capital.foo.bar.baz.biff', function(target, key) { + val = get(obj, key); + count++; + }); - set(get(obj, 'Capital.foo.bar.baz'), 'biff', 'BUZZ'); - assert.equal(val, 'BUZZ'); - assert.equal(count, 1); + set(get(obj, 'Capital.foo.bar.baz'), 'biff', 'BUZZ'); + assert.equal(val, 'BUZZ'); + assert.equal(count, 1); - set(get(obj, 'Capital.foo.bar'), 'baz', { biff: 'BLARG' }); - assert.equal(val, 'BLARG'); - assert.equal(count, 2); + set(get(obj, 'Capital.foo.bar'), 'baz', { biff: 'BLARG' }); + assert.equal(val, 'BLARG'); + assert.equal(count, 2); - set(get(obj, 'Capital.foo'), 'bar', { baz: { biff: 'BOOM' } }); - assert.equal(val, 'BOOM'); - assert.equal(count, 3); + set(get(obj, 'Capital.foo'), 'bar', { baz: { biff: 'BOOM' } }); + assert.equal(val, 'BOOM'); + assert.equal(count, 3); - set(obj, 'Capital.foo', { bar: { baz: { biff: 'BLARG' } } }); - assert.equal(val, 'BLARG'); - assert.equal(count, 4); + set(obj, 'Capital.foo', { bar: { baz: { biff: 'BLARG' } } }); + assert.equal(val, 'BLARG'); + assert.equal(count, 4); - set(get(obj, 'Capital.foo.bar.baz'), 'biff', 'BUZZ'); - assert.equal(val, 'BUZZ'); - assert.equal(count, 5); + set(get(obj, 'Capital.foo.bar.baz'), 'biff', 'BUZZ'); + assert.equal(val, 'BUZZ'); + assert.equal(count, 5); - let foo = get(obj, 'foo'); + let foo = get(obj, 'foo'); - set(obj, 'Capital.foo', 'BOO'); - assert.equal(val, undefined); - assert.equal(count, 6); + set(obj, 'Capital.foo', 'BOO'); + assert.equal(val, undefined); + assert.equal(count, 6); - set(foo.bar.baz, 'biff', 'BOOM'); - assert.equal(count, 6, 'should be not have invoked observer'); + set(foo.bar.baz, 'biff', 'BOOM'); + assert.equal(count, 6, 'should be not have invoked observer'); + } } -}); +); // .......................................................... // SETTING IDENTICAL VALUES // -moduleFor('props/observer_test - setting identical values', class extends AbstractTestCase { - ['@test setting simple prop should not trigger'](assert) { - let obj = { foo: 'bar' }; - let count = 0; - - addObserver(obj, 'foo', function() { count++; }); +moduleFor( + 'props/observer_test - setting identical values', + class extends AbstractTestCase { + ['@test setting simple prop should not trigger'](assert) { + let obj = { foo: 'bar' }; + let count = 0; - set(obj, 'foo', 'bar'); - assert.equal(count, 0, 'should not trigger observer'); + addObserver(obj, 'foo', function() { + count++; + }); - set(obj, 'foo', 'baz'); - assert.equal(count, 1, 'should trigger observer'); + set(obj, 'foo', 'bar'); + assert.equal(count, 0, 'should not trigger observer'); - set(obj, 'foo', 'baz'); - assert.equal(count, 1, 'should not trigger observer again'); - } + set(obj, 'foo', 'baz'); + assert.equal(count, 1, 'should trigger observer'); - // The issue here is when a computed property is directly set with a value, then has a - // dependent key change (which triggers a cache expiration and recomputation), observers will - // not be fired if the CP setter is called with the last set value. - ['@test setting a cached computed property whose value has changed should trigger'](assert) { - let obj = {}; + set(obj, 'foo', 'baz'); + assert.equal(count, 1, 'should not trigger observer again'); + } - defineProperty(obj, 'foo', computed({ - get: function() { return get(this, 'baz'); }, - set: function(key, value) { return value; } - }).property('baz')); + // The issue here is when a computed property is directly set with a value, then has a + // dependent key change (which triggers a cache expiration and recomputation), observers will + // not be fired if the CP setter is called with the last set value. + ['@test setting a cached computed property whose value has changed should trigger']( + assert + ) { + let obj = {}; + + defineProperty( + obj, + 'foo', + computed({ + get: function() { + return get(this, 'baz'); + }, + set: function(key, value) { + return value; + } + }).property('baz') + ); - let count = 0; + let count = 0; - addObserver(obj, 'foo', function() { count++; }); + addObserver(obj, 'foo', function() { + count++; + }); - set(obj, 'foo', 'bar'); - assert.equal(count, 1); - assert.equal(get(obj, 'foo'), 'bar'); + set(obj, 'foo', 'bar'); + assert.equal(count, 1); + assert.equal(get(obj, 'foo'), 'bar'); - set(obj, 'baz', 'qux'); - assert.equal(count, 2); - assert.equal(get(obj, 'foo'), 'qux'); + set(obj, 'baz', 'qux'); + assert.equal(count, 2); + assert.equal(get(obj, 'foo'), 'qux'); - get(obj, 'foo'); - set(obj, 'foo', 'bar'); - assert.equal(count, 3); - assert.equal(get(obj, 'foo'), 'bar'); + get(obj, 'foo'); + set(obj, 'foo', 'bar'); + assert.equal(count, 3); + assert.equal(get(obj, 'foo'), 'bar'); + } } -}); - -moduleFor('changeProperties', class extends AbstractTestCase { - ['@test observers added/removed during changeProperties should do the right thing.'](assert) { - let obj = { - foo: 0 - }; - function Observer() { - this.didChangeCount = 0; - } - Observer.prototype = { - add() { - addObserver(obj, 'foo', this, 'didChange'); - }, - remove() { - removeObserver(obj, 'foo', this, 'didChange'); - }, - didChange() { - this.didChangeCount++; +); + +moduleFor( + 'changeProperties', + class extends AbstractTestCase { + ['@test observers added/removed during changeProperties should do the right thing.']( + assert + ) { + let obj = { + foo: 0 + }; + function Observer() { + this.didChangeCount = 0; } - }; - let addedBeforeFirstChangeObserver = new Observer(); - let addedAfterFirstChangeObserver = new Observer(); - let addedAfterLastChangeObserver = new Observer(); - let removedBeforeFirstChangeObserver = new Observer(); - let removedBeforeLastChangeObserver = new Observer(); - let removedAfterLastChangeObserver = new Observer(); - removedBeforeFirstChangeObserver.add(); - removedBeforeLastChangeObserver.add(); - removedAfterLastChangeObserver.add(); - changeProperties(function () { - removedBeforeFirstChangeObserver.remove(); - addedBeforeFirstChangeObserver.add(); - - set(obj, 'foo', 1); - - assert.equal(addedBeforeFirstChangeObserver.didChangeCount, 0, 'addObserver called before the first change is deferred'); - - addedAfterFirstChangeObserver.add(); - removedBeforeLastChangeObserver.remove(); - - set(obj, 'foo', 2); - - assert.equal(addedAfterFirstChangeObserver.didChangeCount, 0, 'addObserver called after the first change is deferred'); - - addedAfterLastChangeObserver.add(); - removedAfterLastChangeObserver.remove(); - }); - - assert.equal(removedBeforeFirstChangeObserver.didChangeCount, 0, 'removeObserver called before the first change sees none'); - assert.equal(addedBeforeFirstChangeObserver.didChangeCount, 1, 'addObserver called before the first change sees only 1'); - assert.equal(addedAfterFirstChangeObserver.didChangeCount, 1, 'addObserver called after the first change sees 1'); - assert.equal(addedAfterLastChangeObserver.didChangeCount, 1, 'addObserver called after the last change sees 1'); - assert.equal(removedBeforeLastChangeObserver.didChangeCount, 0, 'removeObserver called before the last change sees none'); - assert.equal(removedAfterLastChangeObserver.didChangeCount, 0, 'removeObserver called after the last change sees none'); - } + Observer.prototype = { + add() { + addObserver(obj, 'foo', this, 'didChange'); + }, + remove() { + removeObserver(obj, 'foo', this, 'didChange'); + }, + didChange() { + this.didChangeCount++; + } + }; + let addedBeforeFirstChangeObserver = new Observer(); + let addedAfterFirstChangeObserver = new Observer(); + let addedAfterLastChangeObserver = new Observer(); + let removedBeforeFirstChangeObserver = new Observer(); + let removedBeforeLastChangeObserver = new Observer(); + let removedAfterLastChangeObserver = new Observer(); + removedBeforeFirstChangeObserver.add(); + removedBeforeLastChangeObserver.add(); + removedAfterLastChangeObserver.add(); + changeProperties(function() { + removedBeforeFirstChangeObserver.remove(); + addedBeforeFirstChangeObserver.add(); - ['@test calling changeProperties while executing deferred observers works correctly'](assert) { - let obj = { foo: 0 }; - let fooDidChange = 0; + set(obj, 'foo', 1); - addObserver(obj, 'foo', () => { - fooDidChange++; - changeProperties(() => {}); - }); + assert.equal( + addedBeforeFirstChangeObserver.didChangeCount, + 0, + 'addObserver called before the first change is deferred' + ); - changeProperties(() => { - set(obj, 'foo', 1); - }); + addedAfterFirstChangeObserver.add(); + removedBeforeLastChangeObserver.remove(); - assert.equal(fooDidChange, 1); - } -}); + set(obj, 'foo', 2); -moduleFor('Keys behavior with observers', class extends AbstractTestCase { - ['@test should not leak properties on the prototype'](assert) { - function Beer() { } - Beer.prototype.type = 'ipa'; + assert.equal( + addedAfterFirstChangeObserver.didChangeCount, + 0, + 'addObserver called after the first change is deferred' + ); - let beer = new Beer(); + addedAfterLastChangeObserver.add(); + removedAfterLastChangeObserver.remove(); + }); - addObserver(beer, 'type', K); - assert.deepEqual(Object.keys(beer), []); - removeObserver(beer, 'type', K); - } + assert.equal( + removedBeforeFirstChangeObserver.didChangeCount, + 0, + 'removeObserver called before the first change sees none' + ); + assert.equal( + addedBeforeFirstChangeObserver.didChangeCount, + 1, + 'addObserver called before the first change sees only 1' + ); + assert.equal( + addedAfterFirstChangeObserver.didChangeCount, + 1, + 'addObserver called after the first change sees 1' + ); + assert.equal( + addedAfterLastChangeObserver.didChangeCount, + 1, + 'addObserver called after the last change sees 1' + ); + assert.equal( + removedBeforeLastChangeObserver.didChangeCount, + 0, + 'removeObserver called before the last change sees none' + ); + assert.equal( + removedAfterLastChangeObserver.didChangeCount, + 0, + 'removeObserver called after the last change sees none' + ); + } + + ['@test calling changeProperties while executing deferred observers works correctly']( + assert + ) { + let obj = { foo: 0 }; + let fooDidChange = 0; - ['@test observing a non existent property'](assert) { - function Beer() { } - Beer.prototype.type = 'ipa'; + addObserver(obj, 'foo', () => { + fooDidChange++; + changeProperties(() => {}); + }); - let beer = new Beer(); + changeProperties(() => { + set(obj, 'foo', 1); + }); - addObserver(beer, 'brand', K); + assert.equal(fooDidChange, 1); + } + } +); - assert.deepEqual(Object.keys(beer), []); +moduleFor( + 'Keys behavior with observers', + class extends AbstractTestCase { + ['@test should not leak properties on the prototype'](assert) { + function Beer() {} + Beer.prototype.type = 'ipa'; - set(beer, 'brand', 'Corona'); - assert.deepEqual(Object.keys(beer), ['brand']); + let beer = new Beer(); - removeObserver(beer, 'brand', K); - } + addObserver(beer, 'type', K); + assert.deepEqual(Object.keys(beer), []); + removeObserver(beer, 'type', K); + } - ['@test with observers switched on and off'](assert) { - function Beer() { } - Beer.prototype.type = 'ipa'; + ['@test observing a non existent property'](assert) { + function Beer() {} + Beer.prototype.type = 'ipa'; - let beer = new Beer(); + let beer = new Beer(); - addObserver(beer, 'type', K); - removeObserver(beer, 'type', K); + addObserver(beer, 'brand', K); - assert.deepEqual(Object.keys(beer), []); - } + assert.deepEqual(Object.keys(beer), []); - ['@test observers switched on and off with setter in between'](assert) { - function Beer() { } - Beer.prototype.type = 'ipa'; + set(beer, 'brand', 'Corona'); + assert.deepEqual(Object.keys(beer), ['brand']); - let beer = new Beer(); + removeObserver(beer, 'brand', K); + } - addObserver(beer, 'type', K); - set(beer, 'type', 'ale'); - removeObserver(beer, 'type', K); + ['@test with observers switched on and off'](assert) { + function Beer() {} + Beer.prototype.type = 'ipa'; - assert.deepEqual(Object.keys(beer), ['type']); - } + let beer = new Beer(); - ['@test observer switched on and off and then setter'](assert) { - function Beer() { } - Beer.prototype.type = 'ipa'; + addObserver(beer, 'type', K); + removeObserver(beer, 'type', K); - let beer = new Beer(); + assert.deepEqual(Object.keys(beer), []); + } - addObserver(beer, 'type', K); - removeObserver(beer, 'type', K); - set(beer, 'type', 'ale'); + ['@test observers switched on and off with setter in between'](assert) { + function Beer() {} + Beer.prototype.type = 'ipa'; - assert.deepEqual(Object.keys(beer), ['type']); - } + let beer = new Beer(); - ['@test observers switched on and off with setter in between (observed property is not shadowing)'](assert) { - function Beer() { } + addObserver(beer, 'type', K); + set(beer, 'type', 'ale'); + removeObserver(beer, 'type', K); - let beer = new Beer(); - set(beer, 'type', 'ale'); - assert.deepEqual(Object.keys(beer), ['type'], 'only set'); + assert.deepEqual(Object.keys(beer), ['type']); + } - let otherBeer = new Beer(); - addObserver(otherBeer, 'type', K); - set(otherBeer, 'type', 'ale'); - assert.deepEqual(Object.keys(otherBeer), ['type'], 'addObserver -> set'); + ['@test observer switched on and off and then setter'](assert) { + function Beer() {} + Beer.prototype.type = 'ipa'; - let yetAnotherBeer = new Beer(); - addObserver(yetAnotherBeer, 'type', K); - set(yetAnotherBeer, 'type', 'ale'); - removeObserver(beer, 'type', K); - assert.deepEqual(Object.keys(yetAnotherBeer), ['type'], 'addObserver -> set -> removeObserver'); + let beer = new Beer(); - let itsMyLastBeer = new Beer(); - set(itsMyLastBeer, 'type', 'ale'); - removeObserver(beer, 'type', K); - assert.deepEqual(Object.keys(itsMyLastBeer), ['type'], 'set -> removeObserver'); - } + addObserver(beer, 'type', K); + removeObserver(beer, 'type', K); + set(beer, 'type', 'ale'); - ['@test observers switched on and off with setter in between (observed property is shadowing one on the prototype)'](assert) { - function Beer() { } - Beer.prototype.type = 'ipa'; - - let beer = new Beer(); - set(beer, 'type', 'ale'); - assert.deepEqual(Object.keys(beer), ['type'], 'after set'); - - let otherBeer = new Beer(); - addObserver(otherBeer, 'type', K); - set(otherBeer, 'type', 'ale'); - assert.deepEqual(Object.keys(otherBeer), ['type'], 'addObserver -> set'); - - let yetAnotherBeer = new Beer(); - addObserver(yetAnotherBeer, 'type', K); - set(yetAnotherBeer, 'type', 'ale'); - removeObserver(beer, 'type', K); - assert.deepEqual(Object.keys(yetAnotherBeer), ['type'], 'addObserver -> set -> removeObserver'); - - let itsMyLastBeer = new Beer(); - set(itsMyLastBeer, 'type', 'ale'); - removeObserver(beer, 'type', K); - assert.deepEqual(Object.keys(itsMyLastBeer), ['type'], 'set -> removeObserver'); - } -}); + assert.deepEqual(Object.keys(beer), ['type']); + } + ['@test observers switched on and off with setter in between (observed property is not shadowing)']( + assert + ) { + function Beer() {} + + let beer = new Beer(); + set(beer, 'type', 'ale'); + assert.deepEqual(Object.keys(beer), ['type'], 'only set'); + + let otherBeer = new Beer(); + addObserver(otherBeer, 'type', K); + set(otherBeer, 'type', 'ale'); + assert.deepEqual(Object.keys(otherBeer), ['type'], 'addObserver -> set'); + + let yetAnotherBeer = new Beer(); + addObserver(yetAnotherBeer, 'type', K); + set(yetAnotherBeer, 'type', 'ale'); + removeObserver(beer, 'type', K); + assert.deepEqual( + Object.keys(yetAnotherBeer), + ['type'], + 'addObserver -> set -> removeObserver' + ); + + let itsMyLastBeer = new Beer(); + set(itsMyLastBeer, 'type', 'ale'); + removeObserver(beer, 'type', K); + assert.deepEqual( + Object.keys(itsMyLastBeer), + ['type'], + 'set -> removeObserver' + ); + } + + ['@test observers switched on and off with setter in between (observed property is shadowing one on the prototype)']( + assert + ) { + function Beer() {} + Beer.prototype.type = 'ipa'; + + let beer = new Beer(); + set(beer, 'type', 'ale'); + assert.deepEqual(Object.keys(beer), ['type'], 'after set'); + + let otherBeer = new Beer(); + addObserver(otherBeer, 'type', K); + set(otherBeer, 'type', 'ale'); + assert.deepEqual(Object.keys(otherBeer), ['type'], 'addObserver -> set'); + + let yetAnotherBeer = new Beer(); + addObserver(yetAnotherBeer, 'type', K); + set(yetAnotherBeer, 'type', 'ale'); + removeObserver(beer, 'type', K); + assert.deepEqual( + Object.keys(yetAnotherBeer), + ['type'], + 'addObserver -> set -> removeObserver' + ); + + let itsMyLastBeer = new Beer(); + set(itsMyLastBeer, 'type', 'ale'); + removeObserver(beer, 'type', K); + assert.deepEqual( + Object.keys(itsMyLastBeer), + ['type'], + 'set -> removeObserver' + ); + } + } +); diff --git a/packages/ember-metal/tests/performance_test.js b/packages/ember-metal/tests/performance_test.js index 9557bb5b536..c6d5f683542 100644 --- a/packages/ember-metal/tests/performance_test.js +++ b/packages/ember-metal/tests/performance_test.js @@ -17,51 +17,65 @@ import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; bugs that cause them to get evaluated more than necessary should be put here. */ -moduleFor('Computed Properties - Number of times evaluated', class extends AbstractTestCase { - ['@test computed properties that depend on multiple properties should run only once per run loop'](assert) { - let obj = { a: 'a', b: 'b', c: 'c' }; - let cpCount = 0; - let obsCount = 0; - - defineProperty(obj, 'abc', computed(function(key) { - cpCount++; - return 'computed ' + key; - }).property('a', 'b', 'c')); - - get(obj, 'abc'); - - cpCount = 0; - - addObserver(obj, 'abc', function() { - obsCount++; - }); - - beginPropertyChanges(); - set(obj, 'a', 'aa'); - set(obj, 'b', 'bb'); - set(obj, 'c', 'cc'); - endPropertyChanges(); - - get(obj, 'abc'); - - assert.equal(cpCount, 1, 'The computed property is only invoked once'); - assert.equal(obsCount, 1, 'The observer is only invoked once'); +moduleFor( + 'Computed Properties - Number of times evaluated', + class extends AbstractTestCase { + ['@test computed properties that depend on multiple properties should run only once per run loop']( + assert + ) { + let obj = { a: 'a', b: 'b', c: 'c' }; + let cpCount = 0; + let obsCount = 0; + + defineProperty( + obj, + 'abc', + computed(function(key) { + cpCount++; + return 'computed ' + key; + }).property('a', 'b', 'c') + ); + + get(obj, 'abc'); + + cpCount = 0; + + addObserver(obj, 'abc', function() { + obsCount++; + }); + + beginPropertyChanges(); + set(obj, 'a', 'aa'); + set(obj, 'b', 'bb'); + set(obj, 'c', 'cc'); + endPropertyChanges(); + + get(obj, 'abc'); + + assert.equal(cpCount, 1, 'The computed property is only invoked once'); + assert.equal(obsCount, 1, 'The observer is only invoked once'); + } + + ['@test computed properties are not executed if they are the last segment of an observer chain pain']( + assert + ) { + let foo = { bar: { baz: {} } }; + + let count = 0; + + defineProperty( + foo.bar.baz, + 'bam', + computed(function() { + count++; + }) + ); + + addObserver(foo, 'bar.baz.bam', function() {}); + + notifyPropertyChange(get(foo, 'bar.baz'), 'bam'); + + assert.equal(count, 0, 'should not have recomputed property'); + } } - - ['@test computed properties are not executed if they are the last segment of an observer chain pain'](assert) { - let foo = { bar: { baz: { } } }; - - let count = 0; - - defineProperty(foo.bar.baz, 'bam', computed(function() { - count++; - })); - - addObserver(foo, 'bar.baz.bam', function() {}); - - notifyPropertyChange(get(foo, 'bar.baz'), 'bam'); - - assert.equal(count, 0, 'should not have recomputed property'); - } -}); - +); diff --git a/packages/ember-metal/tests/properties_test.js b/packages/ember-metal/tests/properties_test.js index 0246dea0432..e6f8984736c 100644 --- a/packages/ember-metal/tests/properties_test.js +++ b/packages/ember-metal/tests/properties_test.js @@ -1,102 +1,126 @@ -import { - computed, - defineProperty, - deprecateProperty -} from '..'; +import { computed, defineProperty, deprecateProperty } from '..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('defineProperty', class extends AbstractTestCase { - ['@test toString'](assert) { - let obj = {}; - defineProperty(obj, 'toString', undefined, function() { return 'FOO'; }); - assert.equal(obj.toString(), 'FOO', 'should replace toString'); - } - - ['@test for data properties, didDefineProperty hook should be called if implemented'](assert) { - assert.expect(2); - - let obj = { - didDefineProperty(obj, keyName, value) { - assert.equal(keyName, 'foo', 'key name should be foo'); - assert.equal(value, 'bar', 'value should be bar'); - } - }; - - defineProperty(obj, 'foo', undefined, 'bar'); - } - - ['@test for computed properties, didDefineProperty hook should be called if implemented'](assert) { - assert.expect(2); - - let computedProperty = computed(function() { return this; }); - - let obj = { - didDefineProperty(obj, keyName, value) { - assert.equal(keyName, 'foo', 'key name should be foo'); - assert.strictEqual(value, computedProperty, 'value should be passed as computed property'); - } - }; +moduleFor( + 'defineProperty', + class extends AbstractTestCase { + ['@test toString'](assert) { + let obj = {}; + defineProperty(obj, 'toString', undefined, function() { + return 'FOO'; + }); + assert.equal(obj.toString(), 'FOO', 'should replace toString'); + } - defineProperty(obj, 'foo', computedProperty); - } + ['@test for data properties, didDefineProperty hook should be called if implemented']( + assert + ) { + assert.expect(2); - ['@test for descriptor properties, didDefineProperty hook should be called if implemented'](assert) { - assert.expect(2); + let obj = { + didDefineProperty(obj, keyName, value) { + assert.equal(keyName, 'foo', 'key name should be foo'); + assert.equal(value, 'bar', 'value should be bar'); + } + }; - let descriptor = { - writable: true, - configurable: false, - enumerable: true, - value: 42 - }; + defineProperty(obj, 'foo', undefined, 'bar'); + } - let obj = { - didDefineProperty(obj, keyName, value) { - assert.equal(keyName, 'answer', 'key name should be answer'); - assert.strictEqual(value, descriptor, 'value should be passed as descriptor'); - } - }; + ['@test for computed properties, didDefineProperty hook should be called if implemented']( + assert + ) { + assert.expect(2); + + let computedProperty = computed(function() { + return this; + }); + + let obj = { + didDefineProperty(obj, keyName, value) { + assert.equal(keyName, 'foo', 'key name should be foo'); + assert.strictEqual( + value, + computedProperty, + 'value should be passed as computed property' + ); + } + }; + + defineProperty(obj, 'foo', computedProperty); + } - defineProperty(obj, 'answer', descriptor); + ['@test for descriptor properties, didDefineProperty hook should be called if implemented']( + assert + ) { + assert.expect(2); + + let descriptor = { + writable: true, + configurable: false, + enumerable: true, + value: 42 + }; + + let obj = { + didDefineProperty(obj, keyName, value) { + assert.equal(keyName, 'answer', 'key name should be answer'); + assert.strictEqual( + value, + descriptor, + 'value should be passed as descriptor' + ); + } + }; + + defineProperty(obj, 'answer', descriptor); + } } -}); +); -moduleFor('Ember.deprecateProperty', class extends AbstractTestCase { - ['@test enables access to deprecated property and returns the value of the new property'](assert) { - assert.expect(3); - let obj = { foo: 'bar' }; +moduleFor( + 'Ember.deprecateProperty', + class extends AbstractTestCase { + ['@test enables access to deprecated property and returns the value of the new property']( + assert + ) { + assert.expect(3); + let obj = { foo: 'bar' }; - deprecateProperty(obj, 'baz', 'foo'); + deprecateProperty(obj, 'baz', 'foo'); - expectDeprecation(); - assert.equal(obj.baz, obj.foo, 'baz and foo are equal'); + expectDeprecation(); + assert.equal(obj.baz, obj.foo, 'baz and foo are equal'); - obj.foo = 'blammo'; - assert.equal(obj.baz, obj.foo, 'baz and foo are equal'); - } + obj.foo = 'blammo'; + assert.equal(obj.baz, obj.foo, 'baz and foo are equal'); + } - ['@test deprecatedKey is not enumerable'](assert) { - assert.expect(2); - let obj = { foo: 'bar', blammo: 'whammy' }; + ['@test deprecatedKey is not enumerable'](assert) { + assert.expect(2); + let obj = { foo: 'bar', blammo: 'whammy' }; - deprecateProperty(obj, 'baz', 'foo'); + deprecateProperty(obj, 'baz', 'foo'); - for (let prop in obj) { - if (obj.hasOwnProperty(prop)) { - assert.notEqual(prop, 'baz'); + for (let prop in obj) { + if (obj.hasOwnProperty(prop)) { + assert.notEqual(prop, 'baz'); + } } } - } - ['@test enables setter to deprecated property and updates the value of the new property'](assert) { - assert.expect(3); - let obj = { foo: 'bar' }; + ['@test enables setter to deprecated property and updates the value of the new property']( + assert + ) { + assert.expect(3); + let obj = { foo: 'bar' }; - deprecateProperty(obj, 'baz', 'foo'); + deprecateProperty(obj, 'baz', 'foo'); - expectDeprecation(); - obj.baz = 'bloop'; - assert.equal(obj.foo, 'bloop', 'updating baz updates foo'); - assert.equal(obj.baz, obj.foo, 'baz and foo are equal'); + expectDeprecation(); + obj.baz = 'bloop'; + assert.equal(obj.foo, 'bloop', 'updating baz updates foo'); + assert.equal(obj.baz, obj.foo, 'baz and foo are equal'); + } } -}); +); diff --git a/packages/ember-metal/tests/property_did_change_hook.js b/packages/ember-metal/tests/property_did_change_hook.js index f6fec2324a5..3310f9ef810 100644 --- a/packages/ember-metal/tests/property_did_change_hook.js +++ b/packages/ember-metal/tests/property_did_change_hook.js @@ -9,61 +9,79 @@ import { } from '..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('PROPERTY_DID_CHANGE', class extends AbstractTestCase { - ['@test alias and cp'](assert) { - let counts = {}; - let obj = { - child: {}, - [PROPERTY_DID_CHANGE](keyName) { - counts[keyName] = (counts[keyName] || 0) + 1; - } - }; +moduleFor( + 'PROPERTY_DID_CHANGE', + class extends AbstractTestCase { + ['@test alias and cp'](assert) { + let counts = {}; + let obj = { + child: {}, + [PROPERTY_DID_CHANGE](keyName) { + counts[keyName] = (counts[keyName] || 0) + 1; + } + }; - defineProperty(obj, 'cost', alias('child.cost')); - defineProperty(obj, 'tax', alias('child.tax')); + defineProperty(obj, 'cost', alias('child.cost')); + defineProperty(obj, 'tax', alias('child.tax')); - defineProperty(obj, 'total', computed('cost', 'tax', { - get() { - return get(this, 'cost') + get(this, 'tax'); - } - })); + defineProperty( + obj, + 'total', + computed('cost', 'tax', { + get() { + return get(this, 'cost') + get(this, 'tax'); + } + }) + ); - assert.ok(!isWatching(obj, 'child.cost'), 'precond alias target `child.cost` is not watched'); - assert.equal(get(obj, 'cost'), undefined); - // this is how PROPERTY_DID_CHANGE will get notified - assert.ok(isWatching(obj, 'child.cost'), 'alias target `child.cost` is watched after consumption'); + assert.ok( + !isWatching(obj, 'child.cost'), + 'precond alias target `child.cost` is not watched' + ); + assert.equal(get(obj, 'cost'), undefined); + // this is how PROPERTY_DID_CHANGE will get notified + assert.ok( + isWatching(obj, 'child.cost'), + 'alias target `child.cost` is watched after consumption' + ); - assert.ok(!isWatching(obj, 'child.tax'), 'precond alias target `child.tax` is not watched'); - assert.equal(get(obj, 'tax'), undefined); - // this is how PROPERTY_DID_CHANGE will get notified - assert.ok(isWatching(obj, 'child.tax'), 'alias target `child.cost` is watched after consumption'); + assert.ok( + !isWatching(obj, 'child.tax'), + 'precond alias target `child.tax` is not watched' + ); + assert.equal(get(obj, 'tax'), undefined); + // this is how PROPERTY_DID_CHANGE will get notified + assert.ok( + isWatching(obj, 'child.tax'), + 'alias target `child.cost` is watched after consumption' + ); - // increments the watching count on the alias itself to 1 - assert.ok(isNaN(get(obj, 'total')), 'total is initialized'); + // increments the watching count on the alias itself to 1 + assert.ok(isNaN(get(obj, 'total')), 'total is initialized'); - // decrements the watching count on the alias itself to 0 - set(obj, 'child', { - cost: 399.00, - tax: 32.93 - }); + // decrements the watching count on the alias itself to 0 + set(obj, 'child', { + cost: 399.0, + tax: 32.93 + }); - // this should have called PROPERTY_DID_CHANGE for all of them - assert.equal(counts['cost'], 1, 'PROPERTY_DID_CHANGE called with cost'); - assert.equal(counts['tax'], 1, 'PROPERTY_DID_CHANGE called with tax'); - assert.equal(counts['total'], 1, 'PROPERTY_DID_CHANGE called with total'); + // this should have called PROPERTY_DID_CHANGE for all of them + assert.equal(counts['cost'], 1, 'PROPERTY_DID_CHANGE called with cost'); + assert.equal(counts['tax'], 1, 'PROPERTY_DID_CHANGE called with tax'); + assert.equal(counts['total'], 1, 'PROPERTY_DID_CHANGE called with total'); - // we should still have a dependency installed - assert.ok(isWatching(obj, 'child.cost'), 'watching child.cost'); - assert.ok(isWatching(obj, 'child.tax'), 'watching child.tax'); + // we should still have a dependency installed + assert.ok(isWatching(obj, 'child.cost'), 'watching child.cost'); + assert.ok(isWatching(obj, 'child.tax'), 'watching child.tax'); - set(obj, 'child', { - cost: 100.00, - tax: 10.00 - }); + set(obj, 'child', { + cost: 100.0, + tax: 10.0 + }); - assert.equal(counts['cost'], 2, 'PROPERTY_DID_CHANGE called with cost'); - assert.equal(counts['tax'], 2, 'PROPERTY_DID_CHANGE called with tax'); - assert.equal(counts['total'], 1, 'PROPERTY_DID_CHANGE called with total'); + assert.equal(counts['cost'], 2, 'PROPERTY_DID_CHANGE called with cost'); + assert.equal(counts['tax'], 2, 'PROPERTY_DID_CHANGE called with tax'); + assert.equal(counts['total'], 1, 'PROPERTY_DID_CHANGE called with total'); + } } -}); - +); diff --git a/packages/ember-metal/tests/run_loop/debounce_test.js b/packages/ember-metal/tests/run_loop/debounce_test.js index fc7bec21b64..c1aca507398 100644 --- a/packages/ember-metal/tests/run_loop/debounce_test.js +++ b/packages/ember-metal/tests/run_loop/debounce_test.js @@ -1,80 +1,99 @@ import { debounce } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('debounce', class extends AbstractTestCase { - ['@test debounce - with target, with method, without args'](assert) { - let done = assert.async(); - - let calledWith = []; - let target = { - someFunc(...args) { - calledWith.push(args); - } - }; - - debounce(target, target.someFunc, 10); - debounce(target, target.someFunc, 10); - debounce(target, target.someFunc, 10); +moduleFor( + 'debounce', + class extends AbstractTestCase { + ['@test debounce - with target, with method, without args'](assert) { + let done = assert.async(); + + let calledWith = []; + let target = { + someFunc(...args) { + calledWith.push(args); + } + }; + + debounce(target, target.someFunc, 10); + debounce(target, target.someFunc, 10); + debounce(target, target.someFunc, 10); + + setTimeout(() => { + assert.deepEqual( + calledWith, + [[]], + 'someFunc called once with correct arguments' + ); + done(); + }, 20); + } - setTimeout(() => { - assert.deepEqual(calledWith, [ [] ], 'someFunc called once with correct arguments'); - done(); - }, 20); - } + ['@test debounce - with target, with method name, without args'](assert) { + let done = assert.async(); + + let calledWith = []; + let target = { + someFunc(...args) { + calledWith.push(args); + } + }; + + debounce(target, 'someFunc', 10); + debounce(target, 'someFunc', 10); + debounce(target, 'someFunc', 10); + + setTimeout(() => { + assert.deepEqual( + calledWith, + [[]], + 'someFunc called once with correct arguments' + ); + done(); + }, 20); + } - ['@test debounce - with target, with method name, without args'](assert) { - let done = assert.async(); + ['@test debounce - without target, without args'](assert) { + let done = assert.async(); - let calledWith = []; - let target = { - someFunc(...args) { + let calledWith = []; + function someFunc(...args) { calledWith.push(args); } - }; - debounce(target, 'someFunc', 10); - debounce(target, 'someFunc', 10); - debounce(target, 'someFunc', 10); - - setTimeout(() => { - assert.deepEqual(calledWith, [ [] ], 'someFunc called once with correct arguments'); - done(); - }, 20); - } - - ['@test debounce - without target, without args'](assert) { - let done = assert.async(); - - let calledWith = []; - function someFunc(...args) { - calledWith.push(args); + debounce(someFunc, 10); + debounce(someFunc, 10); + debounce(someFunc, 10); + + setTimeout(() => { + assert.deepEqual( + calledWith, + [[]], + 'someFunc called once with correct arguments' + ); + done(); + }, 20); } - debounce(someFunc, 10); - debounce(someFunc, 10); - debounce(someFunc, 10); - - setTimeout(() => { - assert.deepEqual(calledWith, [ [] ], 'someFunc called once with correct arguments'); - done(); - }, 20); - } + ['@test debounce - without target, with args'](assert) { + let done = assert.async(); - ['@test debounce - without target, with args'](assert) { - let done = assert.async(); + let calledWith = []; + function someFunc(...args) { + calledWith.push(args); + } - let calledWith = []; - function someFunc(...args) { - calledWith.push(args); + debounce(someFunc, { isFoo: true }, 10); + debounce(someFunc, { isBar: true }, 10); + debounce(someFunc, { isBaz: true }, 10); + + setTimeout(() => { + assert.deepEqual( + calledWith, + [[{ isBaz: true }]], + 'someFunc called once with correct arguments' + ); + done(); + }, 20); } - - debounce(someFunc, { isFoo: true }, 10); - debounce(someFunc, { isBar: true }, 10); - debounce(someFunc, { isBaz: true }, 10); - - setTimeout(() => { - assert.deepEqual(calledWith, [ [ { isBaz: true } ] ], 'someFunc called once with correct arguments'); - done(); - }, 20); } -}); +); diff --git a/packages/ember-metal/tests/run_loop/later_test.js b/packages/ember-metal/tests/run_loop/later_test.js index afba8f74c7a..8a399edb68e 100644 --- a/packages/ember-metal/tests/run_loop/later_test.js +++ b/packages/ember-metal/tests/run_loop/later_test.js @@ -6,7 +6,7 @@ import { backburner, isNone, hasScheduledTimers, - getCurrentRunLoop, + getCurrentRunLoop } from '../..'; const originalSetTimeout = window.setTimeout; @@ -35,214 +35,250 @@ function wait(callback, maxWaitCount) { // run loop has to flush, it would have considered // the timer already expired. function pauseUntil(time) { - while (+new Date() < time) { /* do nothing - sleeping */ } -} - -moduleFor('run.later', class extends AbstractTestCase { - teardown() { - backburner._platform = originalPlatform; - window.setTimeout = originalSetTimeout; - Date.prototype.valueOf = originalDateValueOf; - } - - ['@test should invoke after specified period of time - function only'](assert) { - let done = assert.async(); - let invoked = false; - - run(() => { - later(() => invoked = true, 100); - }); - - wait(() => { - assert.equal(invoked, true, 'should have invoked later item'); - done(); - }); - } - - ['@test should invoke after specified period of time - target/method'](assert) { - let done = assert.async(); - let obj = { invoked: false }; - - run(() => { - later(obj, function() { this.invoked = true; }, 100); - }); - - wait(() => { - assert.equal(obj.invoked, true, 'should have invoked later item'); - done(); - }); - } - - ['@test should invoke after specified period of time - target/method/args'](assert) { - let done = assert.async(); - let obj = { invoked: 0 }; - - run(() => { - later(obj, function(amt) { this.invoked += amt; }, 10, 100); - }); - - wait(() => { - assert.equal(obj.invoked, 10, 'should have invoked later item'); - done(); - }); + while (+new Date() < time) { + /* do nothing - sleeping */ } +} - ['@test should always invoke within a separate runloop'](assert) { - let done = assert.async(); - let obj = { invoked: 0 }; - let firstRunLoop, secondRunLoop; - - run(() => { - firstRunLoop = getCurrentRunLoop(); - - later(obj, function(amt) { - this.invoked += amt; - secondRunLoop = getCurrentRunLoop(); - }, 10, 1); - - pauseUntil(+new Date() + 100); - }); - - assert.ok(firstRunLoop, 'first run loop captured'); - assert.ok(!getCurrentRunLoop(), 'shouldn\'t be in a run loop after flush'); - assert.equal(obj.invoked, 0, 'shouldn\'t have invoked later item yet'); - - wait(() => { - assert.equal(obj.invoked, 10, 'should have invoked later item'); - assert.ok(secondRunLoop, 'second run loop took place'); - assert.ok(secondRunLoop !== firstRunLoop, 'two different run loops took place'); - done(); - }); - } - - // Our current implementation doesn't allow us to correctly enforce this ordering. - // We should probably implement a queue to provide this guarantee. - // See https://github.com/emberjs/ember.js/issues/3526 for more information. - - // asyncTest('callback order', function() { - // let array = []; - // function fn(val) { array.push(val); } - - // run(function() { - // later(this, fn, 4, 5); - // later(this, fn, 1, 1); - // later(this, fn, 5, 10); - // later(this, fn, 2, 3); - // later(this, fn, 3, 3); - // }); - - // deepEqual(array, []); - - // wait(function() { - // QUnit.start(); - // deepEqual(array, [1,2,3,4,5], 'callbacks were called in expected order'); - // }); - // }); - - - // Out current implementation doesn't allow us to properly enforce what is tested here. - // We should probably fix it, but it's not technically a bug right now. - // See https://github.com/emberjs/ember.js/issues/3522 for more information. - - // asyncTest('callbacks coalesce into same run loop if expiring at the same time', function() { - // let array = []; - // function fn(val) { array.push(getCurrentRunLoop()); } - - // run(function() { - - // // Force +new Date to return the same result while scheduling - // // later timers. Otherwise: non-determinism! - // let now = +new Date(); - // Date.prototype.valueOf = function() { return now; }; +moduleFor( + 'run.later', + class extends AbstractTestCase { + teardown() { + backburner._platform = originalPlatform; + window.setTimeout = originalSetTimeout; + Date.prototype.valueOf = originalDateValueOf; + } - // later(this, fn, 10); - // later(this, fn, 200); - // later(this, fn, 200); + ['@test should invoke after specified period of time - function only']( + assert + ) { + let done = assert.async(); + let invoked = false; - // Date.prototype.valueOf = originalDateValueOf; - // }); + run(() => { + later(() => (invoked = true), 100); + }); - // deepEqual(array, []); + wait(() => { + assert.equal(invoked, true, 'should have invoked later item'); + done(); + }); + } - // wait(function() { - // QUnit.start(); - // equal(array.length, 3, 'all callbacks called'); - // ok(array[0] !== array[1], 'first two callbacks have different run loops'); - // ok(array[0], 'first runloop present'); - // ok(array[1], 'second runloop present'); - // equal(array[1], array[2], 'last two callbacks got the same run loop'); - // }); - // }); + ['@test should invoke after specified period of time - target/method']( + assert + ) { + let done = assert.async(); + let obj = { invoked: false }; + + run(() => { + later( + obj, + function() { + this.invoked = true; + }, + 100 + ); + }); + + wait(() => { + assert.equal(obj.invoked, true, 'should have invoked later item'); + done(); + }); + } - ['@test inception calls to later should run callbacks in separate run loops'](assert) { - let done = assert.async(); - let runLoop, finished; + ['@test should invoke after specified period of time - target/method/args']( + assert + ) { + let done = assert.async(); + let obj = { invoked: 0 }; + + run(() => { + later( + obj, + function(amt) { + this.invoked += amt; + }, + 10, + 100 + ); + }); + + wait(() => { + assert.equal(obj.invoked, 10, 'should have invoked later item'); + done(); + }); + } - run(() => { - runLoop = getCurrentRunLoop(); - assert.ok(runLoop); + ['@test should always invoke within a separate runloop'](assert) { + let done = assert.async(); + let obj = { invoked: 0 }; + let firstRunLoop, secondRunLoop; + + run(() => { + firstRunLoop = getCurrentRunLoop(); + + later( + obj, + function(amt) { + this.invoked += amt; + secondRunLoop = getCurrentRunLoop(); + }, + 10, + 1 + ); + + pauseUntil(+new Date() + 100); + }); + + assert.ok(firstRunLoop, 'first run loop captured'); + assert.ok(!getCurrentRunLoop(), "shouldn't be in a run loop after flush"); + assert.equal(obj.invoked, 0, "shouldn't have invoked later item yet"); + + wait(() => { + assert.equal(obj.invoked, 10, 'should have invoked later item'); + assert.ok(secondRunLoop, 'second run loop took place'); + assert.ok( + secondRunLoop !== firstRunLoop, + 'two different run loops took place' + ); + done(); + }); + } - later(() => { - assert.ok(getCurrentRunLoop() && getCurrentRunLoop() !== runLoop, - 'first later callback has own run loop'); + // Our current implementation doesn't allow us to correctly enforce this ordering. + // We should probably implement a queue to provide this guarantee. + // See https://github.com/emberjs/ember.js/issues/3526 for more information. + + // asyncTest('callback order', function() { + // let array = []; + // function fn(val) { array.push(val); } + + // run(function() { + // later(this, fn, 4, 5); + // later(this, fn, 1, 1); + // later(this, fn, 5, 10); + // later(this, fn, 2, 3); + // later(this, fn, 3, 3); + // }); + + // deepEqual(array, []); + + // wait(function() { + // QUnit.start(); + // deepEqual(array, [1,2,3,4,5], 'callbacks were called in expected order'); + // }); + // }); + + // Out current implementation doesn't allow us to properly enforce what is tested here. + // We should probably fix it, but it's not technically a bug right now. + // See https://github.com/emberjs/ember.js/issues/3522 for more information. + + // asyncTest('callbacks coalesce into same run loop if expiring at the same time', function() { + // let array = []; + // function fn(val) { array.push(getCurrentRunLoop()); } + + // run(function() { + + // // Force +new Date to return the same result while scheduling + // // later timers. Otherwise: non-determinism! + // let now = +new Date(); + // Date.prototype.valueOf = function() { return now; }; + + // later(this, fn, 10); + // later(this, fn, 200); + // later(this, fn, 200); + + // Date.prototype.valueOf = originalDateValueOf; + // }); + + // deepEqual(array, []); + + // wait(function() { + // QUnit.start(); + // equal(array.length, 3, 'all callbacks called'); + // ok(array[0] !== array[1], 'first two callbacks have different run loops'); + // ok(array[0], 'first runloop present'); + // ok(array[1], 'second runloop present'); + // equal(array[1], array[2], 'last two callbacks got the same run loop'); + // }); + // }); + + ['@test inception calls to later should run callbacks in separate run loops']( + assert + ) { + let done = assert.async(); + let runLoop, finished; + + run(() => { runLoop = getCurrentRunLoop(); + assert.ok(runLoop); later(() => { - assert.ok(getCurrentRunLoop() && getCurrentRunLoop() !== runLoop, - 'second later callback has own run loop'); - finished = true; + assert.ok( + getCurrentRunLoop() && getCurrentRunLoop() !== runLoop, + 'first later callback has own run loop' + ); + runLoop = getCurrentRunLoop(); + + later(() => { + assert.ok( + getCurrentRunLoop() && getCurrentRunLoop() !== runLoop, + 'second later callback has own run loop' + ); + finished = true; + }, 40); }, 40); - }, 40); - }); + }); - wait(() => { - assert.ok(finished, 'all .later callbacks run'); - done(); - }); - } + wait(() => { + assert.ok(finished, 'all .later callbacks run'); + done(); + }); + } - ['@test setTimeout should never run with a negative wait'](assert) { - let done = assert.async(); - // Rationale: The old run loop code was susceptible to an occasional - // bug where invokeLaterTimers would be scheduled with a setTimeout - // with a negative wait. Modern browsers normalize this to 0, but - // older browsers (IE <= 8) break with a negative wait, which - // happens when an expired timer callback takes a while to run, - // which is what we simulate here. - let newSetTimeoutUsed; - backburner._platform = assign({}, originalPlatform, { - setTimeout() { - let wait = arguments[arguments.length - 1]; - newSetTimeoutUsed = true; - assert.ok(!isNaN(wait) && wait >= 0, 'wait is a non-negative number'); - - return originalPlatform.setTimeout.apply(originalPlatform, arguments); - } - }); - - let count = 0; - run(() => { - later(() => { - count++; - - // This will get run first. Waste some time. - // This is intended to break invokeLaterTimers code by taking a - // long enough time that other timers should technically expire. It's - // fine that they're not called in this run loop; just need to - // make sure that invokeLaterTimers doesn't end up scheduling - // a negative setTimeout. - pauseUntil(+new Date() + 60); - }, 1); - - later(() => { - assert.equal(count, 1, 'callbacks called in order'); - }, 50); - }); - - wait(() => { - assert.ok(newSetTimeoutUsed, 'stub setTimeout was used'); - done(); - }); - } -}); + ['@test setTimeout should never run with a negative wait'](assert) { + let done = assert.async(); + // Rationale: The old run loop code was susceptible to an occasional + // bug where invokeLaterTimers would be scheduled with a setTimeout + // with a negative wait. Modern browsers normalize this to 0, but + // older browsers (IE <= 8) break with a negative wait, which + // happens when an expired timer callback takes a while to run, + // which is what we simulate here. + let newSetTimeoutUsed; + backburner._platform = assign({}, originalPlatform, { + setTimeout() { + let wait = arguments[arguments.length - 1]; + newSetTimeoutUsed = true; + assert.ok(!isNaN(wait) && wait >= 0, 'wait is a non-negative number'); + + return originalPlatform.setTimeout.apply(originalPlatform, arguments); + } + }); + + let count = 0; + run(() => { + later(() => { + count++; + + // This will get run first. Waste some time. + // This is intended to break invokeLaterTimers code by taking a + // long enough time that other timers should technically expire. It's + // fine that they're not called in this run loop; just need to + // make sure that invokeLaterTimers doesn't end up scheduling + // a negative setTimeout. + pauseUntil(+new Date() + 60); + }, 1); + later(() => { + assert.equal(count, 1, 'callbacks called in order'); + }, 50); + }); + + wait(() => { + assert.ok(newSetTimeoutUsed, 'stub setTimeout was used'); + done(); + }); + } + } +); diff --git a/packages/ember-metal/tests/run_loop/next_test.js b/packages/ember-metal/tests/run_loop/next_test.js index eae20986ca8..5c2e1fb5ee0 100644 --- a/packages/ember-metal/tests/run_loop/next_test.js +++ b/packages/ember-metal/tests/run_loop/next_test.js @@ -1,48 +1,58 @@ import { run, next, getCurrentRunLoop } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('run.next', class extends AbstractTestCase { - ['@test should invoke immediately on next timeout'](assert) { - let done = assert.async(); - let invoked = false; - - run(() => next(() => invoked = true)); - - assert.equal(invoked, false, 'should not have invoked yet'); - - setTimeout(() => { - assert.equal(invoked, true, 'should have invoked later item'); - done(); - }, 20); - } - - ['@test callback should be called from within separate loop'](assert) { - let done = assert.async(); - let firstRunLoop, secondRunLoop; - run(() => { - firstRunLoop = getCurrentRunLoop(); - next(() => secondRunLoop = getCurrentRunLoop()); - }); - - setTimeout(() => { - assert.ok(secondRunLoop, 'callback was called from within run loop'); - assert.ok(firstRunLoop && secondRunLoop !== firstRunLoop, 'two separate run loops were invoked'); - done(); - }, 20); - } - - ['@test multiple calls to next share coalesce callbacks into same run loop'](assert) { - let done = assert.async(); - let secondRunLoop, thirdRunLoop; - run(() => { - next(() => secondRunLoop = getCurrentRunLoop()); - next(() => thirdRunLoop = getCurrentRunLoop()); - }); - - setTimeout(() => { - assert.ok(secondRunLoop && secondRunLoop === thirdRunLoop, 'callbacks coalesced into same run loop'); - done(); - }, 20); +moduleFor( + 'run.next', + class extends AbstractTestCase { + ['@test should invoke immediately on next timeout'](assert) { + let done = assert.async(); + let invoked = false; + + run(() => next(() => (invoked = true))); + + assert.equal(invoked, false, 'should not have invoked yet'); + + setTimeout(() => { + assert.equal(invoked, true, 'should have invoked later item'); + done(); + }, 20); + } + + ['@test callback should be called from within separate loop'](assert) { + let done = assert.async(); + let firstRunLoop, secondRunLoop; + run(() => { + firstRunLoop = getCurrentRunLoop(); + next(() => (secondRunLoop = getCurrentRunLoop())); + }); + + setTimeout(() => { + assert.ok(secondRunLoop, 'callback was called from within run loop'); + assert.ok( + firstRunLoop && secondRunLoop !== firstRunLoop, + 'two separate run loops were invoked' + ); + done(); + }, 20); + } + + ['@test multiple calls to next share coalesce callbacks into same run loop']( + assert + ) { + let done = assert.async(); + let secondRunLoop, thirdRunLoop; + run(() => { + next(() => (secondRunLoop = getCurrentRunLoop())); + next(() => (thirdRunLoop = getCurrentRunLoop())); + }); + + setTimeout(() => { + assert.ok( + secondRunLoop && secondRunLoop === thirdRunLoop, + 'callbacks coalesced into same run loop' + ); + done(); + }, 20); + } } -}); - +); diff --git a/packages/ember-metal/tests/run_loop/once_test.js b/packages/ember-metal/tests/run_loop/once_test.js index d4f06255c02..5b554d0c433 100644 --- a/packages/ember-metal/tests/run_loop/once_test.js +++ b/packages/ember-metal/tests/run_loop/once_test.js @@ -1,55 +1,62 @@ import { run, getCurrentRunLoop, once } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('system/run_loop/once_test', class extends AbstractTestCase { - ['@test calling invokeOnce more than once invokes only once'](assert) { - let count = 0; - run(() => { - function F() { count++; } - once(F); - once(F); - once(F); - }); - - assert.equal(count, 1, 'should have invoked once'); +moduleFor( + 'system/run_loop/once_test', + class extends AbstractTestCase { + ['@test calling invokeOnce more than once invokes only once'](assert) { + let count = 0; + run(() => { + function F() { + count++; + } + once(F); + once(F); + once(F); + }); + + assert.equal(count, 1, 'should have invoked once'); + } + + ['@test should differentiate based on target'](assert) { + let A = { count: 0 }; + let B = { count: 0 }; + run(() => { + function F() { + this.count++; + } + once(A, F); + once(B, F); + once(A, F); + once(B, F); + }); + + assert.equal(A.count, 1, 'should have invoked once on A'); + assert.equal(B.count, 1, 'should have invoked once on B'); + } + + ['@test should ignore other arguments - replacing previous ones'](assert) { + let A = { count: 0 }; + let B = { count: 0 }; + + run(() => { + function F(amt) { + this.count += amt; + } + once(A, F, 10); + once(B, F, 20); + once(A, F, 30); + once(B, F, 40); + }); + + assert.equal(A.count, 30, 'should have invoked once on A'); + assert.equal(B.count, 40, 'should have invoked once on B'); + } + + ['@test should be inside of a runloop when running'](assert) { + run(() => { + once(() => assert.ok(!!getCurrentRunLoop(), 'should have a runloop')); + }); + } } - - ['@test should differentiate based on target'](assert) { - let A = { count: 0 }; - let B = { count: 0 }; - run(() => { - function F() { this.count++; } - once(A, F); - once(B, F); - once(A, F); - once(B, F); - }); - - assert.equal(A.count, 1, 'should have invoked once on A'); - assert.equal(B.count, 1, 'should have invoked once on B'); - } - - - ['@test should ignore other arguments - replacing previous ones'](assert) { - let A = { count: 0 }; - let B = { count: 0 }; - - run(() => { - function F(amt) { this.count += amt; } - once(A, F, 10); - once(B, F, 20); - once(A, F, 30); - once(B, F, 40); - }); - - assert.equal(A.count, 30, 'should have invoked once on A'); - assert.equal(B.count, 40, 'should have invoked once on B'); - } - - ['@test should be inside of a runloop when running'](assert) { - run(() => { - once(() => assert.ok(!!getCurrentRunLoop(), 'should have a runloop')); - }); - } -}); - +); diff --git a/packages/ember-metal/tests/run_loop/onerror_test.js b/packages/ember-metal/tests/run_loop/onerror_test.js index 9990b680df9..b3492966b98 100644 --- a/packages/ember-metal/tests/run_loop/onerror_test.js +++ b/packages/ember-metal/tests/run_loop/onerror_test.js @@ -8,43 +8,52 @@ import { import { isTesting, setTesting } from 'ember-debug'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('system/run_loop/onerror_test', class extends AbstractTestCase { - ['@test With Ember.onerror undefined, errors in run are thrown'](assert) { - let thrown = new Error('Boom!'); - let original = getOnerror(); +moduleFor( + 'system/run_loop/onerror_test', + class extends AbstractTestCase { + ['@test With Ember.onerror undefined, errors in run are thrown'](assert) { + let thrown = new Error('Boom!'); + let original = getOnerror(); - let caught; - setOnerror(undefined); - try { - run(() => { throw thrown; }); - } catch (error) { - caught = error; - } finally { - setOnerror(original); + let caught; + setOnerror(undefined); + try { + run(() => { + throw thrown; + }); + } catch (error) { + caught = error; + } finally { + setOnerror(original); + } + + assert.deepEqual(caught, thrown); } - assert.deepEqual(caught, thrown); - } + ['@test With Ember.onerror set, errors in run are caught'](assert) { + let thrown = new Error('Boom!'); + let original = getOnerror(); + let originalDispatchOverride = getDispatchOverride(); + let originalIsTesting = isTesting(); - ['@test With Ember.onerror set, errors in run are caught'](assert) { - let thrown = new Error('Boom!'); - let original = getOnerror(); - let originalDispatchOverride = getDispatchOverride(); - let originalIsTesting = isTesting(); + let caught; + setOnerror(error => { + caught = error; + }); + setDispatchOverride(null); + setTesting(false); - let caught; - setOnerror(error => { caught = error; }); - setDispatchOverride(null); - setTesting(false); + try { + run(() => { + throw thrown; + }); + } finally { + setOnerror(original); + setDispatchOverride(originalDispatchOverride); + setTesting(originalIsTesting); + } - try { - run(() => { throw thrown; }); - } finally { - setOnerror(original); - setDispatchOverride(originalDispatchOverride); - setTesting(originalIsTesting); + assert.deepEqual(caught, thrown); } - - assert.deepEqual(caught, thrown); } -}); +); diff --git a/packages/ember-metal/tests/run_loop/run_bind_test.js b/packages/ember-metal/tests/run_loop/run_bind_test.js index 12194d35f99..5e7a695df80 100644 --- a/packages/ember-metal/tests/run_loop/run_bind_test.js +++ b/packages/ember-metal/tests/run_loop/run_bind_test.js @@ -1,37 +1,40 @@ import { bind, getCurrentRunLoop } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('system/run_loop/run_bind_test', class extends AbstractTestCase { - ['@test bind builds a run-loop wrapped callback handler'](assert) { - assert.expect(3); +moduleFor( + 'system/run_loop/run_bind_test', + class extends AbstractTestCase { + ['@test bind builds a run-loop wrapped callback handler'](assert) { + assert.expect(3); - let obj = { - value: 0, - increment(increment) { - assert.ok(getCurrentRunLoop(), 'expected a run-loop'); - return this.value += increment; - } - }; + let obj = { + value: 0, + increment(increment) { + assert.ok(getCurrentRunLoop(), 'expected a run-loop'); + return (this.value += increment); + } + }; - let proxiedFunction = bind(obj, obj.increment, 1); - assert.equal(proxiedFunction(), 1); - assert.equal(obj.value, 1); - } + let proxiedFunction = bind(obj, obj.increment, 1); + assert.equal(proxiedFunction(), 1); + assert.equal(obj.value, 1); + } - ['@test bind keeps the async callback arguments'](assert) { - assert.expect(4); + ['@test bind keeps the async callback arguments'](assert) { + assert.expect(4); - function asyncCallback(increment, increment2, increment3) { - assert.ok(getCurrentRunLoop(), 'expected a run-loop'); - assert.equal(increment, 1); - assert.equal(increment2, 2); - assert.equal(increment3, 3); - } + function asyncCallback(increment, increment2, increment3) { + assert.ok(getCurrentRunLoop(), 'expected a run-loop'); + assert.equal(increment, 1); + assert.equal(increment2, 2); + assert.equal(increment3, 3); + } - function asyncFunction(fn) { - fn(2, 3); - } + function asyncFunction(fn) { + fn(2, 3); + } - asyncFunction(bind(asyncCallback, asyncCallback, 1)); + asyncFunction(bind(asyncCallback, asyncCallback, 1)); + } } -}); +); diff --git a/packages/ember-metal/tests/run_loop/run_test.js b/packages/ember-metal/tests/run_loop/run_test.js index d7acf8ede19..e370cc4b6bd 100644 --- a/packages/ember-metal/tests/run_loop/run_test.js +++ b/packages/ember-metal/tests/run_loop/run_test.js @@ -1,17 +1,36 @@ import { run } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('system/run_loop/run_test', class extends AbstractTestCase { - ['@test run invokes passed function, returning value'](assert) { - let obj = { - foo() { return [this.bar, 'FOO']; }, - bar: 'BAR', - checkArgs(arg1, arg2) { return [arg1, this.bar, arg2]; } - }; +moduleFor( + 'system/run_loop/run_test', + class extends AbstractTestCase { + ['@test run invokes passed function, returning value'](assert) { + let obj = { + foo() { + return [this.bar, 'FOO']; + }, + bar: 'BAR', + checkArgs(arg1, arg2) { + return [arg1, this.bar, arg2]; + } + }; - assert.equal(run(() => 'FOO'), 'FOO', 'pass function only'); - assert.deepEqual(run(obj, obj.foo), ['BAR', 'FOO'], 'pass obj and obj.method'); - assert.deepEqual(run(obj, 'foo'), ['BAR', 'FOO'], 'pass obj and "method"'); - assert.deepEqual(run(obj, obj.checkArgs, 'hello', 'world'), ['hello', 'BAR', 'world'], 'pass obj, obj.method, and extra arguments'); + assert.equal(run(() => 'FOO'), 'FOO', 'pass function only'); + assert.deepEqual( + run(obj, obj.foo), + ['BAR', 'FOO'], + 'pass obj and obj.method' + ); + assert.deepEqual( + run(obj, 'foo'), + ['BAR', 'FOO'], + 'pass obj and "method"' + ); + assert.deepEqual( + run(obj, obj.checkArgs, 'hello', 'world'), + ['hello', 'BAR', 'world'], + 'pass obj, obj.method, and extra arguments' + ); + } } -}); +); diff --git a/packages/ember-metal/tests/run_loop/schedule_test.js b/packages/ember-metal/tests/run_loop/schedule_test.js index 0682c4468e2..5eda08bb028 100644 --- a/packages/ember-metal/tests/run_loop/schedule_test.js +++ b/packages/ember-metal/tests/run_loop/schedule_test.js @@ -1,68 +1,56 @@ import { run, cancel, schedule, getCurrentRunLoop } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('system/run_loop/schedule_test', class extends AbstractTestCase { - ['@test scheduling item in queue should defer until finished'](assert) { - let cnt = 0; +moduleFor( + 'system/run_loop/schedule_test', + class extends AbstractTestCase { + ['@test scheduling item in queue should defer until finished'](assert) { + let cnt = 0; - run(() => { - schedule('actions', () => cnt++); - schedule('actions', () => cnt++); - assert.equal(cnt, 0, 'should not run action yet'); - }); - - assert.equal(cnt, 2, 'should flush actions now'); - } - - ['@test a scheduled item can be canceled'](assert) { - let hasRan = false; - - run(() => { - let cancelId = schedule('actions', () => hasRan = true); - cancel(cancelId); - }); - - assert.notOk(hasRan, 'should not have ran callback run'); - } + run(() => { + schedule('actions', () => cnt++); + schedule('actions', () => cnt++); + assert.equal(cnt, 0, 'should not run action yet'); + }); - ['@test nested runs should queue each phase independently'](assert) { - let cnt = 0; + assert.equal(cnt, 2, 'should flush actions now'); + } - run(() => { - schedule('actions', () => cnt++); - assert.equal(cnt, 0, 'should not run action yet'); + ['@test a scheduled item can be canceled'](assert) { + let hasRan = false; run(() => { - schedule('actions', () => cnt++); + let cancelId = schedule('actions', () => (hasRan = true)); + cancel(cancelId); }); - assert.equal(cnt, 1, 'should not run action yet'); - }); - assert.equal(cnt, 2, 'should flush actions now'); - } + assert.notOk(hasRan, 'should not have ran callback run'); + } - ['@test prior queues should be flushed before moving on to next queue'](assert) { - let order = []; + ['@test nested runs should queue each phase independently'](assert) { + let cnt = 0; - run(() => { - let runLoop = getCurrentRunLoop(); - assert.ok(runLoop, 'run loop present'); + run(() => { + schedule('actions', () => cnt++); + assert.equal(cnt, 0, 'should not run action yet'); - expectDeprecation(() => { - schedule('sync', () => { - order.push('sync'); - assert.equal(runLoop, getCurrentRunLoop(), 'same run loop used'); + run(() => { + schedule('actions', () => cnt++); }); - }, `Scheduling into the 'sync' run loop queue is deprecated.`); + assert.equal(cnt, 1, 'should not run action yet'); + }); - schedule('actions', () => { - order.push('actions'); - assert.equal(runLoop, getCurrentRunLoop(), 'same run loop used'); + assert.equal(cnt, 2, 'should flush actions now'); + } - schedule('actions', () => { - order.push('actions'); - assert.equal(runLoop, getCurrentRunLoop(), 'same run loop used'); - }); + ['@test prior queues should be flushed before moving on to next queue']( + assert + ) { + let order = []; + + run(() => { + let runLoop = getCurrentRunLoop(); + assert.ok(runLoop, 'run loop present'); expectDeprecation(() => { schedule('sync', () => { @@ -70,21 +58,50 @@ moduleFor('system/run_loop/schedule_test', class extends AbstractTestCase { assert.equal(runLoop, getCurrentRunLoop(), 'same run loop used'); }); }, `Scheduling into the 'sync' run loop queue is deprecated.`); - }); - schedule('destroy', () => { - order.push('destroy'); - assert.equal(runLoop, getCurrentRunLoop(), 'same run loop used'); - }); - }); + schedule('actions', () => { + order.push('actions'); + assert.equal(runLoop, getCurrentRunLoop(), 'same run loop used'); - assert.deepEqual(order, ['sync', 'actions', 'sync', 'actions', 'destroy']); - } + schedule('actions', () => { + order.push('actions'); + assert.equal(runLoop, getCurrentRunLoop(), 'same run loop used'); + }); + + expectDeprecation(() => { + schedule('sync', () => { + order.push('sync'); + assert.equal(runLoop, getCurrentRunLoop(), 'same run loop used'); + }); + }, `Scheduling into the 'sync' run loop queue is deprecated.`); + }); - ['@test makes sure it does not trigger an autorun during testing']() { - expectAssertion(() => schedule('actions', () => {}), /wrap any code with asynchronous side-effects in a run/); + schedule('destroy', () => { + order.push('destroy'); + assert.equal(runLoop, getCurrentRunLoop(), 'same run loop used'); + }); + }); - // make sure not just the first violation is asserted. - expectAssertion(() => schedule('actions', () => {}), /wrap any code with asynchronous side-effects in a run/); + assert.deepEqual(order, [ + 'sync', + 'actions', + 'sync', + 'actions', + 'destroy' + ]); + } + + ['@test makes sure it does not trigger an autorun during testing']() { + expectAssertion( + () => schedule('actions', () => {}), + /wrap any code with asynchronous side-effects in a run/ + ); + + // make sure not just the first violation is asserted. + expectAssertion( + () => schedule('actions', () => {}), + /wrap any code with asynchronous side-effects in a run/ + ); + } } -}); +); diff --git a/packages/ember-metal/tests/run_loop/sync_test.js b/packages/ember-metal/tests/run_loop/sync_test.js index 0749c4d1e8e..7486828a2c2 100644 --- a/packages/ember-metal/tests/run_loop/sync_test.js +++ b/packages/ember-metal/tests/run_loop/sync_test.js @@ -1,28 +1,32 @@ import { run, schedule } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('system/run_loop/sync_test', class extends AbstractTestCase { - ['@test sync() will immediately flush the sync queue only'](assert) { - let cnt = 0; +moduleFor( + 'system/run_loop/sync_test', + class extends AbstractTestCase { + ['@test sync() will immediately flush the sync queue only'](assert) { + let cnt = 0; - run(() => { - function cntup() { cnt++; } + run(() => { + function cntup() { + cnt++; + } - function syncfunc() { - if (++cnt < 5) { - expectDeprecation(() => { - schedule('sync', syncfunc); - }, `Scheduling into the 'sync' run loop queue is deprecated.`); + function syncfunc() { + if (++cnt < 5) { + expectDeprecation(() => { + schedule('sync', syncfunc); + }, `Scheduling into the 'sync' run loop queue is deprecated.`); + } + schedule('actions', cntup); } - schedule('actions', cntup); - } - syncfunc(); + syncfunc(); - assert.equal(cnt, 1, 'should not run action yet'); - }); + assert.equal(cnt, 1, 'should not run action yet'); + }); - assert.equal(cnt, 10, 'should flush actions now too'); + assert.equal(cnt, 10, 'should flush actions now too'); + } } -}); - +); diff --git a/packages/ember-metal/tests/run_loop/unwind_test.js b/packages/ember-metal/tests/run_loop/unwind_test.js index 85bf6260022..2e2475e39e1 100644 --- a/packages/ember-metal/tests/run_loop/unwind_test.js +++ b/packages/ember-metal/tests/run_loop/unwind_test.js @@ -2,33 +2,53 @@ import { run, schedule, getCurrentRunLoop } from '../..'; import { Error as EmberError } from 'ember-debug'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('system/run_loop/unwind_test', class extends AbstractTestCase { - ['@test RunLoop unwinds despite unhandled exception'](assert) { - let initialRunLoop = getCurrentRunLoop(); +moduleFor( + 'system/run_loop/unwind_test', + class extends AbstractTestCase { + ['@test RunLoop unwinds despite unhandled exception'](assert) { + let initialRunLoop = getCurrentRunLoop(); - assert.throws(() => { - run(() => { - schedule('actions', function() { throw new EmberError('boom!'); }); - }); - }, Error, 'boom!'); + assert.throws( + () => { + run(() => { + schedule('actions', function() { + throw new EmberError('boom!'); + }); + }); + }, + Error, + 'boom!' + ); - // The real danger at this point is that calls to autorun will stick - // tasks into the already-dead runloop, which will never get - // flushed. I can't easily demonstrate this in a unit test because - // autorun explicitly doesn't work in test mode. - ef4 - assert.equal(getCurrentRunLoop(), initialRunLoop, 'Previous run loop should be cleaned up despite exception'); - } + // The real danger at this point is that calls to autorun will stick + // tasks into the already-dead runloop, which will never get + // flushed. I can't easily demonstrate this in a unit test because + // autorun explicitly doesn't work in test mode. - ef4 + assert.equal( + getCurrentRunLoop(), + initialRunLoop, + 'Previous run loop should be cleaned up despite exception' + ); + } - ['@test run unwinds despite unhandled exception'](assert) { - var initialRunLoop = getCurrentRunLoop(); + ['@test run unwinds despite unhandled exception'](assert) { + var initialRunLoop = getCurrentRunLoop(); - assert.throws(() => { - run(function() { - throw new EmberError('boom!'); - }); - }, EmberError, 'boom!'); + assert.throws( + () => { + run(function() { + throw new EmberError('boom!'); + }); + }, + EmberError, + 'boom!' + ); - assert.equal(getCurrentRunLoop(), initialRunLoop, 'Previous run loop should be cleaned up despite exception'); + assert.equal( + getCurrentRunLoop(), + initialRunLoop, + 'Previous run loop should be cleaned up despite exception' + ); + } } -}); - +); diff --git a/packages/ember-metal/tests/set_properties_test.js b/packages/ember-metal/tests/set_properties_test.js index 05638a0fb0e..27bef59a2d3 100644 --- a/packages/ember-metal/tests/set_properties_test.js +++ b/packages/ember-metal/tests/set_properties_test.js @@ -1,27 +1,56 @@ import { setProperties } from '..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('setProperties', class extends AbstractTestCase { - ['@test supports setting multiple attributes at once'](assert) { - assert.deepEqual(setProperties(null, null), null, 'noop for null properties and null object'); - assert.deepEqual(setProperties(undefined, undefined), undefined, 'noop for undefined properties and undefined object'); - - assert.deepEqual(setProperties({}), undefined, 'noop for no properties'); - assert.deepEqual(setProperties({}, undefined), undefined, 'noop for undefined'); - assert.deepEqual(setProperties({}, null), null, 'noop for null'); - assert.deepEqual(setProperties({}, NaN), NaN, 'noop for NaN'); - assert.deepEqual(setProperties({}, {}), {}, 'meh'); - - assert.deepEqual(setProperties({}, { foo: 1 }), { foo: 1 }, 'Set a single property'); - - assert.deepEqual(setProperties({}, { foo: 1, bar: 1 }), { foo: 1, bar: 1 }, 'Set multiple properties'); - - assert.deepEqual(setProperties({ foo: 2, baz: 2 }, { foo: 1 }), { foo: 1 }, 'Set one of multiple properties'); - - assert.deepEqual(setProperties({ foo: 2, baz: 2 }, { bar: 2 }), { - bar: 2 - }, 'Set an additional, previously unset property'); +moduleFor( + 'setProperties', + class extends AbstractTestCase { + ['@test supports setting multiple attributes at once'](assert) { + assert.deepEqual( + setProperties(null, null), + null, + 'noop for null properties and null object' + ); + assert.deepEqual( + setProperties(undefined, undefined), + undefined, + 'noop for undefined properties and undefined object' + ); + + assert.deepEqual(setProperties({}), undefined, 'noop for no properties'); + assert.deepEqual( + setProperties({}, undefined), + undefined, + 'noop for undefined' + ); + assert.deepEqual(setProperties({}, null), null, 'noop for null'); + assert.deepEqual(setProperties({}, NaN), NaN, 'noop for NaN'); + assert.deepEqual(setProperties({}, {}), {}, 'meh'); + + assert.deepEqual( + setProperties({}, { foo: 1 }), + { foo: 1 }, + 'Set a single property' + ); + + assert.deepEqual( + setProperties({}, { foo: 1, bar: 1 }), + { foo: 1, bar: 1 }, + 'Set multiple properties' + ); + + assert.deepEqual( + setProperties({ foo: 2, baz: 2 }, { foo: 1 }), + { foo: 1 }, + 'Set one of multiple properties' + ); + + assert.deepEqual( + setProperties({ foo: 2, baz: 2 }, { bar: 2 }), + { + bar: 2 + }, + 'Set an additional, previously unset property' + ); + } } -}); - - +); diff --git a/packages/ember-metal/tests/tracked/computed_test.js b/packages/ember-metal/tests/tracked/computed_test.js index def110d0f7d..65dfb0b22f3 100644 --- a/packages/ember-metal/tests/tracked/computed_test.js +++ b/packages/ember-metal/tests/tracked/computed_test.js @@ -4,7 +4,6 @@ import { get, set, tracked } from '../..'; import { EMBER_METAL_TRACKED_PROPERTIES } from 'ember/features'; if (EMBER_METAL_TRACKED_PROPERTIES) { - QUnit.module('tracked getters'); QUnit.test('works without get', assert => { @@ -17,7 +16,11 @@ if (EMBER_METAL_TRACKED_PROPERTIES) { } } - tracked(Count.prototype, 'foo', Object.getOwnPropertyDescriptor(Count.prototype, 'foo')); + tracked( + Count.prototype, + 'foo', + Object.getOwnPropertyDescriptor(Count.prototype, 'foo') + ); let obj = new Count(); @@ -25,44 +28,50 @@ if (EMBER_METAL_TRACKED_PROPERTIES) { assert.equal(count, 1, 'should have invoked computed property'); }); + QUnit.test( + 'defining computed property should invoke property on get', + function(assert) { + let count = 0; - QUnit.test('defining computed property should invoke property on get', function(assert) { - let count = 0; - - class Count { - get foo() { - count++; - return `computed foo`; - } - } - - tracked(Count.prototype, 'foo', Object.getOwnPropertyDescriptor(Count.prototype, 'foo')); - - let obj = new Count(); - - assert.equal(get(obj, 'foo'), 'computed foo', 'should return value'); - assert.equal(count, 1, 'should have invoked computed property'); - }); - - - QUnit.test('defining computed property should invoke property on set', function(assert) { - let count = 0; - - let obj = createWithDescriptors({ - get foo() { - return this.__foo; - }, - - set foo(value) { - count++; - this.__foo = `computed ${value}`; + class Count { + get foo() { + count++; + return `computed foo`; + } } - }); + tracked( + Count.prototype, + 'foo', + Object.getOwnPropertyDescriptor(Count.prototype, 'foo') + ); - assert.equal(set(obj, 'foo', 'bar'), 'bar', 'should return set value'); - assert.equal(count, 1, 'should have invoked computed property'); - assert.equal(get(obj, 'foo'), 'computed bar', 'should return new value'); - }); + let obj = new Count(); + assert.equal(get(obj, 'foo'), 'computed foo', 'should return value'); + assert.equal(count, 1, 'should have invoked computed property'); + } + ); + + QUnit.test( + 'defining computed property should invoke property on set', + function(assert) { + let count = 0; + + let obj = createWithDescriptors({ + get foo() { + return this.__foo; + }, + + set foo(value) { + count++; + this.__foo = `computed ${value}`; + } + }); + + assert.equal(set(obj, 'foo', 'bar'), 'bar', 'should return set value'); + assert.equal(count, 1, 'should have invoked computed property'); + assert.equal(get(obj, 'foo'), 'computed bar', 'should return new value'); + } + ); } diff --git a/packages/ember-metal/tests/tracked/get_test.js b/packages/ember-metal/tests/tracked/get_test.js index d5bccbb29bd..db737a6a5f5 100644 --- a/packages/ember-metal/tests/tracked/get_test.js +++ b/packages/ember-metal/tests/tracked/get_test.js @@ -1,8 +1,4 @@ -import { - get, - getWithDefault, - tracked -} from '../..'; +import { get, getWithDefault, tracked } from '../..'; import { createTracked } from './support'; @@ -11,68 +7,84 @@ import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; import { EMBER_METAL_TRACKED_PROPERTIES } from 'ember/features'; if (EMBER_METAL_TRACKED_PROPERTIES) { - - moduleFor('tracked get', class extends AbstractTestCase { - ['@test should get arbitrary properties on an object'](assert) { - let obj = createTracked({ - string: 'string', - number: 23, - boolTrue: true, - boolFalse: false, - nullValue: null - }); - - for (let key in obj) { - assert.equal(get(obj, key), obj[key], key); + moduleFor( + 'tracked get', + class extends AbstractTestCase { + ['@test should get arbitrary properties on an object'](assert) { + let obj = createTracked({ + string: 'string', + number: 23, + boolTrue: true, + boolFalse: false, + nullValue: null + }); + + for (let key in obj) { + assert.equal(get(obj, key), obj[key], key); + } } - } - ['@test should retrieve a number key on an object'](assert) { - let obj = createTracked({ 1: 'first' }); + ['@test should retrieve a number key on an object'](assert) { + let obj = createTracked({ 1: 'first' }); - assert.equal(get(obj, 1), 'first'); - } + assert.equal(get(obj, 1), 'first'); + } - ['@test should not access a property more than once'](assert) { - let count = 20; + ['@test should not access a property more than once'](assert) { + let count = 20; - class Count { - get id() { - return ++count; + class Count { + get id() { + return ++count; + } } - } - tracked(Count.prototype, 'id', Object.getOwnPropertyDescriptor(Count.prototype, 'id')); + tracked( + Count.prototype, + 'id', + Object.getOwnPropertyDescriptor(Count.prototype, 'id') + ); - let obj = new Count(); + let obj = new Count(); - get(obj, 'id'); + get(obj, 'id'); - assert.equal(count, 21); - } - }); - - moduleFor('tracked getWithDefault', class extends AbstractTestCase { - ['@test should get arbitrary properties on an object'](assert) { - let obj = createTracked({ - string: 'string', - number: 23, - boolTrue: true, - boolFalse: false, - nullValue: null - }); - - for (let key in obj) { - assert.equal(getWithDefault(obj, key, 'fail'), obj[key], key); + assert.equal(count, 21); } - - obj = createTracked({ - undef: undefined - }); - - assert.equal(getWithDefault(obj, 'undef', 'default'), 'default', 'explicit undefined retrieves the default'); - assert.equal(getWithDefault(obj, 'not-present', 'default'), 'default', 'non-present key retrieves the default'); } - }); + ); + + moduleFor( + 'tracked getWithDefault', + class extends AbstractTestCase { + ['@test should get arbitrary properties on an object'](assert) { + let obj = createTracked({ + string: 'string', + number: 23, + boolTrue: true, + boolFalse: false, + nullValue: null + }); + + for (let key in obj) { + assert.equal(getWithDefault(obj, key, 'fail'), obj[key], key); + } + obj = createTracked({ + undef: undefined + }); + + assert.equal( + getWithDefault(obj, 'undef', 'default'), + 'default', + 'explicit undefined retrieves the default' + ); + assert.equal( + getWithDefault(obj, 'not-present', 'default'), + 'default', + 'non-present key retrieves the default' + ); + } + } + ); } diff --git a/packages/ember-metal/tests/tracked/set_test.js b/packages/ember-metal/tests/tracked/set_test.js index 79f312c8f62..3389493bdda 100644 --- a/packages/ember-metal/tests/tracked/set_test.js +++ b/packages/ember-metal/tests/tracked/set_test.js @@ -1,8 +1,4 @@ -import { - get, - set, - setHasViews -} from '../..'; +import { get, set, setHasViews } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; import { createTracked } from './support'; @@ -10,38 +6,43 @@ import { createTracked } from './support'; import { EMBER_METAL_TRACKED_PROPERTIES } from 'ember/features'; if (EMBER_METAL_TRACKED_PROPERTIES) { + moduleFor( + 'tracked set', + class extends AbstractTestCase { + teardown() { + setHasViews(() => false); + } - moduleFor('tracked set', class extends AbstractTestCase { - teardown() { - setHasViews(() => false); - } - - ['@test should set arbitrary properties on an object'](assert) { - let obj = createTracked({ - string: 'string', - number: 23, - boolTrue: true, - boolFalse: false, - nullValue: null, - undefinedValue: undefined - }); - - let newObj = createTracked({ - undefinedValue: 'emberjs' - }); - - for (let key in obj) { - assert.equal(set(newObj, key, obj[key]), obj[key], 'should return value'); - assert.equal(get(newObj, key), obj[key], 'should set value'); + ['@test should set arbitrary properties on an object'](assert) { + let obj = createTracked({ + string: 'string', + number: 23, + boolTrue: true, + boolFalse: false, + nullValue: null, + undefinedValue: undefined + }); + + let newObj = createTracked({ + undefinedValue: 'emberjs' + }); + + for (let key in obj) { + assert.equal( + set(newObj, key, obj[key]), + obj[key], + 'should return value' + ); + assert.equal(get(newObj, key), obj[key], 'should set value'); + } } - } - ['@test should set a number key on an object'](assert) { - let obj = createTracked({ 1: 'original' }); + ['@test should set a number key on an object'](assert) { + let obj = createTracked({ 1: 'original' }); - set(obj, 1, 'first'); - assert.equal(obj[1], 'first'); + set(obj, 1, 'first'); + assert.equal(obj[1], 'first'); + } } - }); - + ); } diff --git a/packages/ember-metal/tests/tracked/support.js b/packages/ember-metal/tests/tracked/support.js index 30221acd21a..96834c18573 100644 --- a/packages/ember-metal/tests/tracked/support.js +++ b/packages/ember-metal/tests/tracked/support.js @@ -1,6 +1,4 @@ -import { - tracked -} from '../..'; +import { tracked } from '../..'; export function createTracked(values, proto = {}) { function Class() { @@ -10,7 +8,16 @@ export function createTracked(values, proto = {}) { } for (let prop in values) { - Object.defineProperty(proto, prop, tracked(proto, prop, { enumerable: true, configurable: true, writable: true, value: values[prop] })); + Object.defineProperty( + proto, + prop, + tracked(proto, prop, { + enumerable: true, + configurable: true, + writable: true, + value: values[prop] + }) + ); } Class.prototype = proto; @@ -23,7 +30,11 @@ export function createWithDescriptors(values) { for (let prop in values) { let descriptor = Object.getOwnPropertyDescriptor(values, prop); - Object.defineProperty(Class.prototype, prop, tracked(Class.prototype, prop, descriptor)); + Object.defineProperty( + Class.prototype, + prop, + tracked(Class.prototype, prop, descriptor) + ); } return new Class(); diff --git a/packages/ember-metal/tests/tracked/validation_test.js b/packages/ember-metal/tests/tracked/validation_test.js index 153d0f3a1a4..5a86995ee43 100644 --- a/packages/ember-metal/tests/tracked/validation_test.js +++ b/packages/ember-metal/tests/tracked/validation_test.js @@ -1,10 +1,4 @@ -import { - computed, - defineProperty, - get, - set, - tracked -} from '../..'; +import { computed, defineProperty, get, set, tracked } from '../..'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; import { tagForProperty } from '../..'; @@ -12,182 +6,219 @@ import { tagForProperty } from '../..'; import { EMBER_METAL_TRACKED_PROPERTIES } from 'ember/features'; if (EMBER_METAL_TRACKED_PROPERTIES) { - - moduleFor('tracked get validation', class extends AbstractTestCase { - [`@test validators for tracked getters with dependencies should invalidate when the dependencies invalidate`](assert) { - class Tracked { - constructor(first, last) { - this.first = first; - this.last = last; + moduleFor( + 'tracked get validation', + class extends AbstractTestCase { + [`@test validators for tracked getters with dependencies should invalidate when the dependencies invalidate`]( + assert + ) { + class Tracked { + constructor(first, last) { + this.first = first; + this.last = last; + } } - } - track(Tracked, ['first', 'last'], { - get full() { - return `${this.first} ${this.last}`; - } - }); + track(Tracked, ['first', 'last'], { + get full() { + return `${this.first} ${this.last}`; + } + }); - let obj = new Tracked('Tom', 'Dale'); + let obj = new Tracked('Tom', 'Dale'); - let tag = tagForProperty(obj, 'full'); - let snapshot = tag.value(); + let tag = tagForProperty(obj, 'full'); + let snapshot = tag.value(); - let full = obj.full; - assert.equal(full, 'Tom Dale', 'The full name starts correct'); - assert.equal(tag.validate(snapshot), true); + let full = obj.full; + assert.equal(full, 'Tom Dale', 'The full name starts correct'); + assert.equal(tag.validate(snapshot), true); - snapshot = tag.value(); - assert.equal(tag.validate(snapshot), true); + snapshot = tag.value(); + assert.equal(tag.validate(snapshot), true); - obj.first = 'Thomas'; - assert.equal(tag.validate(snapshot), false); + obj.first = 'Thomas'; + assert.equal(tag.validate(snapshot), false); - assert.equal(obj.full, 'Thomas Dale'); - snapshot = tag.value(); - - assert.equal(tag.validate(snapshot), true); - } + assert.equal(obj.full, 'Thomas Dale'); + snapshot = tag.value(); - [`@test interaction with Ember object model (tracked property depending on Ember property)`](assert) { - class Tracked { - constructor(name) { - this.name = name; - } + assert.equal(tag.validate(snapshot), true); } - track(Tracked, ['name'], { - get full() { - return `${get(this.name, 'first')} ${get(this.name, 'last')}`; + [`@test interaction with Ember object model (tracked property depending on Ember property)`]( + assert + ) { + class Tracked { + constructor(name) { + this.name = name; + } } - }); - let tom = { first: 'Tom', last: 'Dale' }; + track(Tracked, ['name'], { + get full() { + return `${get(this.name, 'first')} ${get(this.name, 'last')}`; + } + }); - let obj = new Tracked(tom); + let tom = { first: 'Tom', last: 'Dale' }; - let tag = tagForProperty(obj, 'full'); - let snapshot = tag.value(); + let obj = new Tracked(tom); - let full = obj.full; - assert.equal(full, 'Tom Dale'); - assert.equal(tag.validate(snapshot), true); + let tag = tagForProperty(obj, 'full'); + let snapshot = tag.value(); - snapshot = tag.value(); - assert.equal(tag.validate(snapshot), true); + let full = obj.full; + assert.equal(full, 'Tom Dale'); + assert.equal(tag.validate(snapshot), true); - set(tom, 'first', 'Thomas'); - assert.equal(tag.validate(snapshot), false, 'invalid after setting with Ember set'); + snapshot = tag.value(); + assert.equal(tag.validate(snapshot), true); - assert.equal(obj.full, 'Thomas Dale'); - snapshot = tag.value(); + set(tom, 'first', 'Thomas'); + assert.equal( + tag.validate(snapshot), + false, + 'invalid after setting with Ember set' + ); - assert.equal(tag.validate(snapshot), true); - } + assert.equal(obj.full, 'Thomas Dale'); + snapshot = tag.value(); - [`@test interaction with Ember object model (Ember computed property depending on tracked property)`](assert) { - class EmberObject { - constructor(name) { - this.name = name; - } + assert.equal(tag.validate(snapshot), true); } - defineProperty(EmberObject.prototype, 'full', computed('name', function() { - let name = get(this, 'name'); - return `${name.first} ${name.last}`; - })); - - class Name { - constructor(first, last) { - this.first = first; - this.last = last; + [`@test interaction with Ember object model (Ember computed property depending on tracked property)`]( + assert + ) { + class EmberObject { + constructor(name) { + this.name = name; + } } - } - track(Name, ['first', 'last']); + defineProperty( + EmberObject.prototype, + 'full', + computed('name', function() { + let name = get(this, 'name'); + return `${name.first} ${name.last}`; + }) + ); + + class Name { + constructor(first, last) { + this.first = first; + this.last = last; + } + } - let tom = new Name('Tom', 'Dale'); - let obj = new EmberObject(tom); + track(Name, ['first', 'last']); - let tag = tagForProperty(obj, 'full'); - let snapshot = tag.value(); + let tom = new Name('Tom', 'Dale'); + let obj = new EmberObject(tom); - let full = get(obj, 'full'); - assert.equal(full, 'Tom Dale'); - assert.equal(tag.validate(snapshot), true); + let tag = tagForProperty(obj, 'full'); + let snapshot = tag.value(); - snapshot = tag.value(); - assert.equal(tag.validate(snapshot), true); + let full = get(obj, 'full'); + assert.equal(full, 'Tom Dale'); + assert.equal(tag.validate(snapshot), true); - tom.first = 'Thomas'; - assert.equal(tag.validate(snapshot), false, 'invalid after setting with tracked properties'); + snapshot = tag.value(); + assert.equal(tag.validate(snapshot), true); - assert.equal(get(obj, 'full'), 'Thomas Dale'); - snapshot = tag.value(); + tom.first = 'Thomas'; + assert.equal( + tag.validate(snapshot), + false, + 'invalid after setting with tracked properties' + ); - // assert.equal(tag.validate(snapshot), true); - } + assert.equal(get(obj, 'full'), 'Thomas Dale'); + snapshot = tag.value(); - ['@test interaction with the Ember object model (paths going through tracked properties)'](assert) { - class EmberObject { - constructor(contact) { - this.contact = contact; - } + // assert.equal(tag.validate(snapshot), true); } - defineProperty(EmberObject.prototype, 'full', computed('contact.name.first', 'contact.name.last', function() { - let contact = get(this, 'contact'); - return `${get(contact.name, 'first')} ${get(contact.name, 'last')}`; - })); + ['@test interaction with the Ember object model (paths going through tracked properties)']( + assert + ) { + class EmberObject { + constructor(contact) { + this.contact = contact; + } + } - class Contact { - constructor(name) { - this.name = name; + defineProperty( + EmberObject.prototype, + 'full', + computed('contact.name.first', 'contact.name.last', function() { + let contact = get(this, 'contact'); + return `${get(contact.name, 'first')} ${get(contact.name, 'last')}`; + }) + ); + + class Contact { + constructor(name) { + this.name = name; + } } - } - track(Contact, ['name']); + track(Contact, ['name']); - class EmberName { - constructor(first, last) { - this.first = first; - this.last = last; + class EmberName { + constructor(first, last) { + this.first = first; + this.last = last; + } } - } - let tom = new EmberName('Tom', 'Dale'); - let contact = new Contact(tom); - let obj = new EmberObject(contact); + let tom = new EmberName('Tom', 'Dale'); + let contact = new Contact(tom); + let obj = new EmberObject(contact); - let tag = tagForProperty(obj, 'full'); - let snapshot = tag.value(); + let tag = tagForProperty(obj, 'full'); + let snapshot = tag.value(); - let full = get(obj, 'full'); - assert.equal(full, 'Tom Dale'); - assert.equal(tag.validate(snapshot), true); + let full = get(obj, 'full'); + assert.equal(full, 'Tom Dale'); + assert.equal(tag.validate(snapshot), true); - snapshot = tag.value(); - assert.equal(tag.validate(snapshot), true); + snapshot = tag.value(); + assert.equal(tag.validate(snapshot), true); - set(tom, 'first', 'Thomas'); - assert.equal(tag.validate(snapshot), false, 'invalid after setting with Ember.set'); + set(tom, 'first', 'Thomas'); + assert.equal( + tag.validate(snapshot), + false, + 'invalid after setting with Ember.set' + ); - assert.equal(get(obj, 'full'), 'Thomas Dale'); - snapshot = tag.value(); + assert.equal(get(obj, 'full'), 'Thomas Dale'); + snapshot = tag.value(); - tom = contact.name = new EmberName('T', 'Dale'); - assert.equal(tag.validate(snapshot), false, 'invalid after setting with Ember.set'); + tom = contact.name = new EmberName('T', 'Dale'); + assert.equal( + tag.validate(snapshot), + false, + 'invalid after setting with Ember.set' + ); - assert.equal(get(obj, 'full'), 'T Dale'); - snapshot = tag.value(); + assert.equal(get(obj, 'full'), 'T Dale'); + snapshot = tag.value(); - set(tom, 'first', 'Tizzle'); - assert.equal(tag.validate(snapshot), false, 'invalid after setting with Ember.set'); + set(tom, 'first', 'Tizzle'); + assert.equal( + tag.validate(snapshot), + false, + 'invalid after setting with Ember.set' + ); - assert.equal(get(obj, 'full'), 'Tizzle Dale'); + assert.equal(get(obj, 'full'), 'Tizzle Dale'); + } } - }); - + ); } function track(Class, properties, accessors = {}) { @@ -197,18 +228,28 @@ function track(Class, properties, accessors = {}) { let keys = Object.getOwnPropertyNames(accessors); - keys.forEach(key => defineAccessor(proto, key, Object.getOwnPropertyDescriptor(accessors, key))); + keys.forEach(key => + defineAccessor(proto, key, Object.getOwnPropertyDescriptor(accessors, key)) + ); } function defineData(prototype, property) { - Object.defineProperty(prototype, property, tracked(prototype, property, { - enumerable: true, - configurable: true, - writable: true, - value: undefined - })); + Object.defineProperty( + prototype, + property, + tracked(prototype, property, { + enumerable: true, + configurable: true, + writable: true, + value: undefined + }) + ); } function defineAccessor(prototype, property, descriptor) { - Object.defineProperty(prototype, property, tracked(prototype, property, descriptor)); + Object.defineProperty( + prototype, + property, + tracked(prototype, property, descriptor) + ); } diff --git a/packages/ember-metal/tests/watching/is_watching_test.js b/packages/ember-metal/tests/watching/is_watching_test.js index 5ced6198d08..c22f1cd7109 100644 --- a/packages/ember-metal/tests/watching/is_watching_test.js +++ b/packages/ember-metal/tests/watching/is_watching_test.js @@ -14,57 +14,96 @@ function testObserver(assert, setup, teardown, key = 'key') { let obj = {}; function fn() {} - assert.equal(isWatching(obj, key), false, 'precond - isWatching is false by default'); + assert.equal( + isWatching(obj, key), + false, + 'precond - isWatching is false by default' + ); setup(obj, key, fn); - assert.equal(isWatching(obj, key), true, 'isWatching is true when observers are added'); + assert.equal( + isWatching(obj, key), + true, + 'isWatching is true when observers are added' + ); teardown(obj, key, fn); - assert.equal(isWatching(obj, key), false, 'isWatching is false after observers are removed'); + assert.equal( + isWatching(obj, key), + false, + 'isWatching is false after observers are removed' + ); } -moduleFor('isWatching', class extends AbstractTestCase { - ['@test isWatching is true for regular local observers'](assert) { - testObserver(assert, (obj, key, fn) => { - Mixin.create({ - didChange: observer(key, fn) - }).apply(obj); - }, (obj, key, fn) => removeObserver(obj, key, obj, fn)); - } +moduleFor( + 'isWatching', + class extends AbstractTestCase { + ['@test isWatching is true for regular local observers'](assert) { + testObserver( + assert, + (obj, key, fn) => { + Mixin.create({ + didChange: observer(key, fn) + }).apply(obj); + }, + (obj, key, fn) => removeObserver(obj, key, obj, fn) + ); + } - ['@test isWatching is true for nonlocal observers'](assert) { - testObserver(assert, (obj, key, fn) => { - addObserver(obj, key, obj, fn); - }, (obj, key, fn) => removeObserver(obj, key, obj, fn)); - } + ['@test isWatching is true for nonlocal observers'](assert) { + testObserver( + assert, + (obj, key, fn) => { + addObserver(obj, key, obj, fn); + }, + (obj, key, fn) => removeObserver(obj, key, obj, fn) + ); + } - ['@test isWatching is true for chained observers'](assert) { - testObserver(assert, function(obj, key, fn) { - addObserver(obj, key + '.bar', obj, fn); - }, function(obj, key, fn) { - removeObserver(obj, key + '.bar', obj, fn); - }); - } + ['@test isWatching is true for chained observers'](assert) { + testObserver( + assert, + function(obj, key, fn) { + addObserver(obj, key + '.bar', obj, fn); + }, + function(obj, key, fn) { + removeObserver(obj, key + '.bar', obj, fn); + } + ); + } - ['@test isWatching is true for computed properties'](assert) { - testObserver(assert, (obj, key, fn) => { - defineProperty(obj, 'computed', computed(fn).property(key)); - get(obj, 'computed'); - }, obj => defineProperty(obj, 'computed', null)); - } + ['@test isWatching is true for computed properties'](assert) { + testObserver( + assert, + (obj, key, fn) => { + defineProperty(obj, 'computed', computed(fn).property(key)); + get(obj, 'computed'); + }, + obj => defineProperty(obj, 'computed', null) + ); + } - ['@test isWatching is true for chained computed properties'](assert) { - testObserver(assert, (obj, key, fn) => { - defineProperty(obj, 'computed', computed(fn).property(key + '.bar')); - get(obj, 'computed'); - }, obj => defineProperty(obj, 'computed', null)); - } + ['@test isWatching is true for chained computed properties'](assert) { + testObserver( + assert, + (obj, key, fn) => { + defineProperty(obj, 'computed', computed(fn).property(key + '.bar')); + get(obj, 'computed'); + }, + obj => defineProperty(obj, 'computed', null) + ); + } - // can't watch length on Array - it is special... - // But you should be able to watch a length property of an object - ['@test isWatching is true for \'length\' property on object'](assert) { - testObserver(assert, (obj, key, fn) => { - defineProperty(obj, 'length', null, '26.2 miles'); - addObserver(obj, 'length', obj, fn); - }, (obj, key, fn) => removeObserver(obj, 'length', obj, fn), 'length'); + // can't watch length on Array - it is special... + // But you should be able to watch a length property of an object + ["@test isWatching is true for 'length' property on object"](assert) { + testObserver( + assert, + (obj, key, fn) => { + defineProperty(obj, 'length', null, '26.2 miles'); + addObserver(obj, 'length', obj, fn); + }, + (obj, key, fn) => removeObserver(obj, 'length', obj, fn), + 'length' + ); + } } -}); - +); diff --git a/packages/ember-metal/tests/watching/unwatch_test.js b/packages/ember-metal/tests/watching/unwatch_test.js index 455b4176cda..10ed03bb2bf 100644 --- a/packages/ember-metal/tests/watching/unwatch_test.js +++ b/packages/ember-metal/tests/watching/unwatch_test.js @@ -6,10 +6,7 @@ import { computed, set } from '../..'; -import { - moduleFor, - AbstractTestCase -} from 'internal-test-helpers'; +import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; let didCount; @@ -17,93 +14,105 @@ function addListeners(obj, keyPath) { addListener(obj, keyPath + ':change', () => didCount++); } -moduleFor('unwatch', class extends AbstractTestCase { - beforeEach() { - didCount = 0; - } - - ['@test unwatching a computed property - regular get/set'](assert) { - let obj = {}; - - defineProperty(obj, 'foo', computed({ - get() { - return this.__foo; - }, - set(keyName, value) { - this.__foo = value; - return this.__foo; - } - })); - addListeners(obj, 'foo'); - - watch(obj, 'foo'); - set(obj, 'foo', 'bar'); - assert.equal(didCount, 1, 'should have invoked didCount'); - - unwatch(obj, 'foo'); - didCount = 0; - set(obj, 'foo', 'BAZ'); - assert.equal(didCount, 0, 'should NOT have invoked didCount'); - } - - ['@test unwatching a regular property - regular get/set'](assert) { - let obj = { foo: 'BIFF' }; - addListeners(obj, 'foo'); - - watch(obj, 'foo'); - set(obj, 'foo', 'bar'); - assert.equal(didCount, 1, 'should have invoked didCount'); - - unwatch(obj, 'foo'); - didCount = 0; - set(obj, 'foo', 'BAZ'); - assert.equal(didCount, 0, 'should NOT have invoked didCount'); - } - - ['@test unwatching should be nested'](assert) { - let obj = { foo: 'BIFF' }; - addListeners(obj, 'foo'); - - watch(obj, 'foo'); - watch(obj, 'foo'); - set(obj, 'foo', 'bar'); - assert.equal(didCount, 1, 'should have invoked didCount'); - - unwatch(obj, 'foo'); - didCount = 0; - set(obj, 'foo', 'BAZ'); - assert.equal(didCount, 1, 'should NOT have invoked didCount'); - - unwatch(obj, 'foo'); - didCount = 0; - set(obj, 'foo', 'BAZ'); - assert.equal(didCount, 0, 'should NOT have invoked didCount'); - } - - ['@test unwatching "length" property on an object'](assert) { - let obj = { foo: 'RUN' }; - addListeners(obj, 'length'); - - // Can watch length when it is undefined - watch(obj, 'length'); - set(obj, 'length', '10k'); - assert.equal(didCount, 1, 'should have invoked didCount'); - - // Should stop watching despite length now being defined (making object 'array-like') - unwatch(obj, 'length'); - didCount = 0; - set(obj, 'length', '5k'); - assert.equal(didCount, 0, 'should NOT have invoked didCount'); +moduleFor( + 'unwatch', + class extends AbstractTestCase { + beforeEach() { + didCount = 0; + } + + ['@test unwatching a computed property - regular get/set'](assert) { + let obj = {}; + + defineProperty( + obj, + 'foo', + computed({ + get() { + return this.__foo; + }, + set(keyName, value) { + this.__foo = value; + return this.__foo; + } + }) + ); + addListeners(obj, 'foo'); + + watch(obj, 'foo'); + set(obj, 'foo', 'bar'); + assert.equal(didCount, 1, 'should have invoked didCount'); + + unwatch(obj, 'foo'); + didCount = 0; + set(obj, 'foo', 'BAZ'); + assert.equal(didCount, 0, 'should NOT have invoked didCount'); + } + + ['@test unwatching a regular property - regular get/set'](assert) { + let obj = { foo: 'BIFF' }; + addListeners(obj, 'foo'); + + watch(obj, 'foo'); + set(obj, 'foo', 'bar'); + assert.equal(didCount, 1, 'should have invoked didCount'); + + unwatch(obj, 'foo'); + didCount = 0; + set(obj, 'foo', 'BAZ'); + assert.equal(didCount, 0, 'should NOT have invoked didCount'); + } + + ['@test unwatching should be nested'](assert) { + let obj = { foo: 'BIFF' }; + addListeners(obj, 'foo'); + + watch(obj, 'foo'); + watch(obj, 'foo'); + set(obj, 'foo', 'bar'); + assert.equal(didCount, 1, 'should have invoked didCount'); + + unwatch(obj, 'foo'); + didCount = 0; + set(obj, 'foo', 'BAZ'); + assert.equal(didCount, 1, 'should NOT have invoked didCount'); + + unwatch(obj, 'foo'); + didCount = 0; + set(obj, 'foo', 'BAZ'); + assert.equal(didCount, 0, 'should NOT have invoked didCount'); + } + + ['@test unwatching "length" property on an object'](assert) { + let obj = { foo: 'RUN' }; + addListeners(obj, 'length'); + + // Can watch length when it is undefined + watch(obj, 'length'); + set(obj, 'length', '10k'); + assert.equal(didCount, 1, 'should have invoked didCount'); + + // Should stop watching despite length now being defined (making object 'array-like') + unwatch(obj, 'length'); + didCount = 0; + set(obj, 'length', '5k'); + assert.equal(didCount, 0, 'should NOT have invoked didCount'); + } + + ['@test unwatching should not destroy non MANDATORY_SETTER descriptor']( + assert + ) { + let obj = { + get foo() { + return 'RUN'; + } + }; + + assert.equal(obj.foo, 'RUN', 'obj.foo'); + watch(obj, 'foo'); + assert.equal(obj.foo, 'RUN', 'obj.foo after watch'); + unwatch(obj, 'foo'); + assert.equal(obj.foo, 'RUN', 'obj.foo after unwatch'); + } } - - ['@test unwatching should not destroy non MANDATORY_SETTER descriptor'](assert) { - let obj = { get foo() { return 'RUN'; } }; - - assert.equal(obj.foo, 'RUN', 'obj.foo'); - watch(obj, 'foo'); - assert.equal(obj.foo, 'RUN', 'obj.foo after watch'); - unwatch(obj, 'foo'); - assert.equal(obj.foo, 'RUN', 'obj.foo after unwatch'); - } -}); - +); diff --git a/packages/ember-metal/tests/watching/watch_test.js b/packages/ember-metal/tests/watching/watch_test.js index bc752e9fd03..bf3e62b2006 100644 --- a/packages/ember-metal/tests/watching/watch_test.js +++ b/packages/ember-metal/tests/watching/watch_test.js @@ -10,10 +10,7 @@ import { unwatch, deleteMeta } from '../..'; -import { - moduleFor, - AbstractTestCase -} from 'internal-test-helpers'; +import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; let didCount, didKeys, originalLookup; @@ -24,220 +21,266 @@ function addListeners(obj, keyPath) { }); } -moduleFor('watch', class extends AbstractTestCase { - beforeEach() { - didCount = 0; - didKeys = []; - - originalLookup = context.lookup; - context.lookup = {}; - } - - afterEach() { - context.lookup = originalLookup; - } - - ['@test watching a computed property'](assert) { - let obj = {}; - defineProperty(obj, 'foo', computed({ - get() { - return this.__foo; - }, - set(keyName, value) { - if (value !== undefined) { - this.__foo = value; +moduleFor( + 'watch', + class extends AbstractTestCase { + beforeEach() { + didCount = 0; + didKeys = []; + + originalLookup = context.lookup; + context.lookup = {}; + } + + afterEach() { + context.lookup = originalLookup; + } + + ['@test watching a computed property'](assert) { + let obj = {}; + defineProperty( + obj, + 'foo', + computed({ + get() { + return this.__foo; + }, + set(keyName, value) { + if (value !== undefined) { + this.__foo = value; + } + return this.__foo; + } + }) + ); + addListeners(obj, 'foo'); + + watch(obj, 'foo'); + set(obj, 'foo', 'bar'); + assert.equal(didCount, 1, 'should have invoked didCount'); + } + + ['@test watching a regular defined property'](assert) { + let obj = { foo: 'baz' }; + addListeners(obj, 'foo'); + + watch(obj, 'foo'); + assert.equal(get(obj, 'foo'), 'baz', 'should have original prop'); + + set(obj, 'foo', 'bar'); + assert.equal(didCount, 1, 'should have invoked didCount'); + + assert.equal(get(obj, 'foo'), 'bar', 'should get new value'); + assert.equal(obj.foo, 'bar', 'property should be accessible on obj'); + } + + ['@test watching a regular undefined property'](assert) { + let obj = {}; + addListeners(obj, 'foo'); + + watch(obj, 'foo'); + + assert.equal('foo' in obj, false, 'precond undefined'); + + set(obj, 'foo', 'bar'); + + assert.equal(didCount, 1, 'should have invoked didCount'); + + assert.equal(get(obj, 'foo'), 'bar', 'should get new value'); + assert.equal(obj.foo, 'bar', 'property should be accessible on obj'); + } + + ['@test watches should inherit'](assert) { + let obj = { foo: 'baz' }; + let objB = Object.create(obj); + + addListeners(obj, 'foo'); + watch(obj, 'foo'); + assert.equal(get(obj, 'foo'), 'baz', 'should have original prop'); + + set(obj, 'foo', 'bar'); + set(objB, 'foo', 'baz'); + assert.equal(didCount, 2, 'should have invoked didCount once only'); + } + + ['@test watching an object THEN defining it should work also'](assert) { + let obj = {}; + addListeners(obj, 'foo'); + + watch(obj, 'foo'); + + defineProperty(obj, 'foo'); + set(obj, 'foo', 'bar'); + + assert.equal(get(obj, 'foo'), 'bar', 'should have set'); + assert.equal(didCount, 1, 'should have invoked didChange once'); + } + + ['@test watching a chain then defining the property'](assert) { + let obj = {}; + let foo = { bar: 'bar' }; + addListeners(obj, 'foo.bar'); + addListeners(foo, 'bar'); + + watch(obj, 'foo.bar'); + + defineProperty(obj, 'foo', undefined, foo); + set(foo, 'bar', 'baz'); + + assert.deepEqual( + didKeys, + ['foo.bar', 'bar'], + 'should have invoked didChange with bar, foo.bar' + ); + assert.equal(didCount, 2, 'should have invoked didChange twice'); + } + + ['@test watching a chain then defining the nested property'](assert) { + let bar = {}; + let obj = { foo: bar }; + let baz = { baz: 'baz' }; + addListeners(obj, 'foo.bar.baz'); + addListeners(baz, 'baz'); + + watch(obj, 'foo.bar.baz'); + + defineProperty(bar, 'bar', undefined, baz); + set(baz, 'baz', 'BOO'); + + assert.deepEqual( + didKeys, + ['foo.bar.baz', 'baz'], + 'should have invoked didChange with bar, foo.bar' + ); + assert.equal(didCount, 2, 'should have invoked didChange twice'); + } + + ['@test watching an object value then unwatching should restore old value']( + assert + ) { + let obj = { foo: { bar: { baz: { biff: 'BIFF' } } } }; + addListeners(obj, 'foo.bar.baz.biff'); + + watch(obj, 'foo.bar.baz.biff'); + + let foo = get(obj, 'foo'); + assert.equal( + get(get(get(foo, 'bar'), 'baz'), 'biff'), + 'BIFF', + 'biff should exist' + ); + + unwatch(obj, 'foo.bar.baz.biff'); + assert.equal( + get(get(get(foo, 'bar'), 'baz'), 'biff'), + 'BIFF', + 'biff should exist' + ); + } + + ['@test when watching another object, destroy should remove chain watchers from the other object']( + assert + ) { + let objA = {}; + let objB = { foo: 'bar' }; + objA.b = objB; + addListeners(objA, 'b.foo'); + + watch(objA, 'b.foo'); + + let meta_objB = meta(objB); + let chainNode = meta(objA).readableChains()._chains.b._chains.foo; + + assert.equal(meta_objB.peekWatching('foo'), 1, 'should be watching foo'); + assert.equal( + meta_objB.readableChainWatchers().has('foo', chainNode), + true, + 'should have chain watcher' + ); + + deleteMeta(objA); + + assert.equal( + meta_objB.peekWatching('foo'), + 0, + 'should not be watching foo' + ); + assert.equal( + meta_objB.readableChainWatchers().has('foo', chainNode), + false, + 'should not have chain watcher' + ); + } + + // TESTS for length property + + ['@test watching "length" property on an object'](assert) { + let obj = { length: '26.2 miles' }; + addListeners(obj, 'length'); + + watch(obj, 'length'); + assert.equal( + get(obj, 'length'), + '26.2 miles', + 'should have original prop' + ); + + set(obj, 'length', '10k'); + assert.equal(didCount, 1, 'should have invoked didCount'); + + assert.equal(get(obj, 'length'), '10k', 'should get new value'); + assert.equal(obj.length, '10k', 'property should be accessible on obj'); + } + + ['@test watching "length" property on an array'](assert) { + let arr = []; + addListeners(arr, 'length'); + + watch(arr, 'length'); + assert.equal(get(arr, 'length'), 0, 'should have original prop'); + + set(arr, 'length', '10'); + assert.equal(didCount, 1, 'should NOT have invoked didCount'); + + assert.equal(get(arr, 'length'), 10, 'should get new value'); + assert.equal(arr.length, 10, 'property should be accessible on arr'); + } + + ['@test watch + ES5 getter'](assert) { + let parent = { b: 1 }; + let child = { + get b() { + return parent.b; } - return this.__foo; - } - })); - addListeners(obj, 'foo'); - - watch(obj, 'foo'); - set(obj, 'foo', 'bar'); - assert.equal(didCount, 1, 'should have invoked didCount'); - } - - ['@test watching a regular defined property'](assert) { - let obj = { foo: 'baz' }; - addListeners(obj, 'foo'); - - watch(obj, 'foo'); - assert.equal(get(obj, 'foo'), 'baz', 'should have original prop'); - - set(obj, 'foo', 'bar'); - assert.equal(didCount, 1, 'should have invoked didCount'); - - assert.equal(get(obj, 'foo'), 'bar', 'should get new value'); - assert.equal(obj.foo, 'bar', 'property should be accessible on obj'); - } - - ['@test watching a regular undefined property'](assert) { - let obj = { }; - addListeners(obj, 'foo'); - - watch(obj, 'foo'); - - assert.equal('foo' in obj, false, 'precond undefined'); - - set(obj, 'foo', 'bar'); - - assert.equal(didCount, 1, 'should have invoked didCount'); - - assert.equal(get(obj, 'foo'), 'bar', 'should get new value'); - assert.equal(obj.foo, 'bar', 'property should be accessible on obj'); - } - - ['@test watches should inherit'](assert) { - let obj = { foo: 'baz' }; - let objB = Object.create(obj); - - addListeners(obj, 'foo'); - watch(obj, 'foo'); - assert.equal(get(obj, 'foo'), 'baz', 'should have original prop'); - - set(obj, 'foo', 'bar'); - set(objB, 'foo', 'baz'); - assert.equal(didCount, 2, 'should have invoked didCount once only'); - } - - ['@test watching an object THEN defining it should work also'](assert) { - let obj = {}; - addListeners(obj, 'foo'); - - watch(obj, 'foo'); - - defineProperty(obj, 'foo'); - set(obj, 'foo', 'bar'); - - assert.equal(get(obj, 'foo'), 'bar', 'should have set'); - assert.equal(didCount, 1, 'should have invoked didChange once'); - } - - ['@test watching a chain then defining the property'](assert) { - let obj = {}; - let foo = { bar: 'bar' }; - addListeners(obj, 'foo.bar'); - addListeners(foo, 'bar'); - - watch(obj, 'foo.bar'); - - defineProperty(obj, 'foo', undefined, foo); - set(foo, 'bar', 'baz'); - - assert.deepEqual(didKeys, ['foo.bar', 'bar'], 'should have invoked didChange with bar, foo.bar'); - assert.equal(didCount, 2, 'should have invoked didChange twice'); - } - - ['@test watching a chain then defining the nested property'](assert) { - let bar = {}; - let obj = { foo: bar }; - let baz = { baz: 'baz' }; - addListeners(obj, 'foo.bar.baz'); - addListeners(baz, 'baz'); - - watch(obj, 'foo.bar.baz'); - - defineProperty(bar, 'bar', undefined, baz); - set(baz, 'baz', 'BOO'); - - assert.deepEqual(didKeys, ['foo.bar.baz', 'baz'], 'should have invoked didChange with bar, foo.bar'); - assert.equal(didCount, 2, 'should have invoked didChange twice'); - } - - ['@test watching an object value then unwatching should restore old value'](assert) { - let obj = { foo: { bar: { baz: { biff: 'BIFF' } } } }; - addListeners(obj, 'foo.bar.baz.biff'); - - watch(obj, 'foo.bar.baz.biff'); - - let foo = get(obj, 'foo'); - assert.equal(get(get(get(foo, 'bar'), 'baz'), 'biff'), 'BIFF', 'biff should exist'); - - unwatch(obj, 'foo.bar.baz.biff'); - assert.equal(get(get(get(foo, 'bar'), 'baz'), 'biff'), 'BIFF', 'biff should exist'); - } - - ['@test when watching another object, destroy should remove chain watchers from the other object'](assert) { - let objA = {}; - let objB = { foo: 'bar' }; - objA.b = objB; - addListeners(objA, 'b.foo'); - - watch(objA, 'b.foo'); - - let meta_objB = meta(objB); - let chainNode = meta(objA).readableChains()._chains.b._chains.foo; - - assert.equal(meta_objB.peekWatching('foo'), 1, 'should be watching foo'); - assert.equal(meta_objB.readableChainWatchers().has('foo', chainNode), true, 'should have chain watcher'); - - deleteMeta(objA); + }; - assert.equal(meta_objB.peekWatching('foo'), 0, 'should not be watching foo'); - assert.equal(meta_objB.readableChainWatchers().has('foo', chainNode), false, 'should not have chain watcher'); - } - - // TESTS for length property - - ['@test watching "length" property on an object'](assert) { - let obj = { length: '26.2 miles' }; - addListeners(obj, 'length'); - - watch(obj, 'length'); - assert.equal(get(obj, 'length'), '26.2 miles', 'should have original prop'); - - set(obj, 'length', '10k'); - assert.equal(didCount, 1, 'should have invoked didCount'); - - assert.equal(get(obj, 'length'), '10k', 'should get new value'); - assert.equal(obj.length, '10k', 'property should be accessible on obj'); - } - - ['@test watching "length" property on an array'](assert) { - let arr = []; - addListeners(arr, 'length'); + assert.equal(parent.b, 1, 'parent.b should be 1'); + assert.equal(child.b, 1, 'child.b should be 1'); + assert.equal(get(child, 'b'), 1, 'get(child, "b") should be 1'); - watch(arr, 'length'); - assert.equal(get(arr, 'length'), 0, 'should have original prop'); + watch(child, 'b'); - set(arr, 'length', '10'); - assert.equal(didCount, 1, 'should NOT have invoked didCount'); + assert.equal(parent.b, 1, 'parent.b should be 1 (after watch)'); + assert.equal(child.b, 1, 'child.b should be 1 (after watch)'); - assert.equal(get(arr, 'length'), 10, 'should get new value'); - assert.equal(arr.length, 10, 'property should be accessible on arr'); - } - - ['@test watch + ES5 getter'](assert) { - let parent = { b: 1 }; - let child = { - get b() { - return parent.b; - } - }; - - assert.equal(parent.b, 1, 'parent.b should be 1'); - assert.equal(child.b, 1, 'child.b should be 1'); - assert.equal(get(child, 'b'), 1, 'get(child, "b") should be 1'); - - watch(child, 'b'); + assert.equal( + get(child, 'b'), + 1, + 'get(child, "b") should be 1 (after watch)' + ); + } - assert.equal(parent.b, 1, 'parent.b should be 1 (after watch)'); - assert.equal(child.b, 1, 'child.b should be 1 (after watch)'); + ['@test watch + set + no-descriptor'](assert) { + let child = {}; - assert.equal(get(child, 'b'), 1, 'get(child, "b") should be 1 (after watch)'); - } - - ['@test watch + set + no-descriptor'](assert) { - let child = { }; + assert.equal(child.b, undefined, 'child.b '); + assert.equal(get(child, 'b'), undefined, 'get(child, "b")'); - assert.equal(child.b, undefined, 'child.b '); - assert.equal(get(child, 'b'), undefined, 'get(child, "b")'); + watch(child, 'b'); + set(child, 'b', 1); - watch(child, 'b'); - set(child, 'b', 1); - - assert.equal(child.b, 1, 'child.b (after watch)'); - assert.equal(get(child, 'b'), 1, 'get(child, "b") (after watch)'); + assert.equal(child.b, 1, 'child.b (after watch)'); + assert.equal(get(child, 'b'), 1, 'get(child, "b") (after watch)'); + } } -}); - +); diff --git a/packages/ember-routing/lib/location/api.js b/packages/ember-routing/lib/location/api.js index f7940af7b07..10a5e8f3143 100644 --- a/packages/ember-routing/lib/location/api.js +++ b/packages/ember-routing/lib/location/api.js @@ -88,10 +88,16 @@ export default { */ create(options) { let implementation = options && options.implementation; - assert('Location.create: you must specify a \'implementation\' option', !!implementation); + assert( + "Location.create: you must specify a 'implementation' option", + !!implementation + ); let implementationClass = this.implementations[implementation]; - assert(`Location.create: ${implementation} is not a valid implementation`, !!implementationClass); + assert( + `Location.create: ${implementation} is not a valid implementation`, + !!implementationClass + ); return implementationClass.create(...arguments); }, diff --git a/packages/ember-routing/lib/location/auto_location.js b/packages/ember-routing/lib/location/auto_location.js index a8eb997de9f..a81cace6ba6 100644 --- a/packages/ember-routing/lib/location/auto_location.js +++ b/packages/ember-routing/lib/location/auto_location.js @@ -18,7 +18,6 @@ import { @module @ember/routing */ - /** AutoLocation will select the best location option based off browser support with the priority order: history, hash, none. @@ -142,8 +141,10 @@ export default EmberObject.extend({ detect() { let rootURL = this.rootURL; - assert('rootURL must end with a trailing forward slash e.g. "/app/"', - rootURL.charAt(rootURL.length - 1) === '/'); + assert( + 'rootURL must end with a trailing forward slash e.g. "/app/"', + rootURL.charAt(rootURL.length - 1) === '/' + ); let implementation = detectImplementation({ location: this.location, @@ -186,7 +187,10 @@ export default EmberObject.extend({ function delegateToConcreteImplementation(methodName) { return function(...args) { let concreteImplementation = get(this, 'concreteImplementation'); - assert('AutoLocation\'s detect() method should be called before calling any other hooks.', !!concreteImplementation); + assert( + "AutoLocation's detect() method should be called before calling any other hooks.", + !!concreteImplementation + ); return tryInvoke(concreteImplementation, methodName, args); }; } @@ -206,14 +210,7 @@ function delegateToConcreteImplementation(methodName) { */ function detectImplementation(options) { - let { - location, - userAgent, - history, - documentMode, - global, - rootURL - } = options; + let { location, userAgent, history, documentMode, global, rootURL } = options; let implementation = 'none'; let cancelRouterSetup = false; @@ -239,7 +236,10 @@ function detectImplementation(options) { // Be sure we're using a hashed path, otherwise let's switch over it to so // we start off clean and consistent. We'll count an index path with no // hash as "good enough" as well. - if (currentPath === hashPath || (currentPath === '/' && hashPath === '/#/')) { + if ( + currentPath === hashPath || + (currentPath === '/' && hashPath === '/#/') + ) { implementation = 'hash'; } else { // Our URL isn't in the expected hash-supported format, so we want to @@ -270,7 +270,10 @@ export function getHistoryPath(rootURL, location) { let rootURLIndex = path.indexOf(rootURL); let routeHash, hashParts; - assert(`Path ${path} does not start with the provided rootURL ${rootURL}`, rootURLIndex === 0); + assert( + `Path ${path} does not start with the provided rootURL ${rootURL}`, + rootURLIndex === 0 + ); // By convention, Ember.js routes using HashLocation are required to start // with `#/`. Anything else should NOT be considered a route and should diff --git a/packages/ember-routing/lib/location/hash_location.js b/packages/ember-routing/lib/location/hash_location.js index fa6216d23eb..e8586702da6 100644 --- a/packages/ember-routing/lib/location/hash_location.js +++ b/packages/ember-routing/lib/location/hash_location.js @@ -1,8 +1,4 @@ -import { - get, - set, - bind -} from 'ember-metal'; +import { get, set, bind } from 'ember-metal'; import { Object as EmberObject } from 'ember-runtime'; import EmberLocation from './api'; @@ -129,7 +125,9 @@ export default EmberObject.extend({ this._hashchangeHandler = bind(this, function() { let path = this.getURL(); - if (get(this, 'lastSetURL') === path) { return; } + if (get(this, 'lastSetURL') === path) { + return; + } set(this, 'lastSetURL', null); diff --git a/packages/ember-routing/lib/location/history_location.js b/packages/ember-routing/lib/location/history_location.js index abc658177d0..5f8069cd121 100644 --- a/packages/ember-routing/lib/location/history_location.js +++ b/packages/ember-routing/lib/location/history_location.js @@ -1,7 +1,4 @@ -import { - get, - set -} from 'ember-metal'; +import { get, set } from 'ember-metal'; import { Object as EmberObject } from 'ember-runtime'; import EmberLocation from './api'; @@ -15,13 +12,12 @@ let popstateFired = false; function _uuid() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { var r, v; - r = Math.random() * 16 | 0; - v = c === 'x' ? r : r & 3 | 8; + r = (Math.random() * 16) | 0; + v = c === 'x' ? r : (r & 3) | 8; return v.toString(16); }); } - /** HistoryLocation implements the location API using the browser's history.pushState API. @@ -86,7 +82,8 @@ export default EmberObject.extend({ let state = this.getState(); let path = this.formatURL(this.getURL()); - if (state && state.path === path) { // preserve existing state + if (state && state.path === path) { + // preserve existing state // used for webkit workaround, since there will be no initial popstate event this._previousURL = this.getURL(); } else { @@ -125,7 +122,7 @@ export default EmberObject.extend({ let url = path .replace(new RegExp(`^${baseURL}(?=/|$)`), '') .replace(new RegExp(`^${rootURL}(?=/|$)`), '') - .replace(/\/\/$/g,'/'); // remove extra slashes + .replace(/\/\/$/g, '/'); // remove extra slashes let search = location.search || ''; url += search + this.getHash(); @@ -239,7 +236,9 @@ export default EmberObject.extend({ // Ignore initial page load popstate event in Chrome if (!popstateFired) { popstateFired = true; - if (this.getURL() === this._previousURL) { return; } + if (this.getURL() === this._previousURL) { + return; + } } callback(this.getURL()); }; diff --git a/packages/ember-routing/lib/location/none_location.js b/packages/ember-routing/lib/location/none_location.js index e7001dbbc3c..fd75cfe2bc8 100644 --- a/packages/ember-routing/lib/location/none_location.js +++ b/packages/ember-routing/lib/location/none_location.js @@ -1,7 +1,4 @@ -import { - get, - set -} from 'ember-metal'; +import { get, set } from 'ember-metal'; import { assert } from 'ember-debug'; import { Object as EmberObject } from 'ember-runtime'; diff --git a/packages/ember-routing/lib/location/util.js b/packages/ember-routing/lib/location/util.js index 90a7df36cf7..945f9ebbc86 100644 --- a/packages/ember-routing/lib/location/util.js +++ b/packages/ember-routing/lib/location/util.js @@ -72,7 +72,9 @@ export function getOrigin(location) { @function supportsHashChange */ export function supportsHashChange(documentMode, global) { - return ('onhashchange' in global) && (documentMode === undefined || documentMode > 7); + return ( + 'onhashchange' in global && (documentMode === undefined || documentMode > 7) + ); } /* @@ -91,11 +93,13 @@ export function supportsHistory(userAgent, history) { // We only want Android 2 and 4.0, stock browser, and not Chrome which identifies // itself as 'Mobile Safari' as well, nor Windows Phone. - if ((userAgent.indexOf('Android 2.') !== -1 || - (userAgent.indexOf('Android 4.0') !== -1)) && - userAgent.indexOf('Mobile Safari') !== -1 && - userAgent.indexOf('Chrome') === -1 && - userAgent.indexOf('Windows Phone') === -1) { + if ( + (userAgent.indexOf('Android 2.') !== -1 || + userAgent.indexOf('Android 4.0') !== -1) && + userAgent.indexOf('Mobile Safari') !== -1 && + userAgent.indexOf('Chrome') === -1 && + userAgent.indexOf('Windows Phone') === -1 + ) { return false; } diff --git a/packages/ember-routing/lib/services/router.js b/packages/ember-routing/lib/services/router.js index dd8c293a1b5..c7332f19e11 100644 --- a/packages/ember-routing/lib/services/router.js +++ b/packages/ember-routing/lib/services/router.js @@ -2,15 +2,8 @@ @module ember */ -import { - Service, - readOnly -} from 'ember-runtime'; -import { - shallowEqual, - resemblesURL, - extractRouteArgs -} from '../utils'; +import { Service, readOnly } from 'ember-runtime'; +import { shallowEqual, resemblesURL, extractRouteArgs } from '../utils'; /** The Router service is the public API that provides component/view layer @@ -21,7 +14,6 @@ import { @category ember-routing-router-service */ const RouterService = Service.extend({ - /** Name of the current route. @@ -149,7 +141,12 @@ const RouterService = Service.extend({ let { routeName, models, queryParams } = extractRouteArgs(args); - let transition = this._router._doTransition(routeName, models, queryParams, true); + let transition = this._router._doTransition( + routeName, + models, + queryParams, + true + ); transition._keepDefaultQueryParamValues = true; return transition; @@ -210,17 +207,23 @@ const RouterService = Service.extend({ let { routeName, models, queryParams } = extractRouteArgs(args); let routerMicrolib = this._router._routerMicrolib; - if (!routerMicrolib.isActiveIntent(routeName, models, null)) { return false; } + if (!routerMicrolib.isActiveIntent(routeName, models, null)) { + return false; + } let hasQueryParams = Object.keys(queryParams).length > 0; if (hasQueryParams) { - this._router._prepareQueryParams(routeName, models, queryParams, true /* fromRouterService */); + this._router._prepareQueryParams( + routeName, + models, + queryParams, + true /* fromRouterService */ + ); return shallowEqual(queryParams, routerMicrolib.state.queryParams); } return true; } - }); export default RouterService; diff --git a/packages/ember-routing/lib/services/routing.js b/packages/ember-routing/lib/services/routing.js index 0453c0b8277..7ef90b10cc0 100644 --- a/packages/ember-routing/lib/services/routing.js +++ b/packages/ember-routing/lib/services/routing.js @@ -3,10 +3,7 @@ */ import { assign } from 'ember-utils'; -import { - Service, - readOnly -} from 'ember-runtime'; +import { Service, readOnly } from 'ember-runtime'; import { get } from 'ember-metal'; /** @@ -50,7 +47,9 @@ export default Service.extend({ generateURL(routeName, models, queryParams) { let router = get(this, 'router'); // return early when the router microlib is not present, which is the case for {{link-to}} in integration tests - if (!router._routerMicrolib) { return; } + if (!router._routerMicrolib) { + return; + } let visibleQueryParams = {}; if (queryParams) { @@ -58,15 +57,26 @@ export default Service.extend({ this.normalizeQueryParams(routeName, models, visibleQueryParams); } - return router.generate(routeName, ...models, { queryParams: visibleQueryParams }); + return router.generate(routeName, ...models, { + queryParams: visibleQueryParams + }); }, - isActiveForRoute(contexts, queryParams, routeName, routerState, isCurrentWhenSpecified) { + isActiveForRoute( + contexts, + queryParams, + routeName, + routerState, + isCurrentWhenSpecified + ) { let router = get(this, 'router'); let handlers = router._routerMicrolib.recognizer.handlersFor(routeName); let leafName = handlers[handlers.length - 1].handler; - let maximumContexts = numberOfContextsAcceptedByHandler(routeName, handlers); + let maximumContexts = numberOfContextsAcceptedByHandler( + routeName, + handlers + ); // NOTE: any ugliness in the calculation of activeness is largely // due to the fact that we support automatic normalizing of @@ -82,7 +92,12 @@ export default Service.extend({ routeName = leafName; } - return routerState.isActiveIntent(routeName, contexts, queryParams, !isCurrentWhenSpecified); + return routerState.isActiveIntent( + routeName, + contexts, + queryParams, + !isCurrentWhenSpecified + ); } }); diff --git a/packages/ember-routing/lib/system/controller_for.js b/packages/ember-routing/lib/system/controller_for.js index 2880e5851ac..42575d46121 100644 --- a/packages/ember-routing/lib/system/controller_for.js +++ b/packages/ember-routing/lib/system/controller_for.js @@ -9,6 +9,10 @@ @method controllerFor @private */ -export default function controllerFor(container, controllerName, lookupOptions) { +export default function controllerFor( + container, + controllerName, + lookupOptions +) { return container.lookup(`controller:${controllerName}`, lookupOptions); } diff --git a/packages/ember-routing/lib/system/dsl.js b/packages/ember-routing/lib/system/dsl.js index d07d7e44cd1..583db4835ca 100644 --- a/packages/ember-routing/lib/system/dsl.js +++ b/packages/ember-routing/lib/system/dsl.js @@ -19,15 +19,25 @@ class DSL { options = {}; } - assert(`'${name}' cannot be used as a route name.`, (() => { - if (options.overrideNameAssertion === true) { return true; } + assert( + `'${name}' cannot be used as a route name.`, + (() => { + if (options.overrideNameAssertion === true) { + return true; + } - return ['array', 'basic', 'object', 'application'].indexOf(name) === -1; - })()); + return ['array', 'basic', 'object', 'application'].indexOf(name) === -1; + })() + ); if (this.enableLoadingSubstates) { - createRoute(this, `${name}_loading`, { resetNamespace: options.resetNamespace }); - createRoute(this, `${name}_error`, { resetNamespace: options.resetNamespace, path: dummyErrorRoute }); + createRoute(this, `${name}_loading`, { + resetNamespace: options.resetNamespace + }); + createRoute(this, `${name}_error`, { + resetNamespace: options.resetNamespace, + path: dummyErrorRoute + }); } if (callback) { @@ -49,7 +59,9 @@ class DSL { let parts = name.split('.'); if (this.options.engineInfo) { - let localFullName = name.slice(this.options.engineInfo.fullName.length + 1); + let localFullName = name.slice( + this.options.engineInfo.fullName.length + 1 + ); let routeInfo = assign({ localFullName }, this.options.engineInfo); if (serialize) { @@ -58,10 +70,14 @@ class DSL { this.options.addRouteForEngine(name, routeInfo); } else if (serialize) { - throw new Error(`Defining a route serializer on route '${name}' outside an Engine is not allowed.`); + throw new Error( + `Defining a route serializer on route '${name}' outside an Engine is not allowed.` + ); } - if (url === '' || url === '/' || parts[parts.length - 1] === 'index') { this.explicitIndex = true; } + if (url === '' || url === '/' || parts[parts.length - 1] === 'index') { + this.explicitIndex = true; + } this.matches.push(url, name, callback); } @@ -137,13 +153,18 @@ class DSL { let substateName = `${name}_loading`; let localFullName = `application_loading`; let routeInfo = assign({ localFullName }, engineInfo); - createRoute(this, substateName, { resetNamespace: options.resetNamespace }); + createRoute(this, substateName, { + resetNamespace: options.resetNamespace + }); this.options.addRouteForEngine(substateName, routeInfo); substateName = `${name}_error`; localFullName = `application_error`; routeInfo = assign({ localFullName }, engineInfo); - createRoute(this, substateName, { resetNamespace: options.resetNamespace, path: dummyErrorRoute }); + createRoute(this, substateName, { + resetNamespace: options.resetNamespace, + path: dummyErrorRoute + }); this.options.addRouteForEngine(substateName, routeInfo); } diff --git a/packages/ember-routing/lib/system/query_params.js b/packages/ember-routing/lib/system/query_params.js index aa1d18582d0..8ba27d0770b 100644 --- a/packages/ember-routing/lib/system/query_params.js +++ b/packages/ember-routing/lib/system/query_params.js @@ -1,4 +1,3 @@ - export default class QueryParams { constructor(values = null) { this.values = values; diff --git a/packages/ember-routing/lib/system/route.js b/packages/ember-routing/lib/system/route.js index df2c0148343..d561b4af3da 100644 --- a/packages/ember-routing/lib/system/route.js +++ b/packages/ember-routing/lib/system/route.js @@ -27,10 +27,14 @@ import { prefixRouteNameArg } from '../utils'; -function K() { return this; } +function K() { + return this; +} export function defaultSerialize(model, params) { - if (params.length < 1 || !model) { return; } + if (params.length < 1 || !model) { + return; + } let object = {}; @@ -121,7 +125,12 @@ let Route = EmberObject.extend(ActionHandler, Evented, { deprecate( 'Route#router is an intimate API that has been renamed to Route#_router. However you might want to consider using the router service', false, - { id: 'ember-routing.route-router', until: '3.5.0', url: 'https://emberjs.com/deprecations/v3.x#toc_ember-routing-route-router' } + { + id: 'ember-routing.route-router', + until: '3.5.0', + url: + 'https://emberjs.com/deprecations/v3.x#toc_ember-routing-route-router' + } ); return this._router; }), @@ -164,7 +173,8 @@ let Route = EmberObject.extend(ActionHandler, Evented, { let owner = getOwner(this); let controller = owner.lookup(`controller:${controllerName}`); let queryParameterConfiguraton = get(this, 'queryParams'); - let hasRouterDefinedQueryParams = Object.keys(queryParameterConfiguraton).length > 0; + let hasRouterDefinedQueryParams = + Object.keys(queryParameterConfiguraton).length > 0; if (controller) { // the developer has authored a controller class in their application for @@ -172,9 +182,15 @@ let Route = EmberObject.extend(ActionHandler, Evented, { // merge in the query params for the route. As a mergedProperty, // Route#queryParams is always at least `{}` - let controllerDefinedQueryParameterConfiguration = get(controller, 'queryParams') || {}; - let normalizedControllerQueryParameterConfiguration = normalizeControllerQueryParams(controllerDefinedQueryParameterConfiguration); - combinedQueryParameterConfiguration = mergeEachQueryParams(normalizedControllerQueryParameterConfiguration, queryParameterConfiguraton); + let controllerDefinedQueryParameterConfiguration = + get(controller, 'queryParams') || {}; + let normalizedControllerQueryParameterConfiguration = normalizeControllerQueryParams( + controllerDefinedQueryParameterConfiguration + ); + combinedQueryParameterConfiguration = mergeEachQueryParams( + normalizedControllerQueryParameterConfiguration, + queryParameterConfiguraton + ); } else if (hasRouterDefinedQueryParams) { // the developer has not defined a controller but *has* supplied route query params. // Generate a class for them so we can later insert default values @@ -187,7 +203,9 @@ let Route = EmberObject.extend(ActionHandler, Evented, { let propertyNames = []; for (let propName in combinedQueryParameterConfiguration) { - if (!combinedQueryParameterConfiguration.hasOwnProperty(propName)) { continue; } + if (!combinedQueryParameterConfiguration.hasOwnProperty(propName)) { + continue; + } // to support the dubious feature of using unknownProperty // on queryParams configuration @@ -213,7 +231,11 @@ let Route = EmberObject.extend(ActionHandler, Evented, { let type = desc.type || typeOf(defaultValue); - let defaultValueSerialized = this.serializeQueryParam(defaultValue, urlKey, type); + let defaultValueSerialized = this.serializeQueryParam( + defaultValue, + urlKey, + type + ); let scopedPropertyName = `${controllerName}:${propName}`; let qp = { undecoratedDefaultValue: get(controller, propName), @@ -287,12 +309,14 @@ let Route = EmberObject.extend(ActionHandler, Evented, { @method _stashNames */ _stashNames(handlerInfo, dynamicParent) { - if (this._names) { return; } - let names = this._names = handlerInfo._names; + if (this._names) { + return; + } + let names = (this._names = handlerInfo._names); if (!names.length) { handlerInfo = dynamicParent; - names = handlerInfo && handlerInfo._names || []; + names = (handlerInfo && handlerInfo._names) || []; } let qps = get(this, '_qp.qps'); @@ -388,14 +412,21 @@ let Route = EmberObject.extend(ActionHandler, Evented, { } let transition = this._router._routerMicrolib.activeTransition; - let state = transition ? transition.state : this._router._routerMicrolib.state; + let state = transition + ? transition.state + : this._router._routerMicrolib.state; let fullName = route.fullRouteName; let params = assign({}, state.params[fullName]); let queryParams = getQueryParamsFor(route, state); return Object.keys(queryParams).reduce((params, key) => { - assert(`The route '${this.routeName}' has both a dynamic segment and query param with name '${key}'. Please rename one to avoid collisions.`, !params[key]); + assert( + `The route '${ + this.routeName + }' has both a dynamic segment and query param with name '${key}'. Please rename one to avoid collisions.`, + !params[key] + ); params[key] = queryParams[key]; return params; }, params); @@ -450,7 +481,11 @@ let Route = EmberObject.extend(ActionHandler, Evented, { @property _optionsForQueryParam */ _optionsForQueryParam(qp) { - return get(this, `queryParams.${qp.urlKey}`) || get(this, `queryParams.${qp.prop}`) || {}; + return ( + get(this, `queryParams.${qp.urlKey}`) || + get(this, `queryParams.${qp.prop}`) || + {} + ); }, /** @@ -799,7 +834,6 @@ let Route = EmberObject.extend(ActionHandler, Evented, { */ actions: { - /** This action is called when one or more query params have changed. Bubbles. @@ -816,7 +850,11 @@ let Route = EmberObject.extend(ActionHandler, Evented, { let totalChanged = Object.keys(changed).concat(Object.keys(removed)); for (let i = 0; i < totalChanged.length; ++i) { let qp = qpMap[totalChanged[i]]; - if (qp && get(this._optionsForQueryParam(qp), 'refreshModel') && this._router.currentState) { + if ( + qp && + get(this._optionsForQueryParam(qp), 'refreshModel') && + this._router.currentState + ) { this.refresh(); break; } @@ -826,10 +864,14 @@ let Route = EmberObject.extend(ActionHandler, Evented, { }, finalizeQueryParamChange(params, finalParams, transition) { - if (this.fullRouteName !== 'application') { return true; } + if (this.fullRouteName !== 'application') { + return true; + } // Transition object is absent for intermediate transitions. - if (!transition) { return; } + if (!transition) { + return; + } let handlerInfos = transition.state.handlerInfos; let router = this._router; @@ -867,10 +909,9 @@ let Route = EmberObject.extend(ActionHandler, Evented, { } } - controller._qpDelegate = get(route, '_qp.states.inactive'); - let thisQueryParamChanged = (svalue !== qp.serializedValue); + let thisQueryParamChanged = svalue !== qp.serializedValue; if (thisQueryParamChanged) { if (transition.queryParamsOnly && replaceUrl !== false) { let options = route._optionsForQueryParam(qp); @@ -889,8 +930,12 @@ let Route = EmberObject.extend(ActionHandler, Evented, { // Stash current serialized value of controller. qp.serializedValue = svalue; - let thisQueryParamHasDefaultValue = (qp.serializedDefaultValue === svalue); - if (!thisQueryParamHasDefaultValue || transition._keepDefaultQueryParamValues) { + let thisQueryParamHasDefaultValue = + qp.serializedDefaultValue === svalue; + if ( + !thisQueryParamHasDefaultValue || + transition._keepDefaultQueryParamValues + ) { finalParams.push({ value: svalue, visible: true, @@ -1126,7 +1171,8 @@ let Route = EmberObject.extend(ActionHandler, Evented, { @since 1.0.0 @public */ - transitionTo(name, context) { // eslint-disable-line no-unused-vars + transitionTo(/* name, context */) { + // eslint-disable-line no-unused-vars return this._router.transitionTo(...prefixRouteNameArg(this, arguments)); }, @@ -1148,7 +1194,9 @@ let Route = EmberObject.extend(ActionHandler, Evented, { @public */ intermediateTransitionTo() { - this._router.intermediateTransitionTo(...prefixRouteNameArg(this, arguments)); + this._router.intermediateTransitionTo( + ...prefixRouteNameArg(this, arguments) + ); }, /** @@ -1273,7 +1321,9 @@ let Route = EmberObject.extend(ActionHandler, Evented, { */ send(...args) { assert( - `Attempted to call .send() with the action '${args[0]}' on the destroyed route '${this.routeName}'.`, + `Attempted to call .send() with the action '${ + args[0] + }' on the destroyed route '${this.routeName}'.`, !this.isDestroying && !this.isDestroyed ); if ((this._router && this._router._routerMicrolib) || !isTesting()) { @@ -1331,7 +1381,11 @@ let Route = EmberObject.extend(ActionHandler, Evented, { let aQp = queryParams.map[prop]; aQp.values = params; - let cacheKey = calculateCacheKey(aQp.route.fullRouteName, aQp.parts, aQp.values); + let cacheKey = calculateCacheKey( + aQp.route.fullRouteName, + aQp.parts, + aQp.values + ); let value = cache.lookup(cacheKey, prop, aQp.undecoratedDefaultValue); set(controller, prop, value); }); @@ -1353,11 +1407,17 @@ let Route = EmberObject.extend(ActionHandler, Evented, { value in the cache so if this route becomes active, the cache value has been updated. */ _qpChanged(prop, value, qp) { - if (!qp) { return; } + if (!qp) { + return; + } // Update model-dep cache let cache = this._bucketCache; - let cacheKey = calculateCacheKey(qp.route.fullRouteName, qp.parts, qp.values); + let cacheKey = calculateCacheKey( + qp.route.fullRouteName, + qp.parts, + qp.values + ); cache.stash(cacheKey, prop, value); }, @@ -1570,8 +1630,11 @@ let Route = EmberObject.extend(ActionHandler, Evented, { if (sawParams) { return copy(params); } else { - if (transition.resolveIndex < 1) { return; } - return transition.state.handlerInfos[transition.resolveIndex - 1].context; + if (transition.resolveIndex < 1) { + return; + } + return transition.state.handlerInfos[transition.resolveIndex - 1] + .context; } } @@ -1626,15 +1689,22 @@ let Route = EmberObject.extend(ActionHandler, Evented, { let modelClass = owner.factoryFor(`model:${name}`); assert( - `You used the dynamic segment ${name}_id in your route ${routeName}, but ${namespace}.${StringUtils.classify(name)} did not exist and you did not override your route's \`model\` hook.`, + `You used the dynamic segment ${name}_id in your route ${routeName}, but ${namespace}.${StringUtils.classify( + name + )} did not exist and you did not override your route's \`model\` hook.`, !!modelClass ); - if (!modelClass) { return; } + if (!modelClass) { + return; + } modelClass = modelClass.class; - assert(`${StringUtils.classify(name)} has no method \`find\`.`, typeof modelClass.find === 'function'); + assert( + `${StringUtils.classify(name)} has no method \`find\`.`, + typeof modelClass.find === 'function' + ); return modelClass.find(value); } @@ -1759,8 +1829,9 @@ let Route = EmberObject.extend(ActionHandler, Evented, { @since 1.0.0 @public */ - setupController(controller, context, transition) { // eslint-disable-line no-unused-vars - if (controller && (context !== undefined)) { + setupController(controller, context /*, transition */) { + // eslint-disable-line no-unused-vars + if (controller && context !== undefined) { set(controller, 'model', context); } }, @@ -1803,7 +1874,10 @@ let Route = EmberObject.extend(ActionHandler, Evented, { // NOTE: We're specifically checking that skipAssert is true, because according // to the old API the second parameter was model. We do not want people who // passed a model to skip the assertion. - assert(`The controller named '${name}' could not be found. Make sure that this route exists and has already been entered at least once. If you are accessing a controller not associated with a route, make sure the controller class is explicitly defined.`, controller || _skipAssert === true); + assert( + `The controller named '${name}' could not be found. Make sure that this route exists and has already been entered at least once. If you are accessing a controller not associated with a route, make sure the controller class is explicitly defined.`, + controller || _skipAssert === true + ); return controller; }, @@ -1878,7 +1952,9 @@ let Route = EmberObject.extend(ActionHandler, Evented, { modelFor(_name) { let name; let owner = getOwner(this); - let transition = this._router ? this._router._routerMicrolib.activeTransition : null; + let transition = this._router + ? this._router._routerMicrolib.activeTransition + : null; // Only change the route name when there is an active transition. // Otherwise, use the passed in route name. @@ -1935,7 +2011,8 @@ let Route = EmberObject.extend(ActionHandler, Evented, { @since 1.0.0 @public */ - renderTemplate(controller, model) { // eslint-disable-line no-unused-vars + renderTemplate(/* controller, model */) { + // eslint-disable-line no-unused-vars this.render(); }, @@ -2075,12 +2152,20 @@ let Route = EmberObject.extend(ActionHandler, Evented, { name = this.templateName || this.routeName; options = _name; } else { - assert('The name in the given arguments is undefined or empty string', !isEmpty(_name)); + assert( + 'The name in the given arguments is undefined or empty string', + !isEmpty(_name) + ); name = _name; } } - let renderOptions = buildRenderOptions(this, isDefaultRender, name, options); + let renderOptions = buildRenderOptions( + this, + isDefaultRender, + name, + options + ); this.connections.push(renderOptions); once(this._router, '_setOutlets'); }, @@ -2150,7 +2235,9 @@ let Route = EmberObject.extend(ActionHandler, Evented, { outletName = options; } else { outletName = options.outlet; - parentView = options.parentView ? options.parentView.replace(/\//g, '.') : undefined; + parentView = options.parentView + ? options.parentView.replace(/\//g, '.') + : undefined; assert( 'You passed undefined as the outlet name.', @@ -2191,7 +2278,7 @@ let Route = EmberObject.extend(ActionHandler, Evented, { outlet: connection.outlet, name: connection.name, controller: undefined, - template: undefined, + template: undefined }; once(this._router, '_setOutlets'); } @@ -2220,24 +2307,33 @@ Route.reopenClass({ }); function parentRoute(route) { - let handlerInfo = handlerInfoFor(route, route._router._routerMicrolib.state.handlerInfos, -1); + let handlerInfo = handlerInfoFor( + route, + route._router._routerMicrolib.state.handlerInfos, + -1 + ); return handlerInfo && handlerInfo.handler; } function handlerInfoFor(route, handlerInfos, offset = 0) { - if (!handlerInfos) { return; } + if (!handlerInfos) { + return; + } let current; for (let i = 0; i < handlerInfos.length; i++) { current = handlerInfos[i].handler; - if (current === route) { return handlerInfos[i + offset]; } + if (current === route) { + return handlerInfos[i + offset]; + } } } function buildRenderOptions(route, isDefaultRender, _name, options) { assert( 'You passed undefined as the outlet name.', - isDefaultRender || !(options && 'outlet' in options && options.outlet === undefined) + isDefaultRender || + !(options && 'outlet' in options && options.outlet === undefined) ); let owner = getOwner(route); @@ -2262,7 +2358,10 @@ function buildRenderOptions(route, isDefaultRender, _name, options) { if (isDefaultRender) { controller = route.controllerName || owner.lookup(`controller:${name}`); } else { - controller = owner.lookup(`controller:${name}`) || route.controllerName || route.routeName; + controller = + owner.lookup(`controller:${name}`) || + route.controllerName || + route.routeName; } } @@ -2280,7 +2379,10 @@ function buildRenderOptions(route, isDefaultRender, _name, options) { } let template = owner.lookup(`template:${templateName}`); - assert(`Could not find "${templateName}" template, view, or component.`, isDefaultRender || template); + assert( + `Could not find "${templateName}" template, view, or component.`, + isDefaultRender || template + ); let parent; if (into && (parent = parentRoute(route)) && into === parent.routeName) { @@ -2293,13 +2395,15 @@ function buildRenderOptions(route, isDefaultRender, _name, options) { outlet, name, controller, - template: template || route._topLevelViewTemplate, + template: template || route._topLevelViewTemplate }; if (DEBUG) { let LOG_VIEW_LOOKUPS = get(route._router, 'namespace.LOG_VIEW_LOOKUPS'); if (LOG_VIEW_LOOKUPS && !template) { - info(`Could not find "${name}" template. Nothing will be rendered`, { fullName: `template:${name}` }); + info(`Could not find "${name}" template. Nothing will be rendered`, { + fullName: `template:${name}` + }); } } @@ -2307,7 +2411,9 @@ function buildRenderOptions(route, isDefaultRender, _name, options) { } function getFullQueryParams(router, state) { - if (state.fullQueryParams) { return state.fullQueryParams; } + if (state.fullQueryParams) { + return state.fullQueryParams; + } state.fullQueryParams = {}; assign(state.fullQueryParams, state.queryParams); @@ -2320,11 +2426,13 @@ function getQueryParamsFor(route, state) { state.queryParamsFor = state.queryParamsFor || {}; let name = route.fullRouteName; - if (state.queryParamsFor[name]) { return state.queryParamsFor[name]; } + if (state.queryParamsFor[name]) { + return state.queryParamsFor[name]; + } let fullQueryParams = getFullQueryParams(route._router, state); - let params = state.queryParamsFor[name] = {}; + let params = (state.queryParamsFor[name] = {}); // Copy over all the query params for this route/controller into params hash. let qpMeta = get(route, '_qp'); @@ -2333,10 +2441,10 @@ function getQueryParamsFor(route, state) { // Put deserialized qp on params hash. let qp = qps[i]; - let qpValueWasPassedIn = (qp.prop in fullQueryParams); - params[qp.prop] = qpValueWasPassedIn ? - fullQueryParams[qp.prop] : - copyDefaultValue(qp.defaultValue); + let qpValueWasPassedIn = qp.prop in fullQueryParams; + params[qp.prop] = qpValueWasPassedIn + ? fullQueryParams[qp.prop] + : copyDefaultValue(qp.defaultValue); } return params; @@ -2366,10 +2474,16 @@ function mergeEachQueryParams(controllerQP, routeQP) { // first loop over all controller qps, merging them with any matching route qps // into a new empty object to avoid mutating. for (let cqpName in controllerQP) { - if (!controllerQP.hasOwnProperty(cqpName)) { continue; } + if (!controllerQP.hasOwnProperty(cqpName)) { + continue; + } let newControllerParameterConfiguration = {}; - assign(newControllerParameterConfiguration, controllerQP[cqpName], routeQP[cqpName]); + assign( + newControllerParameterConfiguration, + controllerQP[cqpName], + routeQP[cqpName] + ); qps[cqpName] = newControllerParameterConfiguration; @@ -2380,10 +2494,19 @@ function mergeEachQueryParams(controllerQP, routeQP) { // loop over all route qps, skipping those that were merged in the first pass // because they also appear in controller qps for (let rqpName in routeQP) { - if (!routeQP.hasOwnProperty(rqpName) || keysAlreadyMergedOrSkippable[rqpName]) { continue; } + if ( + !routeQP.hasOwnProperty(rqpName) || + keysAlreadyMergedOrSkippable[rqpName] + ) { + continue; + } let newRouteParameterConfiguration = {}; - assign(newRouteParameterConfiguration, routeQP[rqpName], controllerQP[rqpName]); + assign( + newRouteParameterConfiguration, + routeQP[rqpName], + controllerQP[rqpName] + ); qps[rqpName] = newRouteParameterConfiguration; } diff --git a/packages/ember-routing/lib/system/router.js b/packages/ember-routing/lib/system/router.js index e3038a0d73d..19291c99f43 100644 --- a/packages/ember-routing/lib/system/router.js +++ b/packages/ember-routing/lib/system/router.js @@ -1,7 +1,4 @@ -import { - assign, - getOwner -} from 'ember-utils'; +import { assign, getOwner } from 'ember-utils'; import { get, set, @@ -11,24 +8,16 @@ import { once, scheduleOnce, schedule, - cancel, + cancel } from 'ember-metal'; -import { - Error as EmberError, - deprecate, - assert, - info -} from 'ember-debug'; +import { Error as EmberError, deprecate, assert, info } from 'ember-debug'; import { Object as EmberObject, Evented, typeOf, A as emberA } from 'ember-runtime'; -import { - defaultSerialize, - hasDefaultSerialize -} from './route'; +import { defaultSerialize, hasDefaultSerialize } from './route'; import EmberRouterDSL from './dsl'; import EmberLocation from '../location/api'; import { @@ -46,11 +35,12 @@ import { DEBUG } from 'ember-env-flags'; import Router from 'router'; -function K() { return this; } +function K() { + return this; +} const { slice } = Array.prototype; - /** The `EmberRouter` class manages the application state and URLs. Refer to the [routing guide](https://emberjs.com/guides/routing/) for documentation. @@ -92,7 +82,7 @@ const EmberRouter = EmberObject.extend(Evented, { rootURL: '/', _initRouterJs() { - let routerMicrolib = this._routerMicrolib = new Router(); + let routerMicrolib = (this._routerMicrolib = new Router()); routerMicrolib.triggerEvent = triggerEvent.bind(this); routerMicrolib._triggerWillChangeContext = K; @@ -101,11 +91,15 @@ const EmberRouter = EmberObject.extend(Evented, { let dslCallbacks = this.constructor.dslCallbacks || [K]; let dsl = this._buildDSL(); - dsl.route('application', { path: '/', resetNamespace: true, overrideNameAssertion: true }, function() { - for (let i = 0; i < dslCallbacks.length; i++) { - dslCallbacks[i].call(this); + dsl.route( + 'application', + { path: '/', resetNamespace: true, overrideNameAssertion: true }, + function() { + for (let i = 0; i < dslCallbacks.length; i++) { + dslCallbacks[i].call(this); + } } - }); + ); if (DEBUG) { if (get(this, 'namespace.LOG_TRANSITIONS_INTERNAL')) { @@ -170,9 +164,14 @@ const EmberRouter = EmberObject.extend(Evented, { _hasModuleBasedResolver() { let owner = getOwner(this); - if (!owner) { return false; } + if (!owner) { + return false; + } - let resolver = get(owner, 'application.__registry__.resolver.moduleBasedResolver'); + let resolver = get( + owner, + 'application.__registry__.resolver.moduleBasedResolver' + ); return !!resolver; }, @@ -276,7 +275,9 @@ const EmberRouter = EmberObject.extend(Evented, { // This is triggered async during Route#willDestroy. // If the router is also being destroyed we do not want to // to create another this._toplevelView (and leak the renderer) - if (this.isDestroying || this.isDestroyed) { return; } + if (this.isDestroying || this.isDestroyed) { + return; + } let handlerInfos = this._routerMicrolib.currentHandlerInfos; let route; @@ -292,9 +293,16 @@ const EmberRouter = EmberObject.extend(Evented, { let connections = route.connections; let ownState; for (let j = 0; j < connections.length; j++) { - let appended = appendLiveRoute(liveRoutes, defaultParentState, connections[j]); + let appended = appendLiveRoute( + liveRoutes, + defaultParentState, + connections[j] + ); liveRoutes = appended.liveRoutes; - if (appended.ownState.render.name === route.routeName || appended.ownState.render.outlet === 'main') { + if ( + appended.ownState.render.name === route.routeName || + appended.ownState.render.outlet === 'main' + ) { ownState = appended.ownState; } } @@ -341,7 +349,11 @@ const EmberRouter = EmberObject.extend(Evented, { if (DEBUG) { if (get(this, 'namespace').LOG_TRANSITIONS) { // eslint-disable-next-line no-console - console.log(`Preparing to transition from '${EmberRouter._routePath(oldInfos)}' to '${EmberRouter._routePath(newInfos)}'`); + console.log( + `Preparing to transition from '${EmberRouter._routePath( + oldInfos + )}' to '${EmberRouter._routePath(newInfos)}'` + ); } } }, @@ -377,11 +389,21 @@ const EmberRouter = EmberObject.extend(Evented, { */ transitionTo(...args) { if (resemblesURL(args[0])) { - assert(`A transition was attempted from '${this.currentRouteName}' to '${args[0]}' but the application instance has already been destroyed.`, !this.isDestroying && !this.isDestroyed); + assert( + `A transition was attempted from '${this.currentRouteName}' to '${ + args[0] + }' but the application instance has already been destroyed.`, + !this.isDestroying && !this.isDestroyed + ); return this._doURLTransition('transitionTo', args[0]); } let { routeName, models, queryParams } = extractRouteArgs(args); - assert(`A transition was attempted from '${this.currentRouteName}' to '${routeName}' but the application instance has already been destroyed.`, !this.isDestroying && !this.isDestroyed); + assert( + `A transition was attempted from '${ + this.currentRouteName + }' to '${routeName}' but the application instance has already been destroyed.`, + !this.isDestroying && !this.isDestroyed + ); return this._doTransition(routeName, models, queryParams); }, @@ -394,7 +416,9 @@ const EmberRouter = EmberObject.extend(Evented, { let infos = this._routerMicrolib.currentHandlerInfos; if (get(this, 'namespace').LOG_TRANSITIONS) { // eslint-disable-next-line no-console - console.log(`Intermediate-transitioned into '${EmberRouter._routePath(infos)}'`); + console.log( + `Intermediate-transitioned into '${EmberRouter._routePath(infos)}'` + ); } } }, @@ -437,7 +461,8 @@ const EmberRouter = EmberObject.extend(Evented, { return this.currentState.isActiveIntent(routeName, models, queryParams); }, - send() { /*name, context*/ + send() { + /*name, context*/ this._routerMicrolib.trigger(...arguments); }, @@ -603,7 +628,9 @@ const EmberRouter = EmberObject.extend(Evented, { handler._setRouteName(routeName); if (engineInfo && !hasDefaultSerialize(handler)) { - throw new Error('Defining a custom serialize method on an Engine route is not supported.'); + throw new Error( + 'Defining a custom serialize method on an Engine route is not supported.' + ); } return handler; @@ -674,7 +701,11 @@ const EmberRouter = EmberObject.extend(Evented, { forEachQueryParam(this, handlerInfos, queryParams, (key, value, qp) => { if (qp) { delete queryParams[key]; - queryParams[qp.urlKey] = qp.route.serializeQueryParam(value, qp.urlKey, qp.type); + queryParams[qp.urlKey] = qp.route.serializeQueryParam( + value, + qp.urlKey, + qp.type + ); } else if (value === undefined) { return; // We don't serialize undefined values } else { @@ -716,7 +747,11 @@ const EmberRouter = EmberObject.extend(Evented, { // because all values will be treated as strings if (qp) { delete queryParams[key]; - queryParams[qp.prop] = qp.route.deserializeQueryParam(value, qp.urlKey, qp.type); + queryParams[qp.prop] = qp.route.deserializeQueryParam( + value, + qp.urlKey, + qp.type + ); } }); }, @@ -735,7 +770,7 @@ const EmberRouter = EmberObject.extend(Evented, { } else if (defaultType === 'boolean') { return value === 'true'; } else if (defaultType === 'number') { - return (Number(value)).valueOf(); + return Number(value).valueOf(); } else if (defaultType === 'array') { return emberA(JSON.parse(value)); } @@ -762,28 +797,58 @@ const EmberRouter = EmberObject.extend(Evented, { } }, - _doTransition(_targetRouteName, models, _queryParams, _keepDefaultQueryParamValues) { - let targetRouteName = _targetRouteName || getActiveTargetName(this._routerMicrolib); - assert(`The route ${targetRouteName} was not found`, targetRouteName && this._routerMicrolib.hasRoute(targetRouteName)); + _doTransition( + _targetRouteName, + models, + _queryParams, + _keepDefaultQueryParamValues + ) { + let targetRouteName = + _targetRouteName || getActiveTargetName(this._routerMicrolib); + assert( + `The route ${targetRouteName} was not found`, + targetRouteName && this._routerMicrolib.hasRoute(targetRouteName) + ); let queryParams = {}; - this._processActiveTransitionQueryParams(targetRouteName, models, queryParams, _queryParams); + this._processActiveTransitionQueryParams( + targetRouteName, + models, + queryParams, + _queryParams + ); assign(queryParams, _queryParams); - this._prepareQueryParams(targetRouteName, models, queryParams, _keepDefaultQueryParamValues); + this._prepareQueryParams( + targetRouteName, + models, + queryParams, + _keepDefaultQueryParamValues + ); - let transition = this._routerMicrolib.transitionTo(targetRouteName, ...models, { queryParams }); + let transition = this._routerMicrolib.transitionTo( + targetRouteName, + ...models, + { queryParams } + ); didBeginTransition(transition, this); return transition; }, - _processActiveTransitionQueryParams(targetRouteName, models, queryParams, _queryParams) { + _processActiveTransitionQueryParams( + targetRouteName, + models, + queryParams, + _queryParams + ) { // merge in any queryParams from the active transition which could include // queryParams from the url on initial load. - if (!this._routerMicrolib.activeTransition) { return; } + if (!this._routerMicrolib.activeTransition) { + return; + } let unchangedQPs = {}; let qpUpdates = this._qpUpdates || {}; @@ -814,7 +879,12 @@ const EmberRouter = EmberObject.extend(Evented, { @param {boolean} keepDefaultQueryParamValues @return {Void} */ - _prepareQueryParams(targetRouteName, models, queryParams, _fromRouterService) { + _prepareQueryParams( + targetRouteName, + models, + queryParams, + _fromRouterService + ) { let state = calculatePostTransitionState(this, targetRouteName, models); this._hydrateUnsuppliedQueryParams(state, queryParams, _fromRouterService); this._serializeQueryParams(state.handlerInfos, queryParams); @@ -876,7 +946,16 @@ const EmberRouter = EmberObject.extend(Evented, { if (qpOther && qpOther.controllerName !== qp.controllerName) { let otherQP = qpsByUrlKey[urlKey]; - assert(`You're not allowed to have more than one controller property map to the same query param key, but both \`${otherQP.scopedPropertyName}\` and \`${qp.scopedPropertyName}\` map to \`${urlKey}\`. You can fix this by mapping one of the controller properties to a different query param key via the \`as\` config option, e.g. \`${otherQP.prop}: { as: \'other-${otherQP.prop}\' }\``, false); + assert( + `You're not allowed to have more than one controller property map to the same query param key, but both \`${ + otherQP.scopedPropertyName + }\` and \`${ + qp.scopedPropertyName + }\` map to \`${urlKey}\`. You can fix this by mapping one of the controller properties to a different query param key via the \`as\` config option, e.g. \`${ + otherQP.prop + }: { as: \'other-${otherQP.prop}\' }\``, + false + ); } qpsByUrlKey[urlKey] = qp; @@ -913,14 +992,17 @@ const EmberRouter = EmberObject.extend(Evented, { for (let i = 0, len = handlerInfos.length; i < len; ++i) { let qpMeta = this._getQPMeta(handlerInfos[i]); - if (!qpMeta) { continue; } + if (!qpMeta) { + continue; + } for (let j = 0, qpLen = qpMeta.qps.length; j < qpLen; ++j) { let qp = qpMeta.qps[j]; - let presentProp = qp.prop in queryParams && qp.prop || - qp.scopedPropertyName in queryParams && qp.scopedPropertyName || - qp.urlKey in queryParams && qp.urlKey; + let presentProp = + (qp.prop in queryParams && qp.prop) || + (qp.scopedPropertyName in queryParams && qp.scopedPropertyName) || + (qp.urlKey in queryParams && qp.urlKey); if (presentProp) { if (presentProp !== qp.scopedPropertyName) { @@ -950,17 +1032,22 @@ const EmberRouter = EmberObject.extend(Evented, { for (let i = 0; i < handlerInfos.length; ++i) { let qpMeta = this._getQPMeta(handlerInfos[i]); - if (!qpMeta) { continue; } + if (!qpMeta) { + continue; + } for (let j = 0, qpLen = qpMeta.qps.length; j < qpLen; ++j) { var qp = qpMeta.qps[j]; - var presentProp = qp.prop in queryParams && qp.prop || - qp.scopedPropertyName in queryParams && qp.scopedPropertyName || - qp.urlKey in queryParams && qp.urlKey; + var presentProp = + (qp.prop in queryParams && qp.prop) || + (qp.scopedPropertyName in queryParams && qp.scopedPropertyName) || + (qp.urlKey in queryParams && qp.urlKey); assert( - `You passed the \`${presentProp}\` query parameter during a transition into ${qp.route.routeName}, please update to ${qp.urlKey}`, + `You passed the \`${presentProp}\` query parameter during a transition into ${ + qp.route.routeName + }, please update to ${qp.urlKey}`, (function() { if (qp.urlKey === presentProp) { return true; @@ -980,8 +1067,16 @@ const EmberRouter = EmberObject.extend(Evented, { delete queryParams[presentProp]; } } else { - let cacheKey = calculateCacheKey(qp.route.fullRouteName, qp.parts, state.params); - queryParams[qp.scopedPropertyName] = appCache.lookup(cacheKey, qp.prop, qp.defaultValue); + let cacheKey = calculateCacheKey( + qp.route.fullRouteName, + qp.parts, + state.params + ); + queryParams[qp.scopedPropertyName] = appCache.lookup( + cacheKey, + qp.prop, + qp.defaultValue + ); } } } @@ -989,7 +1084,13 @@ const EmberRouter = EmberObject.extend(Evented, { _scheduleLoadingEvent(transition, originRoute) { this._cancelSlowTransitionTimer(); - this._slowTransitionTimer = scheduleOnce('routerTransitions', this, '_handleSlowTransition', transition, originRoute); + this._slowTransitionTimer = scheduleOnce( + 'routerTransitions', + this, + '_handleSlowTransition', + transition, + originRoute + ); }, currentState: null, @@ -1002,7 +1103,8 @@ const EmberRouter = EmberObject.extend(Evented, { return; } let targetState = new RouterState( - this, this._routerMicrolib, + this, + this._routerMicrolib, this._routerMicrolib.activeTransition.state ); this.set('targetState', targetState); @@ -1078,7 +1180,6 @@ const EmberRouter = EmberObject.extend(Evented, { @return {Void} */ function forEachRouteAbove(handlerInfos, callback) { - for (let i = handlerInfos.length - 1; i >= 0; --i) { let handlerInfo = handlerInfos[i]; let route = handlerInfo.handler; @@ -1090,7 +1191,9 @@ function forEachRouteAbove(handlerInfos, callback) { // // In both of these cases, we cannot invoke the callback on that specific // route, because it just doesn't exist... - if (route === undefined) { continue; } + if (route === undefined) { + continue; + } if (callback(route, handlerInfo) !== true) { return; @@ -1101,7 +1204,6 @@ function forEachRouteAbove(handlerInfos, callback) { // These get invoked when an action bubbles above ApplicationRoute // and are not meant to be overridable. let defaultActionHandlers = { - willResolveModel(handlerInfos, transition, originRoute) { this._scheduleLoadingEvent(transition, originRoute); }, @@ -1173,19 +1275,31 @@ let defaultActionHandlers = { function logError(_error, initialMessage) { let errorArgs = []; let error; - if (_error && typeof _error === 'object' && typeof _error.errorThrown === 'object') { + if ( + _error && + typeof _error === 'object' && + typeof _error.errorThrown === 'object' + ) { error = _error.errorThrown; } else { error = _error; } - if (initialMessage) { errorArgs.push(initialMessage); } + if (initialMessage) { + errorArgs.push(initialMessage); + } if (error) { - if (error.message) { errorArgs.push(error.message); } - if (error.stack) { errorArgs.push(error.stack); } + if (error.message) { + errorArgs.push(error.message); + } + if (error.stack) { + errorArgs.push(error.stack); + } - if (typeof error === 'string') { errorArgs.push(error); } + if (typeof error === 'string') { + errorArgs.push(error); + } } console.error(...errorArgs); //eslint-disable-line no-console @@ -1207,9 +1321,9 @@ function findRouteSubstateName(route, state) { let substateName = `${routeName}_${state}`; let substateNameFull = `${fullRouteName}_${state}`; - return routeHasBeenDefined(owner, router, substateName, substateNameFull) ? - substateNameFull : - ''; + return routeHasBeenDefined(owner, router, substateName, substateNameFull) + ? substateNameFull + : ''; } /** @@ -1227,11 +1341,12 @@ function findRouteStateName(route, state) { let { routeName, fullRouteName, _router: router } = route; let stateName = routeName === 'application' ? state : `${routeName}.${state}`; - let stateNameFull = fullRouteName === 'application' ? state : `${fullRouteName}.${state}`; + let stateNameFull = + fullRouteName === 'application' ? state : `${fullRouteName}.${state}`; - return routeHasBeenDefined(owner, router, stateName, stateNameFull) ? - stateNameFull : - ''; + return routeHasBeenDefined(owner, router, stateName, stateNameFull) + ? stateNameFull + : ''; } /** @@ -1247,7 +1362,9 @@ function findRouteStateName(route, state) { */ function routeHasBeenDefined(owner, router, localName, fullName) { let routerHasRoute = router.hasRoute(fullName); - let ownerHasRoute = owner.hasRegistration(`template:${localName}`) || owner.hasRegistration(`route:${localName}`); + let ownerHasRoute = + owner.hasRegistration(`template:${localName}`) || + owner.hasRegistration(`route:${localName}`); return routerHasRoute && ownerHasRoute; } @@ -1255,8 +1372,12 @@ export function triggerEvent(handlerInfos, ignoreFailure, args) { let name = args.shift(); if (!handlerInfos) { - if (ignoreFailure) { return; } - throw new EmberError(`Can't trigger action '${name}' because your app hasn't finished transitioning into its first route. To trigger an action on destination routes during a transition, you can call \`.send()\` on the \`Transition\` object passed to the \`model/beforeModel/afterModel\` hooks.`); + if (ignoreFailure) { + return; + } + throw new EmberError( + `Can't trigger action '${name}' because your app hasn't finished transitioning into its first route. To trigger an action on destination routes during a transition, you can call \`.send()\` on the \`Transition\` object passed to the \`model/beforeModel/afterModel\` hooks.` + ); } let eventWasHandled = false; @@ -1286,7 +1407,9 @@ export function triggerEvent(handlerInfos, ignoreFailure, args) { } if (!eventWasHandled && !ignoreFailure) { - throw new EmberError(`Nothing handled the action '${name}'. If you did handle the action, this error can be caused by returning true from an action handler in a controller, causing the action to bubble.`); + throw new EmberError( + `Nothing handled the action '${name}'. If you did handle the action, this error can be caused by returning true from an action handler in a controller, causing the action to bubble.` + ); } } @@ -1309,7 +1432,9 @@ function calculatePostTransitionState(emberRouter, leafRouteName, contexts) { function updatePaths(router) { let infos = router._routerMicrolib.currentHandlerInfos; - if (infos.length === 0) { return; } + if (infos.length === 0) { + return; + } let path = EmberRouter._routePath(infos); let currentRouteName = infos[infos.length - 1].name; @@ -1455,7 +1580,9 @@ function forEachQueryParam(router, handlerInfos, queryParams, callback) { let qpCache = router._queryParamsFor(handlerInfos); for (let key in queryParams) { - if (!queryParams.hasOwnProperty(key)) { continue; } + if (!queryParams.hasOwnProperty(key)) { + continue; + } let value = queryParams[key]; let qp = qpCache.map[key]; @@ -1464,7 +1591,9 @@ function forEachQueryParam(router, handlerInfos, queryParams, callback) { } function findLiveRoute(liveRoutes, name) { - if (!liveRoutes) { return; } + if (!liveRoutes) { + return; + } let stack = [liveRoutes]; while (stack.length > 0) { let test = stack.shift(); @@ -1500,7 +1629,8 @@ function appendLiveRoute(liveRoutes, defaultParentState, renderOptions) { { id: 'ember-routing.top-level-render-helper', until: '3.0.0', - url: 'https://emberjs.com/deprecations/v2.x/#toc_rendering-into-a-render-helper-that-resolves-to-an-outlet' + url: + 'https://emberjs.com/deprecations/v2.x/#toc_rendering-into-a-render-helper-that-resolves-to-an-outlet' } ); @@ -1533,8 +1663,10 @@ function appendOrphan(liveRoutes, into, myState) { liveRoutes.outlets.__ember_orphans__.outlets[into] = myState; schedule('afterRender', () => { // `wasUsed` gets set by the render helper. - assert(`You attempted to render into '${into}' but it was not found`, - liveRoutes.outlets.__ember_orphans__.outlets[into].wasUsed); + assert( + `You attempted to render into '${into}' but it was not found`, + liveRoutes.outlets.__ember_orphans__.outlets[into].wasUsed + ); }); } diff --git a/packages/ember-routing/lib/system/router_state.js b/packages/ember-routing/lib/system/router_state.js index 54a8ddf708f..62a10984ddf 100644 --- a/packages/ember-routing/lib/system/router_state.js +++ b/packages/ember-routing/lib/system/router_state.js @@ -10,16 +10,21 @@ export default class RouterState { isActiveIntent(routeName, models, queryParams, queryParamsMustMatch) { let state = this.routerJsState; - if (!this.routerJs.isActiveIntent(routeName, models, null, state)) { return false; } + if (!this.routerJs.isActiveIntent(routeName, models, null, state)) { + return false; + } if (queryParamsMustMatch && Object.keys(queryParams).length > 0) { let visibleQueryParams = assign({}, queryParams); - this.emberRouter._prepareQueryParams(routeName, models, visibleQueryParams); + this.emberRouter._prepareQueryParams( + routeName, + models, + visibleQueryParams + ); return shallowEqual(visibleQueryParams, state.queryParams); } return true; } - } diff --git a/packages/ember-routing/lib/utils.js b/packages/ember-routing/lib/utils.js index 23b9c4fee48..4ccde67e208 100644 --- a/packages/ember-routing/lib/utils.js +++ b/packages/ember-routing/lib/utils.js @@ -9,7 +9,10 @@ export function extractRouteArgs(args) { let possibleQueryParams = args[args.length - 1]; let queryParams; - if (possibleQueryParams && possibleQueryParams.hasOwnProperty('queryParams')) { + if ( + possibleQueryParams && + possibleQueryParams.hasOwnProperty('queryParams') + ) { queryParams = args.pop().queryParams; } else { queryParams = {}; @@ -21,21 +24,25 @@ export function extractRouteArgs(args) { } export function getActiveTargetName(router) { - let handlerInfos = router.activeTransition ? - router.activeTransition.state.handlerInfos : - router.state.handlerInfos; + let handlerInfos = router.activeTransition + ? router.activeTransition.state.handlerInfos + : router.state.handlerInfos; return handlerInfos[handlerInfos.length - 1].name; } export function stashParamNames(router, handlerInfos) { - if (handlerInfos._namesStashed) { return; } + if (handlerInfos._namesStashed) { + return; + } // This helper exists because router.js/route-recognizer.js awkwardly // keeps separate a handlerInfo's list of parameter names depending // on whether a URL transition or named transition is happening. // Hopefully we can remove this in the future. let targetRouteName = handlerInfos[handlerInfos.length - 1].name; - let recogHandlers = router._routerMicrolib.recognizer.handlersFor(targetRouteName); + let recogHandlers = router._routerMicrolib.recognizer.handlersFor( + targetRouteName + ); let dynamicParent = null; for (let i = 0; i < handlerInfos.length; ++i) { @@ -90,7 +97,10 @@ export function calculateCacheKey(prefix, parts = [], values) { let value; if (values) { if (cacheValuePrefix && cacheValuePrefix in values) { - let partRemovedPrefix = (part.indexOf(cacheValuePrefix) === 0) ? part.substr(cacheValuePrefix.length + 1) : part; + let partRemovedPrefix = + part.indexOf(cacheValuePrefix) === 0 + ? part.substr(cacheValuePrefix.length + 1) + : part; value = get(values[cacheValuePrefix], partRemovedPrefix); } else { value = get(values, part); @@ -101,7 +111,6 @@ export function calculateCacheKey(prefix, parts = [], values) { return prefix + suffixes.replace(ALL_PERIODS_REGEX, '-'); } - /* Controller-defined query parameters can come in three shapes: @@ -154,7 +163,9 @@ function accumulateQueryParamDescriptors(_desc, accum) { } for (let key in desc) { - if (!desc.hasOwnProperty(key)) { return; } + if (!desc.hasOwnProperty(key)) { + return; + } let singleDesc = desc[key]; if (typeof singleDesc === 'string') { @@ -190,7 +201,9 @@ export function prefixRouteNameArg(route, args) { // only alter the routeName if it's actually referencing a route. if (owner.routable && typeof routeName === 'string') { if (resemblesURL(routeName)) { - throw new EmberError('Programmatic transitions by URL cannot be used within an Engine. Please use the route name instead.'); + throw new EmberError( + 'Programmatic transitions by URL cannot be used within an Engine. Please use the route name instead.' + ); } else { routeName = `${prefix}.${routeName}`; args[0] = routeName; @@ -206,7 +219,9 @@ export function shallowEqual(a, b) { let bCount = 0; for (k in a) { if (a.hasOwnProperty(k)) { - if (a[k] !== b[k]) { return false; } + if (a[k] !== b[k]) { + return false; + } aCount++; } } diff --git a/packages/ember-routing/tests/ext/controller_test.js b/packages/ember-routing/tests/ext/controller_test.js index d3c941ab8f8..47223f746bb 100644 --- a/packages/ember-routing/tests/ext/controller_test.js +++ b/packages/ember-routing/tests/ext/controller_test.js @@ -2,54 +2,87 @@ import { setOwner } from 'ember-utils'; import { Controller } from 'ember-runtime'; import { buildOwner, moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('ember-routing/ext/controller', class extends AbstractTestCase { - ['@test transitionToRoute considers an engine\'s mountPoint'](assert) { - let router = { - transitionTo(route) { - return route; - } - }; - - let engineInstance = buildOwner({ - ownerOptions: { - routable: true, - mountPoint: 'foo.bar' - } - }); - - let controller = Controller.create({ target: router }); - setOwner(controller, engineInstance); - - assert.strictEqual(controller.transitionToRoute('application'), 'foo.bar.application', 'properly prefixes application route'); - assert.strictEqual(controller.transitionToRoute('posts'), 'foo.bar.posts', 'properly prefixes child routes'); - assert.throws(() => controller.transitionToRoute('/posts'), 'throws when trying to use a url'); - - let queryParams = {}; - assert.strictEqual(controller.transitionToRoute(queryParams), queryParams, 'passes query param only transitions through'); - } +moduleFor( + 'ember-routing/ext/controller', + class extends AbstractTestCase { + ["@test transitionToRoute considers an engine's mountPoint"](assert) { + let router = { + transitionTo(route) { + return route; + } + }; + + let engineInstance = buildOwner({ + ownerOptions: { + routable: true, + mountPoint: 'foo.bar' + } + }); + + let controller = Controller.create({ target: router }); + setOwner(controller, engineInstance); + + assert.strictEqual( + controller.transitionToRoute('application'), + 'foo.bar.application', + 'properly prefixes application route' + ); + assert.strictEqual( + controller.transitionToRoute('posts'), + 'foo.bar.posts', + 'properly prefixes child routes' + ); + assert.throws( + () => controller.transitionToRoute('/posts'), + 'throws when trying to use a url' + ); + + let queryParams = {}; + assert.strictEqual( + controller.transitionToRoute(queryParams), + queryParams, + 'passes query param only transitions through' + ); + } + + ["@test replaceRoute considers an engine's mountPoint"](assert) { + let router = { + replaceWith(route) { + return route; + } + }; + + let engineInstance = buildOwner({ + ownerOptions: { + routable: true, + mountPoint: 'foo.bar' + } + }); + + let controller = Controller.create({ target: router }); + setOwner(controller, engineInstance); + + assert.strictEqual( + controller.replaceRoute('application'), + 'foo.bar.application', + 'properly prefixes application route' + ); + assert.strictEqual( + controller.replaceRoute('posts'), + 'foo.bar.posts', + 'properly prefixes child routes' + ); + assert.throws( + () => controller.replaceRoute('/posts'), + 'throws when trying to use a url' + ); - ['@test replaceRoute considers an engine\'s mountPoint'](assert) { - let router = { - replaceWith(route) { - return route; - } - }; - - let engineInstance = buildOwner({ - ownerOptions: { - routable: true, - mountPoint: 'foo.bar' - } - }); - - let controller = Controller.create({ target: router }); - setOwner(controller, engineInstance); - - assert.strictEqual(controller.replaceRoute('application'), 'foo.bar.application', 'properly prefixes application route'); - assert.strictEqual(controller.replaceRoute('posts'), 'foo.bar.posts', 'properly prefixes child routes'); - assert.throws(() => controller.replaceRoute('/posts'), 'throws when trying to use a url'); - - let queryParams = {}; - assert.strictEqual(controller.replaceRoute(queryParams), queryParams, 'passes query param only transitions through'); + let queryParams = {}; + assert.strictEqual( + controller.replaceRoute(queryParams), + queryParams, + 'passes query param only transitions through' + ); + } } -}); +); diff --git a/packages/ember-routing/tests/location/auto_location_test.js b/packages/ember-routing/tests/location/auto_location_test.js index d776c8d5ed5..e512af54783 100644 --- a/packages/ember-routing/tests/location/auto_location_test.js +++ b/packages/ember-routing/tests/location/auto_location_test.js @@ -2,36 +2,48 @@ import { assign, OWNER } from 'ember-utils'; import { environment } from 'ember-environment'; import { get, run } from 'ember-metal'; import AutoLocation from '../../location/auto_location'; -import { - getHistoryPath, - getHashPath -} from '../../location/auto_location'; +import { getHistoryPath, getHashPath } from '../../location/auto_location'; import HistoryLocation from '../../location/history_location'; import HashLocation from '../../location/hash_location'; import NoneLocation from '../../location/none_location'; import { buildOwner, moduleFor, AbstractTestCase } from 'internal-test-helpers'; function mockBrowserLocation(overrides, assert) { - return assign({ - href: 'http://test.com/', - pathname: '/', - hash: '', - search: '', - replace() { - assert.ok(false, 'location.replace should not be called during testing'); - } - }, overrides); + return assign( + { + href: 'http://test.com/', + pathname: '/', + hash: '', + search: '', + replace() { + assert.ok( + false, + 'location.replace should not be called during testing' + ); + } + }, + overrides + ); } function mockBrowserHistory(overrides, assert) { - return assign({ - pushState() { - assert.ok(false, 'history.pushState should not be called during testing'); + return assign( + { + pushState() { + assert.ok( + false, + 'history.pushState should not be called during testing' + ); + }, + replaceState() { + assert.ok( + false, + 'history.replaceState should not be called during testing' + ); + } }, - replaceState() { - assert.ok(false, 'history.replaceState should not be called during testing'); - } - }, overrides); + overrides + ); } function createLocation(location, history) { @@ -53,228 +65,341 @@ function createLocation(location, history) { let location; -moduleFor('AutoLocation', class extends AbstractTestCase { - teardown() { - if (location) { - run(location, 'destroy'); +moduleFor( + 'AutoLocation', + class extends AbstractTestCase { + teardown() { + if (location) { + run(location, 'destroy'); + } } - } - - ['@test AutoLocation should have the `global`'](assert) { - let location = AutoLocation.create(); - - assert.ok(location.global, 'has a global defined'); - assert.strictEqual(location.global, environment.window, 'has the environments window global'); - } - - ['@test AutoLocation should return concrete implementation\'s value for `getURL`'](assert) { - let browserLocation = mockBrowserLocation({}, assert); - let browserHistory = mockBrowserHistory({}, assert); - - location = createLocation(browserLocation, browserHistory); - location.detect(); - - let concreteImplementation = get(location, 'concreteImplementation'); - concreteImplementation.getURL = function() { - return '/lincoln/park'; - }; + ['@test AutoLocation should have the `global`'](assert) { + let location = AutoLocation.create(); - assert.equal(location.getURL(), '/lincoln/park'); - } - - ['@test AutoLocation should use a HistoryLocation instance when pushStates is supported'](assert) { - let browserLocation = mockBrowserLocation({}, assert); - let browserHistory = mockBrowserHistory({}, assert); - - location = createLocation(browserLocation, browserHistory); - location.detect(); - - assert.ok(get(location, 'concreteImplementation') instanceof HistoryLocation); - } - - ['@test AutoLocation should use a HashLocation instance when pushStates are not supported, but hashchange events are and the URL is already in the HashLocation format'](assert) { - let browserLocation = mockBrowserLocation({ - hash: '#/testd' - }, assert); - - location = createLocation(browserLocation); - location.global = { - onhashchange() { } - }; - - location.detect(); - assert.ok(get(location, 'concreteImplementation') instanceof HashLocation); - } + assert.ok(location.global, 'has a global defined'); + assert.strictEqual( + location.global, + environment.window, + 'has the environments window global' + ); + } - ['@test AutoLocation should use a NoneLocation instance when neither history nor hashchange are supported.'](assert) { - location = createLocation(mockBrowserLocation({}, assert)); - location.detect(); + ["@test AutoLocation should return concrete implementation's value for `getURL`"]( + assert + ) { + let browserLocation = mockBrowserLocation({}, assert); + let browserHistory = mockBrowserHistory({}, assert); - assert.ok(get(location, 'concreteImplementation') instanceof NoneLocation); - } + location = createLocation(browserLocation, browserHistory); + location.detect(); - ['@test AutoLocation should use an index path (i.e. \'/\') without any location.hash as OK for HashLocation'](assert) { - let browserLocation = mockBrowserLocation({ - href: 'http://test.com/', - pathname: '/', - hash: '', - search: '', - replace() { - assert.ok(false, 'location.replace should not be called'); - } - }, assert); + let concreteImplementation = get(location, 'concreteImplementation'); - location = createLocation(browserLocation); - location.global = { - onhashchange() { } - }; + concreteImplementation.getURL = function() { + return '/lincoln/park'; + }; - location.detect(); + assert.equal(location.getURL(), '/lincoln/park'); + } - assert.ok(get(location, 'concreteImplementation') instanceof HashLocation, 'uses a HashLocation'); - } + ['@test AutoLocation should use a HistoryLocation instance when pushStates is supported']( + assert + ) { + let browserLocation = mockBrowserLocation({}, assert); + let browserHistory = mockBrowserHistory({}, assert); - ['@test AutoLocation should transform the URL for hashchange-only browsers viewing a HistoryLocation-formatted path'](assert) { - assert.expect(3); + location = createLocation(browserLocation, browserHistory); + location.detect(); - let browserLocation = mockBrowserLocation({ - hash: '', - hostname: 'test.com', - href: 'http://test.com/test', - pathname: '/test', - protocol: 'http:', - port: '', - search: '', - replace(path) { - assert.equal(path, 'http://test.com/#/test', 'location.replace should be called with normalized HashLocation path'); - } - }, assert); + assert.ok( + get(location, 'concreteImplementation') instanceof HistoryLocation + ); + } - let location = createLocation(browserLocation); - location.global = { - onhashchange() { } - }; + ['@test AutoLocation should use a HashLocation instance when pushStates are not supported, but hashchange events are and the URL is already in the HashLocation format']( + assert + ) { + let browserLocation = mockBrowserLocation( + { + hash: '#/testd' + }, + assert + ); + + location = createLocation(browserLocation); + location.global = { + onhashchange() {} + }; - location.detect(); + location.detect(); + assert.ok( + get(location, 'concreteImplementation') instanceof HashLocation + ); + } - assert.ok(get(location, 'concreteImplementation') instanceof NoneLocation, 'NoneLocation should be used while we attempt to location.replace()'); - assert.equal(get(location, 'cancelRouterSetup'), true, 'cancelRouterSetup should be set so the router knows.'); - } + ['@test AutoLocation should use a NoneLocation instance when neither history nor hashchange are supported.']( + assert + ) { + location = createLocation(mockBrowserLocation({}, assert)); + location.detect(); - ['@test AutoLocation should replace the URL for pushState-supported browsers viewing a HashLocation-formatted url'](assert) { - assert.expect(2); - let browserLocation = mockBrowserLocation({ - hash: '#/test', - hostname: 'test.com', - href: 'http://test.com/#/test', - pathname: '/', - protocol: 'http:', - port: '', - search: '' - }, assert); - - let browserHistory = mockBrowserHistory({ - replaceState(state, title, path) { - assert.equal(path, '/test', 'history.replaceState should be called with normalized HistoryLocation url'); - } - }, assert); + assert.ok( + get(location, 'concreteImplementation') instanceof NoneLocation + ); + } - let location = createLocation(browserLocation, browserHistory); - location.detect(); + ["@test AutoLocation should use an index path (i.e. '/') without any location.hash as OK for HashLocation"]( + assert + ) { + let browserLocation = mockBrowserLocation( + { + href: 'http://test.com/', + pathname: '/', + hash: '', + search: '', + replace() { + assert.ok(false, 'location.replace should not be called'); + } + }, + assert + ); + + location = createLocation(browserLocation); + location.global = { + onhashchange() {} + }; - assert.ok(get(location, 'concreteImplementation'), HistoryLocation); - } + location.detect(); - ['@test AutoLocation requires any rootURL given to end in a trailing forward slash'](assert) { - let browserLocation = mockBrowserLocation({}, assert); - let expectedMsg = /rootURL must end with a trailing forward slash e.g. "\/app\/"/; + assert.ok( + get(location, 'concreteImplementation') instanceof HashLocation, + 'uses a HashLocation' + ); + } - location = createLocation(browserLocation); - location.rootURL = 'app'; + ['@test AutoLocation should transform the URL for hashchange-only browsers viewing a HistoryLocation-formatted path']( + assert + ) { + assert.expect(3); + + let browserLocation = mockBrowserLocation( + { + hash: '', + hostname: 'test.com', + href: 'http://test.com/test', + pathname: '/test', + protocol: 'http:', + port: '', + search: '', + replace(path) { + assert.equal( + path, + 'http://test.com/#/test', + 'location.replace should be called with normalized HashLocation path' + ); + } + }, + assert + ); + + let location = createLocation(browserLocation); + location.global = { + onhashchange() {} + }; - expectAssertion(function() { location.detect(); - }, expectedMsg); - location.rootURL = '/app'; - expectAssertion(function() { - location.detect(); - }, expectedMsg); + assert.ok( + get(location, 'concreteImplementation') instanceof NoneLocation, + 'NoneLocation should be used while we attempt to location.replace()' + ); + assert.equal( + get(location, 'cancelRouterSetup'), + true, + 'cancelRouterSetup should be set so the router knows.' + ); + } - // Note the trailing whitespace - location.rootURL = '/app/ '; - expectAssertion(function() { + ['@test AutoLocation should replace the URL for pushState-supported browsers viewing a HashLocation-formatted url']( + assert + ) { + assert.expect(2); + let browserLocation = mockBrowserLocation( + { + hash: '#/test', + hostname: 'test.com', + href: 'http://test.com/#/test', + pathname: '/', + protocol: 'http:', + port: '', + search: '' + }, + assert + ); + + let browserHistory = mockBrowserHistory( + { + replaceState(state, title, path) { + assert.equal( + path, + '/test', + 'history.replaceState should be called with normalized HistoryLocation url' + ); + } + }, + assert + ); + + let location = createLocation(browserLocation, browserHistory); location.detect(); - }, expectedMsg); - } - - ['@test AutoLocation provides its rootURL to the concreteImplementation'](assert) { - let browserLocation = mockBrowserLocation({ - pathname: '/some/subdir/derp' - }, assert); - let browserHistory = mockBrowserHistory({}, assert); - - location = createLocation(browserLocation, browserHistory); - location.rootURL = '/some/subdir/'; - location.detect(); + assert.ok(get(location, 'concreteImplementation'), HistoryLocation); + } - let concreteLocation = get(location, 'concreteImplementation'); - assert.equal(location.rootURL, concreteLocation.rootURL); - } + ['@test AutoLocation requires any rootURL given to end in a trailing forward slash']( + assert + ) { + let browserLocation = mockBrowserLocation({}, assert); + let expectedMsg = /rootURL must end with a trailing forward slash e.g. "\/app\/"/; + + location = createLocation(browserLocation); + location.rootURL = 'app'; + + expectAssertion(function() { + location.detect(); + }, expectedMsg); + + location.rootURL = '/app'; + expectAssertion(function() { + location.detect(); + }, expectedMsg); + + // Note the trailing whitespace + location.rootURL = '/app/ '; + expectAssertion(function() { + location.detect(); + }, expectedMsg); + } - ['@test getHistoryPath() should return a normalized, HistoryLocation-supported path'](assert) { - let browserLocation = mockBrowserLocation({ - href: 'http://test.com/app/about?foo=bar#foo', - pathname: '/app/about', - search: '?foo=bar', - hash: '#foo' - }, assert); + ['@test AutoLocation provides its rootURL to the concreteImplementation']( + assert + ) { + let browserLocation = mockBrowserLocation( + { + pathname: '/some/subdir/derp' + }, + assert + ); + let browserHistory = mockBrowserHistory({}, assert); - assert.equal(getHistoryPath('/app/', browserLocation), '/app/about?foo=bar#foo', 'URLs already in HistoryLocation form should come out the same'); + location = createLocation(browserLocation, browserHistory); + location.rootURL = '/some/subdir/'; - browserLocation = mockBrowserLocation({ - href: 'http://test.com/app/#/about?foo=bar#foo', - pathname: '/app/', - search: '', - hash: '#/about?foo=bar#foo' - }, assert); - assert.equal(getHistoryPath('/app/', browserLocation), '/app/about?foo=bar#foo', 'HashLocation formed URLs should be normalized'); + location.detect(); - browserLocation = mockBrowserLocation({ - href: 'http://test.com/app/#about?foo=bar#foo', - pathname: '/app/', - search: '', - hash: '#about?foo=bar#foo' - }, assert); - assert.equal(getHistoryPath('/app', browserLocation), '/app/#about?foo=bar#foo', 'URLs with a hash not following #/ convention shouldn\'t be normalized as a route'); - } + let concreteLocation = get(location, 'concreteImplementation'); + assert.equal(location.rootURL, concreteLocation.rootURL); + } - ['@test getHashPath() should return a normalized, HashLocation-supported path'](assert) { - let browserLocation = mockBrowserLocation({ - href: 'http://test.com/app/#/about?foo=bar#foo', - pathname: '/app/', - search: '', - hash: '#/about?foo=bar#foo' - }, assert); - assert.equal(getHashPath('/app/', browserLocation), '/app/#/about?foo=bar#foo', 'URLs already in HistoryLocation form should come out the same'); - - browserLocation = mockBrowserLocation({ - href: 'http://test.com/app/about?foo=bar#foo', - pathname: '/app/about', - search: '?foo=bar', - hash: '#foo' - }, assert); - assert.equal(getHashPath('/app/', browserLocation), '/app/#/about?foo=bar#foo', 'HistoryLocation formed URLs should be normalized'); - - browserLocation = mockBrowserLocation({ - href: 'http://test.com/app/#about?foo=bar#foo', - pathname: '/app/', - search: '', - hash: '#about?foo=bar#foo' - }, assert); + ['@test getHistoryPath() should return a normalized, HistoryLocation-supported path']( + assert + ) { + let browserLocation = mockBrowserLocation( + { + href: 'http://test.com/app/about?foo=bar#foo', + pathname: '/app/about', + search: '?foo=bar', + hash: '#foo' + }, + assert + ); + + assert.equal( + getHistoryPath('/app/', browserLocation), + '/app/about?foo=bar#foo', + 'URLs already in HistoryLocation form should come out the same' + ); + + browserLocation = mockBrowserLocation( + { + href: 'http://test.com/app/#/about?foo=bar#foo', + pathname: '/app/', + search: '', + hash: '#/about?foo=bar#foo' + }, + assert + ); + assert.equal( + getHistoryPath('/app/', browserLocation), + '/app/about?foo=bar#foo', + 'HashLocation formed URLs should be normalized' + ); + + browserLocation = mockBrowserLocation( + { + href: 'http://test.com/app/#about?foo=bar#foo', + pathname: '/app/', + search: '', + hash: '#about?foo=bar#foo' + }, + assert + ); + assert.equal( + getHistoryPath('/app', browserLocation), + '/app/#about?foo=bar#foo', + "URLs with a hash not following #/ convention shouldn't be normalized as a route" + ); + } - assert.equal(getHashPath('/app/', browserLocation), '/app/#/#about?foo=bar#foo', 'URLs with a hash not following #/ convention shouldn\'t be normalized as a route'); + ['@test getHashPath() should return a normalized, HashLocation-supported path']( + assert + ) { + let browserLocation = mockBrowserLocation( + { + href: 'http://test.com/app/#/about?foo=bar#foo', + pathname: '/app/', + search: '', + hash: '#/about?foo=bar#foo' + }, + assert + ); + assert.equal( + getHashPath('/app/', browserLocation), + '/app/#/about?foo=bar#foo', + 'URLs already in HistoryLocation form should come out the same' + ); + + browserLocation = mockBrowserLocation( + { + href: 'http://test.com/app/about?foo=bar#foo', + pathname: '/app/about', + search: '?foo=bar', + hash: '#foo' + }, + assert + ); + assert.equal( + getHashPath('/app/', browserLocation), + '/app/#/about?foo=bar#foo', + 'HistoryLocation formed URLs should be normalized' + ); + + browserLocation = mockBrowserLocation( + { + href: 'http://test.com/app/#about?foo=bar#foo', + pathname: '/app/', + search: '', + hash: '#about?foo=bar#foo' + }, + assert + ); + + assert.equal( + getHashPath('/app/', browserLocation), + '/app/#/#about?foo=bar#foo', + "URLs with a hash not following #/ convention shouldn't be normalized as a route" + ); + } } -}); +); diff --git a/packages/ember-routing/tests/location/hash_location_test.js b/packages/ember-routing/tests/location/hash_location_test.js index aa8fbf0c808..e43d7e4a75d 100644 --- a/packages/ember-routing/tests/location/hash_location_test.js +++ b/packages/ember-routing/tests/location/hash_location_test.js @@ -12,12 +12,17 @@ function createLocation(options, assert) { hash: '', search: '', replace() { - assert.ok(false, 'location.replace should not be called during testing'); + assert.ok( + false, + 'location.replace should not be called during testing' + ); } } }); - if (!options) { options = {}; } + if (!options) { + options = {}; + } location = HashTestLocation.create(options); } @@ -27,8 +32,8 @@ function mockBrowserLocation(path) { let tmp = document.createElement('a'); tmp.href = path; - let protocol = (!tmp.protocol || tmp.protocol === ':') ? 'http' : tmp.protocol; - let pathname = (tmp.pathname.match(/^\//)) ? tmp.pathname : '/' + tmp.pathname; + let protocol = !tmp.protocol || tmp.protocol === ':' ? 'http' : tmp.protocol; + let pathname = tmp.pathname.match(/^\//) ? tmp.pathname : '/' + tmp.pathname; return { hash: tmp.hash, @@ -48,127 +53,165 @@ function triggerHashchange() { window.dispatchEvent(event); } -moduleFor('HashLocation', class extends AbstractTestCase { - teardown() { - run(function() { - if (location) { location.destroy(); } - }); - } - - ['@test HashLocation.getURL() returns the current url'](assert) { - createLocation({ - _location: mockBrowserLocation('/#/foo/bar') - }, assert); - - assert.equal(location.getURL(), '/foo/bar'); - } - - ['@test HashLocation.getURL() includes extra hashes'](assert) { - createLocation({ - _location: mockBrowserLocation('/#/foo#bar#car') - }, assert); - - assert.equal(location.getURL(), '/foo#bar#car'); - } - - ['@test HashLocation.getURL() assumes location.hash without #/ prefix is not a route path'](assert) { - createLocation({ - _location: mockBrowserLocation('/#foo#bar') - }, assert); +moduleFor( + 'HashLocation', + class extends AbstractTestCase { + teardown() { + run(function() { + if (location) { + location.destroy(); + } + }); + } - assert.equal(location.getURL(), '/#foo#bar'); - } + ['@test HashLocation.getURL() returns the current url'](assert) { + createLocation( + { + _location: mockBrowserLocation('/#/foo/bar') + }, + assert + ); - ['@test HashLocation.getURL() returns a normal forward slash when there is no location.hash'](assert) { - createLocation({ - _location: mockBrowserLocation('/') - }, assert); + assert.equal(location.getURL(), '/foo/bar'); + } - assert.equal(location.getURL(), '/'); - } + ['@test HashLocation.getURL() includes extra hashes'](assert) { + createLocation( + { + _location: mockBrowserLocation('/#/foo#bar#car') + }, + assert + ); - ['@test HashLocation.setURL() correctly sets the url'](assert) { - createLocation({}, assert); + assert.equal(location.getURL(), '/foo#bar#car'); + } - location.setURL('/bar'); + ['@test HashLocation.getURL() assumes location.hash without #/ prefix is not a route path']( + assert + ) { + createLocation( + { + _location: mockBrowserLocation('/#foo#bar') + }, + assert + ); + + assert.equal(location.getURL(), '/#foo#bar'); + } - assert.equal(get(location, 'location.hash'), '/bar'); - assert.equal(get(location, 'lastSetURL'), '/bar'); - } + ['@test HashLocation.getURL() returns a normal forward slash when there is no location.hash']( + assert + ) { + createLocation( + { + _location: mockBrowserLocation('/') + }, + assert + ); + + assert.equal(location.getURL(), '/'); + } - ['@test HashLocation.replaceURL() correctly replaces to the path with a page reload'](assert) { - assert.expect(2); + ['@test HashLocation.setURL() correctly sets the url'](assert) { + createLocation({}, assert); - createLocation({ - _location: { - replace(path) { - assert.equal(path, '#/foo'); - } - } - }, assert); + location.setURL('/bar'); - location.replaceURL('/foo'); + assert.equal(get(location, 'location.hash'), '/bar'); + assert.equal(get(location, 'lastSetURL'), '/bar'); + } - assert.equal(get(location, 'lastSetURL'), '/foo'); - } + ['@test HashLocation.replaceURL() correctly replaces to the path with a page reload']( + assert + ) { + assert.expect(2); + + createLocation( + { + _location: { + replace(path) { + assert.equal(path, '#/foo'); + } + } + }, + assert + ); + + location.replaceURL('/foo'); + + assert.equal(get(location, 'lastSetURL'), '/foo'); + } - ['@test HashLocation.onUpdateURL callback executes as expected'](assert) { - assert.expect(1); + ['@test HashLocation.onUpdateURL callback executes as expected'](assert) { + assert.expect(1); - createLocation({ - _location: mockBrowserLocation('/#/foo/bar') - }, assert); + createLocation( + { + _location: mockBrowserLocation('/#/foo/bar') + }, + assert + ); - let callback = function (param) { - assert.equal(param, '/foo/bar', 'path is passed as param'); - }; + let callback = function(param) { + assert.equal(param, '/foo/bar', 'path is passed as param'); + }; - location.onUpdateURL(callback); + location.onUpdateURL(callback); - triggerHashchange(); - } + triggerHashchange(); + } - ['@test HashLocation.onUpdateURL doesn\'t execute callback if lastSetURL === path'](assert) { - assert.expect(0); + ["@test HashLocation.onUpdateURL doesn't execute callback if lastSetURL === path"]( + assert + ) { + assert.expect(0); - createLocation({ - _location: { - href: '/#/foo/bar' - }, - lastSetURL: '/foo/bar' - }, assert); + createLocation( + { + _location: { + href: '/#/foo/bar' + }, + lastSetURL: '/foo/bar' + }, + assert + ); - let callback = function () { - assert.ok(false, 'callback should not be called'); - }; + let callback = function() { + assert.ok(false, 'callback should not be called'); + }; - location.onUpdateURL(callback); + location.onUpdateURL(callback); - triggerHashchange(); - } + triggerHashchange(); + } - ['@test HashLocation.formatURL() prepends a # to the provided string'](assert) { - createLocation({}, assert); + ['@test HashLocation.formatURL() prepends a # to the provided string']( + assert + ) { + createLocation({}, assert); - assert.equal(location.formatURL('/foo#bar'), '#/foo#bar'); - } + assert.equal(location.formatURL('/foo#bar'), '#/foo#bar'); + } - ['@test HashLocation.willDestroy() cleans up hashchange event listener'](assert) { - assert.expect(1); + ['@test HashLocation.willDestroy() cleans up hashchange event listener']( + assert + ) { + assert.expect(1); - createLocation({}, assert); + createLocation({}, assert); - let callback = function () { - assert.ok(true, 'should invoke callback once'); - }; + let callback = function() { + assert.ok(true, 'should invoke callback once'); + }; - location.onUpdateURL(callback); + location.onUpdateURL(callback); - triggerHashchange(); + triggerHashchange(); - run(location, 'destroy'); - location = null; + run(location, 'destroy'); + location = null; - triggerHashchange(); + triggerHashchange(); + } } -}); +); diff --git a/packages/ember-routing/tests/location/history_location_test.js b/packages/ember-routing/tests/location/history_location_test.js index 1089a6787a5..3863e076fea 100644 --- a/packages/ember-routing/tests/location/history_location_test.js +++ b/packages/ember-routing/tests/location/history_location_test.js @@ -1,14 +1,13 @@ -import { - set, - run -} from 'ember-metal'; +import { set, run } from 'ember-metal'; import HistoryLocation from '../../location/history_location'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; let FakeHistory, HistoryTestLocation, location; function createLocation(options) { - if (!options) { options = {}; } + if (!options) { + options = {}; + } location = HistoryTestLocation.create(options); } @@ -18,8 +17,8 @@ function mockBrowserLocation(path) { let tmp = document.createElement('a'); tmp.href = path; - let protocol = (!tmp.protocol || tmp.protocol === ':') ? 'http' : tmp.protocol; - let pathname = (tmp.pathname.match(/^\//)) ? tmp.pathname : '/' + tmp.pathname; + let protocol = !tmp.protocol || tmp.protocol === ':' ? 'http' : tmp.protocol; + let pathname = tmp.pathname.match(/^\//) ? tmp.pathname : '/' + tmp.pathname; return { hash: tmp.hash, @@ -33,276 +32,307 @@ function mockBrowserLocation(path) { }; } -moduleFor('HistoryLocation', class extends AbstractTestCase { - constructor() { - super(); - - FakeHistory = { - state: null, - _states: [], - replaceState(state) { - this.state = state; - this._states[0] = state; - }, - pushState(state) { - this.state = state; - this._states.unshift(state); - } - }; - - HistoryTestLocation = HistoryLocation.extend({ - history: FakeHistory - }); - } - - teardown() { - run(() => { - if (location) { location.destroy(); } - }); - } - - ['@test HistoryLocation initState does not get fired on init'](assert) { - assert.expect(1); - - HistoryTestLocation.reopen({ - init() { - assert.ok(true, 'init was called'); - this._super(...arguments); - }, - initState() { - assert.ok(false, 'initState() should not be called automatically'); - } - }); - - createLocation(); - } - - ['@test webkit doesn\'t fire popstate on page load'](assert) { - assert.expect(1); - - HistoryTestLocation.reopen({ - initState() { - this._super(...arguments); - // these two should be equal to be able - // to successfully detect webkit initial popstate - assert.equal(this._previousURL, this.getURL()); - } - }); - - createLocation(); - location.initState(); - } - - ['@test base URL is removed when retrieving the current pathname'](assert) { - assert.expect(1); - - HistoryTestLocation.reopen({ - init() { - this._super(...arguments); - - set(this, 'location', mockBrowserLocation('/base/foo/bar')); - set(this, 'baseURL', '/base/'); - }, - - initState() { - this._super(...arguments); - - assert.equal(this.getURL(), '/foo/bar'); - } - }); - - createLocation(); - location.initState(); - } - - ['@test base URL is preserved when moving around'](assert) { - assert.expect(2); - - HistoryTestLocation.reopen({ - init() { - this._super(...arguments); - - set(this, 'location', mockBrowserLocation('/base/foo/bar')); - set(this, 'baseURL', '/base/'); - } - }); - - createLocation(); - location.initState(); - location.setURL('/one/two'); - - assert.equal(location._historyState.path, '/base/one/two'); - assert.ok(location._historyState.uuid); - } - - ['@test setURL continues to set even with a null state (iframes may set this)'](assert) { - createLocation(); - location.initState(); - - FakeHistory.pushState(null); - location.setURL('/three/four'); - - assert.equal(location._historyState.path, '/three/four'); - assert.ok(location._historyState.uuid); - } - - ['@test replaceURL continues to set even with a null state (iframes may set this)'](assert) { - createLocation(); - location.initState(); - - FakeHistory.pushState(null); - location.replaceURL('/three/four'); - - assert.equal(location._historyState.path, '/three/four'); - assert.ok(location._historyState.uuid); - } - - ['@test HistoryLocation.getURL() returns the current url, excluding both rootURL and baseURL'](assert) { - HistoryTestLocation.reopen({ - init() { - this._super(...arguments); - - set(this, 'location', mockBrowserLocation('/base/foo/bar')); - set(this, 'rootURL', '/app/'); - set(this, 'baseURL', '/base/'); - } - }); - - createLocation(); - - assert.equal(location.getURL(), '/foo/bar'); - } - - ['@test HistoryLocation.getURL() returns the current url, does not remove rootURL if its not at start of url'](assert) { - HistoryTestLocation.reopen({ - init() { - this._super(...arguments); - - set(this, 'location', mockBrowserLocation('/foo/bar/baz')); - set(this, 'rootURL', '/bar/'); - } - }); - - createLocation(); - - assert.equal(location.getURL(), '/foo/bar/baz'); - } - - ['@test HistoryLocation.getURL() will not remove the rootURL when only a partial match'](assert) { - HistoryTestLocation.reopen({ - init() { - this._super(...arguments); - set(this, 'location', mockBrowserLocation('/bars/baz')); - set(this, 'rootURL', '/bar/'); - } - }); - - createLocation(); - - assert.equal(location.getURL(), '/bars/baz'); - } - - ['@test HistoryLocation.getURL() returns the current url, does not remove baseURL if its not at start of url'](assert) { - HistoryTestLocation.reopen({ - init() { - this._super(...arguments); - - set(this, 'location', mockBrowserLocation('/foo/bar/baz')); - set(this, 'baseURL', '/bar/'); - } - }); - - createLocation(); - - assert.equal(location.getURL(), '/foo/bar/baz'); - } - - ['@test HistoryLocation.getURL() will not remove the baseURL when only a partial match'](assert) { - HistoryTestLocation.reopen({ - init() { - this._super(...arguments); - set(this, 'location', mockBrowserLocation('/bars/baz')); - set(this, 'baseURL', '/bar/'); - } - }); - - createLocation(); - - assert.equal(location.getURL(), '/bars/baz'); - } - - ['@test HistoryLocation.getURL() includes location.search'](assert) { - HistoryTestLocation.reopen({ - init() { - this._super(...arguments); - set(this, 'location', mockBrowserLocation('/foo/bar?time=morphin')); - } - }); - - createLocation(); - - assert.equal(location.getURL(), '/foo/bar?time=morphin'); - } - - ['@test HistoryLocation.getURL() includes location.hash'](assert) { - HistoryTestLocation.reopen({ - init() { - this._super(...arguments); - set(this, 'location', mockBrowserLocation('/foo/bar#pink-power-ranger')); - } - }); - - createLocation(); - - assert.equal(location.getURL(), '/foo/bar#pink-power-ranger'); - } - - ['@test HistoryLocation.getURL() includes location.hash and location.search'](assert) { - HistoryTestLocation.reopen({ - init() { - this._super(...arguments); - set(this, 'location', mockBrowserLocation('/foo/bar?time=morphin#pink-power-ranger')); - } - }); - - createLocation(); - - assert.equal(location.getURL(), '/foo/bar?time=morphin#pink-power-ranger'); - } - - - ['@test HistoryLocation.getURL() drops duplicate slashes'](assert) { - HistoryTestLocation.reopen({ - init() { - this._super(...arguments); - let location = mockBrowserLocation('//'); - location.pathname = '//'; // mockBrowserLocation does not allow for `//`, so force it - set(this, 'location', location); - } - }); - - createLocation(); - - assert.equal(location.getURL(), '/'); - } - - ['@test Existing state is preserved on init'](assert) { - let existingState = { - path: '/route/path', - uuid: 'abcd' - }; - - FakeHistory.state = existingState; - - HistoryTestLocation.reopen({ - init() { - this._super(...arguments); - set(this, 'location', mockBrowserLocation('/route/path')); - } - }); - - createLocation(); - location.initState(); - assert.deepEqual(location.getState(), existingState); +moduleFor( + 'HistoryLocation', + class extends AbstractTestCase { + constructor() { + super(); + + FakeHistory = { + state: null, + _states: [], + replaceState(state) { + this.state = state; + this._states[0] = state; + }, + pushState(state) { + this.state = state; + this._states.unshift(state); + } + }; + + HistoryTestLocation = HistoryLocation.extend({ + history: FakeHistory + }); + } + + teardown() { + run(() => { + if (location) { + location.destroy(); + } + }); + } + + ['@test HistoryLocation initState does not get fired on init'](assert) { + assert.expect(1); + + HistoryTestLocation.reopen({ + init() { + assert.ok(true, 'init was called'); + this._super(...arguments); + }, + initState() { + assert.ok(false, 'initState() should not be called automatically'); + } + }); + + createLocation(); + } + + ["@test webkit doesn't fire popstate on page load"](assert) { + assert.expect(1); + + HistoryTestLocation.reopen({ + initState() { + this._super(...arguments); + // these two should be equal to be able + // to successfully detect webkit initial popstate + assert.equal(this._previousURL, this.getURL()); + } + }); + + createLocation(); + location.initState(); + } + + ['@test base URL is removed when retrieving the current pathname'](assert) { + assert.expect(1); + + HistoryTestLocation.reopen({ + init() { + this._super(...arguments); + + set(this, 'location', mockBrowserLocation('/base/foo/bar')); + set(this, 'baseURL', '/base/'); + }, + + initState() { + this._super(...arguments); + + assert.equal(this.getURL(), '/foo/bar'); + } + }); + + createLocation(); + location.initState(); + } + + ['@test base URL is preserved when moving around'](assert) { + assert.expect(2); + + HistoryTestLocation.reopen({ + init() { + this._super(...arguments); + + set(this, 'location', mockBrowserLocation('/base/foo/bar')); + set(this, 'baseURL', '/base/'); + } + }); + + createLocation(); + location.initState(); + location.setURL('/one/two'); + + assert.equal(location._historyState.path, '/base/one/two'); + assert.ok(location._historyState.uuid); + } + + ['@test setURL continues to set even with a null state (iframes may set this)']( + assert + ) { + createLocation(); + location.initState(); + + FakeHistory.pushState(null); + location.setURL('/three/four'); + + assert.equal(location._historyState.path, '/three/four'); + assert.ok(location._historyState.uuid); + } + + ['@test replaceURL continues to set even with a null state (iframes may set this)']( + assert + ) { + createLocation(); + location.initState(); + + FakeHistory.pushState(null); + location.replaceURL('/three/four'); + + assert.equal(location._historyState.path, '/three/four'); + assert.ok(location._historyState.uuid); + } + + ['@test HistoryLocation.getURL() returns the current url, excluding both rootURL and baseURL']( + assert + ) { + HistoryTestLocation.reopen({ + init() { + this._super(...arguments); + + set(this, 'location', mockBrowserLocation('/base/foo/bar')); + set(this, 'rootURL', '/app/'); + set(this, 'baseURL', '/base/'); + } + }); + + createLocation(); + + assert.equal(location.getURL(), '/foo/bar'); + } + + ['@test HistoryLocation.getURL() returns the current url, does not remove rootURL if its not at start of url']( + assert + ) { + HistoryTestLocation.reopen({ + init() { + this._super(...arguments); + + set(this, 'location', mockBrowserLocation('/foo/bar/baz')); + set(this, 'rootURL', '/bar/'); + } + }); + + createLocation(); + + assert.equal(location.getURL(), '/foo/bar/baz'); + } + + ['@test HistoryLocation.getURL() will not remove the rootURL when only a partial match']( + assert + ) { + HistoryTestLocation.reopen({ + init() { + this._super(...arguments); + set(this, 'location', mockBrowserLocation('/bars/baz')); + set(this, 'rootURL', '/bar/'); + } + }); + + createLocation(); + + assert.equal(location.getURL(), '/bars/baz'); + } + + ['@test HistoryLocation.getURL() returns the current url, does not remove baseURL if its not at start of url']( + assert + ) { + HistoryTestLocation.reopen({ + init() { + this._super(...arguments); + + set(this, 'location', mockBrowserLocation('/foo/bar/baz')); + set(this, 'baseURL', '/bar/'); + } + }); + + createLocation(); + + assert.equal(location.getURL(), '/foo/bar/baz'); + } + + ['@test HistoryLocation.getURL() will not remove the baseURL when only a partial match']( + assert + ) { + HistoryTestLocation.reopen({ + init() { + this._super(...arguments); + set(this, 'location', mockBrowserLocation('/bars/baz')); + set(this, 'baseURL', '/bar/'); + } + }); + + createLocation(); + + assert.equal(location.getURL(), '/bars/baz'); + } + + ['@test HistoryLocation.getURL() includes location.search'](assert) { + HistoryTestLocation.reopen({ + init() { + this._super(...arguments); + set(this, 'location', mockBrowserLocation('/foo/bar?time=morphin')); + } + }); + + createLocation(); + + assert.equal(location.getURL(), '/foo/bar?time=morphin'); + } + + ['@test HistoryLocation.getURL() includes location.hash'](assert) { + HistoryTestLocation.reopen({ + init() { + this._super(...arguments); + set( + this, + 'location', + mockBrowserLocation('/foo/bar#pink-power-ranger') + ); + } + }); + + createLocation(); + + assert.equal(location.getURL(), '/foo/bar#pink-power-ranger'); + } + + ['@test HistoryLocation.getURL() includes location.hash and location.search']( + assert + ) { + HistoryTestLocation.reopen({ + init() { + this._super(...arguments); + set( + this, + 'location', + mockBrowserLocation('/foo/bar?time=morphin#pink-power-ranger') + ); + } + }); + + createLocation(); + + assert.equal( + location.getURL(), + '/foo/bar?time=morphin#pink-power-ranger' + ); + } + + ['@test HistoryLocation.getURL() drops duplicate slashes'](assert) { + HistoryTestLocation.reopen({ + init() { + this._super(...arguments); + let location = mockBrowserLocation('//'); + location.pathname = '//'; // mockBrowserLocation does not allow for `//`, so force it + set(this, 'location', location); + } + }); + + createLocation(); + + assert.equal(location.getURL(), '/'); + } + + ['@test Existing state is preserved on init'](assert) { + let existingState = { + path: '/route/path', + uuid: 'abcd' + }; + + FakeHistory.state = existingState; + + HistoryTestLocation.reopen({ + init() { + this._super(...arguments); + set(this, 'location', mockBrowserLocation('/route/path')); + } + }); + + createLocation(); + location.initState(); + assert.deepEqual(location.getState(), existingState); + } } -}); +); diff --git a/packages/ember-routing/tests/location/none_location_test.js b/packages/ember-routing/tests/location/none_location_test.js index d82498fd67f..2dce54b108b 100644 --- a/packages/ember-routing/tests/location/none_location_test.js +++ b/packages/ember-routing/tests/location/none_location_test.js @@ -5,74 +5,89 @@ import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; let NoneTestLocation, location; function createLocation(options) { - if (!options) { options = {}; } + if (!options) { + options = {}; + } location = NoneTestLocation.create(options); } -moduleFor('NoneLocation', class extends AbstractTestCase { - constructor() { - super(); - NoneTestLocation = NoneLocation.extend({}); - } - - teardown() { - run(() => { - if (location) { location.destroy(); } - }); - } - - ['@test NoneLocation.formatURL() returns the current url always appending rootURL'](assert) { - NoneTestLocation.reopen({ - init() { - this._super(...arguments); - set(this, 'rootURL', '/en/'); - } - }); - - createLocation(); - - assert.equal(location.formatURL('/foo/bar'), '/en/foo/bar'); - } - - ['@test NoneLocation.getURL() returns the current path minus rootURL'](assert) { - NoneTestLocation.reopen({ - init() { - this._super(...arguments); - set(this, 'rootURL', '/foo/'); - set(this, 'path', '/foo/bar'); - } - }); - - createLocation(); - - assert.equal(location.getURL(), '/bar'); - } - - ['@test NoneLocation.getURL() will remove the rootURL only from the beginning of a url'](assert) { - NoneTestLocation.reopen({ - init() { - this._super(...arguments); - set(this, 'rootURL', '/bar/'); - set(this, 'path', '/foo/bar/baz'); - } - }); - - createLocation(); - - assert.equal(location.getURL(), '/foo/bar/baz'); - } - - ['@test NoneLocation.getURL() will not remove the rootURL when only a partial match'](assert) { - NoneTestLocation.reopen({ - init() { - this._super(...arguments); - set(this, 'rootURL', '/bar/'); - set(this, 'path', '/bars/baz'); - } - }); - - createLocation(); - - assert.equal(location.getURL(), '/bars/baz'); +moduleFor( + 'NoneLocation', + class extends AbstractTestCase { + constructor() { + super(); + NoneTestLocation = NoneLocation.extend({}); + } + + teardown() { + run(() => { + if (location) { + location.destroy(); + } + }); + } + + ['@test NoneLocation.formatURL() returns the current url always appending rootURL']( + assert + ) { + NoneTestLocation.reopen({ + init() { + this._super(...arguments); + set(this, 'rootURL', '/en/'); + } + }); + + createLocation(); + + assert.equal(location.formatURL('/foo/bar'), '/en/foo/bar'); + } + + ['@test NoneLocation.getURL() returns the current path minus rootURL']( + assert + ) { + NoneTestLocation.reopen({ + init() { + this._super(...arguments); + set(this, 'rootURL', '/foo/'); + set(this, 'path', '/foo/bar'); + } + }); + + createLocation(); + + assert.equal(location.getURL(), '/bar'); + } + + ['@test NoneLocation.getURL() will remove the rootURL only from the beginning of a url']( + assert + ) { + NoneTestLocation.reopen({ + init() { + this._super(...arguments); + set(this, 'rootURL', '/bar/'); + set(this, 'path', '/foo/bar/baz'); + } + }); + + createLocation(); + + assert.equal(location.getURL(), '/foo/bar/baz'); + } + + ['@test NoneLocation.getURL() will not remove the rootURL when only a partial match']( + assert + ) { + NoneTestLocation.reopen({ + init() { + this._super(...arguments); + set(this, 'rootURL', '/bar/'); + set(this, 'path', '/bars/baz'); + } + }); + + createLocation(); + + assert.equal(location.getURL(), '/bars/baz'); + } } -}); +); diff --git a/packages/ember-routing/tests/location/util_test.js b/packages/ember-routing/tests/location/util_test.js index cf1400a4a02..6b118f742ac 100644 --- a/packages/ember-routing/tests/location/util_test.js +++ b/packages/ember-routing/tests/location/util_test.js @@ -5,125 +5,175 @@ import { getQuery, getFullPath } from '../../location/util'; -import { - supportsHistory, - supportsHashChange -} from '../../location/util'; +import { supportsHistory, supportsHashChange } from '../../location/util'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; function mockBrowserLocation(overrides, assert) { - return assign({ - href: 'http://test.com/', - pathname: '/', - hash: '', - search: '', - replace() { - assert.ok(false, 'location.replace should not be called during testing'); - } - }, overrides); + return assign( + { + href: 'http://test.com/', + pathname: '/', + hash: '', + search: '', + replace() { + assert.ok( + false, + 'location.replace should not be called during testing' + ); + } + }, + overrides + ); } -moduleFor('Location Utilities', class extends AbstractTestCase { - ['@test replacePath cannot be used to redirect to a different origin'](assert) { - assert.expect(1); - - let expectedURL; +moduleFor( + 'Location Utilities', + class extends AbstractTestCase { + ['@test replacePath cannot be used to redirect to a different origin']( + assert + ) { + assert.expect(1); - let location = { - protocol: 'http:', - hostname: 'emberjs.com', - port: '1337', + let expectedURL; - replace(url) { - assert.equal(url, expectedURL); - } - }; - - expectedURL = 'http://emberjs.com:1337//google.com'; - replacePath(location, '//google.com'); - } + let location = { + protocol: 'http:', + hostname: 'emberjs.com', + port: '1337', - ['@test getPath() should normalize location.pathname, making sure it always returns a leading slash'](assert) { - let location = mockBrowserLocation({ pathname: 'test' }, assert); - assert.equal(getPath(location), '/test', 'When there is no leading slash, one is added.'); + replace(url) { + assert.equal(url, expectedURL); + } + }; - location = mockBrowserLocation({ pathname: '/test' }, assert); - assert.equal(getPath(location), '/test', 'When a leading slash is already there, it isn\'t added again'); - } + expectedURL = 'http://emberjs.com:1337//google.com'; + replacePath(location, '//google.com'); + } - ['@test getQuery() should return location.search as-is'](assert) { - let location = mockBrowserLocation({ search: '?foo=bar' }, assert); - assert.equal(getQuery(location), '?foo=bar'); - } + ['@test getPath() should normalize location.pathname, making sure it always returns a leading slash']( + assert + ) { + let location = mockBrowserLocation({ pathname: 'test' }, assert); + assert.equal( + getPath(location), + '/test', + 'When there is no leading slash, one is added.' + ); + + location = mockBrowserLocation({ pathname: '/test' }, assert); + assert.equal( + getPath(location), + '/test', + "When a leading slash is already there, it isn't added again" + ); + } - ['@test getFullPath() should return full pathname including query and hash'](assert) { - let location = mockBrowserLocation({ - href: 'http://test.com/about?foo=bar#foo', - pathname: '/about', - search: '?foo=bar', - hash: '#foo' - }, assert); + ['@test getQuery() should return location.search as-is'](assert) { + let location = mockBrowserLocation({ search: '?foo=bar' }, assert); + assert.equal(getQuery(location), '?foo=bar'); + } - assert.equal(getFullPath(location), '/about?foo=bar#foo'); - } + ['@test getFullPath() should return full pathname including query and hash']( + assert + ) { + let location = mockBrowserLocation( + { + href: 'http://test.com/about?foo=bar#foo', + pathname: '/about', + search: '?foo=bar', + hash: '#foo' + }, + assert + ); + + assert.equal(getFullPath(location), '/about?foo=bar#foo'); + } - ['@test Feature-Detecting onhashchange'](assert) { - assert.equal(supportsHashChange(undefined, { onhashchange() {} }), true, 'When not in IE, use onhashchange existence as evidence of the feature'); - assert.equal(supportsHashChange(undefined, { }), false, 'When not in IE, use onhashchange absence as evidence of the feature absence'); - assert.equal(supportsHashChange(7, { onhashchange() {} }), false, 'When in IE7 compatibility mode, never report existence of the feature'); - assert.equal(supportsHashChange(8, { onhashchange() {} }), true, 'When in IE8+, use onhashchange existence as evidence of the feature'); - } + ['@test Feature-Detecting onhashchange'](assert) { + assert.equal( + supportsHashChange(undefined, { onhashchange() {} }), + true, + 'When not in IE, use onhashchange existence as evidence of the feature' + ); + assert.equal( + supportsHashChange(undefined, {}), + false, + 'When not in IE, use onhashchange absence as evidence of the feature absence' + ); + assert.equal( + supportsHashChange(7, { onhashchange() {} }), + false, + 'When in IE7 compatibility mode, never report existence of the feature' + ); + assert.equal( + supportsHashChange(8, { onhashchange() {} }), + true, + 'When in IE8+, use onhashchange existence as evidence of the feature' + ); + } - ['@test Feature-detecting the history API'](assert) { - assert.equal(supportsHistory("", { pushState: true }), true, "returns true if not Android Gingerbread and history.pushState exists"); - assert.equal(supportsHistory("", {}), false, "returns false if history.pushState doesn't exist"); - assert.equal(supportsHistory("", undefined), false, "returns false if history doesn't exist"); - - assert.equal( - supportsHistory( - "Mozilla/5.0 (Linux; U; Android 2.3.5; en-us; HTC Vision Build/GRI40) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", - { pushState: true } - ), - false, - "returns false if Android 2.x stock browser (not Chrome) claiming to support pushState" - ); - - assert.equal( - supportsHistory( - "Mozilla/5.0 (Linux; U; Android 4.0.3; nl-nl; GT-N7000 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30", - { pushState: true } - ), - false, - "returns false for Android 4.0.x stock browser (not Chrome) claiming to support pushState" - ); - - assert.equal( - supportsHistory( - "Mozilla/5.0 (Linux; U; Android 20.3.5; en-us; HTC Vision Build/GRI40) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", - { pushState: true } - ), - true, - "returns true if Android version begins with 2, but is greater than 2" - ); - - assert.equal( - supportsHistory( - "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19", - { pushState: true } - ), - true, - "returns true for Chrome (not stock browser) on Android 4.0.x" - ); - - // Windows Phone UA and History API: https://github.com/Modernizr/Modernizr/issues/1471 - assert.equal( - supportsHistory( - "Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; Microsoft; Virtual) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537", - { pushState: true } - ), - true, - "returns true for Windows Phone 8.1 with misleading user agent string" - ); + ['@test Feature-detecting the history API'](assert) { + assert.equal( + supportsHistory('', { pushState: true }), + true, + 'returns true if not Android Gingerbread and history.pushState exists' + ); + assert.equal( + supportsHistory('', {}), + false, + "returns false if history.pushState doesn't exist" + ); + assert.equal( + supportsHistory('', undefined), + false, + "returns false if history doesn't exist" + ); + + assert.equal( + supportsHistory( + 'Mozilla/5.0 (Linux; U; Android 2.3.5; en-us; HTC Vision Build/GRI40) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1', + { pushState: true } + ), + false, + 'returns false if Android 2.x stock browser (not Chrome) claiming to support pushState' + ); + + assert.equal( + supportsHistory( + 'Mozilla/5.0 (Linux; U; Android 4.0.3; nl-nl; GT-N7000 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30', + { pushState: true } + ), + false, + 'returns false for Android 4.0.x stock browser (not Chrome) claiming to support pushState' + ); + + assert.equal( + supportsHistory( + 'Mozilla/5.0 (Linux; U; Android 20.3.5; en-us; HTC Vision Build/GRI40) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1', + { pushState: true } + ), + true, + 'returns true if Android version begins with 2, but is greater than 2' + ); + + assert.equal( + supportsHistory( + 'Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19', + { pushState: true } + ), + true, + 'returns true for Chrome (not stock browser) on Android 4.0.x' + ); + + // Windows Phone UA and History API: https://github.com/Modernizr/Modernizr/issues/1471 + assert.equal( + supportsHistory( + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; Microsoft; Virtual) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537', + { pushState: true } + ), + true, + 'returns true for Windows Phone 8.1 with misleading user agent string' + ); + } } -}); - +); diff --git a/packages/ember-routing/tests/system/cache_test.js b/packages/ember-routing/tests/system/cache_test.js index 31054a02dd4..8b39a7e8766 100644 --- a/packages/ember-routing/tests/system/cache_test.js +++ b/packages/ember-routing/tests/system/cache_test.js @@ -1,52 +1,70 @@ import BucketCache from '../../system/cache'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('BucketCache', class extends AbstractTestCase { - constructor() { - super(); +moduleFor( + 'BucketCache', + class extends AbstractTestCase { + constructor() { + super(); - this.cache = new BucketCache(); - } + this.cache = new BucketCache(); + } - ['@test has - returns false when bucket is not in cache'](assert) { - assert.strictEqual(this.cache.has('foo'), false); - assert.strictEqual(this.cache.has('constructor'), false); - } + ['@test has - returns false when bucket is not in cache'](assert) { + assert.strictEqual(this.cache.has('foo'), false); + assert.strictEqual(this.cache.has('constructor'), false); + } - ['@test has - returns true when bucket is in cache'](assert) { - let token = {}; + ['@test has - returns true when bucket is in cache'](assert) { + let token = {}; - this.cache.stash('foo', 'bar', token); - this.cache.stash('constructor', 'bar', token); + this.cache.stash('foo', 'bar', token); + this.cache.stash('constructor', 'bar', token); - assert.strictEqual(this.cache.has('foo'), true); - assert.strictEqual(this.cache.has('constructor'), true); - } + assert.strictEqual(this.cache.has('foo'), true); + assert.strictEqual(this.cache.has('constructor'), true); + } - ['@test lookup - returns stashed value if key does exist in bucket'](assert) { - let token = {}; - let defaultValue = {}; + ['@test lookup - returns stashed value if key does exist in bucket']( + assert + ) { + let token = {}; + let defaultValue = {}; - this.cache.stash('foo', 'bar', token); + this.cache.stash('foo', 'bar', token); - assert.strictEqual(this.cache.lookup('foo', 'bar', defaultValue), token); - } + assert.strictEqual(this.cache.lookup('foo', 'bar', defaultValue), token); + } - ['@test lookup - returns default value if key does not exist in bucket'](assert) { - let token = {}; - let defaultValue = {}; + ['@test lookup - returns default value if key does not exist in bucket']( + assert + ) { + let token = {}; + let defaultValue = {}; - this.cache.stash('foo', 'bar', token); + this.cache.stash('foo', 'bar', token); - assert.strictEqual(this.cache.lookup('foo', 'boo', defaultValue), defaultValue); - assert.strictEqual(this.cache.lookup('foo', 'constructor', defaultValue), defaultValue); - } + assert.strictEqual( + this.cache.lookup('foo', 'boo', defaultValue), + defaultValue + ); + assert.strictEqual( + this.cache.lookup('foo', 'constructor', defaultValue), + defaultValue + ); + } - ['@test lookup - returns default value if bucket does not exist'](assert) { - let defaultValue = {}; + ['@test lookup - returns default value if bucket does not exist'](assert) { + let defaultValue = {}; - assert.strictEqual(this.cache.lookup('boo', 'bar', defaultValue), defaultValue); - assert.strictEqual(this.cache.lookup('constructor', 'bar', defaultValue), defaultValue); + assert.strictEqual( + this.cache.lookup('boo', 'bar', defaultValue), + defaultValue + ); + assert.strictEqual( + this.cache.lookup('constructor', 'bar', defaultValue), + defaultValue + ); + } } -}); - +); diff --git a/packages/ember-routing/tests/system/controller_for_test.js b/packages/ember-routing/tests/system/controller_for_test.js index 2936ec59fd2..5bae73045a7 100644 --- a/packages/ember-routing/tests/system/controller_for_test.js +++ b/packages/ember-routing/tests/system/controller_for_test.js @@ -1,71 +1,85 @@ -import { - Controller -} from 'ember-runtime'; +import { Controller } from 'ember-runtime'; import controllerFor from '../../system/controller_for'; import generateController from '../../system/generate_controller'; import { moduleFor, ApplicationTestCase } from 'internal-test-helpers'; import { getDebugFunction, setDebugFunction } from 'ember-debug'; const originalDebug = getDebugFunction('debug'); -const noop = function(){}; +const noop = function() {}; -moduleFor('controllerFor', class extends ApplicationTestCase { - constructor() { - setDebugFunction('debug', noop); - super(); - } +moduleFor( + 'controllerFor', + class extends ApplicationTestCase { + constructor() { + setDebugFunction('debug', noop); + super(); + } - teardown() { - setDebugFunction('debug', originalDebug); - } + teardown() { + setDebugFunction('debug', originalDebug); + } - ['@test controllerFor should lookup for registered controllers'](assert) { - this.add('controller:app', Controller.extend()); + ['@test controllerFor should lookup for registered controllers'](assert) { + this.add('controller:app', Controller.extend()); - return this.visit('/').then(() => { - let appInstance = this.applicationInstance; - let appController = appInstance.lookup('controller:app'); - let controller = controllerFor(appInstance, 'app'); - assert.equal(appController, controller, 'should find app controller'); - }); + return this.visit('/').then(() => { + let appInstance = this.applicationInstance; + let appController = appInstance.lookup('controller:app'); + let controller = controllerFor(appInstance, 'app'); + assert.equal(appController, controller, 'should find app controller'); + }); + } } -}); +); -moduleFor('generateController', class extends ApplicationTestCase { - constructor() { - setDebugFunction('debug', noop); - super(); - } +moduleFor( + 'generateController', + class extends ApplicationTestCase { + constructor() { + setDebugFunction('debug', noop); + super(); + } - teardown() { - setDebugFunction('debug', originalDebug); - } + teardown() { + setDebugFunction('debug', originalDebug); + } - ['@test generateController should return Controller'](assert) { - return this.visit('/').then(() => { - let controller = generateController(this.applicationInstance, 'home'); - assert.ok(controller instanceof Controller, 'should return controller'); - }); - } + ['@test generateController should return Controller'](assert) { + return this.visit('/').then(() => { + let controller = generateController(this.applicationInstance, 'home'); + assert.ok(controller instanceof Controller, 'should return controller'); + }); + } - ['@test generateController should return controller:basic if resolved'](assert) { - let BasicController = Controller.extend(); - this.add('controller:basic', BasicController); + ['@test generateController should return controller:basic if resolved']( + assert + ) { + let BasicController = Controller.extend(); + this.add('controller:basic', BasicController); - return this.visit('/').then(() => { - let controller = generateController(this.applicationInstance, 'home'); - assert.ok(controller instanceof BasicController, 'should return controller'); - }); - } + return this.visit('/').then(() => { + let controller = generateController(this.applicationInstance, 'home'); + assert.ok( + controller instanceof BasicController, + 'should return controller' + ); + }); + } - ['@test generateController should return controller:basic if registered'](assert) { - let BasicController = Controller.extend(); - this.application.register('controller:basic', BasicController); + ['@test generateController should return controller:basic if registered']( + assert + ) { + let BasicController = Controller.extend(); + this.application.register('controller:basic', BasicController); - return this.visit('/').then(() => { - let controller = generateController(this.applicationInstance, 'home'); + return this.visit('/').then(() => { + let controller = generateController(this.applicationInstance, 'home'); - assert.ok(controller instanceof BasicController, 'should return base class of controller'); - }); + assert.ok( + controller instanceof BasicController, + 'should return base class of controller' + ); + }); + } } -}); +); diff --git a/packages/ember-routing/tests/system/dsl_test.js b/packages/ember-routing/tests/system/dsl_test.js index 84e6ff783da..0698981b1eb 100644 --- a/packages/ember-routing/tests/system/dsl_test.js +++ b/packages/ember-routing/tests/system/dsl_test.js @@ -4,296 +4,444 @@ import { buildOwner, moduleFor, AbstractTestCase } from 'internal-test-helpers'; let Router; -moduleFor('Ember Router DSL', class extends AbstractTestCase { - constructor() { - super(); - Router = EmberRouter.extend(); - } - - teardown() { - Router = null; - } - - ['@test should fail when using a reserved route name'](assert) { - let reservedNames = ['array', 'basic', 'object', 'application']; - - assert.expect(reservedNames.length); - - reservedNames.forEach(reservedName => { - expectAssertion(() => { - Router = EmberRouter.extend(); - - Router.map(function() { - this.route(reservedName); - }); - - let router = Router.create(); - router._initRouterJs(); - }, '\'' + reservedName + '\' cannot be used as a route name.'); - }); - } - - ['@test should retain resource namespace if nested with routes'](assert) { - Router = Router.map(function() { - this.route('bleep', function() { - this.route('bloop', function() { - this.route('blork'); +moduleFor( + 'Ember Router DSL', + class extends AbstractTestCase { + constructor() { + super(); + Router = EmberRouter.extend(); + } + + teardown() { + Router = null; + } + + ['@test should fail when using a reserved route name'](assert) { + let reservedNames = ['array', 'basic', 'object', 'application']; + + assert.expect(reservedNames.length); + + reservedNames.forEach(reservedName => { + expectAssertion(() => { + Router = EmberRouter.extend(); + + Router.map(function() { + this.route(reservedName); + }); + + let router = Router.create(); + router._initRouterJs(); + }, "'" + reservedName + "' cannot be used as a route name."); + }); + } + + ['@test should retain resource namespace if nested with routes'](assert) { + Router = Router.map(function() { + this.route('bleep', function() { + this.route('bloop', function() { + this.route('blork'); + }); }); }); - }); - - let router = Router.create(); - router._initRouterJs(); - - assert.ok(router._routerMicrolib.recognizer.names['bleep'], 'parent name was used as base of nested routes'); - assert.ok(router._routerMicrolib.recognizer.names['bleep.bloop'], 'parent name was used as base of nested routes'); - assert.ok(router._routerMicrolib.recognizer.names['bleep.bloop.blork'], 'parent name was used as base of nested routes'); - } - ['@test should add loading and error routes if _isRouterMapResult is true'](assert) { - Router.map(function() { - this.route('blork'); - }); - - let router = Router.create({ - _hasModuleBasedResolver() { return true; } - }); - - router._initRouterJs(); - - assert.ok(router._routerMicrolib.recognizer.names['blork'], 'main route was created'); - assert.ok(router._routerMicrolib.recognizer.names['blork_loading'], 'loading route was added'); - assert.ok(router._routerMicrolib.recognizer.names['blork_error'], 'error route was added'); - } - - ['@test should not add loading and error routes if _isRouterMapResult is false'](assert) { - Router.map(function() { - this.route('blork'); - }); - - let router = Router.create(); - router._initRouterJs(false); - - assert.ok(router._routerMicrolib.recognizer.names['blork'], 'main route was created'); - assert.ok(!router._routerMicrolib.recognizer.names['blork_loading'], 'loading route was not added'); - assert.ok(!router._routerMicrolib.recognizer.names['blork_error'], 'error route was not added'); - } - - ['@test should reset namespace of loading and error routes for routes with resetNamespace'](assert) { - Router.map(function() { - this.route('blork', function() { - this.route('blorp'); - this.route('bleep', { resetNamespace: true }); + let router = Router.create(); + router._initRouterJs(); + + assert.ok( + router._routerMicrolib.recognizer.names['bleep'], + 'parent name was used as base of nested routes' + ); + assert.ok( + router._routerMicrolib.recognizer.names['bleep.bloop'], + 'parent name was used as base of nested routes' + ); + assert.ok( + router._routerMicrolib.recognizer.names['bleep.bloop.blork'], + 'parent name was used as base of nested routes' + ); + } + + ['@test should add loading and error routes if _isRouterMapResult is true']( + assert + ) { + Router.map(function() { + this.route('blork'); }); - }); - - let router = Router.create({ - _hasModuleBasedResolver() { return true; } - }); - - router._initRouterJs(); - - assert.ok(router._routerMicrolib.recognizer.names['blork.blorp'], 'nested route was created'); - assert.ok(router._routerMicrolib.recognizer.names['blork.blorp_loading'], 'nested loading route was added'); - assert.ok(router._routerMicrolib.recognizer.names['blork.blorp_error'], 'nested error route was added'); - - assert.ok(router._routerMicrolib.recognizer.names['bleep'], 'reset route was created'); - assert.ok(router._routerMicrolib.recognizer.names['bleep_loading'], 'reset loading route was added'); - assert.ok(router._routerMicrolib.recognizer.names['bleep_error'], 'reset error route was added'); - assert.ok(!router._routerMicrolib.recognizer.names['blork.bleep'], 'nested reset route was not created'); - assert.ok(!router._routerMicrolib.recognizer.names['blork.bleep_loading'], 'nested reset loading route was not added'); - assert.ok(!router._routerMicrolib.recognizer.names['blork.bleep_error'], 'nested reset error route was not added'); - } - - ['@test should throw an error when defining a route serializer outside an engine'](assert) { - Router.map(function() { - assert.throws(() => { - this.route('posts', { serialize: function() {} }); - }, /Defining a route serializer on route 'posts' outside an Engine is not allowed/); - }); - - Router.create()._initRouterJs(); - } -}); - - -moduleFor('Ember Router DSL with engines', class extends AbstractTestCase { - constructor() { - super(); - Router = EmberRouter.extend(); - } - - teardown() { - Router = null; - } + let router = Router.create({ + _hasModuleBasedResolver() { + return true; + } + }); - ['@test should allow mounting of engines'](assert) { - assert.expect(3); + router._initRouterJs(); + + assert.ok( + router._routerMicrolib.recognizer.names['blork'], + 'main route was created' + ); + assert.ok( + router._routerMicrolib.recognizer.names['blork_loading'], + 'loading route was added' + ); + assert.ok( + router._routerMicrolib.recognizer.names['blork_error'], + 'error route was added' + ); + } + + ['@test should not add loading and error routes if _isRouterMapResult is false']( + assert + ) { + Router.map(function() { + this.route('blork'); + }); - Router = Router.map(function() { - this.route('bleep', function() { - this.route('bloop', function() { - this.mount('chat'); + let router = Router.create(); + router._initRouterJs(false); + + assert.ok( + router._routerMicrolib.recognizer.names['blork'], + 'main route was created' + ); + assert.ok( + !router._routerMicrolib.recognizer.names['blork_loading'], + 'loading route was not added' + ); + assert.ok( + !router._routerMicrolib.recognizer.names['blork_error'], + 'error route was not added' + ); + } + + ['@test should reset namespace of loading and error routes for routes with resetNamespace']( + assert + ) { + Router.map(function() { + this.route('blork', function() { + this.route('blorp'); + this.route('bleep', { resetNamespace: true }); }); }); - }); - let engineInstance = buildOwner({ - ownerOptions: { routable: true } - }); + let router = Router.create({ + _hasModuleBasedResolver() { + return true; + } + }); - let router = Router.create(); - setOwner(router, engineInstance); - router._initRouterJs(); + router._initRouterJs(); + + assert.ok( + router._routerMicrolib.recognizer.names['blork.blorp'], + 'nested route was created' + ); + assert.ok( + router._routerMicrolib.recognizer.names['blork.blorp_loading'], + 'nested loading route was added' + ); + assert.ok( + router._routerMicrolib.recognizer.names['blork.blorp_error'], + 'nested error route was added' + ); + + assert.ok( + router._routerMicrolib.recognizer.names['bleep'], + 'reset route was created' + ); + assert.ok( + router._routerMicrolib.recognizer.names['bleep_loading'], + 'reset loading route was added' + ); + assert.ok( + router._routerMicrolib.recognizer.names['bleep_error'], + 'reset error route was added' + ); + + assert.ok( + !router._routerMicrolib.recognizer.names['blork.bleep'], + 'nested reset route was not created' + ); + assert.ok( + !router._routerMicrolib.recognizer.names['blork.bleep_loading'], + 'nested reset loading route was not added' + ); + assert.ok( + !router._routerMicrolib.recognizer.names['blork.bleep_error'], + 'nested reset error route was not added' + ); + } + + ['@test should throw an error when defining a route serializer outside an engine']( + assert + ) { + Router.map(function() { + assert.throws(() => { + this.route('posts', { serialize: function() {} }); + }, /Defining a route serializer on route 'posts' outside an Engine is not allowed/); + }); - assert.ok(router._routerMicrolib.recognizer.names['bleep'], 'parent name was used as base of nested routes'); - assert.ok(router._routerMicrolib.recognizer.names['bleep.bloop'], 'parent name was used as base of nested routes'); - assert.ok(router._routerMicrolib.recognizer.names['bleep.bloop.chat'], 'parent name was used as base of mounted engine'); + Router.create()._initRouterJs(); + } } - - ['@test should allow mounting of engines at a custom path'](assert) { - assert.expect(1); - - Router = Router.map(function() { - this.route('bleep', function() { - this.route('bloop', function() { - this.mount('chat', { path: 'custom-chat' }); +); + +moduleFor( + 'Ember Router DSL with engines', + class extends AbstractTestCase { + constructor() { + super(); + Router = EmberRouter.extend(); + } + + teardown() { + Router = null; + } + + ['@test should allow mounting of engines'](assert) { + assert.expect(3); + + Router = Router.map(function() { + this.route('bleep', function() { + this.route('bloop', function() { + this.mount('chat'); + }); }); }); - }); - - let engineInstance = buildOwner({ - ownerOptions: { routable: true } - }); - - let router = Router.create(); - setOwner(router, engineInstance); - router._initRouterJs(); - - assert.deepEqual( - router._routerMicrolib.recognizer.names['bleep.bloop.chat'] - .segments - .slice(1, 4) - .map(s => s.value), - ['bleep', 'bloop', 'custom-chat'], - 'segments are properly associated with mounted engine'); - } - ['@test should allow aliasing of engine names with `as`'](assert) { - assert.expect(1); + let engineInstance = buildOwner({ + ownerOptions: { routable: true } + }); - Router = Router.map(function() { - this.route('bleep', function() { - this.route('bloop', function() { - this.mount('chat', { as: 'blork' }); + let router = Router.create(); + setOwner(router, engineInstance); + router._initRouterJs(); + + assert.ok( + router._routerMicrolib.recognizer.names['bleep'], + 'parent name was used as base of nested routes' + ); + assert.ok( + router._routerMicrolib.recognizer.names['bleep.bloop'], + 'parent name was used as base of nested routes' + ); + assert.ok( + router._routerMicrolib.recognizer.names['bleep.bloop.chat'], + 'parent name was used as base of mounted engine' + ); + } + + ['@test should allow mounting of engines at a custom path'](assert) { + assert.expect(1); + + Router = Router.map(function() { + this.route('bleep', function() { + this.route('bloop', function() { + this.mount('chat', { path: 'custom-chat' }); + }); }); }); - }); - - let engineInstance = buildOwner({ - ownerOptions: { routable: true } - }); - - let router = Router.create(); - setOwner(router, engineInstance); - router._initRouterJs(); - - assert.deepEqual( - router._routerMicrolib.recognizer.names['bleep.bloop.blork'] - .segments - .slice(1, 4) - .map(s => s.value), - ['bleep', 'bloop', 'blork'], - 'segments are properly associated with mounted engine with aliased name'); - } - - ['@test should add loading and error routes to a mount if _isRouterMapResult is true'](assert) { - Router.map(function() { - this.mount('chat'); - }); - - let engineInstance = buildOwner({ - ownerOptions: { routable: true } - }); - let router = Router.create({ - _hasModuleBasedResolver() { return true; } - }); - setOwner(router, engineInstance); - router._initRouterJs(); - - assert.ok(router._routerMicrolib.recognizer.names['chat'], 'main route was created'); - assert.ok(router._routerMicrolib.recognizer.names['chat_loading'], 'loading route was added'); - assert.ok(router._routerMicrolib.recognizer.names['chat_error'], 'error route was added'); - } - - ['@test should add loading and error routes to a mount alias if _isRouterMapResult is true'](assert) { - Router.map(function() { - this.mount('chat', { as: 'shoutbox' }); - }); - - let engineInstance = buildOwner({ - ownerOptions: { routable: true } - }); + let engineInstance = buildOwner({ + ownerOptions: { routable: true } + }); - let router = Router.create({ - _hasModuleBasedResolver() { return true; } - }); - setOwner(router, engineInstance); - router._initRouterJs(); + let router = Router.create(); + setOwner(router, engineInstance); + router._initRouterJs(); + + assert.deepEqual( + router._routerMicrolib.recognizer.names['bleep.bloop.chat'].segments + .slice(1, 4) + .map(s => s.value), + ['bleep', 'bloop', 'custom-chat'], + 'segments are properly associated with mounted engine' + ); + } + + ['@test should allow aliasing of engine names with `as`'](assert) { + assert.expect(1); + + Router = Router.map(function() { + this.route('bleep', function() { + this.route('bloop', function() { + this.mount('chat', { as: 'blork' }); + }); + }); + }); - assert.ok(router._routerMicrolib.recognizer.names['shoutbox'], 'main route was created'); - assert.ok(router._routerMicrolib.recognizer.names['shoutbox_loading'], 'loading route was added'); - assert.ok(router._routerMicrolib.recognizer.names['shoutbox_error'], 'error route was added'); - } + let engineInstance = buildOwner({ + ownerOptions: { routable: true } + }); - ['@test should not add loading and error routes to a mount if _isRouterMapResult is false'](assert) { - Router.map(function() { - this.mount('chat'); - }); + let router = Router.create(); + setOwner(router, engineInstance); + router._initRouterJs(); + + assert.deepEqual( + router._routerMicrolib.recognizer.names['bleep.bloop.blork'].segments + .slice(1, 4) + .map(s => s.value), + ['bleep', 'bloop', 'blork'], + 'segments are properly associated with mounted engine with aliased name' + ); + } + + ['@test should add loading and error routes to a mount if _isRouterMapResult is true']( + assert + ) { + Router.map(function() { + this.mount('chat'); + }); - let engineInstance = buildOwner({ - ownerOptions: { routable: true } - }); + let engineInstance = buildOwner({ + ownerOptions: { routable: true } + }); - let router = Router.create(); - setOwner(router, engineInstance); - router._initRouterJs(false); + let router = Router.create({ + _hasModuleBasedResolver() { + return true; + } + }); + setOwner(router, engineInstance); + router._initRouterJs(); + + assert.ok( + router._routerMicrolib.recognizer.names['chat'], + 'main route was created' + ); + assert.ok( + router._routerMicrolib.recognizer.names['chat_loading'], + 'loading route was added' + ); + assert.ok( + router._routerMicrolib.recognizer.names['chat_error'], + 'error route was added' + ); + } + + ['@test should add loading and error routes to a mount alias if _isRouterMapResult is true']( + assert + ) { + Router.map(function() { + this.mount('chat', { as: 'shoutbox' }); + }); - assert.ok(router._routerMicrolib.recognizer.names['chat'], 'main route was created'); - assert.ok(!router._routerMicrolib.recognizer.names['chat_loading'], 'loading route was not added'); - assert.ok(!router._routerMicrolib.recognizer.names['chat_error'], 'error route was not added'); - } + let engineInstance = buildOwner({ + ownerOptions: { routable: true } + }); - ['@test should reset namespace of loading and error routes for mounts with resetNamespace'](assert) { - Router.map(function() { - this.route('news', function() { + let router = Router.create({ + _hasModuleBasedResolver() { + return true; + } + }); + setOwner(router, engineInstance); + router._initRouterJs(); + + assert.ok( + router._routerMicrolib.recognizer.names['shoutbox'], + 'main route was created' + ); + assert.ok( + router._routerMicrolib.recognizer.names['shoutbox_loading'], + 'loading route was added' + ); + assert.ok( + router._routerMicrolib.recognizer.names['shoutbox_error'], + 'error route was added' + ); + } + + ['@test should not add loading and error routes to a mount if _isRouterMapResult is false']( + assert + ) { + Router.map(function() { this.mount('chat'); - this.mount('blog', { resetNamespace: true }); }); - }); - - let engineInstance = buildOwner({ - ownerOptions: { routable: true } - }); - let router = Router.create({ - _hasModuleBasedResolver() { return true; } - }); - setOwner(router, engineInstance); - router._initRouterJs(); + let engineInstance = buildOwner({ + ownerOptions: { routable: true } + }); - assert.ok(router._routerMicrolib.recognizer.names['news.chat'], 'nested route was created'); - assert.ok(router._routerMicrolib.recognizer.names['news.chat_loading'], 'nested loading route was added'); - assert.ok(router._routerMicrolib.recognizer.names['news.chat_error'], 'nested error route was added'); + let router = Router.create(); + setOwner(router, engineInstance); + router._initRouterJs(false); + + assert.ok( + router._routerMicrolib.recognizer.names['chat'], + 'main route was created' + ); + assert.ok( + !router._routerMicrolib.recognizer.names['chat_loading'], + 'loading route was not added' + ); + assert.ok( + !router._routerMicrolib.recognizer.names['chat_error'], + 'error route was not added' + ); + } + + ['@test should reset namespace of loading and error routes for mounts with resetNamespace']( + assert + ) { + Router.map(function() { + this.route('news', function() { + this.mount('chat'); + this.mount('blog', { resetNamespace: true }); + }); + }); - assert.ok(router._routerMicrolib.recognizer.names['blog'], 'reset route was created'); - assert.ok(router._routerMicrolib.recognizer.names['blog_loading'], 'reset loading route was added'); - assert.ok(router._routerMicrolib.recognizer.names['blog_error'], 'reset error route was added'); + let engineInstance = buildOwner({ + ownerOptions: { routable: true } + }); - assert.ok(!router._routerMicrolib.recognizer.names['news.blog'], 'nested reset route was not created'); - assert.ok(!router._routerMicrolib.recognizer.names['news.blog_loading'], 'nested reset loading route was not added'); - assert.ok(!router._routerMicrolib.recognizer.names['news.blog_error'], 'nested reset error route was not added'); + let router = Router.create({ + _hasModuleBasedResolver() { + return true; + } + }); + setOwner(router, engineInstance); + router._initRouterJs(); + + assert.ok( + router._routerMicrolib.recognizer.names['news.chat'], + 'nested route was created' + ); + assert.ok( + router._routerMicrolib.recognizer.names['news.chat_loading'], + 'nested loading route was added' + ); + assert.ok( + router._routerMicrolib.recognizer.names['news.chat_error'], + 'nested error route was added' + ); + + assert.ok( + router._routerMicrolib.recognizer.names['blog'], + 'reset route was created' + ); + assert.ok( + router._routerMicrolib.recognizer.names['blog_loading'], + 'reset loading route was added' + ); + assert.ok( + router._routerMicrolib.recognizer.names['blog_error'], + 'reset error route was added' + ); + + assert.ok( + !router._routerMicrolib.recognizer.names['news.blog'], + 'nested reset route was not created' + ); + assert.ok( + !router._routerMicrolib.recognizer.names['news.blog_loading'], + 'nested reset loading route was not added' + ); + assert.ok( + !router._routerMicrolib.recognizer.names['news.blog_error'], + 'nested reset error route was not added' + ); + } } -}); +); diff --git a/packages/ember-routing/tests/system/route_test.js b/packages/ember-routing/tests/system/route_test.js index 9551f6c012a..4f7935cb0be 100644 --- a/packages/ember-routing/tests/system/route_test.js +++ b/packages/ember-routing/tests/system/route_test.js @@ -1,485 +1,613 @@ import { setOwner } from 'ember-utils'; -import { runDestroy, buildOwner, moduleFor, AbstractTestCase } from 'internal-test-helpers'; import { - Service, - Object as EmberObject, - inject -} from 'ember-runtime'; + runDestroy, + buildOwner, + moduleFor, + AbstractTestCase +} from 'internal-test-helpers'; +import { Service, Object as EmberObject, inject } from 'ember-runtime'; import EmberRoute from '../../system/route'; let route, routeOne, routeTwo, lookupHash; -moduleFor('Route', class extends AbstractTestCase { - constructor() { - super(); - route = EmberRoute.create(); - } - - teardown() { - runDestroy(route); - } - - ['@test default store utilizes the container to acquire the model factory'](assert) { - assert.expect(4); - - let Post = EmberObject.extend(); - let post = {}; - - Post.reopenClass({ - find() { - return post; - } - }); - - let ownerOptions = { - ownerOptions: { - hasRegistration() { - return true; - }, - factoryFor(fullName) { - assert.equal(fullName, 'model:post', 'correct factory was looked up'); - - return { - class: Post, - create() { - return Post.create(); - } - }; +moduleFor( + 'Route', + class extends AbstractTestCase { + constructor() { + super(); + route = EmberRoute.create(); + } + + teardown() { + runDestroy(route); + } + + ['@test default store utilizes the container to acquire the model factory']( + assert + ) { + assert.expect(4); + + let Post = EmberObject.extend(); + let post = {}; + + Post.reopenClass({ + find() { + return post; } - } - }; + }); + + let ownerOptions = { + ownerOptions: { + hasRegistration() { + return true; + }, + factoryFor(fullName) { + assert.equal( + fullName, + 'model:post', + 'correct factory was looked up' + ); + + return { + class: Post, + create() { + return Post.create(); + } + }; + } + } + }; - setOwner(route, buildOwner(ownerOptions)); + setOwner(route, buildOwner(ownerOptions)); - route.set('_qp', null); + route.set('_qp', null); - assert.equal(route.model({ post_id: 1 }), post); - assert.equal(route.findModel('post', 1), post, '#findModel returns the correct post'); - } + assert.equal(route.model({ post_id: 1 }), post); + assert.equal( + route.findModel('post', 1), + post, + '#findModel returns the correct post' + ); + } - ['@test \'store\' can be injected by data persistence frameworks'](assert) { - assert.expect(8); - runDestroy(route); + ["@test 'store' can be injected by data persistence frameworks"](assert) { + assert.expect(8); + runDestroy(route); - let owner = buildOwner(); + let owner = buildOwner(); - let post = { - id: 1 - }; + let post = { + id: 1 + }; - let Store = EmberObject.extend({ - find(type, value) { - assert.ok(true, 'injected model was called'); - assert.equal(type, 'post', 'correct type was called'); - assert.equal(value, 1, 'correct value was called'); - return post; - } - }); + let Store = EmberObject.extend({ + find(type, value) { + assert.ok(true, 'injected model was called'); + assert.equal(type, 'post', 'correct type was called'); + assert.equal(value, 1, 'correct value was called'); + return post; + } + }); - owner.register('route:index', EmberRoute); - owner.register('store:main', Store); + owner.register('route:index', EmberRoute); + owner.register('store:main', Store); - owner.inject('route', 'store', 'store:main'); + owner.inject('route', 'store', 'store:main'); - route = owner.lookup('route:index'); + route = owner.lookup('route:index'); - assert.equal(route.model({ post_id: 1 }), post, '#model returns the correct post'); - assert.equal(route.findModel('post', 1), post, '#findModel returns the correct post'); - } + assert.equal( + route.model({ post_id: 1 }), + post, + '#model returns the correct post' + ); + assert.equal( + route.findModel('post', 1), + post, + '#findModel returns the correct post' + ); + } - ['@test assert if \'store.find\' method is not found']() { - runDestroy(route); + ["@test assert if 'store.find' method is not found"]() { + runDestroy(route); - let owner = buildOwner(); - let Post = EmberObject.extend(); + let owner = buildOwner(); + let Post = EmberObject.extend(); - owner.register('route:index', EmberRoute); - owner.register('model:post', Post); + owner.register('route:index', EmberRoute); + owner.register('model:post', Post); - route = owner.lookup('route:index'); + route = owner.lookup('route:index'); - expectAssertion(function() { - route.findModel('post', 1); - }, 'Post has no method `find`.'); - } + expectAssertion(function() { + route.findModel('post', 1); + }, 'Post has no method `find`.'); + } - ['@test asserts if model class is not found']() { - runDestroy(route); + ['@test asserts if model class is not found']() { + runDestroy(route); - let owner = buildOwner(); - owner.register('route:index', EmberRoute); + let owner = buildOwner(); + owner.register('route:index', EmberRoute); - route = owner.lookup('route:index'); + route = owner.lookup('route:index'); - expectAssertion(function() { - route.model({ post_id: 1 }); - }, /You used the dynamic segment post_id in your route undefined, but .Post did not exist and you did not override your route\'s `model` hook./); - } + expectAssertion(function() { + route.model({ post_id: 1 }); + }, /You used the dynamic segment post_id in your route undefined, but .Post did not exist and you did not override your route\'s `model` hook./); + } - ['@test \'store\' does not need to be injected'](assert) { - runDestroy(route); + ["@test 'store' does not need to be injected"](assert) { + runDestroy(route); - let owner = buildOwner(); + let owner = buildOwner(); - owner.register('route:index', EmberRoute); + owner.register('route:index', EmberRoute); - route = owner.lookup('route:index'); + route = owner.lookup('route:index'); - ignoreAssertion(function() { - route.model({ post_id: 1 }); - }); + ignoreAssertion(function() { + route.model({ post_id: 1 }); + }); - assert.ok(true, 'no error was raised'); - } + assert.ok(true, 'no error was raised'); + } - ['@test modelFor doesn\'t require the router'](assert) { - let owner = buildOwner(); - setOwner(route, owner); + ["@test modelFor doesn't require the router"](assert) { + let owner = buildOwner(); + setOwner(route, owner); - let foo = { name: 'foo' }; + let foo = { name: 'foo' }; - let FooRoute = EmberRoute.extend({ - currentModel: foo - }); + let FooRoute = EmberRoute.extend({ + currentModel: foo + }); - owner.register('route:foo', FooRoute); + owner.register('route:foo', FooRoute); - assert.strictEqual(route.modelFor('foo'), foo); - } + assert.strictEqual(route.modelFor('foo'), foo); + } - ['@test .send just calls an action if the router is absent'](assert) { - assert.expect(7); - let route = EmberRoute.extend({ - actions: { - returnsTrue(foo, bar) { - assert.equal(foo, 1); - assert.equal(bar, 2); - assert.equal(this, route); - return true; - }, - - returnsFalse() { - assert.ok(true, 'returnsFalse was called'); - return false; - } - } - }).create(); + ['@test .send just calls an action if the router is absent'](assert) { + assert.expect(7); + let route = EmberRoute.extend({ + actions: { + returnsTrue(foo, bar) { + assert.equal(foo, 1); + assert.equal(bar, 2); + assert.equal(this, route); + return true; + }, - assert.equal(true, route.send('returnsTrue', 1, 2)); - assert.equal(false, route.send('returnsFalse')); - assert.equal(undefined, route.send('nonexistent', 1, 2, 3)); - } - - ['@test .send just calls an action if the routers internal router property is absent'](assert) { - assert.expect(7); - let route = EmberRoute.extend({ - router: { }, - actions: { - returnsTrue(foo, bar) { - assert.equal(foo, 1); - assert.equal(bar, 2); - assert.equal(this, route); - return true; - }, - - returnsFalse() { - assert.ok(true, 'returnsFalse was called'); - return false; + returnsFalse() { + assert.ok(true, 'returnsFalse was called'); + return false; + } } - } - }).create(); + }).create(); + + assert.equal(true, route.send('returnsTrue', 1, 2)); + assert.equal(false, route.send('returnsFalse')); + assert.equal(undefined, route.send('nonexistent', 1, 2, 3)); + } + + ['@test .send just calls an action if the routers internal router property is absent']( + assert + ) { + assert.expect(7); + let route = EmberRoute.extend({ + router: {}, + actions: { + returnsTrue(foo, bar) { + assert.equal(foo, 1); + assert.equal(bar, 2); + assert.equal(this, route); + return true; + }, + + returnsFalse() { + assert.ok(true, 'returnsFalse was called'); + return false; + } + } + }).create(); - assert.equal(true, route.send('returnsTrue', 1, 2)); - assert.equal(false, route.send('returnsFalse')); - assert.equal(undefined, route.send('nonexistent', 1, 2, 3)); - } + assert.equal(true, route.send('returnsTrue', 1, 2)); + assert.equal(false, route.send('returnsFalse')); + assert.equal(undefined, route.send('nonexistent', 1, 2, 3)); + } - ['@test .send asserts if called on a destroyed route']() { - route.routeName = 'rip-alley'; - runDestroy(route); + ['@test .send asserts if called on a destroyed route']() { + route.routeName = 'rip-alley'; + runDestroy(route); - expectAssertion( - () => { + expectAssertion(() => { route.send('trigger-me-dead'); - }, - "Attempted to call .send() with the action 'trigger-me-dead' on the destroyed route 'rip-alley'." - ); - } -}); - -moduleFor('Route serialize', class extends AbstractTestCase { - constructor() { - super(); - route = EmberRoute.create(); - } - - teardown() { - runDestroy(route); - } - - ['@test returns the models properties if params does not include *_id'](assert) { - let model = { id: 2, firstName: 'Ned', lastName: 'Ryerson' }; - - assert.deepEqual(route.serialize(model, ['firstName', 'lastName']), { firstName: 'Ned', lastName: 'Ryerson' }, 'serialized correctly'); + }, "Attempted to call .send() with the action 'trigger-me-dead' on the destroyed route 'rip-alley'."); + } } - - ['@test returns model.id if params include *_id'](assert) { - let model = { id: 2 }; - - assert.deepEqual(route.serialize(model, ['post_id']), { post_id: 2 }, 'serialized correctly'); +); + +moduleFor( + 'Route serialize', + class extends AbstractTestCase { + constructor() { + super(); + route = EmberRoute.create(); + } + + teardown() { + runDestroy(route); + } + + ['@test returns the models properties if params does not include *_id']( + assert + ) { + let model = { id: 2, firstName: 'Ned', lastName: 'Ryerson' }; + + assert.deepEqual( + route.serialize(model, ['firstName', 'lastName']), + { firstName: 'Ned', lastName: 'Ryerson' }, + 'serialized correctly' + ); + } + + ['@test returns model.id if params include *_id'](assert) { + let model = { id: 2 }; + + assert.deepEqual( + route.serialize(model, ['post_id']), + { post_id: 2 }, + 'serialized correctly' + ); + } + + ['@test returns checks for existence of model.post_id before trying model.id']( + assert + ) { + let model = { post_id: 3 }; + + assert.deepEqual( + route.serialize(model, ['post_id']), + { post_id: 3 }, + 'serialized correctly' + ); + } + + ['@test returns undefined if model is not set'](assert) { + assert.equal( + route.serialize(undefined, ['post_id']), + undefined, + 'serialized correctly' + ); + } } +); - ['@test returns checks for existence of model.post_id before trying model.id'](assert) { - let model = { post_id: 3 }; +moduleFor( + 'Route interaction', + class extends AbstractTestCase { + constructor() { + super(); - assert.deepEqual(route.serialize(model, ['post_id']), { post_id: 3 }, 'serialized correctly'); - } - - ['@test returns undefined if model is not set'](assert) { - assert.equal(route.serialize(undefined, ['post_id']), undefined, 'serialized correctly'); - } -}); - -moduleFor('Route interaction', class extends AbstractTestCase { - constructor() { - super(); - - let owner = { - lookup(fullName) { - return lookupHash[fullName]; - } - }; + let owner = { + lookup(fullName) { + return lookupHash[fullName]; + } + }; - routeOne = EmberRoute.create({ routeName: 'one' }); - routeTwo = EmberRoute.create({ routeName: 'two' }); + routeOne = EmberRoute.create({ routeName: 'one' }); + routeTwo = EmberRoute.create({ routeName: 'two' }); - setOwner(routeOne, owner); - setOwner(routeTwo, owner); + setOwner(routeOne, owner); + setOwner(routeTwo, owner); - lookupHash = { - 'route:one': routeOne, - 'route:two': routeTwo - }; - } + lookupHash = { + 'route:one': routeOne, + 'route:two': routeTwo + }; + } - teardown() { - runDestroy(routeOne); - runDestroy(routeTwo); - } + teardown() { + runDestroy(routeOne); + runDestroy(routeTwo); + } - ['@test route._qp does not crash if the controller has no QP, or setProperties'](assert) { - lookupHash['controller:test'] = {}; + ['@test route._qp does not crash if the controller has no QP, or setProperties']( + assert + ) { + lookupHash['controller:test'] = {}; - routeOne.controllerName = 'test'; - let qp = routeOne.get('_qp'); + routeOne.controllerName = 'test'; + let qp = routeOne.get('_qp'); - assert.deepEqual(qp.map, {}, 'map should be empty'); - assert.deepEqual(qp.propertyNames, [], 'property names should be empty'); - assert.deepEqual(qp.qps, [], 'qps is should be empty'); - } + assert.deepEqual(qp.map, {}, 'map should be empty'); + assert.deepEqual(qp.propertyNames, [], 'property names should be empty'); + assert.deepEqual(qp.qps, [], 'qps is should be empty'); + } - ['@test controllerFor uses route\'s controllerName if specified'](assert) { - let testController = {}; - lookupHash['controller:test'] = testController; + ["@test controllerFor uses route's controllerName if specified"](assert) { + let testController = {}; + lookupHash['controller:test'] = testController; - routeOne.controllerName = 'test'; + routeOne.controllerName = 'test'; - assert.equal(routeTwo.controllerFor('one'), testController); + assert.equal(routeTwo.controllerFor('one'), testController); + } } -}); - -moduleFor('Route injected properties', class extends AbstractTestCase { - ['@test services can be injected into routes'](assert) { - let owner = buildOwner(); - - owner.register('route:application', EmberRoute.extend({ - authService: inject.service('auth') - })); - - owner.register('service:auth', Service.extend()); - - let appRoute = owner.lookup('route:application'); - let authService = owner.lookup('service:auth'); - - assert.equal(authService, appRoute.get('authService'), 'service.auth is injected'); +); + +moduleFor( + 'Route injected properties', + class extends AbstractTestCase { + ['@test services can be injected into routes'](assert) { + let owner = buildOwner(); + + owner.register( + 'route:application', + EmberRoute.extend({ + authService: inject.service('auth') + }) + ); + + owner.register('service:auth', Service.extend()); + + let appRoute = owner.lookup('route:application'); + let authService = owner.lookup('service:auth'); + + assert.equal( + authService, + appRoute.get('authService'), + 'service.auth is injected' + ); + } } -}); - -moduleFor('Route with engines', class extends AbstractTestCase { - - ['@test paramsFor considers an engine\'s mountPoint'](assert) { - let router = { - _deserializeQueryParams() {}, - _routerMicrolib: { - state: { - handlerInfos: [ - { name: 'posts' } - ], - params: { - 'foo.bar': { a: 'b' }, - 'foo.bar.posts': { c: 'd' } +); + +moduleFor( + 'Route with engines', + class extends AbstractTestCase { + ["@test paramsFor considers an engine's mountPoint"](assert) { + let router = { + _deserializeQueryParams() {}, + _routerMicrolib: { + state: { + handlerInfos: [{ name: 'posts' }], + params: { + 'foo.bar': { a: 'b' }, + 'foo.bar.posts': { c: 'd' } + } } } - } - }; + }; - let engineInstance = buildOwner({ - ownerOptions: { - routable: true, + let engineInstance = buildOwner({ + ownerOptions: { + routable: true, - mountPoint: 'foo.bar', + mountPoint: 'foo.bar', - lookup(name) { - if (name === 'route:posts') { - return postsRoute; - } else if (name === 'route:application') { - return applicationRoute; + lookup(name) { + if (name === 'route:posts') { + return postsRoute; + } else if (name === 'route:application') { + return applicationRoute; + } } } - } - }); - - let applicationRoute = EmberRoute.create({ _router: router, routeName: 'application', fullRouteName: 'foo.bar' }); - let postsRoute = EmberRoute.create({ _router: router, routeName: 'posts', fullRouteName: 'foo.bar.posts' }); - let route = EmberRoute.create({ _router: router }); - - setOwner(applicationRoute, engineInstance); - setOwner(postsRoute, engineInstance); - setOwner(route, engineInstance); - - assert.deepEqual(route.paramsFor('application'), { a: 'b' }, 'params match for root `application` route in engine'); - assert.deepEqual(route.paramsFor('posts'), { c: 'd' }, 'params match for `posts` route in engine'); - } - - ['@test modelFor considers an engine\'s mountPoint'](assert) { - let applicationModel = { id: '1' }; - let postsModel = { id: '2' }; - - let router = { - _routerMicrolib: { - activeTransition: { - resolvedModels: { - 'foo.bar': applicationModel, - 'foo.bar.posts': postsModel + }); + + let applicationRoute = EmberRoute.create({ + _router: router, + routeName: 'application', + fullRouteName: 'foo.bar' + }); + let postsRoute = EmberRoute.create({ + _router: router, + routeName: 'posts', + fullRouteName: 'foo.bar.posts' + }); + let route = EmberRoute.create({ _router: router }); + + setOwner(applicationRoute, engineInstance); + setOwner(postsRoute, engineInstance); + setOwner(route, engineInstance); + + assert.deepEqual( + route.paramsFor('application'), + { a: 'b' }, + 'params match for root `application` route in engine' + ); + assert.deepEqual( + route.paramsFor('posts'), + { c: 'd' }, + 'params match for `posts` route in engine' + ); + } + + ["@test modelFor considers an engine's mountPoint"](assert) { + let applicationModel = { id: '1' }; + let postsModel = { id: '2' }; + + let router = { + _routerMicrolib: { + activeTransition: { + resolvedModels: { + 'foo.bar': applicationModel, + 'foo.bar.posts': postsModel + } } } - } - }; + }; - let engineInstance = buildOwner({ - ownerOptions: { - routable: true, + let engineInstance = buildOwner({ + ownerOptions: { + routable: true, - mountPoint: 'foo.bar', + mountPoint: 'foo.bar', - lookup(name) { - if (name === 'route:posts') { - return postsRoute; - } else if (name === 'route:application') { - return applicationRoute; + lookup(name) { + if (name === 'route:posts') { + return postsRoute; + } else if (name === 'route:application') { + return applicationRoute; + } } } - } - }); - - let applicationRoute = EmberRoute.create({ _router: router, routeName: 'application' }); - let postsRoute = EmberRoute.create({ _router: router, routeName: 'posts' }); - let route = EmberRoute.create({ _router: router }); - - setOwner(applicationRoute, engineInstance); - setOwner(postsRoute, engineInstance); - setOwner(route, engineInstance); - - assert.strictEqual(route.modelFor('application'), applicationModel); - assert.strictEqual(route.modelFor('posts'), postsModel); - } - - ['@test transitionTo considers an engine\'s mountPoint'](assert) { - let router = { - transitionTo(route) { - return route; - } - }; - - let engineInstance = buildOwner({ - ownerOptions: { - routable: true, - mountPoint: 'foo.bar' - } - }); - - let route = EmberRoute.create({ _router: router }); - setOwner(route, engineInstance); - - assert.strictEqual(route.transitionTo('application'), 'foo.bar.application', 'properly prefixes application route'); - assert.strictEqual(route.transitionTo('posts'), 'foo.bar.posts', 'properly prefixes child routes'); - assert.throws(() => route.transitionTo('/posts'), 'throws when trying to use a url'); - - let queryParams = {}; - assert.strictEqual(route.transitionTo(queryParams), queryParams, 'passes query param only transitions through'); - } - - ['@test intermediateTransitionTo considers an engine\'s mountPoint'](assert) { - let lastRoute; - let router = { - intermediateTransitionTo(route) { - lastRoute = route; - } - }; - - let engineInstance = buildOwner({ - ownerOptions: { - routable: true, - mountPoint: 'foo.bar' - } - }); - - let route = EmberRoute.create({ _router: router }); - setOwner(route, engineInstance); - - route.intermediateTransitionTo('application'); - assert.strictEqual(lastRoute, 'foo.bar.application', 'properly prefixes application route'); - - route.intermediateTransitionTo('posts'); - assert.strictEqual(lastRoute, 'foo.bar.posts', 'properly prefixes child routes'); - - assert.throws(() => route.intermediateTransitionTo('/posts'), 'throws when trying to use a url'); + }); + + let applicationRoute = EmberRoute.create({ + _router: router, + routeName: 'application' + }); + let postsRoute = EmberRoute.create({ + _router: router, + routeName: 'posts' + }); + let route = EmberRoute.create({ _router: router }); + + setOwner(applicationRoute, engineInstance); + setOwner(postsRoute, engineInstance); + setOwner(route, engineInstance); + + assert.strictEqual(route.modelFor('application'), applicationModel); + assert.strictEqual(route.modelFor('posts'), postsModel); + } + + ["@test transitionTo considers an engine's mountPoint"](assert) { + let router = { + transitionTo(route) { + return route; + } + }; - let queryParams = {}; - route.intermediateTransitionTo(queryParams); - assert.strictEqual(lastRoute, queryParams, 'passes query param only transitions through'); - } + let engineInstance = buildOwner({ + ownerOptions: { + routable: true, + mountPoint: 'foo.bar' + } + }); + + let route = EmberRoute.create({ _router: router }); + setOwner(route, engineInstance); + + assert.strictEqual( + route.transitionTo('application'), + 'foo.bar.application', + 'properly prefixes application route' + ); + assert.strictEqual( + route.transitionTo('posts'), + 'foo.bar.posts', + 'properly prefixes child routes' + ); + assert.throws( + () => route.transitionTo('/posts'), + 'throws when trying to use a url' + ); + + let queryParams = {}; + assert.strictEqual( + route.transitionTo(queryParams), + queryParams, + 'passes query param only transitions through' + ); + } + + ["@test intermediateTransitionTo considers an engine's mountPoint"]( + assert + ) { + let lastRoute; + let router = { + intermediateTransitionTo(route) { + lastRoute = route; + } + }; - ['@test replaceWith considers an engine\'s mountPoint'](assert) { - let router = { - replaceWith(route) { - return route; - } - }; - - let engineInstance = buildOwner({ - ownerOptions: { - routable: true, - mountPoint: 'foo.bar' - } - }); - - let route = EmberRoute.create({ _router: router }); - setOwner(route, engineInstance); - - assert.strictEqual(route.replaceWith('application'), 'foo.bar.application', 'properly prefixes application route'); - assert.strictEqual(route.replaceWith('posts'), 'foo.bar.posts', 'properly prefixes child routes'); - assert.throws(() => route.replaceWith('/posts'), 'throws when trying to use a url'); - - let queryParams = {}; - assert.strictEqual(route.replaceWith(queryParams), queryParams, 'passes query param only transitions through'); - } + let engineInstance = buildOwner({ + ownerOptions: { + routable: true, + mountPoint: 'foo.bar' + } + }); + + let route = EmberRoute.create({ _router: router }); + setOwner(route, engineInstance); + + route.intermediateTransitionTo('application'); + assert.strictEqual( + lastRoute, + 'foo.bar.application', + 'properly prefixes application route' + ); + + route.intermediateTransitionTo('posts'); + assert.strictEqual( + lastRoute, + 'foo.bar.posts', + 'properly prefixes child routes' + ); + + assert.throws( + () => route.intermediateTransitionTo('/posts'), + 'throws when trying to use a url' + ); + + let queryParams = {}; + route.intermediateTransitionTo(queryParams); + assert.strictEqual( + lastRoute, + queryParams, + 'passes query param only transitions through' + ); + } + + ["@test replaceWith considers an engine's mountPoint"](assert) { + let router = { + replaceWith(route) { + return route; + } + }; - ['@test `router` is a deprecated one-way alias to `_router`'](assert) { - let router = {}; - let route = EmberRoute.create({ _router: router }); - expectDeprecation(function() { - return assert.equal(route.router, router); - }, 'Route#router is an intimate API that has been renamed to Route#_router. However you might want to consider using the router service'); + let engineInstance = buildOwner({ + ownerOptions: { + routable: true, + mountPoint: 'foo.bar' + } + }); + + let route = EmberRoute.create({ _router: router }); + setOwner(route, engineInstance); + + assert.strictEqual( + route.replaceWith('application'), + 'foo.bar.application', + 'properly prefixes application route' + ); + assert.strictEqual( + route.replaceWith('posts'), + 'foo.bar.posts', + 'properly prefixes child routes' + ); + assert.throws( + () => route.replaceWith('/posts'), + 'throws when trying to use a url' + ); + + let queryParams = {}; + assert.strictEqual( + route.replaceWith(queryParams), + queryParams, + 'passes query param only transitions through' + ); + } + + ['@test `router` is a deprecated one-way alias to `_router`'](assert) { + let router = {}; + let route = EmberRoute.create({ _router: router }); + expectDeprecation(function() { + return assert.equal(route.router, router); + }, 'Route#router is an intimate API that has been renamed to Route#_router. However you might want to consider using the router service'); + } } -}); +); diff --git a/packages/ember-routing/tests/system/router_test.js b/packages/ember-routing/tests/system/router_test.js index 4aacaeb812f..fbf42f3deee 100644 --- a/packages/ember-routing/tests/system/router_test.js +++ b/packages/ember-routing/tests/system/router_test.js @@ -4,7 +4,12 @@ import HistoryLocation from '../../location/history_location'; import AutoLocation from '../../location/auto_location'; import NoneLocation from '../../location/none_location'; import Router, { triggerEvent } from '../../system/router'; -import { runDestroy, buildOwner, moduleFor, AbstractTestCase } from 'internal-test-helpers'; +import { + runDestroy, + buildOwner, + moduleFor, + AbstractTestCase +} from 'internal-test-helpers'; let owner; @@ -23,258 +28,291 @@ function createRouter(settings, options = {}) { return router; } -moduleFor('Ember Router', class extends AbstractTestCase { - constructor() { - super(); - owner = buildOwner(); - - //register the HashLocation (the default) - owner.register('location:hash', HashLocation); - owner.register('location:history', HistoryLocation); - owner.register('location:auto', AutoLocation); - owner.register('location:none', NoneLocation); - } - - teardown() { - runDestroy(owner); - owner = null; - } - - ['@test can create a router without an owner'](assert) { - createRouter(undefined, { disableSetup: true, skipOwner: true }); - - assert.ok(true, 'no errors were thrown when creating without a container'); - } +moduleFor( + 'Ember Router', + class extends AbstractTestCase { + constructor() { + super(); + owner = buildOwner(); + + //register the HashLocation (the default) + owner.register('location:hash', HashLocation); + owner.register('location:history', HistoryLocation); + owner.register('location:auto', AutoLocation); + owner.register('location:none', NoneLocation); + } - ['@test [GH#15237] EmberError is imported correctly'](assert) { - // If we get the right message it means Error is being imported correctly. - assert.throws(function() { - triggerEvent(null, false, []); - }, /because your app hasn't finished transitioning/); - } + teardown() { + runDestroy(owner); + owner = null; + } - ['@test should not create a router.js instance upon init'](assert) { - let router = createRouter(undefined, { disableSetup: true }); + ['@test can create a router without an owner'](assert) { + createRouter(undefined, { disableSetup: true, skipOwner: true }); - assert.ok(!router._routerMicrolib); - } - - ['@test should not reify location until setupRouter is called'](assert) { - let router = createRouter(undefined, { disableSetup: true }); - assert.equal(typeof router.location, 'string', 'location is specified as a string'); + assert.ok( + true, + 'no errors were thrown when creating without a container' + ); + } - router.setupRouter(); + ['@test [GH#15237] EmberError is imported correctly'](assert) { + // If we get the right message it means Error is being imported correctly. + assert.throws(function() { + triggerEvent(null, false, []); + }, /because your app hasn't finished transitioning/); + } - assert.equal(typeof router.location, 'object', 'location is reified into an object'); - } + ['@test should not create a router.js instance upon init'](assert) { + let router = createRouter(undefined, { disableSetup: true }); - ['@test should destroy its location upon destroying the routers owner.'](assert) { - let router = createRouter(); - let location = router.get('location'); + assert.ok(!router._routerMicrolib); + } - runDestroy(owner); + ['@test should not reify location until setupRouter is called'](assert) { + let router = createRouter(undefined, { disableSetup: true }); + assert.equal( + typeof router.location, + 'string', + 'location is specified as a string' + ); + + router.setupRouter(); + + assert.equal( + typeof router.location, + 'object', + 'location is reified into an object' + ); + } - assert.ok(location.isDestroyed, 'location should be destroyed'); - } + ['@test should destroy its location upon destroying the routers owner.']( + assert + ) { + let router = createRouter(); + let location = router.get('location'); - ['@test should instantiate its location with its `rootURL`'](assert) { - let router = createRouter({ - rootURL: '/rootdir/' - }); - let location = router.get('location'); + runDestroy(owner); - assert.equal(location.get('rootURL'), '/rootdir/'); - } + assert.ok(location.isDestroyed, 'location should be destroyed'); + } - ['@test replacePath should be called with the right path'](assert) { - assert.expect(1); + ['@test should instantiate its location with its `rootURL`'](assert) { + let router = createRouter({ + rootURL: '/rootdir/' + }); + let location = router.get('location'); - let location = owner.lookup('location:auto'); + assert.equal(location.get('rootURL'), '/rootdir/'); + } - let browserLocation = { - href: 'http://test.com/rootdir/welcome', - origin: 'http://test.com', - pathname: '/rootdir/welcome', - hash: '', - search: '', - replace(url) { - assert.equal(url, 'http://test.com/rootdir/#/welcome'); - } - }; + ['@test replacePath should be called with the right path'](assert) { + assert.expect(1); - location.location = browserLocation; - location.global = { onhashchange() { } }; - location.history = null; + let location = owner.lookup('location:auto'); - createRouter({ - location: 'auto', - rootURL: '/rootdir/' - }); - } + let browserLocation = { + href: 'http://test.com/rootdir/welcome', + origin: 'http://test.com', + pathname: '/rootdir/welcome', + hash: '', + search: '', + replace(url) { + assert.equal(url, 'http://test.com/rootdir/#/welcome'); + } + }; - ['@test Router._routePath should consume identical prefixes'](assert) { - createRouter(); + location.location = browserLocation; + location.global = { onhashchange() {} }; + location.history = null; - function routePath() { - let handlerInfos = Array.prototype.slice.call(arguments).map(function(s) { - return { name: s }; + createRouter({ + location: 'auto', + rootURL: '/rootdir/' }); - handlerInfos.unshift({ name: 'ignored' }); - - return Router._routePath(handlerInfos); } - assert.equal(routePath('foo'), 'foo'); - assert.equal(routePath('foo', 'bar', 'baz'), 'foo.bar.baz'); - assert.equal(routePath('foo', 'foo.bar'), 'foo.bar'); - assert.equal(routePath('foo', 'foo.bar', 'foo.bar.baz'), 'foo.bar.baz'); - assert.equal(routePath('foo', 'foo.bar', 'foo.bar.baz.wow'), 'foo.bar.baz.wow'); - assert.equal(routePath('foo', 'foo.bar.baz.wow'), 'foo.bar.baz.wow'); - assert.equal(routePath('foo.bar', 'bar.baz.wow'), 'foo.bar.baz.wow'); - - // This makes no sense, not trying to handle it, just - // making sure it doesn't go boom. - assert.equal(routePath('foo.bar.baz', 'foo'), 'foo.bar.baz.foo'); - } + ['@test Router._routePath should consume identical prefixes'](assert) { + createRouter(); - ['@test Router should cancel routing setup when the Location class says so via cancelRouterSetup'](assert) { - assert.expect(0); + function routePath() { + let handlerInfos = Array.prototype.slice + .call(arguments) + .map(function(s) { + return { name: s }; + }); + handlerInfos.unshift({ name: 'ignored' }); - let router; - let FakeLocation = { - cancelRouterSetup: true, - create() { return this; } - }; + return Router._routePath(handlerInfos); + } - owner.register('location:fake', FakeLocation); + assert.equal(routePath('foo'), 'foo'); + assert.equal(routePath('foo', 'bar', 'baz'), 'foo.bar.baz'); + assert.equal(routePath('foo', 'foo.bar'), 'foo.bar'); + assert.equal(routePath('foo', 'foo.bar', 'foo.bar.baz'), 'foo.bar.baz'); + assert.equal( + routePath('foo', 'foo.bar', 'foo.bar.baz.wow'), + 'foo.bar.baz.wow' + ); + assert.equal(routePath('foo', 'foo.bar.baz.wow'), 'foo.bar.baz.wow'); + assert.equal(routePath('foo.bar', 'bar.baz.wow'), 'foo.bar.baz.wow'); + + // This makes no sense, not trying to handle it, just + // making sure it doesn't go boom. + assert.equal(routePath('foo.bar.baz', 'foo'), 'foo.bar.baz.foo'); + } - router = createRouter({ - location: 'fake', + ['@test Router should cancel routing setup when the Location class says so via cancelRouterSetup']( + assert + ) { + assert.expect(0); - _setupRouter() { - assert.ok(false, '_setupRouter should not be called'); - } - }); + let router; + let FakeLocation = { + cancelRouterSetup: true, + create() { + return this; + } + }; - router.startRouting(); - } + owner.register('location:fake', FakeLocation); - ['@test AutoLocation should replace the url when it\'s not in the preferred format'](assert) { - assert.expect(1); + router = createRouter({ + location: 'fake', - let location = owner.lookup('location:auto'); + _setupRouter() { + assert.ok(false, '_setupRouter should not be called'); + } + }); - location.location = { - href: 'http://test.com/rootdir/welcome', - origin: 'http://test.com', - pathname: '/rootdir/welcome', - hash: '', - search: '', - replace(url) { - assert.equal(url, 'http://test.com/rootdir/#/welcome'); - } - }; - location.history = null; - location.global = { - onhashchange() { } - }; - - createRouter({ - location: 'auto', - rootURL: '/rootdir/' - }); - } + router.startRouting(); + } - ['@test Router#handleURL should remove any #hashes before doing URL transition'](assert) { - assert.expect(2); + ["@test AutoLocation should replace the url when it's not in the preferred format"]( + assert + ) { + assert.expect(1); + + let location = owner.lookup('location:auto'); + + location.location = { + href: 'http://test.com/rootdir/welcome', + origin: 'http://test.com', + pathname: '/rootdir/welcome', + hash: '', + search: '', + replace(url) { + assert.equal(url, 'http://test.com/rootdir/#/welcome'); + } + }; + location.history = null; + location.global = { + onhashchange() {} + }; + + createRouter({ + location: 'auto', + rootURL: '/rootdir/' + }); + } - let router = createRouter({ - _doURLTransition(routerJsMethod, url) { - assert.equal(routerJsMethod, 'handleURL'); - assert.equal(url, '/foo/bar?time=morphin'); - } - }); + ['@test Router#handleURL should remove any #hashes before doing URL transition']( + assert + ) { + assert.expect(2); - router.handleURL('/foo/bar?time=morphin#pink-power-ranger'); - } + let router = createRouter({ + _doURLTransition(routerJsMethod, url) { + assert.equal(routerJsMethod, 'handleURL'); + assert.equal(url, '/foo/bar?time=morphin'); + } + }); - ['@test Router#triggerEvent allows actions to bubble when returning true'](assert) { - assert.expect(2); + router.handleURL('/foo/bar?time=morphin#pink-power-ranger'); + } - let handlerInfos = [ - { - name: 'application', - handler: { - actions: { - loading() { - assert.ok(false, 'loading not handled by application route'); + ['@test Router#triggerEvent allows actions to bubble when returning true']( + assert + ) { + assert.expect(2); + + let handlerInfos = [ + { + name: 'application', + handler: { + actions: { + loading() { + assert.ok(false, 'loading not handled by application route'); + } } } - } - }, - { - name: 'about', - handler: { - actions: { - loading() { - assert.ok(true, 'loading handled by about route'); - return false; + }, + { + name: 'about', + handler: { + actions: { + loading() { + assert.ok(true, 'loading handled by about route'); + return false; + } } } - } - }, - { - name: 'about.me', - handler: { - actions: { - loading() { - assert.ok(true, 'loading handled by about.me route'); - return true; + }, + { + name: 'about.me', + handler: { + actions: { + loading() { + assert.ok(true, 'loading handled by about.me route'); + return true; + } } } } - } - ]; + ]; - triggerEvent(handlerInfos, false, ['loading']); - } - - ['@test Router#triggerEvent ignores handlers that have not loaded yet'](assert) { - assert.expect(1); + triggerEvent(handlerInfos, false, ['loading']); + } - let handlerInfos = [ - { - name: 'about', - handler: { - actions: { - loading() { - assert.ok(true, 'loading handled by about route'); + ['@test Router#triggerEvent ignores handlers that have not loaded yet']( + assert + ) { + assert.expect(1); + + let handlerInfos = [ + { + name: 'about', + handler: { + actions: { + loading() { + assert.ok(true, 'loading handled by about route'); + } } } + }, + { + name: 'about.me', + handler: undefined } - }, - { - name: 'about.me', - handler: undefined - } - ]; + ]; - triggerEvent(handlerInfos, false, ['loading']); - } + triggerEvent(handlerInfos, false, ['loading']); + } - ['@test transitionTo should throw an error when called after owner is destroyed']() { - let router = createRouter(); + ['@test transitionTo should throw an error when called after owner is destroyed']() { + let router = createRouter(); - runDestroy(router); + runDestroy(router); - router.currentRouteName = 'route-a'; + router.currentRouteName = 'route-a'; - expectAssertion(function() { - router.transitionTo('route-b'); - }, "A transition was attempted from 'route-a' to 'route-b' but the application instance has already been destroyed."); + expectAssertion(function() { + router.transitionTo('route-b'); + }, "A transition was attempted from 'route-a' to 'route-b' but the application instance has already been destroyed."); - expectAssertion(function() { - router.transitionTo('./route-b/1'); - }, "A transition was attempted from 'route-a' to './route-b/1' but the application instance has already been destroyed."); + expectAssertion(function() { + router.transitionTo('./route-b/1'); + }, "A transition was attempted from 'route-a' to './route-b/1' but the application instance has already been destroyed."); + } } -}); +); diff --git a/packages/ember-routing/tests/utils_test.js b/packages/ember-routing/tests/utils_test.js index 48dc50dbc69..3d655737fbf 100644 --- a/packages/ember-routing/tests/utils_test.js +++ b/packages/ember-routing/tests/utils_test.js @@ -1,34 +1,63 @@ import { normalizeControllerQueryParams } from '../utils'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('Routing query parameter utils - normalizeControllerQueryParams', class extends AbstractTestCase { - ['@test converts array style into verbose object style'](assert) { - let paramName = 'foo'; - let params = [paramName]; - let normalized = normalizeControllerQueryParams(params); +moduleFor( + 'Routing query parameter utils - normalizeControllerQueryParams', + class extends AbstractTestCase { + ['@test converts array style into verbose object style'](assert) { + let paramName = 'foo'; + let params = [paramName]; + let normalized = normalizeControllerQueryParams(params); - assert.ok(normalized[paramName], 'turns the query param name into key'); - assert.equal(normalized[paramName].as, null, 'includes a blank alias in \'as\' key'); - assert.equal(normalized[paramName].scope, 'model', 'defaults scope to model'); - } + assert.ok(normalized[paramName], 'turns the query param name into key'); + assert.equal( + normalized[paramName].as, + null, + "includes a blank alias in 'as' key" + ); + assert.equal( + normalized[paramName].scope, + 'model', + 'defaults scope to model' + ); + } - ['@test converts object style [{foo: \'an_alias\'}]'](assert) { - let paramName = 'foo'; - let params = [{ 'foo': 'an_alias' }]; - let normalized = normalizeControllerQueryParams(params); + ["@test converts object style [{foo: 'an_alias'}]"](assert) { + let paramName = 'foo'; + let params = [{ foo: 'an_alias' }]; + let normalized = normalizeControllerQueryParams(params); - assert.ok(normalized[paramName], 'retains the query param name as key'); - assert.equal(normalized[paramName].as, 'an_alias', 'includes the provided alias in \'as\' key'); - assert.equal(normalized[paramName].scope, 'model', 'defaults scope to model'); - } + assert.ok(normalized[paramName], 'retains the query param name as key'); + assert.equal( + normalized[paramName].as, + 'an_alias', + "includes the provided alias in 'as' key" + ); + assert.equal( + normalized[paramName].scope, + 'model', + 'defaults scope to model' + ); + } - ['@test retains maximally verbose object style [{foo: {as: \'foo\'}}]'](assert) { - let paramName = 'foo'; - let params = [{ 'foo': { as: 'an_alias' } }]; - let normalized = normalizeControllerQueryParams(params); + ["@test retains maximally verbose object style [{foo: {as: 'foo'}}]"]( + assert + ) { + let paramName = 'foo'; + let params = [{ foo: { as: 'an_alias' } }]; + let normalized = normalizeControllerQueryParams(params); - assert.ok(normalized[paramName], 'retains the query param name as key'); - assert.equal(normalized[paramName].as, 'an_alias', 'includes the provided alias in \'as\' key'); - assert.equal(normalized[paramName].scope, 'model', 'defaults scope to model'); + assert.ok(normalized[paramName], 'retains the query param name as key'); + assert.equal( + normalized[paramName].as, + 'an_alias', + "includes the provided alias in 'as' key" + ); + assert.equal( + normalized[paramName].scope, + 'model', + 'defaults scope to model' + ); + } } -}); +); diff --git a/packages/ember-runtime/lib/compare.js b/packages/ember-runtime/lib/compare.js index da830a4a629..8d872fe3669 100644 --- a/packages/ember-runtime/lib/compare.js +++ b/packages/ember-runtime/lib/compare.js @@ -2,17 +2,17 @@ import { typeOf } from './utils'; import Comparable from './mixins/comparable'; const TYPE_ORDER = { - 'undefined': 0, - 'null': 1, - 'boolean': 2, - 'number': 3, - 'string': 4, - 'array': 5, - 'object': 6, - 'instance': 7, - 'function': 8, - 'class': 9, - 'date': 10 + undefined: 0, + null: 1, + boolean: 2, + number: 3, + string: 4, + array: 5, + object: 6, + instance: 7, + function: 8, + class: 9, + date: 10 }; // diff --git a/packages/ember-runtime/lib/computed/computed_macros.js b/packages/ember-runtime/lib/computed/computed_macros.js index 04fc096a6ae..b7993a894e4 100644 --- a/packages/ember-runtime/lib/computed/computed_macros.js +++ b/packages/ember-runtime/lib/computed/computed_macros.js @@ -8,10 +8,7 @@ import { alias, expandProperties } from 'ember-metal'; -import { - assert, - deprecate -} from 'ember-debug'; +import { assert, deprecate } from 'ember-debug'; /** @module @ember/object @@ -26,7 +23,10 @@ function expandPropertiesToArray(predicateName, properties) { for (let i = 0; i < properties.length; i++) { let property = properties[i]; - assert(`Dependent keys passed to computed.${predicateName}() can\'t have spaces.`, property.indexOf(' ') < 0); + assert( + `Dependent keys passed to computed.${predicateName}() can\'t have spaces.`, + property.indexOf(' ') < 0 + ); expandProperties(property, extractProperty); } @@ -38,18 +38,21 @@ function generateComputedWithPredicate(name, predicate) { return (...properties) => { let dependentKeys = expandPropertiesToArray(name, properties); - let computedFunc = new ComputedProperty(function() { - let lastIdx = dependentKeys.length - 1; + let computedFunc = new ComputedProperty( + function() { + let lastIdx = dependentKeys.length - 1; - for (let i = 0; i < lastIdx; i++) { - let value = get(this, dependentKeys[i]); - if (!predicate(value)) { - return value; + for (let i = 0; i < lastIdx; i++) { + let value = get(this, dependentKeys[i]); + if (!predicate(value)) { + return value; + } } - } - return get(this, dependentKeys[lastIdx]); - }, { dependentKeys }); + return get(this, dependentKeys[lastIdx]); + }, + { dependentKeys } + ); return computedFunc; }; @@ -719,11 +722,19 @@ export function readOnly(dependentKey) { export function deprecatingAlias(dependentKey, options) { return computed(dependentKey, { get(key) { - deprecate(`Usage of \`${key}\` is deprecated, use \`${dependentKey}\` instead.`, false, options); + deprecate( + `Usage of \`${key}\` is deprecated, use \`${dependentKey}\` instead.`, + false, + options + ); return get(this, dependentKey); }, set(key, value) { - deprecate(`Usage of \`${key}\` is deprecated, use \`${dependentKey}\` instead.`, false, options); + deprecate( + `Usage of \`${key}\` is deprecated, use \`${dependentKey}\` instead.`, + false, + options + ); set(this, dependentKey, value); return value; } diff --git a/packages/ember-runtime/lib/computed/reduce_computed_macros.js b/packages/ember-runtime/lib/computed/reduce_computed_macros.js index 1cb3af731c8..cb93371856d 100644 --- a/packages/ember-runtime/lib/computed/reduce_computed_macros.js +++ b/packages/ember-runtime/lib/computed/reduce_computed_macros.js @@ -19,11 +19,16 @@ function reduceMacro(dependentKey, callback, initialValue, name) { !/[\[\]\{\}]/g.test(dependentKey) ); - let cp = new ComputedProperty(function() { - let arr = get(this, dependentKey); - if (arr === null || typeof arr !== 'object') { return initialValue; } - return arr.reduce(callback, initialValue, this); - }, { dependentKeys: [`${dependentKey}.[]`], readOnly: true }); + let cp = new ComputedProperty( + function() { + let arr = get(this, dependentKey); + if (arr === null || typeof arr !== 'object') { + return initialValue; + } + return arr.reduce(callback, initialValue, this); + }, + { dependentKeys: [`${dependentKey}.[]`], readOnly: true } + ); return cp; } @@ -38,14 +43,17 @@ function arrayMacro(dependentKey, callback) { dependentKey += '.[]'; } - let cp = new ComputedProperty(function() { - let value = get(this, propertyName); - if (isArray(value)) { - return emberA(callback.call(this, value)); - } else { - return emberA(); - } - }, { readOnly: true }); + let cp = new ComputedProperty( + function() { + let value = get(this, propertyName); + if (isArray(value)) { + return emberA(callback.call(this, value)); + } else { + return emberA(); + } + }, + { readOnly: true } + ); cp.property(dependentKey); // this forces to expand properties GH #15855 @@ -55,13 +63,16 @@ function arrayMacro(dependentKey, callback) { function multiArrayMacro(_dependentKeys, callback, name) { assert( `Dependent keys passed to \`computed.${name}\` shouldn't contain brace expanding pattern.`, - _dependentKeys.every((dependentKey)=> !/[\[\]\{\}]/g.test(dependentKey)) + _dependentKeys.every(dependentKey => !/[\[\]\{\}]/g.test(dependentKey)) ); let dependentKeys = _dependentKeys.map(key => `${key}.[]`); - let cp = new ComputedProperty(function() { - return emberA(callback.call(this, _dependentKeys)); - }, { dependentKeys, readOnly: true }); + let cp = new ComputedProperty( + function() { + return emberA(callback.call(this, _dependentKeys)); + }, + { dependentKeys, readOnly: true } + ); return cp; } @@ -128,7 +139,12 @@ export function sum(dependentKey) { @public */ export function max(dependentKey) { - return reduceMacro(dependentKey, (max, item) => Math.max(max, item), -Infinity, 'max'); + return reduceMacro( + dependentKey, + (max, item) => Math.max(max, item), + -Infinity, + 'max' + ); } /** @@ -177,7 +193,12 @@ export function max(dependentKey) { @public */ export function min(dependentKey) { - return reduceMacro(dependentKey, (min, item) => Math.min(min, item), Infinity, 'min'); + return reduceMacro( + dependentKey, + (min, item) => Math.min(min, item), + Infinity, + 'min' + ); } /** @@ -260,8 +281,8 @@ export function map(dependentKey, callback) { */ export function mapBy(dependentKey, propertyKey) { assert( - '\`computed.mapBy\` expects a property string for its second argument, ' + - 'perhaps you meant to use "map"', + '`computed.mapBy` expects a property string for its second argument, ' + + 'perhaps you meant to use "map"', typeof propertyKey === 'string' ); assert( @@ -269,7 +290,9 @@ export function mapBy(dependentKey, propertyKey) { !/[\[\]\{\}]/g.test(dependentKey) ); - return map(`${dependentKey}.@each.${propertyKey}`, item => get(item, propertyKey)); + return map(`${dependentKey}.@each.${propertyKey}`, item => + get(item, propertyKey) + ); } /** @@ -384,9 +407,9 @@ export function filterBy(dependentKey, propertyKey, value) { let callback; if (arguments.length === 2) { - callback = (item) => get(item, propertyKey); + callback = item => get(item, propertyKey); } else { - callback = (item) => get(item, propertyKey) === value; + callback = item => get(item, propertyKey) === value; } return filter(`${dependentKey}.@each.${propertyKey}`, callback); @@ -427,24 +450,28 @@ export function filterBy(dependentKey, propertyKey, value) { @public */ export function uniq(...args) { - return multiArrayMacro(args, function(dependentKeys) { - let uniq = emberA(); - let seen = new Set(); + return multiArrayMacro( + args, + function(dependentKeys) { + let uniq = emberA(); + let seen = new Set(); - dependentKeys.forEach(dependentKey => { - let value = get(this, dependentKey); - if (isArray(value)) { - value.forEach(item => { - if (!seen.has(item)) { - seen.add(item); - uniq.push(item); - } - }); - } - }); + dependentKeys.forEach(dependentKey => { + let value = get(this, dependentKey); + if (isArray(value)) { + value.forEach(item => { + if (!seen.has(item)) { + seen.add(item); + uniq.push(item); + } + }); + } + }); - return uniq; - }, 'uniq'); + return uniq; + }, + 'uniq' + ); } /** @@ -486,21 +513,24 @@ export function uniqBy(dependentKey, propertyKey) { !/[\[\]\{\}]/g.test(dependentKey) ); - let cp = new ComputedProperty(function() { - let uniq = emberA(); - let list = get(this, dependentKey); - if (isArray(list)) { - let seen = new Set(); - list.forEach(item => { - let val = get(item, propertyKey); - if (!seen.has(val)) { - seen.add(val); - uniq.push(item); - } - }); - } - return uniq; - }, { dependentKeys: [`${dependentKey}.[]`], readOnly: true }); + let cp = new ComputedProperty( + function() { + let uniq = emberA(); + let list = get(this, dependentKey); + if (isArray(list)) { + let seen = new Set(); + list.forEach(item => { + let val = get(item, propertyKey); + if (!seen.has(val)) { + seen.add(val); + uniq.push(item); + } + }); + } + return uniq; + }, + { dependentKeys: [`${dependentKey}.[]`], readOnly: true } + ); return cp; } @@ -593,7 +623,9 @@ export function intersect(...args) { } } - if (found === false) { return false; } + if (found === false) { + return false; + } } return true; @@ -603,7 +635,6 @@ export function intersect(...args) { }); } - /** A computed property which returns a new array with all the properties from the first dependent array that are not in the second @@ -641,7 +672,8 @@ export function intersect(...args) { @public */ export function setDiff(setAProperty, setBProperty) { - assert('\`computed.setDiff\` requires exactly two dependent arrays.', + assert( + '`computed.setDiff` requires exactly two dependent arrays.', arguments.length === 2 ); assert( @@ -649,18 +681,25 @@ export function setDiff(setAProperty, setBProperty) { !/[\[\]\{\}]/g.test(setAProperty) && !/[\[\]\{\}]/g.test(setBProperty) ); - let cp = new ComputedProperty(function() { - let setA = this.get(setAProperty); - let setB = this.get(setBProperty); + let cp = new ComputedProperty( + function() { + let setA = this.get(setAProperty); + let setB = this.get(setBProperty); - if (!isArray(setA)) { return emberA(); } - if (!isArray(setB)) { return emberA(setA); } + if (!isArray(setA)) { + return emberA(); + } + if (!isArray(setB)) { + return emberA(setA); + } - return setA.filter(x => setB.indexOf(x) === -1); - }, { - dependentKeys: [ `${setAProperty}.[]`, `${setBProperty}.[]` ], - readOnly: true - }); + return setA.filter(x => setB.indexOf(x) === -1); + }, + { + dependentKeys: [`${setAProperty}.[]`, `${setBProperty}.[]`], + readOnly: true + } + ); return cp; } @@ -696,20 +735,24 @@ export function setDiff(setAProperty, setBProperty) { @public */ export function collect(...dependentKeys) { - return multiArrayMacro(dependentKeys, function() { - let properties = getProperties(this, dependentKeys); - let res = emberA(); - for (let key in properties) { - if (properties.hasOwnProperty(key)) { - if (properties[key] === undefined) { - res.push(null); - } else { - res.push(properties[key]); + return multiArrayMacro( + dependentKeys, + function() { + let properties = getProperties(this, dependentKeys); + let res = emberA(); + for (let key in properties) { + if (properties.hasOwnProperty(key)) { + if (properties[key] === undefined) { + res.push(null); + } else { + res.push(properties[key]); + } } } - } - return res; - }, 'collect'); + return res; + }, + 'collect' + ); } /** @@ -783,8 +826,8 @@ export function collect(...dependentKeys) { */ export function sort(itemsKey, sortDefinition) { assert( - '\`computed.sort\` requires two arguments: an array key to sort and ' + - 'either a sort properties key or sort function', + '`computed.sort` requires two arguments: an array key to sort and ' + + 'either a sort properties key or sort function', arguments.length === 2 ); @@ -804,45 +847,54 @@ function customSort(itemsKey, comparator) { // This one needs to dynamically set up and tear down observers on the itemsKey // depending on the sortProperties function propertySort(itemsKey, sortPropertiesKey) { - let cp = new ComputedProperty(function(key) { - let sortProperties = get(this, sortPropertiesKey); - - assert( - `The sort definition for '${key}' on ${this} must be a function or an array of strings`, - isArray(sortProperties) && sortProperties.every(s => typeof s === 'string') - ); - - // Add/remove property observers as required. - let activeObserversMap = cp._activeObserverMap || (cp._activeObserverMap = new WeakMap()); - let activeObservers = activeObserversMap.get(this); - - if (activeObservers !== undefined) { - activeObservers.forEach(args => removeObserver(...args)); - } + let cp = new ComputedProperty( + function(key) { + let sortProperties = get(this, sortPropertiesKey); + + assert( + `The sort definition for '${key}' on ${this} must be a function or an array of strings`, + isArray(sortProperties) && + sortProperties.every(s => typeof s === 'string') + ); + + // Add/remove property observers as required. + let activeObserversMap = + cp._activeObserverMap || (cp._activeObserverMap = new WeakMap()); + let activeObservers = activeObserversMap.get(this); + + if (activeObservers !== undefined) { + activeObservers.forEach(args => removeObserver(...args)); + } - function sortPropertyDidChange() { - this.notifyPropertyChange(key); - } + function sortPropertyDidChange() { + this.notifyPropertyChange(key); + } - let itemsKeyIsAtThis = (itemsKey === '@this'); - let normalizedSortProperties = normalizeSortProperties(sortProperties); - activeObservers = normalizedSortProperties.map(([prop]) => { - let path = itemsKeyIsAtThis ? `@each.${prop}` : `${itemsKey}.@each.${prop}`; - addObserver(this, path, sortPropertyDidChange); - return [this, path, sortPropertyDidChange]; - }); + let itemsKeyIsAtThis = itemsKey === '@this'; + let normalizedSortProperties = normalizeSortProperties(sortProperties); + activeObservers = normalizedSortProperties.map(([prop]) => { + let path = itemsKeyIsAtThis + ? `@each.${prop}` + : `${itemsKey}.@each.${prop}`; + addObserver(this, path, sortPropertyDidChange); + return [this, path, sortPropertyDidChange]; + }); - activeObserversMap.set(this, activeObservers); + activeObserversMap.set(this, activeObservers); - let items = itemsKeyIsAtThis ? this : get(this, itemsKey); - if (!isArray(items)) { return emberA(); } + let items = itemsKeyIsAtThis ? this : get(this, itemsKey); + if (!isArray(items)) { + return emberA(); + } - if (normalizedSortProperties.length === 0) { - return emberA(items.slice()); - } else { - return sortByNormalizedSortProperties(items, normalizedSortProperties); - } - }, { dependentKeys: [`${sortPropertiesKey}.[]`], readOnly: true }); + if (normalizedSortProperties.length === 0) { + return emberA(items.slice()); + } else { + return sortByNormalizedSortProperties(items, normalizedSortProperties); + } + }, + { dependentKeys: [`${sortPropertiesKey}.[]`], readOnly: true } + ); cp._activeObserverMap = undefined; @@ -859,14 +911,16 @@ function normalizeSortProperties(sortProperties) { } function sortByNormalizedSortProperties(items, normalizedSortProperties) { - return emberA(items.slice().sort((itemA, itemB) => { - for (let i = 0; i < normalizedSortProperties.length; i++) { - let [prop, direction] = normalizedSortProperties[i]; - let result = compare(get(itemA, prop), get(itemB, prop)); - if (result !== 0) { - return (direction === 'desc') ? (-1 * result) : result; + return emberA( + items.slice().sort((itemA, itemB) => { + for (let i = 0; i < normalizedSortProperties.length; i++) { + let [prop, direction] = normalizedSortProperties[i]; + let result = compare(get(itemA, prop), get(itemB, prop)); + if (result !== 0) { + return direction === 'desc' ? -1 * result : result; + } } - } - return 0; - })); + return 0; + }) + ); } diff --git a/packages/ember-runtime/lib/controllers/controller.js b/packages/ember-runtime/lib/controllers/controller.js index 96e702b24bd..ccec3ddc257 100644 --- a/packages/ember-runtime/lib/controllers/controller.js +++ b/packages/ember-runtime/lib/controllers/controller.js @@ -18,7 +18,7 @@ const Controller = EmberObject.extend(Mixin); function controllerInjectionHelper(factory) { assert( 'Defining an injected controller property on a ' + - 'non-controller is not allowed.', + 'non-controller is not allowed.', Mixin.detect(factory.PrototypeMixin) ); } diff --git a/packages/ember-runtime/lib/ext/function.js b/packages/ember-runtime/lib/ext/function.js index 71991095333..2274f923769 100644 --- a/packages/ember-runtime/lib/ext/function.js +++ b/packages/ember-runtime/lib/ext/function.js @@ -3,11 +3,7 @@ */ import { ENV } from 'ember-environment'; -import { - on, - computed, - observer -} from 'ember-metal'; +import { on, computed, observer } from 'ember-metal'; import { assert } from 'ember-debug'; const FunctionPrototype = Function.prototype; @@ -82,7 +78,7 @@ if (ENV.EXTEND_PROTOTYPES.Function) { configurable: true, enumerable: false, writable: true, - value: function () { + value: function() { return computed(...arguments, this); } }); @@ -118,7 +114,7 @@ if (ENV.EXTEND_PROTOTYPES.Function) { configurable: true, enumerable: false, writable: true, - value: function () { + value: function() { return observer(...arguments, this); } }); @@ -127,10 +123,10 @@ if (ENV.EXTEND_PROTOTYPES.Function) { configurable: true, enumerable: false, writable: true, - value: function () { + value: function() { assert( 'Immediate observers must observe internal properties only, ' + - 'not properties on other objects.', + 'not properties on other objects.', function checkIsInternalProperty() { for (let i = 0; i < arguments.length; i++) { if (arguments[i].indexOf('.') !== -1) { @@ -175,7 +171,7 @@ if (ENV.EXTEND_PROTOTYPES.Function) { configurable: true, enumerable: false, writable: true, - value: function () { + value: function() { return on(...arguments, this); } }); diff --git a/packages/ember-runtime/lib/ext/rsvp.js b/packages/ember-runtime/lib/ext/rsvp.js index d16f97881d2..c7631606d5c 100644 --- a/packages/ember-runtime/lib/ext/rsvp.js +++ b/packages/ember-runtime/lib/ext/rsvp.js @@ -1,8 +1,5 @@ import * as RSVP from 'rsvp'; -import { - backburner, - getDispatchOverride -} from 'ember-metal'; +import { backburner, getDispatchOverride } from 'ember-metal'; import { assert } from 'ember-debug'; import { privatize as P } from 'container'; @@ -36,7 +33,12 @@ function errorFor(reason) { } if (reason.name === 'UnrecognizedURLError') { - assert(`The URL '${reason.message}' did not match any routes in your application`, false); + assert( + `The URL '${ + reason.message + }' did not match any routes in your application`, + false + ); return; } diff --git a/packages/ember-runtime/lib/inject.js b/packages/ember-runtime/lib/inject.js index 18992ba30f0..6b6259b618a 100644 --- a/packages/ember-runtime/lib/inject.js +++ b/packages/ember-runtime/lib/inject.js @@ -14,9 +14,13 @@ import { EMBER_MODULE_UNIFICATION } from 'ember/features'; @public */ export default function inject() { - assert(`Injected properties must be created through helpers, see '${Object.keys(inject) - .map(k => `'inject.${k}'`) - .join(' or ')}'`); + assert( + `Injected properties must be created through helpers, see '${Object.keys( + inject + ) + .map(k => `'inject.${k}'`) + .join(' or ')}'` + ); } // Dictionary of injection validations by type, added to by `createInjectionHelper` diff --git a/packages/ember-runtime/lib/mixins/-proxy.js b/packages/ember-runtime/lib/mixins/-proxy.js index b941ef43abf..9c9c2b28c2f 100644 --- a/packages/ember-runtime/lib/mixins/-proxy.js +++ b/packages/ember-runtime/lib/mixins/-proxy.js @@ -2,7 +2,12 @@ @module ember */ -import { combine, CONSTANT_TAG, DirtyableTag, UpdatableTag } from '@glimmer/reference'; +import { + combine, + CONSTANT_TAG, + DirtyableTag, + UpdatableTag +} from '@glimmer/reference'; import { get, set, @@ -15,14 +20,14 @@ import { tagFor, setProxy } from 'ember-metal'; -import { - assert, -} from 'ember-debug'; +import { assert } from 'ember-debug'; import { bool } from '../computed/computed_macros'; function contentPropertyDidChange(content, contentKey) { let key = contentKey.slice(8); // remove "content." - if (key in this) { return; } // if shadowed in proxy + if (key in this) { + return; + } // if shadowed in proxy notifyPropertyChange(this, key); } @@ -58,7 +63,9 @@ export default Mixin.create({ this._super(...arguments); setProxy(this); let m = meta(this); - m.writableTag(() => combine([DirtyableTag.create(), UpdatableTag.create(CONSTANT_TAG)])); + m.writableTag(() => + combine([DirtyableTag.create(), UpdatableTag.create(CONSTANT_TAG)]) + ); }, isTruthy: bool('content'), @@ -92,7 +99,10 @@ export default Mixin.create({ let content = contentFor(this, m); - assert(`Cannot delegate set('${key}', ${value}) to the \'content\' property of object proxy ${this}: its 'content' is undefined.`, content); + assert( + `Cannot delegate set('${key}', ${value}) to the \'content\' property of object proxy ${this}: its 'content' is undefined.`, + content + ); return set(content, key, value); } diff --git a/packages/ember-runtime/lib/mixins/action_handler.js b/packages/ember-runtime/lib/mixins/action_handler.js index 339f93859f4..aeb2429534e 100644 --- a/packages/ember-runtime/lib/mixins/action_handler.js +++ b/packages/ember-runtime/lib/mixins/action_handler.js @@ -203,7 +203,9 @@ const ActionHandler = Mixin.create({ ); if (this.actions && this.actions[actionName]) { let shouldBubble = this.actions[actionName].apply(this, args) === true; - if (!shouldBubble) { return; } + if (!shouldBubble) { + return; + } } let target = get(this, 'target'); diff --git a/packages/ember-runtime/lib/mixins/array.js b/packages/ember-runtime/lib/mixins/array.js index 6146b8c2e85..d98a852e76e 100644 --- a/packages/ember-runtime/lib/mixins/array.js +++ b/packages/ember-runtime/lib/mixins/array.js @@ -41,9 +41,9 @@ export function isEmberArray(obj) { function iter(key, value) { let valueProvided = arguments.length === 2; - return valueProvided ? - (item)=> value === get(item, key) : - (item)=> !!get(item, key); + return valueProvided + ? item => value === get(item, key) + : item => !!get(item, key); } // .......................................................... @@ -83,7 +83,6 @@ function iter(key, value) { @public */ const ArrayMixin = Mixin.create(Enumerable, { - [EMBER_ARRAY]: true, /** @@ -158,7 +157,8 @@ const ArrayMixin = Mixin.create(Enumerable, { @public */ '[]': computed({ - get(key) { // eslint-disable-line no-unused-vars + get() { + // eslint-disable-line no-unused-vars return this; }, set(key, value) { @@ -219,7 +219,7 @@ const ArrayMixin = Mixin.create(Enumerable, { beginIndex = length + beginIndex; } - if (isNone(endIndex) || (endIndex > length)) { + if (isNone(endIndex) || endIndex > length) { endIndex = length; } else if (endIndex < 0) { endIndex = length + endIndex; @@ -376,7 +376,9 @@ const ArrayMixin = Mixin.create(Enumerable, { @public */ hasArrayObservers: computed(function() { - return hasListeners(this, '@array:change') || hasListeners(this, '@array:before'); + return ( + hasListeners(this, '@array:change') || hasListeners(this, '@array:before') + ); }), /** @@ -444,7 +446,10 @@ const ArrayMixin = Mixin.create(Enumerable, { @public */ forEach(callback, target = null) { - assert('forEach expects a function as first argument.', typeof callback === 'function'); + assert( + 'forEach expects a function as first argument.', + typeof callback === 'function' + ); let length = get(this, 'length'); @@ -510,11 +515,14 @@ const ArrayMixin = Mixin.create(Enumerable, { @public */ map(callback, target) { - assert('map expects a function as first argument.', typeof callback === 'function'); + assert( + 'map expects a function as first argument.', + typeof callback === 'function' + ); let ret = A(); - this.forEach((x, idx, i) => ret[idx] = callback.call(target, x, idx, i)); + this.forEach((x, idx, i) => (ret[idx] = callback.call(target, x, idx, i))); return ret; }, @@ -562,7 +570,10 @@ const ArrayMixin = Mixin.create(Enumerable, { @public */ filter(callback, target) { - assert('filter expects a function as first argument.', typeof callback === 'function'); + assert( + 'filter expects a function as first argument.', + typeof callback === 'function' + ); let ret = A(); @@ -603,10 +614,13 @@ const ArrayMixin = Mixin.create(Enumerable, { @public */ reject(callback, target) { - assert('reject expects a function as first argument.', typeof callback === 'function'); + assert( + 'reject expects a function as first argument.', + typeof callback === 'function' + ); return this.filter(function() { - return !(callback.apply(target, arguments)); + return !callback.apply(target, arguments); }); }, @@ -621,7 +635,8 @@ const ArrayMixin = Mixin.create(Enumerable, { @return {Array} filtered array @public */ - filterBy(key, value) { // eslint-disable-line no-unused-vars + filterBy() { + // eslint-disable-line no-unused-vars return this.filter(iter.apply(this, arguments)); }, @@ -638,8 +653,8 @@ const ArrayMixin = Mixin.create(Enumerable, { */ rejectBy(key, value) { let exactValue = item => get(item, key) === value; - let hasValue = item => !!get(item, key); - let use = (arguments.length === 2 ? exactValue : hasValue); + let hasValue = item => !!get(item, key); + let use = arguments.length === 2 ? exactValue : hasValue; return this.reject(use); }, @@ -673,7 +688,10 @@ const ArrayMixin = Mixin.create(Enumerable, { @public */ find(callback, target = null) { - assert('find expects a function as first argument.', typeof callback === 'function'); + assert( + 'find expects a function as first argument.', + typeof callback === 'function' + ); let length = get(this, 'length'); @@ -699,7 +717,8 @@ const ArrayMixin = Mixin.create(Enumerable, { @return {Object} found item or `undefined` @public */ - findBy(key, value) { // eslint-disable-line no-unused-vars + findBy() { + // eslint-disable-line no-unused-vars return this.find(iter.apply(this, arguments)); }, @@ -739,7 +758,10 @@ const ArrayMixin = Mixin.create(Enumerable, { @public */ every(callback, target) { - assert('every expects a function as first argument.', typeof callback === 'function'); + assert( + 'every expects a function as first argument.', + typeof callback === 'function' + ); return !this.find((x, idx, i) => !callback.call(target, x, idx, i)); }, @@ -759,7 +781,8 @@ const ArrayMixin = Mixin.create(Enumerable, { @since 1.3.0 @public */ - isEvery(key, value) { // eslint-disable-line no-unused-vars + isEvery() { + // eslint-disable-line no-unused-vars return this.every(iter.apply(this, arguments)); }, @@ -801,7 +824,10 @@ const ArrayMixin = Mixin.create(Enumerable, { @public */ any(callback, target = null) { - assert('any expects a function as first argument.', typeof callback === 'function'); + assert( + 'any expects a function as first argument.', + typeof callback === 'function' + ); let length = get(this, 'length'); @@ -828,7 +854,8 @@ const ArrayMixin = Mixin.create(Enumerable, { @since 1.3.0 @public */ - isAny(key, value) { // eslint-disable-line no-unused-vars + isAny() { + // eslint-disable-line no-unused-vars return this.any(iter.apply(this, arguments)); }, @@ -867,7 +894,10 @@ const ArrayMixin = Mixin.create(Enumerable, { @public */ reduce(callback, initialValue, reducerProperty) { - assert('reduce expects a function as first argument.', typeof callback === 'function'); + assert( + 'reduce expects a function as first argument.', + typeof callback === 'function' + ); let ret = initialValue; @@ -914,7 +944,7 @@ const ArrayMixin = Mixin.create(Enumerable, { toArray() { let ret = A(); - this.forEach((o, idx) => ret[idx] = o); + this.forEach((o, idx) => (ret[idx] = o)); return ret; }, @@ -1060,7 +1090,7 @@ const ArrayMixin = Mixin.create(Enumerable, { let ret = A(); let seen = new Set(); - this.forEach((item) => { + this.forEach(item => { let val = get(item, key); if (!seen.has(val)) { seen.add(val); @@ -1095,7 +1125,7 @@ const ArrayMixin = Mixin.create(Enumerable, { this.forEach(k => { // SameValueZero comparison (NaN !== NaN) - if (!(k === value || k !== k && value !== value)) { + if (!(k === value || (k !== k && value !== value))) { ret[ret.length] = k; } }); @@ -1136,7 +1166,8 @@ const ArrayMixin = Mixin.create(Enumerable, { { id: 'ember-metal.getting-each', until: '3.5.0', - url: 'https://emberjs.com/deprecations/v3.x#toc_getting-the-each-property' + url: + 'https://emberjs.com/deprecations/v3.x#toc_getting-the-each-property' } ); @@ -1144,13 +1175,12 @@ const ArrayMixin = Mixin.create(Enumerable, { }).readOnly() }); - const OUT_OF_RANGE_EXCEPTION = 'Index out of range'; const EMPTY = []; export function removeAt(array, start, len) { if ('number' === typeof start) { - if ((start < 0) || (start >= get(array, 'length'))) { + if (start < 0 || start >= get(array, 'length')) { throw new EmberError(OUT_OF_RANGE_EXCEPTION); } @@ -1187,7 +1217,6 @@ export function removeAt(array, start, len) { */ const MutableArray = Mixin.create(ArrayMixin, MutableEnumerable, { - /** __Required.__ You must implement this method to apply this mixin. @@ -1609,7 +1638,6 @@ const MutableArray = Mixin.create(ArrayMixin, MutableEnumerable, { @public */ let NativeArray = Mixin.create(MutableArray, Observable, Copyable, { - // because length is a built-in property we need to know to just get the // original property. get(key) { @@ -1626,7 +1654,10 @@ let NativeArray = Mixin.create(MutableArray, Observable, Copyable, { // primitive for array support. replace(start, deleteCount, items = EMPTY_ARRAY) { - assert('The third argument to replace needs to be an array.', Array.isArray(items)); + assert( + 'The third argument to replace needs to be an array.', + Array.isArray(items) + ); replaceInNativeArray(this, start, deleteCount, items); @@ -1636,7 +1667,7 @@ let NativeArray = Mixin.create(MutableArray, Observable, Copyable, { // If you ask for an unknown property, then try to collect the value // from member items. unknownProperty(key, value) { - let ret;// = this.reducedProperty(key, value); + let ret; // = this.reducedProperty(key, value); if (value !== undefined && ret === undefined) { ret = this[key] = value; } @@ -1648,7 +1679,7 @@ let NativeArray = Mixin.create(MutableArray, Observable, Copyable, { copy(deep) { if (deep) { - return this.map((item) => copy(item, true)); + return this.map(item => copy(item, true)); } return this.slice(); @@ -1657,7 +1688,7 @@ let NativeArray = Mixin.create(MutableArray, Observable, Copyable, { // Remove any methods implemented natively so we don't override them const ignore = ['length']; -NativeArray.keys().forEach((methodName) => { +NativeArray.keys().forEach(methodName => { if (Array.prototype[methodName]) { ignore.push(methodName); } @@ -1672,15 +1703,13 @@ if (ENV.EXTEND_PROTOTYPES.Array) { A = arr => arr || []; } else { A = arr => { - if (!arr) { arr = []; } + if (!arr) { + arr = []; + } return ArrayMixin.detect(arr) ? arr : NativeArray.apply(arr); }; } -export { - A, - NativeArray, - MutableArray -}; +export { A, NativeArray, MutableArray }; export default ArrayMixin; diff --git a/packages/ember-runtime/lib/mixins/comparable.js b/packages/ember-runtime/lib/mixins/comparable.js index 3045202deb6..8a041b45a04 100644 --- a/packages/ember-runtime/lib/mixins/comparable.js +++ b/packages/ember-runtime/lib/mixins/comparable.js @@ -16,7 +16,6 @@ import { Mixin } from 'ember-metal'; @private */ export default Mixin.create({ - /** __Required.__ You must implement this method to apply this mixin. diff --git a/packages/ember-runtime/lib/mixins/container_proxy.js b/packages/ember-runtime/lib/mixins/container_proxy.js index 60120d1dd99..bea1c35dbe2 100644 --- a/packages/ember-runtime/lib/mixins/container_proxy.js +++ b/packages/ember-runtime/lib/mixins/container_proxy.js @@ -1,10 +1,7 @@ /** @module ember */ -import { - Mixin, - run -} from 'ember-metal'; +import { Mixin, run } from 'ember-metal'; /** ContainerProxyMixin is used to provide public access to specific @@ -107,7 +104,7 @@ let containerProxyMixin = { } }, -/** + /** Given a fullName return a factory manager. This method returns a manager which can be used for introspection of the diff --git a/packages/ember-runtime/lib/mixins/controller.js b/packages/ember-runtime/lib/mixins/controller.js index 3e897091878..3fbb795fb28 100644 --- a/packages/ember-runtime/lib/mixins/controller.js +++ b/packages/ember-runtime/lib/mixins/controller.js @@ -38,5 +38,5 @@ export default Mixin.create(ActionHandler, { @property model @public */ - model: null, + model: null }); diff --git a/packages/ember-runtime/lib/mixins/evented.js b/packages/ember-runtime/lib/mixins/evented.js index cbed68d8d45..12d79ea5b09 100644 --- a/packages/ember-runtime/lib/mixins/evented.js +++ b/packages/ember-runtime/lib/mixins/evented.js @@ -51,7 +51,6 @@ import { @public */ export default Mixin.create({ - /** Subscribes to a named event with given function. diff --git a/packages/ember-runtime/lib/mixins/observable.js b/packages/ember-runtime/lib/mixins/observable.js index 777cc44acab..f96f1eb02c7 100644 --- a/packages/ember-runtime/lib/mixins/observable.js +++ b/packages/ember-runtime/lib/mixins/observable.js @@ -93,7 +93,6 @@ import { assert } from 'ember-debug'; @public */ export default Mixin.create({ - /** Retrieves the value of a property from the object. @@ -212,7 +211,6 @@ export default Mixin.create({ return set(this, keyName, value); }, - /** Sets a list of properties at once. These properties are set inside a single `beginPropertyChanges` and `endPropertyChanges` batch, so @@ -422,9 +420,18 @@ export default Mixin.create({ @public */ incrementProperty(keyName, increment) { - if (isNone(increment)) { increment = 1; } - assert('Must pass a numeric value to incrementProperty', (!isNaN(parseFloat(increment)) && isFinite(increment))); - return set(this, keyName, (parseFloat(get(this, keyName)) || 0) + increment); + if (isNone(increment)) { + increment = 1; + } + assert( + 'Must pass a numeric value to incrementProperty', + !isNaN(parseFloat(increment)) && isFinite(increment) + ); + return set( + this, + keyName, + (parseFloat(get(this, keyName)) || 0) + increment + ); }, /** @@ -442,8 +449,13 @@ export default Mixin.create({ @public */ decrementProperty(keyName, decrement) { - if (isNone(decrement)) { decrement = 1; } - assert('Must pass a numeric value to decrementProperty', (!isNaN(parseFloat(decrement)) && isFinite(decrement))); + if (isNone(decrement)) { + decrement = 1; + } + assert( + 'Must pass a numeric value to decrementProperty', + !isNaN(parseFloat(decrement)) && isFinite(decrement) + ); return set(this, keyName, (get(this, keyName) || 0) - decrement); }, @@ -477,5 +489,5 @@ export default Mixin.create({ */ cacheFor(keyName) { return getCachedValueFor(this, keyName); - }, + } }); diff --git a/packages/ember-runtime/lib/mixins/promise_proxy.js b/packages/ember-runtime/lib/mixins/promise_proxy.js index 7707566efca..380e4cd4e9b 100644 --- a/packages/ember-runtime/lib/mixins/promise_proxy.js +++ b/packages/ember-runtime/lib/mixins/promise_proxy.js @@ -1,9 +1,4 @@ -import { - get, - setProperties, - computed, - Mixin -} from 'ember-metal'; +import { get, setProperties, computed, Mixin } from 'ember-metal'; import { Error as EmberError } from 'ember-debug'; import { not, or } from '../computed/computed_macros'; @@ -17,23 +12,27 @@ function tap(proxy, promise) { isRejected: false }); - return promise.then(value => { - if (!proxy.isDestroyed && !proxy.isDestroying) { - setProperties(proxy, { - content: value, - isFulfilled: true - }); - } - return value; - }, reason => { - if (!proxy.isDestroyed && !proxy.isDestroying) { - setProperties(proxy, { - reason, - isRejected: true - }); - } - throw reason; - }, 'Ember: PromiseProxy'); + return promise.then( + value => { + if (!proxy.isDestroyed && !proxy.isDestroying) { + setProperties(proxy, { + content: value, + isFulfilled: true + }); + } + return value; + }, + reason => { + if (!proxy.isDestroyed && !proxy.isDestroying) { + setProperties(proxy, { + reason, + isRejected: true + }); + } + throw reason; + }, + 'Ember: PromiseProxy' + ); } /** @@ -168,7 +167,7 @@ export default Mixin.create({ */ promise: computed({ get() { - throw new EmberError('PromiseProxy\'s promise must be set'); + throw new EmberError("PromiseProxy's promise must be set"); }, set(key, promise) { return tap(this, promise); @@ -198,7 +197,7 @@ export default Mixin.create({ @since 1.3.0 @public */ - 'catch': promiseAlias('catch'), + catch: promiseAlias('catch'), /** An alias to the proxied promise's `finally`. @@ -211,12 +210,11 @@ export default Mixin.create({ @since 1.3.0 @public */ - 'finally': promiseAlias('finally') - + finally: promiseAlias('finally') }); function promiseAlias(name) { - return function () { + return function() { let promise = get(this, 'promise'); return promise[name](...arguments); }; diff --git a/packages/ember-runtime/lib/mixins/registry_proxy.js b/packages/ember-runtime/lib/mixins/registry_proxy.js index 18ac79b75e9..4095d269108 100644 --- a/packages/ember-runtime/lib/mixins/registry_proxy.js +++ b/packages/ember-runtime/lib/mixins/registry_proxy.js @@ -3,9 +3,7 @@ */ import { assert } from 'ember-debug'; -import { - Mixin -} from 'ember-metal'; +import { Mixin } from 'ember-metal'; /** RegistryProxyMixin is used to provide public access to specific @@ -26,7 +24,10 @@ export default Mixin.create({ @return {Function} fullName's factory */ resolveRegistration(fullName, options) { - assert('fullName must be a proper full name', this.__registry__.isValidFullName(fullName)); + assert( + 'fullName must be a proper full name', + this.__registry__.isValidFullName(fullName) + ); return this.__registry__.resolve(fullName, options); }, @@ -261,7 +262,7 @@ export default Mixin.create({ }); function registryAlias(name) { - return function () { + return function() { return this.__registry__[name](...arguments); }; } diff --git a/packages/ember-runtime/lib/mixins/target_action_support.js b/packages/ember-runtime/lib/mixins/target_action_support.js index cbf15f09edf..85fca5e48f4 100644 --- a/packages/ember-runtime/lib/mixins/target_action_support.js +++ b/packages/ember-runtime/lib/mixins/target_action_support.js @@ -3,12 +3,7 @@ */ import { context } from 'ember-environment'; -import { - get, - Mixin, - computed, - descriptor -} from 'ember-metal'; +import { get, Mixin, computed, descriptor } from 'ember-metal'; import { assert, deprecate } from 'ember-debug'; /** `Ember.TargetActionSupport` is a mixin that can be included in a class @@ -48,7 +43,9 @@ export default Mixin.create({ if (typeof actionContext === 'string') { let value = get(this, actionContext); - if (value === undefined) { value = get(context.lookup, actionContext); } + if (value === undefined) { + value = get(context.lookup, actionContext); + } return value; } else { return actionContext; @@ -127,7 +124,10 @@ export default Mixin.create({ if (target.send) { ret = target.send(...[action].concat(actionContext)); } else { - assert(`The action '${action}' did not exist on ${target}`, typeof target[action] === 'function'); + assert( + `The action '${action}' did not exist on ${target}`, + typeof target[action] === 'function' + ); ret = target[action](...[].concat(actionContext)); } @@ -156,10 +156,14 @@ function getTarget(instance) { } // if a `targetObject` CP was provided, use it - if (target) { return target; } + if (target) { + return target; + } // if _targetObject use it - if (instance._targetObject) { return instance._targetObject; } + if (instance._targetObject) { + return instance._targetObject; + } return null; } diff --git a/packages/ember-runtime/lib/system/array_proxy.js b/packages/ember-runtime/lib/system/array_proxy.js index 453dc4e5ff2..efa7b3a9678 100644 --- a/packages/ember-runtime/lib/system/array_proxy.js +++ b/packages/ember-runtime/lib/system/array_proxy.js @@ -11,9 +11,7 @@ import { addArrayObserver, removeArrayObserver } from 'ember-metal'; -import { - isArray -} from '../utils'; +import { isArray } from '../utils'; import EmberObject from './object'; import { MutableArray } from '../mixins/array'; import { assert } from 'ember-debug'; @@ -132,7 +130,10 @@ export default EmberObject.extend(MutableArray, { }, replace(idx, amt, objects) { - assert('Mutating an arranged ArrayProxy is not allowed', get(this, 'arrangedContent') === get(this, 'content') ); + assert( + 'Mutating an arranged ArrayProxy is not allowed', + get(this, 'arrangedContent') === get(this, 'content') + ); this.replaceContent(idx, amt, objects); }, @@ -164,7 +165,7 @@ export default EmberObject.extend(MutableArray, { if (this._objectsDirtyIndex !== -1 && idx >= this._objectsDirtyIndex) { let arrangedContent = get(this, 'arrangedContent'); if (arrangedContent) { - let length = this._objects.length = get(arrangedContent, 'length'); + let length = (this._objects.length = get(arrangedContent, 'length')); for (let i = this._objectsDirtyIndex; i < length; i++) { this._objects[i] = this.objectAtContent(i); @@ -209,9 +210,14 @@ export default EmberObject.extend(MutableArray, { _addArrangedContentArrayObsever() { let arrangedContent = get(this, 'arrangedContent'); if (arrangedContent) { - assert('Can\'t set ArrayProxy\'s content to itself', arrangedContent !== this); - assert(`ArrayProxy expects an Array or ArrayProxy, but you passed ${typeof arrangedContent}`, - isArray(arrangedContent) || arrangedContent.isDestroyed); + assert( + "Can't set ArrayProxy's content to itself", + arrangedContent !== this + ); + assert( + `ArrayProxy expects an Array or ArrayProxy, but you passed ${typeof arrangedContent}`, + isArray(arrangedContent) || arrangedContent.isDestroyed + ); addArrayObserver(arrangedContent, this, ARRAY_OBSERVER_MAPPING); diff --git a/packages/ember-runtime/lib/system/string.js b/packages/ember-runtime/lib/system/string.js index fc647aa08cd..fa13c4ea1bd 100644 --- a/packages/ember-runtime/lib/system/string.js +++ b/packages/ember-runtime/lib/system/string.js @@ -4,49 +4,73 @@ import { Cache } from 'ember-metal'; import { inspect } from 'ember-utils'; import { isArray } from '../utils'; -import { - get as getString -} from '../string_registry'; +import { get as getString } from '../string_registry'; -const STRING_DASHERIZE_REGEXP = (/[ _]/g); +const STRING_DASHERIZE_REGEXP = /[ _]/g; -const STRING_DASHERIZE_CACHE = new Cache(1000, key => decamelize(key).replace(STRING_DASHERIZE_REGEXP, '-')); +const STRING_DASHERIZE_CACHE = new Cache(1000, key => + decamelize(key).replace(STRING_DASHERIZE_REGEXP, '-') +); -const STRING_CAMELIZE_REGEXP_1 = (/(\-|\_|\.|\s)+(.)?/g); -const STRING_CAMELIZE_REGEXP_2 = (/(^|\/)([A-Z])/g); +const STRING_CAMELIZE_REGEXP_1 = /(\-|\_|\.|\s)+(.)?/g; +const STRING_CAMELIZE_REGEXP_2 = /(^|\/)([A-Z])/g; -const CAMELIZE_CACHE = new Cache(1000, key => key.replace(STRING_CAMELIZE_REGEXP_1, (match, separator, chr) => chr ? chr.toUpperCase() : '').replace(STRING_CAMELIZE_REGEXP_2, (match /*, separator, chr */) => match.toLowerCase())); +const CAMELIZE_CACHE = new Cache(1000, key => + key + .replace( + STRING_CAMELIZE_REGEXP_1, + (match, separator, chr) => (chr ? chr.toUpperCase() : '') + ) + .replace(STRING_CAMELIZE_REGEXP_2, (match /*, separator, chr */) => + match.toLowerCase() + ) +); -const STRING_CLASSIFY_REGEXP_1 = (/^(\-|_)+(.)?/); -const STRING_CLASSIFY_REGEXP_2 = (/(.)(\-|\_|\.|\s)+(.)?/g); -const STRING_CLASSIFY_REGEXP_3 = (/(^|\/|\.)([a-z])/g); +const STRING_CLASSIFY_REGEXP_1 = /^(\-|_)+(.)?/; +const STRING_CLASSIFY_REGEXP_2 = /(.)(\-|\_|\.|\s)+(.)?/g; +const STRING_CLASSIFY_REGEXP_3 = /(^|\/|\.)([a-z])/g; const CLASSIFY_CACHE = new Cache(1000, str => { - let replace1 = (match, separator, chr) => chr ? (`_${chr.toUpperCase()}`) : ''; - let replace2 = (match, initialChar, separator, chr) => initialChar + (chr ? chr.toUpperCase() : ''); + let replace1 = (match, separator, chr) => + chr ? `_${chr.toUpperCase()}` : ''; + let replace2 = (match, initialChar, separator, chr) => + initialChar + (chr ? chr.toUpperCase() : ''); let parts = str.split('/'); for (let i = 0; i < parts.length; i++) { parts[i] = parts[i] .replace(STRING_CLASSIFY_REGEXP_1, replace1) .replace(STRING_CLASSIFY_REGEXP_2, replace2); } - return parts.join('/') - .replace(STRING_CLASSIFY_REGEXP_3, (match /*, separator, chr */) => match.toUpperCase()); + return parts + .join('/') + .replace(STRING_CLASSIFY_REGEXP_3, (match /*, separator, chr */) => + match.toUpperCase() + ); }); -const STRING_UNDERSCORE_REGEXP_1 = (/([a-z\d])([A-Z]+)/g); -const STRING_UNDERSCORE_REGEXP_2 = (/\-|\s+/g); +const STRING_UNDERSCORE_REGEXP_1 = /([a-z\d])([A-Z]+)/g; +const STRING_UNDERSCORE_REGEXP_2 = /\-|\s+/g; -const UNDERSCORE_CACHE = new Cache(1000, str => str.replace(STRING_UNDERSCORE_REGEXP_1, '$1_$2'). - replace(STRING_UNDERSCORE_REGEXP_2, '_').toLowerCase()); +const UNDERSCORE_CACHE = new Cache(1000, str => + str + .replace(STRING_UNDERSCORE_REGEXP_1, '$1_$2') + .replace(STRING_UNDERSCORE_REGEXP_2, '_') + .toLowerCase() +); -const STRING_CAPITALIZE_REGEXP = (/(^|\/)([a-z\u00C0-\u024F])/g); +const STRING_CAPITALIZE_REGEXP = /(^|\/)([a-z\u00C0-\u024F])/g; -const CAPITALIZE_CACHE = new Cache(1000, str => str.replace(STRING_CAPITALIZE_REGEXP, (match /*, separator, chr */) => match.toUpperCase())); +const CAPITALIZE_CACHE = new Cache(1000, str => + str.replace(STRING_CAPITALIZE_REGEXP, (match /*, separator, chr */) => + match.toUpperCase() + ) +); -const STRING_DECAMELIZE_REGEXP = (/([a-z\d])([A-Z])/g); +const STRING_DECAMELIZE_REGEXP = /([a-z\d])([A-Z])/g; -const DECAMELIZE_CACHE = new Cache(1000, str => str.replace(STRING_DECAMELIZE_REGEXP, '$1_$2').toLowerCase()); +const DECAMELIZE_CACHE = new Cache(1000, str => + str.replace(STRING_DECAMELIZE_REGEXP, '$1_$2').toLowerCase() +); function _fmt(str, formats) { let cachedFormats = formats; @@ -62,9 +86,9 @@ function _fmt(str, formats) { // first, replace any ORDERED replacements. let idx = 0; // the current index for non-numerical replacements return str.replace(/%@([0-9]+)?/g, (s, argIndex) => { - argIndex = (argIndex) ? parseInt(argIndex, 10) - 1 : idx++; + argIndex = argIndex ? parseInt(argIndex, 10) - 1 : idx++; s = cachedFormats[argIndex]; - return (s === null) ? '(null)' : (s === undefined) ? '' : inspect(s); + return s === null ? '(null)' : s === undefined ? '' : inspect(s); }); } diff --git a/packages/ember-runtime/lib/utils.js b/packages/ember-runtime/lib/utils.js index 59682f3d087..2b0b0601894 100644 --- a/packages/ember-runtime/lib/utils.js +++ b/packages/ember-runtime/lib/utils.js @@ -5,14 +5,14 @@ import EmberObject from './system/object'; // TYPING & ARRAY MESSAGING // const TYPE_MAP = { - '[object Boolean]': 'boolean', - '[object Number]': 'number', - '[object String]': 'string', + '[object Boolean]': 'boolean', + '[object Number]': 'number', + '[object String]': 'string', '[object Function]': 'function', - '[object Array]': 'array', - '[object Date]': 'date', - '[object RegExp]': 'regexp', - '[object Object]': 'object', + '[object Array]': 'array', + '[object Date]': 'date', + '[object RegExp]': 'regexp', + '[object Object]': 'object', '[object FileList]': 'filelist' }; @@ -49,14 +49,24 @@ const { toString } = Object.prototype; @public */ export function isArray(obj) { - if (!obj || obj.setInterval) { return false; } - if (Array.isArray(obj)) { return true; } - if (EmberArray.detect(obj)) { return true; } + if (!obj || obj.setInterval) { + return false; + } + if (Array.isArray(obj)) { + return true; + } + if (EmberArray.detect(obj)) { + return true; + } let type = typeOf(obj); - if ('array' === type) { return true; } + if ('array' === type) { + return true; + } let length = obj.length; - if (typeof length === 'number' && length === length && 'object' === type) { return true; } + if (typeof length === 'number' && length === length && 'object' === type) { + return true; + } return false; } /** @@ -123,8 +133,12 @@ export function isArray(obj) { @static */ export function typeOf(item) { - if (item === null) { return 'null'; } - if (item === undefined) { return 'undefined'; } + if (item === null) { + return 'null'; + } + if (item === undefined) { + return 'undefined'; + } let ret = TYPE_MAP[toString.call(item)] || 'object'; if (ret === 'function') { diff --git a/packages/ember-runtime/tests/array/any-test.js b/packages/ember-runtime/tests/array/any-test.js index 47ec61ece70..12b27445f82 100644 --- a/packages/ember-runtime/tests/array/any-test.js +++ b/packages/ember-runtime/tests/array/any-test.js @@ -31,8 +31,16 @@ class AnyTests extends AbstractTestCase { return --cnt <= 0; }); this.assert.equal(result, true, 'return value of obj.any'); - this.assert.equal(found.length, exp, 'should invoke proper number of times'); - this.assert.deepEqual(found, ary.slice(0, -2), 'items passed during any() should match'); + this.assert.equal( + found.length, + exp, + 'should invoke proper number of times' + ); + this.assert.deepEqual( + found, + ary.slice(0, -2), + 'items passed during any() should match' + ); } '@test any should return true if any object matches the callback'() { @@ -43,7 +51,9 @@ class AnyTests extends AbstractTestCase { this.assert.equal(result, true, 'return value of obj.any'); } - '@test any should produce correct results even if the matching element is undefined'(assert) { + '@test any should produce correct results even if the matching element is undefined'( + assert + ) { let obj = emberA([undefined]); let result; @@ -52,4 +62,4 @@ class AnyTests extends AbstractTestCase { } } -runArrayTests('any', AnyTests); \ No newline at end of file +runArrayTests('any', AnyTests); diff --git a/packages/ember-runtime/tests/array/compact-test.js b/packages/ember-runtime/tests/array/compact-test.js index ac7f5f43812..eabf464d860 100644 --- a/packages/ember-runtime/tests/array/compact-test.js +++ b/packages/ember-runtime/tests/array/compact-test.js @@ -9,4 +9,4 @@ class CompactTests extends AbstractTestCase { } } -runArrayTests('compact', CompactTests); \ No newline at end of file +runArrayTests('compact', CompactTests); diff --git a/packages/ember-runtime/tests/array/every-test.js b/packages/ember-runtime/tests/array/every-test.js index 5690d07b7ab..faeb26e766a 100644 --- a/packages/ember-runtime/tests/array/every-test.js +++ b/packages/ember-runtime/tests/array/every-test.js @@ -14,7 +14,11 @@ class EveryTest extends AbstractTestCase { return true; }); this.assert.equal(result, true, 'return value of obj.every'); - this.assert.deepEqual(found, ary, 'items passed during every() should match'); + this.assert.deepEqual( + found, + ary, + 'items passed during every() should match' + ); } '@test every should stop invoking when you return false'() { @@ -30,8 +34,16 @@ class EveryTest extends AbstractTestCase { return --cnt > 0; }); this.assert.equal(result, false, 'return value of obj.every'); - this.assert.equal(found.length, exp, 'should invoke proper number of times'); - this.assert.deepEqual(found, ary.slice(0, -2), 'items passed during every() should match'); + this.assert.equal( + found.length, + exp, + 'should invoke proper number of times' + ); + this.assert.deepEqual( + found, + ary.slice(0, -2), + 'items passed during every() should match' + ); } } @@ -63,8 +75,8 @@ class IsEveryTest extends AbstractTestCase { EmberObject.create({ foo: null, bar: null }) ]); - this.assert.equal(obj.isEvery('foo', null), true, 'isEvery(\'foo\', null)'); - this.assert.equal(obj.isEvery('bar', null), false, 'isEvery(\'bar\', null)'); + this.assert.equal(obj.isEvery('foo', null), true, "isEvery('foo', null)"); + this.assert.equal(obj.isEvery('bar', null), false, "isEvery('bar', null)"); } '@test should return true if every property is undefined'() { @@ -73,10 +85,18 @@ class IsEveryTest extends AbstractTestCase { EmberObject.create({ bar: undefined }) ]); - this.assert.equal(obj.isEvery('foo', undefined), true, 'isEvery(\'foo\', undefined)'); - this.assert.equal(obj.isEvery('bar', undefined), false, 'isEvery(\'bar\', undefined)'); + this.assert.equal( + obj.isEvery('foo', undefined), + true, + "isEvery('foo', undefined)" + ); + this.assert.equal( + obj.isEvery('bar', undefined), + false, + "isEvery('bar', undefined)" + ); } } runArrayTests('every', EveryTest); -runArrayTests('isEvery', IsEveryTest); \ No newline at end of file +runArrayTests('isEvery', IsEveryTest); diff --git a/packages/ember-runtime/tests/array/filter-test.js b/packages/ember-runtime/tests/array/filter-test.js index eb01da6072d..aeeb717272c 100644 --- a/packages/ember-runtime/tests/array/filter-test.js +++ b/packages/ember-runtime/tests/array/filter-test.js @@ -16,7 +16,11 @@ class FilterTest extends AbstractTestCase { return --cnt >= 0; }); this.assert.deepEqual(found, ary, 'should have invoked on each item'); - this.assert.deepEqual(result, ary.slice(0, -2), 'filtered array should exclude items'); + this.assert.deepEqual( + result, + ary.slice(0, -2), + 'filtered array should exclude items' + ); } } @@ -32,7 +36,11 @@ class FilterByTest extends AbstractTestCase { obj = this.newObject(ary); this.assert.deepEqual(obj.filterBy('foo', 'foo'), ary, 'filterBy(foo)'); - this.assert.deepEqual(obj.filterBy('bar', 'bar'), [ary[1]], 'filterBy(bar)'); + this.assert.deepEqual( + obj.filterBy('bar', 'bar'), + [ary[1]], + 'filterBy(bar)' + ); } '@test should include in result if property is true'() { @@ -62,7 +70,11 @@ class FilterByTest extends AbstractTestCase { obj = this.newObject(ary); - this.assert.deepEqual(obj.filterBy('foo', 3), [ary[0], ary[3]], 'filterBy(\'foo\', 3)\')'); + this.assert.deepEqual( + obj.filterBy('foo', 3), + [ary[0], ary[3]], + "filterBy('foo', 3)')" + ); } '@test should correctly filter null second argument'() { @@ -77,7 +89,11 @@ class FilterByTest extends AbstractTestCase { obj = this.newObject(ary); - this.assert.deepEqual(obj.filterBy('foo', null), [ary[1], ary[2]], 'filterBy(\'foo\', 3)\')'); + this.assert.deepEqual( + obj.filterBy('foo', null), + [ary[1], ary[2]], + "filterBy('foo', 3)')" + ); } '@test should not return all objects on undefined second argument'() { @@ -90,7 +106,11 @@ class FilterByTest extends AbstractTestCase { obj = this.newObject(ary); - this.assert.deepEqual(obj.filterBy('foo', undefined), [], 'filterBy(\'foo\', 3)\')'); + this.assert.deepEqual( + obj.filterBy('foo', undefined), + [], + "filterBy('foo', 3)')" + ); } '@test should correctly filter explicit undefined second argument'() { @@ -107,7 +127,11 @@ class FilterByTest extends AbstractTestCase { obj = this.newObject(ary); - this.assert.deepEqual(obj.filterBy('foo', undefined), ary.slice(2), 'filterBy(\'foo\', 3)\')'); + this.assert.deepEqual( + obj.filterBy('foo', undefined), + ary.slice(2), + "filterBy('foo', 3)')" + ); } '@test should not match undefined properties without second argument'() { @@ -124,9 +148,13 @@ class FilterByTest extends AbstractTestCase { obj = this.newObject(ary); - this.assert.deepEqual(obj.filterBy('foo'), ary.slice(0, 2), 'filterBy(\'foo\', 3)\')'); + this.assert.deepEqual( + obj.filterBy('foo'), + ary.slice(0, 2), + "filterBy('foo', 3)')" + ); } } runArrayTests('filter', FilterTest); -runArrayTests('filter', FilterByTest); \ No newline at end of file +runArrayTests('filter', FilterByTest); diff --git a/packages/ember-runtime/tests/array/find-test.js b/packages/ember-runtime/tests/array/find-test.js index d334c31f941..e9bd57bf6b1 100644 --- a/packages/ember-runtime/tests/array/find-test.js +++ b/packages/ember-runtime/tests/array/find-test.js @@ -14,7 +14,11 @@ class FindTests extends AbstractTestCase { return false; }); this.assert.equal(result, undefined, 'return value of obj.find'); - this.assert.deepEqual(found, ary, 'items passed during find() should match'); + this.assert.deepEqual( + found, + ary, + 'items passed during find() should match' + ); } '@test every should stop invoking when you return true'() { @@ -30,8 +34,16 @@ class FindTests extends AbstractTestCase { return --cnt >= 0; }); this.assert.equal(result, ary[exp - 1], 'return value of obj.find'); - this.assert.equal(found.length, exp, 'should invoke proper number of times'); - this.assert.deepEqual(found, ary.slice(0, -2), 'items passed during find() should match'); + this.assert.equal( + found.length, + exp, + 'should invoke proper number of times' + ); + this.assert.deepEqual( + found, + ary.slice(0, -2), + 'items passed during find() should match' + ); } } @@ -75,24 +87,29 @@ class FindByTests extends AbstractTestCase { obj = this.newObject(ary); - this.assert.equal(obj.findBy('foo', null), ary[0], 'findBy(\'foo\', null)'); - this.assert.equal(obj.findBy('bar', null), ary[1], 'findBy(\'bar\', null)'); + this.assert.equal(obj.findBy('foo', null), ary[0], "findBy('foo', null)"); + this.assert.equal(obj.findBy('bar', null), ary[1], "findBy('bar', null)"); } '@test should return first undefined property match'() { let ary, obj; - ary = [ - { foo: undefined, bar: 'BAZ' }, - EmberObject.create({ }) - ]; + ary = [{ foo: undefined, bar: 'BAZ' }, EmberObject.create({})]; obj = this.newObject(ary); - this.assert.equal(obj.findBy('foo', undefined), ary[0], 'findBy(\'foo\', undefined)'); - this.assert.equal(obj.findBy('bar', undefined), ary[1], 'findBy(\'bar\', undefined)'); + this.assert.equal( + obj.findBy('foo', undefined), + ary[0], + "findBy('foo', undefined)" + ); + this.assert.equal( + obj.findBy('bar', undefined), + ary[1], + "findBy('bar', undefined)" + ); } } runArrayTests('find', FindTests); -runArrayTests('findBy', FindByTests); \ No newline at end of file +runArrayTests('findBy', FindByTests); diff --git a/packages/ember-runtime/tests/array/firstObject-test.js b/packages/ember-runtime/tests/array/firstObject-test.js index 2b68a72e624..9af692608c9 100644 --- a/packages/ember-runtime/tests/array/firstObject-test.js +++ b/packages/ember-runtime/tests/array/firstObject-test.js @@ -24,4 +24,4 @@ class FirstObjectTests extends AbstractTestCase { } } -runArrayTests('firstObject', FirstObjectTests); \ No newline at end of file +runArrayTests('firstObject', FirstObjectTests); diff --git a/packages/ember-runtime/tests/array/forEach-test.js b/packages/ember-runtime/tests/array/forEach-test.js index 8497eedc7cf..45dc3484de8 100644 --- a/packages/ember-runtime/tests/array/forEach-test.js +++ b/packages/ember-runtime/tests/array/forEach-test.js @@ -10,10 +10,13 @@ class ForEachTests extends AbstractTestCase { let found = []; obj.forEach(i => found.push(i)); - this.assert.deepEqual(found, ary, 'items passed during forEach should match'); + this.assert.deepEqual( + found, + ary, + 'items passed during forEach should match' + ); } - '@test forEach should iterate over list after mutation'() { if (get(this, 'canTestMutation')) { this.assert.expect(0); @@ -25,14 +28,22 @@ class ForEachTests extends AbstractTestCase { let found = []; obj.forEach(i => found.push(i)); - this.assert.deepEqual(found, ary, 'items passed during forEach should match'); + this.assert.deepEqual( + found, + ary, + 'items passed during forEach should match' + ); this.mutate(obj); ary = this.toArray(obj); found = []; obj.forEach(i => found.push(i)); - this.assert.deepEqual(found, ary, 'items passed during forEach should match'); + this.assert.deepEqual( + found, + ary, + 'items passed during forEach should match' + ); } '@test 2nd target parameter'() { @@ -48,11 +59,14 @@ class ForEachTests extends AbstractTestCase { }); obj.forEach(() => { - this.assert.equal(guidFor(this), guidFor(target), 'should pass target as this if context'); + this.assert.equal( + guidFor(this), + guidFor(target), + 'should pass target as this if context' + ); }, target); } - '@test callback params'() { let obj = this.newObject(); let ary = this.toArray(obj); diff --git a/packages/ember-runtime/tests/array/includes-test.js b/packages/ember-runtime/tests/array/includes-test.js index 33710994619..a2c411f56c7 100644 --- a/packages/ember-runtime/tests/array/includes-test.js +++ b/packages/ember-runtime/tests/array/includes-test.js @@ -4,34 +4,66 @@ import { runArrayTests, newFixture } from '../helpers/array'; class IncludesTests extends AbstractTestCase { '@test includes returns correct value if startAt is positive'() { let data = newFixture(3); - let obj = this.newObject(data); + let obj = this.newObject(data); - this.assert.equal(obj.includes(data[1], 1), true, 'should return true if included'); - this.assert.equal(obj.includes(data[0], 1), false, 'should return false if not included'); + this.assert.equal( + obj.includes(data[1], 1), + true, + 'should return true if included' + ); + this.assert.equal( + obj.includes(data[0], 1), + false, + 'should return false if not included' + ); } '@test includes returns correct value if startAt is negative'() { let data = newFixture(3); - let obj = this.newObject(data); + let obj = this.newObject(data); - this.assert.equal(obj.includes(data[1], -2), true, 'should return true if included'); - this.assert.equal(obj.includes(data[0], -2), false, 'should return false if not included'); + this.assert.equal( + obj.includes(data[1], -2), + true, + 'should return true if included' + ); + this.assert.equal( + obj.includes(data[0], -2), + false, + 'should return false if not included' + ); } '@test includes returns true if startAt + length is still negative'() { let data = newFixture(1); - let obj = this.newObject(data); + let obj = this.newObject(data); - this.assert.equal(obj.includes(data[0], -2), true, 'should return true if included'); - this.assert.equal(obj.includes(newFixture(1), -2), false, 'should return false if not included'); + this.assert.equal( + obj.includes(data[0], -2), + true, + 'should return true if included' + ); + this.assert.equal( + obj.includes(newFixture(1), -2), + false, + 'should return false if not included' + ); } '@test includes returns false if startAt out of bounds'() { let data = newFixture(1); - let obj = this.newObject(data); + let obj = this.newObject(data); - this.assert.equal(obj.includes(data[0], 2), false, 'should return false if startAt >= length'); - this.assert.equal(obj.includes(newFixture(1), 2), false, 'should return false if startAt >= length'); + this.assert.equal( + obj.includes(data[0], 2), + false, + 'should return false if startAt >= length' + ); + this.assert.equal( + obj.includes(newFixture(1), 2), + false, + 'should return false if startAt >= length' + ); } } diff --git a/packages/ember-runtime/tests/array/indexOf-test.js b/packages/ember-runtime/tests/array/indexOf-test.js index c3cfa06f270..aa03ed0f118 100644 --- a/packages/ember-runtime/tests/array/indexOf-test.js +++ b/packages/ember-runtime/tests/array/indexOf-test.js @@ -4,11 +4,15 @@ import { runArrayTests, newFixture } from '../helpers/array'; class IndexOfTests extends AbstractTestCase { '@test should return index of object'() { let expected = newFixture(3); - let obj = this.newObject(expected); - let len = 3; + let obj = this.newObject(expected); + let len = 3; for (let idx = 0; idx < len; idx++) { - this.assert.equal(obj.indexOf(expected[idx]), idx, `obj.indexOf(${expected[idx]}) should match idx`); + this.assert.equal( + obj.indexOf(expected[idx]), + idx, + `obj.indexOf(${expected[idx]}) should match idx` + ); } } diff --git a/packages/ember-runtime/tests/array/isAny-test.js b/packages/ember-runtime/tests/array/isAny-test.js index 5d5ad85a905..3ef9b64d072 100644 --- a/packages/ember-runtime/tests/array/isAny-test.js +++ b/packages/ember-runtime/tests/array/isAny-test.js @@ -32,8 +32,8 @@ class IsAnyTests extends AbstractTestCase { EmberObject.create({ foo: 'foo', bar: null }) ]); - this.assert.equal(obj.isAny('foo', null), true, 'isAny(\'foo\', null)'); - this.assert.equal(obj.isAny('bar', null), true, 'isAny(\'bar\', null)'); + this.assert.equal(obj.isAny('foo', null), true, "isAny('foo', null)"); + this.assert.equal(obj.isAny('bar', null), true, "isAny('bar', null)"); } '@test should return true if any property is undefined'() { @@ -42,17 +42,22 @@ class IsAnyTests extends AbstractTestCase { EmberObject.create({ foo: 'foo' }) ]); - this.assert.equal(obj.isAny('foo', undefined), true, 'isAny(\'foo\', undefined)'); - this.assert.equal(obj.isAny('bar', undefined), true, 'isAny(\'bar\', undefined)'); + this.assert.equal( + obj.isAny('foo', undefined), + true, + "isAny('foo', undefined)" + ); + this.assert.equal( + obj.isAny('bar', undefined), + true, + "isAny('bar', undefined)" + ); } '@test should not match undefined properties without second argument'() { - let obj = this.newObject([ - { foo: undefined }, - EmberObject.create({ }) - ]); + let obj = this.newObject([{ foo: undefined }, EmberObject.create({})]); - this.assert.equal(obj.isAny('foo'), false, 'isAny(\'foo\', undefined)'); + this.assert.equal(obj.isAny('foo'), false, "isAny('foo', undefined)"); } } diff --git a/packages/ember-runtime/tests/array/lastIndexOf-test.js b/packages/ember-runtime/tests/array/lastIndexOf-test.js index a4769507d44..9ce1fa704dd 100644 --- a/packages/ember-runtime/tests/array/lastIndexOf-test.js +++ b/packages/ember-runtime/tests/array/lastIndexOf-test.js @@ -3,33 +3,45 @@ import { AbstractTestCase } from 'internal-test-helpers'; import { runArrayTests, newFixture } from '../helpers/array'; class LastIndexOfTests extends AbstractTestCase { - '@test should return index of object\'s last occurrence'() { + "@test should return index of object's last occurrence"() { let expected = newFixture(3); - let obj = this.newObject(expected); - let len = 3; + let obj = this.newObject(expected); + let len = 3; for (let idx = 0; idx < len; idx++) { - this.assert.equal(obj.lastIndexOf(expected[idx]), idx, `obj.lastIndexOf(${expected[idx]}) should match idx`); + this.assert.equal( + obj.lastIndexOf(expected[idx]), + idx, + `obj.lastIndexOf(${expected[idx]}) should match idx` + ); } } - '@test should return index of object\'s last occurrence even startAt search location is equal to length'() { + "@test should return index of object's last occurrence even startAt search location is equal to length"() { let expected = newFixture(3); - let obj = this.newObject(expected); - let len = 3; + let obj = this.newObject(expected); + let len = 3; for (let idx = 0; idx < len; idx++) { - this.assert.equal(obj.lastIndexOf(expected[idx], len), idx, `obj.lastIndexOfs(${expected[idx]}) should match idx`); + this.assert.equal( + obj.lastIndexOf(expected[idx], len), + idx, + `obj.lastIndexOfs(${expected[idx]}) should match idx` + ); } } - '@test should return index of object\'s last occurrence even startAt search location is greater than length'() { + "@test should return index of object's last occurrence even startAt search location is greater than length"() { let expected = newFixture(3); - let obj = this.newObject(expected); - let len = 3; + let obj = this.newObject(expected); + let len = 3; for (let idx = 0; idx < len; idx++) { - this.assert.equal(obj.lastIndexOf(expected[idx], len + 1), idx, `obj.lastIndexOf(${expected[idx]}) should match idx`); + this.assert.equal( + obj.lastIndexOf(expected[idx], len + 1), + idx, + `obj.lastIndexOf(${expected[idx]}) should match idx` + ); } } @@ -37,22 +49,34 @@ class LastIndexOfTests extends AbstractTestCase { let obj = this.newObject(newFixture(3)); let foo = {}; - this.assert.equal(obj.lastIndexOf(foo), -1, 'obj.lastIndexOf(foo) should be -1'); + this.assert.equal( + obj.lastIndexOf(foo), + -1, + 'obj.lastIndexOf(foo) should be -1' + ); } '@test should return -1 when no match is found even startAt search location is equal to length'() { let obj = this.newObject(newFixture(3)); let foo = {}; - this.assert.equal(obj.lastIndexOf(foo, get(obj, 'length')), -1, 'obj.lastIndexOf(foo) should be -1'); + this.assert.equal( + obj.lastIndexOf(foo, get(obj, 'length')), + -1, + 'obj.lastIndexOf(foo) should be -1' + ); } '@test should return -1 when no match is found even startAt search location is greater than length'() { let obj = this.newObject(newFixture(3)); let foo = {}; - this.assert.equal(obj.lastIndexOf(foo, get(obj, 'length') + 1), -1, 'obj.lastIndexOf(foo) should be -1'); + this.assert.equal( + obj.lastIndexOf(foo, get(obj, 'length') + 1), + -1, + 'obj.lastIndexOf(foo) should be -1' + ); } } -runArrayTests('lastIndexOf', LastIndexOfTests); \ No newline at end of file +runArrayTests('lastIndexOf', LastIndexOfTests); diff --git a/packages/ember-runtime/tests/array/map-test.js b/packages/ember-runtime/tests/array/map-test.js index 3f8e1bba80f..1977be43b0e 100644 --- a/packages/ember-runtime/tests/array/map-test.js +++ b/packages/ember-runtime/tests/array/map-test.js @@ -3,7 +3,7 @@ import { AbstractTestCase } from 'internal-test-helpers'; import { runArrayTests } from '../helpers/array'; import { get } from 'ember-metal'; -const mapFunc = item => item ? item.toString() : null; +const mapFunc = item => (item ? item.toString() : null); class MapTests extends AbstractTestCase { '@test map should iterate over list'() { @@ -26,19 +26,26 @@ class MapTests extends AbstractTestCase { let found; found = obj.map(mapFunc); - this.assert.deepEqual(found, ary, 'items passed during forEach should match'); + this.assert.deepEqual( + found, + ary, + 'items passed during forEach should match' + ); this.mutate(obj); ary = this.toArray(obj).map(mapFunc); found = obj.map(mapFunc); - this.assert.deepEqual(found, ary, 'items passed during forEach should match'); + this.assert.deepEqual( + found, + ary, + 'items passed during forEach should match' + ); } '@test 2nd target parameter'() { let obj = this.newObject(); let target = this; - obj.map(() => { // ES6TODO: When transpiled we will end up with "use strict" which disables automatically binding to the global context. // Therefore, the following test can never pass in strict mode unless we modify the `map` function implementation to @@ -48,11 +55,14 @@ class MapTests extends AbstractTestCase { }); obj.map(() => { - this.assert.equal(guidFor(this), guidFor(target), 'should pass target as this if context'); + this.assert.equal( + guidFor(this), + guidFor(target), + 'should pass target as this if context' + ); }, target); } - '@test callback params'() { let obj = this.newObject(); let ary = this.toArray(obj); diff --git a/packages/ember-runtime/tests/array/objectAt-test.js b/packages/ember-runtime/tests/array/objectAt-test.js index cff2262b2bb..18e09d81659 100644 --- a/packages/ember-runtime/tests/array/objectAt-test.js +++ b/packages/ember-runtime/tests/array/objectAt-test.js @@ -4,11 +4,15 @@ import { runArrayTests, newFixture } from '../helpers/array'; class ObjectAtTests extends AbstractTestCase { '@test should return object at specified index'() { let expected = newFixture(3); - let obj = this.newObject(expected); - let len = expected.length; + let obj = this.newObject(expected); + let len = expected.length; for (let idx = 0; idx < len; idx++) { - this.assert.equal(obj.objectAt(idx), expected[idx], `obj.objectAt(${idx}) should match`); + this.assert.equal( + obj.objectAt(idx), + expected[idx], + `obj.objectAt(${idx}) should match` + ); } } @@ -16,10 +20,18 @@ class ObjectAtTests extends AbstractTestCase { let obj; obj = this.newObject(newFixture(3)); - this.assert.equal(obj.objectAt(obj, 5), undefined, 'should return undefined for obj.objectAt(5) when len = 3'); + this.assert.equal( + obj.objectAt(obj, 5), + undefined, + 'should return undefined for obj.objectAt(5) when len = 3' + ); obj = this.newObject([]); - this.assert.equal(obj.objectAt(obj, 0), undefined, 'should return undefined for obj.objectAt(0) when len = 0'); + this.assert.equal( + obj.objectAt(obj, 0), + undefined, + 'should return undefined for obj.objectAt(0) when len = 0' + ); } } diff --git a/packages/ember-runtime/tests/array/reduce-test.js b/packages/ember-runtime/tests/array/reduce-test.js index cf549f7ce08..05b9d842ebf 100644 --- a/packages/ember-runtime/tests/array/reduce-test.js +++ b/packages/ember-runtime/tests/array/reduce-test.js @@ -10,13 +10,19 @@ class ReduceTests extends AbstractTestCase { '@test passes index of item to callback'() { let obj = this.newObject([1, 2, 3]); - let res = obj.reduce((previousValue, item, index) => previousValue + index, 0); + let res = obj.reduce( + (previousValue, item, index) => previousValue + index, + 0 + ); this.assert.equal(res, 3); } '@test passes enumerable object to callback'() { let obj = this.newObject([1, 2, 3]); - let res = obj.reduce((previousValue, item, index, enumerable) => enumerable, 0); + let res = obj.reduce( + (previousValue, item, index, enumerable) => enumerable, + 0 + ); this.assert.equal(res, obj); } } diff --git a/packages/ember-runtime/tests/array/reject-test.js b/packages/ember-runtime/tests/array/reject-test.js index d261938a65b..a88784f68ff 100644 --- a/packages/ember-runtime/tests/array/reject-test.js +++ b/packages/ember-runtime/tests/array/reject-test.js @@ -36,7 +36,11 @@ class RejectByTest extends AbstractTestCase { obj = this.newObject(ary); this.assert.deepEqual(obj.rejectBy('foo', 'foo'), [], 'rejectBy(foo)'); - this.assert.deepEqual(obj.rejectBy('bar', 'bar'), [ary[0]], 'rejectBy(bar)'); + this.assert.deepEqual( + obj.rejectBy('bar', 'bar'), + [ary[0]], + 'rejectBy(bar)' + ); } '@test should include in result if property is false'() { @@ -65,7 +69,11 @@ class RejectByTest extends AbstractTestCase { obj = this.newObject(ary); - this.assert.deepEqual(obj.rejectBy('foo', 3), [ary[1], ary[2]], 'rejectBy(\'foo\', 3)\')'); + this.assert.deepEqual( + obj.rejectBy('foo', 3), + [ary[1], ary[2]], + "rejectBy('foo', 3)')" + ); } '@test should correctly reject null second argument'() { @@ -80,7 +88,11 @@ class RejectByTest extends AbstractTestCase { obj = this.newObject(ary); - this.assert.deepEqual(obj.rejectBy('foo', null), [ary[0], ary[3]], 'rejectBy(\'foo\', null)\')'); + this.assert.deepEqual( + obj.rejectBy('foo', null), + [ary[0], ary[3]], + "rejectBy('foo', null)')" + ); } '@test should correctly reject undefined second argument'() { @@ -93,7 +105,11 @@ class RejectByTest extends AbstractTestCase { obj = this.newObject(ary); - this.assert.deepEqual(obj.rejectBy('bar', undefined), [], 'rejectBy(\'bar\', undefined)\')'); + this.assert.deepEqual( + obj.rejectBy('bar', undefined), + [], + "rejectBy('bar', undefined)')" + ); } '@test should correctly reject explicit undefined second argument'() { @@ -110,7 +126,11 @@ class RejectByTest extends AbstractTestCase { obj = this.newObject(ary); - this.assert.deepEqual(obj.rejectBy('foo', undefined), ary.slice(0, 2), 'rejectBy(\'foo\', undefined)\')'); + this.assert.deepEqual( + obj.rejectBy('foo', undefined), + ary.slice(0, 2), + "rejectBy('foo', undefined)')" + ); } '@test should match undefined, null, or false properties without second argument'() { @@ -131,9 +151,13 @@ class RejectByTest extends AbstractTestCase { obj = this.newObject(ary); - this.assert.deepEqual(obj.rejectBy('foo'), ary.slice(2), 'rejectBy(\'foo\')\')'); + this.assert.deepEqual( + obj.rejectBy('foo'), + ary.slice(2), + "rejectBy('foo')')" + ); } } runArrayTests('reject', RejectTest); -runArrayTests('rejectBy', RejectByTest); \ No newline at end of file +runArrayTests('rejectBy', RejectByTest); diff --git a/packages/ember-runtime/tests/array/uniq-test.js b/packages/ember-runtime/tests/array/uniq-test.js index aff9f1b61d8..f064ed8732e 100644 --- a/packages/ember-runtime/tests/array/uniq-test.js +++ b/packages/ember-runtime/tests/array/uniq-test.js @@ -5,14 +5,18 @@ class UniqTests extends AbstractTestCase { '@test should return new instance with duplicates removed'() { let before, after, obj, ret; - after = newFixture(3); + after = newFixture(3); before = [after[0], after[1], after[2], after[1], after[0]]; - obj = this.newObject(before); + obj = this.newObject(before); before = obj.toArray(); // in case of set before will be different... ret = obj.uniq(); this.assert.deepEqual(this.toArray(ret), after, 'should have removed item'); - this.assert.deepEqual(this.toArray(obj), before, 'should not have changed original'); + this.assert.deepEqual( + this.toArray(obj), + before, + 'should not have changed original' + ); } '@test should return duplicate of same content if no duplicates found'() { @@ -20,8 +24,12 @@ class UniqTests extends AbstractTestCase { obj = this.newObject(newFixture(3)); ret = obj.uniq(item); this.assert.ok(ret !== obj, 'should not be same object'); - this.assert.deepEqual(this.toArray(ret), this.toArray(obj), 'should be the same content'); + this.assert.deepEqual( + this.toArray(ret), + this.toArray(obj), + 'should be the same content' + ); } } -runArrayTests('uniq', UniqTests); \ No newline at end of file +runArrayTests('uniq', UniqTests); diff --git a/packages/ember-runtime/tests/array/uniqBy-test.js b/packages/ember-runtime/tests/array/uniqBy-test.js index 7d88bb0f2eb..f04613a591c 100644 --- a/packages/ember-runtime/tests/array/uniqBy-test.js +++ b/packages/ember-runtime/tests/array/uniqBy-test.js @@ -15,4 +15,4 @@ class UniqByTests extends AbstractTestCase { } } -runArrayTests('uniqBy', UniqByTests); \ No newline at end of file +runArrayTests('uniqBy', UniqByTests); diff --git a/packages/ember-runtime/tests/array/without-test.js b/packages/ember-runtime/tests/array/without-test.js index c52b9b9c235..bfbdc78b326 100644 --- a/packages/ember-runtime/tests/array/without-test.js +++ b/packages/ember-runtime/tests/array/without-test.js @@ -6,20 +6,24 @@ class WithoutTests extends AbstractTestCase { let before, after, obj, ret; before = newFixture(3); - after = [before[0], before[2]]; - obj = this.newObject(before); + after = [before[0], before[2]]; + obj = this.newObject(before); ret = obj.without(before[1]); this.assert.deepEqual(this.toArray(ret), after, 'should have removed item'); - this.assert.deepEqual(this.toArray(obj), before, 'should not have changed original'); + this.assert.deepEqual( + this.toArray(obj), + before, + 'should not have changed original' + ); } '@test should remove NaN value'() { let before, after, obj, ret; before = [...newFixture(2), NaN]; - after = [before[0], before[1]]; - obj = this.newObject(before); + after = [before[0], before[1]]; + obj = this.newObject(before); ret = obj.without(NaN); this.assert.deepEqual(this.toArray(ret), after, 'should have removed item'); @@ -28,13 +32,12 @@ class WithoutTests extends AbstractTestCase { '@test should return same instance if object not found'() { let item, obj, ret; - item = newFixture(1)[0]; - obj = this.newObject(newFixture(3)); + item = newFixture(1)[0]; + obj = this.newObject(newFixture(3)); ret = obj.without(item); this.assert.equal(ret, obj, 'should be same instance'); } - } runArrayTests('without', WithoutTests); diff --git a/packages/ember-runtime/tests/computed/computed_macros_test.js b/packages/ember-runtime/tests/computed/computed_macros_test.js index 9f61fff4258..f7ad3947648 100644 --- a/packages/ember-runtime/tests/computed/computed_macros_test.js +++ b/packages/ember-runtime/tests/computed/computed_macros_test.js @@ -1,8 +1,4 @@ -import { - computed, - alias, - defineProperty, -} from 'ember-metal'; +import { computed, alias, defineProperty } from 'ember-metal'; import { empty, notEmpty, @@ -18,7 +14,7 @@ import { readOnly, deprecatingAlias, and, - or, + or } from '../../computed/computed_macros'; import { testBoth } from 'internal-test-helpers'; @@ -27,7 +23,7 @@ import { A as emberA } from '../../mixins/array'; QUnit.module('CP macros'); -testBoth('Ember.computed.empty', function (get, set, assert) { +testBoth('Ember.computed.empty', function(get, set, assert) { let obj = EmberObject.extend({ bestLannister: null, lannisters: null, @@ -38,14 +34,30 @@ testBoth('Ember.computed.empty', function (get, set, assert) { lannisters: emberA() }); - assert.equal(get(obj, 'bestLannisterUnspecified'), true, 'bestLannister initially empty'); - assert.equal(get(obj, 'noLannistersKnown'), true, 'lannisters initially empty'); + assert.equal( + get(obj, 'bestLannisterUnspecified'), + true, + 'bestLannister initially empty' + ); + assert.equal( + get(obj, 'noLannistersKnown'), + true, + 'lannisters initially empty' + ); get(obj, 'lannisters').pushObject('Tyrion'); set(obj, 'bestLannister', 'Tyrion'); - assert.equal(get(obj, 'bestLannisterUnspecified'), false, 'empty respects strings'); - assert.equal(get(obj, 'noLannistersKnown'), false, 'empty respects array mutations'); + assert.equal( + get(obj, 'bestLannisterUnspecified'), + false, + 'empty respects strings' + ); + assert.equal( + get(obj, 'noLannistersKnown'), + false, + 'empty respects array mutations' + ); }); testBoth('Ember.computed.notEmpty', function(get, set, assert) { @@ -59,14 +71,30 @@ testBoth('Ember.computed.notEmpty', function(get, set, assert) { lannisters: emberA() }); - assert.equal(get(obj, 'bestLannisterSpecified'), false, 'bestLannister initially empty'); - assert.equal(get(obj, 'LannistersKnown'), false, 'lannisters initially empty'); + assert.equal( + get(obj, 'bestLannisterSpecified'), + false, + 'bestLannister initially empty' + ); + assert.equal( + get(obj, 'LannistersKnown'), + false, + 'lannisters initially empty' + ); get(obj, 'lannisters').pushObject('Tyrion'); set(obj, 'bestLannister', 'Tyrion'); - assert.equal(get(obj, 'bestLannisterSpecified'), true, 'empty respects strings'); - assert.equal(get(obj, 'LannistersKnown'), true, 'empty respects array mutations'); + assert.equal( + get(obj, 'bestLannisterSpecified'), + true, + 'empty respects strings' + ); + assert.equal( + get(obj, 'LannistersKnown'), + true, + 'empty respects array mutations' + ); }); testBoth('computed.not', function(get, set, assert) { @@ -110,9 +138,13 @@ testBoth('computed.bool', function(get, set, assert) { testBoth('computed.alias', function(get, set, assert) { let obj = { bar: 'asdf', baz: null, quz: false }; - defineProperty(obj, 'bay', computed(function() { - return 'apple'; - })); + defineProperty( + obj, + 'bay', + computed(function() { + return 'apple'; + }) + ); defineProperty(obj, 'barAlias', alias('bar')); defineProperty(obj, 'bazAlias', alias('baz')); @@ -141,10 +173,18 @@ testBoth('computed.alias set', function(get, set, assert) { let obj = {}; let constantValue = 'always `a`'; - defineProperty(obj, 'original', computed({ - get: function() { return constantValue; }, - set: function() { return constantValue; } - })); + defineProperty( + obj, + 'original', + computed({ + get: function() { + return constantValue; + }, + set: function() { + return constantValue; + } + }) + ); defineProperty(obj, 'aliased', alias('original')); assert.equal(get(obj, 'original'), constantValue); @@ -351,7 +391,11 @@ testBoth('computed.or three properties', function(get, set, assert) { set(obj, 'three', null); - assert.equal(get(obj, 'oneTwoThree'), null, 'returns last falsy value as in ||'); + assert.equal( + get(obj, 'oneTwoThree'), + null, + 'returns last falsy value as in ||' + ); set(obj, 'two', true); @@ -382,7 +426,11 @@ testBoth('computed.or expand properties', function(get, set, assert) { set(obj, 'three', null); - assert.equal(get(obj, 'oneTwoThree'), null, 'returns last falsy value as in ||'); + assert.equal( + get(obj, 'oneTwoThree'), + null, + 'returns last falsy value as in ||' + ); set(obj, 'two', true); @@ -393,16 +441,19 @@ testBoth('computed.or expand properties', function(get, set, assert) { assert.equal(get(obj, 'oneTwoThree'), 1, 'returns truthy value as in ||'); }); -testBoth('computed.or and computed.and warn about dependent keys with spaces', function() { - let obj = { one: true, two: true }; - expectAssertion(function() { - defineProperty(obj, 'oneOrTwo', or('one', 'two three')); - }, /Dependent keys passed to computed\.or\(\) can't have spaces\./); +testBoth( + 'computed.or and computed.and warn about dependent keys with spaces', + function() { + let obj = { one: true, two: true }; + expectAssertion(function() { + defineProperty(obj, 'oneOrTwo', or('one', 'two three')); + }, /Dependent keys passed to computed\.or\(\) can't have spaces\./); - expectAssertion(function() { - defineProperty(obj, 'oneAndTwo', and('one', 'two three')); - }, /Dependent keys passed to computed\.and\(\) can't have spaces\./); -}); + expectAssertion(function() { + defineProperty(obj, 'oneAndTwo', and('one', 'two three')); + }, /Dependent keys passed to computed\.and\(\) can't have spaces\./); + } +); testBoth('computed.oneWay', function(get, set, assert) { let obj = { @@ -456,9 +507,13 @@ testBoth('computed.readOnly', function(get, set, assert) { testBoth('computed.deprecatingAlias', function(get, set, assert) { let obj = { bar: 'asdf', baz: null, quz: false }; - defineProperty(obj, 'bay', computed(function() { - return 'apple'; - })); + defineProperty( + obj, + 'bay', + computed(function() { + return 'apple'; + }) + ); defineProperty(obj, 'barAlias', deprecatingAlias('bar')); defineProperty(obj, 'bazAlias', deprecatingAlias('baz')); @@ -493,7 +548,6 @@ testBoth('computed.deprecatingAlias', function(get, set, assert) { set(obj, 'quzAlias', null); }, 'Usage of `quzAlias` is deprecated, use `quz` instead.'); - assert.equal(get(obj, 'barAlias'), 'newBar'); assert.equal(get(obj, 'bazAlias'), 'newBaz'); assert.equal(get(obj, 'quzAlias'), null); diff --git a/packages/ember-runtime/tests/computed/reduce_computed_macros_test.js b/packages/ember-runtime/tests/computed/reduce_computed_macros_test.js index 5696410fb9c..153a3f169a5 100644 --- a/packages/ember-runtime/tests/computed/reduce_computed_macros_test.js +++ b/packages/ember-runtime/tests/computed/reduce_computed_macros_test.js @@ -35,20 +35,17 @@ let obj; QUnit.module('map', { beforeEach() { obj = EmberObject.extend({ - mapped: map('array.@each.v', (item) => item.v), - mappedObjects: map('arrayObjects.@each.v', (item) => ({ name: item.v.name })) + mapped: map('array.@each.v', item => item.v), + mappedObjects: map('arrayObjects.@each.v', item => ({ + name: item.v.name + })) }).create({ arrayObjects: emberA([ { v: { name: 'Robert' } }, { v: { name: 'Leanna' } } ]), - array: emberA([ - { v: 1 }, - { v: 3 }, - { v: 2 }, - { v: 1 } - ]) + array: emberA([{ v: 1 }, { v: 3 }, { v: 2 }, { v: 1 }]) }); }, @@ -79,7 +76,7 @@ QUnit.test('it maps simple unshifted properties', function(assert) { let array = emberA(); obj = EmberObject.extend({ - mapped: map('array', (item) => item.toUpperCase()) + mapped: map('array', item => item.toUpperCase()) }).create({ array }); @@ -90,12 +87,16 @@ QUnit.test('it maps simple unshifted properties', function(assert) { array.popObject(); - assert.deepEqual(obj.get('mapped'), ['A', 'B'], 'properties unshifted in sequence are mapped correctly'); + assert.deepEqual( + obj.get('mapped'), + ['A', 'B'], + 'properties unshifted in sequence are mapped correctly' + ); }); QUnit.test('it has the correct `this`', function(assert) { obj = EmberObject.extend({ - mapped: map('array', function(item) { + mapped: map('array', function(item) { assert.equal(this, obj, 'should have correct context'); return this.upperCase(item); }), @@ -106,7 +107,11 @@ QUnit.test('it has the correct `this`', function(assert) { array: ['a', 'b', 'c'] }); - assert.deepEqual(obj.get('mapped'), ['A', 'B', 'C'], 'properties unshifted in sequence are mapped correctly'); + assert.deepEqual( + obj.get('mapped'), + ['A', 'B', 'C'], + 'properties unshifted in sequence are mapped correctly' + ); }); QUnit.test('it passes the index to the callback', function(assert) { @@ -118,7 +123,11 @@ QUnit.test('it passes the index to the callback', function(assert) { array }); - assert.deepEqual(obj.get('mapped'), [0, 1, 2], 'index is passed to callback correctly'); + assert.deepEqual( + obj.get('mapped'), + [0, 1, 2], + 'index is passed to callback correctly' + ); }); QUnit.test('it maps objects', function(assert) { @@ -152,12 +161,14 @@ QUnit.test('it maps objects', function(assert) { ]); }); -QUnit.test('it maps unshifted objects with property observers', function(assert) { +QUnit.test('it maps unshifted objects with property observers', function( + assert +) { let array = emberA(); let cObj = { v: 'c' }; obj = EmberObject.extend({ - mapped: map('array.@each.v', (item) => get(item, 'v').toUpperCase()) + mapped: map('array.@each.v', item => get(item, 'v').toUpperCase()) }).create({ array }); @@ -168,8 +179,16 @@ QUnit.test('it maps unshifted objects with property observers', function(assert) set(cObj, 'v', 'd'); - assert.deepEqual(array.mapBy('v'), ['a', 'b', 'd'], 'precond - unmapped array is correct'); - assert.deepEqual(obj.get('mapped'), ['A', 'B', 'D'], 'properties unshifted in sequence are mapped correctly'); + assert.deepEqual( + array.mapBy('v'), + ['a', 'b', 'd'], + 'precond - unmapped array is correct' + ); + assert.deepEqual( + obj.get('mapped'), + ['A', 'B', 'D'], + 'properties unshifted in sequence are mapped correctly' + ); }); QUnit.module('mapBy', { @@ -177,12 +196,7 @@ QUnit.module('mapBy', { obj = EmberObject.extend({ mapped: mapBy('array', 'v') }).create({ - array: emberA([ - { v: 1 }, - { v: 3 }, - { v: 2 }, - { v: 1 } - ]) + array: emberA([{ v: 1 }, { v: 3 }, { v: 2 }, { v: 1 }]) }); }, afterEach() { @@ -223,7 +237,7 @@ QUnit.test('it is observable', function(assert) { QUnit.module('filter', { beforeEach() { obj = EmberObject.extend({ - filtered: filter('array', (item) => item % 2 === 0) + filtered: filter('array', item => item % 2 === 0) }).create({ array: emberA([1, 2, 3, 4, 5, 6, 7, 8]) }); @@ -239,8 +253,14 @@ QUnit.test('filter is readOnly', function(assert) { }, /Cannot set read-only property "filtered" on object:/); }); -QUnit.test('it filters according to the specified filter function', function(assert) { - assert.deepEqual(obj.get('filtered'), [2, 4, 6, 8], 'filter filters by the specified function'); +QUnit.test('it filters according to the specified filter function', function( + assert +) { + assert.deepEqual( + obj.get('filtered'), + [2, 4, 6, 8], + 'filter filters by the specified function' + ); }); QUnit.test('it passes the index to the callback', function(assert) { @@ -250,7 +270,11 @@ QUnit.test('it passes the index to the callback', function(assert) { array: ['a', 'b', 'c'] }); - assert.deepEqual(get(obj, 'filtered'), ['b'], 'index is passed to callback correctly'); + assert.deepEqual( + get(obj, 'filtered'), + ['b'], + 'index is passed to callback correctly' + ); }); QUnit.test('it has the correct `this`', function(assert) { @@ -266,17 +290,28 @@ QUnit.test('it has the correct `this`', function(assert) { array: ['a', 'b', 'c'] }); - assert.deepEqual(get(obj, 'filtered'), ['b'], 'index is passed to callback correctly'); + assert.deepEqual( + get(obj, 'filtered'), + ['b'], + 'index is passed to callback correctly' + ); }); QUnit.test('it passes the array to the callback', function(assert) { obj = EmberObject.extend({ - filtered: filter('array', (item, index, array) => index === get(array, 'length') - 2) + filtered: filter( + 'array', + (item, index, array) => index === get(array, 'length') - 2 + ) }).create({ array: emberA(['a', 'b', 'c']) }); - assert.deepEqual(obj.get('filtered'), ['b'], 'array is passed to callback correctly'); + assert.deepEqual( + obj.get('filtered'), + ['b'], + 'array is passed to callback correctly' + ); }); QUnit.test('it caches properly', function(assert) { @@ -296,24 +331,46 @@ QUnit.test('it caches properly', function(assert) { QUnit.test('it updates as the array is modified', function(assert) { let array = obj.get('array'); - assert.deepEqual(obj.get('filtered'), [2, 4, 6, 8], 'precond - filtered array is initially correct'); + assert.deepEqual( + obj.get('filtered'), + [2, 4, 6, 8], + 'precond - filtered array is initially correct' + ); array.addObject(11); - assert.deepEqual(obj.get('filtered'), [2, 4, 6, 8], 'objects not passing the filter are not added'); + assert.deepEqual( + obj.get('filtered'), + [2, 4, 6, 8], + 'objects not passing the filter are not added' + ); array.addObject(12); - assert.deepEqual(obj.get('filtered'), [2, 4, 6, 8, 12], 'objects passing the filter are added'); + assert.deepEqual( + obj.get('filtered'), + [2, 4, 6, 8, 12], + 'objects passing the filter are added' + ); array.removeObject(3); array.removeObject(4); - assert.deepEqual(obj.get('filtered'), [2, 6, 8, 12], 'objects removed from the dependent array are removed from the computed array'); + assert.deepEqual( + obj.get('filtered'), + [2, 6, 8, 12], + 'objects removed from the dependent array are removed from the computed array' + ); }); -QUnit.test('the dependent array can be cleared one at a time', function(assert) { +QUnit.test('the dependent array can be cleared one at a time', function( + assert +) { let array = get(obj, 'array'); - assert.deepEqual(obj.get('filtered'), [2, 4, 6, 8], 'precond - filtered array is initially correct'); + assert.deepEqual( + obj.get('filtered'), + [2, 4, 6, 8], + 'precond - filtered array is initially correct' + ); // clear 1-8 but in a random order array.removeObject(3); @@ -328,8 +385,14 @@ QUnit.test('the dependent array can be cleared one at a time', function(assert) assert.deepEqual(obj.get('filtered'), [], 'filtered array cleared correctly'); }); -QUnit.test('the dependent array can be `clear`ed directly (#3272)', function(assert) { - assert.deepEqual(obj.get('filtered'), [2, 4, 6, 8], 'precond - filtered array is initially correct'); +QUnit.test('the dependent array can be `clear`ed directly (#3272)', function( + assert +) { + assert.deepEqual( + obj.get('filtered'), + [2, 4, 6, 8], + 'precond - filtered array is initially correct' + ); obj.get('array').clear(); @@ -337,15 +400,25 @@ QUnit.test('the dependent array can be `clear`ed directly (#3272)', function(ass }); QUnit.test('it updates as the array is replaced', function(assert) { - assert.deepEqual(obj.get('filtered'), [2, 4, 6, 8], 'precond - filtered array is initially correct'); + assert.deepEqual( + obj.get('filtered'), + [2, 4, 6, 8], + 'precond - filtered array is initially correct' + ); obj.set('array', [20, 21, 22, 23, 24]); - assert.deepEqual(obj.get('filtered'), [20, 22, 24], 'computed array is updated when array is changed'); + assert.deepEqual( + obj.get('filtered'), + [20, 22, 24], + 'computed array is updated when array is changed' + ); }); -QUnit.test('it updates properly on @each with {} dependencies', function(assert) { - let item = EmberObject.create({prop: true}); +QUnit.test('it updates properly on @each with {} dependencies', function( + assert +) { + let item = EmberObject.create({ prop: true }); obj = EmberObject.extend({ filtered: filter('items.@each.{prop}', function(item) { @@ -389,8 +462,16 @@ QUnit.test('filterBy is readOnly', function(assert) { }); QUnit.test('properties can be filtered by truthiness', function(assert) { - assert.deepEqual(obj.get('as').mapBy('name'), ['one', 'two', 'three'], 'properties can be filtered by existence'); - assert.deepEqual(obj.get('bs').mapBy('name'), ['three', 'four'], 'booleans can be filtered'); + assert.deepEqual( + obj.get('as').mapBy('name'), + ['one', 'two', 'three'], + 'properties can be filtered by existence' + ); + assert.deepEqual( + obj.get('bs').mapBy('name'), + ['three', 'four'], + 'booleans can be filtered' + ); set(obj.get('array')[0], 'a', undefined); set(obj.get('array')[3], 'a', true); @@ -398,42 +479,88 @@ QUnit.test('properties can be filtered by truthiness', function(assert) { set(obj.get('array')[0], 'b', true); set(obj.get('array')[3], 'b', false); - assert.deepEqual(obj.get('as').mapBy('name'), ['two', 'three', 'four'], 'arrays computed by filter property respond to property changes'); - assert.deepEqual(obj.get('bs').mapBy('name'), ['one', 'three'], 'arrays computed by filtered property respond to property changes'); + assert.deepEqual( + obj.get('as').mapBy('name'), + ['two', 'three', 'four'], + 'arrays computed by filter property respond to property changes' + ); + assert.deepEqual( + obj.get('bs').mapBy('name'), + ['one', 'three'], + 'arrays computed by filtered property respond to property changes' + ); obj.get('array').pushObject({ name: 'five', a: 6, b: true }); - assert.deepEqual(obj.get('as').mapBy('name'), ['two', 'three', 'four', 'five'], 'arrays computed by filter property respond to added objects'); - assert.deepEqual(obj.get('bs').mapBy('name'), ['one', 'three', 'five'], 'arrays computed by filtered property respond to added objects'); + assert.deepEqual( + obj.get('as').mapBy('name'), + ['two', 'three', 'four', 'five'], + 'arrays computed by filter property respond to added objects' + ); + assert.deepEqual( + obj.get('bs').mapBy('name'), + ['one', 'three', 'five'], + 'arrays computed by filtered property respond to added objects' + ); obj.get('array').popObject(); - assert.deepEqual(obj.get('as').mapBy('name'), ['two', 'three', 'four'], 'arrays computed by filter property respond to removed objects'); - assert.deepEqual(obj.get('bs').mapBy('name'), ['one', 'three'], 'arrays computed by filtered property respond to removed objects'); - - obj.set('array', [ - { name: 'six', a: 12, b: true } - ]); - - assert.deepEqual(obj.get('as').mapBy('name'), ['six'], 'arrays computed by filter property respond to array changes'); - assert.deepEqual(obj.get('bs').mapBy('name'), ['six'], 'arrays computed by filtered property respond to array changes'); + assert.deepEqual( + obj.get('as').mapBy('name'), + ['two', 'three', 'four'], + 'arrays computed by filter property respond to removed objects' + ); + assert.deepEqual( + obj.get('bs').mapBy('name'), + ['one', 'three'], + 'arrays computed by filtered property respond to removed objects' + ); + + obj.set('array', [{ name: 'six', a: 12, b: true }]); + + assert.deepEqual( + obj.get('as').mapBy('name'), + ['six'], + 'arrays computed by filter property respond to array changes' + ); + assert.deepEqual( + obj.get('bs').mapBy('name'), + ['six'], + 'arrays computed by filtered property respond to array changes' + ); }); QUnit.test('properties can be filtered by values', function(assert) { - assert.deepEqual(obj.get('a1s').mapBy('name'), ['one', 'three'], 'properties can be filtered by matching value'); + assert.deepEqual( + obj.get('a1s').mapBy('name'), + ['one', 'three'], + 'properties can be filtered by matching value' + ); obj.get('array').pushObject({ name: 'five', a: 1 }); - assert.deepEqual(obj.get('a1s').mapBy('name'), ['one', 'three', 'five'], 'arrays computed by matching value respond to added objects'); + assert.deepEqual( + obj.get('a1s').mapBy('name'), + ['one', 'three', 'five'], + 'arrays computed by matching value respond to added objects' + ); obj.get('array').popObject(); - assert.deepEqual(obj.get('a1s').mapBy('name'), ['one', 'three'], 'arrays computed by matching value respond to removed objects'); + assert.deepEqual( + obj.get('a1s').mapBy('name'), + ['one', 'three'], + 'arrays computed by matching value respond to removed objects' + ); set(obj.get('array')[1], 'a', 1); set(obj.get('array')[2], 'a', 2); - assert.deepEqual(obj.get('a1s').mapBy('name'), ['one', 'two'], 'arrays computed by matching value respond to modified properties'); + assert.deepEqual( + obj.get('a1s').mapBy('name'), + ['one', 'two'], + 'arrays computed by matching value respond to modified properties' + ); }); QUnit.test('properties values can be replaced', function(assert) { @@ -444,19 +571,22 @@ QUnit.test('properties values can be replaced', function(assert) { array: [] }); - assert.deepEqual(obj.get('a1bs').mapBy('name'), [], 'properties can be filtered by matching value'); + assert.deepEqual( + obj.get('a1bs').mapBy('name'), + [], + 'properties can be filtered by matching value' + ); - set(obj, 'array', [ - { name: 'item1', a: 1, b: true } - ]); + set(obj, 'array', [{ name: 'item1', a: 1, b: true }]); - assert.deepEqual(obj.get('a1bs').mapBy('name'), ['item1'], 'properties can be filtered by matching value'); + assert.deepEqual( + obj.get('a1bs').mapBy('name'), + ['item1'], + 'properties can be filtered by matching value' + ); }); -[ - ['uniq', uniq], - ['union', union] -].forEach((tuple) => { +[['uniq', uniq], ['union', union]].forEach(tuple => { let [name, macro] = tuple; QUnit.module(`computed.${name}`, { @@ -484,37 +614,69 @@ QUnit.test('properties values can be replaced', function(assert) { let array = obj.get('array'); let array2 = obj.get('array2'); - assert.deepEqual(obj.get('union').sort((x, y) => x - y), [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], name + ' does not include duplicates'); + assert.deepEqual( + obj.get('union').sort((x, y) => x - y), + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + name + ' does not include duplicates' + ); array.pushObject(8); - assert.deepEqual(obj.get('union').sort((x, y) => x - y), [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], name + ' does not add existing items'); + assert.deepEqual( + obj.get('union').sort((x, y) => x - y), + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + name + ' does not add existing items' + ); array.pushObject(11); - assert.deepEqual(obj.get('union').sort((x, y) => x - y), [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], name + ' adds new items'); + assert.deepEqual( + obj.get('union').sort((x, y) => x - y), + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], + name + ' adds new items' + ); removeAt(array2, 6); // remove 7 - assert.deepEqual(obj.get('union').sort((x, y) => x - y), [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], name + ' does not remove items that are still in the dependent array'); + assert.deepEqual( + obj.get('union').sort((x, y) => x - y), + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], + name + ' does not remove items that are still in the dependent array' + ); array2.removeObject(7); - assert.deepEqual(obj.get('union').sort((x, y) => x - y), [1, 2, 3, 4, 5, 6, 8, 9, 10, 11], name + ' removes items when their last instance is gone'); + assert.deepEqual( + obj.get('union').sort((x, y) => x - y), + [1, 2, 3, 4, 5, 6, 8, 9, 10, 11], + name + ' removes items when their last instance is gone' + ); }); QUnit.test('has set-union semantics', function(assert) { let array = obj.get('array'); - assert.deepEqual(obj.get('union').sort((x, y) => x - y), [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], name + ' is initially correct'); + assert.deepEqual( + obj.get('union').sort((x, y) => x - y), + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + name + ' is initially correct' + ); array.removeObject(6); - assert.deepEqual(obj.get('union').sort((x, y) => x - y), [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 'objects are not removed if they exist in other dependent arrays'); + assert.deepEqual( + obj.get('union').sort((x, y) => x - y), + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + 'objects are not removed if they exist in other dependent arrays' + ); array.clear(); - assert.deepEqual(obj.get('union').sort((x, y) => x - y), [1, 4, 5, 6, 7, 8, 9, 10], 'objects are removed when they are no longer in any dependent array'); + assert.deepEqual( + obj.get('union').sort((x, y) => x - y), + [1, 4, 5, 6, 7, 8, 9, 10], + 'objects are removed when they are no longer in any dependent array' + ); }); }); @@ -553,33 +715,48 @@ QUnit.test('it does not share state among instances', function(assert) { list: [], uniqueByName: uniqBy('list', 'name') }); - let a = MyObject.create({ list: [{ name: 'bob' }, { name: 'mitch' }, { name: 'mitch' }] }); + let a = MyObject.create({ + list: [{ name: 'bob' }, { name: 'mitch' }, { name: 'mitch' }] + }); let b = MyObject.create({ list: [{ name: 'warren' }, { name: 'mitch' }] }); assert.deepEqual(a.get('uniqueByName'), [{ name: 'bob' }, { name: 'mitch' }]); // Making sure that 'mitch' appears - assert.deepEqual(b.get('uniqueByName'), [{ name: 'warren' }, { name: 'mitch' }]); + assert.deepEqual(b.get('uniqueByName'), [ + { name: 'warren' }, + { name: 'mitch' } + ]); }); QUnit.test('it handles changes to the dependent array', function(assert) { obj.get('list').pushObject({ id: 3, value: 'three' }); - assert.deepEqual(obj.get('uniqueById'), [ - { id: 1, value: 'one' }, - { id: 2, value: 'two' }, - { id: 3, value: 'three' } - ], 'The list includes three'); + assert.deepEqual( + obj.get('uniqueById'), + [ + { id: 1, value: 'one' }, + { id: 2, value: 'two' }, + { id: 3, value: 'three' } + ], + 'The list includes three' + ); obj.get('list').pushObject({ id: 3, value: 'three' }); - assert.deepEqual(obj.get('uniqueById'), [ - { id: 1, value: 'one' }, - { id: 2, value: 'two' }, - { id: 3, value: 'three' } - ], 'The list does not include a duplicate three'); + assert.deepEqual( + obj.get('uniqueById'), + [ + { id: 1, value: 'one' }, + { id: 2, value: 'two' }, + { id: 3, value: 'three' } + ], + 'The list does not include a duplicate three' + ); }); -QUnit.test('it returns an empty array when computed on a non-array', function(assert) { +QUnit.test('it returns an empty array when computed on a non-array', function( + assert +) { let MyObject = EmberObject.extend({ list: null, uniq: uniqBy('list', 'name') @@ -614,27 +791,51 @@ QUnit.test('it has set-intersection semantics', function(assert) { let array2 = obj.get('array2'); let array3 = obj.get('array3'); - assert.deepEqual(obj.get('intersection').sort((x, y) => x - y), [3, 5], 'intersection is initially correct'); + assert.deepEqual( + obj.get('intersection').sort((x, y) => x - y), + [3, 5], + 'intersection is initially correct' + ); array2.shiftObject(); - assert.deepEqual(obj.get('intersection').sort((x, y) => x - y), [3, 5], 'objects are not removed when they are still in all dependent arrays'); + assert.deepEqual( + obj.get('intersection').sort((x, y) => x - y), + [3, 5], + 'objects are not removed when they are still in all dependent arrays' + ); array2.shiftObject(); - assert.deepEqual(obj.get('intersection').sort((x, y) => x - y), [3, 5], 'objects are not removed when they are still in all dependent arrays'); + assert.deepEqual( + obj.get('intersection').sort((x, y) => x - y), + [3, 5], + 'objects are not removed when they are still in all dependent arrays' + ); array2.shiftObject(); - assert.deepEqual(obj.get('intersection'), [5], 'objects are removed once they are gone from all dependent arrays'); + assert.deepEqual( + obj.get('intersection'), + [5], + 'objects are removed once they are gone from all dependent arrays' + ); array2.pushObject(1); - assert.deepEqual(obj.get('intersection'), [5], 'objects are not added as long as they are missing from any dependent array'); + assert.deepEqual( + obj.get('intersection'), + [5], + 'objects are not added as long as they are missing from any dependent array' + ); array3.pushObject(1); - assert.deepEqual(obj.get('intersection').sort((x, y) => x - y), [1, 5], 'objects added once they belong to all dependent arrays'); + assert.deepEqual( + obj.get('intersection').sort((x, y) => x - y), + [1, 5], + 'objects added once they belong to all dependent arrays' + ); }); QUnit.module('setDiff', { @@ -657,82 +858,114 @@ QUnit.test('setDiff is readOnly', function(assert) { }, /Cannot set read-only property "diff" on object:/); }); -QUnit.test('it asserts if given fewer or more than two dependent properties', function() { - expectAssertion(function () { - EmberObject.extend({ - diff: setDiff('array') - }).create({ - array: emberA([1, 2, 3, 4, 5, 6, 7]), - array2: emberA([3, 4, 5]) - }); - }, /\`computed\.setDiff\` requires exactly two dependent arrays/, 'setDiff requires two dependent arrays'); - - expectAssertion(function () { - EmberObject.extend({ - diff: setDiff('array', 'array2', 'array3') - }).create({ - array: emberA([1, 2, 3, 4, 5, 6, 7]), - array2: emberA([3, 4, 5]), - array3: emberA([7]) - }); - }, /\`computed\.setDiff\` requires exactly two dependent arrays/, 'setDiff requires two dependent arrays'); -}); - +QUnit.test( + 'it asserts if given fewer or more than two dependent properties', + function() { + expectAssertion( + function() { + EmberObject.extend({ + diff: setDiff('array') + }).create({ + array: emberA([1, 2, 3, 4, 5, 6, 7]), + array2: emberA([3, 4, 5]) + }); + }, + /\`computed\.setDiff\` requires exactly two dependent arrays/, + 'setDiff requires two dependent arrays' + ); + + expectAssertion( + function() { + EmberObject.extend({ + diff: setDiff('array', 'array2', 'array3') + }).create({ + array: emberA([1, 2, 3, 4, 5, 6, 7]), + array2: emberA([3, 4, 5]), + array3: emberA([7]) + }); + }, + /\`computed\.setDiff\` requires exactly two dependent arrays/, + 'setDiff requires two dependent arrays' + ); + } +); QUnit.test('it has set-diff semantics', function(assert) { let array1 = obj.get('array'); let array2 = obj.get('array2'); - assert.deepEqual(obj.get('diff').sort((x, y) => x - y), [1, 2, 6, 7], 'set-diff is initially correct'); + assert.deepEqual( + obj.get('diff').sort((x, y) => x - y), + [1, 2, 6, 7], + 'set-diff is initially correct' + ); array2.popObject(); - assert.deepEqual(obj.get('diff').sort((x, y) => x - y), [1, 2, 6, 7], 'removing objects from the remove set has no effect if the object is not in the keep set'); + assert.deepEqual( + obj.get('diff').sort((x, y) => x - y), + [1, 2, 6, 7], + 'removing objects from the remove set has no effect if the object is not in the keep set' + ); array2.shiftObject(); - assert.deepEqual(obj.get('diff').sort((x, y) => x - y), [1, 2, 3, 6, 7], 'removing objects from the remove set adds them if they\'re in the keep set'); + assert.deepEqual( + obj.get('diff').sort((x, y) => x - y), + [1, 2, 3, 6, 7], + "removing objects from the remove set adds them if they're in the keep set" + ); array1.removeObject(3); - assert.deepEqual(obj.get('diff').sort((x, y) => x - y), [1, 2, 6, 7], 'removing objects from the keep array removes them from the computed array'); + assert.deepEqual( + obj.get('diff').sort((x, y) => x - y), + [1, 2, 6, 7], + 'removing objects from the keep array removes them from the computed array' + ); array1.pushObject(5); - assert.deepEqual(obj.get('diff').sort((x, y) => x - y), [1, 2, 6, 7], 'objects added to the keep array that are in the remove array are not added to the computed array'); + assert.deepEqual( + obj.get('diff').sort((x, y) => x - y), + [1, 2, 6, 7], + 'objects added to the keep array that are in the remove array are not added to the computed array' + ); array1.pushObject(22); - assert.deepEqual(obj.get('diff').sort((x, y) => x - y), [1, 2, 6, 7, 22], 'objects added to the keep array not in the remove array are added to the computed array'); + assert.deepEqual( + obj.get('diff').sort((x, y) => x - y), + [1, 2, 6, 7, 22], + 'objects added to the keep array not in the remove array are added to the computed array' + ); }); - function commonSortTests() { QUnit.test('arrays are initially sorted', function(assert) { - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Cersei', - 'Jaime', - 'Bran', - 'Robb' - ], 'array is initially sorted'); + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Cersei', 'Jaime', 'Bran', 'Robb'], + 'array is initially sorted' + ); }); QUnit.test('default sort order is correct', function(assert) { - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Cersei', - 'Jaime', - 'Bran', - 'Robb' - ], 'array is initially sorted'); + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Cersei', 'Jaime', 'Bran', 'Robb'], + 'array is initially sorted' + ); }); - QUnit.test('changing the dependent array updates the sorted array', function(assert) { - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Cersei', - 'Jaime', - 'Bran', - 'Robb' - ], 'precond - array is initially sorted'); + QUnit.test('changing the dependent array updates the sorted array', function( + assert + ) { + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Cersei', 'Jaime', 'Bran', 'Robb'], + 'precond - array is initially sorted' + ); obj.set('items', [ { fname: 'Roose', lname: 'Bolton' }, @@ -741,136 +974,139 @@ function commonSortTests() { { fname: 'Stannis', lname: 'Baratheon' } ]); - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Stannis', - 'Ramsey', - 'Roose', - 'Theon' - ], 'changing dependent array updates sorted array'); + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Stannis', 'Ramsey', 'Roose', 'Theon'], + 'changing dependent array updates sorted array' + ); }); - QUnit.test('adding to the dependent array updates the sorted array', function(assert) { + QUnit.test('adding to the dependent array updates the sorted array', function( + assert + ) { let items = obj.get('items'); - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Cersei', - 'Jaime', - 'Bran', - 'Robb' - ], 'precond - array is initially sorted'); + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Cersei', 'Jaime', 'Bran', 'Robb'], + 'precond - array is initially sorted' + ); items.pushObject({ fname: 'Tyrion', lname: 'Lannister' }); - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Cersei', - 'Jaime', - 'Tyrion', - 'Bran', - 'Robb' - ], 'Adding to the dependent array updates the sorted array'); - }); - - QUnit.test('removing from the dependent array updates the sorted array', function(assert) { - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Cersei', - 'Jaime', - 'Bran', - 'Robb' - ], 'precond - array is initially sorted'); - - obj.get('items').popObject(); - - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Cersei', - 'Jaime', - 'Robb' - ], 'Removing from the dependent array updates the sorted array'); + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Cersei', 'Jaime', 'Tyrion', 'Bran', 'Robb'], + 'Adding to the dependent array updates the sorted array' + ); }); - QUnit.test('distinct items may be sort-equal, although their relative order will not be guaranteed', function(assert) { - // We recreate jaime and "Cersei" here only for test stability: we want - // their guid-ordering to be deterministic - let jaimeInDisguise = { - fname: 'Cersei', - lname: 'Lannister', - age: 34 - }; - - let jaime = { - fname: 'Jaime', - lname: 'Lannister', - age: 34 - }; - - let items = obj.get('items'); - - items.replace(0, 1, [jaime]); - items.replace(1, 1, [jaimeInDisguise]); - - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Cersei', - 'Jaime', - 'Bran', - 'Robb' - ], 'precond - array is initially sorted'); - - set(jaimeInDisguise, 'fname', 'Jaime'); - - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Jaime', - 'Jaime', - 'Bran', - 'Robb' - ], 'sorted array is updated'); - - set(jaimeInDisguise, 'fname', 'Cersei'); - - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Cersei', - 'Jaime', - 'Bran', - 'Robb' - ], 'sorted array is updated'); - }); - - QUnit.test('guid sort-order fallback with a search proxy is not confused by non-search ObjectProxys', function(assert) { - let tyrion = { - fname: 'Tyrion', - lname: 'Lannister' - }; - - let tyrionInDisguise = ObjectProxy.create({ - fname: 'Yollo', - lname: '', - content: tyrion - }); + QUnit.test( + 'removing from the dependent array updates the sorted array', + function(assert) { + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Cersei', 'Jaime', 'Bran', 'Robb'], + 'precond - array is initially sorted' + ); + + obj.get('items').popObject(); + + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Cersei', 'Jaime', 'Robb'], + 'Removing from the dependent array updates the sorted array' + ); + } + ); + + QUnit.test( + 'distinct items may be sort-equal, although their relative order will not be guaranteed', + function(assert) { + // We recreate jaime and "Cersei" here only for test stability: we want + // their guid-ordering to be deterministic + let jaimeInDisguise = { + fname: 'Cersei', + lname: 'Lannister', + age: 34 + }; + + let jaime = { + fname: 'Jaime', + lname: 'Lannister', + age: 34 + }; + + let items = obj.get('items'); + + items.replace(0, 1, [jaime]); + items.replace(1, 1, [jaimeInDisguise]); + + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Cersei', 'Jaime', 'Bran', 'Robb'], + 'precond - array is initially sorted' + ); + + set(jaimeInDisguise, 'fname', 'Jaime'); + + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Jaime', 'Jaime', 'Bran', 'Robb'], + 'sorted array is updated' + ); + + set(jaimeInDisguise, 'fname', 'Cersei'); + + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Cersei', 'Jaime', 'Bran', 'Robb'], + 'sorted array is updated' + ); + } + ); + + QUnit.test( + 'guid sort-order fallback with a search proxy is not confused by non-search ObjectProxys', + function(assert) { + let tyrion = { + fname: 'Tyrion', + lname: 'Lannister' + }; + + let tyrionInDisguise = ObjectProxy.create({ + fname: 'Yollo', + lname: '', + content: tyrion + }); - let items = obj.get('items'); + let items = obj.get('items'); - items.pushObject(tyrion); + items.pushObject(tyrion); - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Cersei', - 'Jaime', - 'Tyrion', - 'Bran', - 'Robb' - ]); + assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ + 'Cersei', + 'Jaime', + 'Tyrion', + 'Bran', + 'Robb' + ]); - items.pushObject(tyrionInDisguise); + items.pushObject(tyrionInDisguise); - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Yollo', - 'Cersei', - 'Jaime', - 'Tyrion', - 'Bran', - 'Robb' - ]); - }); + assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ + 'Yollo', + 'Cersei', + 'Jaime', + 'Tyrion', + 'Bran', + 'Robb' + ]); + } + ); } QUnit.module('sort - sortProperties', { @@ -900,114 +1136,120 @@ QUnit.test('sort is readOnly', function(assert) { commonSortTests(); -QUnit.test('updating sort properties detaches observers for old sort properties', function(assert) { - let objectToRemove = obj.get('items')[3]; +QUnit.test( + 'updating sort properties detaches observers for old sort properties', + function(assert) { + let objectToRemove = obj.get('items')[3]; - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Cersei', - 'Jaime', - 'Bran', - 'Robb' - ], 'precond - array is initially sorted'); + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Cersei', 'Jaime', 'Bran', 'Robb'], + 'precond - array is initially sorted' + ); - obj.set('itemSorting', emberA(['fname:desc'])); + obj.set('itemSorting', emberA(['fname:desc'])); - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Robb', - 'Jaime', - 'Cersei', - 'Bran' - ], 'after updating sort properties array is updated'); + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Robb', 'Jaime', 'Cersei', 'Bran'], + 'after updating sort properties array is updated' + ); - obj.get('items').removeObject(objectToRemove); + obj.get('items').removeObject(objectToRemove); - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Robb', - 'Jaime', - 'Cersei' - ], 'after removing item array is updated'); + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Robb', 'Jaime', 'Cersei'], + 'after removing item array is updated' + ); - set(objectToRemove, 'lname', 'Updated-Stark'); + set(objectToRemove, 'lname', 'Updated-Stark'); - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Robb', - 'Jaime', - 'Cersei' - ], 'after changing removed item array is not updated'); -}); + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Robb', 'Jaime', 'Cersei'], + 'after changing removed item array is not updated' + ); + } +); + +QUnit.test( + 'sort works if array property is null (non array value) on first evaluation of computed prop', + function(assert) { + obj.set('items', null); + assert.deepEqual(obj.get('sortedItems'), []); + obj.set('items', emberA([{ fname: 'Cersei', lname: 'Lanister' }])); + assert.deepEqual(obj.get('sortedItems'), [ + { fname: 'Cersei', lname: 'Lanister' } + ]); + } +); -QUnit.test('sort works if array property is null (non array value) on first evaluation of computed prop', function(assert) { - obj.set('items', null); - assert.deepEqual(obj.get('sortedItems'), []); - obj.set('items', emberA([{fname: 'Cersei', lname: 'Lanister'}])); - assert.deepEqual(obj.get('sortedItems'), [{fname: 'Cersei', lname: 'Lanister'}]); -}); - -QUnit.test('updating sort properties updates the sorted array', function(assert) { - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Cersei', - 'Jaime', - 'Bran', - 'Robb' - ], 'precond - array is initially sorted'); +QUnit.test('updating sort properties updates the sorted array', function( + assert +) { + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Cersei', 'Jaime', 'Bran', 'Robb'], + 'precond - array is initially sorted' + ); obj.set('itemSorting', emberA(['fname:desc'])); - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Robb', - 'Jaime', - 'Cersei', - 'Bran' - ], 'after updating sort properties array is updated'); + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Robb', 'Jaime', 'Cersei', 'Bran'], + 'after updating sort properties array is updated' + ); }); -QUnit.test('updating sort properties invalidates the sorted array', function(assert) { +QUnit.test('updating sort properties invalidates the sorted array', function( + assert +) { let sortProps = obj.get('itemSorting'); - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Cersei', - 'Jaime', - 'Bran', - 'Robb' - ], 'precond - array is initially sorted'); + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Cersei', 'Jaime', 'Bran', 'Robb'], + 'precond - array is initially sorted' + ); sortProps.clear(); sortProps.pushObject('fname'); - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Bran', - 'Cersei', - 'Jaime', - 'Robb' - ], 'after updating sort properties array is updated'); -}); - -QUnit.test('updating new sort properties invalidates the sorted array', function(assert) { - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Cersei', - 'Jaime', - 'Bran', - 'Robb' - ], 'precond - array is initially sorted'); - - obj.set('itemSorting', emberA(['age:desc', 'fname:asc'])); - - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Cersei', - 'Jaime', - 'Robb', - 'Bran' - ], 'precond - array is correct after item sorting is changed'); - - set(obj.get('items')[1], 'age', 29); - - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Jaime', - 'Cersei', - 'Robb', - 'Bran' - ], 'after updating sort properties array is updated'); -}); + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Bran', 'Cersei', 'Jaime', 'Robb'], + 'after updating sort properties array is updated' + ); +}); + +QUnit.test( + 'updating new sort properties invalidates the sorted array', + function(assert) { + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Cersei', 'Jaime', 'Bran', 'Robb'], + 'precond - array is initially sorted' + ); + + obj.set('itemSorting', emberA(['age:desc', 'fname:asc'])); + + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Cersei', 'Jaime', 'Robb', 'Bran'], + 'precond - array is correct after item sorting is changed' + ); + + set(obj.get('items')[1], 'age', 29); + + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Jaime', 'Cersei', 'Robb', 'Bran'], + 'after updating sort properties array is updated' + ); + } +); QUnit.test('sort direction defaults to ascending', function(assert) { assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ @@ -1018,122 +1260,138 @@ QUnit.test('sort direction defaults to ascending', function(assert) { ]); }); -QUnit.test('sort direction defaults to ascending (with sort property change)', function(assert) { - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Cersei', - 'Jaime', - 'Bran', - 'Robb' - ], 'precond - array is initially sorted'); - - obj.set('itemSorting', emberA(['fname'])); - - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Bran', - 'Cersei', - 'Jaime', - 'Robb' - ], 'sort direction defaults to ascending'); -}); +QUnit.test( + 'sort direction defaults to ascending (with sort property change)', + function(assert) { + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Cersei', 'Jaime', 'Bran', 'Robb'], + 'precond - array is initially sorted' + ); -QUnit.test('updating an item\'s sort properties updates the sorted array', function(assert) { - let tyrionInDisguise = obj.get('items')[1]; + obj.set('itemSorting', emberA(['fname'])); - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Cersei', - 'Jaime', - 'Bran', - 'Robb' - ], 'precond - array is initially sorted'); - - set(tyrionInDisguise, 'fname', 'Tyrion'); - - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Jaime', - 'Tyrion', - 'Bran', - 'Robb' - ], 'updating an item\'s sort properties updates the sorted array'); -}); - -QUnit.test('updating several of an item\'s sort properties updated the sorted array', function(assert) { - let sansaInDisguise = obj.get('items')[1]; - - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Cersei', - 'Jaime', - 'Bran', - 'Robb' - ], 'precond - array is initially sorted'); - - setProperties(sansaInDisguise, { - fname: 'Sansa', - lname: 'Stark' - }); + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Bran', 'Cersei', 'Jaime', 'Robb'], + 'sort direction defaults to ascending' + ); + } +); + +QUnit.test( + "updating an item's sort properties updates the sorted array", + function(assert) { + let tyrionInDisguise = obj.get('items')[1]; + + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Cersei', 'Jaime', 'Bran', 'Robb'], + 'precond - array is initially sorted' + ); + + set(tyrionInDisguise, 'fname', 'Tyrion'); + + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Jaime', 'Tyrion', 'Bran', 'Robb'], + "updating an item's sort properties updates the sorted array" + ); + } +); + +QUnit.test( + "updating several of an item's sort properties updated the sorted array", + function(assert) { + let sansaInDisguise = obj.get('items')[1]; + + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Cersei', 'Jaime', 'Bran', 'Robb'], + 'precond - array is initially sorted' + ); + + setProperties(sansaInDisguise, { + fname: 'Sansa', + lname: 'Stark' + }); - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), [ - 'Jaime', - 'Bran', - 'Robb', - 'Sansa' - ], 'updating an item\'s sort properties updates the sorted array'); -}); + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Jaime', 'Bran', 'Robb', 'Sansa'], + "updating an item's sort properties updates the sorted array" + ); + } +); -QUnit.test('updating an item\'s sort properties does not error when binary search does a self compare (#3273)', function(assert) { - let jaime = { - name: 'Jaime', - status: 1 - }; +QUnit.test( + "updating an item's sort properties does not error when binary search does a self compare (#3273)", + function(assert) { + let jaime = { + name: 'Jaime', + status: 1 + }; - let cersei = { - name: 'Cersei', - status: 2 - }; + let cersei = { + name: 'Cersei', + status: 2 + }; - let obj = EmberObject.extend({ - sortProps: ['status'], - sortedPeople: sort('people', 'sortProps') - }).create({ - people: [jaime, cersei] - }); + let obj = EmberObject.extend({ + sortProps: ['status'], + sortedPeople: sort('people', 'sortProps') + }).create({ + people: [jaime, cersei] + }); - assert.deepEqual(obj.get('sortedPeople'), [ - jaime, - cersei - ], 'precond - array is initially sorted'); + assert.deepEqual( + obj.get('sortedPeople'), + [jaime, cersei], + 'precond - array is initially sorted' + ); - set(cersei, 'status', 3); + set(cersei, 'status', 3); - assert.deepEqual(obj.get('sortedPeople'), [ - jaime, - cersei - ], 'array is sorted correctly'); + assert.deepEqual( + obj.get('sortedPeople'), + [jaime, cersei], + 'array is sorted correctly' + ); - set(cersei, 'status', 2); + set(cersei, 'status', 2); - assert.deepEqual(obj.get('sortedPeople'), [ - jaime, - cersei - ], 'array is sorted correctly'); -}); + assert.deepEqual( + obj.get('sortedPeople'), + [jaime, cersei], + 'array is sorted correctly' + ); + } +); -QUnit.test('array should not be sorted if sort properties array is empty', function(assert) { - var o = EmberObject.extend({ - sortedItems: sort('items', 'itemSorting') - }).create({ - itemSorting: emberA([]), - // This bug only manifests when array.sort(() => 0) is not equal to array. - // In order for this to happen, the browser must use an unstable sort and the - // array must be sufficient large. On Chrome, 12 items is currently sufficient. - items: emberA([6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5]) - }); +QUnit.test( + 'array should not be sorted if sort properties array is empty', + function(assert) { + var o = EmberObject.extend({ + sortedItems: sort('items', 'itemSorting') + }).create({ + itemSorting: emberA([]), + // This bug only manifests when array.sort(() => 0) is not equal to array. + // In order for this to happen, the browser must use an unstable sort and the + // array must be sufficient large. On Chrome, 12 items is currently sufficient. + items: emberA([6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5]) + }); - assert.deepEqual(o.get('sortedItems'), [6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5], 'array is not changed'); -}); + assert.deepEqual( + o.get('sortedItems'), + [6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5], + 'array is not changed' + ); + } +); QUnit.test('array observers do not leak', function(assert) { let daria = { name: 'Daria' }; - let jane = { name: 'Jane' }; + let jane = { name: 'Jane' }; let sisters = [jane, daria]; @@ -1158,67 +1416,81 @@ QUnit.test('array observers do not leak', function(assert) { } }); -QUnit.test('property paths in sort properties update the sorted array', function(assert) { - let jaime = { - relatedObj: { status: 1, firstName: 'Jaime', lastName: 'Lannister' } - }; +QUnit.test( + 'property paths in sort properties update the sorted array', + function(assert) { + let jaime = { + relatedObj: { status: 1, firstName: 'Jaime', lastName: 'Lannister' } + }; - let cersei = { - relatedObj: { status: 2, firstName: 'Cersei', lastName: 'Lannister' } - }; + let cersei = { + relatedObj: { status: 2, firstName: 'Cersei', lastName: 'Lannister' } + }; - let sansa = EmberObject.create({ - relatedObj: { status: 3, firstName: 'Sansa', lastName: 'Stark' } - }); + let sansa = EmberObject.create({ + relatedObj: { status: 3, firstName: 'Sansa', lastName: 'Stark' } + }); - let obj = EmberObject.extend({ - sortProps: ['relatedObj.status'], - sortedPeople: sort('people', 'sortProps') - }).create({ - people: [jaime, cersei, sansa] - }); + let obj = EmberObject.extend({ + sortProps: ['relatedObj.status'], + sortedPeople: sort('people', 'sortProps') + }).create({ + people: [jaime, cersei, sansa] + }); - assert.deepEqual(obj.get('sortedPeople'), [ - jaime, - cersei, - sansa - ], 'precond - array is initially sorted'); + assert.deepEqual( + obj.get('sortedPeople'), + [jaime, cersei, sansa], + 'precond - array is initially sorted' + ); - set(cersei, 'status', 3); + set(cersei, 'status', 3); - assert.deepEqual(obj.get('sortedPeople'), [ - jaime, - cersei, - sansa - ], 'array is sorted correctly'); + assert.deepEqual( + obj.get('sortedPeople'), + [jaime, cersei, sansa], + 'array is sorted correctly' + ); - set(cersei, 'status', 1); + set(cersei, 'status', 1); - assert.deepEqual(obj.get('sortedPeople'), [ - jaime, - cersei, - sansa - ], 'array is sorted correctly'); + assert.deepEqual( + obj.get('sortedPeople'), + [jaime, cersei, sansa], + 'array is sorted correctly' + ); - sansa.set('status', 1); + sansa.set('status', 1); - assert.deepEqual(obj.get('sortedPeople'), [jaime, cersei, sansa], 'array is sorted correctly'); + assert.deepEqual( + obj.get('sortedPeople'), + [jaime, cersei, sansa], + 'array is sorted correctly' + ); - obj.set('sortProps', ['relatedObj.firstName']); + obj.set('sortProps', ['relatedObj.firstName']); - assert.deepEqual(obj.get('sortedPeople'), [cersei, jaime, sansa], 'array is sorted correctly'); -}); + assert.deepEqual( + obj.get('sortedPeople'), + [cersei, jaime, sansa], + 'array is sorted correctly' + ); + } +); -QUnit.test('if the dependentKey is neither an array nor object, it will return an empty array', assert => { - set(obj, 'items', null); - assert.ok(isArray(obj.get('sortedItems')), 'returns an empty arrays'); +QUnit.test( + 'if the dependentKey is neither an array nor object, it will return an empty array', + assert => { + set(obj, 'items', null); + assert.ok(isArray(obj.get('sortedItems')), 'returns an empty arrays'); - set(obj, 'array', undefined); - assert.ok(isArray(obj.get('sortedItems')), 'returns an empty arrays'); + set(obj, 'array', undefined); + assert.ok(isArray(obj.get('sortedItems')), 'returns an empty arrays'); - set(obj, 'array', 'not an array'); - assert.ok(isArray(obj.get('sortedItems')), 'returns an empty arrays'); -}); + set(obj, 'array', 'not an array'); + assert.ok(isArray(obj.get('sortedItems')), 'returns an empty arrays'); + } +); function sortByLnameFname(a, b) { let lna = get(a, 'lname'); @@ -1288,36 +1560,64 @@ QUnit.test('sort (with function) is readOnly', function(assert) { commonSortTests(); -QUnit.test('changing item properties specified via @each triggers a resort of the modified item', function(assert) { - let items = get(obj, 'items'); +QUnit.test( + 'changing item properties specified via @each triggers a resort of the modified item', + function(assert) { + let items = get(obj, 'items'); - let tyrionInDisguise = items[1]; + let tyrionInDisguise = items[1]; - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), ['Cersei', 'Jaime', 'Bran', 'Robb'], 'precond - array is initially sorted'); + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Cersei', 'Jaime', 'Bran', 'Robb'], + 'precond - array is initially sorted' + ); - set(tyrionInDisguise, 'fname', 'Tyrion'); + set(tyrionInDisguise, 'fname', 'Tyrion'); - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), ['Jaime', 'Tyrion', 'Bran', 'Robb'], 'updating a specified property on an item resorts it'); -}); + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Jaime', 'Tyrion', 'Bran', 'Robb'], + 'updating a specified property on an item resorts it' + ); + } +); if (!EMBER_METAL_TRACKED_PROPERTIES) { - QUnit.test('changing item properties not specified via @each does not trigger a resort', function(assert) { - let items = obj.get('items'); - let cersei = items[1]; - - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), ['Cersei', 'Jaime', 'Bran', 'Robb'], 'precond - array is initially sorted'); - - set(cersei, 'lname', 'Stark'); // plot twist! (possibly not canon) - - // The array has become unsorted. If your sort function is sensitive to - // properties, they *must* be specified as dependent item property keys or - // we'll be doing binary searches on unsorted arrays. - assert.deepEqual(obj.get('sortedItems').mapBy('fname'), ['Cersei', 'Jaime', 'Bran', 'Robb'], 'updating an unspecified property on an item does not resort it'); - }); + QUnit.test( + 'changing item properties not specified via @each does not trigger a resort', + function(assert) { + let items = obj.get('items'); + let cersei = items[1]; + + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Cersei', 'Jaime', 'Bran', 'Robb'], + 'precond - array is initially sorted' + ); + + set(cersei, 'lname', 'Stark'); // plot twist! (possibly not canon) + + // The array has become unsorted. If your sort function is sensitive to + // properties, they *must* be specified as dependent item property keys or + // we'll be doing binary searches on unsorted arrays. + assert.deepEqual( + obj.get('sortedItems').mapBy('fname'), + ['Cersei', 'Jaime', 'Bran', 'Robb'], + 'updating an unspecified property on an item does not resort it' + ); + } + ); } else { - QUnit.skip('changing item properties not specified via @each does not trigger a resort', assert => { - assert.ok(false, 'It is unclear whether changing this behavior should be considered a breaking change, and whether it catches more bugs than it causes'); - }); + QUnit.skip( + 'changing item properties not specified via @each does not trigger a resort', + assert => { + assert.ok( + false, + 'It is unclear whether changing this behavior should be considered a breaking change, and whether it catches more bugs than it causes' + ); + } + ); } QUnit.module('sort - stability', { @@ -1340,11 +1640,19 @@ QUnit.module('sort - stability', { }); QUnit.test('sorts correctly as only one property changes', function(assert) { - assert.deepEqual(obj.get('sortedItems').mapBy('name'), ['A', 'B', 'C', 'D'], 'initial'); + assert.deepEqual( + obj.get('sortedItems').mapBy('name'), + ['A', 'B', 'C', 'D'], + 'initial' + ); set(obj.get('items')[3], 'count', 2); - assert.deepEqual(obj.get('sortedItems').mapBy('name'), ['A', 'B', 'C', 'D'], 'final'); + assert.deepEqual( + obj.get('sortedItems').mapBy('name'), + ['A', 'B', 'C', 'D'], + 'final' + ); }); let klass; @@ -1370,28 +1678,48 @@ QUnit.module('sort - concurrency', { } }); -QUnit.test('sorts correctly after mutation to the sort properties', function(assert) { +QUnit.test('sorts correctly after mutation to the sort properties', function( + assert +) { let sorted = obj.get('sortedItems'); assert.deepEqual(sorted.mapBy('name'), ['A', 'B', 'C', 'D'], 'initial'); set(obj.get('items')[1], 'count', 5); set(obj.get('items')[2], 'count', 6); - assert.deepEqual(obj.get('sortedItems').mapBy('name'), ['A', 'D', 'B', 'C'], 'final'); + assert.deepEqual( + obj.get('sortedItems').mapBy('name'), + ['A', 'D', 'B', 'C'], + 'final' + ); }); QUnit.test('sort correctly after mutation to the sort', function(assert) { - assert.deepEqual(obj.get('customSortedItems').mapBy('name'), ['A', 'B', 'C', 'D'], 'initial'); + assert.deepEqual( + obj.get('customSortedItems').mapBy('name'), + ['A', 'B', 'C', 'D'], + 'initial' + ); set(obj.get('items')[1], 'count', 5); set(obj.get('items')[2], 'count', 6); - assert.deepEqual(obj.get('customSortedItems').mapBy('name'), ['A', 'D', 'B', 'C'], 'final'); + assert.deepEqual( + obj.get('customSortedItems').mapBy('name'), + ['A', 'D', 'B', 'C'], + 'final' + ); - assert.deepEqual(obj.get('sortedItems').mapBy('name'), ['A', 'D', 'B', 'C'], 'final'); + assert.deepEqual( + obj.get('sortedItems').mapBy('name'), + ['A', 'D', 'B', 'C'], + 'final' + ); }); -QUnit.test('sort correctly on multiple instances of the same class', function(assert) { +QUnit.test('sort correctly on multiple instances of the same class', function( + assert +) { let obj2 = klass.create({ items: emberA([ { name: 'W', count: 23, thing: 4 }, @@ -1401,43 +1729,70 @@ QUnit.test('sort correctly on multiple instances of the same class', function(as ]) }); - assert.deepEqual(obj2.get('sortedItems').mapBy('name'), ['W', 'X', 'Y', 'Z'], 'initial'); - assert.deepEqual(obj.get('sortedItems').mapBy('name'), ['A', 'B', 'C', 'D'], 'initial'); + assert.deepEqual( + obj2.get('sortedItems').mapBy('name'), + ['W', 'X', 'Y', 'Z'], + 'initial' + ); + assert.deepEqual( + obj.get('sortedItems').mapBy('name'), + ['A', 'B', 'C', 'D'], + 'initial' + ); set(obj.get('items')[1], 'count', 5); set(obj.get('items')[2], 'count', 6); set(obj2.get('items')[1], 'count', 27); set(obj2.get('items')[2], 'count', 28); - assert.deepEqual(obj.get('sortedItems').mapBy('name'), ['A', 'D', 'B', 'C'], 'final'); - assert.deepEqual(obj2.get('sortedItems').mapBy('name'), ['W', 'Z', 'X', 'Y'], 'final'); + assert.deepEqual( + obj.get('sortedItems').mapBy('name'), + ['A', 'D', 'B', 'C'], + 'final' + ); + assert.deepEqual( + obj2.get('sortedItems').mapBy('name'), + ['W', 'Z', 'X', 'Y'], + 'final' + ); obj.set('sortProps', ['thing']); - assert.deepEqual(obj.get('sortedItems').mapBy('name'), ['D', 'C', 'B', 'A'], 'final'); + assert.deepEqual( + obj.get('sortedItems').mapBy('name'), + ['D', 'C', 'B', 'A'], + 'final' + ); obj2.notifyPropertyChange('sortedItems'); // invalidate to flush, to get DK refreshed obj2.get('sortedItems'); // flush to get updated DK obj2.set('items.firstObject.count', 9999); - assert.deepEqual(obj2.get('sortedItems').mapBy('name'), ['Z', 'X', 'Y', 'W'], 'final'); -}); - - -QUnit.test('sort correctly when multiple sorts are chained on the same instance of a class', function(assert) { - let obj2 = klass.extend({ - items: computed('sibling.sortedItems.[]', function() { - return this.get('sibling.sortedItems'); - }), - asdf: observer('sibling.sortedItems.[]', function() { - this.get('sibling.sortedItems'); - }) - }).create({ - sibling: obj - }); + assert.deepEqual( + obj2.get('sortedItems').mapBy('name'), + ['Z', 'X', 'Y', 'W'], + 'final' + ); +}); + +QUnit.test( + 'sort correctly when multiple sorts are chained on the same instance of a class', + function(assert) { + let obj2 = klass + .extend({ + items: computed('sibling.sortedItems.[]', function() { + return this.get('sibling.sortedItems'); + }), + asdf: observer('sibling.sortedItems.[]', function() { + this.get('sibling.sortedItems'); + }) + }) + .create({ + sibling: obj + }); - /* + /* ┌───────────┐ ┌────────────┐ │sortedProps│ │sortedProps2│ └───────────┘ └────────────┘ @@ -1453,21 +1808,46 @@ QUnit.test('sort correctly when multiple sorts are chained on the same instance └───────────┘ ┗━━━━━━━━━━━┛ ┗━━━━━━━━━━━━┛ */ - assert.deepEqual(obj.get('sortedItems').mapBy('name'), ['A', 'B', 'C', 'D'], 'obj.sortedItems.name should be sorted alpha'); - assert.deepEqual(obj2.get('sortedItems').mapBy('name'), ['A', 'B', 'C', 'D'], 'obj2.sortedItems.name should be sorted alpha'); - - set(obj.get('items')[1], 'count', 5); - set(obj.get('items')[2], 'count', 6); - - assert.deepEqual(obj.get('sortedItems').mapBy('name'), ['A', 'D', 'B', 'C'], 'obj.sortedItems.name should now have changed'); - assert.deepEqual(obj2.get('sortedItems').mapBy('name'), ['A', 'D', 'B', 'C'], 'obj2.sortedItems.name should still mirror sortedItems2'); - - obj.set('sortProps', ['thing']); - obj2.set('sortProps', ['id']); - - assert.deepEqual(obj2.get('sortedItems').mapBy('name'), ['A', 'B', 'C', 'D'], 'we now sort obj2 by id, so we expect a b c d'); - assert.deepEqual(obj.get('sortedItems').mapBy('name'), ['D', 'C', 'B', 'A'], 'we now sort obj by thing'); -}); + assert.deepEqual( + obj.get('sortedItems').mapBy('name'), + ['A', 'B', 'C', 'D'], + 'obj.sortedItems.name should be sorted alpha' + ); + assert.deepEqual( + obj2.get('sortedItems').mapBy('name'), + ['A', 'B', 'C', 'D'], + 'obj2.sortedItems.name should be sorted alpha' + ); + + set(obj.get('items')[1], 'count', 5); + set(obj.get('items')[2], 'count', 6); + + assert.deepEqual( + obj.get('sortedItems').mapBy('name'), + ['A', 'D', 'B', 'C'], + 'obj.sortedItems.name should now have changed' + ); + assert.deepEqual( + obj2.get('sortedItems').mapBy('name'), + ['A', 'D', 'B', 'C'], + 'obj2.sortedItems.name should still mirror sortedItems2' + ); + + obj.set('sortProps', ['thing']); + obj2.set('sortProps', ['id']); + + assert.deepEqual( + obj2.get('sortedItems').mapBy('name'), + ['A', 'B', 'C', 'D'], + 'we now sort obj2 by id, so we expect a b c d' + ); + assert.deepEqual( + obj.get('sortedItems').mapBy('name'), + ['D', 'C', 'B', 'A'], + 'we now sort obj by thing' + ); + } +); QUnit.module('max', { beforeEach() { @@ -1499,7 +1879,11 @@ QUnit.test('max tracks the max number as objects are added', function(assert) { items.pushObject(2); - assert.equal(obj.get('max'), 5, 'max does not update when a smaller number is added'); + assert.equal( + obj.get('max'), + 5, + 'max does not update when a smaller number is added' + ); }); QUnit.test('max recomputes when the current max is removed', function(assert) { @@ -1507,11 +1891,19 @@ QUnit.test('max recomputes when the current max is removed', function(assert) { obj.get('items').removeObject(2); - assert.equal(obj.get('max'), 3, 'max is unchanged when a non-max item is removed'); + assert.equal( + obj.get('max'), + 3, + 'max is unchanged when a non-max item is removed' + ); obj.get('items').removeObject(3); - assert.equal(obj.get('max'), 1, 'max is recomputed when the current max is removed'); + assert.equal( + obj.get('max'), + 1, + 'max is recomputed when the current max is removed' + ); }); QUnit.module('min', { @@ -1538,11 +1930,19 @@ QUnit.test('min tracks the min number as objects are added', function(assert) { obj.get('items').pushObject(-2); - assert.equal(obj.get('min'), -2, 'min updates when a smaller number is added'); + assert.equal( + obj.get('min'), + -2, + 'min updates when a smaller number is added' + ); obj.get('items').pushObject(2); - assert.equal(obj.get('min'), -2, 'min does not update when a larger number is added'); + assert.equal( + obj.get('min'), + -2, + 'min does not update when a larger number is added' + ); }); QUnit.test('min recomputes when the current min is removed', function(assert) { @@ -1552,11 +1952,19 @@ QUnit.test('min recomputes when the current min is removed', function(assert) { items.removeObject(2); - assert.equal(obj.get('min'), 1, 'min is unchanged when a non-min item is removed'); + assert.equal( + obj.get('min'), + 1, + 'min is unchanged when a non-min item is removed' + ); items.removeObject(1); - assert.equal(obj.get('min'), 3, 'min is recomputed when the current min is removed'); + assert.equal( + obj.get('min'), + 3, + 'min is recomputed when the current min is removed' + ); }); QUnit.module('Ember.arrayComputed - mixed sugar', { @@ -1586,19 +1994,33 @@ QUnit.module('Ember.arrayComputed - mixed sugar', { QUnit.test('filtering and sorting can be combined', function(assert) { let items = obj.get('items'); - assert.deepEqual(obj.get('sortedLannisters').mapBy('fname'), ['Cersei', 'Jaime'], 'precond - array is initially filtered and sorted'); + assert.deepEqual( + obj.get('sortedLannisters').mapBy('fname'), + ['Cersei', 'Jaime'], + 'precond - array is initially filtered and sorted' + ); - items.pushObject({ fname: 'Tywin', lname: 'Lannister' }); - items.pushObject({ fname: 'Lyanna', lname: 'Stark' }); - items.pushObject({ fname: 'Gerion', lname: 'Lannister' }); + items.pushObject({ fname: 'Tywin', lname: 'Lannister' }); + items.pushObject({ fname: 'Lyanna', lname: 'Stark' }); + items.pushObject({ fname: 'Gerion', lname: 'Lannister' }); - assert.deepEqual(obj.get('sortedLannisters').mapBy('fname'), ['Cersei', 'Gerion', 'Jaime', 'Tywin'], 'updates propagate to array'); + assert.deepEqual( + obj.get('sortedLannisters').mapBy('fname'), + ['Cersei', 'Gerion', 'Jaime', 'Tywin'], + 'updates propagate to array' + ); }); -QUnit.test('filtering, sorting and reduce (max) can be combined', function(assert) { +QUnit.test('filtering, sorting and reduce (max) can be combined', function( + assert +) { let items = obj.get('items'); - assert.equal(16, obj.get('oldestStarkAge'), 'precond - end of chain is initially correct'); + assert.equal( + 16, + obj.get('oldestStarkAge'), + 'precond - end of chain is initially correct' + ); items.pushObject({ fname: 'Rickon', lname: 'Stark', age: 5 }); @@ -1646,17 +2068,44 @@ QUnit.module('Ember.arrayComputed - chains', { } }); -QUnit.test('it can filter and sort when both depend on the same item property', function(assert) { - assert.deepEqual(obj.get('todos').mapBy('name'), ['E', 'D', 'C', 'B', 'A'], 'precond - todos initially correct'); - assert.deepEqual(obj.get('sorted').mapBy('name'), ['A', 'B', 'C', 'D', 'E'], 'precond - sorted initially correct'); - assert.deepEqual(obj.get('filtered').mapBy('name'), ['A', 'C', 'E'], 'precond - filtered initially correct'); - - set(obj.get('todos')[1], 'priority', 6); - - assert.deepEqual(obj.get('todos').mapBy('name'), ['E', 'D', 'C', 'B', 'A'], 'precond - todos remain correct'); - assert.deepEqual(obj.get('sorted').mapBy('name'), ['A', 'B', 'C', 'E', 'D'], 'precond - sorted updated correctly'); - assert.deepEqual(obj.get('filtered').mapBy('name'), ['A', 'C', 'E', 'D'], 'filtered updated correctly'); -}); +QUnit.test( + 'it can filter and sort when both depend on the same item property', + function(assert) { + assert.deepEqual( + obj.get('todos').mapBy('name'), + ['E', 'D', 'C', 'B', 'A'], + 'precond - todos initially correct' + ); + assert.deepEqual( + obj.get('sorted').mapBy('name'), + ['A', 'B', 'C', 'D', 'E'], + 'precond - sorted initially correct' + ); + assert.deepEqual( + obj.get('filtered').mapBy('name'), + ['A', 'C', 'E'], + 'precond - filtered initially correct' + ); + + set(obj.get('todos')[1], 'priority', 6); + + assert.deepEqual( + obj.get('todos').mapBy('name'), + ['E', 'D', 'C', 'B', 'A'], + 'precond - todos remain correct' + ); + assert.deepEqual( + obj.get('sorted').mapBy('name'), + ['A', 'B', 'C', 'E', 'D'], + 'precond - sorted updated correctly' + ); + assert.deepEqual( + obj.get('filtered').mapBy('name'), + ['A', 'C', 'E', 'D'], + 'filtered updated correctly' + ); + } +); let userFnCalls; QUnit.module('Chaining array and reduced CPs', { @@ -1667,12 +2116,7 @@ QUnit.module('Chaining array and reduced CPs', { max: max('mapped'), maxDidChange: observer('max', () => userFnCalls++) }).create({ - array: emberA([ - { v: 1 }, - { v: 3 }, - { v: 2 }, - { v: 1 } - ]) + array: emberA([{ v: 1 }, { v: 3 }, { v: 2 }, { v: 1 }]) }); }, afterEach() { @@ -1680,8 +2124,14 @@ QUnit.module('Chaining array and reduced CPs', { } }); -QUnit.test('it computes interdependent array computed properties', function(assert) { - assert.equal(obj.get('max'), 3, 'sanity - it properly computes the maximum value'); +QUnit.test('it computes interdependent array computed properties', function( + assert +) { + assert.equal( + obj.get('max'), + 3, + 'sanity - it properly computes the maximum value' + ); let calls = 0; @@ -1717,16 +2167,19 @@ QUnit.test('sums the values in the dependentKey', function(assert) { assert.equal(obj.get('total'), 6, 'sums the values'); }); -QUnit.test('if the dependentKey is neither an array nor object, it will return `0`', assert => { - set(obj, 'array', null); - assert.equal(get(obj, 'total'), 0, 'returns 0'); +QUnit.test( + 'if the dependentKey is neither an array nor object, it will return `0`', + assert => { + set(obj, 'array', null); + assert.equal(get(obj, 'total'), 0, 'returns 0'); - set(obj, 'array', undefined); - assert.equal(get(obj, 'total'), 0, 'returns 0'); + set(obj, 'array', undefined); + assert.equal(get(obj, 'total'), 0, 'returns 0'); - set(obj, 'array', 'not an array'); - assert.equal(get(obj, 'total'), 0, 'returns 0'); -}); + set(obj, 'array', 'not an array'); + assert.equal(get(obj, 'total'), 0, 'returns 0'); + } +); QUnit.test('updates when array is modified', function(assert) { obj.get('array').pushObject(1); @@ -1744,11 +2197,19 @@ testBoth('works', function(get, set, assert) { let obj = { one: 'foo', two: 'bar', three: null }; defineProperty(obj, 'all', collect('one', 'two', 'three', 'four')); - assert.deepEqual(get(obj, 'all'), ['foo', 'bar', null, null], 'have all of them'); + assert.deepEqual( + get(obj, 'all'), + ['foo', 'bar', null, null], + 'have all of them' + ); set(obj, 'four', true); - assert.deepEqual(get(obj, 'all'), ['foo', 'bar', null, true], 'have all of them'); + assert.deepEqual( + get(obj, 'all'), + ['foo', 'bar', null, true], + 'have all of them' + ); let a = []; set(obj, 'one', 0); diff --git a/packages/ember-runtime/tests/controllers/controller_test.js b/packages/ember-runtime/tests/controllers/controller_test.js index c6e12f67e6d..16253a540fe 100644 --- a/packages/ember-runtime/tests/controllers/controller_test.js +++ b/packages/ember-runtime/tests/controllers/controller_test.js @@ -9,7 +9,9 @@ import { runDestroy, buildOwner } from 'internal-test-helpers'; QUnit.module('Controller event handling'); -QUnit.test('Action can be handled by a function on actions object', function(assert) { +QUnit.test('Action can be handled by a function on actions object', function( + assert +) { assert.expect(1); let TestController = Controller.extend({ actions: { @@ -22,30 +24,35 @@ QUnit.test('Action can be handled by a function on actions object', function(ass controller.send('poke'); }); -QUnit.test('A handled action can be bubbled to the target for continued processing', function(assert) { - assert.expect(2); - let TestController = Controller.extend({ - actions: { - poke() { - assert.ok(true, 'poked 1'); - return true; - } - } - }); - - let controller = TestController.create({ - target: Controller.extend({ +QUnit.test( + 'A handled action can be bubbled to the target for continued processing', + function(assert) { + assert.expect(2); + let TestController = Controller.extend({ actions: { poke() { - assert.ok(true, 'poked 2'); + assert.ok(true, 'poked 1'); + return true; } } - }).create() - }); - controller.send('poke'); -}); - -QUnit.test('Action can be handled by a superclass\' actions object', function(assert) { + }); + + let controller = TestController.create({ + target: Controller.extend({ + actions: { + poke() { + assert.ok(true, 'poked 2'); + } + } + }).create() + }); + controller.send('poke'); + } +); + +QUnit.test("Action can be handled by a superclass' actions object", function( + assert +) { assert.expect(4); let SuperController = Controller.extend({ @@ -85,28 +92,30 @@ QUnit.test('Action can be handled by a superclass\' actions object', function(as QUnit.test('.send asserts if called on a destroyed controller', function() { let owner = buildOwner(); - owner.register('controller:application', Controller.extend({ - toString() { - return 'controller:rip-alley'; - } - })); + owner.register( + 'controller:application', + Controller.extend({ + toString() { + return 'controller:rip-alley'; + } + }) + ); let controller = owner.lookup('controller:application'); runDestroy(owner); - expectAssertion( - () => { - controller.send('trigger-me-dead'); - }, - "Attempted to call .send() with the action 'trigger-me-dead' on the destroyed object 'controller:rip-alley'." - ); + expectAssertion(() => { + controller.send('trigger-me-dead'); + }, "Attempted to call .send() with the action 'trigger-me-dead' on the destroyed object 'controller:rip-alley'."); }); QUnit.module('Controller deprecations'); QUnit.module('Controller Content -> Model Alias'); -QUnit.test('`content` is not moved to `model` when `model` is unset', function(assert) { +QUnit.test('`content` is not moved to `model` when `model` is unset', function( + assert +) { assert.expect(2); let controller; @@ -117,78 +126,105 @@ QUnit.test('`content` is not moved to `model` when `model` is unset', function(a }); assert.notEqual(controller.get('model'), 'foo-bar', 'model is set properly'); - assert.equal(controller.get('content'), 'foo-bar', 'content is not set properly'); + assert.equal( + controller.get('content'), + 'foo-bar', + 'content is not set properly' + ); }); -QUnit.test('specifying `content` (without `model` specified) does not result in deprecation', function(assert) { - assert.expect(2); - expectNoDeprecation(); +QUnit.test( + 'specifying `content` (without `model` specified) does not result in deprecation', + function(assert) { + assert.expect(2); + expectNoDeprecation(); - let controller = Controller.extend({ - content: 'foo-bar' - }).create(); + let controller = Controller.extend({ + content: 'foo-bar' + }).create(); - assert.equal(get(controller, 'content'), 'foo-bar'); -}); + assert.equal(get(controller, 'content'), 'foo-bar'); + } +); -QUnit.test('specifying `content` (with `model` specified) does not result in deprecation', function(assert) { - assert.expect(3); - expectNoDeprecation(); +QUnit.test( + 'specifying `content` (with `model` specified) does not result in deprecation', + function(assert) { + assert.expect(3); + expectNoDeprecation(); - let controller = Controller.extend({ - content: 'foo-bar', - model: 'blammo' - }).create(); + let controller = Controller.extend({ + content: 'foo-bar', + model: 'blammo' + }).create(); - assert.equal(get(controller, 'content'), 'foo-bar'); - assert.equal(get(controller, 'model'), 'blammo'); -}); + assert.equal(get(controller, 'content'), 'foo-bar'); + assert.equal(get(controller, 'model'), 'blammo'); + } +); QUnit.module('Controller injected properties'); if (!EmberDev.runningProdBuild) { - QUnit.test('defining a controller on a non-controller should fail assertion', function() { - expectAssertion(function() { - let owner = buildOwner(); + QUnit.test( + 'defining a controller on a non-controller should fail assertion', + function() { + expectAssertion(function() { + let owner = buildOwner(); - let AnObject = EmberObject.extend({ - foo: inject.controller('bar') - }); + let AnObject = EmberObject.extend({ + foo: inject.controller('bar') + }); - owner.register('controller:bar', EmberObject.extend()); - owner.register('foo:main', AnObject); + owner.register('controller:bar', EmberObject.extend()); + owner.register('foo:main', AnObject); - owner.lookup('foo:main'); - }, /Defining an injected controller property on a non-controller is not allowed./); - }); + owner.lookup('foo:main'); + }, /Defining an injected controller property on a non-controller is not allowed./); + } + ); } QUnit.test('controllers can be injected into controllers', function(assert) { let owner = buildOwner(); - owner.register('controller:post', Controller.extend({ - postsController: inject.controller('posts') - })); + owner.register( + 'controller:post', + Controller.extend({ + postsController: inject.controller('posts') + }) + ); owner.register('controller:posts', Controller.extend()); let postController = owner.lookup('controller:post'); let postsController = owner.lookup('controller:posts'); - assert.equal(postsController, postController.get('postsController'), 'controller.posts is injected'); + assert.equal( + postsController, + postController.get('postsController'), + 'controller.posts is injected' + ); }); QUnit.test('services can be injected into controllers', function(assert) { let owner = buildOwner(); - owner.register('controller:application', Controller.extend({ - authService: inject.service('auth') - })); + owner.register( + 'controller:application', + Controller.extend({ + authService: inject.service('auth') + }) + ); owner.register('service:auth', Service.extend()); let appController = owner.lookup('controller:application'); let authService = owner.lookup('service:auth'); - assert.equal(authService, appController.get('authService'), 'service.auth is injected'); + assert.equal( + authService, + appController.get('authService'), + 'service.auth is injected' + ); }); diff --git a/packages/ember-runtime/tests/copyable-array/copy-test.js b/packages/ember-runtime/tests/copyable-array/copy-test.js index 31e7cf77910..58b877b149a 100644 --- a/packages/ember-runtime/tests/copyable-array/copy-test.js +++ b/packages/ember-runtime/tests/copyable-array/copy-test.js @@ -5,8 +5,11 @@ class CopyTest extends AbstractTestCase { '@test should return an equivalent copy'() { let obj = this.newObject(); let copy = obj.copy(); - this.assert.ok(this.isEqual(obj, copy), 'old object and new object should be equivalent'); + this.assert.ok( + this.isEqual(obj, copy), + 'old object and new object should be equivalent' + ); } } -runArrayTests('copy', CopyTest, 'CopyableNativeArray', 'CopyableArray'); \ No newline at end of file +runArrayTests('copy', CopyTest, 'CopyableNativeArray', 'CopyableArray'); diff --git a/packages/ember-runtime/tests/core/compare_test.js b/packages/ember-runtime/tests/core/compare_test.js index 0c2adb33bd3..0311f113a56 100644 --- a/packages/ember-runtime/tests/core/compare_test.js +++ b/packages/ember-runtime/tests/core/compare_test.js @@ -13,66 +13,111 @@ Comp.reopenClass({ } }); -moduleFor('Ember.compare()', class extends AbstractTestCase { - beforeEach() { - data[0] = null; - data[1] = false; - data[2] = true; - data[3] = -12; - data[4] = 3.5; - data[5] = 'a string'; - data[6] = 'another string'; - data[7] = 'last string'; - data[8] = [1, 2]; - data[9] = [1, 2, 3]; - data[10] = [1, 3]; - data[11] = { a: 'hash' }; - data[12] = EmberObject.create(); - data[13] = function (a) {return a;}; - data[14] = new Date('2012/01/01'); - data[15] = new Date('2012/06/06'); - } - +moduleFor( + 'Ember.compare()', + class extends AbstractTestCase { + beforeEach() { + data[0] = null; + data[1] = false; + data[2] = true; + data[3] = -12; + data[4] = 3.5; + data[5] = 'a string'; + data[6] = 'another string'; + data[7] = 'last string'; + data[8] = [1, 2]; + data[9] = [1, 2, 3]; + data[10] = [1, 3]; + data[11] = { a: 'hash' }; + data[12] = EmberObject.create(); + data[13] = function(a) { + return a; + }; + data[14] = new Date('2012/01/01'); + data[15] = new Date('2012/06/06'); + } - ['@test ordering should work'](assert) { - let suspect, comparable, failureMessage, suspectIndex, comparableIndex; + ['@test ordering should work'](assert) { + let suspect, comparable, failureMessage, suspectIndex, comparableIndex; - for (suspectIndex = 0; suspectIndex < data.length; suspectIndex++) { - suspect = data[suspectIndex]; + for (suspectIndex = 0; suspectIndex < data.length; suspectIndex++) { + suspect = data[suspectIndex]; - assert.equal(compare(suspect, suspect), 0, suspectIndex + ' should equal itself'); + assert.equal( + compare(suspect, suspect), + 0, + suspectIndex + ' should equal itself' + ); - for (comparableIndex = suspectIndex + 1; comparableIndex < data.length; comparableIndex++) { - comparable = data[comparableIndex]; + for ( + comparableIndex = suspectIndex + 1; + comparableIndex < data.length; + comparableIndex++ + ) { + comparable = data[comparableIndex]; - failureMessage = 'data[' + suspectIndex + '] (' + typeOf(suspect) + - ') should be smaller than data[' + comparableIndex + '] (' + - typeOf(comparable) + ')'; + failureMessage = + 'data[' + + suspectIndex + + '] (' + + typeOf(suspect) + + ') should be smaller than data[' + + comparableIndex + + '] (' + + typeOf(comparable) + + ')'; - assert.equal(compare(suspect, comparable), -1, failureMessage); + assert.equal(compare(suspect, comparable), -1, failureMessage); + } } } - } - ['@test comparables should return values in the range of -1, 0, 1'](assert) { - let negOne = Comp.create({ - val: -1 - }); + ['@test comparables should return values in the range of -1, 0, 1']( + assert + ) { + let negOne = Comp.create({ + val: -1 + }); - let zero = Comp.create({ - val: 0 - }); + let zero = Comp.create({ + val: 0 + }); - let one = Comp.create({ - val: 1 - }); + let one = Comp.create({ + val: 1 + }); - assert.equal(compare(negOne, 'a'), -1, 'First item comparable - returns -1 (not negated)'); - assert.equal(compare(zero, 'b'), 0, 'First item comparable - returns 0 (not negated)'); - assert.equal(compare(one, 'c'), 1, 'First item comparable - returns 1 (not negated)'); + assert.equal( + compare(negOne, 'a'), + -1, + 'First item comparable - returns -1 (not negated)' + ); + assert.equal( + compare(zero, 'b'), + 0, + 'First item comparable - returns 0 (not negated)' + ); + assert.equal( + compare(one, 'c'), + 1, + 'First item comparable - returns 1 (not negated)' + ); - assert.equal(compare('a', negOne), 1, 'Second item comparable - returns -1 (negated)'); - assert.equal(compare('b', zero), 0, 'Second item comparable - returns 0 (negated)'); - assert.equal(compare('c', one), -1, 'Second item comparable - returns 1 (negated)'); + assert.equal( + compare('a', negOne), + 1, + 'Second item comparable - returns -1 (negated)' + ); + assert.equal( + compare('b', zero), + 0, + 'Second item comparable - returns 0 (negated)' + ); + assert.equal( + compare('c', one), + -1, + 'Second item comparable - returns 1 (negated)' + ); + } } -}); +); diff --git a/packages/ember-runtime/tests/core/copy_test.js b/packages/ember-runtime/tests/core/copy_test.js index 3d3fd18ae47..00e8028e085 100644 --- a/packages/ember-runtime/tests/core/copy_test.js +++ b/packages/ember-runtime/tests/core/copy_test.js @@ -1,35 +1,43 @@ import copy from '../../copy'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('Ember Copy Method', class extends AbstractTestCase { - - ['@test Ember.copy null'](assert) { - let obj = { field: null }; - - assert.equal(copy(obj, true).field, null, 'null should still be null'); - } - - ['@test Ember.copy date'](assert) { - let date = new Date(2014, 7, 22); - let dateCopy = copy(date); - - assert.equal(date.getTime(), dateCopy.getTime(), 'dates should be equivalent'); - } - - ['@test Ember.copy null prototype object'](assert) { - let obj = Object.create(null); - - obj.foo = 'bar'; - - assert.equal(copy(obj).foo, 'bar', 'bar should still be bar'); - } - - ['@test Ember.copy Array'](assert) { - let array = [1, null, new Date(2015, 9, 9), 'four']; - let arrayCopy = copy(array); - - assert.deepEqual(array, arrayCopy, 'array content cloned successfully in new array'); - } -}); +moduleFor( + 'Ember Copy Method', + class extends AbstractTestCase { + ['@test Ember.copy null'](assert) { + let obj = { field: null }; + + assert.equal(copy(obj, true).field, null, 'null should still be null'); + } + + ['@test Ember.copy date'](assert) { + let date = new Date(2014, 7, 22); + let dateCopy = copy(date); + assert.equal( + date.getTime(), + dateCopy.getTime(), + 'dates should be equivalent' + ); + } + ['@test Ember.copy null prototype object'](assert) { + let obj = Object.create(null); + + obj.foo = 'bar'; + + assert.equal(copy(obj).foo, 'bar', 'bar should still be bar'); + } + + ['@test Ember.copy Array'](assert) { + let array = [1, null, new Date(2015, 9, 9), 'four']; + let arrayCopy = copy(array); + + assert.deepEqual( + array, + arrayCopy, + 'array content cloned successfully in new array' + ); + } + } +); diff --git a/packages/ember-runtime/tests/core/isEqual_test.js b/packages/ember-runtime/tests/core/isEqual_test.js index b9cb010521e..3d7b6bd2085 100644 --- a/packages/ember-runtime/tests/core/isEqual_test.js +++ b/packages/ember-runtime/tests/core/isEqual_test.js @@ -1,40 +1,75 @@ import isEqual from '../../is-equal'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('isEqual', class extends AbstractTestCase { - - ['@test undefined and null'](assert) { - assert.ok(isEqual(undefined, undefined), 'undefined is equal to undefined'); - assert.ok(!isEqual(undefined, null), 'undefined is not equal to null'); - assert.ok(isEqual(null, null), 'null is equal to null'); - assert.ok(!isEqual(null, undefined), 'null is not equal to undefined'); - } - - ['@test strings should be equal'](assert) { - assert.ok(!isEqual('Hello', 'Hi'), 'different Strings are unequal'); - assert.ok(isEqual('Hello', 'Hello'), 'same Strings are equal'); - } - - ['@test numericals should be equal'](assert) { - assert.ok(isEqual(24, 24), 'same numbers are equal'); - assert.ok(!isEqual(24, 21), 'different numbers are inequal'); - } - - ['@test dates should be equal'](assert) { - assert.ok(isEqual(new Date(1985, 7, 22), new Date(1985, 7, 22)), 'same dates are equal'); - assert.ok(!isEqual(new Date(2014, 7, 22), new Date(1985, 7, 22)), 'different dates are not equal'); - } - - ['@test array should be equal'](assert) { - // NOTE: We don't test for array contents -- that would be too expensive. - assert.ok(!isEqual([1, 2], [1, 2]), 'two array instances with the same values should not be equal'); - assert.ok(!isEqual([1, 2], [1]), 'two array instances with different values should not be equal'); - } - - ['@test first object implements isEqual should use it'](assert) { - assert.ok(isEqual({ isEqual() { return true; } }, null), 'should return true always'); - - let obj = { isEqual() { return false; } }; - assert.equal(isEqual(obj, obj), false, 'should return false because isEqual returns false'); +moduleFor( + 'isEqual', + class extends AbstractTestCase { + ['@test undefined and null'](assert) { + assert.ok( + isEqual(undefined, undefined), + 'undefined is equal to undefined' + ); + assert.ok(!isEqual(undefined, null), 'undefined is not equal to null'); + assert.ok(isEqual(null, null), 'null is equal to null'); + assert.ok(!isEqual(null, undefined), 'null is not equal to undefined'); + } + + ['@test strings should be equal'](assert) { + assert.ok(!isEqual('Hello', 'Hi'), 'different Strings are unequal'); + assert.ok(isEqual('Hello', 'Hello'), 'same Strings are equal'); + } + + ['@test numericals should be equal'](assert) { + assert.ok(isEqual(24, 24), 'same numbers are equal'); + assert.ok(!isEqual(24, 21), 'different numbers are inequal'); + } + + ['@test dates should be equal'](assert) { + assert.ok( + isEqual(new Date(1985, 7, 22), new Date(1985, 7, 22)), + 'same dates are equal' + ); + assert.ok( + !isEqual(new Date(2014, 7, 22), new Date(1985, 7, 22)), + 'different dates are not equal' + ); + } + + ['@test array should be equal'](assert) { + // NOTE: We don't test for array contents -- that would be too expensive. + assert.ok( + !isEqual([1, 2], [1, 2]), + 'two array instances with the same values should not be equal' + ); + assert.ok( + !isEqual([1, 2], [1]), + 'two array instances with different values should not be equal' + ); + } + + ['@test first object implements isEqual should use it'](assert) { + assert.ok( + isEqual( + { + isEqual() { + return true; + } + }, + null + ), + 'should return true always' + ); + + let obj = { + isEqual() { + return false; + } + }; + assert.equal( + isEqual(obj, obj), + false, + 'should return false because isEqual returns false' + ); + } } -}); +); diff --git a/packages/ember-runtime/tests/core/is_array_test.js b/packages/ember-runtime/tests/core/is_array_test.js index c3aeb407cdd..79b20523485 100644 --- a/packages/ember-runtime/tests/core/is_array_test.js +++ b/packages/ember-runtime/tests/core/is_array_test.js @@ -6,40 +6,44 @@ import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; const global = this; -moduleFor('Ember Type Checking', class extends AbstractTestCase { - - ['@test Ember.isArray'](assert) { - let numarray = [1, 2, 3]; - let number = 23; - let strarray = ['Hello', 'Hi']; - let string = 'Hello'; - let object = {}; - let length = { length: 12 }; - let strangeLength = { length: 'yes' }; - let fn = function() {}; - let arrayProxy = ArrayProxy.create({ content: emberA() }); - - assert.equal(isArray(numarray), true, '[1,2,3]'); - assert.equal(isArray(number), false, '23'); - assert.equal(isArray(strarray), true, '["Hello", "Hi"]'); - assert.equal(isArray(string), false, '"Hello"'); - assert.equal(isArray(object), false, '{}'); - assert.equal(isArray(length), true, '{ length: 12 }'); - assert.equal(isArray(strangeLength), false, '{ length: "yes" }'); - assert.equal(isArray(global), false, 'global'); - assert.equal(isArray(fn), false, 'function() {}'); - assert.equal(isArray(arrayProxy), true, '[]'); - } +moduleFor( + 'Ember Type Checking', + class extends AbstractTestCase { + ['@test Ember.isArray'](assert) { + let numarray = [1, 2, 3]; + let number = 23; + let strarray = ['Hello', 'Hi']; + let string = 'Hello'; + let object = {}; + let length = { length: 12 }; + let strangeLength = { length: 'yes' }; + let fn = function() {}; + let arrayProxy = ArrayProxy.create({ content: emberA() }); + assert.equal(isArray(numarray), true, '[1,2,3]'); + assert.equal(isArray(number), false, '23'); + assert.equal(isArray(strarray), true, '["Hello", "Hi"]'); + assert.equal(isArray(string), false, '"Hello"'); + assert.equal(isArray(object), false, '{}'); + assert.equal(isArray(length), true, '{ length: 12 }'); + assert.equal(isArray(strangeLength), false, '{ length: "yes" }'); + assert.equal(isArray(global), false, 'global'); + assert.equal(isArray(fn), false, 'function() {}'); + assert.equal(isArray(arrayProxy), true, '[]'); + } - ['@test Ember.isArray(fileList)'](assert) { - if (environment.window && typeof environment.window.FileList === 'function') { - let fileListElement = document.createElement('input'); - fileListElement.type = 'file'; - let fileList = fileListElement.files; - assert.equal(isArray(fileList), false, 'fileList'); - } else { - assert.ok(true, 'FileList is not present on window'); + ['@test Ember.isArray(fileList)'](assert) { + if ( + environment.window && + typeof environment.window.FileList === 'function' + ) { + let fileListElement = document.createElement('input'); + fileListElement.type = 'file'; + let fileList = fileListElement.files; + assert.equal(isArray(fileList), false, 'fileList'); + } else { + assert.ok(true, 'FileList is not present on window'); + } } } -}); +); diff --git a/packages/ember-runtime/tests/core/is_empty_test.js b/packages/ember-runtime/tests/core/is_empty_test.js index 8ac6d71980f..f9198825e55 100644 --- a/packages/ember-runtime/tests/core/is_empty_test.js +++ b/packages/ember-runtime/tests/core/is_empty_test.js @@ -3,11 +3,17 @@ import ArrayProxy from '../../system/array_proxy'; import { A as emberA } from '../../mixins/array'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('Ember.isEmpty', class extends AbstractTestCase { - ['@test Ember.isEmpty'](assert) { - let arrayProxy = ArrayProxy.create({ content: emberA() }); +moduleFor( + 'Ember.isEmpty', + class extends AbstractTestCase { + ['@test Ember.isEmpty'](assert) { + let arrayProxy = ArrayProxy.create({ content: emberA() }); - assert.equal(true, isEmpty(arrayProxy), 'for an ArrayProxy that has empty content'); + assert.equal( + true, + isEmpty(arrayProxy), + 'for an ArrayProxy that has empty content' + ); + } } -}); - +); diff --git a/packages/ember-runtime/tests/core/type_of_test.js b/packages/ember-runtime/tests/core/type_of_test.js index 51449fda19f..bd454884c5b 100644 --- a/packages/ember-runtime/tests/core/type_of_test.js +++ b/packages/ember-runtime/tests/core/type_of_test.js @@ -3,50 +3,59 @@ import EmberObject from '../../system/object'; import { environment } from 'ember-environment'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('Ember Type Checking', class extends AbstractTestCase { - ['@test Ember.typeOf'](assert) { - let MockedDate = function() { }; - MockedDate.prototype = new Date(); - - let mockedDate = new MockedDate(); - let date = new Date(); - let error = new Error('boum'); - let object = { a: 'b' }; - let a = null; - let arr = [1, 2, 3]; - let obj = {}; - let instance = EmberObject.create({ method() {} }); - - assert.equal(typeOf(), 'undefined', 'undefined'); - assert.equal(typeOf(null), 'null', 'null'); - assert.equal(typeOf('Cyril'), 'string', 'Cyril'); - assert.equal(typeOf(101), 'number', '101'); - assert.equal(typeOf(true), 'boolean', 'true'); - assert.equal(typeOf([1, 2, 90]), 'array', '[1,2,90]'); - assert.equal(typeOf(/abc/), 'regexp', '/abc/'); - assert.equal(typeOf(date), 'date', 'new Date()'); - assert.equal(typeOf(mockedDate), 'date', 'mocked date'); - assert.equal(typeOf(error), 'error', 'error'); - assert.equal(typeOf(object), 'object', 'object'); - assert.equal(typeOf(undefined), 'undefined', 'item of type undefined'); - assert.equal(typeOf(a), 'null', 'item of type null'); - assert.equal(typeOf(arr), 'array', 'item of type array'); - assert.equal(typeOf(obj), 'object', 'item of type object'); - assert.equal(typeOf(instance), 'instance', 'item of type instance'); - assert.equal(typeOf(instance.method), 'function', 'item of type function'); - assert.equal(typeOf(EmberObject.extend()), 'class', 'item of type class'); - assert.equal(typeOf(new Error()), 'error', 'item of type error'); - } - - - ['@test Ember.typeOf(fileList)'](assert) { - if (environment.window && typeof environment.window.FileList === 'function') { - let fileListElement = document.createElement('input'); - fileListElement.type = 'file'; - let fileList = fileListElement.files; - assert.equal(typeOf(fileList), 'filelist', 'item of type filelist'); - } else { - assert.ok(true, 'FileList is not present on window'); +moduleFor( + 'Ember Type Checking', + class extends AbstractTestCase { + ['@test Ember.typeOf'](assert) { + let MockedDate = function() {}; + MockedDate.prototype = new Date(); + + let mockedDate = new MockedDate(); + let date = new Date(); + let error = new Error('boum'); + let object = { a: 'b' }; + let a = null; + let arr = [1, 2, 3]; + let obj = {}; + let instance = EmberObject.create({ method() {} }); + + assert.equal(typeOf(), 'undefined', 'undefined'); + assert.equal(typeOf(null), 'null', 'null'); + assert.equal(typeOf('Cyril'), 'string', 'Cyril'); + assert.equal(typeOf(101), 'number', '101'); + assert.equal(typeOf(true), 'boolean', 'true'); + assert.equal(typeOf([1, 2, 90]), 'array', '[1,2,90]'); + assert.equal(typeOf(/abc/), 'regexp', '/abc/'); + assert.equal(typeOf(date), 'date', 'new Date()'); + assert.equal(typeOf(mockedDate), 'date', 'mocked date'); + assert.equal(typeOf(error), 'error', 'error'); + assert.equal(typeOf(object), 'object', 'object'); + assert.equal(typeOf(undefined), 'undefined', 'item of type undefined'); + assert.equal(typeOf(a), 'null', 'item of type null'); + assert.equal(typeOf(arr), 'array', 'item of type array'); + assert.equal(typeOf(obj), 'object', 'item of type object'); + assert.equal(typeOf(instance), 'instance', 'item of type instance'); + assert.equal( + typeOf(instance.method), + 'function', + 'item of type function' + ); + assert.equal(typeOf(EmberObject.extend()), 'class', 'item of type class'); + assert.equal(typeOf(new Error()), 'error', 'item of type error'); + } + + ['@test Ember.typeOf(fileList)'](assert) { + if ( + environment.window && + typeof environment.window.FileList === 'function' + ) { + let fileListElement = document.createElement('input'); + fileListElement.type = 'file'; + let fileList = fileListElement.files; + assert.equal(typeOf(fileList), 'filelist', 'item of type filelist'); + } else { + assert.ok(true, 'FileList is not present on window'); + } } } -}); +); diff --git a/packages/ember-runtime/tests/ext/function_test.js b/packages/ember-runtime/tests/ext/function_test.js index a4d94bd64cd..fbbc5cb2604 100644 --- a/packages/ember-runtime/tests/ext/function_test.js +++ b/packages/ember-runtime/tests/ext/function_test.js @@ -6,20 +6,25 @@ import Evented from '../../mixins/evented'; QUnit.module('Function.prototype.observes() helper'); -testBoth('global observer helper takes multiple params', function(get, set, assert) { +testBoth('global observer helper takes multiple params', function( + get, + set, + assert +) { if (!ENV.EXTEND_PROTOTYPES.Function) { - assert.ok('undefined' === typeof Function.prototype.observes, 'Function.prototype helper disabled'); + assert.ok( + 'undefined' === typeof Function.prototype.observes, + 'Function.prototype helper disabled' + ); return; } let MyMixin = Mixin.create({ - count: 0, foo: function() { set(this, 'count', get(this, 'count') + 1); }.observes('bar', 'baz') - }); let obj = mixin({}, MyMixin); @@ -32,29 +37,41 @@ testBoth('global observer helper takes multiple params', function(get, set, asse QUnit.module('Function.prototype.on() helper'); -testBoth('sets up an event listener, and can trigger the function on multiple events', function(get, set, assert) { - if (!ENV.EXTEND_PROTOTYPES.Function) { - assert.ok('undefined' === typeof Function.prototype.on, 'Function.prototype helper disabled'); - return; +testBoth( + 'sets up an event listener, and can trigger the function on multiple events', + function(get, set, assert) { + if (!ENV.EXTEND_PROTOTYPES.Function) { + assert.ok( + 'undefined' === typeof Function.prototype.on, + 'Function.prototype helper disabled' + ); + return; + } + + let MyMixin = Mixin.create({ + count: 0, + + foo: function() { + set(this, 'count', get(this, 'count') + 1); + }.on('bar', 'baz') + }); + + let obj = mixin({}, Evented, MyMixin); + assert.equal( + get(obj, 'count'), + 0, + 'should not invoke listener immediately' + ); + + obj.trigger('bar'); + obj.trigger('baz'); + assert.equal( + get(obj, 'count'), + 2, + 'should invoke listeners when events trigger' + ); } - - let MyMixin = Mixin.create({ - - count: 0, - - foo: function() { - set(this, 'count', get(this, 'count') + 1); - }.on('bar', 'baz') - - }); - - let obj = mixin({}, Evented, MyMixin); - assert.equal(get(obj, 'count'), 0, 'should not invoke listener immediately'); - - obj.trigger('bar'); - obj.trigger('baz'); - assert.equal(get(obj, 'count'), 2, 'should invoke listeners when events trigger'); -}); +); testBoth('can be chained with observes', function(get, set, assert) { if (!ENV.EXTEND_PROTOTYPES.Function) { @@ -63,12 +80,13 @@ testBoth('can be chained with observes', function(get, set, assert) { } let MyMixin = Mixin.create({ - count: 0, bay: 'bay', foo: function() { set(this, 'count', get(this, 'count') + 1); - }.observes('bay').on('bar') + } + .observes('bay') + .on('bar') }); let obj = mixin({}, Evented, MyMixin); @@ -83,7 +101,10 @@ QUnit.module('Function.prototype.property() helper'); testBoth('sets up a ComputedProperty', function(get, set, assert) { if (!ENV.EXTEND_PROTOTYPES.Function) { - assert.ok('undefined' === typeof Function.prototype.property, 'Function.prototype helper disabled'); + assert.ok( + 'undefined' === typeof Function.prototype.property, + 'Function.prototype helper disabled' + ); return; } @@ -96,11 +117,23 @@ testBoth('sets up a ComputedProperty', function(get, set, assert) { }); let obj = MyClass.create({ firstName: 'Fred', lastName: 'Flinstone' }); - assert.equal(get(obj, 'fullName'), 'Fred Flinstone', 'should return the computed value'); + assert.equal( + get(obj, 'fullName'), + 'Fred Flinstone', + 'should return the computed value' + ); set(obj, 'firstName', 'Wilma'); - assert.equal(get(obj, 'fullName'), 'Wilma Flinstone', 'should return the new computed value'); + assert.equal( + get(obj, 'fullName'), + 'Wilma Flinstone', + 'should return the new computed value' + ); set(obj, 'lastName', ''); - assert.equal(get(obj, 'fullName'), 'Wilma ', 'should return the new computed value'); + assert.equal( + get(obj, 'fullName'), + 'Wilma ', + 'should return the new computed value' + ); }); diff --git a/packages/ember-runtime/tests/ext/rsvp_test.js b/packages/ember-runtime/tests/ext/rsvp_test.js index 3f2e0d266c1..34765b86131 100644 --- a/packages/ember-runtime/tests/ext/rsvp_test.js +++ b/packages/ember-runtime/tests/ext/rsvp_test.js @@ -1,10 +1,4 @@ -import { - setOnerror, - getOnerror, - run, - schedule, - next, -} from 'ember-metal'; +import { setOnerror, getOnerror, run, schedule, next } from 'ember-metal'; import RSVP from '../../ext/rsvp'; import { isTesting, setTesting } from 'ember-debug'; @@ -16,20 +10,23 @@ QUnit.module('Ember.RSVP', { } }); -QUnit.test('Ensure that errors thrown from within a promise are sent to the console', function(assert) { - let error = new Error('Error thrown in a promise for testing purposes.'); +QUnit.test( + 'Ensure that errors thrown from within a promise are sent to the console', + function(assert) { + let error = new Error('Error thrown in a promise for testing purposes.'); - try { - run(function() { - new RSVP.Promise(function() { - throw error; + try { + run(function() { + new RSVP.Promise(function() { + throw error; + }); }); - }); - assert.ok(false, 'expected assertion to be thrown'); - } catch (e) { - assert.equal(e, error, 'error was re-thrown'); + assert.ok(false, 'expected assertion to be thrown'); + } catch (e) { + assert.equal(e, error, 'error was re-thrown'); + } } -}); +); QUnit.test('TransitionAborted errors are not re-thrown', function(assert) { assert.expect(1); @@ -70,61 +67,83 @@ QUnit.test('Can reject with no arguments', function(assert) { assert.ok(true); }); -QUnit.test('rejections like jqXHR which have errorThrown property work', function(assert) { - assert.expect(2); - - let wasEmberTesting = isTesting(); - let wasOnError = getOnerror(); - - try { - setTesting(false); - setOnerror(error => { - assert.equal(error, actualError, 'expected the real error on the jqXHR'); - assert.equal(error.__reason_with_error_thrown__, jqXHR, 'also retains a helpful reference to the rejection reason'); - }); +QUnit.test( + 'rejections like jqXHR which have errorThrown property work', + function(assert) { + assert.expect(2); + + let wasEmberTesting = isTesting(); + let wasOnError = getOnerror(); + + try { + setTesting(false); + setOnerror(error => { + assert.equal( + error, + actualError, + 'expected the real error on the jqXHR' + ); + assert.equal( + error.__reason_with_error_thrown__, + jqXHR, + 'also retains a helpful reference to the rejection reason' + ); + }); - let actualError = new Error('OMG what really happened'); - let jqXHR = { - errorThrown: actualError - }; + let actualError = new Error('OMG what really happened'); + let jqXHR = { + errorThrown: actualError + }; - run(RSVP, 'reject', jqXHR); - } finally { - setOnerror(wasOnError); - setTesting(wasEmberTesting); + run(RSVP, 'reject', jqXHR); + } finally { + setOnerror(wasOnError); + setTesting(wasEmberTesting); + } } -}); - -QUnit.test('rejections where the errorThrown is a string should wrap the sting in an error object', function(assert) { - assert.expect(2); - - let wasEmberTesting = isTesting(); - let wasOnError = getOnerror(); - - try { - setTesting(false); - setOnerror(error => { - assert.equal(error.message, actualError, 'expected the real error on the jqXHR'); - assert.equal(error.__reason_with_error_thrown__, jqXHR, 'also retains a helpful reference to the rejection reason'); - }); +); + +QUnit.test( + 'rejections where the errorThrown is a string should wrap the sting in an error object', + function(assert) { + assert.expect(2); + + let wasEmberTesting = isTesting(); + let wasOnError = getOnerror(); + + try { + setTesting(false); + setOnerror(error => { + assert.equal( + error.message, + actualError, + 'expected the real error on the jqXHR' + ); + assert.equal( + error.__reason_with_error_thrown__, + jqXHR, + 'also retains a helpful reference to the rejection reason' + ); + }); - let actualError = 'OMG what really happened'; - let jqXHR = { - errorThrown: actualError - }; + let actualError = 'OMG what really happened'; + let jqXHR = { + errorThrown: actualError + }; - run(RSVP, 'reject', jqXHR); - } finally { - setOnerror(wasOnError); - setTesting(wasEmberTesting); + run(RSVP, 'reject', jqXHR); + } finally { + setOnerror(wasOnError); + setTesting(wasEmberTesting); + } } -}); +); -QUnit.test('rejections can be serialized to JSON', function (assert) { +QUnit.test('rejections can be serialized to JSON', function(assert) { assert.expect(2); let wasEmberTesting = isTesting(); - let wasOnError = getOnerror(); + let wasOnError = getOnerror(); try { setTesting(false); @@ -163,28 +182,35 @@ QUnit.test('unambigiously unhandled rejection', function(assert) { QUnit.test('sync handled', function(assert) { run(function() { - RSVP.Promise.reject(reason).catch(function() { }); + RSVP.Promise.reject(reason).catch(function() {}); }); // handled, we shouldn't need to assert. assert.ok(true, 'reached end of test'); }); -QUnit.test('handled within the same micro-task (via Ember.RVP.Promise)', function(assert) { - run(function() { - let rejection = RSVP.Promise.reject(reason); - RSVP.Promise.resolve(1).then(() => rejection.catch(function() { })); - }); // handled, we shouldn't need to assert. - assert.ok(true, 'reached end of test'); -}); +QUnit.test( + 'handled within the same micro-task (via Ember.RVP.Promise)', + function(assert) { + run(function() { + let rejection = RSVP.Promise.reject(reason); + RSVP.Promise.resolve(1).then(() => rejection.catch(function() {})); + }); // handled, we shouldn't need to assert. + assert.ok(true, 'reached end of test'); + } +); -QUnit.test('handled within the same micro-task (via direct run-loop)', function(assert) { +QUnit.test('handled within the same micro-task (via direct run-loop)', function( + assert +) { run(function() { let rejection = RSVP.Promise.reject(reason); - schedule('afterRender', () => rejection.catch(function() { })); + schedule('afterRender', () => rejection.catch(function() {})); }); // handled, we shouldn't need to assert. assert.ok(true, 'reached end of test'); }); -QUnit.test('handled in the next microTask queue flush (next)', function(assert) { +QUnit.test('handled in the next microTask queue flush (next)', function( + assert +) { assert.expect(2); let done = assert.async(); @@ -193,7 +219,7 @@ QUnit.test('handled in the next microTask queue flush (next)', function(assert) let rejection = RSVP.Promise.reject(reason); next(() => { - rejection.catch(function() { }); + rejection.catch(function() {}); assert.ok(true, 'reached end of test'); done(); }); @@ -204,44 +230,52 @@ QUnit.test('handled in the next microTask queue flush (next)', function(assert) // this is very likely an issue. }); -QUnit.test('handled in the same microTask Queue flush do to data locality', function(assert) { - // an ambiguous scenario, this may or may not assert - // it depends on the locality of `user#1` - let store = { - find() { - return RSVP.Promise.resolve(1); - } - }; - run(function() { - let rejection = RSVP.Promise.reject(reason); - store.find('user', 1).then(() => rejection.catch(function() { })); - }); - - assert.ok(true, 'reached end of test'); -}); - -QUnit.test('handled in a different microTask Queue flush do to data locality', function(assert) { - let done = assert.async(); - // an ambiguous scenario, this may or may not assert - // it depends on the locality of `user#1` - let store = { - find() { - return ajax(); - } - }; - assert.throws(function() { +QUnit.test( + 'handled in the same microTask Queue flush do to data locality', + function(assert) { + // an ambiguous scenario, this may or may not assert + // it depends on the locality of `user#1` + let store = { + find() { + return RSVP.Promise.resolve(1); + } + }; run(function() { let rejection = RSVP.Promise.reject(reason); - store.find('user', 1).then(() => { - rejection.catch(function() { }); - assert.ok(true, 'reached end of test'); - done(); - }); + store.find('user', 1).then(() => rejection.catch(function() {})); }); - }, reason); -}); -QUnit.test('handled in the next microTask queue flush (ajax example)', function(assert) { + assert.ok(true, 'reached end of test'); + } +); + +QUnit.test( + 'handled in a different microTask Queue flush do to data locality', + function(assert) { + let done = assert.async(); + // an ambiguous scenario, this may or may not assert + // it depends on the locality of `user#1` + let store = { + find() { + return ajax(); + } + }; + assert.throws(function() { + run(function() { + let rejection = RSVP.Promise.reject(reason); + store.find('user', 1).then(() => { + rejection.catch(function() {}); + assert.ok(true, 'reached end of test'); + done(); + }); + }); + }, reason); + } +); + +QUnit.test('handled in the next microTask queue flush (ajax example)', function( + assert +) { let done = assert.async(); assert.throws(function() { diff --git a/packages/ember-runtime/tests/helpers/array.js b/packages/ember-runtime/tests/helpers/array.js index 3f4848c4e31..731c7cfe727 100644 --- a/packages/ember-runtime/tests/helpers/array.js +++ b/packages/ember-runtime/tests/helpers/array.js @@ -1,8 +1,5 @@ import ArrayProxy from '../../system/array_proxy'; -import EmberArray, { - A as emberA, - MutableArray -} from '../../mixins/array'; +import EmberArray, { A as emberA, MutableArray } from '../../mixins/array'; import { generateGuid, guidFor } from 'ember-utils'; import { get, @@ -54,7 +51,7 @@ const ArrayTestsObserverClass = EmberObject.extend({ observe(obj, ...keys) { if (obj.addObserver) { - let loc = keys.length; + let loc = keys.length; while (--loc >= 0) { obj.addObserver(keys[loc], this, 'propertyDidChange'); @@ -76,18 +73,28 @@ const ArrayTestsObserverClass = EmberObject.extend({ }, propertyDidChange(target, key, value) { - if (this._keys[key] === undefined) { this._keys[key] = 0; } + if (this._keys[key] === undefined) { + this._keys[key] = 0; + } this._keys[key]++; this._values[key] = value; }, arrayWillChange() { - QUnit.config.current.assert.equal(this._before, null, 'should only call once'); + QUnit.config.current.assert.equal( + this._before, + null, + 'should only call once' + ); this._before = Array.prototype.slice.call(arguments); }, arrayDidChange() { - QUnit.config.current.assert.equal(this._after, null, 'should only call once'); + QUnit.config.current.assert.equal( + this._after, + null, + 'should only call once' + ); this._after = Array.prototype.slice.call(arguments); }, @@ -233,7 +240,6 @@ const TestArray = EmberObject.extend(EmberArray, { enumerable can impl this API. */ const TestMutableArray = EmberObject.extend(MutableArray, { - _content: null, init(ary = []) { @@ -243,7 +249,7 @@ const TestMutableArray = EmberObject.extend(MutableArray, { replace(idx, amt, objects) { let args = objects ? objects.slice() : []; let removeAmt = amt; - let addAmt = args.length; + let addAmt = args.length; arrayContentWillChange(this, idx, removeAmt, addAmt); @@ -301,8 +307,8 @@ class EmberArrayHelpers extends MutableArrayHelpers { export function runArrayTests(name, Tests, ...types) { if (types.length > 0) { - types.forEach((type) => { - switch(type) { + types.forEach(type => { + switch (type) { case 'ArrayProxy': moduleFor(`ArrayProxy: ${name}`, Tests, ArrayProxyHelpers); break; diff --git a/packages/ember-runtime/tests/inject_test.js b/packages/ember-runtime/tests/inject_test.js index a18c884b8b1..31605c56838 100644 --- a/packages/ember-runtime/tests/inject_test.js +++ b/packages/ember-runtime/tests/inject_test.js @@ -3,9 +3,7 @@ import { InjectedProperty } from 'ember-metal'; import { DEBUG } from 'ember-env-flags'; import inject from '../inject'; -import { - createInjectionHelper -} from '../inject'; +import { createInjectionHelper } from '../inject'; import EmberObject from '../system/object'; import { buildOwner } from 'internal-test-helpers'; @@ -20,7 +18,9 @@ QUnit.test('calling `inject` directly should error', function() { if (!EmberDev.runningProdBuild) { // this check is done via an assertion which is stripped from // production builds - QUnit.test('injection type validation is run when first looked up', function(assert) { + QUnit.test('injection type validation is run when first looked up', function( + assert + ) { createInjectionHelper('foo', function() { assert.ok(true, 'should call validation method'); }); @@ -40,32 +40,48 @@ if (!EmberDev.runningProdBuild) { owner.lookup('foo:main'); }); - QUnit.test('attempting to inject a nonexistent container key should error', function(assert) { - let owner = buildOwner(); - let AnObject = EmberObject.extend({ - foo: new InjectedProperty('bar', 'baz') - }); + QUnit.test( + 'attempting to inject a nonexistent container key should error', + function(assert) { + let owner = buildOwner(); + let AnObject = EmberObject.extend({ + foo: new InjectedProperty('bar', 'baz') + }); - owner.register('foo:main', AnObject); + owner.register('foo:main', AnObject); - assert.throws(() => { - owner.lookup('foo:main'); - }, /Attempting to inject an unknown injection: 'bar:baz'/); - }); + assert.throws(() => { + owner.lookup('foo:main'); + }, /Attempting to inject an unknown injection: 'bar:baz'/); + } + ); } if (DEBUG) { - QUnit.test('factories should return a list of lazy injection full names', function(assert) { - let AnObject = EmberObject.extend({ - foo: new InjectedProperty('foo', 'bar'), - bar: new InjectedProperty('quux') - }); + QUnit.test( + 'factories should return a list of lazy injection full names', + function(assert) { + let AnObject = EmberObject.extend({ + foo: new InjectedProperty('foo', 'bar'), + bar: new InjectedProperty('quux') + }); - assert.deepEqual( - AnObject._lazyInjections(), - { - 'foo': { specifier: 'foo:bar', source: undefined, namespace: undefined }, - 'bar': { specifier: 'quux:bar', source: undefined, namespace: undefined } - }, 'should return injected container keys'); - }); + assert.deepEqual( + AnObject._lazyInjections(), + { + foo: { + specifier: 'foo:bar', + source: undefined, + namespace: undefined + }, + bar: { + specifier: 'quux:bar', + source: undefined, + namespace: undefined + } + }, + 'should return injected container keys' + ); + } + ); } diff --git a/packages/ember-runtime/tests/legacy_1x/mixins/observable/chained_test.js b/packages/ember-runtime/tests/legacy_1x/mixins/observable/chained_test.js index b5b432206a3..3c2144e4e7d 100644 --- a/packages/ember-runtime/tests/legacy_1x/mixins/observable/chained_test.js +++ b/packages/ember-runtime/tests/legacy_1x/mixins/observable/chained_test.js @@ -14,41 +14,61 @@ import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; * changed obj.addObserver() to addObserver() */ -moduleFor('Ember.Observable - Observing with @each', class extends AbstractTestCase{ +moduleFor( + 'Ember.Observable - Observing with @each', + class extends AbstractTestCase { + ['@test chained observers on enumerable properties are triggered when the observed property of any item changes']( + assert + ) { + let family = EmberObject.create({ momma: null }); + let momma = EmberObject.create({ children: [] }); - ['@test chained observers on enumerable properties are triggered when the observed property of any item changes'](assert) { - let family = EmberObject.create({ momma: null }); - let momma = EmberObject.create({ children: [] }); + let child1 = EmberObject.create({ name: 'Bartholomew' }); + let child2 = EmberObject.create({ name: 'Agnes' }); + let child3 = EmberObject.create({ name: 'Dan' }); + let child4 = EmberObject.create({ name: 'Nancy' }); - let child1 = EmberObject.create({ name: 'Bartholomew' }); - let child2 = EmberObject.create({ name: 'Agnes' }); - let child3 = EmberObject.create({ name: 'Dan' }); - let child4 = EmberObject.create({ name: 'Nancy' }); + set(family, 'momma', momma); + set(momma, 'children', emberA([child1, child2, child3])); - set(family, 'momma', momma); - set(momma, 'children', emberA([child1, child2, child3])); + let observerFiredCount = 0; + addObserver(family, 'momma.children.@each.name', this, function() { + observerFiredCount++; + }); - let observerFiredCount = 0; - addObserver(family, 'momma.children.@each.name', this, function() { - observerFiredCount++; - }); + observerFiredCount = 0; + run(() => get(momma, 'children').setEach('name', 'Juan')); + assert.equal( + observerFiredCount, + 3, + 'observer fired after changing child names' + ); - observerFiredCount = 0; - run(() => get(momma, 'children').setEach('name', 'Juan')); - assert.equal(observerFiredCount, 3, 'observer fired after changing child names'); + observerFiredCount = 0; + run(() => get(momma, 'children').pushObject(child4)); + assert.equal( + observerFiredCount, + 1, + 'observer fired after adding a new item' + ); - observerFiredCount = 0; - run(() => get(momma, 'children').pushObject(child4)); - assert.equal(observerFiredCount, 1, 'observer fired after adding a new item'); + observerFiredCount = 0; + run(() => set(child4, 'name', 'Herbert')); + assert.equal( + observerFiredCount, + 1, + 'observer fired after changing property on new object' + ); - observerFiredCount = 0; - run(() => set(child4, 'name', 'Herbert')); - assert.equal(observerFiredCount, 1, 'observer fired after changing property on new object'); + set(momma, 'children', []); - set(momma, 'children', []); - - observerFiredCount = 0; - run(() => set(child1, 'name', 'Hanna')); - assert.equal(observerFiredCount, 0, 'observer did not fire after removing changing property on a removed object'); + observerFiredCount = 0; + run(() => set(child1, 'name', 'Hanna')); + assert.equal( + observerFiredCount, + 0, + 'observer did not fire after removing changing property on a removed object' + ); + } } -}); \ No newline at end of file +); diff --git a/packages/ember-runtime/tests/legacy_1x/mixins/observable/observable_test.js b/packages/ember-runtime/tests/legacy_1x/mixins/observable/observable_test.js index 9f0c44307a5..66753082a9a 100644 --- a/packages/ember-runtime/tests/legacy_1x/mixins/observable/observable_test.js +++ b/packages/ember-runtime/tests/legacy_1x/mixins/observable/observable_test.js @@ -40,102 +40,124 @@ var originalLookup = context.lookup; // GET() // -moduleFor('object.get()', class extends AbstractTestCase { - - beforeEach() { - object = ObservableObject.extend(Observable, { - computed: computed(function() { return 'value'; }).volatile(), - method() { return 'value'; }, - unknownProperty(key) { - this.lastUnknownProperty = key; - return 'unknown'; - } - }).create({ - normal: 'value', - numberVal: 24, - toggleVal: true, - nullProperty: null - }); - } +moduleFor( + 'object.get()', + class extends AbstractTestCase { + beforeEach() { + object = ObservableObject.extend(Observable, { + computed: computed(function() { + return 'value'; + }).volatile(), + method() { + return 'value'; + }, + unknownProperty(key) { + this.lastUnknownProperty = key; + return 'unknown'; + } + }).create({ + normal: 'value', + numberVal: 24, + toggleVal: true, + nullProperty: null + }); + } - ['@test should get normal properties'](assert) { - assert.equal(object.get('normal'), 'value'); - } + ['@test should get normal properties'](assert) { + assert.equal(object.get('normal'), 'value'); + } - ['@test should call computed properties and return their result'](assert) { - assert.equal(object.get('computed'), 'value'); - } + ['@test should call computed properties and return their result'](assert) { + assert.equal(object.get('computed'), 'value'); + } - ['@test should return the function for a non-computed property'](assert) { - var value = object.get('method'); - assert.equal(typeof value, 'function'); - } + ['@test should return the function for a non-computed property'](assert) { + var value = object.get('method'); + assert.equal(typeof value, 'function'); + } - ['@test should return null when property value is null'](assert) { - assert.equal(object.get('nullProperty'), null); - } + ['@test should return null when property value is null'](assert) { + assert.equal(object.get('nullProperty'), null); + } - ['@test should call unknownProperty when value is undefined'](assert) { - assert.equal(object.get('unknown'), 'unknown'); - assert.equal(object.lastUnknownProperty, 'unknown'); + ['@test should call unknownProperty when value is undefined'](assert) { + assert.equal(object.get('unknown'), 'unknown'); + assert.equal(object.lastUnknownProperty, 'unknown'); + } } -}); +); // .......................................................... // Ember.GET() // -moduleFor('Ember.get()', class extends AbstractTestCase { - beforeEach() { - objectA = ObservableObject.extend({ - computed: computed(function() { return 'value'; }).volatile(), - method() { return 'value'; }, - unknownProperty(key) { - this.lastUnknownProperty = key; - return 'unknown'; - } - }).create({ - normal: 'value', - numberVal: 24, - toggleVal: true, - nullProperty: null - }); +moduleFor( + 'Ember.get()', + class extends AbstractTestCase { + beforeEach() { + objectA = ObservableObject.extend({ + computed: computed(function() { + return 'value'; + }).volatile(), + method() { + return 'value'; + }, + unknownProperty(key) { + this.lastUnknownProperty = key; + return 'unknown'; + } + }).create({ + normal: 'value', + numberVal: 24, + toggleVal: true, + nullProperty: null + }); - objectB = { - normal: 'value', - nullProperty: null - }; - } + objectB = { + normal: 'value', + nullProperty: null + }; + } - ['@test should get normal properties on Ember.Observable'](assert) { - assert.equal(get(objectA, 'normal'), 'value'); - } + ['@test should get normal properties on Ember.Observable'](assert) { + assert.equal(get(objectA, 'normal'), 'value'); + } - ['@test should call computed properties on Ember.Observable and return their result'](assert) { - assert.equal(get(objectA, 'computed'), 'value'); - } + ['@test should call computed properties on Ember.Observable and return their result']( + assert + ) { + assert.equal(get(objectA, 'computed'), 'value'); + } - ['@test should return the function for a non-computed property on Ember.Observable'](assert) { - var value = get(objectA, 'method'); - assert.equal(typeof value, 'function'); - } + ['@test should return the function for a non-computed property on Ember.Observable']( + assert + ) { + var value = get(objectA, 'method'); + assert.equal(typeof value, 'function'); + } - ['@test should return null when property value is null on Ember.Observable'](assert) { - assert.equal(get(objectA, 'nullProperty'), null); - } + ['@test should return null when property value is null on Ember.Observable']( + assert + ) { + assert.equal(get(objectA, 'nullProperty'), null); + } - ['@test should call unknownProperty when value is undefined on Ember.Observable'](assert) { - assert.equal(get(objectA, 'unknown'), 'unknown'); - assert.equal(objectA.lastUnknownProperty, 'unknown'); - } + ['@test should call unknownProperty when value is undefined on Ember.Observable']( + assert + ) { + assert.equal(get(objectA, 'unknown'), 'unknown'); + assert.equal(objectA.lastUnknownProperty, 'unknown'); + } - ['@test should get normal properties on standard objects'](assert) { - assert.equal(get(objectB, 'normal'), 'value'); - } + ['@test should get normal properties on standard objects'](assert) { + assert.equal(get(objectB, 'normal'), 'value'); + } - ['@test should return null when property is null on standard objects'](assert) { - assert.equal(get(objectB, 'nullProperty'), null); - } + ['@test should return null when property is null on standard objects']( + assert + ) { + assert.equal(get(objectB, 'nullProperty'), null); + } - /* + /* QUnit.test("raise if the provided object is null", function() { throws(function() { get(null, 'key'); @@ -143,648 +165,871 @@ moduleFor('Ember.get()', class extends AbstractTestCase { }); */ - ['@test raise if the provided object is undefined']() { - expectAssertion(function() { - get(undefined, 'key'); - }, /Cannot call get with 'key' on an undefined object/i); + ['@test raise if the provided object is undefined']() { + expectAssertion(function() { + get(undefined, 'key'); + }, /Cannot call get with 'key' on an undefined object/i); + } } -}); - -moduleFor('Ember.get() with paths', class extends AbstractTestCase { - - ['@test should return a property at a given path relative to the passed object'](assert) { - var foo = ObservableObject.create({ - bar: ObservableObject.extend({ - baz: computed(function() { return 'blargh'; }).volatile() - }).create() - }); +); + +moduleFor( + 'Ember.get() with paths', + class extends AbstractTestCase { + ['@test should return a property at a given path relative to the passed object']( + assert + ) { + var foo = ObservableObject.create({ + bar: ObservableObject.extend({ + baz: computed(function() { + return 'blargh'; + }).volatile() + }).create() + }); - assert.equal(get(foo, 'bar.baz'), 'blargh'); - } + assert.equal(get(foo, 'bar.baz'), 'blargh'); + } - ['@test should return a property at a given path relative to the passed object - JavaScript hash'](assert) { - var foo = { - bar: { - baz: 'blargh' - } - }; + ['@test should return a property at a given path relative to the passed object - JavaScript hash']( + assert + ) { + var foo = { + bar: { + baz: 'blargh' + } + }; - assert.equal(get(foo, 'bar.baz'), 'blargh'); + assert.equal(get(foo, 'bar.baz'), 'blargh'); + } } -}); +); // .......................................................... // SET() // -moduleFor('object.set()', class extends AbstractTestCase { +moduleFor( + 'object.set()', + class extends AbstractTestCase { + beforeEach() { + object = ObservableObject.extend({ + computed: computed({ + get() { + return this._computed; + }, + set(key, value) { + this._computed = value; + return this._computed; + } + }).volatile(), + + method(key, value) { + if (value !== undefined) { + this._method = value; + } + return this._method; + }, - beforeEach() { - object = ObservableObject.extend({ - computed: computed({ - get() { - return this._computed; + unknownProperty() { + return this._unknown; }, - set(key, value) { - this._computed = value; - return this._computed; - } - }).volatile(), - method(key, value) { - if (value !== undefined) { - this._method = value; - } - return this._method; - }, - - unknownProperty() { - return this._unknown; - }, - - setUnknownProperty(key, value) { - this._unknown = value; - return this._unknown; - }, - - // normal property - normal: 'value', - - // computed property - _computed: 'computed', - // method, but not a property - _method: 'method', - // null property - nullProperty: null, - - // unknown property - _unknown: 'unknown' - }).create(); - } + setUnknownProperty(key, value) { + this._unknown = value; + return this._unknown; + }, - ['@test should change normal properties and return the value'](assert) { - var ret = object.set('normal', 'changed'); - assert.equal(object.get('normal'), 'changed'); - assert.equal(ret, 'changed'); - } + // normal property + normal: 'value', - ['@test should call computed properties passing value and return the value'](assert) { - var ret = object.set('computed', 'changed'); - assert.equal(object.get('_computed'), 'changed'); - assert.equal(ret, 'changed'); - } + // computed property + _computed: 'computed', + // method, but not a property + _method: 'method', + // null property + nullProperty: null, - ['@test should change normal properties when passing undefined'](assert) { - var ret = object.set('normal', undefined); - assert.equal(object.get('normal'), undefined); - assert.equal(ret, undefined); - } + // unknown property + _unknown: 'unknown' + }).create(); + } - ['@test should replace the function for a non-computed property and return the value'](assert) { - var ret = object.set('method', 'changed'); - assert.equal(object.get('_method'), 'method'); // make sure this was NOT run - assert.ok(typeof object.get('method') !== 'function'); - assert.equal(ret, 'changed'); - } + ['@test should change normal properties and return the value'](assert) { + var ret = object.set('normal', 'changed'); + assert.equal(object.get('normal'), 'changed'); + assert.equal(ret, 'changed'); + } - ['@test should replace prover when property value is null'](assert) { - var ret = object.set('nullProperty', 'changed'); - assert.equal(object.get('nullProperty'), 'changed'); - assert.equal(ret, 'changed'); - } + ['@test should call computed properties passing value and return the value']( + assert + ) { + var ret = object.set('computed', 'changed'); + assert.equal(object.get('_computed'), 'changed'); + assert.equal(ret, 'changed'); + } + + ['@test should change normal properties when passing undefined'](assert) { + var ret = object.set('normal', undefined); + assert.equal(object.get('normal'), undefined); + assert.equal(ret, undefined); + } + + ['@test should replace the function for a non-computed property and return the value']( + assert + ) { + var ret = object.set('method', 'changed'); + assert.equal(object.get('_method'), 'method'); // make sure this was NOT run + assert.ok(typeof object.get('method') !== 'function'); + assert.equal(ret, 'changed'); + } + + ['@test should replace prover when property value is null'](assert) { + var ret = object.set('nullProperty', 'changed'); + assert.equal(object.get('nullProperty'), 'changed'); + assert.equal(ret, 'changed'); + } - ['@test should call unknownProperty with value when property is undefined'](assert) { - var ret = object.set('unknown', 'changed'); - assert.equal(object.get('_unknown'), 'changed'); - assert.equal(ret, 'changed'); + ['@test should call unknownProperty with value when property is undefined']( + assert + ) { + var ret = object.set('unknown', 'changed'); + assert.equal(object.get('_unknown'), 'changed'); + assert.equal(ret, 'changed'); + } } -}); +); // .......................................................... // COMPUTED PROPERTIES // -moduleFor('Computed properties', class extends AbstractTestCase { - beforeEach() { - lookup = context.lookup = {}; - - object = ObservableObject.extend({ - computed: computed({ - get() { - this.computedCalls.push('getter-called'); - return 'computed'; - }, - set(key, value) { - this.computedCalls.push(value); - } - }).volatile(), - - computedCached: computed({ - get() { - this.computedCachedCalls.push('getter-called'); - return 'computedCached'; - }, - set: function(key, value) { - this.computedCachedCalls.push(value); - } - }), +moduleFor( + 'Computed properties', + class extends AbstractTestCase { + beforeEach() { + lookup = context.lookup = {}; + + object = ObservableObject.extend({ + computed: computed({ + get() { + this.computedCalls.push('getter-called'); + return 'computed'; + }, + set(key, value) { + this.computedCalls.push(value); + } + }).volatile(), + + computedCached: computed({ + get() { + this.computedCachedCalls.push('getter-called'); + return 'computedCached'; + }, + set: function(key, value) { + this.computedCachedCalls.push(value); + } + }), + + dependent: computed({ + get() { + this.dependentCalls.push('getter-called'); + return 'dependent'; + }, + set(key, value) { + this.dependentCalls.push(value); + } + }) + .property('changer') + .volatile(), + dependentFront: computed('changer', { + get() { + this.dependentFrontCalls.push('getter-called'); + return 'dependentFront'; + }, + set(key, value) { + this.dependentFrontCalls.push(value); + } + }).volatile(), + dependentCached: computed({ + get() { + this.dependentCachedCalls.push('getter-called!'); + return 'dependentCached'; + }, + set(key, value) { + this.dependentCachedCalls.push(value); + } + }).property('changer'), + + inc: computed('changer', function() { + return this.incCallCount++; + }), + + nestedInc: computed(function() { + get(this, 'inc'); + return this.nestedIncCallCount++; + }).property('inc'), + + isOn: computed({ + get() { + return this.get('state') === 'on'; + }, + set() { + this.set('state', 'on'); + return this.get('state') === 'on'; + } + }) + .property('state') + .volatile(), + + isOff: computed({ + get() { + return this.get('state') === 'off'; + }, + set() { + this.set('state', 'off'); + return this.get('state') === 'off'; + } + }) + .property('state') + .volatile() + }).create({ + computedCalls: [], + computedCachedCalls: [], + changer: 'foo', + dependentCalls: [], + dependentFrontCalls: [], + dependentCachedCalls: [], + incCallCount: 0, + nestedIncCallCount: 0, + state: 'on' + }); + } + afterEach() { + context.lookup = originalLookup; + } - dependent: computed({ - get() { - this.dependentCalls.push('getter-called'); - return 'dependent'; - }, - set(key, value) { - this.dependentCalls.push(value); - } - }).property('changer').volatile(), - dependentFront: computed('changer', { - get() { - this.dependentFrontCalls.push('getter-called'); - return 'dependentFront'; - }, - set(key, value) { - this.dependentFrontCalls.push(value); - } - }).volatile(), - dependentCached: computed({ - get() { - this.dependentCachedCalls.push('getter-called!'); - return 'dependentCached'; - }, - set(key, value) { - this.dependentCachedCalls.push(value); - } - }).property('changer'), + ['@test getting values should call function return value'](assert) { + // get each property twice. Verify return. + var keys = w( + 'computed computedCached dependent dependentFront dependentCached' + ); + + keys.forEach(function(key) { + assert.equal( + object.get(key), + key, + `Try #1: object.get(${key}) should run function` + ); + assert.equal( + object.get(key), + key, + `Try #2: object.get(${key}) should run function` + ); + }); - inc: computed('changer', function() { - return this.incCallCount++; - }), + // verify each call count. cached should only be called once + w('computedCalls dependentFrontCalls dependentCalls').forEach(key => { + assert.equal( + object[key].length, + 2, + `non-cached property ${key} should be called 2x` + ); + }); - nestedInc: computed(function() { - get(this, 'inc'); - return this.nestedIncCallCount++; - }).property('inc'), + w('computedCachedCalls dependentCachedCalls').forEach(key => { + assert.equal( + object[key].length, + 1, + `non-cached property ${key} should be called 1x` + ); + }); + } - isOn: computed({ - get() { - return this.get('state') === 'on'; - }, - set() { - this.set('state', 'on'); - return this.get('state') === 'on'; - } - }).property('state').volatile(), + ['@test setting values should call function return value'](assert) { + // get each property twice. Verify return. + var keys = w( + 'computed dependent dependentFront computedCached dependentCached' + ); + var values = w('value1 value2'); + + keys.forEach(key => { + assert.equal( + object.set(key, values[0]), + values[0], + `Try #1: object.set(${key}, ${values[0]}) should run function` + ); + + assert.equal( + object.set(key, values[1]), + values[1], + `Try #2: object.set(${key}, ${values[1]}) should run function` + ); + + assert.equal( + object.set(key, values[1]), + values[1], + `Try #3: object.set(${key}, ${ + values[1] + }) should not run function since it is setting same value as before` + ); + }); - isOff: computed({ - get() { - return this.get('state') === 'off'; - }, - set() { - this.set('state', 'off'); - return this.get('state') === 'off'; + // verify each call count. cached should only be called once + keys.forEach(key => { + var calls = object[key + 'Calls']; + var idx, expectedLength; + + // Cached properties first check their cached value before setting the + // property. Other properties blindly call set. + expectedLength = 3; + assert.equal( + calls.length, + expectedLength, + `set(${key}) should be called the right amount of times` + ); + for (idx = 0; idx < 2; idx++) { + assert.equal( + calls[idx], + values[idx], + `call #${idx + 1} to set(${key}) should have passed value ${ + values[idx] + }` + ); } - }).property('state').volatile() - - }).create({ - computedCalls: [], - computedCachedCalls: [], - changer: 'foo', - dependentCalls: [], - dependentFrontCalls: [], - dependentCachedCalls: [], - incCallCount: 0, - nestedIncCallCount: 0, - state: 'on' - }); - } - afterEach() { - context.lookup = originalLookup; - } - - ['@test getting values should call function return value'](assert) { - // get each property twice. Verify return. - var keys = w('computed computedCached dependent dependentFront dependentCached'); - - keys.forEach(function(key) { - assert.equal(object.get(key), key, `Try #1: object.get(${key}) should run function`); - assert.equal(object.get(key), key, `Try #2: object.get(${key}) should run function`); - }); - - // verify each call count. cached should only be called once - w('computedCalls dependentFrontCalls dependentCalls').forEach((key) => { - assert.equal(object[key].length, 2, `non-cached property ${key} should be called 2x`); - }); - - w('computedCachedCalls dependentCachedCalls').forEach((key) => { - assert.equal(object[key].length, 1, `non-cached property ${key} should be called 1x`); - }); - } - - ['@test setting values should call function return value'](assert) { - // get each property twice. Verify return. - var keys = w('computed dependent dependentFront computedCached dependentCached'); - var values = w('value1 value2'); - - keys.forEach((key) => { - assert.equal(object.set(key, values[0]), values[0], `Try #1: object.set(${key}, ${values[0]}) should run function`); + }); + } - assert.equal(object.set(key, values[1]), values[1], `Try #2: object.set(${key}, ${values[1]}) should run function`); + ['@test notify change should clear cache'](assert) { + // call get several times to collect call count + object.get('computedCached'); // should run func + object.get('computedCached'); // should not run func - assert.equal(object.set(key, values[1]), values[1], `Try #3: object.set(${key}, ${values[1]}) should not run function since it is setting same value as before`); - }); + object.notifyPropertyChange('computedCached'); - // verify each call count. cached should only be called once - keys.forEach((key) => { - var calls = object[key + 'Calls']; - var idx, expectedLength; - - // Cached properties first check their cached value before setting the - // property. Other properties blindly call set. - expectedLength = 3; - assert.equal(calls.length, expectedLength, `set(${key}) should be called the right amount of times`); - for (idx = 0; idx < 2; idx++) { - assert.equal(calls[idx], values[idx], `call #${idx + 1} to set(${key}) should have passed value ${values[idx]}`); - } - }); - } + object.get('computedCached'); // should run again + assert.equal( + object.computedCachedCalls.length, + 2, + 'should have invoked method 2x' + ); + } - ['@test notify change should clear cache'](assert) { - // call get several times to collect call count - object.get('computedCached'); // should run func - object.get('computedCached'); // should not run func + ['@test change dependent should clear cache'](assert) { + // call get several times to collect call count + var ret1 = object.get('inc'); // should run func + assert.equal( + object.get('inc'), + ret1, + 'multiple calls should not run cached prop' + ); + + object.set('changer', 'bar'); + + assert.equal( + object.get('inc'), + ret1 + 1, + 'should increment after dependent key changes' + ); // should run again + } - object.notifyPropertyChange('computedCached'); + ['@test just notifying change of dependent should clear cache'](assert) { + // call get several times to collect call count + var ret1 = object.get('inc'); // should run func + assert.equal( + object.get('inc'), + ret1, + 'multiple calls should not run cached prop' + ); + + object.notifyPropertyChange('changer'); + + assert.equal( + object.get('inc'), + ret1 + 1, + 'should increment after dependent key changes' + ); // should run again + } - object.get('computedCached'); // should run again - assert.equal(object.computedCachedCalls.length, 2, 'should have invoked method 2x'); - } + ['@test changing dependent should clear nested cache'](assert) { + // call get several times to collect call count + var ret1 = object.get('nestedInc'); // should run func + assert.equal( + object.get('nestedInc'), + ret1, + 'multiple calls should not run cached prop' + ); + + object.set('changer', 'bar'); + + assert.equal( + object.get('nestedInc'), + ret1 + 1, + 'should increment after dependent key changes' + ); // should run again + } - ['@test change dependent should clear cache'](assert) { - // call get several times to collect call count - var ret1 = object.get('inc'); // should run func - assert.equal(object.get('inc'), ret1, 'multiple calls should not run cached prop'); + ['@test just notifying change of dependent should clear nested cache']( + assert + ) { + // call get several times to collect call count + var ret1 = object.get('nestedInc'); // should run func + assert.equal( + object.get('nestedInc'), + ret1, + 'multiple calls should not run cached prop' + ); + + object.notifyPropertyChange('changer'); + + assert.equal( + object.get('nestedInc'), + ret1 + 1, + 'should increment after dependent key changes' + ); // should run again + } - object.set('changer', 'bar'); + // This verifies a specific bug encountered where observers for computed + // properties would fire before their prop caches were cleared. + ['@test change dependent should clear cache when observers of dependent are called']( + assert + ) { + // call get several times to collect call count + var ret1 = object.get('inc'); // should run func + assert.equal( + object.get('inc'), + ret1, + 'multiple calls should not run cached prop' + ); + + // add observer to verify change... + object.addObserver('inc', this, function() { + assert.equal( + object.get('inc'), + ret1 + 1, + 'should increment after dependent key changes' + ); // should run again + }); - assert.equal(object.get('inc'), ret1 + 1, 'should increment after dependent key changes'); // should run again - } + // now run + object.set('changer', 'bar'); + } - ['@test just notifying change of dependent should clear cache'](assert) { - // call get several times to collect call count - var ret1 = object.get('inc'); // should run func - assert.equal(object.get('inc'), ret1, 'multiple calls should not run cached prop'); + ['@test setting one of two computed properties that depend on a third property should clear the kvo cache']( + assert + ) { + // we have to call set twice to fill up the cache + object.set('isOff', true); + object.set('isOn', true); + + // setting isOff to true should clear the kvo cache + object.set('isOff', true); + assert.equal(object.get('isOff'), true, 'object.isOff should be true'); + assert.equal(object.get('isOn'), false, 'object.isOn should be false'); + } - object.notifyPropertyChange('changer'); + ['@test dependent keys should be able to be specified as property paths']( + assert + ) { + var depObj = ObservableObject.extend({ + menuPrice: computed(function() { + return this.get('menu.price'); + }).property('menu.price') + }).create({ + menu: ObservableObject.create({ + price: 5 + }) + }); - assert.equal(object.get('inc'), ret1 + 1, 'should increment after dependent key changes'); // should run again - } + assert.equal( + depObj.get('menuPrice'), + 5, + 'precond - initial value returns 5' + ); - ['@test changing dependent should clear nested cache'](assert) { - // call get several times to collect call count - var ret1 = object.get('nestedInc'); // should run func - assert.equal(object.get('nestedInc'), ret1, 'multiple calls should not run cached prop'); + depObj.set('menu.price', 6); - object.set('changer', 'bar'); + assert.equal( + depObj.get('menuPrice'), + 6, + 'cache is properly invalidated after nested property changes' + ); + } - assert.equal(object.get('nestedInc'), ret1 + 1, 'should increment after dependent key changes'); // should run again - } + ['@test cacheable nested dependent keys should clear after their dependencies update']( + assert + ) { + assert.ok(true); - ['@test just notifying change of dependent should clear nested cache'](assert) { - // call get several times to collect call count - var ret1 = object.get('nestedInc'); // should run func - assert.equal(object.get('nestedInc'), ret1, 'multiple calls should not run cached prop'); + var DepObj; - object.notifyPropertyChange('changer'); + run(function() { + lookup.DepObj = DepObj = ObservableObject.extend({ + price: computed('restaurant.menu.price', function() { + return this.get('restaurant.menu.price'); + }) + }).create({ + restaurant: ObservableObject.create({ + menu: ObservableObject.create({ + price: 5 + }) + }) + }); + }); - assert.equal(object.get('nestedInc'), ret1 + 1, 'should increment after dependent key changes'); // should run again - } + assert.equal( + DepObj.get('price'), + 5, + 'precond - computed property is correct' + ); + run(function() { + DepObj.set('restaurant.menu.price', 10); + }); + assert.equal( + DepObj.get('price'), + 10, + 'cacheable computed properties are invalidated even if no run loop occurred' + ); - // This verifies a specific bug encountered where observers for computed - // properties would fire before their prop caches were cleared. - ['@test change dependent should clear cache when observers of dependent are called'](assert) { - // call get several times to collect call count - var ret1 = object.get('inc'); // should run func - assert.equal(object.get('inc'), ret1, 'multiple calls should not run cached prop'); + run(function() { + DepObj.set('restaurant.menu.price', 20); + }); + assert.equal( + DepObj.get('price'), + 20, + 'cacheable computed properties are invalidated after a second get before a run loop' + ); + assert.equal( + DepObj.get('price'), + 20, + 'precond - computed properties remain correct after a run loop' + ); - // add observer to verify change... - object.addObserver('inc', this, function() { - assert.equal(object.get('inc'), ret1 + 1, 'should increment after dependent key changes'); // should run again - }); + run(function() { + DepObj.set( + 'restaurant.menu', + ObservableObject.create({ + price: 15 + }) + ); + }); - // now run - object.set('changer', 'bar'); - } + assert.equal( + DepObj.get('price'), + 15, + 'cacheable computed properties are invalidated after a middle property changes' + ); - ['@test setting one of two computed properties that depend on a third property should clear the kvo cache'](assert) { - // we have to call set twice to fill up the cache - object.set('isOff', true); - object.set('isOn', true); + run(function() { + DepObj.set( + 'restaurant.menu', + ObservableObject.create({ + price: 25 + }) + ); + }); - // setting isOff to true should clear the kvo cache - object.set('isOff', true); - assert.equal(object.get('isOff'), true, 'object.isOff should be true'); - assert.equal(object.get('isOn'), false, 'object.isOn should be false'); + assert.equal( + DepObj.get('price'), + 25, + 'cacheable computed properties are invalidated after a middle property changes again, before a run loop' + ); + } } +); - ['@test dependent keys should be able to be specified as property paths'](assert) { - var depObj = ObservableObject.extend({ - menuPrice: computed(function() { - return this.get('menu.price'); - }).property('menu.price') - }).create({ - menu: ObservableObject.create({ - price: 5 - }) - }); - - assert.equal(depObj.get('menuPrice'), 5, 'precond - initial value returns 5'); - - depObj.set('menu.price', 6); +// .......................................................... +// OBSERVABLE OBJECTS +// - assert.equal(depObj.get('menuPrice'), 6, 'cache is properly invalidated after nested property changes'); - } +moduleFor( + 'Observable objects & object properties ', + class extends AbstractTestCase { + beforeEach() { + object = ObservableObject.extend({ + getEach() { + var keys = ['normal', 'abnormal']; + var ret = []; + for (var idx = 0; idx < keys.length; idx++) { + ret[ret.length] = this.get(keys[idx]); + } + return ret; + }, - ['@test cacheable nested dependent keys should clear after their dependencies update'](assert) { - assert.ok(true); + newObserver() { + this.abnormal = 'changedValueObserved'; + }, - var DepObj; + testObserver: observer('normal', function() { + this.abnormal = 'removedObserver'; + }), - run(function() { - lookup.DepObj = DepObj = ObservableObject.extend({ - price: computed('restaurant.menu.price', function() { - return this.get('restaurant.menu.price'); + testArrayObserver: observer('normalArray.[]', function() { + this.abnormal = 'notifiedObserver'; }) }).create({ - restaurant: ObservableObject.create({ - menu: ObservableObject.create({ - price: 5 - }) - }) + normal: 'value', + abnormal: 'zeroValue', + numberVal: 24, + toggleVal: true, + observedProperty: 'beingWatched', + testRemove: 'observerToBeRemoved', + normalArray: emberA([1, 2, 3, 4, 5]) }); - }); - - assert.equal(DepObj.get('price'), 5, 'precond - computed property is correct'); - - run(function() { - DepObj.set('restaurant.menu.price', 10); - }); - assert.equal(DepObj.get('price'), 10, 'cacheable computed properties are invalidated even if no run loop occurred'); - - run(function() { - DepObj.set('restaurant.menu.price', 20); - }); - assert.equal(DepObj.get('price'), 20, 'cacheable computed properties are invalidated after a second get before a run loop'); - assert.equal(DepObj.get('price'), 20, 'precond - computed properties remain correct after a run loop'); - - run(function() { - DepObj.set('restaurant.menu', ObservableObject.create({ - price: 15 - })); - }); - + } - assert.equal(DepObj.get('price'), 15, 'cacheable computed properties are invalidated after a middle property changes'); + ['@test incrementProperty and decrementProperty'](assert) { + var newValue = object.incrementProperty('numberVal'); + + assert.equal(25, newValue, 'numerical value incremented'); + object.numberVal = 24; + newValue = object.decrementProperty('numberVal'); + assert.equal(23, newValue, 'numerical value decremented'); + object.numberVal = 25; + newValue = object.incrementProperty('numberVal', 5); + assert.equal( + 30, + newValue, + 'numerical value incremented by specified increment' + ); + object.numberVal = 25; + newValue = object.incrementProperty('numberVal', -5); + assert.equal( + 20, + newValue, + 'minus numerical value incremented by specified increment' + ); + object.numberVal = 25; + newValue = object.incrementProperty('numberVal', 0); + assert.equal( + 25, + newValue, + 'zero numerical value incremented by specified increment' + ); + + expectAssertion(function() { + newValue = object.incrementProperty('numberVal', 0 - void 0); // Increment by NaN + }, /Must pass a numeric value to incrementProperty/i); + + expectAssertion(function() { + newValue = object.incrementProperty('numberVal', 'Ember'); // Increment by non-numeric String + }, /Must pass a numeric value to incrementProperty/i); + + expectAssertion(function() { + newValue = object.incrementProperty('numberVal', 1 / 0); // Increment by Infinity + }, /Must pass a numeric value to incrementProperty/i); + + assert.equal( + 25, + newValue, + 'Attempting to increment by non-numeric values should not increment value' + ); + + object.numberVal = 25; + newValue = object.decrementProperty('numberVal', 5); + assert.equal( + 20, + newValue, + 'numerical value decremented by specified increment' + ); + object.numberVal = 25; + newValue = object.decrementProperty('numberVal', -5); + assert.equal( + 30, + newValue, + 'minus numerical value decremented by specified increment' + ); + object.numberVal = 25; + newValue = object.decrementProperty('numberVal', 0); + assert.equal( + 25, + newValue, + 'zero numerical value decremented by specified increment' + ); + + expectAssertion(function() { + newValue = object.decrementProperty('numberVal', 0 - void 0); // Decrement by NaN + }, /Must pass a numeric value to decrementProperty/i); + + expectAssertion(function() { + newValue = object.decrementProperty('numberVal', 'Ember'); // Decrement by non-numeric String + }, /Must pass a numeric value to decrementProperty/i); + + expectAssertion(function() { + newValue = object.decrementProperty('numberVal', 1 / 0); // Decrement by Infinity + }, /Must pass a numeric value to decrementProperty/i); + + assert.equal( + 25, + newValue, + 'Attempting to decrement by non-numeric values should not decrement value' + ); + } - run(function() { - DepObj.set('restaurant.menu', ObservableObject.create({ - price: 25 - })); - }); + ['@test toggle function, should be boolean'](assert) { + assert.equal( + object.toggleProperty('toggleVal', true, false), + object.get('toggleVal') + ); + assert.equal( + object.toggleProperty('toggleVal', true, false), + object.get('toggleVal') + ); + assert.equal( + object.toggleProperty('toggleVal', undefined, undefined), + object.get('toggleVal') + ); + } - assert.equal(DepObj.get('price'), 25, 'cacheable computed properties are invalidated after a middle property changes again, before a run loop'); + ['@test should notify array observer when array changes'](assert) { + get(object, 'normalArray').replace(0, 0, [6]); + assert.equal( + object.abnormal, + 'notifiedObserver', + 'observer should be notified' + ); + } } -}); - +); + +moduleFor( + 'object.addObserver()', + class extends AbstractTestCase { + beforeEach() { + ObjectC = ObservableObject.create({ + objectE: ObservableObject.create({ + propertyVal: 'chainedProperty' + }), + + normal: 'value', + normal1: 'zeroValue', + normal2: 'dependentValue', + incrementor: 10, + + action() { + this.normal1 = 'newZeroValue'; + }, -// .......................................................... -// OBSERVABLE OBJECTS -// + observeOnceAction() { + this.incrementor = this.incrementor + 1; + }, -moduleFor('Observable objects & object properties ', class extends AbstractTestCase { - beforeEach() { - object = ObservableObject.extend({ - getEach() { - var keys = ['normal', 'abnormal']; - var ret = []; - for (var idx = 0; idx < keys.length; idx++) { - ret[ret.length] = this.get(keys[idx]); + chainedObserver() { + this.normal2 = 'chainedPropertyObserved'; } - return ret; - }, - - newObserver() { - this.abnormal = 'changedValueObserved'; - }, - - testObserver: observer('normal', function() { - this.abnormal = 'removedObserver'; - }), - - testArrayObserver: observer('normalArray.[]', function() { - this.abnormal = 'notifiedObserver'; - }) - }).create({ - normal: 'value', - abnormal: 'zeroValue', - numberVal: 24, - toggleVal: true, - observedProperty: 'beingWatched', - testRemove: 'observerToBeRemoved', - normalArray: emberA([1, 2, 3, 4, 5]) - }); - } - - ['@test incrementProperty and decrementProperty'](assert) { - var newValue = object.incrementProperty('numberVal'); - - assert.equal(25, newValue, 'numerical value incremented'); - object.numberVal = 24; - newValue = object.decrementProperty('numberVal'); - assert.equal(23, newValue, 'numerical value decremented'); - object.numberVal = 25; - newValue = object.incrementProperty('numberVal', 5); - assert.equal(30, newValue, 'numerical value incremented by specified increment'); - object.numberVal = 25; - newValue = object.incrementProperty('numberVal', -5); - assert.equal(20, newValue, 'minus numerical value incremented by specified increment'); - object.numberVal = 25; - newValue = object.incrementProperty('numberVal', 0); - assert.equal(25, newValue, 'zero numerical value incremented by specified increment'); - - expectAssertion(function() { - newValue = object.incrementProperty('numberVal', (0 - void(0))); // Increment by NaN - }, /Must pass a numeric value to incrementProperty/i); - - expectAssertion(function() { - newValue = object.incrementProperty('numberVal', 'Ember'); // Increment by non-numeric String - }, /Must pass a numeric value to incrementProperty/i); - - expectAssertion(function() { - newValue = object.incrementProperty('numberVal', 1 / 0); // Increment by Infinity - }, /Must pass a numeric value to incrementProperty/i); - - assert.equal(25, newValue, 'Attempting to increment by non-numeric values should not increment value'); - - object.numberVal = 25; - newValue = object.decrementProperty('numberVal', 5); - assert.equal(20, newValue, 'numerical value decremented by specified increment'); - object.numberVal = 25; - newValue = object.decrementProperty('numberVal', -5); - assert.equal(30, newValue, 'minus numerical value decremented by specified increment'); - object.numberVal = 25; - newValue = object.decrementProperty('numberVal', 0); - assert.equal(25, newValue, 'zero numerical value decremented by specified increment'); - - expectAssertion(function() { - newValue = object.decrementProperty('numberVal', (0 - void(0))); // Decrement by NaN - }, /Must pass a numeric value to decrementProperty/i); - - expectAssertion(function() { - newValue = object.decrementProperty('numberVal', 'Ember'); // Decrement by non-numeric String - }, /Must pass a numeric value to decrementProperty/i); - - expectAssertion(function() { - newValue = object.decrementProperty('numberVal', 1 / 0); // Decrement by Infinity - }, /Must pass a numeric value to decrementProperty/i); - - assert.equal(25, newValue, 'Attempting to decrement by non-numeric values should not decrement value'); - } - - ['@test toggle function, should be boolean'](assert) { - assert.equal(object.toggleProperty('toggleVal', true, false), object.get('toggleVal')); - assert.equal(object.toggleProperty('toggleVal', true, false), object.get('toggleVal')); - assert.equal(object.toggleProperty('toggleVal', undefined, undefined), object.get('toggleVal')); - } - - ['@test should notify array observer when array changes'](assert) { - get(object, 'normalArray').replace(0, 0, [6]); - assert.equal(object.abnormal, 'notifiedObserver', 'observer should be notified'); - } -}); - -moduleFor('object.addObserver()', class extends AbstractTestCase { - beforeEach() { - ObjectC = ObservableObject.create({ - objectE: ObservableObject.create({ - propertyVal: 'chainedProperty' - }), - - normal: 'value', - normal1: 'zeroValue', - normal2: 'dependentValue', - incrementor: 10, - - action() { - this.normal1 = 'newZeroValue'; - }, - - observeOnceAction() { - this.incrementor = this.incrementor + 1; - }, - - chainedObserver() { - this.normal2 = 'chainedPropertyObserved'; - } - }); - } + }); + } - ['@test should register an observer for a property'](assert) { - ObjectC.addObserver('normal', ObjectC, 'action'); - ObjectC.set('normal', 'newValue'); - assert.equal(ObjectC.normal1, 'newZeroValue'); - } + ['@test should register an observer for a property'](assert) { + ObjectC.addObserver('normal', ObjectC, 'action'); + ObjectC.set('normal', 'newValue'); + assert.equal(ObjectC.normal1, 'newZeroValue'); + } - ['@test should register an observer for a property - Special case of chained property'](assert) { - ObjectC.addObserver('objectE.propertyVal', ObjectC, 'chainedObserver'); - ObjectC.objectE.set('propertyVal', 'chainedPropertyValue'); - assert.equal('chainedPropertyObserved', ObjectC.normal2); - ObjectC.normal2 = 'dependentValue'; - ObjectC.set('objectE', ''); - assert.equal('chainedPropertyObserved', ObjectC.normal2); - } -}); - -moduleFor('object.removeObserver()', class extends AbstractTestCase { - beforeEach() { - ObjectD = ObservableObject.create({ - objectF: ObservableObject.create({ - propertyVal: 'chainedProperty' - }), - - normal: 'value', - normal1: 'zeroValue', - normal2: 'dependentValue', - ArrayKeys: ['normal', 'normal1'], - - addAction() { - this.normal1 = 'newZeroValue'; - }, - removeAction() { - this.normal2 = 'newDependentValue'; - }, - removeChainedObserver() { - this.normal2 = 'chainedPropertyObserved'; - }, - - observableValue: 'hello world', - - observer1() { - // Just an observer - }, - observer2() { - this.removeObserver('observableValue', null, 'observer1'); - this.removeObserver('observableValue', null, 'observer2'); - this.hasObserverFor('observableValue'); // Tickle 'getMembers()' - this.removeObserver('observableValue', null, 'observer3'); - }, - observer3() { - // Just an observer - } - }); + ['@test should register an observer for a property - Special case of chained property']( + assert + ) { + ObjectC.addObserver('objectE.propertyVal', ObjectC, 'chainedObserver'); + ObjectC.objectE.set('propertyVal', 'chainedPropertyValue'); + assert.equal('chainedPropertyObserved', ObjectC.normal2); + ObjectC.normal2 = 'dependentValue'; + ObjectC.set('objectE', ''); + assert.equal('chainedPropertyObserved', ObjectC.normal2); + } } +); + +moduleFor( + 'object.removeObserver()', + class extends AbstractTestCase { + beforeEach() { + ObjectD = ObservableObject.create({ + objectF: ObservableObject.create({ + propertyVal: 'chainedProperty' + }), + + normal: 'value', + normal1: 'zeroValue', + normal2: 'dependentValue', + ArrayKeys: ['normal', 'normal1'], + + addAction() { + this.normal1 = 'newZeroValue'; + }, + removeAction() { + this.normal2 = 'newDependentValue'; + }, + removeChainedObserver() { + this.normal2 = 'chainedPropertyObserved'; + }, + observableValue: 'hello world', - ['@test should unregister an observer for a property'](assert) { - ObjectD.addObserver('normal', ObjectD, 'addAction'); - ObjectD.set('normal', 'newValue'); - assert.equal(ObjectD.normal1, 'newZeroValue'); - - ObjectD.set('normal1', 'zeroValue'); + observer1() { + // Just an observer + }, + observer2() { + this.removeObserver('observableValue', null, 'observer1'); + this.removeObserver('observableValue', null, 'observer2'); + this.hasObserverFor('observableValue'); // Tickle 'getMembers()' + this.removeObserver('observableValue', null, 'observer3'); + }, + observer3() { + // Just an observer + } + }); + } - ObjectD.removeObserver('normal', ObjectD, 'addAction'); - ObjectD.set('normal', 'newValue'); - assert.equal(ObjectD.normal1, 'zeroValue'); - } + ['@test should unregister an observer for a property'](assert) { + ObjectD.addObserver('normal', ObjectD, 'addAction'); + ObjectD.set('normal', 'newValue'); + assert.equal(ObjectD.normal1, 'newZeroValue'); + ObjectD.set('normal1', 'zeroValue'); - ['@test should unregister an observer for a property - special case when key has a \'.\' in it.'](assert) { - ObjectD.addObserver('objectF.propertyVal', ObjectD, 'removeChainedObserver'); - ObjectD.objectF.set('propertyVal', 'chainedPropertyValue'); - ObjectD.removeObserver('objectF.propertyVal', ObjectD, 'removeChainedObserver'); - ObjectD.normal2 = 'dependentValue'; - ObjectD.objectF.set('propertyVal', 'removedPropertyValue'); - assert.equal('dependentValue', ObjectD.normal2); - ObjectD.set('objectF', ''); - assert.equal('dependentValue', ObjectD.normal2); - } + ObjectD.removeObserver('normal', ObjectD, 'addAction'); + ObjectD.set('normal', 'newValue'); + assert.equal(ObjectD.normal1, 'zeroValue'); + } + ["@test should unregister an observer for a property - special case when key has a '.' in it."]( + assert + ) { + ObjectD.addObserver( + 'objectF.propertyVal', + ObjectD, + 'removeChainedObserver' + ); + ObjectD.objectF.set('propertyVal', 'chainedPropertyValue'); + ObjectD.removeObserver( + 'objectF.propertyVal', + ObjectD, + 'removeChainedObserver' + ); + ObjectD.normal2 = 'dependentValue'; + ObjectD.objectF.set('propertyVal', 'removedPropertyValue'); + assert.equal('dependentValue', ObjectD.normal2); + ObjectD.set('objectF', ''); + assert.equal('dependentValue', ObjectD.normal2); + } - ['@test removing an observer inside of an observer shouldn’t cause any problems'](assert) { - // The observable system should be protected against clients removing - // observers in the middle of observer notification. - var encounteredError = false; - try { - ObjectD.addObserver('observableValue', null, 'observer1'); - ObjectD.addObserver('observableValue', null, 'observer2'); - ObjectD.addObserver('observableValue', null, 'observer3'); - run(function() { - ObjectD.set('observableValue', 'hi world'); - }); - } catch (e) { - encounteredError = true; + ['@test removing an observer inside of an observer shouldn’t cause any problems']( + assert + ) { + // The observable system should be protected against clients removing + // observers in the middle of observer notification. + var encounteredError = false; + try { + ObjectD.addObserver('observableValue', null, 'observer1'); + ObjectD.addObserver('observableValue', null, 'observer2'); + ObjectD.addObserver('observableValue', null, 'observer3'); + run(function() { + ObjectD.set('observableValue', 'hi world'); + }); + } catch (e) { + encounteredError = true; + } + assert.equal(encounteredError, false); } - assert.equal(encounteredError, false); } -}); +); diff --git a/packages/ember-runtime/tests/legacy_1x/mixins/observable/propertyChanges_test.js b/packages/ember-runtime/tests/legacy_1x/mixins/observable/propertyChanges_test.js index 8bb43c44c8a..8d3213b84c3 100644 --- a/packages/ember-runtime/tests/legacy_1x/mixins/observable/propertyChanges_test.js +++ b/packages/ember-runtime/tests/legacy_1x/mixins/observable/propertyChanges_test.js @@ -26,106 +26,127 @@ const ObservableObject = EmberObject.extend(Observable); let ObjectA; -moduleFor('object.propertyChanges', class extends AbstractTestCase { - beforeEach() { - ObjectA = ObservableObject.extend({ - action: observer('foo', function() { - this.set('prop', 'changedPropValue'); - }), - notifyAction: observer('newFoo', function() { - this.set('newProp', 'changedNewPropValue'); - }), - - notifyAllAction: observer('prop', function() { - this.set('newFoo', 'changedNewFooValue'); - }), - - starObserver(target, key) { - this.starProp = key; - } - }).create({ - starProp: null, - - foo: 'fooValue', - prop: 'propValue', - - newFoo: 'newFooValue', - newProp: 'newPropValue' - }); - } - - ['@test should observe the changes within the nested begin / end property changes'](assert) { - //start the outer nest - ObjectA.beginPropertyChanges(); - - // Inner nest - ObjectA.beginPropertyChanges(); - ObjectA.set('foo', 'changeFooValue'); - - assert.equal(ObjectA.prop, 'propValue'); - ObjectA.endPropertyChanges(); - - //end inner nest - ObjectA.set('prop', 'changePropValue'); - assert.equal(ObjectA.newFoo, 'newFooValue'); - - //close the outer nest - ObjectA.endPropertyChanges(); - - assert.equal(ObjectA.prop, 'changedPropValue'); - assert.equal(ObjectA.newFoo, 'changedNewFooValue'); - } - - ['@test should observe the changes within the begin and end property changes'](assert) { - ObjectA.beginPropertyChanges(); - ObjectA.set('foo', 'changeFooValue'); - - assert.equal(ObjectA.prop, 'propValue'); - ObjectA.endPropertyChanges(); - - assert.equal(ObjectA.prop, 'changedPropValue'); - } - - ['@test should indicate that the property of an object has just changed'](assert) { - //change the value of foo. - ObjectA.set('foo', 'changeFooValue'); - - // Indicate the subscribers of foo that the value has just changed - ObjectA.notifyPropertyChange('foo', null); - - // Values of prop has just changed - assert.equal(ObjectA.prop, 'changedPropValue'); - } - - ['@test should notify that the property of an object has changed'](assert) { - // Notify to its subscriber that the values of 'newFoo' will be changed. In this - // case the observer is "newProp". Therefore this will call the notifyAction function - // and value of "newProp" will be changed. - ObjectA.notifyPropertyChange('newFoo', 'fooValue'); - - //value of newProp changed. - assert.equal(ObjectA.newProp, 'changedNewPropValue'); - } - - ['@test should invalidate function property cache when notifyPropertyChange is called'](assert) { - let a = ObservableObject.extend({ - b: computed({ - get() { return this._b; }, - set(key, value) { - this._b = value; - return this; +moduleFor( + 'object.propertyChanges', + class extends AbstractTestCase { + beforeEach() { + ObjectA = ObservableObject.extend({ + action: observer('foo', function() { + this.set('prop', 'changedPropValue'); + }), + notifyAction: observer('newFoo', function() { + this.set('newProp', 'changedNewPropValue'); + }), + + notifyAllAction: observer('prop', function() { + this.set('newFoo', 'changedNewFooValue'); + }), + + starObserver(target, key) { + this.starProp = key; } - }).volatile() - }).create({ - _b: null - }); - - a.set('b', 'foo'); - assert.equal(a.get('b'), 'foo', 'should have set the correct value for property b'); - - a._b = 'bar'; - a.notifyPropertyChange('b'); - a.set('b', 'foo'); - assert.equal(a.get('b'), 'foo', 'should have invalidated the cache so that the newly set value is actually set'); + }).create({ + starProp: null, + + foo: 'fooValue', + prop: 'propValue', + + newFoo: 'newFooValue', + newProp: 'newPropValue' + }); + } + + ['@test should observe the changes within the nested begin / end property changes']( + assert + ) { + //start the outer nest + ObjectA.beginPropertyChanges(); + + // Inner nest + ObjectA.beginPropertyChanges(); + ObjectA.set('foo', 'changeFooValue'); + + assert.equal(ObjectA.prop, 'propValue'); + ObjectA.endPropertyChanges(); + + //end inner nest + ObjectA.set('prop', 'changePropValue'); + assert.equal(ObjectA.newFoo, 'newFooValue'); + + //close the outer nest + ObjectA.endPropertyChanges(); + + assert.equal(ObjectA.prop, 'changedPropValue'); + assert.equal(ObjectA.newFoo, 'changedNewFooValue'); + } + + ['@test should observe the changes within the begin and end property changes']( + assert + ) { + ObjectA.beginPropertyChanges(); + ObjectA.set('foo', 'changeFooValue'); + + assert.equal(ObjectA.prop, 'propValue'); + ObjectA.endPropertyChanges(); + + assert.equal(ObjectA.prop, 'changedPropValue'); + } + + ['@test should indicate that the property of an object has just changed']( + assert + ) { + //change the value of foo. + ObjectA.set('foo', 'changeFooValue'); + + // Indicate the subscribers of foo that the value has just changed + ObjectA.notifyPropertyChange('foo', null); + + // Values of prop has just changed + assert.equal(ObjectA.prop, 'changedPropValue'); + } + + ['@test should notify that the property of an object has changed'](assert) { + // Notify to its subscriber that the values of 'newFoo' will be changed. In this + // case the observer is "newProp". Therefore this will call the notifyAction function + // and value of "newProp" will be changed. + ObjectA.notifyPropertyChange('newFoo', 'fooValue'); + + //value of newProp changed. + assert.equal(ObjectA.newProp, 'changedNewPropValue'); + } + + ['@test should invalidate function property cache when notifyPropertyChange is called']( + assert + ) { + let a = ObservableObject.extend({ + b: computed({ + get() { + return this._b; + }, + set(key, value) { + this._b = value; + return this; + } + }).volatile() + }).create({ + _b: null + }); + + a.set('b', 'foo'); + assert.equal( + a.get('b'), + 'foo', + 'should have set the correct value for property b' + ); + + a._b = 'bar'; + a.notifyPropertyChange('b'); + a.set('b', 'foo'); + assert.equal( + a.get('b'), + 'foo', + 'should have invalidated the cache so that the newly set value is actually set' + ); + } } -}); \ No newline at end of file +); diff --git a/packages/ember-runtime/tests/legacy_1x/system/object/base_test.js b/packages/ember-runtime/tests/legacy_1x/system/object/base_test.js index e6a10f616a4..d97f684d357 100644 --- a/packages/ember-runtime/tests/legacy_1x/system/object/base_test.js +++ b/packages/ember-runtime/tests/legacy_1x/system/object/base_test.js @@ -26,62 +26,81 @@ import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; let obj, obj1; // global variables -moduleFor('A new EmberObject instance', class extends AbstractTestCase { - - beforeEach() { - obj = EmberObject.create({ - foo: 'bar', - total: 12345, - aMethodThatExists() {}, - aMethodThatReturnsTrue() { return true; }, - aMethodThatReturnsFoobar() { return 'Foobar'; }, - aMethodThatReturnsFalse() { return false; } - }); - } - - afterEach() { - obj = undefined; - } - - ['@test Should return its properties when requested using EmberObject#get'](assert) { - assert.equal(get(obj, 'foo'), 'bar'); - assert.equal(get(obj, 'total'), 12345); - } - - ['@test Should allow changing of those properties by calling EmberObject#set'](assert) { - assert.equal(get(obj, 'foo'), 'bar'); - assert.equal(get(obj, 'total'), 12345); - - set(obj, 'foo', 'Chunky Bacon'); - set(obj, 'total', 12); - - assert.equal(get(obj, 'foo'), 'Chunky Bacon'); - assert.equal(get(obj, 'total'), 12); - } -}); - -moduleFor('EmberObject superclass and subclasses', class extends AbstractTestCase { - beforeEach() { - obj = EmberObject.extend({ - method1() { - return 'hello'; - } - }); - obj1 = obj.extend(); - } - - afterEach() { - obj = undefined; - obj1 = undefined; - } - - ['@test Checking the detect() function on an object and its subclass'](assert) { - assert.equal(obj.detect(obj1), true); - assert.equal(obj1.detect(obj), false); +moduleFor( + 'A new EmberObject instance', + class extends AbstractTestCase { + beforeEach() { + obj = EmberObject.create({ + foo: 'bar', + total: 12345, + aMethodThatExists() {}, + aMethodThatReturnsTrue() { + return true; + }, + aMethodThatReturnsFoobar() { + return 'Foobar'; + }, + aMethodThatReturnsFalse() { + return false; + } + }); + } + + afterEach() { + obj = undefined; + } + + ['@test Should return its properties when requested using EmberObject#get']( + assert + ) { + assert.equal(get(obj, 'foo'), 'bar'); + assert.equal(get(obj, 'total'), 12345); + } + + ['@test Should allow changing of those properties by calling EmberObject#set']( + assert + ) { + assert.equal(get(obj, 'foo'), 'bar'); + assert.equal(get(obj, 'total'), 12345); + + set(obj, 'foo', 'Chunky Bacon'); + set(obj, 'total', 12); + + assert.equal(get(obj, 'foo'), 'Chunky Bacon'); + assert.equal(get(obj, 'total'), 12); + } } - - ['@test Checking the detectInstance() function on an object and its subclass'](assert) { - assert.ok(EmberObject.detectInstance(obj.create())); - assert.ok(obj.detectInstance(obj.create())); +); + +moduleFor( + 'EmberObject superclass and subclasses', + class extends AbstractTestCase { + beforeEach() { + obj = EmberObject.extend({ + method1() { + return 'hello'; + } + }); + obj1 = obj.extend(); + } + + afterEach() { + obj = undefined; + obj1 = undefined; + } + + ['@test Checking the detect() function on an object and its subclass']( + assert + ) { + assert.equal(obj.detect(obj1), true); + assert.equal(obj1.detect(obj), false); + } + + ['@test Checking the detectInstance() function on an object and its subclass']( + assert + ) { + assert.ok(EmberObject.detectInstance(obj.create())); + assert.ok(obj.detectInstance(obj.create())); + } } -}); +); diff --git a/packages/ember-runtime/tests/legacy_1x/system/object/concatenated_test.js b/packages/ember-runtime/tests/legacy_1x/system/object/concatenated_test.js index 93ac62024b1..c6673870076 100644 --- a/packages/ember-runtime/tests/legacy_1x/system/object/concatenated_test.js +++ b/packages/ember-runtime/tests/legacy_1x/system/object/concatenated_test.js @@ -14,90 +14,118 @@ import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; always defined */ -function K() { return this; } +function K() { + return this; +} let klass; -moduleFor('EmberObject Concatenated Properties', class extends AbstractTestCase { - beforeEach() { - klass = EmberObject.extend({ - concatenatedProperties: ['values', 'functions'], - values: ['a', 'b', 'c'], - functions: [K] - }); +moduleFor( + 'EmberObject Concatenated Properties', + class extends AbstractTestCase { + beforeEach() { + klass = EmberObject.extend({ + concatenatedProperties: ['values', 'functions'], + values: ['a', 'b', 'c'], + functions: [K] + }); + } + + ['@test concatenates instances'](assert) { + let obj = klass.create({ + values: ['d', 'e', 'f'] + }); + + let values = get(obj, 'values'); + let expected = ['a', 'b', 'c', 'd', 'e', 'f']; + + assert.deepEqual( + values, + expected, + `should concatenate values property (expected: ${expected}, got: ${values})` + ); + } + + ['@test concatenates subclasses'](assert) { + let subKlass = klass.extend({ + values: ['d', 'e', 'f'] + }); + let obj = subKlass.create(); + + let values = get(obj, 'values'); + let expected = ['a', 'b', 'c', 'd', 'e', 'f']; + + assert.deepEqual( + values, + expected, + `should concatenate values property (expected: ${expected}, got: ${values})` + ); + } + + ['@test concatenates reopen'](assert) { + klass.reopen({ + values: ['d', 'e', 'f'] + }); + let obj = klass.create(); + + let values = get(obj, 'values'); + let expected = ['a', 'b', 'c', 'd', 'e', 'f']; + + assert.deepEqual( + values, + expected, + `should concatenate values property (expected: ${expected}, got: ${values})` + ); + } + + ['@test concatenates mixin'](assert) { + let mixin = { + values: ['d', 'e'] + }; + let subKlass = klass.extend(mixin, { + values: ['f'] + }); + let obj = subKlass.create(); + + let values = get(obj, 'values'); + let expected = ['a', 'b', 'c', 'd', 'e', 'f']; + + assert.deepEqual( + values, + expected, + `should concatenate values property (expected: ${expected}, got: ${values})` + ); + } + + ['@test concatenates reopen, subclass, and instance'](assert) { + klass.reopen({ values: ['d'] }); + let subKlass = klass.extend({ values: ['e'] }); + let obj = subKlass.create({ values: ['f'] }); + + let values = get(obj, 'values'); + let expected = ['a', 'b', 'c', 'd', 'e', 'f']; + + assert.deepEqual( + values, + expected, + `should concatenate values property (expected: ${expected}, got: ${values})` + ); + } + + ['@test concatenates subclasses when the values are functions'](assert) { + let subKlass = klass.extend({ + functions: K + }); + let obj = subKlass.create(); + + let values = get(obj, 'functions'); + let expected = [K, K]; + + assert.deepEqual( + values, + expected, + `should concatenate functions property (expected: ${expected}, got: ${values})` + ); + } } - - - ['@test concatenates instances'](assert) { - let obj = klass.create({ - values: ['d', 'e', 'f'] - }); - - let values = get(obj, 'values'); - let expected = ['a', 'b', 'c', 'd', 'e', 'f']; - - assert.deepEqual(values, expected, `should concatenate values property (expected: ${expected}, got: ${values})`); - } - - ['@test concatenates subclasses'](assert) { - let subKlass = klass.extend({ - values: ['d', 'e', 'f'] - }); - let obj = subKlass.create(); - - let values = get(obj, 'values'); - let expected = ['a', 'b', 'c', 'd', 'e', 'f']; - - assert.deepEqual(values, expected, `should concatenate values property (expected: ${expected}, got: ${values})`); - } - - ['@test concatenates reopen'](assert) { - klass.reopen({ - values: ['d', 'e', 'f'] - }); - let obj = klass.create(); - - let values = get(obj, 'values'); - let expected = ['a', 'b', 'c', 'd', 'e', 'f']; - - assert.deepEqual(values, expected, `should concatenate values property (expected: ${expected}, got: ${values})`); - } - - ['@test concatenates mixin'](assert) { - let mixin = { - values: ['d', 'e'] - }; - let subKlass = klass.extend(mixin, { - values: ['f'] - }); - let obj = subKlass.create(); - - let values = get(obj, 'values'); - let expected = ['a', 'b', 'c', 'd', 'e', 'f']; - - assert.deepEqual(values, expected, `should concatenate values property (expected: ${expected}, got: ${values})`); - } - - ['@test concatenates reopen, subclass, and instance'](assert) { - klass.reopen({ values: ['d'] }); - let subKlass = klass.extend({ values: ['e'] }); - let obj = subKlass.create({ values: ['f'] }); - - let values = get(obj, 'values'); - let expected = ['a', 'b', 'c', 'd', 'e', 'f']; - - assert.deepEqual(values, expected, `should concatenate values property (expected: ${expected}, got: ${values})`); - } - - ['@test concatenates subclasses when the values are functions'](assert) { - let subKlass = klass.extend({ - functions: K - }); - let obj = subKlass.create(); - - let values = get(obj, 'functions'); - let expected = [K, K]; - - assert.deepEqual(values, expected, `should concatenate functions property (expected: ${expected}, got: ${values})`); - } -}); +); diff --git a/packages/ember-runtime/tests/main_test.js b/packages/ember-runtime/tests/main_test.js index 1a827716b6e..d42366ffd12 100644 --- a/packages/ember-runtime/tests/main_test.js +++ b/packages/ember-runtime/tests/main_test.js @@ -1,7 +1,4 @@ -import { - collect, - Object as EmberObject -} from '../index'; +import { collect, Object as EmberObject } from '../index'; QUnit.module('ember-runtime/main'); diff --git a/packages/ember-runtime/tests/mixins/array_test.js b/packages/ember-runtime/tests/mixins/array_test.js index 47ea28e91d3..cb52422f0a2 100644 --- a/packages/ember-runtime/tests/mixins/array_test.js +++ b/packages/ember-runtime/tests/mixins/array_test.js @@ -53,7 +53,9 @@ const TestArray = EmberObject.extend(EmberArray, { QUnit.module('Ember.Array'); -QUnit.test('the return value of slice has Ember.Array applied', function(assert) { +QUnit.test('the return value of slice has Ember.Array applied', function( + assert +) { let x = EmberObject.extend(EmberArray).create({ length: 0 }); @@ -84,7 +86,9 @@ QUnit.test('slice supports negative index arguments', function(assert) { const DummyArray = EmberObject.extend(EmberArray, { length: 0, - objectAt(idx) { return 'ITEM-' + idx; } + objectAt(idx) { + return 'ITEM-' + idx; + } }); let obj, observer; @@ -134,7 +138,9 @@ QUnit.module('notify observers of length', { } }); -QUnit.test('should notify observers when call with no params', function(assert) { +QUnit.test('should notify observers when call with no params', function( + assert +) { arrayContentWillChange(obj); assert.equal(obj._after, 0); @@ -159,7 +165,6 @@ QUnit.test('should notify when passed lengths are different', function(assert) { assert.equal(obj._after, 1); }); - // .......................................................... // NOTIFY ARRAY OBSERVER // @@ -191,7 +196,9 @@ QUnit.module('notify array observers', { } }); -QUnit.test('should notify array observers when called with no params', function(assert) { +QUnit.test('should notify array observers when called with no params', function( + assert +) { arrayContentWillChange(obj); assert.deepEqual(observer._before, [obj, 0, -1, -1]); @@ -200,7 +207,9 @@ QUnit.test('should notify array observers when called with no params', function( }); // API variation that included items only -QUnit.test('should notify when called with same length items', function(assert) { +QUnit.test('should notify when called with same length items', function( + assert +) { arrayContentWillChange(obj, 0, 1, 1); assert.deepEqual(observer._before, [obj, 0, 1, 1]); @@ -208,7 +217,9 @@ QUnit.test('should notify when called with same length items', function(assert) assert.deepEqual(observer._after, [obj, 0, 1, 1]); }); -QUnit.test('should notify when called with diff length items', function(assert) { +QUnit.test('should notify when called with diff length items', function( + assert +) { arrayContentWillChange(obj, 0, 2, 1); assert.deepEqual(observer._before, [obj, 0, 2, 1]); @@ -259,10 +270,12 @@ QUnit.test('adding an object should notify (@each.isDone)', function(assert) { addObserver(ary, '@each.isDone', observerObject, 'wasCalled'); - ary.addObject(EmberObject.create({ - desc: 'foo', - isDone: false - })); + ary.addObject( + EmberObject.create({ + desc: 'foo', + isDone: false + }) + ); assert.equal(called, 1, 'calls observer when object is pushed'); }); @@ -283,51 +296,59 @@ QUnit.test('@each is readOnly', function(assert) { }, /Cannot set read-only property "@each"/); }); -QUnit.test('using @each to observe arrays that does not return objects raise error', function(assert) { - let called = 0; +QUnit.test( + 'using @each to observe arrays that does not return objects raise error', + function(assert) { + let called = 0; - let observerObject = EmberObject.create({ - wasCalled() { - called++; - } - }); + let observerObject = EmberObject.create({ + wasCalled() { + called++; + } + }); - ary = TestArray.create({ - objectAt(idx) { - return get(this._content[idx], 'desc'); - } - }); + ary = TestArray.create({ + objectAt(idx) { + return get(this._content[idx], 'desc'); + } + }); - addObserver(ary, '@each.isDone', observerObject, 'wasCalled'); + addObserver(ary, '@each.isDone', observerObject, 'wasCalled'); - expectAssertion(() => { - ary.addObject(EmberObject.create({ - desc: 'foo', - isDone: false - })); - }, /When using @each to observe the array/); - - assert.equal(called, 0, 'not calls observer when object is pushed'); -}); + expectAssertion(() => { + ary.addObject( + EmberObject.create({ + desc: 'foo', + isDone: false + }) + ); + }, /When using @each to observe the array/); -QUnit.test('modifying the array should also indicate the isDone prop itself has changed', function(assert) { - // NOTE: we never actually get the '@each.isDone' property here. This is - // important because it tests the case where we don't have an isDone - // EachArray materialized but just want to know when the property has - // changed. - let each; - expectDeprecation(() => { - each = get(ary, '@each'); - }); - let count = 0; + assert.equal(called, 0, 'not calls observer when object is pushed'); + } +); + +QUnit.test( + 'modifying the array should also indicate the isDone prop itself has changed', + function(assert) { + // NOTE: we never actually get the '@each.isDone' property here. This is + // important because it tests the case where we don't have an isDone + // EachArray materialized but just want to know when the property has + // changed. + let each; + expectDeprecation(() => { + each = get(ary, '@each'); + }); + let count = 0; - addObserver(each, 'isDone', () => count++); + addObserver(each, 'isDone', () => count++); - count = 0; - let item = objectAt(ary, 2); - set(item, 'isDone', !get(item, 'isDone')); - assert.equal(count, 1, '@each.isDone should have notified'); -}); + count = 0; + let item = objectAt(ary, 2); + set(item, 'isDone', !get(item, 'isDone')); + assert.equal(count, 1, '@each.isDone should have notified'); + } +); QUnit.test('`objectAt` returns correct object', function(assert) { let arr = ['first', 'second', 'third', 'fourth']; @@ -335,42 +356,48 @@ QUnit.test('`objectAt` returns correct object', function(assert) { assert.equal(objectAt(arr, 4), undefined); }); -testBoth('should be clear caches for computed properties that have dependent keys on arrays that are changed after object initialization', function(get, set, assert) { - let obj = EmberObject.extend({ - init() { - this._super(...arguments); - set(this, 'resources', emberA()); - }, - - common: computed('resources.@each.common', function() { - return get(objectAt(get(this, 'resources'), 0), 'common'); - }) - }).create(); - - get(obj, 'resources').pushObject(EmberObject.create({ common: 'HI!' })); - assert.equal('HI!', get(obj, 'common')); +testBoth( + 'should be clear caches for computed properties that have dependent keys on arrays that are changed after object initialization', + function(get, set, assert) { + let obj = EmberObject.extend({ + init() { + this._super(...arguments); + set(this, 'resources', emberA()); + }, - set(objectAt(get(obj, 'resources'), 0), 'common', 'BYE!'); - assert.equal('BYE!', get(obj, 'common')); -}); + common: computed('resources.@each.common', function() { + return get(objectAt(get(this, 'resources'), 0), 'common'); + }) + }).create(); -testBoth('observers that contain @each in the path should fire only once the first time they are accessed', function(get, set, assert) { - let count = 0; + get(obj, 'resources').pushObject(EmberObject.create({ common: 'HI!' })); + assert.equal('HI!', get(obj, 'common')); - let obj = EmberObject.extend({ - init() { - this._super(...arguments); - // Observer does not fire on init - set(this, 'resources', emberA()); - }, + set(objectAt(get(obj, 'resources'), 0), 'common', 'BYE!'); + assert.equal('BYE!', get(obj, 'common')); + } +); + +testBoth( + 'observers that contain @each in the path should fire only once the first time they are accessed', + function(get, set, assert) { + let count = 0; + + let obj = EmberObject.extend({ + init() { + this._super(...arguments); + // Observer does not fire on init + set(this, 'resources', emberA()); + }, - commonDidChange: emberObserver('resources.@each.common', () => count++) - }).create(); + commonDidChange: emberObserver('resources.@each.common', () => count++) + }).create(); - // Observer fires second time when new object is added - get(obj, 'resources').pushObject(EmberObject.create({ common: 'HI!' })); - // Observer fires third time when property on an object is changed - set(objectAt(get(obj, 'resources'), 0), 'common', 'BYE!'); + // Observer fires second time when new object is added + get(obj, 'resources').pushObject(EmberObject.create({ common: 'HI!' })); + // Observer fires third time when property on an object is changed + set(objectAt(get(obj, 'resources'), 0), 'common', 'BYE!'); - assert.equal(count, 2, 'observers should only be called once'); -}); + assert.equal(count, 2, 'observers should only be called once'); + } +); diff --git a/packages/ember-runtime/tests/mixins/comparable_test.js b/packages/ember-runtime/tests/mixins/comparable_test.js index 9a1c761500b..ca8349693c5 100644 --- a/packages/ember-runtime/tests/mixins/comparable_test.js +++ b/packages/ember-runtime/tests/mixins/comparable_test.js @@ -14,7 +14,6 @@ const Rectangle = EmberObject.extend(Comparable, { compare(a, b) { return compare(a.area(), b.area()); } - }); let r1, r2; @@ -26,7 +25,9 @@ QUnit.module('Comparable', { } }); -QUnit.test('should be comparable and return the correct result', function(assert) { +QUnit.test('should be comparable and return the correct result', function( + assert +) { assert.equal(Comparable.detect(r1), true); assert.equal(compare(r1, r1), 0); assert.equal(compare(r1, r2), -1); diff --git a/packages/ember-runtime/tests/mixins/container_proxy_test.js b/packages/ember-runtime/tests/mixins/container_proxy_test.js index 9ba74b91dc6..bf4ac7f8083 100644 --- a/packages/ember-runtime/tests/mixins/container_proxy_test.js +++ b/packages/ember-runtime/tests/mixins/container_proxy_test.js @@ -19,5 +19,9 @@ QUnit.module('ember-runtime/mixins/container_proxy', { QUnit.test('provides ownerInjection helper method', function(assert) { let result = this.instance.ownerInjection(); - assert.equal(result[OWNER], this.instance, 'returns an object with the OWNER symbol'); + assert.equal( + result[OWNER], + this.instance, + 'returns an object with the OWNER symbol' + ); }); diff --git a/packages/ember-runtime/tests/mixins/evented_test.js b/packages/ember-runtime/tests/mixins/evented_test.js index 6d156018251..c806506335f 100644 --- a/packages/ember-runtime/tests/mixins/evented_test.js +++ b/packages/ember-runtime/tests/mixins/evented_test.js @@ -15,8 +15,5 @@ QUnit.test('works properly on proxy-ish objects', function(assert) { eventedProxyObj.on('foo', noop); eventedProxyObj.off('foo', noop); - assert.ok( - true, - "An assertion was triggered" - ); + assert.ok(true, 'An assertion was triggered'); }); diff --git a/packages/ember-runtime/tests/mixins/observable_test.js b/packages/ember-runtime/tests/mixins/observable_test.js index 92446c62339..3de63f47d5c 100644 --- a/packages/ember-runtime/tests/mixins/observable_test.js +++ b/packages/ember-runtime/tests/mixins/observable_test.js @@ -4,48 +4,65 @@ import EmberObject from '../../system/object'; QUnit.module('mixins/observable'); -QUnit.test('should be able to use getProperties to get a POJO of provided keys', function(assert) { - let obj = EmberObject.create({ - firstName: 'Steve', - lastName: 'Jobs', - companyName: 'Apple, Inc.' - }); - - let pojo = obj.getProperties('firstName', 'lastName'); - assert.equal('Steve', pojo.firstName); - assert.equal('Jobs', pojo.lastName); -}); - -QUnit.test('should be able to use getProperties with array parameter to get a POJO of provided keys', function(assert) { - let obj = EmberObject.create({ - firstName: 'Steve', - lastName: 'Jobs', - companyName: 'Apple, Inc.' - }); +QUnit.test( + 'should be able to use getProperties to get a POJO of provided keys', + function(assert) { + let obj = EmberObject.create({ + firstName: 'Steve', + lastName: 'Jobs', + companyName: 'Apple, Inc.' + }); - let pojo = obj.getProperties(['firstName', 'lastName']); - assert.equal('Steve', pojo.firstName); - assert.equal('Jobs', pojo.lastName); -}); + let pojo = obj.getProperties('firstName', 'lastName'); + assert.equal('Steve', pojo.firstName); + assert.equal('Jobs', pojo.lastName); + } +); + +QUnit.test( + 'should be able to use getProperties with array parameter to get a POJO of provided keys', + function(assert) { + let obj = EmberObject.create({ + firstName: 'Steve', + lastName: 'Jobs', + companyName: 'Apple, Inc.' + }); -QUnit.test('should be able to use setProperties to set multiple properties at once', function(assert) { - let obj = EmberObject.create({ - firstName: 'Steve', - lastName: 'Jobs', - companyName: 'Apple, Inc.' - }); + let pojo = obj.getProperties(['firstName', 'lastName']); + assert.equal('Steve', pojo.firstName); + assert.equal('Jobs', pojo.lastName); + } +); + +QUnit.test( + 'should be able to use setProperties to set multiple properties at once', + function(assert) { + let obj = EmberObject.create({ + firstName: 'Steve', + lastName: 'Jobs', + companyName: 'Apple, Inc.' + }); - obj.setProperties({ firstName: 'Tim', lastName: 'Cook' }); - assert.equal('Tim', obj.get('firstName')); - assert.equal('Cook', obj.get('lastName')); -}); + obj.setProperties({ firstName: 'Tim', lastName: 'Cook' }); + assert.equal('Tim', obj.get('firstName')); + assert.equal('Cook', obj.get('lastName')); + } +); -testBoth('calling setProperties completes safely despite exceptions', function(get, set, assert) { +testBoth('calling setProperties completes safely despite exceptions', function( + get, + set, + assert +) { let exc = new Error('Something unexpected happened!'); let obj = EmberObject.extend({ companyName: computed({ - get() { return 'Apple, Inc.'; }, - set() { throw exc; } + get() { + return 'Apple, Inc.'; + }, + set() { + throw exc; + } }) }).create({ firstName: 'Steve', @@ -71,33 +88,51 @@ testBoth('calling setProperties completes safely despite exceptions', function(g assert.equal(firstNameChangedCount, 1, 'firstName should have fired once'); }); -testBoth('should be able to retrieve cached values of computed properties without invoking the computed property', function(get, set, assert) { - let obj = EmberObject.extend({ - foo: computed(function() { - return 'foo'; - }) - }).create({ - bar: 'bar' - }); - - assert.equal(obj.cacheFor('foo'), undefined, 'should return undefined if no value has been cached'); - get(obj, 'foo'); - - assert.equal(get(obj, 'foo'), 'foo', 'precond - should cache the value'); - assert.equal(obj.cacheFor('foo'), 'foo', 'should return the cached value after it is invoked'); +testBoth( + 'should be able to retrieve cached values of computed properties without invoking the computed property', + function(get, set, assert) { + let obj = EmberObject.extend({ + foo: computed(function() { + return 'foo'; + }) + }).create({ + bar: 'bar' + }); - assert.equal(obj.cacheFor('bar'), undefined, 'returns undefined if the value is not a computed property'); -}); + assert.equal( + obj.cacheFor('foo'), + undefined, + 'should return undefined if no value has been cached' + ); + get(obj, 'foo'); + + assert.equal(get(obj, 'foo'), 'foo', 'precond - should cache the value'); + assert.equal( + obj.cacheFor('foo'), + 'foo', + 'should return the cached value after it is invoked' + ); + + assert.equal( + obj.cacheFor('bar'), + undefined, + 'returns undefined if the value is not a computed property' + ); + } +); -QUnit.test('incrementProperty should work even if value is number in string', function(assert) { - let obj = EmberObject.create({ - age: '24' - }); - obj.incrementProperty('age'); - assert.equal(25, obj.get('age')); -}); +QUnit.test( + 'incrementProperty should work even if value is number in string', + function(assert) { + let obj = EmberObject.create({ + age: '24' + }); + obj.incrementProperty('age'); + assert.equal(25, obj.get('age')); + } +); -QUnit.test('propertyWillChange triggers a deprecation warning', function () { +QUnit.test('propertyWillChange triggers a deprecation warning', function() { let obj = EmberObject.create(); expectDeprecation(() => { @@ -105,7 +140,7 @@ QUnit.test('propertyWillChange triggers a deprecation warning', function () { }, /'propertyWillChange' is deprecated and has no effect. It is safe to remove this call./); }); -QUnit.test('propertyDidChange triggers a deprecation warning', function () { +QUnit.test('propertyDidChange triggers a deprecation warning', function() { let obj = EmberObject.create(); expectDeprecation(() => { diff --git a/packages/ember-runtime/tests/mixins/promise_proxy_test.js b/packages/ember-runtime/tests/mixins/promise_proxy_test.js index a76b9d8fcf9..b71a714c166 100644 --- a/packages/ember-runtime/tests/mixins/promise_proxy_test.js +++ b/packages/ember-runtime/tests/mixins/promise_proxy_test.js @@ -2,9 +2,7 @@ import { get, run } from 'ember-metal'; import ObjectProxy from '../../system/object_proxy'; import PromiseProxyMixin from '../../mixins/promise_proxy'; import EmberRSVP from '../../ext/rsvp'; -import { - onerrorDefault -} from '../../ext/rsvp'; +import { onerrorDefault } from '../../ext/rsvp'; import * as RSVP from 'rsvp'; let ObjectPromiseProxy; @@ -27,8 +25,15 @@ QUnit.test('no promise, invoking then should raise', function(assert) { let proxy = ObjectPromiseProxy.create(); assert.throws(function() { - proxy.then(function() { return this; }, function() { return this; }); - }, new RegExp('PromiseProxy\'s promise must be set')); + proxy.then( + function() { + return this; + }, + function() { + return this; + } + ); + }, new RegExp("PromiseProxy's promise must be set")); }); QUnit.test('fulfillment', function(assert) { @@ -44,17 +49,40 @@ QUnit.test('fulfillment', function(assert) { }); let didFulfillCount = 0; - let didRejectCount = 0; - - proxy.then(() => didFulfillCount++, - () => didRejectCount++); + let didRejectCount = 0; - assert.equal(get(proxy, 'content'), undefined, 'expects the proxy to have no content'); - assert.equal(get(proxy, 'reason'), undefined, 'expects the proxy to have no reason'); - assert.equal(get(proxy, 'isPending'), true, 'expects the proxy to indicate that it is loading'); - assert.equal(get(proxy, 'isSettled'), false, 'expects the proxy to indicate that it is not settled'); - assert.equal(get(proxy, 'isRejected'), false, 'expects the proxy to indicate that it is not rejected'); - assert.equal(get(proxy, 'isFulfilled'), false, 'expects the proxy to indicate that it is not fulfilled'); + proxy.then(() => didFulfillCount++, () => didRejectCount++); + + assert.equal( + get(proxy, 'content'), + undefined, + 'expects the proxy to have no content' + ); + assert.equal( + get(proxy, 'reason'), + undefined, + 'expects the proxy to have no reason' + ); + assert.equal( + get(proxy, 'isPending'), + true, + 'expects the proxy to indicate that it is loading' + ); + assert.equal( + get(proxy, 'isSettled'), + false, + 'expects the proxy to indicate that it is not settled' + ); + assert.equal( + get(proxy, 'isRejected'), + false, + 'expects the proxy to indicate that it is not rejected' + ); + assert.equal( + get(proxy, 'isFulfilled'), + false, + 'expects the proxy to indicate that it is not fulfilled' + ); assert.equal(didFulfillCount, 0, 'should not yet have been fulfilled'); assert.equal(didRejectCount, 0, 'should not yet have been rejected'); @@ -64,29 +92,85 @@ QUnit.test('fulfillment', function(assert) { assert.equal(didFulfillCount, 1, 'should have been fulfilled'); assert.equal(didRejectCount, 0, 'should not have been rejected'); - assert.equal(get(proxy, 'content'), value, 'expects the proxy to have content'); - assert.equal(get(proxy, 'reason'), undefined, 'expects the proxy to still have no reason'); - assert.equal(get(proxy, 'isPending'), false, 'expects the proxy to indicate that it is no longer loading'); - assert.equal(get(proxy, 'isSettled'), true, 'expects the proxy to indicate that it is settled'); - assert.equal(get(proxy, 'isRejected'), false, 'expects the proxy to indicate that it is not rejected'); - assert.equal(get(proxy, 'isFulfilled'), true, 'expects the proxy to indicate that it is fulfilled'); + assert.equal( + get(proxy, 'content'), + value, + 'expects the proxy to have content' + ); + assert.equal( + get(proxy, 'reason'), + undefined, + 'expects the proxy to still have no reason' + ); + assert.equal( + get(proxy, 'isPending'), + false, + 'expects the proxy to indicate that it is no longer loading' + ); + assert.equal( + get(proxy, 'isSettled'), + true, + 'expects the proxy to indicate that it is settled' + ); + assert.equal( + get(proxy, 'isRejected'), + false, + 'expects the proxy to indicate that it is not rejected' + ); + assert.equal( + get(proxy, 'isFulfilled'), + true, + 'expects the proxy to indicate that it is fulfilled' + ); run(deferred, 'resolve', value); - assert.equal(didFulfillCount, 1, 'should still have been only fulfilled once'); + assert.equal( + didFulfillCount, + 1, + 'should still have been only fulfilled once' + ); assert.equal(didRejectCount, 0, 'should still not have been rejected'); run(deferred, 'reject', value); - assert.equal(didFulfillCount, 1, 'should still have been only fulfilled once'); + assert.equal( + didFulfillCount, + 1, + 'should still have been only fulfilled once' + ); assert.equal(didRejectCount, 0, 'should still not have been rejected'); - assert.equal(get(proxy, 'content'), value, 'expects the proxy to have still have same content'); - assert.equal(get(proxy, 'reason'), undefined, 'expects the proxy still to have no reason'); - assert.equal(get(proxy, 'isPending'), false, 'expects the proxy to indicate that it is no longer loading'); - assert.equal(get(proxy, 'isSettled'), true, 'expects the proxy to indicate that it is settled'); - assert.equal(get(proxy, 'isRejected'), false, 'expects the proxy to indicate that it is not rejected'); - assert.equal(get(proxy, 'isFulfilled'), true, 'expects the proxy to indicate that it is fulfilled'); + assert.equal( + get(proxy, 'content'), + value, + 'expects the proxy to have still have same content' + ); + assert.equal( + get(proxy, 'reason'), + undefined, + 'expects the proxy still to have no reason' + ); + assert.equal( + get(proxy, 'isPending'), + false, + 'expects the proxy to indicate that it is no longer loading' + ); + assert.equal( + get(proxy, 'isSettled'), + true, + 'expects the proxy to indicate that it is settled' + ); + assert.equal( + get(proxy, 'isRejected'), + false, + 'expects the proxy to indicate that it is not rejected' + ); + assert.equal( + get(proxy, 'isFulfilled'), + true, + 'expects the proxy to indicate that it is fulfilled' + ); // rest of the promise semantics are tested in directly in RSVP }); @@ -99,17 +183,40 @@ QUnit.test('rejection', function(assert) { }); let didFulfillCount = 0; - let didRejectCount = 0; - - proxy.then(() => didFulfillCount++, - () => didRejectCount++); + let didRejectCount = 0; - assert.equal(get(proxy, 'content'), undefined, 'expects the proxy to have no content'); - assert.equal(get(proxy, 'reason'), undefined, 'expects the proxy to have no reason'); - assert.equal(get(proxy, 'isPending'), true, 'expects the proxy to indicate that it is loading'); - assert.equal(get(proxy, 'isSettled'), false, 'expects the proxy to indicate that it is not settled'); - assert.equal(get(proxy, 'isRejected'), false, 'expects the proxy to indicate that it is not rejected'); - assert.equal(get(proxy, 'isFulfilled'), false, 'expects the proxy to indicate that it is not fulfilled'); + proxy.then(() => didFulfillCount++, () => didRejectCount++); + + assert.equal( + get(proxy, 'content'), + undefined, + 'expects the proxy to have no content' + ); + assert.equal( + get(proxy, 'reason'), + undefined, + 'expects the proxy to have no reason' + ); + assert.equal( + get(proxy, 'isPending'), + true, + 'expects the proxy to indicate that it is loading' + ); + assert.equal( + get(proxy, 'isSettled'), + false, + 'expects the proxy to indicate that it is not settled' + ); + assert.equal( + get(proxy, 'isRejected'), + false, + 'expects the proxy to indicate that it is not rejected' + ); + assert.equal( + get(proxy, 'isFulfilled'), + false, + 'expects the proxy to indicate that it is not fulfilled' + ); assert.equal(didFulfillCount, 0, 'should not yet have been fulfilled'); assert.equal(didRejectCount, 0, 'should not yet have been rejected'); @@ -119,12 +226,36 @@ QUnit.test('rejection', function(assert) { assert.equal(didFulfillCount, 0, 'should not yet have been fulfilled'); assert.equal(didRejectCount, 1, 'should have been rejected'); - assert.equal(get(proxy, 'content'), undefined, 'expects the proxy to have no content'); - assert.equal(get(proxy, 'reason'), reason, 'expects the proxy to have a reason'); - assert.equal(get(proxy, 'isPending'), false, 'expects the proxy to indicate that it is not longer loading'); - assert.equal(get(proxy, 'isSettled'), true, 'expects the proxy to indicate that it is settled'); - assert.equal(get(proxy, 'isRejected'), true, 'expects the proxy to indicate that it is rejected'); - assert.equal(get(proxy, 'isFulfilled'), false, 'expects the proxy to indicate that it is not fulfilled'); + assert.equal( + get(proxy, 'content'), + undefined, + 'expects the proxy to have no content' + ); + assert.equal( + get(proxy, 'reason'), + reason, + 'expects the proxy to have a reason' + ); + assert.equal( + get(proxy, 'isPending'), + false, + 'expects the proxy to indicate that it is not longer loading' + ); + assert.equal( + get(proxy, 'isSettled'), + true, + 'expects the proxy to indicate that it is settled' + ); + assert.equal( + get(proxy, 'isRejected'), + true, + 'expects the proxy to indicate that it is rejected' + ); + assert.equal( + get(proxy, 'isFulfilled'), + false, + 'expects the proxy to indicate that it is not fulfilled' + ); run(deferred, 'reject', reason); @@ -136,12 +267,36 @@ QUnit.test('rejection', function(assert) { assert.equal(didFulfillCount, 0, 'should stll not yet have been fulfilled'); assert.equal(didRejectCount, 1, 'should still remain rejected'); - assert.equal(get(proxy, 'content'), undefined, 'expects the proxy to have no content'); - assert.equal(get(proxy, 'reason'), reason, 'expects the proxy to have a reason'); - assert.equal(get(proxy, 'isPending'), false, 'expects the proxy to indicate that it is not longer loading'); - assert.equal(get(proxy, 'isSettled'), true, 'expects the proxy to indicate that it is settled'); - assert.equal(get(proxy, 'isRejected'), true, 'expects the proxy to indicate that it is rejected'); - assert.equal(get(proxy, 'isFulfilled'), false, 'expects the proxy to indicate that it is not fulfilled'); + assert.equal( + get(proxy, 'content'), + undefined, + 'expects the proxy to have no content' + ); + assert.equal( + get(proxy, 'reason'), + reason, + 'expects the proxy to have a reason' + ); + assert.equal( + get(proxy, 'isPending'), + false, + 'expects the proxy to indicate that it is not longer loading' + ); + assert.equal( + get(proxy, 'isSettled'), + true, + 'expects the proxy to indicate that it is settled' + ); + assert.equal( + get(proxy, 'isRejected'), + true, + 'expects the proxy to indicate that it is rejected' + ); + assert.equal( + get(proxy, 'isFulfilled'), + false, + 'expects the proxy to indicate that it is not fulfilled' + ); }); // https://github.com/emberjs/ember.js/issues/15694 @@ -152,17 +307,40 @@ QUnit.test('rejection without specifying reason', function(assert) { }); let didFulfillCount = 0; - let didRejectCount = 0; - - proxy.then(() => didFulfillCount++, - () => didRejectCount++); + let didRejectCount = 0; - assert.equal(get(proxy, 'content'), undefined, 'expects the proxy to have no content'); - assert.equal(get(proxy, 'reason'), undefined, 'expects the proxy to have no reason'); - assert.equal(get(proxy, 'isPending'), true, 'expects the proxy to indicate that it is loading'); - assert.equal(get(proxy, 'isSettled'), false, 'expects the proxy to indicate that it is not settled'); - assert.equal(get(proxy, 'isRejected'), false, 'expects the proxy to indicate that it is not rejected'); - assert.equal(get(proxy, 'isFulfilled'), false, 'expects the proxy to indicate that it is not fulfilled'); + proxy.then(() => didFulfillCount++, () => didRejectCount++); + + assert.equal( + get(proxy, 'content'), + undefined, + 'expects the proxy to have no content' + ); + assert.equal( + get(proxy, 'reason'), + undefined, + 'expects the proxy to have no reason' + ); + assert.equal( + get(proxy, 'isPending'), + true, + 'expects the proxy to indicate that it is loading' + ); + assert.equal( + get(proxy, 'isSettled'), + false, + 'expects the proxy to indicate that it is not settled' + ); + assert.equal( + get(proxy, 'isRejected'), + false, + 'expects the proxy to indicate that it is not rejected' + ); + assert.equal( + get(proxy, 'isFulfilled'), + false, + 'expects the proxy to indicate that it is not fulfilled' + ); assert.equal(didFulfillCount, 0, 'should not yet have been fulfilled'); assert.equal(didRejectCount, 0, 'should not yet have been rejected'); @@ -172,91 +350,188 @@ QUnit.test('rejection without specifying reason', function(assert) { assert.equal(didFulfillCount, 0, 'should not yet have been fulfilled'); assert.equal(didRejectCount, 1, 'should have been rejected'); - assert.equal(get(proxy, 'content'), undefined, 'expects the proxy to have no content'); - assert.equal(get(proxy, 'reason'), undefined, 'expects the proxy to have a reason'); - assert.equal(get(proxy, 'isPending'), false, 'expects the proxy to indicate that it is not longer loading'); - assert.equal(get(proxy, 'isSettled'), true, 'expects the proxy to indicate that it is settled'); - assert.equal(get(proxy, 'isRejected'), true, 'expects the proxy to indicate that it is rejected'); - assert.equal(get(proxy, 'isFulfilled'), false, 'expects the proxy to indicate that it is not fulfilled'); + assert.equal( + get(proxy, 'content'), + undefined, + 'expects the proxy to have no content' + ); + assert.equal( + get(proxy, 'reason'), + undefined, + 'expects the proxy to have a reason' + ); + assert.equal( + get(proxy, 'isPending'), + false, + 'expects the proxy to indicate that it is not longer loading' + ); + assert.equal( + get(proxy, 'isSettled'), + true, + 'expects the proxy to indicate that it is settled' + ); + assert.equal( + get(proxy, 'isRejected'), + true, + 'expects the proxy to indicate that it is rejected' + ); + assert.equal( + get(proxy, 'isFulfilled'), + false, + 'expects the proxy to indicate that it is not fulfilled' + ); }); -QUnit.test('unhandled rejects still propagate to RSVP.on(\'error\', ...) ', function(assert) { - assert.expect(1); +QUnit.test( + "unhandled rejects still propagate to RSVP.on('error', ...) ", + function(assert) { + assert.expect(1); - RSVP.on('error', onerror); - RSVP.off('error', onerrorDefault); + RSVP.on('error', onerror); + RSVP.off('error', onerrorDefault); - let expectedReason = new Error('failure'); - let deferred = RSVP.defer(); + let expectedReason = new Error('failure'); + let deferred = RSVP.defer(); - let proxy = ObjectPromiseProxy.create({ - promise: deferred.promise - }); + let proxy = ObjectPromiseProxy.create({ + promise: deferred.promise + }); - proxy.get('promise'); + proxy.get('promise'); - function onerror(reason) { - assert.equal(reason, expectedReason, 'expected reason'); - } + function onerror(reason) { + assert.equal(reason, expectedReason, 'expected reason'); + } - RSVP.on('error', onerror); - RSVP.off('error', onerrorDefault); + RSVP.on('error', onerror); + RSVP.off('error', onerrorDefault); - run(deferred, 'reject', expectedReason); + run(deferred, 'reject', expectedReason); - RSVP.on('error', onerrorDefault); - RSVP.off('error', onerror); + RSVP.on('error', onerrorDefault); + RSVP.off('error', onerror); - run(deferred, 'reject', expectedReason); + run(deferred, 'reject', expectedReason); - RSVP.on('error', onerrorDefault); - RSVP.off('error', onerror); -}); + RSVP.on('error', onerrorDefault); + RSVP.off('error', onerror); + } +); QUnit.test('should work with promise inheritance', function(assert) { - class PromiseSubclass extends RSVP.Promise { } + class PromiseSubclass extends RSVP.Promise {} let proxy = ObjectPromiseProxy.create({ - promise: new PromiseSubclass(() => { }) + promise: new PromiseSubclass(() => {}) }); - assert.ok(proxy.then() instanceof PromiseSubclass, 'promise proxy respected inheritance'); + assert.ok( + proxy.then() instanceof PromiseSubclass, + 'promise proxy respected inheritance' + ); }); -QUnit.test('should reset isFulfilled and isRejected when promise is reset', function(assert) { - let deferred = EmberRSVP.defer(); - - let proxy = ObjectPromiseProxy.create({ - promise: deferred.promise - }); - - assert.equal(get(proxy, 'isPending'), true, 'expects the proxy to indicate that it is loading'); - assert.equal(get(proxy, 'isSettled'), false, 'expects the proxy to indicate that it is not settled'); - assert.equal(get(proxy, 'isRejected'), false, 'expects the proxy to indicate that it is not rejected'); - assert.equal(get(proxy, 'isFulfilled'), false, 'expects the proxy to indicate that it is not fulfilled'); - - run(deferred, 'resolve'); - - assert.equal(get(proxy, 'isPending'), false, 'expects the proxy to indicate that it is no longer loading'); - assert.equal(get(proxy, 'isSettled'), true, 'expects the proxy to indicate that it is settled'); - assert.equal(get(proxy, 'isRejected'), false, 'expects the proxy to indicate that it is not rejected'); - assert.equal(get(proxy, 'isFulfilled'), true, 'expects the proxy to indicate that it is fulfilled'); +QUnit.test( + 'should reset isFulfilled and isRejected when promise is reset', + function(assert) { + let deferred = EmberRSVP.defer(); - let anotherDeferred = EmberRSVP.defer(); - proxy.set('promise', anotherDeferred.promise); - - assert.equal(get(proxy, 'isPending'), true, 'expects the proxy to indicate that it is loading'); - assert.equal(get(proxy, 'isSettled'), false, 'expects the proxy to indicate that it is not settled'); - assert.equal(get(proxy, 'isRejected'), false, 'expects the proxy to indicate that it is not rejected'); - assert.equal(get(proxy, 'isFulfilled'), false, 'expects the proxy to indicate that it is not fulfilled'); - - run(anotherDeferred, 'reject'); + let proxy = ObjectPromiseProxy.create({ + promise: deferred.promise + }); - assert.equal(get(proxy, 'isPending'), false, 'expects the proxy to indicate that it is not longer loading'); - assert.equal(get(proxy, 'isSettled'), true, 'expects the proxy to indicate that it is settled'); - assert.equal(get(proxy, 'isRejected'), true, 'expects the proxy to indicate that it is rejected'); - assert.equal(get(proxy, 'isFulfilled'), false, 'expects the proxy to indicate that it is not fulfilled'); -}); + assert.equal( + get(proxy, 'isPending'), + true, + 'expects the proxy to indicate that it is loading' + ); + assert.equal( + get(proxy, 'isSettled'), + false, + 'expects the proxy to indicate that it is not settled' + ); + assert.equal( + get(proxy, 'isRejected'), + false, + 'expects the proxy to indicate that it is not rejected' + ); + assert.equal( + get(proxy, 'isFulfilled'), + false, + 'expects the proxy to indicate that it is not fulfilled' + ); + + run(deferred, 'resolve'); + + assert.equal( + get(proxy, 'isPending'), + false, + 'expects the proxy to indicate that it is no longer loading' + ); + assert.equal( + get(proxy, 'isSettled'), + true, + 'expects the proxy to indicate that it is settled' + ); + assert.equal( + get(proxy, 'isRejected'), + false, + 'expects the proxy to indicate that it is not rejected' + ); + assert.equal( + get(proxy, 'isFulfilled'), + true, + 'expects the proxy to indicate that it is fulfilled' + ); + + let anotherDeferred = EmberRSVP.defer(); + proxy.set('promise', anotherDeferred.promise); + + assert.equal( + get(proxy, 'isPending'), + true, + 'expects the proxy to indicate that it is loading' + ); + assert.equal( + get(proxy, 'isSettled'), + false, + 'expects the proxy to indicate that it is not settled' + ); + assert.equal( + get(proxy, 'isRejected'), + false, + 'expects the proxy to indicate that it is not rejected' + ); + assert.equal( + get(proxy, 'isFulfilled'), + false, + 'expects the proxy to indicate that it is not fulfilled' + ); + + run(anotherDeferred, 'reject'); + + assert.equal( + get(proxy, 'isPending'), + false, + 'expects the proxy to indicate that it is not longer loading' + ); + assert.equal( + get(proxy, 'isSettled'), + true, + 'expects the proxy to indicate that it is settled' + ); + assert.equal( + get(proxy, 'isRejected'), + true, + 'expects the proxy to indicate that it is rejected' + ); + assert.equal( + get(proxy, 'isFulfilled'), + false, + 'expects the proxy to indicate that it is not fulfilled' + ); + } +); QUnit.test('should have content when isFulfilled is set', function(assert) { let deferred = EmberRSVP.defer(); @@ -265,7 +540,9 @@ QUnit.test('should have content when isFulfilled is set', function(assert) { promise: deferred.promise }); - proxy.addObserver('isFulfilled', () => assert.equal(get(proxy, 'content'), true)); + proxy.addObserver('isFulfilled', () => + assert.equal(get(proxy, 'content'), true) + ); run(deferred, 'resolve', true); }); @@ -278,7 +555,9 @@ QUnit.test('should have reason when isRejected is set', function(assert) { promise: deferred.promise }); - proxy.addObserver('isRejected', () => assert.equal(get(proxy, 'reason'), error)); + proxy.addObserver('isRejected', () => + assert.equal(get(proxy, 'reason'), error) + ); try { run(deferred, 'reject', error); @@ -287,82 +566,112 @@ QUnit.test('should have reason when isRejected is set', function(assert) { } }); -QUnit.test('should not error if promise is resolved after proxy has been destroyed', function(assert) { - let deferred = EmberRSVP.defer(); - - let proxy = ObjectPromiseProxy.create({ - promise: deferred.promise - }); - - proxy.then(() => {}, () => {}); - - run(proxy, 'destroy'); - - run(deferred, 'resolve', true); - - assert.ok(true, 'resolving the promise after the proxy has been destroyed does not raise an error'); -}); +QUnit.test( + 'should not error if promise is resolved after proxy has been destroyed', + function(assert) { + let deferred = EmberRSVP.defer(); -QUnit.test('should not error if promise is rejected after proxy has been destroyed', function(assert) { - let deferred = EmberRSVP.defer(); + let proxy = ObjectPromiseProxy.create({ + promise: deferred.promise + }); - let proxy = ObjectPromiseProxy.create({ - promise: deferred.promise - }); + proxy.then(() => {}, () => {}); - proxy.then(() => {}, () => {}); + run(proxy, 'destroy'); - run(proxy, 'destroy'); + run(deferred, 'resolve', true); - run(deferred, 'reject', 'some reason'); + assert.ok( + true, + 'resolving the promise after the proxy has been destroyed does not raise an error' + ); + } +); - assert.ok(true, 'rejecting the promise after the proxy has been destroyed does not raise an error'); -}); +QUnit.test( + 'should not error if promise is rejected after proxy has been destroyed', + function(assert) { + let deferred = EmberRSVP.defer(); -QUnit.test('promise chain is not broken if promised is resolved after proxy has been destroyed', function(assert) { - let deferred = EmberRSVP.defer(); - let expectedValue = {}; - let receivedValue; - let didResolveCount = 0; + let proxy = ObjectPromiseProxy.create({ + promise: deferred.promise + }); - let proxy = ObjectPromiseProxy.create({ - promise: deferred.promise - }); + proxy.then(() => {}, () => {}); - proxy.then((value) => { - receivedValue = value; - didResolveCount++; - }, () => {}); + run(proxy, 'destroy'); - run(proxy, 'destroy'); + run(deferred, 'reject', 'some reason'); - run(deferred, 'resolve', expectedValue); + assert.ok( + true, + 'rejecting the promise after the proxy has been destroyed does not raise an error' + ); + } +); + +QUnit.test( + 'promise chain is not broken if promised is resolved after proxy has been destroyed', + function(assert) { + let deferred = EmberRSVP.defer(); + let expectedValue = {}; + let receivedValue; + let didResolveCount = 0; + + let proxy = ObjectPromiseProxy.create({ + promise: deferred.promise + }); - assert.equal(didResolveCount, 1, 'callback called'); - assert.equal(receivedValue, expectedValue, 'passed value is the value the promise was resolved with'); -}); + proxy.then( + value => { + receivedValue = value; + didResolveCount++; + }, + () => {} + ); -QUnit.test('promise chain is not broken if promised is rejected after proxy has been destroyed', function(assert) { - let deferred = EmberRSVP.defer(); - let expectedReason = 'some reason'; - let receivedReason; - let didRejectCount = 0; + run(proxy, 'destroy'); - let proxy = ObjectPromiseProxy.create({ - promise: deferred.promise - }); + run(deferred, 'resolve', expectedValue); - proxy.then( - () => {}, - (reason) => { - receivedReason = reason; - didRejectCount++; + assert.equal(didResolveCount, 1, 'callback called'); + assert.equal( + receivedValue, + expectedValue, + 'passed value is the value the promise was resolved with' + ); + } +); + +QUnit.test( + 'promise chain is not broken if promised is rejected after proxy has been destroyed', + function(assert) { + let deferred = EmberRSVP.defer(); + let expectedReason = 'some reason'; + let receivedReason; + let didRejectCount = 0; + + let proxy = ObjectPromiseProxy.create({ + promise: deferred.promise }); - run(proxy, 'destroy'); + proxy.then( + () => {}, + reason => { + receivedReason = reason; + didRejectCount++; + } + ); - run(deferred, 'reject', expectedReason); + run(proxy, 'destroy'); - assert.equal(didRejectCount, 1, 'callback called'); - assert.equal(receivedReason, expectedReason, 'passed reason is the reason the promise was rejected for'); -}); + run(deferred, 'reject', expectedReason); + + assert.equal(didRejectCount, 1, 'callback called'); + assert.equal( + receivedReason, + expectedReason, + 'passed reason is the reason the promise was rejected for' + ); + } +); diff --git a/packages/ember-runtime/tests/mixins/target_action_support_test.js b/packages/ember-runtime/tests/mixins/target_action_support_test.js index 67fa7ee598f..263ce636f50 100644 --- a/packages/ember-runtime/tests/mixins/target_action_support_test.js +++ b/packages/ember-runtime/tests/mixins/target_action_support_test.js @@ -14,13 +14,19 @@ QUnit.module('TargetActionSupport', { } }); -QUnit.test('it should return false if no target or action are specified', function(assert) { - assert.expect(1); +QUnit.test( + 'it should return false if no target or action are specified', + function(assert) { + assert.expect(1); - let obj = EmberObject.extend(TargetActionSupport).create(); + let obj = EmberObject.extend(TargetActionSupport).create(); - assert.ok(false === obj.triggerAction(), 'no target or action was specified'); -}); + assert.ok( + false === obj.triggerAction(), + 'no target or action was specified' + ); + } +); QUnit.test('it should support actions specified as strings', function(assert) { assert.expect(2); @@ -35,27 +41,46 @@ QUnit.test('it should support actions specified as strings', function(assert) { action: 'anEvent' }); - assert.ok(true === obj.triggerAction(), 'a valid target and action were specified'); + assert.ok( + true === obj.triggerAction(), + 'a valid target and action were specified' + ); }); -QUnit.test('it should invoke the send() method on objects that implement it', function(assert) { - assert.expect(3); - - let obj = EmberObject.extend(TargetActionSupport).create({ - target: EmberObject.create({ - send(evt, context) { - assert.equal(evt, 'anEvent', 'send() method was invoked with correct event name'); - assert.equal(context, obj, 'send() method was invoked with correct context'); - } - }), +QUnit.test( + 'it should invoke the send() method on objects that implement it', + function(assert) { + assert.expect(3); + + let obj = EmberObject.extend(TargetActionSupport).create({ + target: EmberObject.create({ + send(evt, context) { + assert.equal( + evt, + 'anEvent', + 'send() method was invoked with correct event name' + ); + assert.equal( + context, + obj, + 'send() method was invoked with correct context' + ); + } + }), - action: 'anEvent' - }); + action: 'anEvent' + }); - assert.ok(true === obj.triggerAction(), 'a valid target and action were specified'); -}); + assert.ok( + true === obj.triggerAction(), + 'a valid target and action were specified' + ); + } +); -QUnit.test('it should find targets specified using a property path', function(assert) { +QUnit.test('it should find targets specified using a property path', function( + assert +) { assert.expect(2); let Test = {}; @@ -72,64 +97,97 @@ QUnit.test('it should find targets specified using a property path', function(as action: 'anEvent' }); - assert.ok(true === myObj.triggerAction(), 'a valid target and action were specified'); + assert.ok( + true === myObj.triggerAction(), + 'a valid target and action were specified' + ); }); -QUnit.test('it should use an actionContext object specified as a property on the object', function(assert) { - assert.expect(2); - let obj = EmberObject.extend(TargetActionSupport).create({ - action: 'anEvent', - actionContext: {}, - target: EmberObject.create({ - anEvent(ctx) { - assert.ok(obj.actionContext === ctx, 'anEvent method was called with the expected context'); - } - }) - }); - assert.ok(true === obj.triggerAction(), 'a valid target and action were specified'); -}); - - -QUnit.test('it should raise a deprecation warning when targetObject is specified and used', function(assert) { - assert.expect(4); - let obj; - expectDeprecation(() => { - obj = EmberObject.extend(TargetActionSupport).create({ +QUnit.test( + 'it should use an actionContext object specified as a property on the object', + function(assert) { + assert.expect(2); + let obj = EmberObject.extend(TargetActionSupport).create({ action: 'anEvent', actionContext: {}, - targetObject: EmberObject.create({ + target: EmberObject.create({ anEvent(ctx) { - assert.ok(obj.actionContext === ctx, 'anEvent method was called with the expected context'); + assert.ok( + obj.actionContext === ctx, + 'anEvent method was called with the expected context' + ); } }) }); - }, /Usage of `targetObject` is deprecated. Please use `target` instead./); - assert.ok(true === obj.triggerAction(), 'a valid targetObject and action were specified'); - expectDeprecation(() => obj.get('targetObject'), - /Usage of `targetObject` is deprecated. Please use `target` instead./); -}); + assert.ok( + true === obj.triggerAction(), + 'a valid target and action were specified' + ); + } +); + +QUnit.test( + 'it should raise a deprecation warning when targetObject is specified and used', + function(assert) { + assert.expect(4); + let obj; + expectDeprecation(() => { + obj = EmberObject.extend(TargetActionSupport).create({ + action: 'anEvent', + actionContext: {}, + targetObject: EmberObject.create({ + anEvent(ctx) { + assert.ok( + obj.actionContext === ctx, + 'anEvent method was called with the expected context' + ); + } + }) + }); + }, /Usage of `targetObject` is deprecated. Please use `target` instead./); + assert.ok( + true === obj.triggerAction(), + 'a valid targetObject and action were specified' + ); + expectDeprecation( + () => obj.get('targetObject'), + /Usage of `targetObject` is deprecated. Please use `target` instead./ + ); + } +); -QUnit.test('it should find an actionContext specified as a property path', function(assert) { - assert.expect(2); +QUnit.test( + 'it should find an actionContext specified as a property path', + function(assert) { + assert.expect(2); - let Test = {}; - lookup.Test = Test; - Test.aContext = {}; + let Test = {}; + lookup.Test = Test; + Test.aContext = {}; - let obj = EmberObject.extend(TargetActionSupport).create({ - action: 'anEvent', - actionContext: 'Test.aContext', - target: EmberObject.create({ - anEvent(ctx) { - assert.ok(Test.aContext === ctx, 'anEvent method was called with the expected context'); - } - }) - }); + let obj = EmberObject.extend(TargetActionSupport).create({ + action: 'anEvent', + actionContext: 'Test.aContext', + target: EmberObject.create({ + anEvent(ctx) { + assert.ok( + Test.aContext === ctx, + 'anEvent method was called with the expected context' + ); + } + }) + }); - assert.ok(true === obj.triggerAction(), 'a valid target and action were specified'); -}); + assert.ok( + true === obj.triggerAction(), + 'a valid target and action were specified' + ); + } +); -QUnit.test('it should use the target specified in the argument', function(assert) { +QUnit.test('it should use the target specified in the argument', function( + assert +) { assert.expect(2); let targetObj = EmberObject.create({ anEvent() { @@ -140,10 +198,15 @@ QUnit.test('it should use the target specified in the argument', function(assert action: 'anEvent' }); - assert.ok(true === obj.triggerAction({ target: targetObj }), 'a valid target and action were specified'); + assert.ok( + true === obj.triggerAction({ target: targetObj }), + 'a valid target and action were specified' + ); }); -QUnit.test('it should use the action specified in the argument', function(assert) { +QUnit.test('it should use the action specified in the argument', function( + assert +) { assert.expect(2); let obj = EmberObject.extend(TargetActionSupport).create({ @@ -153,50 +216,82 @@ QUnit.test('it should use the action specified in the argument', function(assert } }) }); - assert.ok(true === obj.triggerAction({ action: 'anEvent' }), 'a valid target and action were specified'); + assert.ok( + true === obj.triggerAction({ action: 'anEvent' }), + 'a valid target and action were specified' + ); }); -QUnit.test('it should use the actionContext specified in the argument', function(assert) { - assert.expect(2); - let context = {}; - let obj = EmberObject.extend(TargetActionSupport).create({ - target: EmberObject.create({ - anEvent(ctx) { - assert.ok(context === ctx, 'anEvent method was called with the expected context'); - } - }), - action: 'anEvent' - }); +QUnit.test( + 'it should use the actionContext specified in the argument', + function(assert) { + assert.expect(2); + let context = {}; + let obj = EmberObject.extend(TargetActionSupport).create({ + target: EmberObject.create({ + anEvent(ctx) { + assert.ok( + context === ctx, + 'anEvent method was called with the expected context' + ); + } + }), + action: 'anEvent' + }); - assert.ok(true === obj.triggerAction({ actionContext: context }), 'a valid target and action were specified'); -}); + assert.ok( + true === obj.triggerAction({ actionContext: context }), + 'a valid target and action were specified' + ); + } +); -QUnit.test('it should allow multiple arguments from actionContext', function(assert) { +QUnit.test('it should allow multiple arguments from actionContext', function( + assert +) { assert.expect(3); let param1 = 'someParam'; let param2 = 'someOtherParam'; let obj = EmberObject.extend(TargetActionSupport).create({ target: EmberObject.create({ anEvent(first, second) { - assert.ok(first === param1, 'anEvent method was called with the expected first argument'); - assert.ok(second === param2, 'anEvent method was called with the expected second argument'); + assert.ok( + first === param1, + 'anEvent method was called with the expected first argument' + ); + assert.ok( + second === param2, + 'anEvent method was called with the expected second argument' + ); } }), action: 'anEvent' }); - assert.ok(true === obj.triggerAction({ actionContext: [param1, param2] }), 'a valid target and action were specified'); + assert.ok( + true === obj.triggerAction({ actionContext: [param1, param2] }), + 'a valid target and action were specified' + ); }); -QUnit.test('it should use a null value specified in the actionContext argument', function(assert) { - assert.expect(2); - let obj = EmberObject.extend(TargetActionSupport).create({ - target: EmberObject.create({ - anEvent(ctx) { - assert.ok(null === ctx, 'anEvent method was called with the expected context (null)'); - } - }), - action: 'anEvent' - }); - assert.ok(true === obj.triggerAction({ actionContext: null }), 'a valid target and action were specified'); -}); +QUnit.test( + 'it should use a null value specified in the actionContext argument', + function(assert) { + assert.expect(2); + let obj = EmberObject.extend(TargetActionSupport).create({ + target: EmberObject.create({ + anEvent(ctx) { + assert.ok( + null === ctx, + 'anEvent method was called with the expected context (null)' + ); + } + }), + action: 'anEvent' + }); + assert.ok( + true === obj.triggerAction({ actionContext: null }), + 'a valid target and action were specified' + ); + } +); diff --git a/packages/ember-runtime/tests/mutable-array/addObject-test.js b/packages/ember-runtime/tests/mutable-array/addObject-test.js index 0f82fd78e7f..e402e3f3d7e 100644 --- a/packages/ember-runtime/tests/mutable-array/addObject-test.js +++ b/packages/ember-runtime/tests/mutable-array/addObject-test.js @@ -5,16 +5,23 @@ import { runArrayTests, newFixture } from '../helpers/array'; class AddObjectTest extends AbstractTestCase { '@test should return receiver'() { let before = newFixture(3); - let obj = this.newObject(before); + let obj = this.newObject(before); this.assert.equal(obj.addObject(before[1]), obj, 'should return receiver'); } '@test [A,B].addObject(C) => [A,B,C] + notify'() { let before = newFixture(2); - let item = newFixture(1)[0]; - let after = [before[0], before[1], item]; + let item = newFixture(1)[0]; + let after = [before[0], before[1], item]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -24,21 +31,48 @@ class AddObjectTest extends AbstractTestCase { this.assert.equal(get(obj, 'length'), after.length, 'length'); if (observer.isEnabled) { - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - this.assert.equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('lastObject'), + 1, + 'should have notified lastObject once' + ); - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject once'); + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject once' + ); } } '@test [A,B,C].addObject(A) => [A,B,C] + NO notify'() { let before = newFixture(3); - let after = before; - let item = before[0]; + let after = before; + let item = before[0]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -48,13 +82,39 @@ class AddObjectTest extends AbstractTestCase { this.assert.equal(get(obj, 'length'), after.length, 'length'); if (observer.isEnabled) { - this.assert.equal(observer.validate('[]'), false, 'should NOT have notified []'); - this.assert.equal(observer.validate('@each'), false, 'should NOT have notified @each'); - this.assert.equal(observer.validate('length'), false, 'should NOT have notified length'); - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject once'); - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject once'); + this.assert.equal( + observer.validate('[]'), + false, + 'should NOT have notified []' + ); + this.assert.equal( + observer.validate('@each'), + false, + 'should NOT have notified @each' + ); + this.assert.equal( + observer.validate('length'), + false, + 'should NOT have notified length' + ); + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject once' + ); + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject once' + ); } } } -runArrayTests('addObject', AddObjectTest, 'MutableArray', 'NativeArray', 'ArrayProxy'); +runArrayTests( + 'addObject', + AddObjectTest, + 'MutableArray', + 'NativeArray', + 'ArrayProxy' +); diff --git a/packages/ember-runtime/tests/mutable-array/clear-test.js b/packages/ember-runtime/tests/mutable-array/clear-test.js index d67767372f5..c6314dcfb21 100644 --- a/packages/ember-runtime/tests/mutable-array/clear-test.js +++ b/packages/ember-runtime/tests/mutable-array/clear-test.js @@ -5,9 +5,16 @@ import { runArrayTests, newFixture } from '../helpers/array'; class ClearTests extends AbstractTestCase { '@test [].clear() => [] + notify'() { let before = []; - let after = []; + let after = []; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -16,20 +23,47 @@ class ClearTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.validate('[]'), false, 'should NOT have notified [] once'); - this.assert.equal(observer.validate('@each'), false, 'should NOT have notified @each once'); - this.assert.equal(observer.validate('length'), false, 'should NOT have notified length once'); - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject once'); - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject once'); + this.assert.equal( + observer.validate('[]'), + false, + 'should NOT have notified [] once' + ); + this.assert.equal( + observer.validate('@each'), + false, + 'should NOT have notified @each once' + ); + this.assert.equal( + observer.validate('length'), + false, + 'should NOT have notified length once' + ); + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject once' + ); + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject once' + ); } '@test [X].clear() => [] + notify'() { var obj, before, after, observer; before = newFixture(1); - after = []; + after = []; obj = this.newObject(before); - observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ this.assert.equal(obj.clear(), obj, 'return self'); @@ -37,11 +71,31 @@ class ClearTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - this.assert.equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); - this.assert.equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('firstObject'), + 1, + 'should have notified firstObject once' + ); + this.assert.equal( + observer.timesCalled('lastObject'), + 1, + 'should have notified lastObject once' + ); } } diff --git a/packages/ember-runtime/tests/mutable-array/insertAt-test.js b/packages/ember-runtime/tests/mutable-array/insertAt-test.js index 13e3393ac5a..56afa48445b 100644 --- a/packages/ember-runtime/tests/mutable-array/insertAt-test.js +++ b/packages/ember-runtime/tests/mutable-array/insertAt-test.js @@ -6,7 +6,14 @@ class InsertAtTests extends AbstractTestCase { '@test [].insertAt(0, X) => [X] + notify'() { let after = newFixture(1); let obj = this.newObject([]); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -15,11 +22,31 @@ class InsertAtTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] did change once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each did change once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length did change once'); - this.assert.equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject did change once'); - this.assert.equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject did change once'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] did change once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each did change once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length did change once' + ); + this.assert.equal( + observer.timesCalled('firstObject'), + 1, + 'should have notified firstObject did change once' + ); + this.assert.equal( + observer.timesCalled('lastObject'), + 1, + 'should have notified lastObject did change once' + ); } '@test [].insertAt(200,X) => OUT_OF_RANGE_EXCEPTION exception'() { @@ -34,7 +61,14 @@ class InsertAtTests extends AbstractTestCase { let before = newFixture(1); let after = [item, before[0]]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -43,12 +77,32 @@ class InsertAtTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - this.assert.equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); - - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('firstObject'), + 1, + 'should have notified firstObject once' + ); + + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject' + ); } '@test [A].insertAt(1, X) => [A,X] + notify'() { @@ -56,7 +110,14 @@ class InsertAtTests extends AbstractTestCase { let before = newFixture(1); let after = [before[0], item]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -65,12 +126,32 @@ class InsertAtTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - this.assert.equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); - - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('lastObject'), + 1, + 'should have notified lastObject once' + ); + + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject' + ); } '@test [A].insertAt(200,X) => OUT_OF_RANGE exception'() { @@ -83,9 +164,16 @@ class InsertAtTests extends AbstractTestCase { '@test [A,B,C].insertAt(0,X) => [X,A,B,C] + notify'() { let item = newFixture(1)[0]; let before = newFixture(3); - let after = [item, before[0], before[1], before[2]]; + let after = [item, before[0], before[1], before[2]]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -94,24 +182,51 @@ class InsertAtTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - this.assert.equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); - - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('firstObject'), + 1, + 'should have notified firstObject once' + ); + + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject' + ); } '@test [A,B,C].insertAt(1,X) => [A,X,B,C] + notify'() { let item = newFixture(1)[0]; let before = newFixture(3); - let after = [before[0], item, before[1], before[2]]; + let after = [before[0], item, before[1], before[2]]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); let objectAtCalls = []; let objectAt = obj.objectAt; - obj.objectAt = (ix) => { + obj.objectAt = ix => { objectAtCalls.push(ix); return objectAt.call(obj, ix); }; @@ -121,25 +236,56 @@ class InsertAtTests extends AbstractTestCase { objectAtCalls.splice(0, objectAtCalls.length); obj.insertAt(1, item); - this.assert.deepEqual(objectAtCalls, [], 'objectAt is not called when only inserting items'); + this.assert.deepEqual( + objectAtCalls, + [], + 'objectAt is not called when only inserting items' + ); this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject'); - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject' + ); + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject' + ); } '@test [A,B,C].insertAt(3,X) => [A,B,C,X] + notify'() { let item = newFixture(1)[0]; let before = newFixture(3); - let after = [before[0], before[1], before[2], item]; + let after = [before[0], before[1], before[2], item]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -148,13 +294,39 @@ class InsertAtTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - this.assert.equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); - - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('lastObject'), + 1, + 'should have notified lastObject once' + ); + + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject' + ); } } -runArrayTests('instertAt', InsertAtTests, 'MutableArray', 'NativeArray', 'ArrayProxy'); \ No newline at end of file +runArrayTests( + 'instertAt', + InsertAtTests, + 'MutableArray', + 'NativeArray', + 'ArrayProxy' +); diff --git a/packages/ember-runtime/tests/mutable-array/popObject-test.js b/packages/ember-runtime/tests/mutable-array/popObject-test.js index 30e3ec5139d..a17931a4e1e 100644 --- a/packages/ember-runtime/tests/mutable-array/popObject-test.js +++ b/packages/ember-runtime/tests/mutable-array/popObject-test.js @@ -5,7 +5,14 @@ import { runArrayTests, newFixture } from '../helpers/array'; class PopObjectTests extends AbstractTestCase { '@test [].popObject() => [] + returns undefined + NO notify'() { let obj = this.newObject([]); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -13,18 +20,45 @@ class PopObjectTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), [], 'post item results'); - this.assert.equal(observer.validate('[]'), false, 'should NOT have notified []'); - this.assert.equal(observer.validate('@each'), false, 'should NOT have notified @each'); - this.assert.equal(observer.validate('length'), false, 'should NOT have notified length'); - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject'); - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject'); + this.assert.equal( + observer.validate('[]'), + false, + 'should NOT have notified []' + ); + this.assert.equal( + observer.validate('@each'), + false, + 'should NOT have notified @each' + ); + this.assert.equal( + observer.validate('length'), + false, + 'should NOT have notified length' + ); + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject' + ); + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject' + ); } '@test [X].popObject() => [] + notify'() { let before = newFixture(1); - let after = []; + let after = []; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -34,18 +68,45 @@ class PopObjectTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - this.assert.equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); - this.assert.equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('firstObject'), + 1, + 'should have notified firstObject once' + ); + this.assert.equal( + observer.timesCalled('lastObject'), + 1, + 'should have notified lastObject once' + ); } '@test [A,B,C].popObject() => [A,B] + notify'() { let before = newFixture(3); - let after = [before[0], before[1]]; + let after = [before[0], before[1]]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -55,14 +116,39 @@ class PopObjectTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - this.assert.equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); - - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('lastObject'), + 1, + 'should have notified lastObject once' + ); + + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject' + ); } - } -runArrayTests('popObject', PopObjectTests, 'MutableArray', 'NativeArray', 'ArrayProxy'); \ No newline at end of file +runArrayTests( + 'popObject', + PopObjectTests, + 'MutableArray', + 'NativeArray', + 'ArrayProxy' +); diff --git a/packages/ember-runtime/tests/mutable-array/pushObject-test.js b/packages/ember-runtime/tests/mutable-array/pushObject-test.js index 01d129fb1d8..c0b7de28530 100644 --- a/packages/ember-runtime/tests/mutable-array/pushObject-test.js +++ b/packages/ember-runtime/tests/mutable-array/pushObject-test.js @@ -12,9 +12,16 @@ class PushObjectTests extends AbstractTestCase { '@test [].pushObject(X) => [X] + notify'() { let before = []; - let after = newFixture(1); + let after = newFixture(1); let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -23,11 +30,31 @@ class PushObjectTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - this.assert.equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); - this.assert.equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('firstObject'), + 1, + 'should have notified firstObject once' + ); + this.assert.equal( + observer.timesCalled('lastObject'), + 1, + 'should have notified lastObject once' + ); } '@test [A,B,C].pushObject(X) => [A,B,C,X] + notify'() { @@ -35,7 +62,14 @@ class PushObjectTests extends AbstractTestCase { let item = newFixture(1)[0]; let after = [before[0], before[1], before[2], item]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -44,12 +78,32 @@ class PushObjectTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - this.assert.equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); - - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('lastObject'), + 1, + 'should have notified lastObject once' + ); + + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject' + ); } '@test [A,B,C,C].pushObject(A) => [A,B,C,C] + notify'() { @@ -57,7 +111,14 @@ class PushObjectTests extends AbstractTestCase { let item = before[2]; // note same object as current tail. should end up twice let after = [before[0], before[1], before[2], item]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -66,13 +127,39 @@ class PushObjectTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject'); - this.assert.equal(observer.validate('lastObject'), true, 'should have notified lastObject'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject' + ); + this.assert.equal( + observer.validate('lastObject'), + true, + 'should have notified lastObject' + ); } } -runArrayTests('pushObject', PushObjectTests, 'MutableArray', 'NativeArray', 'ArrayProxy'); \ No newline at end of file +runArrayTests( + 'pushObject', + PushObjectTests, + 'MutableArray', + 'NativeArray', + 'ArrayProxy' +); diff --git a/packages/ember-runtime/tests/mutable-array/pushObjects-test.js b/packages/ember-runtime/tests/mutable-array/pushObjects-test.js index a89d3f97571..c9d41757292 100644 --- a/packages/ember-runtime/tests/mutable-array/pushObjects-test.js +++ b/packages/ember-runtime/tests/mutable-array/pushObjects-test.js @@ -9,4 +9,10 @@ class PushObjectsTests extends AbstractTestCase { } } -runArrayTests('pushObjects', PushObjectsTests, 'MutableArray', 'NativeArray', 'ArrayProxy'); +runArrayTests( + 'pushObjects', + PushObjectsTests, + 'MutableArray', + 'NativeArray', + 'ArrayProxy' +); diff --git a/packages/ember-runtime/tests/mutable-array/removeAt-test.js b/packages/ember-runtime/tests/mutable-array/removeAt-test.js index 574125688aa..552687c1119 100644 --- a/packages/ember-runtime/tests/mutable-array/removeAt-test.js +++ b/packages/ember-runtime/tests/mutable-array/removeAt-test.js @@ -6,9 +6,16 @@ import { get } from 'ember-metal'; class RemoveAtTests extends AbstractTestCase { '@test removeAt([X], 0) => [] + notify'() { let before = newFixture(1); - let after = []; + let after = []; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -17,11 +24,31 @@ class RemoveAtTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - this.assert.equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); - this.assert.equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('firstObject'), + 1, + 'should have notified firstObject once' + ); + this.assert.equal( + observer.timesCalled('lastObject'), + 1, + 'should have notified lastObject once' + ); } '@test removeAt([], 200) => OUT_OF_RANGE_EXCEPTION exception'() { @@ -31,9 +58,16 @@ class RemoveAtTests extends AbstractTestCase { '@test removeAt([A,B], 0) => [B] + notify'() { let before = newFixture(2); - let after = [before[1]]; + let after = [before[1]]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -42,19 +76,46 @@ class RemoveAtTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - this.assert.equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); - - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('firstObject'), + 1, + 'should have notified firstObject once' + ); + + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject' + ); } '@test removeAt([A,B], 1) => [A] + notify'() { let before = newFixture(2); - let after = [before[0]]; + let after = [before[0]]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -63,19 +124,46 @@ class RemoveAtTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - this.assert.equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); - - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject once'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('lastObject'), + 1, + 'should have notified lastObject once' + ); + + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject once' + ); } '@test removeAt([A,B,C], 1) => [A,C] + notify'() { let before = newFixture(3); - let after = [before[0], before[2]]; + let after = [before[0], before[2]]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -84,19 +172,46 @@ class RemoveAtTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject once'); - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject once'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject once' + ); + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject once' + ); } '@test removeAt([A,B,C,D], 1,2) => [A,D] + notify'() { let before = newFixture(4); - let after = [before[0], before[3]]; + let after = [before[0], before[3]]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -105,21 +220,48 @@ class RemoveAtTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject once'); - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject once'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject once' + ); + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject once' + ); } '@test [A,B,C,D].removeAt(1,2) => [A,D] + notify'() { var obj, before, after, observer; before = newFixture(4); - after = [before[0], before[3]]; + after = [before[0], before[3]]; obj = this.newObject(before); - observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ this.assert.equal(obj.removeAt(1, 2), obj, 'return self'); @@ -127,14 +269,39 @@ class RemoveAtTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject once'); - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject once'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject once' + ); + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject once' + ); } - } -runArrayTests('removeAt', RemoveAtTests, 'MutableArray', 'NativeArray', 'ArrayProxy'); +runArrayTests( + 'removeAt', + RemoveAtTests, + 'MutableArray', + 'NativeArray', + 'ArrayProxy' +); diff --git a/packages/ember-runtime/tests/mutable-array/removeObject-test.js b/packages/ember-runtime/tests/mutable-array/removeObject-test.js index 2c37c0a403d..f65c33fe3f2 100644 --- a/packages/ember-runtime/tests/mutable-array/removeObject-test.js +++ b/packages/ember-runtime/tests/mutable-array/removeObject-test.js @@ -5,16 +5,27 @@ import { runArrayTests, newFixture } from '../helpers/array'; class RemoveObjectTests extends AbstractTestCase { '@test should return receiver'() { let before = newFixture(3); - let obj = this.newObject(before); + let obj = this.newObject(before); - this.assert.equal(obj.removeObject(before[1]), obj, 'should return receiver'); + this.assert.equal( + obj.removeObject(before[1]), + obj, + 'should return receiver' + ); } '@test [A,B,C].removeObject(B) => [A,C] + notify'() { let before = newFixture(3); - let after = [before[0], before[2]]; + let after = [before[0], before[2]]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -24,21 +35,48 @@ class RemoveObjectTests extends AbstractTestCase { this.assert.equal(get(obj, 'length'), after.length, 'length'); if (observer.isEnabled) { - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject once'); - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject once'); + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject once' + ); + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject once' + ); } } '@test [A,B,C].removeObject(D) => [A,B,C]'() { let before = newFixture(3); - let after = before; - let item = newFixture(1)[0]; + let after = before; + let item = newFixture(1)[0]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -48,14 +86,40 @@ class RemoveObjectTests extends AbstractTestCase { this.assert.equal(get(obj, 'length'), after.length, 'length'); if (observer.isEnabled) { - this.assert.equal(observer.validate('[]'), false, 'should NOT have notified []'); - this.assert.equal(observer.validate('@each'), false, 'should NOT have notified @each'); - this.assert.equal(observer.validate('length'), false, 'should NOT have notified length'); + this.assert.equal( + observer.validate('[]'), + false, + 'should NOT have notified []' + ); + this.assert.equal( + observer.validate('@each'), + false, + 'should NOT have notified @each' + ); + this.assert.equal( + observer.validate('length'), + false, + 'should NOT have notified length' + ); - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject once'); - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject once'); + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject once' + ); + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject once' + ); } } } -runArrayTests('removeObject', RemoveObjectTests, 'MutableArray', 'NativeArray', 'ArrayProxy'); +runArrayTests( + 'removeObject', + RemoveObjectTests, + 'MutableArray', + 'NativeArray', + 'ArrayProxy' +); diff --git a/packages/ember-runtime/tests/mutable-array/removeObjects-test.js b/packages/ember-runtime/tests/mutable-array/removeObjects-test.js index 1b883efa72a..ee682ecc205 100644 --- a/packages/ember-runtime/tests/mutable-array/removeObjects-test.js +++ b/packages/ember-runtime/tests/mutable-array/removeObjects-test.js @@ -8,14 +8,24 @@ class RemoveObjectsTests extends AbstractTestCase { let before = emberA(newFixture(3)); let obj = before; - this.assert.equal(obj.removeObjects(before[1]), obj, 'should return receiver'); + this.assert.equal( + obj.removeObjects(before[1]), + obj, + 'should return receiver' + ); } '@test [A,B,C].removeObjects([B]) => [A,C] + notify'() { let before = emberA(newFixture(3)); let after = [before[0], before[2]]; let obj = before; - let observer = this.newObserver(obj, '[]', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); // Prime the cache @@ -25,11 +35,27 @@ class RemoveObjectsTests extends AbstractTestCase { this.assert.equal(get(obj, 'length'), after.length, 'length'); if (observer.isEnabled) { - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject'); - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject' + ); + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject' + ); } } @@ -37,7 +63,13 @@ class RemoveObjectsTests extends AbstractTestCase { let before = emberA(newObjectsFixture(3)); let after = [before[0], before[2]]; let obj = before; - let observer = this.newObserver(obj, '[]', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); // Prime the cache @@ -47,19 +79,41 @@ class RemoveObjectsTests extends AbstractTestCase { this.assert.equal(get(obj, 'length'), after.length, 'length'); if (observer.isEnabled) { - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject'); - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject' + ); + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject' + ); } } '@test [A,B,C].removeObjects([A,B]) => [C] + notify'() { let before = emberA(newFixture(3)); - let after = [before[2]]; + let after = [before[2]]; let obj = before; - let observer = this.newObserver(obj, '[]', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); // Prime the cache @@ -69,11 +123,27 @@ class RemoveObjectsTests extends AbstractTestCase { this.assert.equal(get(obj, 'length'), after.length, 'length'); if (observer.isEnabled) { - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - - this.assert.equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject'); - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + + this.assert.equal( + observer.timesCalled('firstObject'), + 1, + 'should have notified firstObject' + ); + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject' + ); } } @@ -81,7 +151,13 @@ class RemoveObjectsTests extends AbstractTestCase { let before = emberA(newObjectsFixture(3)); let after = [before[2]]; let obj = before; - let observer = this.newObserver(obj, '[]', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); // Prime the cache @@ -91,11 +167,27 @@ class RemoveObjectsTests extends AbstractTestCase { this.assert.equal(get(obj, 'length'), after.length, 'length'); if (observer.isEnabled) { - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - - this.assert.equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject'); - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + + this.assert.equal( + observer.timesCalled('firstObject'), + 1, + 'should have notified firstObject' + ); + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject' + ); } } @@ -103,7 +195,13 @@ class RemoveObjectsTests extends AbstractTestCase { let before = emberA(newFixture(3)); let after = []; let obj = before; - let observer = this.newObserver(obj, '[]', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); // Prime the cache @@ -113,11 +211,27 @@ class RemoveObjectsTests extends AbstractTestCase { this.assert.equal(get(obj, 'length'), after.length, 'length'); if (observer.isEnabled) { - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - - this.assert.equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject'); - this.assert.equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + + this.assert.equal( + observer.timesCalled('firstObject'), + 1, + 'should have notified firstObject' + ); + this.assert.equal( + observer.timesCalled('lastObject'), + 1, + 'should have notified lastObject' + ); } } @@ -125,7 +239,13 @@ class RemoveObjectsTests extends AbstractTestCase { let before = emberA(newObjectsFixture(3)); let after = []; let obj = before; - let observer = this.newObserver(obj, '[]', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); // Prime the cache @@ -135,11 +255,27 @@ class RemoveObjectsTests extends AbstractTestCase { this.assert.equal(get(obj, 'length'), after.length, 'length'); if (observer.isEnabled) { - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - - this.assert.equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject'); - this.assert.equal(observer.validate('lastObject'), 1, 'should have notified lastObject'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + + this.assert.equal( + observer.timesCalled('firstObject'), + 1, + 'should have notified firstObject' + ); + this.assert.equal( + observer.validate('lastObject'), + 1, + 'should have notified lastObject' + ); } } @@ -148,7 +284,13 @@ class RemoveObjectsTests extends AbstractTestCase { let after = before; let item = newFixture(1)[0]; let obj = before; - let observer = this.newObserver(obj, '[]', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); // Prime the cache @@ -158,13 +300,35 @@ class RemoveObjectsTests extends AbstractTestCase { this.assert.equal(get(obj, 'length'), after.length, 'length'); if (observer.isEnabled) { - this.assert.equal(observer.validate('[]'), false, 'should NOT have notified []'); - this.assert.equal(observer.validate('length'), false, 'should NOT have notified length'); - - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject'); - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject'); + this.assert.equal( + observer.validate('[]'), + false, + 'should NOT have notified []' + ); + this.assert.equal( + observer.validate('length'), + false, + 'should NOT have notified length' + ); + + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject' + ); + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject' + ); } } } -runArrayTests('removeObjects', RemoveObjectsTests, 'MutableArray', 'NativeArray', 'ArrayProxy'); +runArrayTests( + 'removeObjects', + RemoveObjectsTests, + 'MutableArray', + 'NativeArray', + 'ArrayProxy' +); diff --git a/packages/ember-runtime/tests/mutable-array/replace-test.js b/packages/ember-runtime/tests/mutable-array/replace-test.js index f23d3caad50..9da62f448d1 100644 --- a/packages/ember-runtime/tests/mutable-array/replace-test.js +++ b/packages/ember-runtime/tests/mutable-array/replace-test.js @@ -2,10 +2,17 @@ import { AbstractTestCase } from 'internal-test-helpers'; import { runArrayTests, newFixture } from '../helpers/array'; class ReplaceTests extends AbstractTestCase { - '@test [].replace(0,0,\'X\') => [\'X\'] + notify'() { + "@test [].replace(0,0,'X') => ['X'] + notify"() { let exp = newFixture(1); let obj = this.newObject([]); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -13,11 +20,31 @@ class ReplaceTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), exp, 'post item results'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - this.assert.equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); - this.assert.equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('firstObject'), + 1, + 'should have notified firstObject once' + ); + this.assert.equal( + observer.timesCalled('lastObject'), + 1, + 'should have notified lastObject once' + ); } '@test [].replace(0,0,"X") => ["X"] + avoid calling objectAt and notifying fistObject/lastObject when not in cache'() { @@ -32,18 +59,37 @@ class ReplaceTests extends AbstractTestCase { obj.replace(0, 0, exp); - this.assert.equal(called, 0, 'should NOT have called objectAt upon replace when firstObject/lastObject are not cached'); - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject since not cached'); - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject since not cached'); + this.assert.equal( + called, + 0, + 'should NOT have called objectAt upon replace when firstObject/lastObject are not cached' + ); + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject since not cached' + ); + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject since not cached' + ); } '@test [A,B,C,D].replace(1,2,X) => [A,X,D] + notify'() { - let before = newFixture(4); + let before = newFixture(4); let replace = newFixture(1); - let after = [before[0], replace[0], before[3]]; + let after = [before[0], replace[0], before[3]]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -51,21 +97,48 @@ class ReplaceTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject once'); - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject once'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject once' + ); + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject once' + ); } '@test [A,B,C,D].replace(1,2,[X,Y]) => [A,X,Y,D] + notify'() { - let before = newFixture(4); + let before = newFixture(4); let replace = newFixture(2); - let after = [before[0], replace[0], replace[1], before[3]]; + let after = [before[0], replace[0], replace[1], before[3]]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -73,21 +146,48 @@ class ReplaceTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.validate('length'), false, 'should NOT have notified length'); - - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject once'); - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject once'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.validate('length'), + false, + 'should NOT have notified length' + ); + + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject once' + ); + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject once' + ); } '@test [A,B].replace(1,0,[X,Y]) => [A,X,Y,B] + notify'() { - let before = newFixture(2); + let before = newFixture(2); let replace = newFixture(2); - let after = [before[0], replace[0], replace[1], before[1]]; + let after = [before[0], replace[0], replace[1], before[1]]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -95,20 +195,47 @@ class ReplaceTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject once'); - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject once'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject once' + ); + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject once' + ); } '@test [A,B,C,D].replace(2,2) => [A,B] + notify'() { - let before = newFixture(4); - let after = [before[0], before[1]]; + let before = newFixture(4); + let after = [before[0], before[1]]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -116,20 +243,47 @@ class ReplaceTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - this.assert.equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); - - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject once'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('lastObject'), + 1, + 'should have notified lastObject once' + ); + + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject once' + ); } '@test [A,B,C,D].replace(-1,1) => [A,B,C] + notify'() { - let before = newFixture(4); - let after = [before[0], before[1], before[2]]; + let before = newFixture(4); + let after = [before[0], before[1], before[2]]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -137,12 +291,32 @@ class ReplaceTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - this.assert.equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); - - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject once'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('lastObject'), + 1, + 'should have notified lastObject once' + ); + + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject once' + ); } '@test Adding object should notify array observer'() { @@ -158,4 +332,10 @@ class ReplaceTests extends AbstractTestCase { } } -runArrayTests('replace', ReplaceTests, 'MutableArray', 'NativeArray', 'ArrayProxy'); +runArrayTests( + 'replace', + ReplaceTests, + 'MutableArray', + 'NativeArray', + 'ArrayProxy' +); diff --git a/packages/ember-runtime/tests/mutable-array/reverseObjects-test.js b/packages/ember-runtime/tests/mutable-array/reverseObjects-test.js index 3d9a9e84a57..b6e878a2f8e 100644 --- a/packages/ember-runtime/tests/mutable-array/reverseObjects-test.js +++ b/packages/ember-runtime/tests/mutable-array/reverseObjects-test.js @@ -3,12 +3,18 @@ import { runArrayTests, newFixture } from '../helpers/array'; import { get } from 'ember-metal'; class ReverseObjectsTests extends AbstractTestCase { - '@test [A,B,C].reverseObjects() => [] + notify'() { let before = newFixture(3); - let after = [before[2], before[1], before[0]]; + let after = [before[2], before[1], before[0]]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -17,13 +23,38 @@ class ReverseObjectsTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 0, 'should have notified length once'); - this.assert.equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); - this.assert.equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 0, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('firstObject'), + 1, + 'should have notified firstObject once' + ); + this.assert.equal( + observer.timesCalled('lastObject'), + 1, + 'should have notified lastObject once' + ); } - } -runArrayTests('reverseObjects', ReverseObjectsTests, 'MutableArray', 'NativeArray', 'ArrayProxy'); +runArrayTests( + 'reverseObjects', + ReverseObjectsTests, + 'MutableArray', + 'NativeArray', + 'ArrayProxy' +); diff --git a/packages/ember-runtime/tests/mutable-array/setObjects-test.js b/packages/ember-runtime/tests/mutable-array/setObjects-test.js index 57dc1dd207d..7f6d2adcaa1 100644 --- a/packages/ember-runtime/tests/mutable-array/setObjects-test.js +++ b/packages/ember-runtime/tests/mutable-array/setObjects-test.js @@ -5,9 +5,16 @@ import { get } from 'ember-metal'; class SetObjectsTests extends AbstractTestCase { '@test [A,B,C].setObjects([]) = > [] + notify'() { let before = newFixture(3); - let after = []; + let after = []; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -16,18 +23,45 @@ class SetObjectsTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - this.assert.equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); - this.assert.equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('firstObject'), + 1, + 'should have notified firstObject once' + ); + this.assert.equal( + observer.timesCalled('lastObject'), + 1, + 'should have notified lastObject once' + ); } '@test [A,B,C].setObjects([D, E, F, G]) = > [D, E, F, G] + notify'() { let before = newFixture(3); - let after = newFixture(4); + let after = newFixture(4); let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -36,13 +70,38 @@ class SetObjectsTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - this.assert.equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); - this.assert.equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('firstObject'), + 1, + 'should have notified firstObject once' + ); + this.assert.equal( + observer.timesCalled('lastObject'), + 1, + 'should have notified lastObject once' + ); } - } -runArrayTests('setObjects', SetObjectsTests, 'MutableArray', 'NativeArray', 'ArrayProxy'); +runArrayTests( + 'setObjects', + SetObjectsTests, + 'MutableArray', + 'NativeArray', + 'ArrayProxy' +); diff --git a/packages/ember-runtime/tests/mutable-array/shiftObject-test.js b/packages/ember-runtime/tests/mutable-array/shiftObject-test.js index 1b3b52be36a..ccd4d9268c8 100644 --- a/packages/ember-runtime/tests/mutable-array/shiftObject-test.js +++ b/packages/ember-runtime/tests/mutable-array/shiftObject-test.js @@ -5,9 +5,16 @@ import { get } from 'ember-metal'; class ShiftObjectTests extends AbstractTestCase { '@test [].shiftObject() => [] + returns undefined + NO notify'() { let before = []; - let after = []; + let after = []; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -16,19 +23,46 @@ class ShiftObjectTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.validate('[]', undefined, 1), false, 'should NOT have notified [] once'); - this.assert.equal(observer.validate('@each', undefined, 1), false, 'should NOT have notified @each once'); - this.assert.equal(observer.validate('length', undefined, 1), false, 'should NOT have notified length once'); - - this.assert.equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject once'); - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject once'); + this.assert.equal( + observer.validate('[]', undefined, 1), + false, + 'should NOT have notified [] once' + ); + this.assert.equal( + observer.validate('@each', undefined, 1), + false, + 'should NOT have notified @each once' + ); + this.assert.equal( + observer.validate('length', undefined, 1), + false, + 'should NOT have notified length once' + ); + + this.assert.equal( + observer.validate('firstObject'), + false, + 'should NOT have notified firstObject once' + ); + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject once' + ); } '@test [X].shiftObject() => [] + notify'() { let before = newFixture(1); - let after = []; + let after = []; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -37,18 +71,45 @@ class ShiftObjectTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - this.assert.equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); - this.assert.equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('firstObject'), + 1, + 'should have notified firstObject once' + ); + this.assert.equal( + observer.timesCalled('lastObject'), + 1, + 'should have notified lastObject once' + ); } '@test [A,B,C].shiftObject() => [B,C] + notify'() { let before = newFixture(3); - let after = [before[1], before[2]]; + let after = [before[1], before[2]]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -57,14 +118,39 @@ class ShiftObjectTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - this.assert.equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); - - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject once'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('firstObject'), + 1, + 'should have notified firstObject once' + ); + + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject once' + ); } - } -runArrayTests('shiftObject', ShiftObjectTests, 'MutableArray', 'NativeArray', 'ArrayProxy'); +runArrayTests( + 'shiftObject', + ShiftObjectTests, + 'MutableArray', + 'NativeArray', + 'ArrayProxy' +); diff --git a/packages/ember-runtime/tests/mutable-array/unshiftObject-test.js b/packages/ember-runtime/tests/mutable-array/unshiftObject-test.js index 105587eb3ef..d811daa9118 100644 --- a/packages/ember-runtime/tests/mutable-array/unshiftObject-test.js +++ b/packages/ember-runtime/tests/mutable-array/unshiftObject-test.js @@ -7,15 +7,26 @@ class UnshiftObjectTests extends AbstractTestCase { let obj = this.newObject([]); let item = newFixture(1)[0]; - this.assert.equal(obj.unshiftObject(item), item, 'should return unshifted object'); + this.assert.equal( + obj.unshiftObject(item), + item, + 'should return unshifted object' + ); } '@test [].unshiftObject(X) => [X] + notify'() { let before = []; let item = newFixture(1)[0]; - let after = [item]; + let after = [item]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -24,19 +35,46 @@ class UnshiftObjectTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - this.assert.equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); - this.assert.equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('firstObject'), + 1, + 'should have notified firstObject once' + ); + this.assert.equal( + observer.timesCalled('lastObject'), + 1, + 'should have notified lastObject once' + ); } '@test [A,B,C].unshiftObject(X) => [X,A,B,C] + notify'() { let before = newFixture(3); let item = newFixture(1)[0]; - let after = [item, before[0], before[1], before[2]]; + let after = [item, before[0], before[1], before[2]]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -45,12 +83,32 @@ class UnshiftObjectTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - this.assert.equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); - - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('firstObject'), + 1, + 'should have notified firstObject once' + ); + + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject' + ); } '@test [A,B,C].unshiftObject(A) => [A,A,B,C] + notify'() { @@ -58,7 +116,14 @@ class UnshiftObjectTests extends AbstractTestCase { let item = before[0]; // note same object as current head. should end up twice let after = [item, before[0], before[1], before[2]]; let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -67,13 +132,39 @@ class UnshiftObjectTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - - this.assert.equal(observer.validate('firstObject'), true, 'should have notified firstObject'); - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + + this.assert.equal( + observer.validate('firstObject'), + true, + 'should have notified firstObject' + ); + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject' + ); } } -runArrayTests('unshiftObject', UnshiftObjectTests, 'MutableArray', 'NativeArray', 'ArrayProxy'); +runArrayTests( + 'unshiftObject', + UnshiftObjectTests, + 'MutableArray', + 'NativeArray', + 'ArrayProxy' +); diff --git a/packages/ember-runtime/tests/mutable-array/unshiftObjects-test.js b/packages/ember-runtime/tests/mutable-array/unshiftObjects-test.js index e0e6e0cb84d..1ddbaa540a8 100644 --- a/packages/ember-runtime/tests/mutable-array/unshiftObjects-test.js +++ b/packages/ember-runtime/tests/mutable-array/unshiftObjects-test.js @@ -14,7 +14,14 @@ class UnshiftObjectsTests extends AbstractTestCase { let before = []; let items = newFixture(3); let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -23,19 +30,46 @@ class UnshiftObjectsTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), items, 'post item results'); this.assert.equal(get(obj, 'length'), items.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - this.assert.equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); - this.assert.equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('firstObject'), + 1, + 'should have notified firstObject once' + ); + this.assert.equal( + observer.timesCalled('lastObject'), + 1, + 'should have notified lastObject once' + ); } '@test [A,B,C].unshiftObjects([X,Y]) => [X,Y,A,B,C] + notify'() { let before = newFixture(3); - let items = newFixture(2); - let after = items.concat(before); + let items = newFixture(2); + let after = items.concat(before); let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -44,20 +78,47 @@ class UnshiftObjectsTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - this.assert.equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); - - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + this.assert.equal( + observer.timesCalled('firstObject'), + 1, + 'should have notified firstObject once' + ); + + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject' + ); } '@test [A,B,C].unshiftObjects([A,B]) => [A,B,A,B,C] + notify'() { let before = newFixture(3); let items = [before[0], before[1]]; // note same object as current head. should end up twice - let after = items.concat(before); + let after = items.concat(before); let obj = this.newObject(before); - let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let observer = this.newObserver( + obj, + '[]', + '@each', + 'length', + 'firstObject', + 'lastObject' + ); obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ @@ -66,13 +127,39 @@ class UnshiftObjectsTests extends AbstractTestCase { this.assert.deepEqual(this.toArray(obj), after, 'post item results'); this.assert.equal(get(obj, 'length'), after.length, 'length'); - this.assert.equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - this.assert.equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); - this.assert.equal(observer.timesCalled('length'), 1, 'should have notified length once'); - - this.assert.equal(observer.validate('firstObject'), true, 'should NOT have notified firstObject'); - this.assert.equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject'); + this.assert.equal( + observer.timesCalled('[]'), + 1, + 'should have notified [] once' + ); + this.assert.equal( + observer.timesCalled('@each'), + 0, + 'should not have notified @each once' + ); + this.assert.equal( + observer.timesCalled('length'), + 1, + 'should have notified length once' + ); + + this.assert.equal( + observer.validate('firstObject'), + true, + 'should NOT have notified firstObject' + ); + this.assert.equal( + observer.validate('lastObject'), + false, + 'should NOT have notified lastObject' + ); } } -runArrayTests('unshiftObjects', UnshiftObjectsTests, 'MutableArray', 'NativeArray', 'ArrayProxy'); +runArrayTests( + 'unshiftObjects', + UnshiftObjectsTests, + 'MutableArray', + 'NativeArray', + 'ArrayProxy' +); diff --git a/packages/ember-runtime/tests/system/application/base_test.js b/packages/ember-runtime/tests/system/application/base_test.js index ca907983353..2134409a36e 100644 --- a/packages/ember-runtime/tests/system/application/base_test.js +++ b/packages/ember-runtime/tests/system/application/base_test.js @@ -3,6 +3,12 @@ import Application from '../../../system/application'; QUnit.module('Ember.Application'); -QUnit.test('Ember.Application should be a subclass of Ember.Namespace', function(assert) { - assert.ok(Namespace.detect(Application), 'Ember.Application subclass of Ember.Namespace'); -}); +QUnit.test( + 'Ember.Application should be a subclass of Ember.Namespace', + function(assert) { + assert.ok( + Namespace.detect(Application), + 'Ember.Application subclass of Ember.Namespace' + ); + } +); diff --git a/packages/ember-runtime/tests/system/array_proxy/arranged_content_test.js b/packages/ember-runtime/tests/system/array_proxy/arranged_content_test.js index 12d631797ca..09c8c2837f6 100644 --- a/packages/ember-runtime/tests/system/array_proxy/arranged_content_test.js +++ b/packages/ember-runtime/tests/system/array_proxy/arranged_content_test.js @@ -10,11 +10,20 @@ QUnit.module('ArrayProxy - arrangedContent', { array = ArrayProxy.extend({ arrangedContent: computed('content.[]', function() { let content = this.get('content'); - return content && emberA(content.slice().sort((a, b) => { - if (a == null) { a = -1; } - if (b == null) { b = -1; } - return b - a; - })); + return ( + content && + emberA( + content.slice().sort((a, b) => { + if (a == null) { + a = -1; + } + if (b == null) { + b = -1; + } + return b - a; + }) + ) + ); }) }).create({ content: emberA([1, 2, 4, 5]) @@ -26,44 +35,70 @@ QUnit.module('ArrayProxy - arrangedContent', { } }); -QUnit.test('compact - returns arrangedContent without nulls and undefined', function(assert) { - run(() => array.set('content', emberA([1, 3, null, 2, undefined]))); +QUnit.test( + 'compact - returns arrangedContent without nulls and undefined', + function(assert) { + run(() => array.set('content', emberA([1, 3, null, 2, undefined]))); - assert.deepEqual(array.compact(), [3, 2, 1]); -}); + assert.deepEqual(array.compact(), [3, 2, 1]); + } +); -QUnit.test('indexOf - returns index of object in arrangedContent', function(assert) { +QUnit.test('indexOf - returns index of object in arrangedContent', function( + assert +) { assert.equal(array.indexOf(4), 1, 'returns arranged index'); }); -QUnit.test('lastIndexOf - returns last index of object in arrangedContent', function(assert) { - array.get('content').pushObject(4); - assert.equal(array.lastIndexOf(4), 2, 'returns last arranged index'); -}); +QUnit.test( + 'lastIndexOf - returns last index of object in arrangedContent', + function(assert) { + array.get('content').pushObject(4); + assert.equal(array.lastIndexOf(4), 2, 'returns last arranged index'); + } +); -QUnit.test('objectAt - returns object at index in arrangedContent', function(assert) { +QUnit.test('objectAt - returns object at index in arrangedContent', function( + assert +) { assert.equal(objectAt(array, 1), 4, 'returns object at index'); }); // Not sure if we need a specific test for it, since it's internal -QUnit.test('objectAtContent - returns object at index in arrangedContent', function(assert) { - assert.equal(array.objectAtContent(1), 4, 'returns object at index'); -}); - -QUnit.test('objectsAt - returns objects at indices in arrangedContent', function(assert) { - assert.deepEqual(array.objectsAt([0, 2, 4]), [5, 2, undefined], 'returns objects at indices'); -}); - -QUnit.test('replace - mutating an arranged ArrayProxy is not allowed', function() { - expectAssertion(() => { - array.replace(0, 0, [3]); - }, /Mutating an arranged ArrayProxy is not allowed/); -}); +QUnit.test( + 'objectAtContent - returns object at index in arrangedContent', + function(assert) { + assert.equal(array.objectAtContent(1), 4, 'returns object at index'); + } +); + +QUnit.test( + 'objectsAt - returns objects at indices in arrangedContent', + function(assert) { + assert.deepEqual( + array.objectsAt([0, 2, 4]), + [5, 2, undefined], + 'returns objects at indices' + ); + } +); + +QUnit.test( + 'replace - mutating an arranged ArrayProxy is not allowed', + function() { + expectAssertion(() => { + array.replace(0, 0, [3]); + }, /Mutating an arranged ArrayProxy is not allowed/); + } +); -QUnit.test('replaceContent - does a standard array replace on content', function(assert) { - run(() => array.replaceContent(1, 2, [3])); - assert.deepEqual(array.get('content'), [1, 3, 5]); -}); +QUnit.test( + 'replaceContent - does a standard array replace on content', + function(assert) { + run(() => array.replaceContent(1, 2, [3])); + assert.deepEqual(array.get('content'), [1, 3, 5]); + } +); QUnit.test('slice - returns a slice of the arrangedContent', function(assert) { assert.deepEqual(array.slice(1, 3), [4, 2], 'returns sliced arrangedContent'); @@ -73,8 +108,14 @@ QUnit.test('toArray - returns copy of arrangedContent', function(assert) { assert.deepEqual(array.toArray(), [5, 4, 2, 1]); }); -QUnit.test('without - returns arrangedContent without object', function(assert) { - assert.deepEqual(array.without(2), [5, 4, 1], 'returns arranged without object'); +QUnit.test('without - returns arrangedContent without object', function( + assert +) { + assert.deepEqual( + array.without(2), + [5, 4, 1], + 'returns arranged without object' + ); }); QUnit.test('lastObject - returns last arranged object', function(assert) { @@ -85,7 +126,6 @@ QUnit.test('firstObject - returns first arranged object', function(assert) { assert.equal(array.get('firstObject'), 5, 'returns first arranged object'); }); - QUnit.module('ArrayProxy - arrangedContent matching content', { beforeEach() { run(function() { @@ -102,17 +142,23 @@ QUnit.module('ArrayProxy - arrangedContent matching content', { }); QUnit.test('insertAt - inserts object at specified index', function(assert) { - run(function() { array.insertAt(2, 3); }); + run(function() { + array.insertAt(2, 3); + }); assert.deepEqual(array.get('content'), [1, 2, 3, 4, 5]); }); QUnit.test('replace - does a standard array replace', function(assert) { - run(function() { array.replace(1, 2, [3]); }); + run(function() { + array.replace(1, 2, [3]); + }); assert.deepEqual(array.get('content'), [1, 3, 5]); }); QUnit.test('reverseObjects - reverses content', function(assert) { - run(function() { array.reverseObjects(); }); + run(function() { + array.reverseObjects(); + }); assert.deepEqual(array.get('content'), [5, 4, 2, 1]); }); @@ -122,11 +168,20 @@ QUnit.module('ArrayProxy - arrangedContent with transforms', { array = ArrayProxy.extend({ arrangedContent: computed(function() { let content = this.get('content'); - return content && emberA(content.slice().sort(function(a, b) { - if (a == null) { a = -1; } - if (b == null) { b = -1; } - return b - a; - })); + return ( + content && + emberA( + content.slice().sort(function(a, b) { + if (a == null) { + a = -1; + } + if (b == null) { + b = -1; + } + return b - a; + }) + ) + ); }).property('content.[]'), objectAtContent(idx) { @@ -145,38 +200,65 @@ QUnit.module('ArrayProxy - arrangedContent with transforms', { } }); -QUnit.test('indexOf - returns index of object in arrangedContent', function(assert) { +QUnit.test('indexOf - returns index of object in arrangedContent', function( + assert +) { assert.equal(array.indexOf('4'), 1, 'returns arranged index'); }); -QUnit.test('lastIndexOf - returns last index of object in arrangedContent', function(assert) { - array.get('content').pushObject(4); - assert.equal(array.lastIndexOf('4'), 2, 'returns last arranged index'); -}); +QUnit.test( + 'lastIndexOf - returns last index of object in arrangedContent', + function(assert) { + array.get('content').pushObject(4); + assert.equal(array.lastIndexOf('4'), 2, 'returns last arranged index'); + } +); -QUnit.test('objectAt - returns object at index in arrangedContent', function(assert) { +QUnit.test('objectAt - returns object at index in arrangedContent', function( + assert +) { assert.equal(objectAt(array, 1), '4', 'returns object at index'); }); // Not sure if we need a specific test for it, since it's internal -QUnit.test('objectAtContent - returns object at index in arrangedContent', function(assert) { - assert.equal(array.objectAtContent(1), '4', 'returns object at index'); -}); - -QUnit.test('objectsAt - returns objects at indices in arrangedContent', function(assert) { - assert.deepEqual(array.objectsAt([0, 2, 4]), ['5', '2', undefined], 'returns objects at indices'); -}); +QUnit.test( + 'objectAtContent - returns object at index in arrangedContent', + function(assert) { + assert.equal(array.objectAtContent(1), '4', 'returns object at index'); + } +); + +QUnit.test( + 'objectsAt - returns objects at indices in arrangedContent', + function(assert) { + assert.deepEqual( + array.objectsAt([0, 2, 4]), + ['5', '2', undefined], + 'returns objects at indices' + ); + } +); QUnit.test('slice - returns a slice of the arrangedContent', function(assert) { - assert.deepEqual(array.slice(1, 3), ['4', '2'], 'returns sliced arrangedContent'); + assert.deepEqual( + array.slice(1, 3), + ['4', '2'], + 'returns sliced arrangedContent' + ); }); QUnit.test('toArray - returns copy of arrangedContent', function(assert) { assert.deepEqual(array.toArray(), ['5', '4', '2', '1']); }); -QUnit.test('without - returns arrangedContent without object', function(assert) { - assert.deepEqual(array.without('2'), ['5', '4', '1'], 'returns arranged without object'); +QUnit.test('without - returns arrangedContent without object', function( + assert +) { + assert.deepEqual( + array.without('2'), + ['5', '4', '1'], + 'returns arranged without object' + ); }); QUnit.test('lastObject - returns last arranged object', function(assert) { @@ -207,7 +289,9 @@ QUnit.module('ArrayProxy - with transforms', { } }); -QUnit.test('popObject - removes last object in arrangedContent', function(assert) { +QUnit.test('popObject - removes last object in arrangedContent', function( + assert +) { let popped = array.popObject(); assert.equal(popped, '5', 'returns last object'); assert.deepEqual(array.toArray(), ['1', '2', '4'], 'removes from content'); @@ -223,8 +307,14 @@ QUnit.test('removeObjects - removes objects from content', function(assert) { assert.deepEqual(array.toArray(), ['1', '5']); }); -QUnit.test('shiftObject - removes from start of arrangedContent', function(assert) { +QUnit.test('shiftObject - removes from start of arrangedContent', function( + assert +) { let shifted = array.shiftObject(); assert.equal(shifted, '1', 'returns first object'); - assert.deepEqual(array.toArray(), ['2', '4', '5'], 'removes object from content'); + assert.deepEqual( + array.toArray(), + ['2', '4', '5'], + 'removes object from content' + ); }); diff --git a/packages/ember-runtime/tests/system/array_proxy/content_change_test.js b/packages/ember-runtime/tests/system/array_proxy/content_change_test.js index 938d6ead7ec..5e27a710b82 100644 --- a/packages/ember-runtime/tests/system/array_proxy/content_change_test.js +++ b/packages/ember-runtime/tests/system/array_proxy/content_change_test.js @@ -17,45 +17,54 @@ QUnit.test('should update length for null content', function(assert) { assert.equal(proxy.get('length'), 0, 'length updates'); }); -QUnit.test('should update length for null content when there is a computed property watching length', function(assert) { - let proxy = ArrayProxy.extend({ - isEmpty: not('length') - }).create({ - content: emberA([1, 2, 3]) - }); +QUnit.test( + 'should update length for null content when there is a computed property watching length', + function(assert) { + let proxy = ArrayProxy.extend({ + isEmpty: not('length') + }).create({ + content: emberA([1, 2, 3]) + }); - assert.equal(proxy.get('length'), 3, 'precond - length is 3'); + assert.equal(proxy.get('length'), 3, 'precond - length is 3'); - // Consume computed property that depends on length - proxy.get('isEmpty'); + // Consume computed property that depends on length + proxy.get('isEmpty'); - // update content - proxy.set('content', null); + // update content + proxy.set('content', null); - assert.equal(proxy.get('length'), 0, 'length updates'); -}); + assert.equal(proxy.get('length'), 0, 'length updates'); + } +); -QUnit.test('The ArrayProxy doesn\'t explode when assigned a destroyed object', function(assert) { - let proxy1 = ArrayProxy.create(); - let proxy2 = ArrayProxy.create(); +QUnit.test( + "The ArrayProxy doesn't explode when assigned a destroyed object", + function(assert) { + let proxy1 = ArrayProxy.create(); + let proxy2 = ArrayProxy.create(); - run(() => proxy1.destroy()); + run(() => proxy1.destroy()); - set(proxy2, 'content', proxy1); + set(proxy2, 'content', proxy1); - assert.ok(true, 'No exception was raised'); -}); + assert.ok(true, 'No exception was raised'); + } +); -QUnit.test('should update if content changes while change events are deferred', function(assert) { - let proxy = ArrayProxy.create(); +QUnit.test( + 'should update if content changes while change events are deferred', + function(assert) { + let proxy = ArrayProxy.create(); - assert.deepEqual(proxy.toArray(), []); + assert.deepEqual(proxy.toArray(), []); - changeProperties(() => { - proxy.set('content', emberA([1, 2, 3])); - assert.deepEqual(proxy.toArray(), [1, 2, 3]); - }); -}); + changeProperties(() => { + proxy.set('content', emberA([1, 2, 3])); + assert.deepEqual(proxy.toArray(), [1, 2, 3]); + }); + } +); QUnit.test('objectAt recomputes the object cache correctly', function(assert) { let indexes = []; @@ -87,7 +96,9 @@ QUnit.test('objectAt recomputes the object cache correctly', function(assert) { assert.deepEqual(indexes, [2, 3, 4]); }); -QUnit.test('getting length does not recompute the object cache', function(assert) { +QUnit.test('getting length does not recompute the object cache', function( + assert +) { let indexes = []; let proxy = ArrayProxy.extend({ diff --git a/packages/ember-runtime/tests/system/array_proxy/length_test.js b/packages/ember-runtime/tests/system/array_proxy/length_test.js index 3a9be2d00c3..8489c27844a 100644 --- a/packages/ember-runtime/tests/system/array_proxy/length_test.js +++ b/packages/ember-runtime/tests/system/array_proxy/length_test.js @@ -15,20 +15,18 @@ QUnit.test('array proxy + aliasedProperty complex test', function(assert) { colors: reads('model'), length: reads('colors.length'), - a: observer('length', () => aCalled++), - b: observer('colors.length', () => bCalled++), + a: observer('length', () => aCalled++), + b: observer('colors.length', () => bCalled++), c: observer('colors.content.length', () => cCalled++), - d: observer('colors.[]', () => dCalled++), - e: observer('colors.content.[]', () => eCalled++) + d: observer('colors.[]', () => dCalled++), + e: observer('colors.content.[]', () => eCalled++) }).create(); - obj.set('model', ArrayProxy.create({ - content: a([ - 'red', - 'yellow', - 'blue' - ]) - }) + obj.set( + 'model', + ArrayProxy.create({ + content: a(['red', 'yellow', 'blue']) + }) ); assert.equal(obj.get('colors.content.length'), 3); @@ -36,23 +34,44 @@ QUnit.test('array proxy + aliasedProperty complex test', function(assert) { assert.equal(obj.get('length'), 3); assert.equal(aCalled, 1, 'expected observer `length` to be called ONCE'); - assert.equal(bCalled, 1, 'expected observer `colors.length` to be called ONCE'); - assert.equal(cCalled, 1, 'expected observer `colors.content.length` to be called ONCE'); + assert.equal( + bCalled, + 1, + 'expected observer `colors.length` to be called ONCE' + ); + assert.equal( + cCalled, + 1, + 'expected observer `colors.content.length` to be called ONCE' + ); assert.equal(dCalled, 1, 'expected observer `colors.[]` to be called ONCE'); - assert.equal(eCalled, 1, 'expected observer `colors.content.[]` to be called ONCE'); + assert.equal( + eCalled, + 1, + 'expected observer `colors.content.[]` to be called ONCE' + ); - obj.get('colors').pushObjects([ - 'green', - 'red' - ]); + obj.get('colors').pushObjects(['green', 'red']); assert.equal(obj.get('colors.content.length'), 5); assert.equal(obj.get('colors.length'), 5); assert.equal(obj.get('length'), 5); assert.equal(aCalled, 2, 'expected observer `length` to be called TWICE'); - assert.equal(bCalled, 2, 'expected observer `colors.length` to be called TWICE'); - assert.equal(cCalled, 2, 'expected observer `colors.content.length` to be called TWICE'); + assert.equal( + bCalled, + 2, + 'expected observer `colors.length` to be called TWICE' + ); + assert.equal( + cCalled, + 2, + 'expected observer `colors.content.length` to be called TWICE' + ); assert.equal(dCalled, 2, 'expected observer `colors.[]` to be called TWICE'); - assert.equal(eCalled, 2, 'expected observer `colors.content.[]` to be called TWICE'); + assert.equal( + eCalled, + 2, + 'expected observer `colors.content.[]` to be called TWICE' + ); }); diff --git a/packages/ember-runtime/tests/system/array_proxy/watching_and_listening_test.js b/packages/ember-runtime/tests/system/array_proxy/watching_and_listening_test.js index fa5de00f69b..0a90a88ffd8 100644 --- a/packages/ember-runtime/tests/system/array_proxy/watching_and_listening_test.js +++ b/packages/ember-runtime/tests/system/array_proxy/watching_and_listening_test.js @@ -14,12 +14,11 @@ function sortedListenersFor(obj, eventName) { let keys = []; for (let i = 0; i < listeners.length; i += 3) { - keys.push(listeners[i+1]); + keys.push(listeners[i + 1]); } return keys.sort(); } - QUnit.module('ArrayProxy - watching and listening'); QUnit.test(`setting 'content' adds listeners correctly`, function(assert) { @@ -31,132 +30,135 @@ QUnit.test(`setting 'content' adds listeners correctly`, function(assert) { proxy.set('content', content); - assert.deepEqual( - sortedListenersFor(content, '@array:before'), - ['_arrangedContentArrayWillChange'] - ); - assert.deepEqual( - sortedListenersFor(content, '@array:change'), - ['_arrangedContentArrayDidChange'] - ); + assert.deepEqual(sortedListenersFor(content, '@array:before'), [ + '_arrangedContentArrayWillChange' + ]); + assert.deepEqual(sortedListenersFor(content, '@array:change'), [ + '_arrangedContentArrayDidChange' + ]); }); -QUnit.test(`changing 'content' adds and removes listeners correctly`, function(assert) { +QUnit.test(`changing 'content' adds and removes listeners correctly`, function( + assert +) { let content1 = A(); let content2 = A(); let proxy = ArrayProxy.create({ content: content1 }); - assert.deepEqual( - sortedListenersFor(content1, '@array:before'), - ['_arrangedContentArrayWillChange'] - ); - assert.deepEqual( - sortedListenersFor(content1, '@array:change'), - ['_arrangedContentArrayDidChange'] - ); + assert.deepEqual(sortedListenersFor(content1, '@array:before'), [ + '_arrangedContentArrayWillChange' + ]); + assert.deepEqual(sortedListenersFor(content1, '@array:change'), [ + '_arrangedContentArrayDidChange' + ]); proxy.set('content', content2); assert.deepEqual(sortedListenersFor(content1, '@array:before'), []); assert.deepEqual(sortedListenersFor(content1, '@array:change'), []); - assert.deepEqual( - sortedListenersFor(content2, '@array:before'), - ['_arrangedContentArrayWillChange'] - ); - assert.deepEqual( - sortedListenersFor(content2, '@array:change'), - ['_arrangedContentArrayDidChange'] - ); + assert.deepEqual(sortedListenersFor(content2, '@array:before'), [ + '_arrangedContentArrayWillChange' + ]); + assert.deepEqual(sortedListenersFor(content2, '@array:change'), [ + '_arrangedContentArrayDidChange' + ]); }); -QUnit.test(`regression test for https://github.com/emberjs/ember.js/issues/12475`, function(assert) { - let item1a = { id: 1 }; - let item1b = { id: 2 }; - let item1c = { id: 3 }; - let content1 = A([item1a, item1b, item1c]); - - let proxy = ArrayProxy.create({ content: content1 }); - let obj = { proxy }; - - defineProperty(obj, 'ids', computed('proxy.@each.id', function() { - return get(this, 'proxy').mapBy('id'); - })); - - // These manually added observers are to simulate the observers added by the - // rendering process in a template like: - // - // {{#each items as |item|}} - // {{item.id}} - // {{/each}} - addObserver(item1a, 'id', function() { }); - addObserver(item1b, 'id', function() { }); - addObserver(item1c, 'id', function() { }); - - // The EachProxy has not yet been consumed. Only the manually added - // observers are watching. - assert.equal(watcherCount(item1a, 'id'), 1); - assert.equal(watcherCount(item1b, 'id'), 1); - assert.equal(watcherCount(item1c, 'id'), 1); - - // Consume the each proxy. This causes the EachProxy to add two observers - // per item: one for "before" events and one for "after" events. - assert.deepEqual(get(obj, 'ids'), [1, 2, 3]); - - // For each item, the two each proxy observers and one manual added observer - // are watching. - assert.equal(watcherCount(item1a, 'id'), 2); - assert.equal(watcherCount(item1b, 'id'), 2); - assert.equal(watcherCount(item1c, 'id'), 2); - - // This should be a no-op because observers do not fire if the value - // 1. is an object and 2. is the same as the old value. - proxy.set('content', content1); - - assert.equal(watcherCount(item1a, 'id'), 2); - assert.equal(watcherCount(item1b, 'id'), 2); - assert.equal(watcherCount(item1c, 'id'), 2); - - // This is repeated to catch the regression. It should still be a no-op. - proxy.set('content', content1); - - assert.equal(watcherCount(item1a, 'id'), 2); - assert.equal(watcherCount(item1b, 'id'), 2); - assert.equal(watcherCount(item1c, 'id'), 2); - - // Set the content to a new array with completely different items and - // repeat the process. - let item2a = { id: 4 }; - let item2b = { id: 5 }; - let item2c = { id: 6 }; - let content2 = A([item2a, item2b, item2c]); - - addObserver(item2a, 'id', function() { }); - addObserver(item2b, 'id', function() { }); - addObserver(item2c, 'id', function() { }); - - proxy.set('content', content2); - - assert.deepEqual(get(obj, 'ids'), [4, 5, 6]); - - assert.equal(watcherCount(item2a, 'id'), 2); - assert.equal(watcherCount(item2b, 'id'), 2); - assert.equal(watcherCount(item2c, 'id'), 2); - - // Ensure that the observers added by the EachProxy on all items in the - // first content array have been torn down. - assert.equal(watcherCount(item1a, 'id'), 1); - assert.equal(watcherCount(item1b, 'id'), 1); - assert.equal(watcherCount(item1c, 'id'), 1); - - proxy.set('content', content2); - - assert.equal(watcherCount(item2a, 'id'), 2); - assert.equal(watcherCount(item2b, 'id'), 2); - assert.equal(watcherCount(item2c, 'id'), 2); - - proxy.set('content', content2); - - assert.equal(watcherCount(item2a, 'id'), 2); - assert.equal(watcherCount(item2b, 'id'), 2); - assert.equal(watcherCount(item2c, 'id'), 2); -}); +QUnit.test( + `regression test for https://github.com/emberjs/ember.js/issues/12475`, + function(assert) { + let item1a = { id: 1 }; + let item1b = { id: 2 }; + let item1c = { id: 3 }; + let content1 = A([item1a, item1b, item1c]); + + let proxy = ArrayProxy.create({ content: content1 }); + let obj = { proxy }; + + defineProperty( + obj, + 'ids', + computed('proxy.@each.id', function() { + return get(this, 'proxy').mapBy('id'); + }) + ); + + // These manually added observers are to simulate the observers added by the + // rendering process in a template like: + // + // {{#each items as |item|}} + // {{item.id}} + // {{/each}} + addObserver(item1a, 'id', function() {}); + addObserver(item1b, 'id', function() {}); + addObserver(item1c, 'id', function() {}); + + // The EachProxy has not yet been consumed. Only the manually added + // observers are watching. + assert.equal(watcherCount(item1a, 'id'), 1); + assert.equal(watcherCount(item1b, 'id'), 1); + assert.equal(watcherCount(item1c, 'id'), 1); + + // Consume the each proxy. This causes the EachProxy to add two observers + // per item: one for "before" events and one for "after" events. + assert.deepEqual(get(obj, 'ids'), [1, 2, 3]); + + // For each item, the two each proxy observers and one manual added observer + // are watching. + assert.equal(watcherCount(item1a, 'id'), 2); + assert.equal(watcherCount(item1b, 'id'), 2); + assert.equal(watcherCount(item1c, 'id'), 2); + + // This should be a no-op because observers do not fire if the value + // 1. is an object and 2. is the same as the old value. + proxy.set('content', content1); + + assert.equal(watcherCount(item1a, 'id'), 2); + assert.equal(watcherCount(item1b, 'id'), 2); + assert.equal(watcherCount(item1c, 'id'), 2); + + // This is repeated to catch the regression. It should still be a no-op. + proxy.set('content', content1); + + assert.equal(watcherCount(item1a, 'id'), 2); + assert.equal(watcherCount(item1b, 'id'), 2); + assert.equal(watcherCount(item1c, 'id'), 2); + + // Set the content to a new array with completely different items and + // repeat the process. + let item2a = { id: 4 }; + let item2b = { id: 5 }; + let item2c = { id: 6 }; + let content2 = A([item2a, item2b, item2c]); + + addObserver(item2a, 'id', function() {}); + addObserver(item2b, 'id', function() {}); + addObserver(item2c, 'id', function() {}); + + proxy.set('content', content2); + + assert.deepEqual(get(obj, 'ids'), [4, 5, 6]); + + assert.equal(watcherCount(item2a, 'id'), 2); + assert.equal(watcherCount(item2b, 'id'), 2); + assert.equal(watcherCount(item2c, 'id'), 2); + + // Ensure that the observers added by the EachProxy on all items in the + // first content array have been torn down. + assert.equal(watcherCount(item1a, 'id'), 1); + assert.equal(watcherCount(item1b, 'id'), 1); + assert.equal(watcherCount(item1c, 'id'), 1); + + proxy.set('content', content2); + + assert.equal(watcherCount(item2a, 'id'), 2); + assert.equal(watcherCount(item2b, 'id'), 2); + assert.equal(watcherCount(item2c, 'id'), 2); + + proxy.set('content', content2); + + assert.equal(watcherCount(item2a, 'id'), 2); + assert.equal(watcherCount(item2b, 'id'), 2); + assert.equal(watcherCount(item2c, 'id'), 2); + } +); diff --git a/packages/ember-runtime/tests/system/core_object_test.js b/packages/ember-runtime/tests/system/core_object_test.js index 8d69b7bd478..d3360495f77 100644 --- a/packages/ember-runtime/tests/system/core_object_test.js +++ b/packages/ember-runtime/tests/system/core_object_test.js @@ -15,12 +15,15 @@ QUnit.test('works with new (one arg)', function(assert) { }); QUnit.test('works with new (> 1 arg)', function(assert) { - let obj = new CoreObject({ - firstName: 'Stef', - lastName: 'Penner' - }, { - other: 'name' - }); + let obj = new CoreObject( + { + firstName: 'Stef', + lastName: 'Penner' + }, + { + other: 'name' + } + ); assert.equal(obj.firstName, 'Stef'); assert.equal(obj.lastName, 'Penner'); @@ -28,41 +31,61 @@ QUnit.test('works with new (> 1 arg)', function(assert) { assert.equal(obj.other, undefined); // doesn't support multiple pojo' to the constructor }); -QUnit.test('toString should be not be added as a property when calling toString()', function(assert) { - let obj = new CoreObject({ - firstName: 'Foo', - lastName: 'Bar' - }); +QUnit.test( + 'toString should be not be added as a property when calling toString()', + function(assert) { + let obj = new CoreObject({ + firstName: 'Foo', + lastName: 'Bar' + }); - obj.toString(); + obj.toString(); - assert.notOk(obj.hasOwnProperty('toString'), 'Calling toString() should not create a toString class property'); -}); + assert.notOk( + obj.hasOwnProperty('toString'), + 'Calling toString() should not create a toString class property' + ); + } +); -QUnit.test('should not trigger proxy assertion when retrieving a proxy with (GH#16263)', function(assert) { - let someProxyishThing = CoreObject.extend({ - unknownProperty() { - return true; - } - }).create(); +QUnit.test( + 'should not trigger proxy assertion when retrieving a proxy with (GH#16263)', + function(assert) { + let someProxyishThing = CoreObject.extend({ + unknownProperty() { + return true; + } + }).create(); - let obj = new CoreObject({ - someProxyishThing - }); + let obj = new CoreObject({ + someProxyishThing + }); - let proxy = get(obj, 'someProxyishThing'); - assert.equal(get(proxy, 'lolol'), true, 'should be able to get data from a proxy'); -}); + let proxy = get(obj, 'someProxyishThing'); + assert.equal( + get(proxy, 'lolol'), + true, + 'should be able to get data from a proxy' + ); + } +); -QUnit.test('should not trigger proxy assertion when probing for a "symbol"', function(assert) { - let proxy = CoreObject.extend({ - unknownProperty() { - return true; - } - }).create(); +QUnit.test( + 'should not trigger proxy assertion when probing for a "symbol"', + function(assert) { + let proxy = CoreObject.extend({ + unknownProperty() { + return true; + } + }).create(); - assert.equal(get(proxy, 'lolol'), true, 'should be able to get data from a proxy'); + assert.equal( + get(proxy, 'lolol'), + true, + 'should be able to get data from a proxy' + ); - // should not trigger an assertion - getOwner(proxy); -}); + // should not trigger an assertion + getOwner(proxy); + } +); diff --git a/packages/ember-runtime/tests/system/lazy_load_test.js b/packages/ember-runtime/tests/system/lazy_load_test.js index d24b44b2e78..9b78847b5ba 100644 --- a/packages/ember-runtime/tests/system/lazy_load_test.js +++ b/packages/ember-runtime/tests/system/lazy_load_test.js @@ -10,39 +10,47 @@ QUnit.module('Lazy Loading', { } }); -QUnit.test('if a load hook is registered, it is executed when runLoadHooks are exected', function(assert) { - let count = 0; +QUnit.test( + 'if a load hook is registered, it is executed when runLoadHooks are exected', + function(assert) { + let count = 0; - run(function() { - onLoad('__test_hook__', function(object) { - count += object; + run(function() { + onLoad('__test_hook__', function(object) { + count += object; + }); }); - }); - run(function() { - runLoadHooks('__test_hook__', 1); - }); + run(function() { + runLoadHooks('__test_hook__', 1); + }); - assert.equal(count, 1, 'the object was passed into the load hook'); -}); + assert.equal(count, 1, 'the object was passed into the load hook'); + } +); -QUnit.test('if runLoadHooks was already run, it executes newly added hooks immediately', function(assert) { - let count = 0; - run(() => { - onLoad('__test_hook__', object => count += object); - }); +QUnit.test( + 'if runLoadHooks was already run, it executes newly added hooks immediately', + function(assert) { + let count = 0; + run(() => { + onLoad('__test_hook__', object => (count += object)); + }); - run(() => runLoadHooks('__test_hook__', 1)); + run(() => runLoadHooks('__test_hook__', 1)); - count = 0; - run(() => { - onLoad('__test_hook__', object => count += object); - }); + count = 0; + run(() => { + onLoad('__test_hook__', object => (count += object)); + }); - assert.equal(count, 1, 'the original object was passed into the load hook'); -}); + assert.equal(count, 1, 'the original object was passed into the load hook'); + } +); -QUnit.test('hooks in ENV.EMBER_LOAD_HOOKS[\'hookName\'] get executed', function(assert) { +QUnit.test("hooks in ENV.EMBER_LOAD_HOOKS['hookName'] get executed", function( + assert +) { // Note that the necessary code to perform this test is run before // the Ember lib is loaded in tests/index.html @@ -50,16 +58,28 @@ QUnit.test('hooks in ENV.EMBER_LOAD_HOOKS[\'hookName\'] get executed', function( runLoadHooks('__before_ember_test_hook__', 1); }); - assert.equal(window.ENV.__test_hook_count__, 1, 'the object was passed into the load hook'); + assert.equal( + window.ENV.__test_hook_count__, + 1, + 'the object was passed into the load hook' + ); }); -if (typeof window === 'object' && typeof window.dispatchEvent === 'function' && typeof CustomEvent === 'function') { +if ( + typeof window === 'object' && + typeof window.dispatchEvent === 'function' && + typeof CustomEvent === 'function' +) { QUnit.test('load hooks trigger a custom event', function(assert) { let eventObject = 'super duper awesome events'; window.addEventListener('__test_hook_for_events__', function(e) { assert.ok(true, 'custom event was fired'); - assert.equal(e.detail, eventObject, 'event details are provided properly'); + assert.equal( + e.detail, + eventObject, + 'event details are provided properly' + ); }); run(() => { diff --git a/packages/ember-runtime/tests/system/native_array/replace_test.js b/packages/ember-runtime/tests/system/native_array/replace_test.js index cfb3b04c518..269657170d1 100644 --- a/packages/ember-runtime/tests/system/native_array/replace_test.js +++ b/packages/ember-runtime/tests/system/native_array/replace_test.js @@ -8,6 +8,9 @@ QUnit.test('raises assertion if third argument is not an array', function() { }, 'The third argument to replace needs to be an array.'); }); -QUnit.test('it does not raise an assertion if third parameter is not passed', function(assert) { - assert.deepEqual(A([1, 2, 3]).replace(1, 2), A([1]), 'no assertion raised'); -}); +QUnit.test( + 'it does not raise an assertion if third parameter is not passed', + function(assert) { + assert.deepEqual(A([1, 2, 3]).replace(1, 2), A([1]), 'no assertion raised'); + } +); diff --git a/packages/ember-runtime/tests/system/object/computed_test.js b/packages/ember-runtime/tests/system/object/computed_test.js index 5933d884129..9212611aac3 100644 --- a/packages/ember-runtime/tests/system/object/computed_test.js +++ b/packages/ember-runtime/tests/system/object/computed_test.js @@ -9,35 +9,47 @@ import { oneWay as reads } from 'ember-runtime'; import { testWithDefault } from 'internal-test-helpers'; import EmberObject from '../../../system/object'; -function K() { return this; } +function K() { + return this; +} QUnit.module('EmberObject computed property'); testWithDefault('computed property on instance', function(get, set, assert) { let MyClass = EmberObject.extend({ - foo: computed(function() { return 'FOO'; }) + foo: computed(function() { + return 'FOO'; + }) }); assert.equal(get(new MyClass(), 'foo'), 'FOO'); }); - testWithDefault('computed property on subclass', function(get, set, assert) { let MyClass = EmberObject.extend({ - foo: computed(function() { return 'FOO'; }) + foo: computed(function() { + return 'FOO'; + }) }); let Subclass = MyClass.extend({ - foo: computed(function() { return 'BAR'; }) + foo: computed(function() { + return 'BAR'; + }) }); assert.equal(get(new Subclass(), 'foo'), 'BAR'); }); - -testWithDefault('replacing computed property with regular val', function(get, set, assert) { +testWithDefault('replacing computed property with regular val', function( + get, + set, + assert +) { let MyClass = EmberObject.extend({ - foo: computed(function() { return 'FOO'; }) + foo: computed(function() { + return 'FOO'; + }) }); let Subclass = MyClass.extend({ @@ -49,7 +61,6 @@ testWithDefault('replacing computed property with regular val', function(get, se testWithDefault('complex depndent keys', function(get, set, assert) { let MyClass = EmberObject.extend({ - init() { this._super(...arguments); set(this, 'bar', { baz: 'BIFF' }); @@ -61,7 +72,6 @@ testWithDefault('complex depndent keys', function(get, set, assert) { set(this, 'count', get(this, 'count') + 1); return emberGet(get(this, 'bar'), 'baz') + ' ' + get(this, 'count'); }).property('bar.baz') - }); let Subclass = MyClass.extend({ @@ -85,229 +95,288 @@ testWithDefault('complex depndent keys', function(get, set, assert) { assert.equal(get(obj2, 'foo'), 'BOOM 22'); }); -testWithDefault('complex dependent keys changing complex dependent keys', function(get, set, assert) { - let MyClass = EmberObject.extend({ - init() { - this._super(...arguments); - set(this, 'bar', { baz: 'BIFF' }); - }, - - count: 0, - - foo: computed(function() { - set(this, 'count', get(this, 'count') + 1); - return emberGet(get(this, 'bar'), 'baz') + ' ' + get(this, 'count'); - }).property('bar.baz') - }); +testWithDefault( + 'complex dependent keys changing complex dependent keys', + function(get, set, assert) { + let MyClass = EmberObject.extend({ + init() { + this._super(...arguments); + set(this, 'bar', { baz: 'BIFF' }); + }, + + count: 0, + + foo: computed(function() { + set(this, 'count', get(this, 'count') + 1); + return emberGet(get(this, 'bar'), 'baz') + ' ' + get(this, 'count'); + }).property('bar.baz') + }); - let Subclass = MyClass.extend({ - init() { - this._super(...arguments); - set(this, 'bar2', { baz: 'BIFF2' }); - }, + let Subclass = MyClass.extend({ + init() { + this._super(...arguments); + set(this, 'bar2', { baz: 'BIFF2' }); + }, - count: 0, + count: 0, - foo: computed(function() { - set(this, 'count', get(this, 'count') + 1); - return emberGet(get(this, 'bar2'), 'baz') + ' ' + get(this, 'count'); - }).property('bar2.baz') - }); + foo: computed(function() { + set(this, 'count', get(this, 'count') + 1); + return emberGet(get(this, 'bar2'), 'baz') + ' ' + get(this, 'count'); + }).property('bar2.baz') + }); - let obj2 = new Subclass(); + let obj2 = new Subclass(); - assert.equal(get(obj2, 'foo'), 'BIFF2 1'); + assert.equal(get(obj2, 'foo'), 'BIFF2 1'); - set(get(obj2, 'bar'), 'baz', 'BLARG'); - assert.equal(get(obj2, 'foo'), 'BIFF2 1', 'should not invalidate property'); + set(get(obj2, 'bar'), 'baz', 'BLARG'); + assert.equal(get(obj2, 'foo'), 'BIFF2 1', 'should not invalidate property'); - set(get(obj2, 'bar2'), 'baz', 'BLARG'); - assert.equal(get(obj2, 'foo'), 'BLARG 2', 'should invalidate property'); -}); + set(get(obj2, 'bar2'), 'baz', 'BLARG'); + assert.equal(get(obj2, 'foo'), 'BLARG 2', 'should invalidate property'); + } +); QUnit.test('can retrieve metadata for a computed property', function(assert) { let MyClass = EmberObject.extend({ - computedProperty: computed(function() { - }).meta({ key: 'keyValue' }) + computedProperty: computed(function() {}).meta({ key: 'keyValue' }) }); - assert.equal(emberGet(MyClass.metaForProperty('computedProperty'), 'key'), 'keyValue', 'metadata saved on the computed property can be retrieved'); + assert.equal( + emberGet(MyClass.metaForProperty('computedProperty'), 'key'), + 'keyValue', + 'metadata saved on the computed property can be retrieved' + ); let ClassWithNoMetadata = EmberObject.extend({ - computedProperty: computed(function() { - }).volatile(), + computedProperty: computed(function() {}).volatile(), staticProperty: 12 }); - assert.equal(typeof ClassWithNoMetadata.metaForProperty('computedProperty'), 'object', 'returns empty hash if no metadata has been saved'); + assert.equal( + typeof ClassWithNoMetadata.metaForProperty('computedProperty'), + 'object', + 'returns empty hash if no metadata has been saved' + ); expectAssertion(function() { ClassWithNoMetadata.metaForProperty('nonexistentProperty'); - }, 'metaForProperty() could not find a computed property with key \'nonexistentProperty\'.'); + }, "metaForProperty() could not find a computed property with key 'nonexistentProperty'."); expectAssertion(function() { ClassWithNoMetadata.metaForProperty('staticProperty'); - }, 'metaForProperty() could not find a computed property with key \'staticProperty\'.'); + }, "metaForProperty() could not find a computed property with key 'staticProperty'."); }); -QUnit.test('overriding a computed property with null removes it from eachComputedProperty iteration', function(assert) { - let MyClass = EmberObject.extend({ - foo: computed(function() {}), - - fooDidChange: observer('foo', function() {}), +QUnit.test( + 'overriding a computed property with null removes it from eachComputedProperty iteration', + function(assert) { + let MyClass = EmberObject.extend({ + foo: computed(function() {}), - bar: computed(function() {}), - }); + fooDidChange: observer('foo', function() {}), - let SubClass = MyClass.extend({ - foo: null - }); - - let list = []; + bar: computed(function() {}) + }); - SubClass.eachComputedProperty(name => list.push(name)); + let SubClass = MyClass.extend({ + foo: null + }); - assert.deepEqual(list.sort(), ['bar'], 'overridding with null removes from eachComputedProperty listing'); -}); + let list = []; -QUnit.test('can iterate over a list of computed properties for a class', function(assert) { - let MyClass = EmberObject.extend({ - foo: computed(function() {}), + SubClass.eachComputedProperty(name => list.push(name)); - fooDidChange: observer('foo', function() {}), + assert.deepEqual( + list.sort(), + ['bar'], + 'overridding with null removes from eachComputedProperty listing' + ); + } +); - bar: computed(function() {}), +QUnit.test( + 'can iterate over a list of computed properties for a class', + function(assert) { + let MyClass = EmberObject.extend({ + foo: computed(function() {}), - qux: alias('foo') - }); + fooDidChange: observer('foo', function() {}), - let SubClass = MyClass.extend({ - baz: computed(function() {}) - }); + bar: computed(function() {}), - SubClass.reopen({ - bat: computed(function() {}).meta({ iAmBat: true }) - }); + qux: alias('foo') + }); - let list = []; + let SubClass = MyClass.extend({ + baz: computed(function() {}) + }); - MyClass.eachComputedProperty(function(name) { - list.push(name); - }); + SubClass.reopen({ + bat: computed(function() {}).meta({ iAmBat: true }) + }); - assert.deepEqual(list.sort(), ['bar', 'foo', 'qux'], 'watched and unwatched computed properties are iterated'); + let list = []; - list = []; + MyClass.eachComputedProperty(function(name) { + list.push(name); + }); - SubClass.eachComputedProperty(function(name, meta) { - list.push(name); + assert.deepEqual( + list.sort(), + ['bar', 'foo', 'qux'], + 'watched and unwatched computed properties are iterated' + ); - if (name === 'bat') { - assert.deepEqual(meta, { iAmBat: true }); - } else { - assert.deepEqual(meta, {}); - } - }); + list = []; - assert.deepEqual(list.sort(), ['bar', 'bat', 'baz', 'foo', 'qux'], 'all inherited properties are included'); -}); + SubClass.eachComputedProperty(function(name, meta) { + list.push(name); -QUnit.test('list of properties updates when an additional property is added (such cache busting)', function(assert) { - let MyClass = EmberObject.extend({ - foo: computed(K), + if (name === 'bat') { + assert.deepEqual(meta, { iAmBat: true }); + } else { + assert.deepEqual(meta, {}); + } + }); - fooDidChange: observer('foo', function() {}), + assert.deepEqual( + list.sort(), + ['bar', 'bat', 'baz', 'foo', 'qux'], + 'all inherited properties are included' + ); + } +); - bar: computed(K) - }); +QUnit.test( + 'list of properties updates when an additional property is added (such cache busting)', + function(assert) { + let MyClass = EmberObject.extend({ + foo: computed(K), - let list = []; + fooDidChange: observer('foo', function() {}), - MyClass.eachComputedProperty(function(name) { - list.push(name); - }); + bar: computed(K) + }); - assert.deepEqual(list.sort(), ['bar', 'foo'].sort(), 'expected two computed properties'); + let list = []; - MyClass.reopen({ - baz: computed(K) - }); + MyClass.eachComputedProperty(function(name) { + list.push(name); + }); - MyClass.create(); // force apply mixins + assert.deepEqual( + list.sort(), + ['bar', 'foo'].sort(), + 'expected two computed properties' + ); - list = []; + MyClass.reopen({ + baz: computed(K) + }); - MyClass.eachComputedProperty(function(name) { - list.push(name); - }); + MyClass.create(); // force apply mixins - assert.deepEqual(list.sort(), ['bar', 'foo', 'baz'].sort(), 'expected three computed properties'); + list = []; - defineProperty(MyClass.prototype, 'qux', computed(K)); + MyClass.eachComputedProperty(function(name) { + list.push(name); + }); - list = []; + assert.deepEqual( + list.sort(), + ['bar', 'foo', 'baz'].sort(), + 'expected three computed properties' + ); - MyClass.eachComputedProperty(function(name) { - list.push(name); - }); + defineProperty(MyClass.prototype, 'qux', computed(K)); - assert.deepEqual(list.sort(), ['bar', 'foo', 'baz', 'qux'].sort(), 'expected four computed properties'); -}); + list = []; -QUnit.test('Calling _super in call outside the immediate function of a CP getter works', function(assert) { - function macro(callback) { - return computed(function() { - return callback.call(this); + MyClass.eachComputedProperty(function(name) { + list.push(name); }); - } - let MyClass = EmberObject.extend({ - foo: computed(function() { - return 'FOO'; - }) - }); - - let SubClass = MyClass.extend({ - foo: macro(function() { - return this._super(); - }) - }); + assert.deepEqual( + list.sort(), + ['bar', 'foo', 'baz', 'qux'].sort(), + 'expected four computed properties' + ); + } +); + +QUnit.test( + 'Calling _super in call outside the immediate function of a CP getter works', + function(assert) { + function macro(callback) { + return computed(function() { + return callback.call(this); + }); + } - assert.ok(emberGet(SubClass.create(), 'foo'), 'FOO', 'super value is fetched'); -}); + let MyClass = EmberObject.extend({ + foo: computed(function() { + return 'FOO'; + }) + }); -QUnit.test('Calling _super in apply outside the immediate function of a CP getter works', function(assert) { - function macro(callback) { - return computed(function() { - return callback.apply(this); + let SubClass = MyClass.extend({ + foo: macro(function() { + return this._super(); + }) }); - } - let MyClass = EmberObject.extend({ - foo: computed(function() { - return 'FOO'; - }) - }); + assert.ok( + emberGet(SubClass.create(), 'foo'), + 'FOO', + 'super value is fetched' + ); + } +); + +QUnit.test( + 'Calling _super in apply outside the immediate function of a CP getter works', + function(assert) { + function macro(callback) { + return computed(function() { + return callback.apply(this); + }); + } - let SubClass = MyClass.extend({ - foo: macro(function() { - return this._super(); - }) - }); + let MyClass = EmberObject.extend({ + foo: computed(function() { + return 'FOO'; + }) + }); - assert.ok(emberGet(SubClass.create(), 'foo'), 'FOO', 'super value is fetched'); -}); + let SubClass = MyClass.extend({ + foo: macro(function() { + return this._super(); + }) + }); -QUnit.test('observing computed.reads prop and overriding it in create() works', function(assert) { - let Obj = EmberObject.extend({ - name: reads('model.name'), - nameDidChange: observer('name', function() {}) - }); + assert.ok( + emberGet(SubClass.create(), 'foo'), + 'FOO', + 'super value is fetched' + ); + } +); + +QUnit.test( + 'observing computed.reads prop and overriding it in create() works', + function(assert) { + let Obj = EmberObject.extend({ + name: reads('model.name'), + nameDidChange: observer('name', function() {}) + }); - let obj1 = Obj.create({name: '1'}); - let obj2 = Obj.create({name: '2'}); + let obj1 = Obj.create({ name: '1' }); + let obj2 = Obj.create({ name: '2' }); - assert.equal(obj1.get('name'), '1'); - assert.equal(obj2.get('name'), '2'); -}); + assert.equal(obj1.get('name'), '1'); + assert.equal(obj2.get('name'), '2'); + } +); diff --git a/packages/ember-runtime/tests/system/object/create_test.js b/packages/ember-runtime/tests/system/object/create_test.js index 2ed2354154a..525c696e3f5 100644 --- a/packages/ember-runtime/tests/system/object/create_test.js +++ b/packages/ember-runtime/tests/system/object/create_test.js @@ -1,8 +1,4 @@ -import { - computed, - Mixin, - observer -} from 'ember-metal'; +import { computed, Mixin, observer } from 'ember-metal'; import { MANDATORY_SETTER } from 'ember/features'; import EmberObject from '../../../system/object'; @@ -17,7 +13,7 @@ QUnit.test('calls computed property setters', function(assert) { let MyClass = EmberObject.extend({ foo: computed({ get() { - return 'this is not the value you\'re looking for'; + return "this is not the value you're looking for"; }, set(key, value) { return value; @@ -30,22 +26,25 @@ QUnit.test('calls computed property setters', function(assert) { }); if (MANDATORY_SETTER) { - QUnit.test('sets up mandatory setters for watched simple properties', function(assert) { - let MyClass = EmberObject.extend({ - foo: null, - bar: null, - fooDidChange: observer('foo', function() {}) - }); - - let o = MyClass.create({ foo: 'bar', bar: 'baz' }); - assert.equal(o.get('foo'), 'bar'); - - let descriptor = Object.getOwnPropertyDescriptor(o, 'foo'); - assert.ok(descriptor.set, 'Mandatory setter was setup'); - - descriptor = Object.getOwnPropertyDescriptor(o, 'bar'); - assert.ok(!descriptor.set, 'Mandatory setter was not setup'); - }); + QUnit.test( + 'sets up mandatory setters for watched simple properties', + function(assert) { + let MyClass = EmberObject.extend({ + foo: null, + bar: null, + fooDidChange: observer('foo', function() {}) + }); + + let o = MyClass.create({ foo: 'bar', bar: 'baz' }); + assert.equal(o.get('foo'), 'bar'); + + let descriptor = Object.getOwnPropertyDescriptor(o, 'foo'); + assert.ok(descriptor.set, 'Mandatory setter was setup'); + + descriptor = Object.getOwnPropertyDescriptor(o, 'bar'); + assert.ok(!descriptor.set, 'Mandatory setter was not setup'); + } + ); } QUnit.test('calls setUnknownProperty if defined', function(assert) { @@ -79,7 +78,7 @@ QUnit.test('throws if you try to call _super in a method', function() { }, 'EmberObject.create no longer supports defining methods that call _super.'); }); -QUnit.test('throws if you try to \'mixin\' a definition', function() { +QUnit.test("throws if you try to 'mixin' a definition", function() { let myMixin = Mixin.create({ adder(arg1, arg2) { return arg1 + arg2; @@ -95,16 +94,25 @@ QUnit.test('inherits properties from passed in EmberObject', function(assert) { let baseObj = EmberObject.create({ foo: 'bar' }); let secondaryObj = EmberObject.create(baseObj); - assert.equal(secondaryObj.foo, baseObj.foo, 'Em.O.create inherits properties from EmberObject parameter'); + assert.equal( + secondaryObj.foo, + baseObj.foo, + 'Em.O.create inherits properties from EmberObject parameter' + ); }); -QUnit.test('throws if you try to pass anything a string as a parameter', function() { - let expected = 'EmberObject.create only accepts objects.'; +QUnit.test( + 'throws if you try to pass anything a string as a parameter', + function() { + let expected = 'EmberObject.create only accepts objects.'; - expectAssertion(() => EmberObject.create('some-string'), expected); -}); + expectAssertion(() => EmberObject.create('some-string'), expected); + } +); -QUnit.test('EmberObject.create can take undefined as a parameter', function(assert) { +QUnit.test('EmberObject.create can take undefined as a parameter', function( + assert +) { let o = EmberObject.create(undefined); assert.deepEqual(EmberObject.create(), o); }); diff --git a/packages/ember-runtime/tests/system/object/destroy_test.js b/packages/ember-runtime/tests/system/object/destroy_test.js index 1d0a69773ef..0ab29951436 100644 --- a/packages/ember-runtime/tests/system/object/destroy_test.js +++ b/packages/ember-runtime/tests/system/object/destroy_test.js @@ -12,131 +12,164 @@ import { MANDATORY_SETTER } from 'ember/features'; QUnit.module('ember-runtime/system/object/destroy_test'); -testBoth('should schedule objects to be destroyed at the end of the run loop', function(get , set, assert) { - let obj = EmberObject.create(); - let meta; +testBoth( + 'should schedule objects to be destroyed at the end of the run loop', + function(get, set, assert) { + let obj = EmberObject.create(); + let meta; + + run(() => { + obj.destroy(); + meta = peekMeta(obj); + assert.ok(meta, 'meta is not destroyed immediately'); + assert.ok( + get(obj, 'isDestroying'), + 'object is marked as destroying immediately' + ); + assert.ok( + !get(obj, 'isDestroyed'), + 'object is not destroyed immediately' + ); + }); - run(() => { - obj.destroy(); meta = peekMeta(obj); - assert.ok(meta, 'meta is not destroyed immediately'); - assert.ok(get(obj, 'isDestroying'), 'object is marked as destroying immediately'); - assert.ok(!get(obj, 'isDestroyed'), 'object is not destroyed immediately'); - }); - - meta = peekMeta(obj); - assert.ok(get(obj, 'isDestroyed'), 'object is destroyed after run loop finishes'); -}); + assert.ok( + get(obj, 'isDestroyed'), + 'object is destroyed after run loop finishes' + ); + } +); if (MANDATORY_SETTER) { // MANDATORY_SETTER moves value to meta.values // a destroyed object removes meta but leaves the accessor // that looks it up - QUnit.test('should raise an exception when modifying watched properties on a destroyed object', function(assert) { + QUnit.test( + 'should raise an exception when modifying watched properties on a destroyed object', + function(assert) { + let obj = EmberObject.extend({ + fooDidChange: observer('foo', function() {}) + }).create({ + foo: 'bar' + }); + + run(() => obj.destroy()); + + assert.throws(() => set(obj, 'foo', 'baz'), Error, 'raises an exception'); + } + ); +} + +QUnit.test( + 'observers should not fire after an object has been destroyed', + function(assert) { + let count = 0; let obj = EmberObject.extend({ - fooDidChange: observer('foo', function() { }) - }).create({ - foo: 'bar' + fooDidChange: observer('foo', function() { + count++; + }) + }).create(); + + obj.set('foo', 'bar'); + + assert.equal(count, 1, 'observer was fired once'); + + run(() => { + beginPropertyChanges(); + obj.set('foo', 'quux'); + obj.destroy(); + endPropertyChanges(); }); - run(() => obj.destroy()); + assert.equal( + count, + 1, + 'observer was not called after object was destroyed' + ); + } +); + +QUnit.test( + 'destroyed objects should not see each others changes during teardown but a long lived object should', + function(assert) { + let shouldChange = 0; + let shouldNotChange = 0; + + let objs = {}; + + let A = EmberObject.extend({ + objs: objs, + isAlive: true, + willDestroy() { + this.set('isAlive', false); + }, + bDidChange: observer('objs.b.isAlive', function() { + shouldNotChange++; + }), + cDidChange: observer('objs.c.isAlive', function() { + shouldNotChange++; + }) + }); - assert.throws(() => set(obj, 'foo', 'baz'), Error, 'raises an exception'); - }); -} + let B = EmberObject.extend({ + objs: objs, + isAlive: true, + willDestroy() { + this.set('isAlive', false); + }, + aDidChange: observer('objs.a.isAlive', function() { + shouldNotChange++; + }), + cDidChange: observer('objs.c.isAlive', function() { + shouldNotChange++; + }) + }); -QUnit.test('observers should not fire after an object has been destroyed', function(assert) { - let count = 0; - let obj = EmberObject.extend({ - fooDidChange: observer('foo', function() { - count++; - }) - }).create(); - - obj.set('foo', 'bar'); - - assert.equal(count, 1, 'observer was fired once'); - - run(() => { - beginPropertyChanges(); - obj.set('foo', 'quux'); - obj.destroy(); - endPropertyChanges(); - }); - - assert.equal(count, 1, 'observer was not called after object was destroyed'); -}); - -QUnit.test('destroyed objects should not see each others changes during teardown but a long lived object should', function(assert) { - let shouldChange = 0; - let shouldNotChange = 0; - - let objs = {}; - - let A = EmberObject.extend({ - objs: objs, - isAlive: true, - willDestroy() { - this.set('isAlive', false); - }, - bDidChange: observer('objs.b.isAlive', function () { - shouldNotChange++; - }), - cDidChange: observer('objs.c.isAlive', function () { - shouldNotChange++; - }) - }); - - let B = EmberObject.extend({ - objs: objs, - isAlive: true, - willDestroy() { - this.set('isAlive', false); - }, - aDidChange: observer('objs.a.isAlive', function () { - shouldNotChange++; - }), - cDidChange: observer('objs.c.isAlive', function () { - shouldNotChange++; - }) - }); - - let C = EmberObject.extend({ - objs: objs, - isAlive: true, - willDestroy() { - this.set('isAlive', false); - }, - aDidChange: observer('objs.a.isAlive', function () { - shouldNotChange++; - }), - bDidChange: observer('objs.b.isAlive', function () { - shouldNotChange++; - }) - }); - - let LongLivedObject = EmberObject.extend({ - objs: objs, - isAliveDidChange: observer('objs.a.isAlive', function () { - shouldChange++; - }) - }); - - objs.a = new A(); - - objs.b = new B(); - - objs.c = new C(); - - new LongLivedObject(); - - run(() => { - let keys = Object.keys(objs); - for (let i = 0; i < keys.length; i++) { - objs[keys[i]].destroy(); - } - }); + let C = EmberObject.extend({ + objs: objs, + isAlive: true, + willDestroy() { + this.set('isAlive', false); + }, + aDidChange: observer('objs.a.isAlive', function() { + shouldNotChange++; + }), + bDidChange: observer('objs.b.isAlive', function() { + shouldNotChange++; + }) + }); + + let LongLivedObject = EmberObject.extend({ + objs: objs, + isAliveDidChange: observer('objs.a.isAlive', function() { + shouldChange++; + }) + }); + + objs.a = new A(); + + objs.b = new B(); + + objs.c = new C(); + + new LongLivedObject(); + + run(() => { + let keys = Object.keys(objs); + for (let i = 0; i < keys.length; i++) { + objs[keys[i]].destroy(); + } + }); - assert.equal(shouldNotChange, 0, 'destroyed graph objs should not see change in willDestroy'); - assert.equal(shouldChange, 1, 'long lived should see change in willDestroy'); -}); + assert.equal( + shouldNotChange, + 0, + 'destroyed graph objs should not see change in willDestroy' + ); + assert.equal( + shouldChange, + 1, + 'long lived should see change in willDestroy' + ); + } +); diff --git a/packages/ember-runtime/tests/system/object/detect_test.js b/packages/ember-runtime/tests/system/object/detect_test.js index dd383f8b6d8..3971a136b14 100644 --- a/packages/ember-runtime/tests/system/object/detect_test.js +++ b/packages/ember-runtime/tests/system/object/detect_test.js @@ -7,7 +7,10 @@ QUnit.test('detect detects classes correctly', function(assert) { let B = A.extend(); let C = A.extend(); - assert.ok(EmberObject.detect(EmberObject), 'EmberObject is an EmberObject class'); + assert.ok( + EmberObject.detect(EmberObject), + 'EmberObject is an EmberObject class' + ); assert.ok(EmberObject.detect(A), 'A is an EmberObject class'); assert.ok(EmberObject.detect(B), 'B is an EmberObject class'); assert.ok(EmberObject.detect(C), 'C is an EmberObject class'); diff --git a/packages/ember-runtime/tests/system/object/es-compatibility-test.js b/packages/ember-runtime/tests/system/object/es-compatibility-test.js index 6ad906a039c..0e228917a31 100644 --- a/packages/ember-runtime/tests/system/object/es-compatibility-test.js +++ b/packages/ember-runtime/tests/system/object/es-compatibility-test.js @@ -22,18 +22,50 @@ QUnit.test('extending an Ember.Object', function(assert) { let myObject = MyObject.create({ passedProperty: 'passed-property' }); - assert.deepEqual(calls, ['constructor', 'init'], 'constructor then init called (create)'); - assert.equal(myObject.postInitProperty, 'post-init-property', 'constructor property available on instance (create)'); - assert.equal(myObject.initProperty, 'init-property', 'init property available on instance (create)'); - assert.equal(myObject.passedProperty, 'passed-property', 'passed property available on instance (create)'); + assert.deepEqual( + calls, + ['constructor', 'init'], + 'constructor then init called (create)' + ); + assert.equal( + myObject.postInitProperty, + 'post-init-property', + 'constructor property available on instance (create)' + ); + assert.equal( + myObject.initProperty, + 'init-property', + 'init property available on instance (create)' + ); + assert.equal( + myObject.passedProperty, + 'passed-property', + 'passed property available on instance (create)' + ); calls = []; myObject = new MyObject({ passedProperty: 'passed-property' }); - assert.deepEqual(calls, ['constructor', 'init'], 'constructor then init called (new)'); - assert.equal(myObject.postInitProperty, 'post-init-property', 'constructor property available on instance (new)'); - assert.equal(myObject.initProperty, 'init-property', 'init property available on instance (new)'); - assert.equal(myObject.passedProperty, 'passed-property', 'passed property available on instance (new)'); + assert.deepEqual( + calls, + ['constructor', 'init'], + 'constructor then init called (new)' + ); + assert.equal( + myObject.postInitProperty, + 'post-init-property', + 'constructor property available on instance (new)' + ); + assert.equal( + myObject.initProperty, + 'init-property', + 'init property available on instance (new)' + ); + assert.equal( + myObject.passedProperty, + 'passed-property', + 'passed property available on instance (new)' + ); }); QUnit.test('using super', function(assert) { @@ -62,11 +94,11 @@ QUnit.test('using super', function(assert) { let myObject = new MyObject(); myObject.method(); - assert.deepEqual(calls, [ - 'super-super-method', - 'super-method', - 'method' - ], 'chain of prototype methods called with super'); + assert.deepEqual( + calls, + ['super-super-method', 'super-method', 'method'], + 'chain of prototype methods called with super' + ); }); QUnit.test('using mixins', function(assert) { @@ -116,11 +148,19 @@ QUnit.test('extending an ES subclass of EmberObject', function(assert) { class MyObject extends SubEmberObject {} MyObject.create(); - assert.deepEqual(calls, ['constructor', 'init'], 'constructor then init called (create)'); + assert.deepEqual( + calls, + ['constructor', 'init'], + 'constructor then init called (create)' + ); calls = []; new MyObject(); - assert.deepEqual(calls, ['constructor', 'init'], 'constructor then init called (new)'); + assert.deepEqual( + calls, + ['constructor', 'init'], + 'constructor then init called (new)' + ); }); // TODO: Needs to be fixed. Currently only `init` is called. @@ -142,9 +182,17 @@ QUnit.skip('calling extend on an ES subclass of EmberObject', function(assert) { let MyObject = SubEmberObject.extend({}); MyObject.create(); - assert.deepEqual(calls, ['constructor', 'init'], 'constructor then init called (create)'); + assert.deepEqual( + calls, + ['constructor', 'init'], + 'constructor then init called (create)' + ); calls = []; new MyObject(); - assert.deepEqual(calls, ['constructor', 'init'], 'constructor then init called (new)'); + assert.deepEqual( + calls, + ['constructor', 'init'], + 'constructor then init called (new)' + ); }); diff --git a/packages/ember-runtime/tests/system/object/events_test.js b/packages/ember-runtime/tests/system/object/events_test.js index ff723abaf81..3c8376b7c15 100644 --- a/packages/ember-runtime/tests/system/object/events_test.js +++ b/packages/ember-runtime/tests/system/object/events_test.js @@ -5,7 +5,9 @@ QUnit.module('Object events'); QUnit.test('a listener can be added to an object', function(assert) { let count = 0; - let F = function() { count++; }; + let F = function() { + count++; + }; let obj = EmberObject.extend(Evented).create(); @@ -19,21 +21,26 @@ QUnit.test('a listener can be added to an object', function(assert) { assert.equal(count, 2, 'the event was triggered'); }); -QUnit.test('a listener can be added and removed automatically the first time it is triggered', function(assert) { - let count = 0; - let F = function() { count++; }; +QUnit.test( + 'a listener can be added and removed automatically the first time it is triggered', + function(assert) { + let count = 0; + let F = function() { + count++; + }; - let obj = EmberObject.extend(Evented).create(); + let obj = EmberObject.extend(Evented).create(); - obj.one('event!', F); - obj.trigger('event!'); + obj.one('event!', F); + obj.trigger('event!'); - assert.equal(count, 1, 'the event was triggered'); + assert.equal(count, 1, 'the event was triggered'); - obj.trigger('event!'); + obj.trigger('event!'); - assert.equal(count, 1, 'the event was not triggered again'); -}); + assert.equal(count, 1, 'the event was not triggered again'); + } +); QUnit.test('triggering an event can have arguments', function(assert) { let self, args; @@ -51,30 +58,33 @@ QUnit.test('triggering an event can have arguments', function(assert) { assert.equal(self, obj); }); -QUnit.test('a listener can be added and removed automatically and have arguments', function(assert) { - let self, args; - let count = 0; +QUnit.test( + 'a listener can be added and removed automatically and have arguments', + function(assert) { + let self, args; + let count = 0; - let obj = EmberObject.extend(Evented).create(); + let obj = EmberObject.extend(Evented).create(); - obj.one('event!', function() { - args = [].slice.call(arguments); - self = this; - count++; - }); + obj.one('event!', function() { + args = [].slice.call(arguments); + self = this; + count++; + }); - obj.trigger('event!', 'foo', 'bar'); + obj.trigger('event!', 'foo', 'bar'); - assert.deepEqual(args, ['foo', 'bar']); - assert.equal(self, obj); - assert.equal(count, 1, 'the event is triggered once'); + assert.deepEqual(args, ['foo', 'bar']); + assert.equal(self, obj); + assert.equal(count, 1, 'the event is triggered once'); - obj.trigger('event!', 'baz', 'bat'); + obj.trigger('event!', 'baz', 'bat'); - assert.deepEqual(args, ['foo', 'bar']); - assert.equal(count, 1, 'the event was not triggered again'); - assert.equal(self, obj); -}); + assert.deepEqual(args, ['foo', 'bar']); + assert.equal(count, 1, 'the event was not triggered again'); + assert.equal(self, obj); + } +); QUnit.test('binding an event can specify a different target', function(assert) { let self, args; @@ -93,24 +103,31 @@ QUnit.test('binding an event can specify a different target', function(assert) { assert.equal(self, target); }); -QUnit.test('a listener registered with one can take method as string and can be added with different target', function(assert) { - let count = 0; - let target = {}; - target.fn = function() { count++; }; +QUnit.test( + 'a listener registered with one can take method as string and can be added with different target', + function(assert) { + let count = 0; + let target = {}; + target.fn = function() { + count++; + }; - let obj = EmberObject.extend(Evented).create(); + let obj = EmberObject.extend(Evented).create(); - obj.one('event!', target, 'fn'); - obj.trigger('event!'); + obj.one('event!', target, 'fn'); + obj.trigger('event!'); - assert.equal(count, 1, 'the event was triggered'); + assert.equal(count, 1, 'the event was triggered'); - obj.trigger('event!'); + obj.trigger('event!'); - assert.equal(count, 1, 'the event was not triggered again'); -}); + assert.equal(count, 1, 'the event was not triggered again'); + } +); -QUnit.test('a listener registered with one can be removed with off', function(assert) { +QUnit.test('a listener registered with one can be removed with off', function( + assert +) { let obj = EmberObject.extend(Evented, { F() {} }).create(); @@ -127,7 +144,9 @@ QUnit.test('a listener registered with one can be removed with off', function(as assert.equal(obj.has('event!'), false, 'has no more events'); }); -QUnit.test('adding and removing listeners should be chainable', function(assert) { +QUnit.test('adding and removing listeners should be chainable', function( + assert +) { let obj = EmberObject.extend(Evented).create(); let F = function() {}; diff --git a/packages/ember-runtime/tests/system/object/extend_test.js b/packages/ember-runtime/tests/system/object/extend_test.js index cd94a227f8d..f9ec25fab5c 100644 --- a/packages/ember-runtime/tests/system/object/extend_test.js +++ b/packages/ember-runtime/tests/system/object/extend_test.js @@ -21,10 +21,14 @@ QUnit.test('Sub-subclass', function(assert) { QUnit.test('Overriding a method several layers deep', function(assert) { let SomeClass = EmberObject.extend({ fooCnt: 0, - foo() { this.fooCnt++; }, + foo() { + this.fooCnt++; + }, barCnt: 0, - bar() { this.barCnt++; } + bar() { + this.barCnt++; + } }); let AnotherClass = SomeClass.extend({ @@ -64,15 +68,30 @@ QUnit.test('Overriding a method several layers deep', function(assert) { }); QUnit.test('With concatenatedProperties', function(assert) { - let SomeClass = EmberObject.extend({ things: 'foo', concatenatedProperties: ['things'] }); + let SomeClass = EmberObject.extend({ + things: 'foo', + concatenatedProperties: ['things'] + }); let AnotherClass = SomeClass.extend({ things: 'bar' }); let YetAnotherClass = SomeClass.extend({ things: 'baz' }); let some = new SomeClass(); let another = new AnotherClass(); let yetAnother = new YetAnotherClass(); - assert.deepEqual(some.get('things'), ['foo'], 'base class should have just its value'); - assert.deepEqual(another.get('things'), ['foo', 'bar'], 'subclass should have base class\' and its own'); - assert.deepEqual(yetAnother.get('things'), ['foo', 'baz'], 'subclass should have base class\' and its own'); + assert.deepEqual( + some.get('things'), + ['foo'], + 'base class should have just its value' + ); + assert.deepEqual( + another.get('things'), + ['foo', 'bar'], + "subclass should have base class' and its own" + ); + assert.deepEqual( + yetAnother.get('things'), + ['foo', 'baz'], + "subclass should have base class' and its own" + ); }); QUnit.test('With concatenatedProperties class properties', function(assert) { @@ -88,9 +107,21 @@ QUnit.test('With concatenatedProperties class properties', function(assert) { let some = new SomeClass(); let another = new AnotherClass(); let yetAnother = new YetAnotherClass(); - assert.deepEqual(get(some.constructor, 'things'), ['foo'], 'base class should have just its value'); - assert.deepEqual(get(another.constructor, 'things'), ['foo', 'bar'], 'subclass should have base class\' and its own'); - assert.deepEqual(get(yetAnother.constructor, 'things'), ['foo', 'baz'], 'subclass should have base class\' and its own'); + assert.deepEqual( + get(some.constructor, 'things'), + ['foo'], + 'base class should have just its value' + ); + assert.deepEqual( + get(another.constructor, 'things'), + ['foo', 'bar'], + "subclass should have base class' and its own" + ); + assert.deepEqual( + get(yetAnother.constructor, 'things'), + ['foo', 'baz'], + "subclass should have base class' and its own" + ); }); QUnit.test('Overriding a computed property with an observer', assert => { diff --git a/packages/ember-runtime/tests/system/object/observer_test.js b/packages/ember-runtime/tests/system/object/observer_test.js index 374adaecdab..e62e4d1fd0d 100644 --- a/packages/ember-runtime/tests/system/object/observer_test.js +++ b/packages/ember-runtime/tests/system/object/observer_test.js @@ -70,7 +70,8 @@ testBoth('observer on instance overriding class', function(get, set, assert) { }); let obj = MyClass.extend({ - foo: observer('baz', function() { // <-- change property we observe + foo: observer('baz', function() { + // <-- change property we observe set(this, 'count', get(this, 'count') + 1); }) }).create(); @@ -84,7 +85,11 @@ testBoth('observer on instance overriding class', function(get, set, assert) { assert.equal(get(obj, 'count'), 1, 'should invoke observer after change'); }); -testBoth('observer should not fire after being destroyed', function(get, set, assert) { +testBoth('observer should not fire after being destroyed', function( + get, + set, + assert +) { let obj = EmberObject.extend({ count: 0, foo: observer('bar', function() { @@ -92,7 +97,11 @@ testBoth('observer should not fire after being destroyed', function(get, set, as }) }).create(); - assert.equal(get(obj, 'count'), 0, 'precond - should not invoke observer immediately'); + assert.equal( + get(obj, 'count'), + 0, + 'precond - should not invoke observer immediately' + ); run(() => obj.destroy()); @@ -106,7 +115,6 @@ testBoth('observer should not fire after being destroyed', function(get, set, as // COMPLEX PROPERTIES // - testBoth('chain observer on class', function(get, set, assert) { let MyClass = EmberObject.extend({ count: 0, @@ -136,7 +144,6 @@ testBoth('chain observer on class', function(get, set, assert) { assert.equal(get(obj2, 'count'), 1, 'should invoke observer on obj2'); }); - testBoth('chain observer on class', function(get, set, assert) { let MyClass = EmberObject.extend({ count: 0, @@ -175,36 +182,47 @@ testBoth('chain observer on class', function(get, set, assert) { assert.equal(get(obj2, 'count'), 1, 'should invoke observer on obj2'); }); -testBoth('chain observer on class that has a reference to an uninitialized object will finish chains that reference it', function(get, set, assert) { - let changed = false; - - let ChildClass = EmberObject.extend({ - parent: null, - parentOneTwoDidChange: observer('parent.one.two', function() { - changed = true; - }) - }); - - let ParentClass = EmberObject.extend({ - one: { - two: 'old' - }, - init() { - this.child = ChildClass.create({ - parent: this - }); - } - }); - - let parent = new ParentClass(); - - assert.equal(changed, false, 'precond'); - - set(parent, 'one.two', 'new'); - - assert.equal(changed, true, 'child should have been notified of change to path'); - - set(parent, 'one', { two: 'newer' }); - - assert.equal(changed, true, 'child should have been notified of change to path'); -}); +testBoth( + 'chain observer on class that has a reference to an uninitialized object will finish chains that reference it', + function(get, set, assert) { + let changed = false; + + let ChildClass = EmberObject.extend({ + parent: null, + parentOneTwoDidChange: observer('parent.one.two', function() { + changed = true; + }) + }); + + let ParentClass = EmberObject.extend({ + one: { + two: 'old' + }, + init() { + this.child = ChildClass.create({ + parent: this + }); + } + }); + + let parent = new ParentClass(); + + assert.equal(changed, false, 'precond'); + + set(parent, 'one.two', 'new'); + + assert.equal( + changed, + true, + 'child should have been notified of change to path' + ); + + set(parent, 'one', { two: 'newer' }); + + assert.equal( + changed, + true, + 'child should have been notified of change to path' + ); + } +); diff --git a/packages/ember-runtime/tests/system/object/reopenClass_test.js b/packages/ember-runtime/tests/system/object/reopenClass_test.js index 98bfeb50704..59945c7cb62 100644 --- a/packages/ember-runtime/tests/system/object/reopenClass_test.js +++ b/packages/ember-runtime/tests/system/object/reopenClass_test.js @@ -6,7 +6,9 @@ QUnit.module('system/object/reopenClass'); QUnit.test('adds new properties to subclass', function(assert) { let Subclass = EmberObject.extend(); Subclass.reopenClass({ - foo() { return 'FOO'; }, + foo() { + return 'FOO'; + }, bar: 'BAR' }); @@ -17,7 +19,9 @@ QUnit.test('adds new properties to subclass', function(assert) { QUnit.test('class properties inherited by subclasses', function(assert) { let Subclass = EmberObject.extend(); Subclass.reopenClass({ - foo() { return 'FOO'; }, + foo() { + return 'FOO'; + }, bar: 'BAR' }); @@ -26,4 +30,3 @@ QUnit.test('class properties inherited by subclasses', function(assert) { assert.equal(SubSub.foo(), 'FOO', 'Adds method'); assert.equal(get(SubSub, 'bar'), 'BAR', 'Adds property'); }); - diff --git a/packages/ember-runtime/tests/system/object/reopen_test.js b/packages/ember-runtime/tests/system/object/reopen_test.js index a85e54d7892..0f1d031a07f 100644 --- a/packages/ember-runtime/tests/system/object/reopen_test.js +++ b/packages/ember-runtime/tests/system/object/reopen_test.js @@ -6,7 +6,9 @@ QUnit.module('system/core_object/reopen'); QUnit.test('adds new properties to subclass instance', function(assert) { let Subclass = EmberObject.extend(); Subclass.reopen({ - foo() { return 'FOO'; }, + foo() { + return 'FOO'; + }, bar: 'BAR' }); @@ -19,7 +21,9 @@ QUnit.test('reopened properties inherited by subclasses', function(assert) { let SubSub = Subclass.extend(); Subclass.reopen({ - foo() { return 'FOO'; }, + foo() { + return 'FOO'; + }, bar: 'BAR' }); diff --git a/packages/ember-runtime/tests/system/object/strict-mode-test.js b/packages/ember-runtime/tests/system/object/strict-mode-test.js index 8a24203e71a..0fcb7e2bea4 100644 --- a/packages/ember-runtime/tests/system/object/strict-mode-test.js +++ b/packages/ember-runtime/tests/system/object/strict-mode-test.js @@ -2,7 +2,9 @@ import EmberObject from '../../../system/object'; QUnit.module('strict mode tests'); -QUnit.test('__superWrapper does not throw errors in strict mode', function(assert) { +QUnit.test('__superWrapper does not throw errors in strict mode', function( + assert +) { let Foo = EmberObject.extend({ blah() { return 'foo'; @@ -23,5 +25,9 @@ QUnit.test('__superWrapper does not throw errors in strict mode', function(asser let bar = Bar.create(); - assert.equal(bar.callBlah(), 'bar', 'can call local function without call/apply'); + assert.equal( + bar.callBlah(), + 'bar', + 'can call local function without call/apply' + ); }); diff --git a/packages/ember-runtime/tests/system/object_proxy_test.js b/packages/ember-runtime/tests/system/object_proxy_test.js index 409ac7ae086..c0f3fbfdbda 100644 --- a/packages/ember-runtime/tests/system/object_proxy_test.js +++ b/packages/ember-runtime/tests/system/object_proxy_test.js @@ -12,10 +12,16 @@ import ObjectProxy from '../../system/object_proxy'; QUnit.module('ObjectProxy'); -testBoth('should not proxy properties passed to create', function(get, set, assert) { +testBoth('should not proxy properties passed to create', function( + get, + set, + assert +) { let Proxy = ObjectProxy.extend({ cp: computed({ - get() { return this._cp; }, + get() { + return this._cp; + }, set(key, value) { this._cp = value; return this._cp; @@ -35,30 +41,64 @@ testBoth('should proxy properties to content', function(get, set, assert) { let content = { firstName: 'Tom', lastName: 'Dale', - unknownProperty(key) { return key + ' unknown';} + unknownProperty(key) { + return key + ' unknown'; + } }; let proxy = ObjectProxy.create(); - assert.equal(get(proxy, 'firstName'), undefined, 'get on proxy without content should return undefined'); + assert.equal( + get(proxy, 'firstName'), + undefined, + 'get on proxy without content should return undefined' + ); expectAssertion(() => { set(proxy, 'firstName', 'Foo'); }, /Cannot delegate set\('firstName', Foo\) to the 'content'/i); set(proxy, 'content', content); - assert.equal(get(proxy, 'firstName'), 'Tom', 'get on proxy with content should forward to content'); - assert.equal(get(proxy, 'lastName'), 'Dale', 'get on proxy with content should forward to content'); - assert.equal(get(proxy, 'foo'), 'foo unknown', 'get on proxy with content should forward to content'); + assert.equal( + get(proxy, 'firstName'), + 'Tom', + 'get on proxy with content should forward to content' + ); + assert.equal( + get(proxy, 'lastName'), + 'Dale', + 'get on proxy with content should forward to content' + ); + assert.equal( + get(proxy, 'foo'), + 'foo unknown', + 'get on proxy with content should forward to content' + ); set(proxy, 'lastName', 'Huda'); - assert.equal(get(content, 'lastName'), 'Huda', 'content should have new value from set on proxy'); - assert.equal(get(proxy, 'lastName'), 'Huda', 'proxy should have new value from set on proxy'); + assert.equal( + get(content, 'lastName'), + 'Huda', + 'content should have new value from set on proxy' + ); + assert.equal( + get(proxy, 'lastName'), + 'Huda', + 'proxy should have new value from set on proxy' + ); set(proxy, 'content', { firstName: 'Yehuda', lastName: 'Katz' }); - assert.equal(get(proxy, 'firstName'), 'Yehuda', 'proxy should reflect updated content'); - assert.equal(get(proxy, 'lastName'), 'Katz', 'proxy should reflect updated content'); + assert.equal( + get(proxy, 'firstName'), + 'Yehuda', + 'proxy should reflect updated content' + ); + assert.equal( + get(proxy, 'lastName'), + 'Katz', + 'proxy should reflect updated content' + ); }); QUnit.test('getting proxied properties with Ember.get should work', assert => { @@ -71,7 +111,6 @@ QUnit.test('getting proxied properties with Ember.get should work', assert => { assert.equal(get(proxy, 'foo'), 'FOO'); }); - QUnit.test(`JSON.stringify doens't assert`, assert => { let proxy = ObjectProxy.create({ content: { @@ -79,7 +118,10 @@ QUnit.test(`JSON.stringify doens't assert`, assert => { } }); - assert.equal(JSON.stringify(proxy), JSON.stringify({ content: { foo: 'FOO' } })); + assert.equal( + JSON.stringify(proxy), + JSON.stringify({ content: { foo: 'FOO' } }) + ); }); QUnit.test(`setting a property on the proxy avoids the assertion`, assert => { @@ -95,19 +137,22 @@ QUnit.test(`setting a property on the proxy avoids the assertion`, assert => { assert.equal(JSON.stringify(proxy), JSON.stringify({ content: 'hello' })); }); -QUnit.test(`setting a property on the proxy's prototype avoids the assertion`, assert => { - let proxy = ObjectProxy.extend({ - toJSON: null - }).create({ - content: { - toJSON() { - return 'hello'; +QUnit.test( + `setting a property on the proxy's prototype avoids the assertion`, + assert => { + let proxy = ObjectProxy.extend({ + toJSON: null + }).create({ + content: { + toJSON() { + return 'hello'; + } } - } - }); + }); - assert.equal(JSON.stringify(proxy), JSON.stringify({ content: 'hello' })); -}); + assert.equal(JSON.stringify(proxy), JSON.stringify({ content: 'hello' })); + } +); if (MANDATORY_GETTER && EMBER_METAL_ES5_GETTERS && HAS_NATIVE_PROXY) { QUnit.test('getting proxied properties with [] should be an error', () => { @@ -128,7 +173,7 @@ testBoth('should work with watched properties', function(get, set, assert) { let last; let Proxy = ObjectProxy.extend({ - fullName: computed(function () { + fullName: computed(function() { let firstName = this.get('firstName'); let lastName = this.get('lastName'); @@ -141,7 +186,7 @@ testBoth('should work with watched properties', function(get, set, assert) { let proxy = Proxy.create(); - addObserver(proxy, 'fullName', function () { + addObserver(proxy, 'fullName', function() { last = get(proxy, 'fullName'); count++; }); @@ -191,7 +236,7 @@ QUnit.test('set and get should work with paths', function(assert) { assert.equal(proxy.get('foo.bar'), 'hello'); assert.equal(proxy.get('content.foo.bar'), 'hello'); - proxy.addObserver('foo.bar', function () { + proxy.addObserver('foo.bar', function() { count++; }); @@ -202,7 +247,11 @@ QUnit.test('set and get should work with paths', function(assert) { assert.equal(proxy.get('content.foo.bar'), 'bye'); }); -testBoth('should transition between watched and unwatched strategies', function(get, set, assert) { +testBoth('should transition between watched and unwatched strategies', function( + get, + set, + assert +) { let content = { foo: 'foo' }; let proxy = ObjectProxy.create({ content: content }); let count = 0; @@ -250,12 +299,19 @@ testBoth('should transition between watched and unwatched strategies', function( assert.equal(get(proxy, 'foo'), 'foo'); }); -testBoth('setting `undefined` to a proxied content property should override its existing value', function(get, set, assert) { - let proxyObject = ObjectProxy.create({ - content: { - prop: 'emberjs' - } - }); - set(proxyObject, 'prop', undefined); - assert.equal(get(proxyObject, 'prop'), undefined, 'sets the `undefined` value to the proxied content'); -}); +testBoth( + 'setting `undefined` to a proxied content property should override its existing value', + function(get, set, assert) { + let proxyObject = ObjectProxy.create({ + content: { + prop: 'emberjs' + } + }); + set(proxyObject, 'prop', undefined); + assert.equal( + get(proxyObject, 'prop'), + undefined, + 'sets the `undefined` value to the proxied content' + ); + } +); diff --git a/packages/ember-runtime/tests/system/string/camelize_test.js b/packages/ember-runtime/tests/system/string/camelize_test.js index 433b9378aa6..b41b0bccebc 100644 --- a/packages/ember-runtime/tests/system/string/camelize_test.js +++ b/packages/ember-runtime/tests/system/string/camelize_test.js @@ -4,9 +4,15 @@ import { camelize } from '../../../system/string'; QUnit.module('EmberStringUtils.camelize'); if (!ENV.EXTEND_PROTOTYPES.String) { - QUnit.test('String.prototype.camelize is not modified without EXTEND_PROTOTYPES', function(assert) { - assert.ok('undefined' === typeof String.prototype.camelize, 'String.prototype helper disabled'); - }); + QUnit.test( + 'String.prototype.camelize is not modified without EXTEND_PROTOTYPES', + function(assert) { + assert.ok( + 'undefined' === typeof String.prototype.camelize, + 'String.prototype helper disabled' + ); + } + ); } function test(given, expected, description) { @@ -18,12 +24,24 @@ function test(given, expected, description) { }); } -test('my favorite items', 'myFavoriteItems', 'camelize normal string'); -test('I Love Ramen', 'iLoveRamen', 'camelize capitalized string'); -test('css-class-name', 'cssClassName', 'camelize dasherized string'); -test('action_name', 'actionName', 'camelize underscored string'); -test('action.name', 'actionName', 'camelize dot notation string'); -test('innerHTML', 'innerHTML', 'does nothing with camelcased string'); -test('PrivateDocs/OwnerInvoice', 'privateDocs/ownerInvoice', 'camelize namespaced classified string'); -test('private_docs/owner_invoice', 'privateDocs/ownerInvoice', 'camelize namespaced underscored string'); -test('private-docs/owner-invoice', 'privateDocs/ownerInvoice', 'camelize namespaced dasherized string'); +test('my favorite items', 'myFavoriteItems', 'camelize normal string'); +test('I Love Ramen', 'iLoveRamen', 'camelize capitalized string'); +test('css-class-name', 'cssClassName', 'camelize dasherized string'); +test('action_name', 'actionName', 'camelize underscored string'); +test('action.name', 'actionName', 'camelize dot notation string'); +test('innerHTML', 'innerHTML', 'does nothing with camelcased string'); +test( + 'PrivateDocs/OwnerInvoice', + 'privateDocs/ownerInvoice', + 'camelize namespaced classified string' +); +test( + 'private_docs/owner_invoice', + 'privateDocs/ownerInvoice', + 'camelize namespaced underscored string' +); +test( + 'private-docs/owner-invoice', + 'privateDocs/ownerInvoice', + 'camelize namespaced dasherized string' +); diff --git a/packages/ember-runtime/tests/system/string/capitalize_test.js b/packages/ember-runtime/tests/system/string/capitalize_test.js index 07064a16a17..7259850c321 100644 --- a/packages/ember-runtime/tests/system/string/capitalize_test.js +++ b/packages/ember-runtime/tests/system/string/capitalize_test.js @@ -4,9 +4,15 @@ import { capitalize } from '../../../system/string'; QUnit.module('EmberStringUtils.capitalize'); if (!ENV.EXTEND_PROTOTYPES.String) { - QUnit.test('String.prototype.capitalize is not modified without EXTEND_PROTOTYPES', function(assert) { - assert.ok('undefined' === typeof String.prototype.capitalize, 'String.prototype helper disabled'); - }); + QUnit.test( + 'String.prototype.capitalize is not modified without EXTEND_PROTOTYPES', + function(assert) { + assert.ok( + 'undefined' === typeof String.prototype.capitalize, + 'String.prototype helper disabled' + ); + } + ); } function test(given, expected, description) { @@ -18,12 +24,28 @@ function test(given, expected, description) { }); } -test('my favorite items', 'My favorite items', 'capitalize normal string'); -test('css-class-name', 'Css-class-name', 'capitalize dasherized string'); -test('action_name', 'Action_name', 'capitalize underscored string'); -test('innerHTML', 'InnerHTML', 'capitalize camelcased string'); -test('Capitalized string', 'Capitalized string', 'does nothing with capitalized string'); -test('privateDocs/ownerInvoice', 'PrivateDocs/OwnerInvoice', 'capitalize namespaced camelized string'); -test('private_docs/owner_invoice', 'Private_docs/Owner_invoice', 'capitalize namespaced underscored string'); -test('private-docs/owner-invoice', 'Private-docs/Owner-invoice', 'capitalize namespaced dasherized string'); -test('šabc', 'Šabc', 'capitalize string with accent character'); +test('my favorite items', 'My favorite items', 'capitalize normal string'); +test('css-class-name', 'Css-class-name', 'capitalize dasherized string'); +test('action_name', 'Action_name', 'capitalize underscored string'); +test('innerHTML', 'InnerHTML', 'capitalize camelcased string'); +test( + 'Capitalized string', + 'Capitalized string', + 'does nothing with capitalized string' +); +test( + 'privateDocs/ownerInvoice', + 'PrivateDocs/OwnerInvoice', + 'capitalize namespaced camelized string' +); +test( + 'private_docs/owner_invoice', + 'Private_docs/Owner_invoice', + 'capitalize namespaced underscored string' +); +test( + 'private-docs/owner-invoice', + 'Private-docs/Owner-invoice', + 'capitalize namespaced dasherized string' +); +test('šabc', 'Šabc', 'capitalize string with accent character'); diff --git a/packages/ember-runtime/tests/system/string/classify_test.js b/packages/ember-runtime/tests/system/string/classify_test.js index 83c4d1b97d8..71c9b1f6c39 100644 --- a/packages/ember-runtime/tests/system/string/classify_test.js +++ b/packages/ember-runtime/tests/system/string/classify_test.js @@ -4,9 +4,15 @@ import { classify } from '../../../system/string'; QUnit.module('EmberStringUtils.classify'); if (!ENV.EXTEND_PROTOTYPES.String) { - QUnit.test('String.prototype.classify is not modified without EXTEND_PROTOTYPES', function(assert) { - assert.ok('undefined' === typeof String.prototype.classify, 'String.prototype helper disabled'); - }); + QUnit.test( + 'String.prototype.classify is not modified without EXTEND_PROTOTYPES', + function(assert) { + assert.ok( + 'undefined' === typeof String.prototype.classify, + 'String.prototype helper disabled' + ); + } + ); } function test(given, expected, description) { @@ -18,18 +24,46 @@ function test(given, expected, description) { }); } -test('my favorite items', 'MyFavoriteItems', 'classify normal string'); -test('css-class-name', 'CssClassName', 'classify dasherized string'); -test('action_name', 'ActionName', 'classify underscored string'); -test('privateDocs/ownerInvoice', 'PrivateDocs/OwnerInvoice', 'classify namespaced camelized string'); -test('private_docs/owner_invoice', 'PrivateDocs/OwnerInvoice', 'classify namespaced underscored string'); -test('private-docs/owner-invoice', 'PrivateDocs/OwnerInvoice', 'classify namespaced dasherized string'); -test('-view-registry', '_ViewRegistry', 'classify prefixed dasherized string'); -test('components/-text-field', 'Components/_TextField', 'classify namespaced prefixed dasherized string'); -test('_Foo_Bar', '_FooBar', 'classify underscore-prefixed underscored string'); -test('_Foo-Bar', '_FooBar', 'classify underscore-prefixed dasherized string'); -test('_foo/_bar', '_Foo/_Bar', 'classify underscore-prefixed-namespaced underscore-prefixed string'); -test('-foo/_bar', '_Foo/_Bar', 'classify dash-prefixed-namespaced underscore-prefixed string'); -test('-foo/-bar', '_Foo/_Bar', 'classify dash-prefixed-namespaced dash-prefixed string'); -test('InnerHTML', 'InnerHTML', 'does nothing with classified string'); -test('_FooBar', '_FooBar', 'does nothing with classified prefixed string'); +test('my favorite items', 'MyFavoriteItems', 'classify normal string'); +test('css-class-name', 'CssClassName', 'classify dasherized string'); +test('action_name', 'ActionName', 'classify underscored string'); +test( + 'privateDocs/ownerInvoice', + 'PrivateDocs/OwnerInvoice', + 'classify namespaced camelized string' +); +test( + 'private_docs/owner_invoice', + 'PrivateDocs/OwnerInvoice', + 'classify namespaced underscored string' +); +test( + 'private-docs/owner-invoice', + 'PrivateDocs/OwnerInvoice', + 'classify namespaced dasherized string' +); +test('-view-registry', '_ViewRegistry', 'classify prefixed dasherized string'); +test( + 'components/-text-field', + 'Components/_TextField', + 'classify namespaced prefixed dasherized string' +); +test('_Foo_Bar', '_FooBar', 'classify underscore-prefixed underscored string'); +test('_Foo-Bar', '_FooBar', 'classify underscore-prefixed dasherized string'); +test( + '_foo/_bar', + '_Foo/_Bar', + 'classify underscore-prefixed-namespaced underscore-prefixed string' +); +test( + '-foo/_bar', + '_Foo/_Bar', + 'classify dash-prefixed-namespaced underscore-prefixed string' +); +test( + '-foo/-bar', + '_Foo/_Bar', + 'classify dash-prefixed-namespaced dash-prefixed string' +); +test('InnerHTML', 'InnerHTML', 'does nothing with classified string'); +test('_FooBar', '_FooBar', 'does nothing with classified prefixed string'); diff --git a/packages/ember-runtime/tests/system/string/dasherize_test.js b/packages/ember-runtime/tests/system/string/dasherize_test.js index a2ed66bfe51..2dea8b252b6 100644 --- a/packages/ember-runtime/tests/system/string/dasherize_test.js +++ b/packages/ember-runtime/tests/system/string/dasherize_test.js @@ -4,9 +4,15 @@ import { dasherize } from '../../../system/string'; QUnit.module('EmberStringUtils.dasherize'); if (!ENV.EXTEND_PROTOTYPES.String) { - QUnit.test('String.prototype.dasherize is not modified without EXTEND_PROTOTYPES', function(assert) { - assert.ok('undefined' === typeof String.prototype.dasherize, 'String.prototype helper disabled'); - }); + QUnit.test( + 'String.prototype.dasherize is not modified without EXTEND_PROTOTYPES', + function(assert) { + assert.ok( + 'undefined' === typeof String.prototype.dasherize, + 'String.prototype helper disabled' + ); + } + ); } function test(given, expected, description) { @@ -18,11 +24,27 @@ function test(given, expected, description) { }); } -test('my favorite items', 'my-favorite-items', 'dasherize normal string'); -test('css-class-name', 'css-class-name', 'does nothing with dasherized string'); -test('action_name', 'action-name', 'dasherize underscored string'); -test('innerHTML', 'inner-html', 'dasherize camelcased string'); -test('toString', 'to-string', 'dasherize string that is the property name of Object.prototype'); -test('PrivateDocs/OwnerInvoice', 'private-docs/owner-invoice', 'dasherize namespaced classified string'); -test('privateDocs/ownerInvoice', 'private-docs/owner-invoice', 'dasherize namespaced camelized string'); -test('private_docs/owner_invoice', 'private-docs/owner-invoice', 'dasherize namespaced underscored string'); +test('my favorite items', 'my-favorite-items', 'dasherize normal string'); +test('css-class-name', 'css-class-name', 'does nothing with dasherized string'); +test('action_name', 'action-name', 'dasherize underscored string'); +test('innerHTML', 'inner-html', 'dasherize camelcased string'); +test( + 'toString', + 'to-string', + 'dasherize string that is the property name of Object.prototype' +); +test( + 'PrivateDocs/OwnerInvoice', + 'private-docs/owner-invoice', + 'dasherize namespaced classified string' +); +test( + 'privateDocs/ownerInvoice', + 'private-docs/owner-invoice', + 'dasherize namespaced camelized string' +); +test( + 'private_docs/owner_invoice', + 'private-docs/owner-invoice', + 'dasherize namespaced underscored string' +); diff --git a/packages/ember-runtime/tests/system/string/decamelize_test.js b/packages/ember-runtime/tests/system/string/decamelize_test.js index f635e18825d..949b70a6884 100644 --- a/packages/ember-runtime/tests/system/string/decamelize_test.js +++ b/packages/ember-runtime/tests/system/string/decamelize_test.js @@ -4,9 +4,15 @@ import { decamelize } from '../../../system/string'; QUnit.module('EmberStringUtils.decamelize'); if (!ENV.EXTEND_PROTOTYPES.String) { - QUnit.test('String.prototype.decamelize is not modified without EXTEND_PROTOTYPES', function(assert) { - assert.ok('undefined' === typeof String.prototype.decamelize, 'String.prototype helper disabled'); - }); + QUnit.test( + 'String.prototype.decamelize is not modified without EXTEND_PROTOTYPES', + function(assert) { + assert.ok( + 'undefined' === typeof String.prototype.decamelize, + 'String.prototype helper disabled' + ); + } + ); } function test(given, expected, description) { @@ -18,10 +24,26 @@ function test(given, expected, description) { }); } -test('my favorite items', 'my favorite items', 'does nothing with normal string'); -test('css-class-name', 'css-class-name', 'does nothing with dasherized string'); -test('action_name', 'action_name', 'does nothing with underscored string'); -test('innerHTML', 'inner_html', 'converts a camelized string into all lower case separated by underscores.'); -test('size160Url', 'size160_url', 'decamelizes strings with numbers'); -test('PrivateDocs/OwnerInvoice', 'private_docs/owner_invoice', 'decamelize namespaced classified string'); -test('privateDocs/ownerInvoice', 'private_docs/owner_invoice', 'decamelize namespaced camelized string'); +test( + 'my favorite items', + 'my favorite items', + 'does nothing with normal string' +); +test('css-class-name', 'css-class-name', 'does nothing with dasherized string'); +test('action_name', 'action_name', 'does nothing with underscored string'); +test( + 'innerHTML', + 'inner_html', + 'converts a camelized string into all lower case separated by underscores.' +); +test('size160Url', 'size160_url', 'decamelizes strings with numbers'); +test( + 'PrivateDocs/OwnerInvoice', + 'private_docs/owner_invoice', + 'decamelize namespaced classified string' +); +test( + 'privateDocs/ownerInvoice', + 'private_docs/owner_invoice', + 'decamelize namespaced camelized string' +); diff --git a/packages/ember-runtime/tests/system/string/loc_test.js b/packages/ember-runtime/tests/system/string/loc_test.js index 1d9926a22e2..faf3627d175 100644 --- a/packages/ember-runtime/tests/system/string/loc_test.js +++ b/packages/ember-runtime/tests/system/string/loc_test.js @@ -2,7 +2,6 @@ import { ENV } from 'ember-environment'; import { loc } from '../../../system/string'; import { setStrings, getStrings } from '../../../string_registry'; - let oldString; QUnit.module('EmberStringUtils.loc', { @@ -22,9 +21,15 @@ QUnit.module('EmberStringUtils.loc', { }); if (!ENV.EXTEND_PROTOTYPES.String) { - QUnit.test('String.prototype.loc is not available without EXTEND_PROTOTYPES', function(assert) { - assert.ok('undefined' === typeof String.prototype.loc, 'String.prototype helper disabled'); - }); + QUnit.test( + 'String.prototype.loc is not available without EXTEND_PROTOTYPES', + function(assert) { + assert.ok( + 'undefined' === typeof String.prototype.loc, + 'String.prototype helper disabled' + ); + } + ); } function test(given, args, expected, description) { @@ -36,10 +41,30 @@ function test(given, args, expected, description) { }); } -test('_Hello World', [], 'Bonjour le monde', `loc('_Hello World') => 'Bonjour le monde'`); -test('_Hello %@ %@', ['John', 'Doe'], 'Bonjour John Doe', `loc('_Hello %@ %@', ['John', 'Doe']) => 'Bonjour John Doe'`); -test('_Hello %@# %@#', ['John', 'Doe'], 'Bonjour Doe John', `loc('_Hello %@# %@#', ['John', 'Doe']) => 'Bonjour Doe John'`); -test('_Not In Strings', [], '_Not In Strings', `loc('_Not In Strings') => '_Not In Strings'`); +test( + '_Hello World', + [], + 'Bonjour le monde', + `loc('_Hello World') => 'Bonjour le monde'` +); +test( + '_Hello %@ %@', + ['John', 'Doe'], + 'Bonjour John Doe', + `loc('_Hello %@ %@', ['John', 'Doe']) => 'Bonjour John Doe'` +); +test( + '_Hello %@# %@#', + ['John', 'Doe'], + 'Bonjour Doe John', + `loc('_Hello %@# %@#', ['John', 'Doe']) => 'Bonjour Doe John'` +); +test( + '_Not In Strings', + [], + '_Not In Strings', + `loc('_Not In Strings') => '_Not In Strings'` +); QUnit.test('works with argument form', function(assert) { assert.equal(loc('_Hello %@', 'John'), 'Bonjour John'); diff --git a/packages/ember-runtime/tests/system/string/underscore_test.js b/packages/ember-runtime/tests/system/string/underscore_test.js index 52ac5acc806..78867bd0ca7 100644 --- a/packages/ember-runtime/tests/system/string/underscore_test.js +++ b/packages/ember-runtime/tests/system/string/underscore_test.js @@ -4,9 +4,15 @@ import { underscore } from '../../../system/string'; QUnit.module('EmberStringUtils.underscore'); if (!ENV.EXTEND_PROTOTYPES.String) { - QUnit.test('String.prototype.underscore is not available without EXTEND_PROTOTYPES', function(assert) { - assert.ok('undefined' === typeof String.prototype.underscore, 'String.prototype helper disabled'); - }); + QUnit.test( + 'String.prototype.underscore is not available without EXTEND_PROTOTYPES', + function(assert) { + assert.ok( + 'undefined' === typeof String.prototype.underscore, + 'String.prototype helper disabled' + ); + } + ); } function test(given, expected, description) { @@ -18,10 +24,22 @@ function test(given, expected, description) { }); } -test('my favorite items', 'my_favorite_items', 'with normal string'); -test('css-class-name', 'css_class_name', 'with dasherized string'); -test('action_name', 'action_name', 'does nothing with underscored string'); -test('innerHTML', 'inner_html', 'with camelcased string'); -test('PrivateDocs/OwnerInvoice', 'private_docs/owner_invoice', 'underscore namespaced classified string'); -test('privateDocs/ownerInvoice', 'private_docs/owner_invoice', 'underscore namespaced camelized string'); -test('private-docs/owner-invoice', 'private_docs/owner_invoice', 'underscore namespaced dasherized string'); +test('my favorite items', 'my_favorite_items', 'with normal string'); +test('css-class-name', 'css_class_name', 'with dasherized string'); +test('action_name', 'action_name', 'does nothing with underscored string'); +test('innerHTML', 'inner_html', 'with camelcased string'); +test( + 'PrivateDocs/OwnerInvoice', + 'private_docs/owner_invoice', + 'underscore namespaced classified string' +); +test( + 'privateDocs/ownerInvoice', + 'private_docs/owner_invoice', + 'underscore namespaced camelized string' +); +test( + 'private-docs/owner-invoice', + 'private_docs/owner_invoice', + 'underscore namespaced dasherized string' +); diff --git a/packages/ember-runtime/tests/system/string/w_test.js b/packages/ember-runtime/tests/system/string/w_test.js index d42194851fb..ee92e21e16a 100644 --- a/packages/ember-runtime/tests/system/string/w_test.js +++ b/packages/ember-runtime/tests/system/string/w_test.js @@ -4,9 +4,15 @@ import { w } from '../../../system/string'; QUnit.module('EmberStringUtils.w'); if (!ENV.EXTEND_PROTOTYPES.String) { - QUnit.test('String.prototype.w is not available without EXTEND_PROTOTYPES', function(assert) { - assert.ok('undefined' === typeof String.prototype.w, 'String.prototype helper disabled'); - }); + QUnit.test( + 'String.prototype.w is not available without EXTEND_PROTOTYPES', + function(assert) { + assert.ok( + 'undefined' === typeof String.prototype.w, + 'String.prototype helper disabled' + ); + } + ); } function test(given, expected, description) { @@ -18,6 +24,18 @@ function test(given, expected, description) { }); } -test('one two three', ['one', 'two', 'three'], `w('one two three') => ['one','two','three']`); -test('one two three', ['one', 'two', 'three'], `w('one two three') with extra spaces between words => ['one','two','three']`); -test('one\ttwo three', ['one', 'two', 'three'], `w('one two three') with tabs`); +test( + 'one two three', + ['one', 'two', 'three'], + `w('one two three') => ['one','two','three']` +); +test( + 'one two three', + ['one', 'two', 'three'], + `w('one two three') with extra spaces between words => ['one','two','three']` +); +test( + 'one\ttwo three', + ['one', 'two', 'three'], + `w('one two three') with tabs` +); diff --git a/packages/ember-template-compiler/lib/compat.js b/packages/ember-template-compiler/lib/compat.js index 89634cdc89b..9f13c89b700 100644 --- a/packages/ember-template-compiler/lib/compat.js +++ b/packages/ember-template-compiler/lib/compat.js @@ -3,8 +3,8 @@ import precompile from './system/precompile'; import compile from './system/compile'; import { registerPlugin } from './system/compile-options'; -let EmberHandlebars = Ember.Handlebars = Ember.Handlebars || {}; -let EmberHTMLBars = Ember.HTMLBars = Ember.HTMLBars || {}; +let EmberHandlebars = (Ember.Handlebars = Ember.Handlebars || {}); +let EmberHTMLBars = (Ember.HTMLBars = Ember.HTMLBars || {}); EmberHTMLBars.precompile = EmberHandlebars.precompile = precompile; EmberHTMLBars.compile = EmberHandlebars.compile = compile; diff --git a/packages/ember-template-compiler/lib/index.js b/packages/ember-template-compiler/lib/index.js index 8a77cc37d7f..9c85cc074db 100644 --- a/packages/ember-template-compiler/lib/index.js +++ b/packages/ember-template-compiler/lib/index.js @@ -4,9 +4,15 @@ import { ENV } from 'ember-environment'; import VERSION from 'ember/version'; // private API used by ember-cli-htmlbars to setup ENV and FEATURES -if (!_Ember.ENV) { _Ember.ENV = ENV; } -if (!_Ember.FEATURES) { _Ember.FEATURES = FLAGS.FEATURES; } -if (!_Ember.VERSION) { _Ember.VERSION = VERSION; } +if (!_Ember.ENV) { + _Ember.ENV = ENV; +} +if (!_Ember.FEATURES) { + _Ember.FEATURES = FLAGS.FEATURES; +} +if (!_Ember.VERSION) { + _Ember.VERSION = VERSION; +} export { _Ember }; diff --git a/packages/ember-template-compiler/lib/plugins/assert-if-helper-without-arguments.js b/packages/ember-template-compiler/lib/plugins/assert-if-helper-without-arguments.js index 97db659906f..0046365a267 100644 --- a/packages/ember-template-compiler/lib/plugins/assert-if-helper-without-arguments.js +++ b/packages/ember-template-compiler/lib/plugins/assert-if-helper-without-arguments.js @@ -10,19 +10,31 @@ export default function assertIfHelperWithoutArguments(env) { visitor: { BlockStatement(node) { if (isInvalidBlockIf(node)) { - assert(`${blockAssertMessage(node.path.original)} ${calculateLocationDisplay(moduleName, node.loc)}`); + assert( + `${blockAssertMessage( + node.path.original + )} ${calculateLocationDisplay(moduleName, node.loc)}` + ); } }, MustacheStatement(node) { if (isInvalidInlineIf(node)) { - assert(`${inlineAssertMessage(node.path.original)} ${calculateLocationDisplay(moduleName, node.loc)}`); + assert( + `${inlineAssertMessage( + node.path.original + )} ${calculateLocationDisplay(moduleName, node.loc)}` + ); } }, SubExpression(node) { if (isInvalidInlineIf(node)) { - assert(`${inlineAssertMessage(node.path.original)} ${calculateLocationDisplay(moduleName, node.loc)}`); + assert( + `${inlineAssertMessage( + node.path.original + )} ${calculateLocationDisplay(moduleName, node.loc)}` + ); } } } @@ -38,10 +50,14 @@ function inlineAssertMessage(original) { } function isInvalidInlineIf(node) { - return node.path.original === 'if' && (!node.params || node.params.length < 2 || node.params.length > 3); + return ( + node.path.original === 'if' && + (!node.params || node.params.length < 2 || node.params.length > 3) + ); } function isInvalidBlockIf(node) { - return node.path.original === 'if' && (!node.params || node.params.length !== 1); + return ( + node.path.original === 'if' && (!node.params || node.params.length !== 1) + ); } - diff --git a/packages/ember-template-compiler/lib/plugins/assert-input-helper-without-block.js b/packages/ember-template-compiler/lib/plugins/assert-input-helper-without-block.js index 7cdd29987e3..0213752bbe6 100644 --- a/packages/ember-template-compiler/lib/plugins/assert-input-helper-without-block.js +++ b/packages/ember-template-compiler/lib/plugins/assert-input-helper-without-block.js @@ -9,7 +9,9 @@ export default function errorOnInputWithContent(env) { visitor: { BlockStatement(node) { - if (node.path.original !== 'input') { return; } + if (node.path.original !== 'input') { + return; + } assert(assertMessage(moduleName, node)); } diff --git a/packages/ember-template-compiler/lib/plugins/assert-reserved-named-arguments.js b/packages/ember-template-compiler/lib/plugins/assert-reserved-named-arguments.js index e845edea595..00c6ad683cd 100644 --- a/packages/ember-template-compiler/lib/plugins/assert-reserved-named-arguments.js +++ b/packages/ember-template-compiler/lib/plugins/assert-reserved-named-arguments.js @@ -15,7 +15,12 @@ export default function assertReservedNamedArguments(env) { visitor: { PathExpression({ original, loc }) { if (isReserved(original)) { - assert(`${assertMessage(original)} ${calculateLocationDisplay(moduleName, loc)}`); + assert( + `${assertMessage(original)} ${calculateLocationDisplay( + moduleName, + loc + )}` + ); } } } diff --git a/packages/ember-template-compiler/lib/plugins/deprecate-render-model.js b/packages/ember-template-compiler/lib/plugins/deprecate-render-model.js index 25f836c3ca7..f686781921b 100644 --- a/packages/ember-template-compiler/lib/plugins/deprecate-render-model.js +++ b/packages/ember-template-compiler/lib/plugins/deprecate-render-model.js @@ -1,6 +1,5 @@ import { deprecate } from 'ember-debug'; -import calculateLocationDisplay from - '../system/calculate-location-display'; +import calculateLocationDisplay from '../system/calculate-location-display'; // Remove after 3.4 once _ENABLE_RENDER_SUPPORT flag is no longer needed. export default function deprecateRenderModel(env) { @@ -13,12 +12,15 @@ export default function deprecateRenderModel(env) { MustacheStatement(node) { if (node.path.original === 'render' && node.params.length > 1) { node.params.forEach(param => { - if (param.type !== 'PathExpression') { return; } + if (param.type !== 'PathExpression') { + return; + } deprecate(deprecationMessage(moduleName, node, param), false, { id: 'ember-template-compiler.deprecate-render-model', until: '3.0.0', - url: 'https://emberjs.com/deprecations/v2.x#toc_model-param-in-code-render-code-helper' + url: + 'https://emberjs.com/deprecations/v2.x#toc_model-param-in-code-render-code-helper' }); }); } @@ -34,6 +36,8 @@ function deprecationMessage(moduleName, node, param) { let original = `{{render "${componentName}" ${modelName}}}`; let preferred = `{{${componentName} model=${modelName}}}`; - return `Please refactor \`${original}\` to a component and invoke via` + - ` \`${preferred}\`. ${sourceInformation}`; + return ( + `Please refactor \`${original}\` to a component and invoke via` + + ` \`${preferred}\`. ${sourceInformation}` + ); } diff --git a/packages/ember-template-compiler/lib/plugins/deprecate-render.js b/packages/ember-template-compiler/lib/plugins/deprecate-render.js index 9a0ff429cc5..5e0f9c52332 100644 --- a/packages/ember-template-compiler/lib/plugins/deprecate-render.js +++ b/packages/ember-template-compiler/lib/plugins/deprecate-render.js @@ -10,16 +10,23 @@ export default function deprecateRender(env) { visitor: { MustacheStatement(node) { - if (node.path.original !== 'render') { return; } - if (node.params.length !== 1) { return; } - - each(node.params, (param) => { - if (param.type !== 'StringLiteral') { return; } + if (node.path.original !== 'render') { + return; + } + if (node.params.length !== 1) { + return; + } + + each(node.params, param => { + if (param.type !== 'StringLiteral') { + return; + } deprecate(deprecationMessage(moduleName, node), false, { id: 'ember-template-compiler.deprecate-render', until: '3.0.0', - url: 'https://emberjs.com/deprecations/v2.x#toc_code-render-code-helper' + url: + 'https://emberjs.com/deprecations/v2.x#toc_code-render-code-helper' }); }); } @@ -39,6 +46,8 @@ function deprecationMessage(moduleName, node) { let original = `{{render "${componentName}"}}`; let preferred = `{{${componentName}}}`; - return `Please refactor \`${original}\` to a component and invoke via` + - ` \`${preferred}\`. ${sourceInformation}`; + return ( + `Please refactor \`${original}\` to a component and invoke via` + + ` \`${preferred}\`. ${sourceInformation}` + ); } diff --git a/packages/ember-template-compiler/lib/plugins/transform-dot-component-invocation.js b/packages/ember-template-compiler/lib/plugins/transform-dot-component-invocation.js index 7edd10d42dc..c0ec62e8a55 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-dot-component-invocation.js +++ b/packages/ember-template-compiler/lib/plugins/transform-dot-component-invocation.js @@ -1,4 +1,3 @@ - /** Transforms dot invocation of closure components to be wrapped with the component helper. This allows for a more static invocation @@ -59,12 +58,12 @@ export default function transformDotComponentInvocation(env) { name: 'transform-dot-component-invocation', visitor: { - MustacheStatement: (node) => { + MustacheStatement: node => { if (isInlineInvocation(node.path, node.params, node.hash)) { wrapInComponent(node, b); } }, - BlockStatement: (node) => { + BlockStatement: node => { if (isMultipartPath(node.path)) { wrapInComponent(node, b); } @@ -73,7 +72,7 @@ export default function transformDotComponentInvocation(env) { }; } -function isMultipartPath(path) { +function isMultipartPath(path) { return path.parts && path.parts.length > 1; } diff --git a/packages/ember-template-compiler/lib/plugins/transform-each-in-into-each.js b/packages/ember-template-compiler/lib/plugins/transform-each-in-into-each.js index 50589934398..09cab12329d 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-each-in-into-each.js +++ b/packages/ember-template-compiler/lib/plugins/transform-each-in-into-each.js @@ -45,7 +45,14 @@ export default function transformEachInIntoEach(env) { node.program.blockParams = blockParams; - return b.block(b.path('each'), node.params, node.hash, node.program, node.inverse, node.loc); + return b.block( + b.path('each'), + node.params, + node.hash, + node.program, + node.inverse, + node.loc + ); } } } diff --git a/packages/ember-template-compiler/lib/plugins/transform-has-block-syntax.js b/packages/ember-template-compiler/lib/plugins/transform-has-block-syntax.js index 6ecb24246d8..e44eea6212e 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-has-block-syntax.js +++ b/packages/ember-template-compiler/lib/plugins/transform-has-block-syntax.js @@ -38,12 +38,22 @@ export default function transformHasBlockSyntax(env) { }, MustacheStatement(node) { if (TRANSFORMATIONS[node.path.original]) { - return b.mustache(b.path(TRANSFORMATIONS[node.path.original]), node.params, node.hash, null, node.loc); + return b.mustache( + b.path(TRANSFORMATIONS[node.path.original]), + node.params, + node.hash, + null, + node.loc + ); } }, SubExpression(node) { if (TRANSFORMATIONS[node.path.original]) { - return b.sexpr(b.path(TRANSFORMATIONS[node.path.original]), node.params, node.hash); + return b.sexpr( + b.path(TRANSFORMATIONS[node.path.original]), + node.params, + node.hash + ); } } } diff --git a/packages/ember-template-compiler/lib/plugins/transform-in-element.js b/packages/ember-template-compiler/lib/plugins/transform-in-element.js index 79f1de4dd17..9623f2c16f1 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-in-element.js +++ b/packages/ember-template-compiler/lib/plugins/transform-in-element.js @@ -64,7 +64,7 @@ export default function transformInElement(env) { // https://github.com/glimmerjs/glimmer-vm/blob/ba9b37d44b85fa1385eeeea71910ff5798198c8e/packages/%40glimmer/syntax/lib/parser/handlebars-node-visitors.ts#L340-L363 let hasNextSibling = false; let hash = node.hash; - hash.pairs.forEach((pair) => { + hash.pairs.forEach(pair => { if (pair.key === 'nextSibling') { hasNextSibling = true; } diff --git a/packages/ember-template-compiler/lib/plugins/transform-inline-link-to.js b/packages/ember-template-compiler/lib/plugins/transform-inline-link-to.js index 58534adac51..7db039ede64 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-inline-link-to.js +++ b/packages/ember-template-compiler/lib/plugins/transform-inline-link-to.js @@ -4,15 +4,15 @@ function buildProgram(b, content, loc) { function buildStatement(b, content, loc) { switch (content.type) { - case 'PathExpression': - return b.mustache(content, null, null, null, loc); + case 'PathExpression': + return b.mustache(content, null, null, null, loc); - case 'SubExpression': - return b.mustache(content.path, content.params, content.hash, null, loc); + case 'SubExpression': + return b.mustache(content.path, content.params, content.hash, null, loc); // The default case handles literals. - default: - return b.text(`${content.value}`, loc); + default: + return b.text(`${content.value}`, loc); } } @@ -29,7 +29,9 @@ export default function transformInlineLinkTo(env) { visitor: { MustacheStatement(node) { if (node.path.original === 'link-to') { - let content = node.escaped ? node.params[0] : unsafeHtml(b, node.params[0]); + let content = node.escaped + ? node.params[0] + : unsafeHtml(b, node.params[0]); return b.block( 'link-to', node.params.slice(1), diff --git a/packages/ember-template-compiler/lib/plugins/transform-input-type-syntax.js b/packages/ember-template-compiler/lib/plugins/transform-input-type-syntax.js index eb1458d5bbc..d0440b049a7 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-input-type-syntax.js +++ b/packages/ember-template-compiler/lib/plugins/transform-input-type-syntax.js @@ -53,6 +53,8 @@ function insertTypeHelperParameter(node, builders) { } } if (pair && pair.value.type !== 'StringLiteral') { - node.params.unshift(builders.sexpr('-input-type', [pair.value], null, pair.loc)); + node.params.unshift( + builders.sexpr('-input-type', [pair.value], null, pair.loc) + ); } } diff --git a/packages/ember-template-compiler/lib/plugins/transform-old-binding-syntax.js b/packages/ember-template-compiler/lib/plugins/transform-old-binding-syntax.js index 176445d89bf..d3e47f036b4 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-old-binding-syntax.js +++ b/packages/ember-template-compiler/lib/plugins/transform-old-binding-syntax.js @@ -27,17 +27,29 @@ function processHash(b, node, moduleName) { let sourceInformation = calculateLocationDisplay(moduleName, pair.loc); - if (key === 'classBinding') { return; } + if (key === 'classBinding') { + return; + } - assert(`Setting 'attributeBindings' via template helpers is not allowed ${sourceInformation}`, key !== 'attributeBindings'); + assert( + `Setting 'attributeBindings' via template helpers is not allowed ${sourceInformation}`, + key !== 'attributeBindings' + ); if (key.substr(-7) === 'Binding') { let newKey = key.slice(0, -7); deprecate( - `You're using legacy binding syntax: ${key}=${exprToString(value)} ${sourceInformation}. Please replace with ${newKey}=${value.original}`, + `You're using legacy binding syntax: ${key}=${exprToString( + value + )} ${sourceInformation}. Please replace with ${newKey}=${ + value.original + }`, false, - { id: 'ember-template-compiler.transform-old-binding-syntax', until: '3.0.0' } + { + id: 'ember-template-compiler.transform-old-binding-syntax', + until: '3.0.0' + } ); pair.key = newKey; @@ -50,7 +62,9 @@ function processHash(b, node, moduleName) { function exprToString(expr) { switch (expr.type) { - case 'StringLiteral': return `"${expr.original}"`; - case 'PathExpression': return expr.original; + case 'StringLiteral': + return `"${expr.original}"`; + case 'PathExpression': + return expr.original; } } diff --git a/packages/ember-template-compiler/lib/plugins/transform-old-class-binding-syntax.js b/packages/ember-template-compiler/lib/plugins/transform-old-class-binding-syntax.js index 71a87cf6a57..4cacc96ab48 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-old-class-binding-syntax.js +++ b/packages/ember-template-compiler/lib/plugins/transform-old-class-binding-syntax.js @@ -32,7 +32,9 @@ function process(b, node) { } }); - if (allOfTheMicrosyntaxes.length === 0) { return; } + if (allOfTheMicrosyntaxes.length === 0) { + return; + } let classValue = []; diff --git a/packages/ember-template-compiler/lib/plugins/transform-quoted-bindings-into-just-bindings.js b/packages/ember-template-compiler/lib/plugins/transform-quoted-bindings-into-just-bindings.js index d2fd7cb3f19..e9d7f43f333 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-quoted-bindings-into-just-bindings.js +++ b/packages/ember-template-compiler/lib/plugins/transform-quoted-bindings-into-just-bindings.js @@ -1,5 +1,4 @@ export default function transformQuotedBindingsIntoJustBindings(/* env */) { - return { name: 'transform-quoted-bindings-into-just-bindings', @@ -7,7 +6,9 @@ export default function transformQuotedBindingsIntoJustBindings(/* env */) { ElementNode(node) { let styleAttr = getStyleAttr(node); - if (!validStyleAttr(styleAttr)) { return; } + if (!validStyleAttr(styleAttr)) { + return; + } styleAttr.value = styleAttr.value.parts[0]; } @@ -16,13 +17,15 @@ export default function transformQuotedBindingsIntoJustBindings(/* env */) { } function validStyleAttr(attr) { - if (!attr) { return false; } + if (!attr) { + return false; + } let value = attr.value; - if (!value || - value.type !== 'ConcatStatement' || - value.parts.length !== 1) { return false; } + if (!value || value.type !== 'ConcatStatement' || value.parts.length !== 1) { + return false; + } let onlyPart = value.parts[0]; diff --git a/packages/ember-template-compiler/lib/plugins/transform-top-level-components.js b/packages/ember-template-compiler/lib/plugins/transform-top-level-components.js index 35aa907c2b3..c161f72e63f 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-top-level-components.js +++ b/packages/ember-template-compiler/lib/plugins/transform-top-level-components.js @@ -15,7 +15,9 @@ export default function transformTopLevelComponent(/* env */) { function hasSingleComponentNode(program, componentCallback) { let { loc, body } = program; - if (!loc || loc.start.line !== 1 || loc.start.column !== 0) { return; } + if (!loc || loc.start.line !== 1 || loc.start.column !== 0) { + return; + } let lastComponentNode; let nodeCount = 0; @@ -24,17 +26,23 @@ function hasSingleComponentNode(program, componentCallback) { let curr = body[i]; // text node with whitespace only - if (curr.type === 'TextNode' && /^[\s]*$/.test(curr.chars)) { continue; } + if (curr.type === 'TextNode' && /^[\s]*$/.test(curr.chars)) { + continue; + } // has multiple root elements if we've been here before - if (nodeCount++ > 0) { return false; } + if (nodeCount++ > 0) { + return false; + } if (curr.type === 'ComponentNode' || curr.type === 'ElementNode') { lastComponentNode = curr; } } - if (!lastComponentNode) { return; } + if (!lastComponentNode) { + return; + } if (lastComponentNode.type === 'ComponentNode') { componentCallback(lastComponentNode); diff --git a/packages/ember-template-compiler/lib/system/bootstrap.js b/packages/ember-template-compiler/lib/system/bootstrap.js index f23f5278b50..44124ebba32 100644 --- a/packages/ember-template-compiler/lib/system/bootstrap.js +++ b/packages/ember-template-compiler/lib/system/bootstrap.js @@ -33,7 +33,10 @@ function bootstrap({ context, hasTemplate, setTemplate }) { // Get the name of the script // First look for data-template-name attribute, then fall back to its // id if no name is found. - let templateName = script.getAttribute('data-template-name') || script.getAttribute('id') || 'application'; + let templateName = + script.getAttribute('data-template-name') || + script.getAttribute('id') || + 'application'; let template; template = compile(script.innerHTML, { diff --git a/packages/ember-template-compiler/lib/system/calculate-location-display.js b/packages/ember-template-compiler/lib/system/calculate-location-display.js index 8933677fd6a..2b0b3cdddea 100644 --- a/packages/ember-template-compiler/lib/system/calculate-location-display.js +++ b/packages/ember-template-compiler/lib/system/calculate-location-display.js @@ -2,7 +2,7 @@ export default function calculateLocationDisplay(moduleName, loc = {}) { let { column, line } = loc.start || {}; let moduleInfo = ''; if (moduleName) { - moduleInfo += `'${moduleName}' `; + moduleInfo += `'${moduleName}' `; } if (line !== undefined && column !== undefined) { diff --git a/packages/ember-template-compiler/lib/system/compile-options.js b/packages/ember-template-compiler/lib/system/compile-options.js index 28221c88fc1..cd39f34fdea 100644 --- a/packages/ember-template-compiler/lib/system/compile-options.js +++ b/packages/ember-template-compiler/lib/system/compile-options.js @@ -4,7 +4,7 @@ import PLUGINS from '../plugins/index'; let USER_PLUGINS = []; export default function compileOptions(_options) { - let options = assign({ meta: { } }, _options); + let options = assign({ meta: {} }, _options); // move `moduleName` into `meta` property if (options.moduleName) { @@ -16,8 +16,10 @@ export default function compileOptions(_options) { options.plugins = { ast: [...USER_PLUGINS, ...PLUGINS] }; } else { let potententialPugins = [...USER_PLUGINS, ...PLUGINS]; - let providedPlugins = options.plugins.ast.map(plugin => wrapLegacyPluginIfNeeded(plugin)); - let pluginsToAdd = potententialPugins.filter((plugin) => { + let providedPlugins = options.plugins.ast.map(plugin => + wrapLegacyPluginIfNeeded(plugin) + ); + let pluginsToAdd = potententialPugins.filter(plugin => { return options.plugins.ast.indexOf(plugin) === -1; }); options.plugins.ast = providedPlugins.concat(pluginsToAdd); @@ -29,7 +31,7 @@ export default function compileOptions(_options) { function wrapLegacyPluginIfNeeded(_plugin) { let plugin = _plugin; if (_plugin.prototype && _plugin.prototype.transform) { - plugin = (env) => { + plugin = env => { let pluginInstantiated = false; return { @@ -38,7 +40,6 @@ function wrapLegacyPluginIfNeeded(_plugin) { visitor: { Program(node) { if (!pluginInstantiated) { - pluginInstantiated = true; let plugin = new _plugin(env); @@ -59,7 +60,9 @@ function wrapLegacyPluginIfNeeded(_plugin) { export function registerPlugin(type, _plugin) { if (type !== 'ast') { - throw new Error(`Attempting to register ${_plugin} as "${type}" which is not a valid Glimmer plugin type.`); + throw new Error( + `Attempting to register ${_plugin} as "${type}" which is not a valid Glimmer plugin type.` + ); } for (let i = 0; i < USER_PLUGINS.length; i++) { @@ -76,8 +79,12 @@ export function registerPlugin(type, _plugin) { export function unregisterPlugin(type, PluginClass) { if (type !== 'ast') { - throw new Error(`Attempting to unregister ${PluginClass} as "${type}" which is not a valid Glimmer plugin type.`); + throw new Error( + `Attempting to unregister ${PluginClass} as "${type}" which is not a valid Glimmer plugin type.` + ); } - USER_PLUGINS = USER_PLUGINS.filter((plugin) => plugin !== PluginClass && plugin.__raw !== PluginClass); + USER_PLUGINS = USER_PLUGINS.filter( + plugin => plugin !== PluginClass && plugin.__raw !== PluginClass + ); } diff --git a/packages/ember-template-compiler/lib/system/compile.js b/packages/ember-template-compiler/lib/system/compile.js index e6530427e87..0f5b816c5d3 100644 --- a/packages/ember-template-compiler/lib/system/compile.js +++ b/packages/ember-template-compiler/lib/system/compile.js @@ -21,7 +21,9 @@ export default function compile(templateString, options) { } if (!template) { - throw new Error('Cannot call `compile` with only the template compiler loaded. Please load `ember.debug.js` or `ember.prod.js` prior to calling `compile`.'); + throw new Error( + 'Cannot call `compile` with only the template compiler loaded. Please load `ember.debug.js` or `ember.prod.js` prior to calling `compile`.' + ); } let precompiledTemplateString = precompile(templateString, options); diff --git a/packages/ember-template-compiler/lib/system/initializer.js b/packages/ember-template-compiler/lib/system/initializer.js index 551cc0ffb9b..71f603096f6 100644 --- a/packages/ember-template-compiler/lib/system/initializer.js +++ b/packages/ember-template-compiler/lib/system/initializer.js @@ -1,7 +1,11 @@ import require, { has } from 'require'; // Globals mode template compiler -if (has('ember-application') && has('ember-environment') && has('ember-glimmer')) { +if ( + has('ember-application') && + has('ember-environment') && + has('ember-glimmer') +) { let emberEnv = require('ember-environment'); let emberGlimmer = require('ember-glimmer'); let emberApp = require('ember-application'); @@ -9,7 +13,7 @@ if (has('ember-application') && has('ember-environment') && has('ember-glimmer') let { hasTemplate, setTemplate } = emberGlimmer; let { environment } = emberEnv; - let bootstrap = function() { }; + let bootstrap = function() {}; Application.initializer({ name: 'domTemplates', @@ -25,4 +29,3 @@ if (has('ember-application') && has('ember-environment') && has('ember-glimmer') } }); } - diff --git a/packages/ember-template-compiler/tests/plugins/assert-if-helper-without-arguments-test.js b/packages/ember-template-compiler/tests/plugins/assert-if-helper-without-arguments-test.js index 755e8433872..9076a14c9a6 100644 --- a/packages/ember-template-compiler/tests/plugins/assert-if-helper-without-arguments-test.js +++ b/packages/ember-template-compiler/tests/plugins/assert-if-helper-without-arguments-test.js @@ -1,50 +1,51 @@ import { compile } from '../../index'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('ember-template-compiler: assert-if-helper-without-argument', class extends AbstractTestCase { - [`@test block if helper expects one argument`]() { - expectAssertion(() => { - compile(`{{#if}}aVal{{/if}}`, { +moduleFor( + 'ember-template-compiler: assert-if-helper-without-argument', + class extends AbstractTestCase { + [`@test block if helper expects one argument`]() { + expectAssertion(() => { + compile(`{{#if}}aVal{{/if}}`, { + moduleName: 'baz/foo-bar' + }); + }, `#if requires a single argument. ('baz/foo-bar' @ L1:C0) `); + + expectAssertion(() => { + compile(`{{#if val1 val2}}aVal{{/if}}`, { + moduleName: 'baz/foo-bar' + }); + }, `#if requires a single argument. ('baz/foo-bar' @ L1:C0) `); + + expectAssertion(() => { + compile(`{{#if}}aVal{{/if}}`, { + moduleName: 'baz/foo-bar' + }); + }, `#if requires a single argument. ('baz/foo-bar' @ L1:C0) `); + } + + [`@test inline if helper expects between one and three arguments`]() { + expectAssertion(() => { + compile(`{{if}}`, { + moduleName: 'baz/foo-bar' + }); + }, `The inline form of the 'if' helper expects two or three arguments. ('baz/foo-bar' @ L1:C0) `); + + compile(`{{if foo bar baz}}`, { moduleName: 'baz/foo-bar' }); - }, `#if requires a single argument. ('baz/foo-bar' @ L1:C0) `); + } - expectAssertion(() => { - compile(`{{#if val1 val2}}aVal{{/if}}`, { - moduleName: 'baz/foo-bar' - }); - }, `#if requires a single argument. ('baz/foo-bar' @ L1:C0) `); - - expectAssertion(() => { - compile(`{{#if}}aVal{{/if}}`, { - moduleName: 'baz/foo-bar' - }); - }, `#if requires a single argument. ('baz/foo-bar' @ L1:C0) `); - } - - [`@test inline if helper expects between one and three arguments`]() { - expectAssertion(() => { - compile(`{{if}}`, { - moduleName: 'baz/foo-bar' - }); - }, `The inline form of the 'if' helper expects two or three arguments. ('baz/foo-bar' @ L1:C0) `); - - compile(`{{if foo bar baz}}`, { - moduleName: 'baz/foo-bar' - }); - } + ['@test subexpression if helper expects between one and three arguments']() { + expectAssertion(() => { + compile(`{{input foo=(if)}}`, { + moduleName: 'baz/foo-bar' + }); + }, `The inline form of the 'if' helper expects two or three arguments. ('baz/foo-bar' @ L1:C12) `); - ['@test subexpression if helper expects between one and three arguments']() { - expectAssertion(() => { - compile(`{{input foo=(if)}}`, { + compile(`{{some-thing foo=(if foo bar baz)}}`, { moduleName: 'baz/foo-bar' }); - }, `The inline form of the 'if' helper expects two or three arguments. ('baz/foo-bar' @ L1:C12) `); - - compile(`{{some-thing foo=(if foo bar baz)}}`, { - moduleName: 'baz/foo-bar' - }); + } } - -}); - +); diff --git a/packages/ember-template-compiler/tests/plugins/assert-input-helper-without-block-test.js b/packages/ember-template-compiler/tests/plugins/assert-input-helper-without-block-test.js index 51e5ef3316f..92b90cc12f8 100644 --- a/packages/ember-template-compiler/tests/plugins/assert-input-helper-without-block-test.js +++ b/packages/ember-template-compiler/tests/plugins/assert-input-helper-without-block-test.js @@ -1,16 +1,17 @@ import { compile } from '../../index'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('ember-template-compiler: assert-input-helper-without-block', class extends AbstractTestCase { - ['@test Using {{#input}}{{/input}} is not valid']() { +moduleFor( + 'ember-template-compiler: assert-input-helper-without-block', + class extends AbstractTestCase { + ['@test Using {{#input}}{{/input}} is not valid']() { + let expectedMessage = `The {{input}} helper cannot be used in block form. ('baz/foo-bar' @ L1:C0) `; - let expectedMessage = - `The {{input}} helper cannot be used in block form. ('baz/foo-bar' @ L1:C0) `; - - expectAssertion(() => { - compile('{{#input value="123"}}Completely invalid{{/input}}', { - moduleName: 'baz/foo-bar' - }); - }, expectedMessage); + expectAssertion(() => { + compile('{{#input value="123"}}Completely invalid{{/input}}', { + moduleName: 'baz/foo-bar' + }); + }, expectedMessage); + } } -}); +); diff --git a/packages/ember-template-compiler/tests/plugins/assert-reserved-named-arguments-test.js b/packages/ember-template-compiler/tests/plugins/assert-reserved-named-arguments-test.js index 5c766da1aa6..c72009e6b78 100644 --- a/packages/ember-template-compiler/tests/plugins/assert-reserved-named-arguments-test.js +++ b/packages/ember-template-compiler/tests/plugins/assert-reserved-named-arguments-test.js @@ -3,408 +3,414 @@ import { compile } from '../../index'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; if (EMBER_GLIMMER_NAMED_ARGUMENTS) { - moduleFor('ember-template-compiler: assert-reserved-named-arguments (EMBER_GLIMMER_NAMED_ARGUMENTS) ', class extends AbstractTestCase { - [`@test '@arguments' is reserved`]() { - expectAssertion(() => { - compile(`{{@arguments}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@arguments' is reserved. ('baz/foo-bar' @ L1:C2) `); - - expectAssertion(() => { - compile(`{{#if @arguments}}Yup{{/if}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@arguments' is reserved. ('baz/foo-bar' @ L1:C6) `); - - expectAssertion(() => { - compile(`{{input type=(if @arguments "bar" "baz")}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@arguments' is reserved. ('baz/foo-bar' @ L1:C17) `); + moduleFor( + 'ember-template-compiler: assert-reserved-named-arguments (EMBER_GLIMMER_NAMED_ARGUMENTS) ', + class extends AbstractTestCase { + [`@test '@arguments' is reserved`]() { + expectAssertion(() => { + compile(`{{@arguments}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@arguments' is reserved. ('baz/foo-bar' @ L1:C2) `); + + expectAssertion(() => { + compile(`{{#if @arguments}}Yup{{/if}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@arguments' is reserved. ('baz/foo-bar' @ L1:C6) `); + + expectAssertion(() => { + compile(`{{input type=(if @arguments "bar" "baz")}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@arguments' is reserved. ('baz/foo-bar' @ L1:C17) `); + } + + [`@test '@args' is reserved`]() { + expectAssertion(() => { + compile(`{{@args}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@args' is reserved. ('baz/foo-bar' @ L1:C2) `); + + expectAssertion(() => { + compile(`{{#if @args}}Yup{{/if}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@args' is reserved. ('baz/foo-bar' @ L1:C6) `); + + expectAssertion(() => { + compile(`{{input type=(if @args "bar" "baz")}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@args' is reserved. ('baz/foo-bar' @ L1:C17) `); + } + + [`@test '@block' is reserved`]() { + expectAssertion(() => { + compile(`{{@block}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@block' is reserved. ('baz/foo-bar' @ L1:C2) `); + + expectAssertion(() => { + compile(`{{#if @block}}Yup{{/if}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@block' is reserved. ('baz/foo-bar' @ L1:C6) `); + + expectAssertion(() => { + compile(`{{input type=(if @block "bar" "baz")}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@block' is reserved. ('baz/foo-bar' @ L1:C17) `); + } + + [`@test '@else' is reserved`]() { + expectAssertion(() => { + compile(`{{@else}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@else' is reserved. ('baz/foo-bar' @ L1:C2) `); + + expectAssertion(() => { + compile(`{{#if @else}}Yup{{/if}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@else' is reserved. ('baz/foo-bar' @ L1:C6) `); + + expectAssertion(() => { + compile(`{{input type=(if @else "bar" "baz")}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@else' is reserved. ('baz/foo-bar' @ L1:C17) `); + } + + // anything else that doesn't start with a lower case letter + [`@test '@Arguments' is reserved`]() { + expectAssertion(() => { + compile(`{{@Arguments}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@Arguments' is reserved. ('baz/foo-bar' @ L1:C2) `); + + expectAssertion(() => { + compile(`{{#if @Arguments}}Yup{{/if}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@Arguments' is reserved. ('baz/foo-bar' @ L1:C6) `); + + expectAssertion(() => { + compile(`{{input type=(if @Arguments "bar" "baz")}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@Arguments' is reserved. ('baz/foo-bar' @ L1:C17) `); + } + + [`@test '@Args' is reserved`]() { + expectAssertion(() => { + compile(`{{@Args}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@Args' is reserved. ('baz/foo-bar' @ L1:C2) `); + + expectAssertion(() => { + compile(`{{#if @Args}}Yup{{/if}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@Args' is reserved. ('baz/foo-bar' @ L1:C6) `); + + expectAssertion(() => { + compile(`{{input type=(if @Args "bar" "baz")}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@Args' is reserved. ('baz/foo-bar' @ L1:C17) `); + } + + [`@test '@FOO' is reserved`]() { + expectAssertion(() => { + compile(`{{@FOO}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@FOO' is reserved. ('baz/foo-bar' @ L1:C2) `); + + expectAssertion(() => { + compile(`{{#if @FOO}}Yup{{/if}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@FOO' is reserved. ('baz/foo-bar' @ L1:C6) `); + + expectAssertion(() => { + compile(`{{input type=(if @FOO "bar" "baz")}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@FOO' is reserved. ('baz/foo-bar' @ L1:C17) `); + } + + [`@test '@Foo' is reserved`]() { + expectAssertion(() => { + compile(`{{@Foo}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@Foo' is reserved. ('baz/foo-bar' @ L1:C2) `); + + expectAssertion(() => { + compile(`{{#if @Foo}}Yup{{/if}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@Foo' is reserved. ('baz/foo-bar' @ L1:C6) `); + + expectAssertion(() => { + compile(`{{input type=(if @Foo "bar" "baz")}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@Foo' is reserved. ('baz/foo-bar' @ L1:C17) `); + } + + [`@test '@.' is reserved`]() { + expectAssertion(() => { + compile(`{{@.}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@.' is reserved. ('baz/foo-bar' @ L1:C2) `); + + expectAssertion(() => { + compile(`{{#if @.}}Yup{{/if}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@.' is reserved. ('baz/foo-bar' @ L1:C6) `); + + expectAssertion(() => { + compile(`{{input type=(if @. "bar" "baz")}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@.' is reserved. ('baz/foo-bar' @ L1:C17) `); + } + + [`@test '@_' is reserved`]() { + expectAssertion(() => { + compile(`{{@_}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@_' is reserved. ('baz/foo-bar' @ L1:C2) `); + + expectAssertion(() => { + compile(`{{#if @_}}Yup{{/if}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@_' is reserved. ('baz/foo-bar' @ L1:C6) `); + + expectAssertion(() => { + compile(`{{input type=(if @_ "bar" "baz")}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@_' is reserved. ('baz/foo-bar' @ L1:C17) `); + } + + [`@test '@-' is reserved`]() { + expectAssertion(() => { + compile(`{{@-}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@-' is reserved. ('baz/foo-bar' @ L1:C2) `); + + expectAssertion(() => { + compile(`{{#if @-}}Yup{{/if}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@-' is reserved. ('baz/foo-bar' @ L1:C6) `); + + expectAssertion(() => { + compile(`{{input type=(if @- "bar" "baz")}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@-' is reserved. ('baz/foo-bar' @ L1:C17) `); + } + + [`@test '@$' is reserved`]() { + expectAssertion(() => { + compile(`{{@$}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@$' is reserved. ('baz/foo-bar' @ L1:C2) `); + + expectAssertion(() => { + compile(`{{#if @$}}Yup{{/if}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@$' is reserved. ('baz/foo-bar' @ L1:C6) `); + + expectAssertion(() => { + compile(`{{input type=(if @$ "bar" "baz")}}`, { + moduleName: 'baz/foo-bar' + }); + }, `'@$' is reserved. ('baz/foo-bar' @ L1:C17) `); + } + + [`@test '@' is de facto reserved (parse error)`](assert) { + assert.throws(() => { + compile('{{@}}', { + moduleName: 'baz/foo-bar' + }); + }, /Expecting 'ID'/); + + assert.throws(() => { + compile('{{#if @}}Yup{{/if}}', { + moduleName: 'baz/foo-bar' + }); + }, /Expecting 'ID'/); + + assert.throws(() => { + compile('{{input type=(if @ "bar" "baz")}}', { + moduleName: 'baz/foo-bar' + }); + }, /Expecting 'ID'/); + } + + [`@test '@0' is de facto reserved (parse error)`](assert) { + assert.throws(() => { + compile('{{@0}}', { + moduleName: 'baz/foo-bar' + }); + }, /Expecting 'ID'/); + + assert.throws(() => { + compile('{{#if @0}}Yup{{/if}}', { + moduleName: 'baz/foo-bar' + }); + }, /Expecting 'ID'/); + + assert.throws(() => { + compile('{{input type=(if @0 "bar" "baz")}}', { + moduleName: 'baz/foo-bar' + }); + }, /Expecting 'ID'/); + } + + [`@test '@1' is de facto reserved (parse error)`](assert) { + assert.throws(() => { + compile('{{@1}}', { + moduleName: 'baz/foo-bar' + }); + }, /Expecting 'ID'/); + + assert.throws(() => { + compile('{{#if @1}}Yup{{/if}}', { + moduleName: 'baz/foo-bar' + }); + }, /Expecting 'ID'/); + + assert.throws(() => { + compile('{{input type=(if @1 "bar" "baz")}}', { + moduleName: 'baz/foo-bar' + }); + }, /Expecting 'ID'/); + } + + [`@test '@2' is de facto reserved (parse error)`](assert) { + assert.throws(() => { + compile('{{@2}}', { + moduleName: 'baz/foo-bar' + }); + }, /Expecting 'ID'/); + + assert.throws(() => { + compile('{{#if @2}}Yup{{/if}}', { + moduleName: 'baz/foo-bar' + }); + }, /Expecting 'ID'/); + + assert.throws(() => { + compile('{{input type=(if @2 "bar" "baz")}}', { + moduleName: 'baz/foo-bar' + }); + }, /Expecting 'ID'/); + } + + [`@test '@@' is de facto reserved (parse error)`](assert) { + assert.throws(() => { + compile('{{@@}}', { + moduleName: 'baz/foo-bar' + }); + }, /Expecting 'ID'/); + + assert.throws(() => { + compile('{{#if @@}}Yup{{/if}}', { + moduleName: 'baz/foo-bar' + }); + }, /Expecting 'ID'/); + + assert.throws(() => { + compile('{{input type=(if @@ "bar" "baz")}}', { + moduleName: 'baz/foo-bar' + }); + }, /Expecting 'ID'/); + } + + [`@test '@=' is de facto reserved (parse error)`](assert) { + assert.throws(() => { + compile('{{@=}}', { + moduleName: 'baz/foo-bar' + }); + }, /Expecting 'ID'/); + + assert.throws(() => { + compile('{{#if @=}}Yup{{/if}}', { + moduleName: 'baz/foo-bar' + }); + }, /Expecting 'ID'/); + + assert.throws(() => { + compile('{{input type=(if @= "bar" "baz")}}', { + moduleName: 'baz/foo-bar' + }); + }, /Expecting 'ID'/); + } + + [`@test '@!' is de facto reserved (parse error)`](assert) { + assert.throws(() => { + compile('{{@!}}', { + moduleName: 'baz/foo-bar' + }); + }, /Expecting 'ID'/); + + assert.throws(() => { + compile('{{#if @!}}Yup{{/if}}', { + moduleName: 'baz/foo-bar' + }); + }, /Expecting 'ID'/); + + assert.throws(() => { + compile('{{input type=(if @! "bar" "baz")}}', { + moduleName: 'baz/foo-bar' + }); + }, /Expecting 'ID'/); + } } - - [`@test '@args' is reserved`]() { - expectAssertion(() => { - compile(`{{@args}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@args' is reserved. ('baz/foo-bar' @ L1:C2) `); - - expectAssertion(() => { - compile(`{{#if @args}}Yup{{/if}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@args' is reserved. ('baz/foo-bar' @ L1:C6) `); - - expectAssertion(() => { - compile(`{{input type=(if @args "bar" "baz")}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@args' is reserved. ('baz/foo-bar' @ L1:C17) `); - } - - [`@test '@block' is reserved`]() { - expectAssertion(() => { - compile(`{{@block}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@block' is reserved. ('baz/foo-bar' @ L1:C2) `); - - expectAssertion(() => { - compile(`{{#if @block}}Yup{{/if}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@block' is reserved. ('baz/foo-bar' @ L1:C6) `); - - expectAssertion(() => { - compile(`{{input type=(if @block "bar" "baz")}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@block' is reserved. ('baz/foo-bar' @ L1:C17) `); - } - - [`@test '@else' is reserved`]() { - expectAssertion(() => { - compile(`{{@else}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@else' is reserved. ('baz/foo-bar' @ L1:C2) `); - - expectAssertion(() => { - compile(`{{#if @else}}Yup{{/if}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@else' is reserved. ('baz/foo-bar' @ L1:C6) `); - - expectAssertion(() => { - compile(`{{input type=(if @else "bar" "baz")}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@else' is reserved. ('baz/foo-bar' @ L1:C17) `); - } - - // anything else that doesn't start with a lower case letter - [`@test '@Arguments' is reserved`]() { - expectAssertion(() => { - compile(`{{@Arguments}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@Arguments' is reserved. ('baz/foo-bar' @ L1:C2) `); - - expectAssertion(() => { - compile(`{{#if @Arguments}}Yup{{/if}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@Arguments' is reserved. ('baz/foo-bar' @ L1:C6) `); - - expectAssertion(() => { - compile(`{{input type=(if @Arguments "bar" "baz")}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@Arguments' is reserved. ('baz/foo-bar' @ L1:C17) `); - } - - [`@test '@Args' is reserved`]() { - expectAssertion(() => { - compile(`{{@Args}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@Args' is reserved. ('baz/foo-bar' @ L1:C2) `); - - expectAssertion(() => { - compile(`{{#if @Args}}Yup{{/if}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@Args' is reserved. ('baz/foo-bar' @ L1:C6) `); - - expectAssertion(() => { - compile(`{{input type=(if @Args "bar" "baz")}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@Args' is reserved. ('baz/foo-bar' @ L1:C17) `); - } - - [`@test '@FOO' is reserved`]() { - expectAssertion(() => { - compile(`{{@FOO}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@FOO' is reserved. ('baz/foo-bar' @ L1:C2) `); - - expectAssertion(() => { - compile(`{{#if @FOO}}Yup{{/if}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@FOO' is reserved. ('baz/foo-bar' @ L1:C6) `); - - expectAssertion(() => { - compile(`{{input type=(if @FOO "bar" "baz")}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@FOO' is reserved. ('baz/foo-bar' @ L1:C17) `); - } - - [`@test '@Foo' is reserved`]() { - expectAssertion(() => { - compile(`{{@Foo}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@Foo' is reserved. ('baz/foo-bar' @ L1:C2) `); - - expectAssertion(() => { - compile(`{{#if @Foo}}Yup{{/if}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@Foo' is reserved. ('baz/foo-bar' @ L1:C6) `); - - expectAssertion(() => { - compile(`{{input type=(if @Foo "bar" "baz")}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@Foo' is reserved. ('baz/foo-bar' @ L1:C17) `); - } - - [`@test '@.' is reserved`]() { - expectAssertion(() => { - compile(`{{@.}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@.' is reserved. ('baz/foo-bar' @ L1:C2) `); - - expectAssertion(() => { - compile(`{{#if @.}}Yup{{/if}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@.' is reserved. ('baz/foo-bar' @ L1:C6) `); - - expectAssertion(() => { - compile(`{{input type=(if @. "bar" "baz")}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@.' is reserved. ('baz/foo-bar' @ L1:C17) `); - } - - [`@test '@_' is reserved`]() { - expectAssertion(() => { - compile(`{{@_}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@_' is reserved. ('baz/foo-bar' @ L1:C2) `); - - expectAssertion(() => { - compile(`{{#if @_}}Yup{{/if}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@_' is reserved. ('baz/foo-bar' @ L1:C6) `); - - expectAssertion(() => { - compile(`{{input type=(if @_ "bar" "baz")}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@_' is reserved. ('baz/foo-bar' @ L1:C17) `); - } - - [`@test '@-' is reserved`]() { - expectAssertion(() => { - compile(`{{@-}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@-' is reserved. ('baz/foo-bar' @ L1:C2) `); - - expectAssertion(() => { - compile(`{{#if @-}}Yup{{/if}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@-' is reserved. ('baz/foo-bar' @ L1:C6) `); - - expectAssertion(() => { - compile(`{{input type=(if @- "bar" "baz")}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@-' is reserved. ('baz/foo-bar' @ L1:C17) `); - } - - [`@test '@$' is reserved`]() { - expectAssertion(() => { - compile(`{{@$}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@$' is reserved. ('baz/foo-bar' @ L1:C2) `); - - expectAssertion(() => { - compile(`{{#if @$}}Yup{{/if}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@$' is reserved. ('baz/foo-bar' @ L1:C6) `); - - expectAssertion(() => { - compile(`{{input type=(if @$ "bar" "baz")}}`, { - moduleName: 'baz/foo-bar' - }); - }, `'@$' is reserved. ('baz/foo-bar' @ L1:C17) `); - } - - [`@test '@' is de facto reserved (parse error)`](assert) { - assert.throws(() => { - compile('{{@}}', { - moduleName: 'baz/foo-bar' - }); - }, /Expecting 'ID'/); - - assert.throws(() => { - compile('{{#if @}}Yup{{/if}}', { - moduleName: 'baz/foo-bar' - }); - }, /Expecting 'ID'/); - - assert.throws(() => { - compile('{{input type=(if @ "bar" "baz")}}', { - moduleName: 'baz/foo-bar' - }); - }, /Expecting 'ID'/); - } - - [`@test '@0' is de facto reserved (parse error)`](assert) { - assert.throws(() => { - compile('{{@0}}', { - moduleName: 'baz/foo-bar' - }); - }, /Expecting 'ID'/); - - assert.throws(() => { - compile('{{#if @0}}Yup{{/if}}', { - moduleName: 'baz/foo-bar' - }); - }, /Expecting 'ID'/); - - assert.throws(() => { - compile('{{input type=(if @0 "bar" "baz")}}', { - moduleName: 'baz/foo-bar' - }); - }, /Expecting 'ID'/); - } - - [`@test '@1' is de facto reserved (parse error)`](assert) { - assert.throws(() => { - compile('{{@1}}', { - moduleName: 'baz/foo-bar' - }); - }, /Expecting 'ID'/); - - assert.throws(() => { - compile('{{#if @1}}Yup{{/if}}', { - moduleName: 'baz/foo-bar' - }); - }, /Expecting 'ID'/); - - assert.throws(() => { - compile('{{input type=(if @1 "bar" "baz")}}', { - moduleName: 'baz/foo-bar' - }); - }, /Expecting 'ID'/); - } - - [`@test '@2' is de facto reserved (parse error)`](assert) { - assert.throws(() => { - compile('{{@2}}', { - moduleName: 'baz/foo-bar' - }); - }, /Expecting 'ID'/); - - assert.throws(() => { - compile('{{#if @2}}Yup{{/if}}', { - moduleName: 'baz/foo-bar' - }); - }, /Expecting 'ID'/); - - assert.throws(() => { - compile('{{input type=(if @2 "bar" "baz")}}', { - moduleName: 'baz/foo-bar' - }); - }, /Expecting 'ID'/); - } - - [`@test '@@' is de facto reserved (parse error)`](assert) { - assert.throws(() => { - compile('{{@@}}', { - moduleName: 'baz/foo-bar' - }); - }, /Expecting 'ID'/); - - assert.throws(() => { - compile('{{#if @@}}Yup{{/if}}', { - moduleName: 'baz/foo-bar' - }); - }, /Expecting 'ID'/); - - assert.throws(() => { - compile('{{input type=(if @@ "bar" "baz")}}', { - moduleName: 'baz/foo-bar' - }); - }, /Expecting 'ID'/); - } - - [`@test '@=' is de facto reserved (parse error)`](assert) { - assert.throws(() => { - compile('{{@=}}', { - moduleName: 'baz/foo-bar' - }); - }, /Expecting 'ID'/); - - assert.throws(() => { - compile('{{#if @=}}Yup{{/if}}', { - moduleName: 'baz/foo-bar' - }); - }, /Expecting 'ID'/); - - assert.throws(() => { - compile('{{input type=(if @= "bar" "baz")}}', { - moduleName: 'baz/foo-bar' - }); - }, /Expecting 'ID'/); - } - - [`@test '@!' is de facto reserved (parse error)`](assert) { - assert.throws(() => { - compile('{{@!}}', { - moduleName: 'baz/foo-bar' - }); - }, /Expecting 'ID'/); - - assert.throws(() => { - compile('{{#if @!}}Yup{{/if}}', { - moduleName: 'baz/foo-bar' - }); - }, /Expecting 'ID'/); - - assert.throws(() => { - compile('{{input type=(if @! "bar" "baz")}}', { - moduleName: 'baz/foo-bar' - }); - }, /Expecting 'ID'/); - } - }); + ); } else { - moduleFor('ember-template-compiler: assert-reserved-named-arguments', class extends AbstractTestCase { - ['@test Paths beginning with @ are not valid']() { - expectAssertion(() => { - compile('{{@foo}}', { - moduleName: 'baz/foo-bar' - }); - }, `'@foo' is not a valid path. ('baz/foo-bar' @ L1:C2) `); - - expectAssertion(() => { - compile('{{#if @foo}}Yup{{/if}}', { - moduleName: 'baz/foo-bar' - }); - }, `'@foo' is not a valid path. ('baz/foo-bar' @ L1:C6) `); - - expectAssertion(() => { - compile('{{input type=(if @foo "bar" "baz")}}', { - moduleName: 'baz/foo-bar' - }); - }, `'@foo' is not a valid path. ('baz/foo-bar' @ L1:C17) `); + moduleFor( + 'ember-template-compiler: assert-reserved-named-arguments', + class extends AbstractTestCase { + ['@test Paths beginning with @ are not valid']() { + expectAssertion(() => { + compile('{{@foo}}', { + moduleName: 'baz/foo-bar' + }); + }, `'@foo' is not a valid path. ('baz/foo-bar' @ L1:C2) `); + + expectAssertion(() => { + compile('{{#if @foo}}Yup{{/if}}', { + moduleName: 'baz/foo-bar' + }); + }, `'@foo' is not a valid path. ('baz/foo-bar' @ L1:C6) `); + + expectAssertion(() => { + compile('{{input type=(if @foo "bar" "baz")}}', { + moduleName: 'baz/foo-bar' + }); + }, `'@foo' is not a valid path. ('baz/foo-bar' @ L1:C17) `); + } } - }); + ); } diff --git a/packages/ember-template-compiler/tests/plugins/deprecate-render-model-test.js b/packages/ember-template-compiler/tests/plugins/deprecate-render-model-test.js index c4ce8466a74..dc19ab55b6b 100644 --- a/packages/ember-template-compiler/tests/plugins/deprecate-render-model-test.js +++ b/packages/ember-template-compiler/tests/plugins/deprecate-render-model-test.js @@ -1,17 +1,19 @@ import { compile } from '../../index'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('ember-template-compiler: deprecate-model-render', class extends AbstractTestCase { - ['@test Using `{{render` with model provides a deprecation']() { +moduleFor( + 'ember-template-compiler: deprecate-model-render', + class extends AbstractTestCase { + ['@test Using `{{render` with model provides a deprecation']() { + let expectedMessage = + `Please refactor \`{{render "foo-bar" coolModel}}\` to a component and` + + ` invoke via \`{{foo-bar model=coolModel}}\`. ('baz/foo-bar' @ L1:C0) `; - let expectedMessage = - `Please refactor \`{{render "foo-bar" coolModel}}\` to a component and` + - ` invoke via \`{{foo-bar model=coolModel}}\`. ('baz/foo-bar' @ L1:C0) `; - - expectDeprecation(() => { - compile('{{render "foo-bar" coolModel}}', { - moduleName: 'baz/foo-bar' - }); - }, expectedMessage); + expectDeprecation(() => { + compile('{{render "foo-bar" coolModel}}', { + moduleName: 'baz/foo-bar' + }); + }, expectedMessage); + } } -}); +); diff --git a/packages/ember-template-compiler/tests/plugins/deprecate-render-test.js b/packages/ember-template-compiler/tests/plugins/deprecate-render-test.js index e253860d6a3..2985a1334f5 100644 --- a/packages/ember-template-compiler/tests/plugins/deprecate-render-test.js +++ b/packages/ember-template-compiler/tests/plugins/deprecate-render-test.js @@ -1,17 +1,19 @@ import { compile } from '../../index'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('ember-template-compiler: deprecate-render', class extends AbstractTestCase { - ['@test Using `{{render` without a model provides a deprecation']() { +moduleFor( + 'ember-template-compiler: deprecate-render', + class extends AbstractTestCase { + ['@test Using `{{render` without a model provides a deprecation']() { + let expectedMessage = + `Please refactor \`{{render "foo-bar"}}\` to a component and` + + ` invoke via \`{{foo-bar}}\`. ('baz/foo-bar' @ L1:C0) `; - let expectedMessage = - `Please refactor \`{{render "foo-bar"}}\` to a component and` + - ` invoke via \`{{foo-bar}}\`. ('baz/foo-bar' @ L1:C0) `; - - expectDeprecation(() => { - compile('{{render "foo-bar"}}', { - moduleName: 'baz/foo-bar' - }); - }, expectedMessage); + expectDeprecation(() => { + compile('{{render "foo-bar"}}', { + moduleName: 'baz/foo-bar' + }); + }, expectedMessage); + } } -}); +); diff --git a/packages/ember-template-compiler/tests/plugins/transform-dot-component-invocation-test.js b/packages/ember-template-compiler/tests/plugins/transform-dot-component-invocation-test.js index ee87fe2963b..f633e9be316 100644 --- a/packages/ember-template-compiler/tests/plugins/transform-dot-component-invocation-test.js +++ b/packages/ember-template-compiler/tests/plugins/transform-dot-component-invocation-test.js @@ -1,25 +1,27 @@ import { compile } from '../../index'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('ember-template-compiler: transforms dot component invocation', class extends AbstractTestCase { - ['@test Does not throw a compiler error for path components'](assert) { - assert.expect(0); - - [ - '{{this.modal open}}', - '{{this.modal isOpen=true}}', - '{{#this.modal}}Woot{{/this.modal}}', - '{{c.modal open}}', - '{{c.modal isOpen=true}}', - '{{#c.modal}}Woot{{/c.modal}}', - '{{#my-component as |c|}}{{c.a name="Chad"}}{{/my-component}}', - '{{#my-component as |c|}}{{c.a "Chad"}}{{/my-component}}', - '{{#my-component as |c|}}{{#c.a}}{{/c.a}}{{/my-component}}', - '', // GH#15740 - '' // GH#15217 - ].forEach((layout, i) => { - compile(layout, { moduleName: `example-${i}` }); - }); +moduleFor( + 'ember-template-compiler: transforms dot component invocation', + class extends AbstractTestCase { + ['@test Does not throw a compiler error for path components'](assert) { + assert.expect(0); + [ + '{{this.modal open}}', + '{{this.modal isOpen=true}}', + '{{#this.modal}}Woot{{/this.modal}}', + '{{c.modal open}}', + '{{c.modal isOpen=true}}', + '{{#c.modal}}Woot{{/c.modal}}', + '{{#my-component as |c|}}{{c.a name="Chad"}}{{/my-component}}', + '{{#my-component as |c|}}{{c.a "Chad"}}{{/my-component}}', + '{{#my-component as |c|}}{{#c.a}}{{/c.a}}{{/my-component}}', + '', // GH#15740 + '' // GH#15217 + ].forEach((layout, i) => { + compile(layout, { moduleName: `example-${i}` }); + }); + } } -}); +); diff --git a/packages/ember-template-compiler/tests/plugins/transform-inline-link-to-test.js b/packages/ember-template-compiler/tests/plugins/transform-inline-link-to-test.js index 6758daa759e..d043f5805a1 100644 --- a/packages/ember-template-compiler/tests/plugins/transform-inline-link-to-test.js +++ b/packages/ember-template-compiler/tests/plugins/transform-inline-link-to-test.js @@ -1,12 +1,15 @@ import { compile } from '../../index'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('ember-template-compiler: inline-link-to', class extends AbstractTestCase { - ['@test Can transform an inline {{link-to}} without error'](assert) { - assert.expect(0); +moduleFor( + 'ember-template-compiler: inline-link-to', + class extends AbstractTestCase { + ['@test Can transform an inline {{link-to}} without error'](assert) { + assert.expect(0); - compile(`{{link-to 'foo' 'index'}}`, { - moduleName: 'foo/bar/baz' - }); + compile(`{{link-to 'foo' 'index'}}`, { + moduleName: 'foo/bar/baz' + }); + } } -}); +); diff --git a/packages/ember-template-compiler/tests/plugins/transform-input-type-syntax-test.js b/packages/ember-template-compiler/tests/plugins/transform-input-type-syntax-test.js index e4d29e4754b..f627a85b60f 100644 --- a/packages/ember-template-compiler/tests/plugins/transform-input-type-syntax-test.js +++ b/packages/ember-template-compiler/tests/plugins/transform-input-type-syntax-test.js @@ -1,22 +1,31 @@ import { compile } from '../../index'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; -moduleFor('ember-template-compiler: input type syntax', class extends AbstractTestCase { - ['@test Can compile an {{input}} helper that has a sub-expression value as its type'](assert) { - assert.expect(0); +moduleFor( + 'ember-template-compiler: input type syntax', + class extends AbstractTestCase { + ['@test Can compile an {{input}} helper that has a sub-expression value as its type']( + assert + ) { + assert.expect(0); - compile(`{{input type=(if true 'password' 'text')}}`); - } + compile(`{{input type=(if true 'password' 'text')}}`); + } - ['@test Can compile an {{input}} helper with a string literal type'](assert) { - assert.expect(0); + ['@test Can compile an {{input}} helper with a string literal type']( + assert + ) { + assert.expect(0); - compile(`{{input type='text'}}`); - } + compile(`{{input type='text'}}`); + } - ['@test Can compile an {{input}} helper with a type stored in a var'](assert) { - assert.expect(0); + ['@test Can compile an {{input}} helper with a type stored in a var']( + assert + ) { + assert.expect(0); - compile(`{{input type=_type}}`); + compile(`{{input type=_type}}`); + } } -}); +); diff --git a/packages/ember-template-compiler/tests/system/bootstrap-test.js b/packages/ember-template-compiler/tests/system/bootstrap-test.js index 94c7412474b..89e52c854f4 100644 --- a/packages/ember-template-compiler/tests/system/bootstrap-test.js +++ b/packages/ember-template-compiler/tests/system/bootstrap-test.js @@ -28,100 +28,145 @@ function checkTemplate(templateName, assert) { let owner = buildOwner(); owner.register('template:-top-level', template); - owner.register('component:-top-level', Component.extend({ - layoutName: '-top-level', - firstName: 'Tobias', - drug: 'teamocil' - })); + owner.register( + 'component:-top-level', + Component.extend({ + layoutName: '-top-level', + firstName: 'Tobias', + drug: 'teamocil' + }) + ); component = owner.lookup('component:-top-level'); runAppend(component); - assert.equal(qunitFixture.textContent.trim(), 'Tobias takes teamocil', 'template works'); + assert.equal( + qunitFixture.textContent.trim(), + 'Tobias takes teamocil', + 'template works' + ); runDestroy(component); } -moduleFor('ember-templates: bootstrap', class extends AbstractTestCase { - constructor() { - super(); - - fixture = document.getElementById('qunit-fixture'); - } - - teardown() { - setTemplates({}); - runDestroy(component); - } - - ['@test template with data-template-name should add a new template to Ember.TEMPLATES'](assert) { - fixture.innerHTML = ''; - - checkTemplate('funkyTemplate', assert); - } - - ['@test template with id instead of data-template-name should add a new template to Ember.TEMPLATES'](assert) { - fixture.innerHTML = ''; - - checkTemplate('funkyTemplate', assert); - } - - ['@test template without data-template-name or id should default to application'](assert) { - fixture.innerHTML = ''; - - checkTemplate('application', assert); - } - - // Add this test case, only for typeof Handlebars === 'object'; - [`${typeof Handlebars === 'object' ? '@test' : '@skip'} template with type text/x-raw-handlebars should be parsed`](assert) { - fixture.innerHTML = ''; - - run(() => bootstrap({ context: fixture, hasTemplate, setTemplate })); - - let template = getTemplate('funkyTemplate'); - - assert.ok(template, 'template with name funkyTemplate available'); - - // This won't even work with Ember templates - assert.equal(template({ name: 'Tobias' }).trim(), 'Tobias'); - } - - ['@test duplicated default application templates should throw exception'](assert) { - fixture.innerHTML = ''; - - assert.throws(() => bootstrap({ context: fixture, hasTemplate, setTemplate }), - /Template named "[^"]+" already exists\./, - 'duplicate templates should not be allowed'); - } - - ['@test default default application template and id application template present should throw exception'](assert) { - fixture.innerHTML = ''; - - assert.throws(() => bootstrap({ context: fixture, hasTemplate, setTemplate }), - /Template named "[^"]+" already exists\./, - 'duplicate templates should not be allowed'); - } - - ['@test default application template and data-template-name application template present should throw exception'](assert) { - fixture.innerHTML = ''; - - assert.throws(() => bootstrap({ context: fixture, hasTemplate, setTemplate }), - /Template named "[^"]+" already exists\./, - 'duplicate templates should not be allowed'); - } - - ['@test duplicated template id should throw exception'](assert) { - fixture.innerHTML = ''; - - assert.throws(() => bootstrap({ context: fixture, hasTemplate, setTemplate }), - /Template named "[^"]+" already exists\./, - 'duplicate templates should not be allowed'); - } - - ['@test duplicated template data-template-name should throw exception'](assert) { - fixture.innerHTML = ''; - - assert.throws(() => bootstrap({ context: fixture, hasTemplate, setTemplate }), - /Template named "[^"]+" already exists\./, - 'duplicate templates should not be allowed'); +moduleFor( + 'ember-templates: bootstrap', + class extends AbstractTestCase { + constructor() { + super(); + + fixture = document.getElementById('qunit-fixture'); + } + + teardown() { + setTemplates({}); + runDestroy(component); + } + + ['@test template with data-template-name should add a new template to Ember.TEMPLATES']( + assert + ) { + fixture.innerHTML = + ''; + + checkTemplate('funkyTemplate', assert); + } + + ['@test template with id instead of data-template-name should add a new template to Ember.TEMPLATES']( + assert + ) { + fixture.innerHTML = + ''; + + checkTemplate('funkyTemplate', assert); + } + + ['@test template without data-template-name or id should default to application']( + assert + ) { + fixture.innerHTML = + ''; + + checkTemplate('application', assert); + } + + // Add this test case, only for typeof Handlebars === 'object'; + [`${ + typeof Handlebars === 'object' ? '@test' : '@skip' + } template with type text/x-raw-handlebars should be parsed`](assert) { + fixture.innerHTML = + ''; + + run(() => bootstrap({ context: fixture, hasTemplate, setTemplate })); + + let template = getTemplate('funkyTemplate'); + + assert.ok(template, 'template with name funkyTemplate available'); + + // This won't even work with Ember templates + assert.equal(template({ name: 'Tobias' }).trim(), 'Tobias'); + } + + ['@test duplicated default application templates should throw exception']( + assert + ) { + fixture.innerHTML = + ''; + + assert.throws( + () => bootstrap({ context: fixture, hasTemplate, setTemplate }), + /Template named "[^"]+" already exists\./, + 'duplicate templates should not be allowed' + ); + } + + ['@test default default application template and id application template present should throw exception']( + assert + ) { + fixture.innerHTML = + ''; + + assert.throws( + () => bootstrap({ context: fixture, hasTemplate, setTemplate }), + /Template named "[^"]+" already exists\./, + 'duplicate templates should not be allowed' + ); + } + + ['@test default application template and data-template-name application template present should throw exception']( + assert + ) { + fixture.innerHTML = + ''; + + assert.throws( + () => bootstrap({ context: fixture, hasTemplate, setTemplate }), + /Template named "[^"]+" already exists\./, + 'duplicate templates should not be allowed' + ); + } + + ['@test duplicated template id should throw exception'](assert) { + fixture.innerHTML = + ''; + + assert.throws( + () => bootstrap({ context: fixture, hasTemplate, setTemplate }), + /Template named "[^"]+" already exists\./, + 'duplicate templates should not be allowed' + ); + } + + ['@test duplicated template data-template-name should throw exception']( + assert + ) { + fixture.innerHTML = + ''; + + assert.throws( + () => bootstrap({ context: fixture, hasTemplate, setTemplate }), + /Template named "[^"]+" already exists\./, + 'duplicate templates should not be allowed' + ); + } } -}); +); diff --git a/packages/ember-template-compiler/tests/system/compile_options_test.js b/packages/ember-template-compiler/tests/system/compile_options_test.js index aaa423b010c..1c0dcb8574d 100644 --- a/packages/ember-template-compiler/tests/system/compile_options_test.js +++ b/packages/ember-template-compiler/tests/system/compile_options_test.js @@ -1,22 +1,35 @@ -import { compile, compileOptions, defaultPlugins, registerPlugin, unregisterPlugin } from '../../index'; -import { moduleFor, AbstractTestCase, RenderingTestCase } from 'internal-test-helpers'; - -moduleFor('ember-template-compiler: default compile options', class extends AbstractTestCase { - ['@test default options are a new copy'](assert) { - assert.notEqual(compileOptions(), compileOptions()); - } +import { + compile, + compileOptions, + defaultPlugins, + registerPlugin, + unregisterPlugin +} from '../../index'; +import { + moduleFor, + AbstractTestCase, + RenderingTestCase +} from 'internal-test-helpers'; + +moduleFor( + 'ember-template-compiler: default compile options', + class extends AbstractTestCase { + ['@test default options are a new copy'](assert) { + assert.notEqual(compileOptions(), compileOptions()); + } - ['@test has default AST plugins'](assert) { - assert.expect(defaultPlugins.length); + ['@test has default AST plugins'](assert) { + assert.expect(defaultPlugins.length); - let plugins = compileOptions().plugins.ast; + let plugins = compileOptions().plugins.ast; - for (let i = 0; i < defaultPlugins.length; i++) { - let plugin = defaultPlugins[i]; - assert.ok(plugins.indexOf(plugin) > -1, `includes ${plugin}`); + for (let i = 0; i < defaultPlugins.length; i++) { + let plugin = defaultPlugins[i]; + assert.ok(plugins.indexOf(plugin) > -1, `includes ${plugin}`); + } } } -}); +); let customTransformCounter = 0; class CustomTransform { @@ -64,34 +77,51 @@ class CustomPluginsTests extends RenderingTestCase { ['@test wrapped plugins are only invoked once per template'](assert) { this.render('
{{#if falsey}}nope{{/if}}
'); - assert.equal(customTransformCounter, 1, 'transform should only be instantiated once'); + assert.equal( + customTransformCounter, + 1, + 'transform should only be instantiated once' + ); } } -moduleFor('ember-template-compiler: registerPlugin with a custom plugins', class extends CustomPluginsTests { - beforeEach() { - registerPlugin('ast', CustomTransform); - } +moduleFor( + 'ember-template-compiler: registerPlugin with a custom plugins', + class extends CustomPluginsTests { + beforeEach() { + registerPlugin('ast', CustomTransform); + } - afterEach() { - unregisterPlugin('ast', CustomTransform); - return super.afterEach(); - } + afterEach() { + unregisterPlugin('ast', CustomTransform); + return super.afterEach(); + } - ['@test custom registered plugins are deduplicated'](assert) { - registerPlugin('ast', CustomTransform); - this.registerTemplate('application', '
'); - assert.equal(customTransformCounter, 1, 'transform should only be instantiated once'); + ['@test custom registered plugins are deduplicated'](assert) { + registerPlugin('ast', CustomTransform); + this.registerTemplate( + 'application', + '
' + ); + assert.equal( + customTransformCounter, + 1, + 'transform should only be instantiated once' + ); + } } -}); - -moduleFor('ember-template-compiler: custom plugins passed to compile', class extends RenderingTestCase { - // override so that we can provide custom AST plugins to compile - compile(templateString) { - return compile(templateString, { - plugins: { - ast: [CustomTransform] - } - }); +); + +moduleFor( + 'ember-template-compiler: custom plugins passed to compile', + class extends RenderingTestCase { + // override so that we can provide custom AST plugins to compile + compile(templateString) { + return compile(templateString, { + plugins: { + ast: [CustomTransform] + } + }); + } } -}); +); diff --git a/packages/ember-testing/lib/adapters/adapter.js b/packages/ember-testing/lib/adapters/adapter.js index c4dd29fd57f..88371e81ead 100644 --- a/packages/ember-testing/lib/adapters/adapter.js +++ b/packages/ember-testing/lib/adapters/adapter.js @@ -1,6 +1,8 @@ import { Object as EmberObject } from 'ember-runtime'; -function K() { return this; } +function K() { + return this; +} /** @module @ember/test diff --git a/packages/ember-testing/lib/adapters/qunit.js b/packages/ember-testing/lib/adapters/qunit.js index 8cdc8ada41d..59eda9c5d61 100644 --- a/packages/ember-testing/lib/adapters/qunit.js +++ b/packages/ember-testing/lib/adapters/qunit.js @@ -24,7 +24,9 @@ export default Adapter.extend({ // very old QUnit version QUnit.stop(); } else { - this.doneCallbacks.push(QUnit.config.current ? QUnit.config.current.assert.async() : null); + this.doneCallbacks.push( + QUnit.config.current ? QUnit.config.current.assert.async() : null + ); } }, asyncEnd() { diff --git a/packages/ember-testing/lib/events.js b/packages/ember-testing/lib/events.js index 185d63c119f..94e480cb24e 100644 --- a/packages/ember-testing/lib/events.js +++ b/packages/ember-testing/lib/events.js @@ -4,10 +4,22 @@ import isFormControl from './helpers/-is-form-control'; const DEFAULT_EVENT_OPTIONS = { canBubble: true, cancelable: true }; const KEYBOARD_EVENT_TYPES = ['keydown', 'keypress', 'keyup']; -const MOUSE_EVENT_TYPES = ['click', 'mousedown', 'mouseup', 'dblclick', 'mouseenter', 'mouseleave', 'mousemove', 'mouseout', 'mouseover']; +const MOUSE_EVENT_TYPES = [ + 'click', + 'mousedown', + 'mouseup', + 'dblclick', + 'mouseenter', + 'mouseleave', + 'mousemove', + 'mouseout', + 'mouseover' +]; export function focus(el) { - if (!el) { return; } + if (!el) { + return; + } if (el.isContentEditable || isFormControl(el)) { let type = el.getAttribute('type'); if (type !== 'checkbox' && type !== 'radio' && type !== 'hidden') { @@ -16,16 +28,16 @@ export function focus(el) { // makes `document.activeElement` be `element`. If the browser is focused, it also fires a focus event el.focus(); - + // Firefox does not trigger the `focusin` event if the window // does not have focus. If the document does not have focus then // fire `focusin` event as well. if (browserIsNotFocused) { // if the browser is not focused the previous `el.focus()` didn't fire an event, so we simulate it fireEvent(el, 'focus', { - bubbles: false, + bubbles: false }); - + fireEvent(el, 'focusin'); } }); @@ -92,7 +104,8 @@ function buildMouseEvent(type, options = {}) { eventOpts.shiftKey, eventOpts.metaKey, eventOpts.button, - eventOpts.relatedTarget); + eventOpts.relatedTarget + ); } catch (e) { event = buildBasicEvent(type, options); } diff --git a/packages/ember-testing/lib/ext/application.js b/packages/ember-testing/lib/ext/application.js index 4d0159da305..313a24f7eb9 100644 --- a/packages/ember-testing/lib/ext/application.js +++ b/packages/ember-testing/lib/ext/application.js @@ -1,16 +1,10 @@ import { Application as EmberApplication } from 'ember-application'; import setupForTesting from '../setup_for_testing'; import { helpers } from '../test/helpers'; -import TestPromise, { - resolve, - getLastPromise -} from '../test/promise'; +import TestPromise, { resolve, getLastPromise } from '../test/promise'; import run from '../test/run'; import { invokeInjectHelpersCallbacks } from '../test/on_inject_helpers'; -import { - asyncStart, - asyncEnd -} from '../test/adapter'; +import { asyncStart, asyncEnd } from '../test/adapter'; EmberApplication.reopen({ /** @@ -41,7 +35,6 @@ EmberApplication.reopen({ */ originalMethods: {}, - /** This property indicates whether or not this application is currently in testing mode. This is set when `setupForTesting` is called on the current @@ -130,7 +123,12 @@ EmberApplication.reopen({ for (let name in helpers) { this.originalMethods[name] = this.helperContainer[name]; this.testHelpers[name] = this.helperContainer[name] = helper(this, name); - protoWrap(TestPromise.prototype, name, helper(this, name), helpers[name].meta.wait); + protoWrap( + TestPromise.prototype, + name, + helper(this, name), + helpers[name].meta.wait + ); } invokeInjectHelpersCallbacks(this); @@ -150,7 +148,9 @@ EmberApplication.reopen({ @method removeTestHelpers */ removeTestHelpers() { - if (!this.helperContainer) { return; } + if (!this.helperContainer) { + return; + } for (let name in helpers) { this.helperContainer[name] = this.originalMethods[name]; @@ -191,6 +191,8 @@ function helper(app, name) { // asynchronous here, because fn may not be invoked before we // return. asyncStart(); - return lastPromise.then(() => fn.apply(app, [app, ...args])).finally(asyncEnd); + return lastPromise + .then(() => fn.apply(app, [app, ...args])) + .finally(asyncEnd); }; } diff --git a/packages/ember-testing/lib/ext/rsvp.js b/packages/ember-testing/lib/ext/rsvp.js index 54ec2bf8754..81240c62cf5 100644 --- a/packages/ember-testing/lib/ext/rsvp.js +++ b/packages/ember-testing/lib/ext/rsvp.js @@ -1,10 +1,7 @@ import { RSVP } from 'ember-runtime'; import { backburner } from 'ember-metal'; import { isTesting } from 'ember-debug'; -import { - asyncStart, - asyncEnd -} from '../test/adapter'; +import { asyncStart, asyncEnd } from '../test/adapter'; RSVP.configure('async', function(callback, promise) { // if schedule will cause autorun, we need to inform adapter diff --git a/packages/ember-testing/lib/helpers/-is-form-control.js b/packages/ember-testing/lib/helpers/-is-form-control.js index 607a0049bcc..f1419e44bdc 100644 --- a/packages/ember-testing/lib/helpers/-is-form-control.js +++ b/packages/ember-testing/lib/helpers/-is-form-control.js @@ -13,4 +13,4 @@ export default function isFormControl(element) { } return FORM_CONTROL_TAGS.indexOf(tagName) > -1; -} \ No newline at end of file +} diff --git a/packages/ember-testing/lib/helpers/and_then.js b/packages/ember-testing/lib/helpers/and_then.js index 73ffde468fb..5e451dccb95 100644 --- a/packages/ember-testing/lib/helpers/and_then.js +++ b/packages/ember-testing/lib/helpers/and_then.js @@ -1,4 +1,3 @@ - export default function andThen(app, callback) { return app.testHelpers.wait(callback(app)); } diff --git a/packages/ember-testing/lib/helpers/find.js b/packages/ember-testing/lib/helpers/find.js index c298baa7b59..f32d7d2f694 100644 --- a/packages/ember-testing/lib/helpers/find.js +++ b/packages/ember-testing/lib/helpers/find.js @@ -30,7 +30,9 @@ import { jQueryDisabled } from 'ember-views'; */ export default function find(app, selector, context) { if (jQueryDisabled) { - assert('If jQuery is disabled, please import and use helpers from @ember/test-helpers [https://github.com/emberjs/ember-test-helpers]. Note: `find` is not an available helper.'); + assert( + 'If jQuery is disabled, please import and use helpers from @ember/test-helpers [https://github.com/emberjs/ember-test-helpers]. Note: `find` is not an available helper.' + ); } let $el; context = context || get(app, 'rootElement'); diff --git a/packages/ember-testing/lib/helpers/key_event.js b/packages/ember-testing/lib/helpers/key_event.js index f657d1b4073..857bff8daea 100644 --- a/packages/ember-testing/lib/helpers/key_event.js +++ b/packages/ember-testing/lib/helpers/key_event.js @@ -17,7 +17,13 @@ @since 1.5.0 @public */ -export default function keyEvent(app, selector, contextOrType, typeOrKeyCode, keyCode) { +export default function keyEvent( + app, + selector, + contextOrType, + typeOrKeyCode, + keyCode +) { let context, type; if (keyCode === undefined) { @@ -29,5 +35,8 @@ export default function keyEvent(app, selector, contextOrType, typeOrKeyCode, ke type = typeOrKeyCode; } - return app.testHelpers.triggerEvent(selector, context, type, { keyCode, which: keyCode }); + return app.testHelpers.triggerEvent(selector, context, type, { + keyCode, + which: keyCode + }); } diff --git a/packages/ember-testing/lib/helpers/pause_test.js b/packages/ember-testing/lib/helpers/pause_test.js index 66b1460149c..ffa6375f531 100644 --- a/packages/ember-testing/lib/helpers/pause_test.js +++ b/packages/ember-testing/lib/helpers/pause_test.js @@ -59,7 +59,7 @@ export function resumeTest() { export function pauseTest() { info('Testing paused. Use `resumeTest()` to continue.'); - return new RSVP.Promise((resolve) => { + return new RSVP.Promise(resolve => { resume = resolve; }, 'TestAdapter paused promise'); } diff --git a/packages/ember-testing/lib/helpers/trigger_event.js b/packages/ember-testing/lib/helpers/trigger_event.js index 7ae22a9142a..ad2acaec3e9 100644 --- a/packages/ember-testing/lib/helpers/trigger_event.js +++ b/packages/ember-testing/lib/helpers/trigger_event.js @@ -22,7 +22,13 @@ import { fireEvent } from '../events'; @since 1.5.0 @public */ -export default function triggerEvent(app, selector, contextOrType, typeOrOptions, possibleOptions) { +export default function triggerEvent( + app, + selector, + contextOrType, + typeOrOptions, + possibleOptions +) { let arity = arguments.length; let context, type, options; @@ -34,12 +40,14 @@ export default function triggerEvent(app, selector, contextOrType, typeOrOptions options = {}; } else if (arity === 4) { // context and options are optional, so this is - if (typeof typeOrOptions === 'object') { // either + if (typeof typeOrOptions === 'object') { + // either // app, selector, type, options context = null; type = contextOrType; options = typeOrOptions; - } else { // or + } else { + // or // app, selector, context, type context = contextOrType; type = typeOrOptions; diff --git a/packages/ember-testing/lib/helpers/wait.js b/packages/ember-testing/lib/helpers/wait.js index e97a29b09f8..5c237682cd7 100644 --- a/packages/ember-testing/lib/helpers/wait.js +++ b/packages/ember-testing/lib/helpers/wait.js @@ -43,14 +43,21 @@ export default function wait(app, value) { // Every 10ms, poll for the async thing to have finished let watcher = setInterval(() => { // 1. If the router is loading, keep polling - let routerIsLoading = router._routerMicrolib && !!router._routerMicrolib.activeTransition; - if (routerIsLoading) { return; } + let routerIsLoading = + router._routerMicrolib && !!router._routerMicrolib.activeTransition; + if (routerIsLoading) { + return; + } // 2. If there are pending Ajax requests, keep polling - if (pendingRequests()) { return; } + if (pendingRequests()) { + return; + } // 3. If there are scheduled timers or we are inside of a run loop, keep polling - if (hasScheduledTimers() || getCurrentRunLoop()) { return; } + if (hasScheduledTimers() || getCurrentRunLoop()) { + return; + } if (checkWaiters()) { return; diff --git a/packages/ember-testing/lib/index.js b/packages/ember-testing/lib/index.js index 81291f878f7..acd534bf0dd 100644 --- a/packages/ember-testing/lib/index.js +++ b/packages/ember-testing/lib/index.js @@ -3,8 +3,8 @@ export { default as Adapter } from './adapters/adapter'; export { default as setupForTesting } from './setup_for_testing'; export { default as QUnitAdapter } from './adapters/qunit'; -import './support'; // to handle various edge cases +import './support'; // to handle various edge cases import './ext/application'; -import './ext/rsvp'; // setup RSVP + run loop integration -import './helpers'; // adds helpers to helpers object in Test +import './ext/rsvp'; // setup RSVP + run loop integration +import './helpers'; // adds helpers to helpers object in Test import './initializers'; // to setup initializer diff --git a/packages/ember-testing/lib/setup_for_testing.js b/packages/ember-testing/lib/setup_for_testing.js index 01a731dabd9..1ac8d9afe54 100644 --- a/packages/ember-testing/lib/setup_for_testing.js +++ b/packages/ember-testing/lib/setup_for_testing.js @@ -1,10 +1,7 @@ /* global self */ import { setTesting } from 'ember-debug'; -import { - getAdapter, - setAdapter -} from './test/adapter'; +import { getAdapter, setAdapter } from './test/adapter'; import { incrementPendingRequests, decrementPendingRequests, @@ -33,7 +30,9 @@ export default function setupForTesting() { let adapter = getAdapter(); // if adapter is not manually set default to QUnit if (!adapter) { - setAdapter((typeof self.QUnit === 'undefined') ? new Adapter() : new QUnitAdapter()); + setAdapter( + typeof self.QUnit === 'undefined' ? new Adapter() : new QUnitAdapter() + ); } document.removeEventListener('ajaxSend', incrementPendingRequests); diff --git a/packages/ember-testing/lib/support.js b/packages/ember-testing/lib/support.js index 200c0634102..6b62bdc031e 100644 --- a/packages/ember-testing/lib/support.js +++ b/packages/ember-testing/lib/support.js @@ -43,7 +43,11 @@ if (environment.hasDOM && !jQueryDisabled) { $.event.special.click = { // For checkbox, fire native event so checked state will be right trigger() { - if (this.nodeName === 'INPUT' && this.type === 'checkbox' && this.click) { + if ( + this.nodeName === 'INPUT' && + this.type === 'checkbox' && + this.click + ) { this.click(); return false; } @@ -55,7 +59,7 @@ if (environment.hasDOM && !jQueryDisabled) { // Try again to verify that the patch took effect or blow up. testCheckboxClick(function() { warn( - 'clicked checkboxes should be checked! the jQuery patch didn\'t work', + "clicked checkboxes should be checked! the jQuery patch didn't work", this.checked, { id: 'ember-testing.test-checkbox-click' } ); diff --git a/packages/ember-testing/lib/test.js b/packages/ember-testing/lib/test.js index a5c80cf1ce8..1aff70ba7f7 100644 --- a/packages/ember-testing/lib/test.js +++ b/packages/ember-testing/lib/test.js @@ -8,20 +8,10 @@ import { unregisterHelper } from './test/helpers'; import { onInjectHelpers } from './test/on_inject_helpers'; -import TestPromise, { - promise, - resolve -} from './test/promise'; -import { - checkWaiters, - registerWaiter, - unregisterWaiter -} from './test/waiters'; +import TestPromise, { promise, resolve } from './test/promise'; +import { checkWaiters, registerWaiter, unregisterWaiter } from './test/waiters'; -import { - getAdapter, - setAdapter -} from './test/adapter'; +import { getAdapter, setAdapter } from './test/adapter'; /** This is a container for an assortment of testing related functionality: diff --git a/packages/ember-testing/lib/test/adapter.js b/packages/ember-testing/lib/test/adapter.js index 64dd3aa1b50..fd8079d7083 100644 --- a/packages/ember-testing/lib/test/adapter.js +++ b/packages/ember-testing/lib/test/adapter.js @@ -29,5 +29,5 @@ export function asyncEnd() { function adapterDispatch(error) { adapter.exception(error); - console.error(error.stack);// eslint-disable-line no-console + console.error(error.stack); // eslint-disable-line no-console } diff --git a/packages/ember-testing/lib/test/pending_requests.js b/packages/ember-testing/lib/test/pending_requests.js index 77d5cb296e4..eb73e32a21b 100644 --- a/packages/ember-testing/lib/test/pending_requests.js +++ b/packages/ember-testing/lib/test/pending_requests.js @@ -8,12 +8,16 @@ export function clearPendingRequests() { requests.length = 0; } -export function incrementPendingRequests({ detail } = { detail: { xhr: null }}) { +export function incrementPendingRequests( + { detail } = { detail: { xhr: null } } +) { let xhr = detail.xhr; requests.push(xhr); } -export function decrementPendingRequests({ detail } = { detail: { xhr: null }}) { +export function decrementPendingRequests( + { detail } = { detail: { xhr: null } } +) { let xhr = detail.xhr; for (let i = 0; i < requests.length; i++) { if (xhr === requests[i]) { diff --git a/packages/ember-testing/lib/test/promise.js b/packages/ember-testing/lib/test/promise.js index 81a78a95846..d69bfea4c83 100644 --- a/packages/ember-testing/lib/test/promise.js +++ b/packages/ember-testing/lib/test/promise.js @@ -10,8 +10,10 @@ export default class TestPromise extends RSVP.Promise { } then(_onFulfillment, ...args) { - let onFulfillment = typeof _onFulfillment === 'function' ? - result => isolate(_onFulfillment, result) : undefined; + let onFulfillment = + typeof _onFulfillment === 'function' + ? result => isolate(_onFulfillment, result) + : undefined; return super.then(onFulfillment, ...args); } } @@ -53,7 +55,6 @@ export function getLastPromise() { return lastPromise; } - // This method isolates nested async methods // so that they don't conflict with other last promises. // @@ -72,7 +73,7 @@ function isolate(onFulfillment, result) { // If the method returned a promise // return that promise. If not, // return the last async helper's promise - if ((value && (value instanceof TestPromise)) || !promise) { + if ((value && value instanceof TestPromise) || !promise) { return value; } else { return run(() => resolve(promise).then(() => value)); diff --git a/packages/ember-testing/tests/acceptance_test.js b/packages/ember-testing/tests/acceptance_test.js index ddff8a95d17..ac85e60b67b 100644 --- a/packages/ember-testing/tests/acceptance_test.js +++ b/packages/ember-testing/tests/acceptance_test.js @@ -1,7 +1,4 @@ -import { - moduleFor, - AutobootApplicationTestCase -} from 'internal-test-helpers'; +import { moduleFor, AutobootApplicationTestCase } from 'internal-test-helpers'; import { later } from 'ember-metal'; import Test from '../test'; @@ -12,396 +9,558 @@ import { jQueryDisabled } from 'ember-views'; import { getDebugFunction, setDebugFunction } from 'ember-debug'; const originalDebug = getDebugFunction('debug'); -const noop = function(){}; +const noop = function() {}; var originalConsoleError = console.error; // eslint-disable-line no-console if (!jQueryDisabled) { + moduleFor( + 'ember-testing Acceptance', + class extends AutobootApplicationTestCase { + constructor() { + setDebugFunction('debug', noop); + super(); + this._originalAdapter = Test.adapter; + + this.runTask(() => { + this.createApplication(); + this.router.map(function() { + this.route('posts'); + this.route('comments'); + + this.route('abort_transition'); + + this.route('redirect'); + }); - moduleFor('ember-testing Acceptance', class extends AutobootApplicationTestCase { - constructor() { - setDebugFunction('debug', noop); - super(); - this._originalAdapter = Test.adapter; - - this.runTask(() => { - this.createApplication(); - this.router.map(function() { - this.route('posts'); - this.route('comments'); - - this.route('abort_transition'); - - this.route('redirect'); - }); - - this.indexHitCount = 0; - this.currentRoute = 'index'; - let testContext = this; - - this.add('route:index', Route.extend({ - model() { - testContext.indexHitCount += 1; - } - })); + this.indexHitCount = 0; + this.currentRoute = 'index'; + let testContext = this; + + this.add( + 'route:index', + Route.extend({ + model() { + testContext.indexHitCount += 1; + } + }) + ); - this.add('route:posts', Route.extend({ - renderTemplate() { - testContext.currentRoute = 'posts'; - this._super(...arguments); - } - })); + this.add( + 'route:posts', + Route.extend({ + renderTemplate() { + testContext.currentRoute = 'posts'; + this._super(...arguments); + } + }) + ); - this.addTemplate('posts', ` + this.addTemplate( + 'posts', + `
- `); + ` + ); - this.add('route:comments', Route.extend({ - renderTemplate() { - testContext.currentRoute = 'comments'; - this._super(...arguments); - } - })); + this.add( + 'route:comments', + Route.extend({ + renderTemplate() { + testContext.currentRoute = 'comments'; + this._super(...arguments); + } + }) + ); - this.addTemplate('comments', `
{{input type="text"}}
`); + this.addTemplate('comments', `
{{input type="text"}}
`); - this.add('route:abort_transition', Route.extend({ - beforeModel(transition) { - transition.abort(); - } - })); + this.add( + 'route:abort_transition', + Route.extend({ + beforeModel(transition) { + transition.abort(); + } + }) + ); - this.add('route:redirect', Route.extend({ - beforeModel() { - this.transitionTo('comments'); - } - })); + this.add( + 'route:redirect', + Route.extend({ + beforeModel() { + this.transitionTo('comments'); + } + }) + ); - this.application.setupForTesting(); + this.application.setupForTesting(); - Test.registerAsyncHelper('slowHelper', () => { - return new RSVP.Promise(resolve => later(resolve, 10)); - }); + Test.registerAsyncHelper('slowHelper', () => { + return new RSVP.Promise(resolve => later(resolve, 10)); + }); - this.application.injectTestHelpers(); - }); - } - afterEach() { - console.error = originalConsoleError;// eslint-disable-line no-console - super.afterEach(); - } + this.application.injectTestHelpers(); + }); + } + afterEach() { + console.error = originalConsoleError; // eslint-disable-line no-console + super.afterEach(); + } - teardown() { - setDebugFunction('debug', originalDebug); - Test.adapter = this._originalAdapter; - super.teardown(); - } + teardown() { + setDebugFunction('debug', originalDebug); + Test.adapter = this._originalAdapter; + super.teardown(); + } - [`@test helpers can be chained with then`](assert) { - assert.expect(6); - - window.visit('/posts').then(() => { - assert.equal(this.currentRoute, 'posts', 'Successfully visited posts route'); - assert.equal(window.currentURL(), '/posts', 'posts URL is correct'); - return window.click('a:contains("Comments")'); - }).then(() => { - assert.equal(this.currentRoute, 'comments', 'visit chained with click'); - return window.fillIn('.ember-text-field', 'yeah'); - }).then(() => { - assert.equal(document.querySelector('.ember-text-field').value, 'yeah', 'chained with fillIn'); - return window.fillIn('.ember-text-field', '#qunit-fixture', 'context working'); - }).then(() => { - assert.equal(document.querySelector('.ember-text-field').value, 'context working', 'chained with fillIn'); - return window.click('.does-not-exist'); - }).catch(e => { - assert.equal(e.message, 'Element .does-not-exist not found.', 'Non-existent click exception caught'); - }); - } + [`@test helpers can be chained with then`](assert) { + assert.expect(6); + + window + .visit('/posts') + .then(() => { + assert.equal( + this.currentRoute, + 'posts', + 'Successfully visited posts route' + ); + assert.equal(window.currentURL(), '/posts', 'posts URL is correct'); + return window.click('a:contains("Comments")'); + }) + .then(() => { + assert.equal( + this.currentRoute, + 'comments', + 'visit chained with click' + ); + return window.fillIn('.ember-text-field', 'yeah'); + }) + .then(() => { + assert.equal( + document.querySelector('.ember-text-field').value, + 'yeah', + 'chained with fillIn' + ); + return window.fillIn( + '.ember-text-field', + '#qunit-fixture', + 'context working' + ); + }) + .then(() => { + assert.equal( + document.querySelector('.ember-text-field').value, + 'context working', + 'chained with fillIn' + ); + return window.click('.does-not-exist'); + }) + .catch(e => { + assert.equal( + e.message, + 'Element .does-not-exist not found.', + 'Non-existent click exception caught' + ); + }); + } - [`@test helpers can be chained to each other (legacy)`](assert) { - assert.expect(7); - - window.visit('/posts') - .click('a:first', '#comments-link') - .fillIn('.ember-text-field', 'hello') - .then(() => { - assert.equal(this.currentRoute, 'comments', 'Successfully visited comments route'); - assert.equal(window.currentURL(), '/comments', 'Comments URL is correct'); - assert.equal(document.querySelector('.ember-text-field').value, 'hello', 'Fillin successfully works'); - window.find('.ember-text-field').one('keypress', e => { - assert.equal(e.keyCode, 13, 'keyevent chained with correct keyCode.'); - assert.equal(e.which, 13, 'keyevent chained with correct which.'); + [`@test helpers can be chained to each other (legacy)`](assert) { + assert.expect(7); + + window + .visit('/posts') + .click('a:first', '#comments-link') + .fillIn('.ember-text-field', 'hello') + .then(() => { + assert.equal( + this.currentRoute, + 'comments', + 'Successfully visited comments route' + ); + assert.equal( + window.currentURL(), + '/comments', + 'Comments URL is correct' + ); + assert.equal( + document.querySelector('.ember-text-field').value, + 'hello', + 'Fillin successfully works' + ); + window.find('.ember-text-field').one('keypress', e => { + assert.equal( + e.keyCode, + 13, + 'keyevent chained with correct keyCode.' + ); + assert.equal(e.which, 13, 'keyevent chained with correct which.'); + }); + }) + .keyEvent('.ember-text-field', 'keypress', 13) + .visit('/posts') + .then(() => { + assert.equal( + this.currentRoute, + 'posts', + 'Thens can also be chained to helpers' + ); + assert.equal( + window.currentURL(), + '/posts', + 'URL is set correct on chained helpers' + ); }); - }) - .keyEvent('.ember-text-field', 'keypress', 13) - .visit('/posts') - .then(() => { - assert.equal(this.currentRoute, 'posts', 'Thens can also be chained to helpers'); - assert.equal(window.currentURL(), '/posts', 'URL is set correct on chained helpers'); - }); - } + } - [`@test helpers don't need to be chained`](assert) { - assert.expect(5); + [`@test helpers don't need to be chained`](assert) { + assert.expect(5); - window.visit('/posts'); + window.visit('/posts'); - window.click('a:first', '#comments-link'); + window.click('a:first', '#comments-link'); - window.fillIn('.ember-text-field', 'hello'); + window.fillIn('.ember-text-field', 'hello'); - window.andThen(() => { - assert.equal(this.currentRoute, 'comments', 'Successfully visited comments route'); - assert.equal(window.currentURL(), '/comments', 'Comments URL is correct'); - assert.equal(window.find('.ember-text-field').val(), 'hello', 'Fillin successfully works'); - }); + window.andThen(() => { + assert.equal( + this.currentRoute, + 'comments', + 'Successfully visited comments route' + ); + assert.equal( + window.currentURL(), + '/comments', + 'Comments URL is correct' + ); + assert.equal( + window.find('.ember-text-field').val(), + 'hello', + 'Fillin successfully works' + ); + }); - window.visit('/posts'); + window.visit('/posts'); - window.andThen(() => { - assert.equal(this.currentRoute, 'posts'); - assert.equal(window.currentURL(), '/posts'); - }); - } + window.andThen(() => { + assert.equal(this.currentRoute, 'posts'); + assert.equal(window.currentURL(), '/posts'); + }); + } - [`@test Nested async helpers`](assert) { - assert.expect(5); + [`@test Nested async helpers`](assert) { + assert.expect(5); - window.visit('/posts'); + window.visit('/posts'); - window.andThen(() => { - window.click('a:first', '#comments-link'); - window.fillIn('.ember-text-field', 'hello'); - }); + window.andThen(() => { + window.click('a:first', '#comments-link'); + window.fillIn('.ember-text-field', 'hello'); + }); - window.andThen(() => { - assert.equal(this.currentRoute, 'comments', 'Successfully visited comments route'); - assert.equal(window.currentURL(), '/comments', 'Comments URL is correct'); - assert.equal(window.find('.ember-text-field').val(), 'hello', 'Fillin successfully works'); - }); + window.andThen(() => { + assert.equal( + this.currentRoute, + 'comments', + 'Successfully visited comments route' + ); + assert.equal( + window.currentURL(), + '/comments', + 'Comments URL is correct' + ); + assert.equal( + window.find('.ember-text-field').val(), + 'hello', + 'Fillin successfully works' + ); + }); - window.visit('/posts'); + window.visit('/posts'); - window.andThen(() => { - assert.equal(this.currentRoute, 'posts'); - assert.equal(window.currentURL(), '/posts'); - }); - } + window.andThen(() => { + assert.equal(this.currentRoute, 'posts'); + assert.equal(window.currentURL(), '/posts'); + }); + } - [`@test Multiple nested async helpers`](assert) { - assert.expect(3); + [`@test Multiple nested async helpers`](assert) { + assert.expect(3); - window.visit('/posts'); + window.visit('/posts'); - window.andThen(() => { - window.click('a:first', '#comments-link'); + window.andThen(() => { + window.click('a:first', '#comments-link'); - window.fillIn('.ember-text-field', 'hello'); - window.fillIn('.ember-text-field', 'goodbye'); - }); - - window.andThen(() => { - assert.equal(window.find('.ember-text-field').val(), 'goodbye', 'Fillin successfully works'); - assert.equal(this.currentRoute, 'comments', 'Successfully visited comments route'); - assert.equal(window.currentURL(), '/comments', 'Comments URL is correct'); - }); - } + window.fillIn('.ember-text-field', 'hello'); + window.fillIn('.ember-text-field', 'goodbye'); + }); - [`@test Helpers nested in thens`](assert) { - assert.expect(5); + window.andThen(() => { + assert.equal( + window.find('.ember-text-field').val(), + 'goodbye', + 'Fillin successfully works' + ); + assert.equal( + this.currentRoute, + 'comments', + 'Successfully visited comments route' + ); + assert.equal( + window.currentURL(), + '/comments', + 'Comments URL is correct' + ); + }); + } - window.visit('/posts').then(() => { - window.click('a:first', '#comments-link'); - }); + [`@test Helpers nested in thens`](assert) { + assert.expect(5); - window.andThen(() => { - window.fillIn('.ember-text-field', 'hello'); - }); + window.visit('/posts').then(() => { + window.click('a:first', '#comments-link'); + }); - window.andThen(() => { - assert.equal(this.currentRoute, 'comments', 'Successfully visited comments route'); - assert.equal(window.currentURL(), '/comments', 'Comments URL is correct'); - assert.equal(window.find('.ember-text-field').val(), 'hello', 'Fillin successfully works'); - }); + window.andThen(() => { + window.fillIn('.ember-text-field', 'hello'); + }); + + window.andThen(() => { + assert.equal( + this.currentRoute, + 'comments', + 'Successfully visited comments route' + ); + assert.equal( + window.currentURL(), + '/comments', + 'Comments URL is correct' + ); + assert.equal( + window.find('.ember-text-field').val(), + 'hello', + 'Fillin successfully works' + ); + }); - window.visit('/posts'); + window.visit('/posts'); - window.andThen(() => { - assert.equal(this.currentRoute, 'posts'); - assert.equal(window.currentURL(), '/posts', 'Posts URL is correct'); - }); - } + window.andThen(() => { + assert.equal(this.currentRoute, 'posts'); + assert.equal(window.currentURL(), '/posts', 'Posts URL is correct'); + }); + } - [`@test Aborted transitions are not logged via Ember.Test.adapter#exception`](assert) { - assert.expect(0); + [`@test Aborted transitions are not logged via Ember.Test.adapter#exception`]( + assert + ) { + assert.expect(0); - Test.adapter = QUnitAdapter.create({ - exception() { - assert.ok(false, 'aborted transitions are not logged'); - } - }); + Test.adapter = QUnitAdapter.create({ + exception() { + assert.ok(false, 'aborted transitions are not logged'); + } + }); - window.visit('/abort_transition'); - } + window.visit('/abort_transition'); + } - [`@test Unhandled exceptions are logged via Ember.Test.adapter#exception`](assert) { - assert.expect(2); + [`@test Unhandled exceptions are logged via Ember.Test.adapter#exception`]( + assert + ) { + assert.expect(2); + + console.error = () => {}; // eslint-disable-line no-console + let asyncHandled; + Test.adapter = QUnitAdapter.create({ + exception(error) { + assert.equal( + error.message, + 'Element .does-not-exist not found.', + 'Exception successfully caught and passed to Ember.Test.adapter.exception' + ); + // handle the rejection so it doesn't leak later. + asyncHandled.catch(() => {}); + } + }); - console.error = () => {}; // eslint-disable-line no-console - let asyncHandled; - Test.adapter = QUnitAdapter.create({ - exception(error) { + window.visit('/posts'); + + window.click('.invalid-element').catch(error => { assert.equal( - error.message, 'Element .does-not-exist not found.', - 'Exception successfully caught and passed to Ember.Test.adapter.exception' + error.message, + 'Element .invalid-element not found.', + 'Exception successfully handled in the rejection handler' ); - // handle the rejection so it doesn't leak later. - asyncHandled.catch(() => { }); - } - }); + }); + + asyncHandled = window.click('.does-not-exist'); + } + + [`@test Unhandled exceptions in 'andThen' are logged via Ember.Test.adapter#exception`]( + assert + ) { + assert.expect(1); + + console.error = () => {}; // eslint-disable-line no-console + Test.adapter = QUnitAdapter.create({ + exception(error) { + assert.equal( + error.message, + 'Catch me', + 'Exception successfully caught and passed to Ember.Test.adapter.exception' + ); + } + }); - window.visit('/posts'); + window.visit('/posts'); - window.click('.invalid-element').catch(error => { - assert.equal( - error.message, 'Element .invalid-element not found.', - 'Exception successfully handled in the rejection handler' - ); - }); + window.andThen(() => { + throw new Error('Catch me'); + }); + } - asyncHandled = window.click('.does-not-exist'); - } + [`@test should not start routing on the root URL when visiting another`]( + assert + ) { + assert.expect(4); - [`@test Unhandled exceptions in 'andThen' are logged via Ember.Test.adapter#exception`](assert) { - assert.expect(1); + window.visit('/posts'); - console.error = () => {}; // eslint-disable-line no-console - Test.adapter = QUnitAdapter.create({ - exception(error) { + window.andThen(() => { + assert.ok(window.find('#comments-link'), 'found comments-link'); assert.equal( - error.message, 'Catch me', - 'Exception successfully caught and passed to Ember.Test.adapter.exception' + this.currentRoute, + 'posts', + 'Successfully visited posts route' ); - } - }); - - window.visit('/posts'); + assert.equal(window.currentURL(), '/posts', 'Posts URL is correct'); + assert.equal( + this.indexHitCount, + 0, + 'should not hit index route when visiting another route' + ); + }); + } - window.andThen(() => { - throw new Error('Catch me'); - }); - } + [`@test only enters the index route once when visiting `](assert) { + assert.expect(1); - [`@test should not start routing on the root URL when visiting another`](assert) { - assert.expect(4); + window.visit('/'); - window.visit('/posts'); + window.andThen(() => { + assert.equal( + this.indexHitCount, + 1, + 'should hit index once when visiting /' + ); + }); + } - window.andThen(() => { - assert.ok(window.find('#comments-link'), 'found comments-link'); - assert.equal(this.currentRoute, 'posts', 'Successfully visited posts route'); - assert.equal(window.currentURL(), '/posts', 'Posts URL is correct'); - assert.equal(this.indexHitCount, 0, 'should not hit index route when visiting another route'); - }); - } + [`@test test must not finish while asyncHelpers are pending`](assert) { + assert.expect(2); - [`@test only enters the index route once when visiting `](assert) { - assert.expect(1); + let async = 0; + let innerRan = false; - window.visit('/'); + Test.adapter = QUnitAdapter.extend({ + asyncStart() { + async++; + this._super(); + }, + asyncEnd() { + async--; + this._super(); + } + }).create(); - window.andThen(() => { - assert.equal(this.indexHitCount, 1, 'should hit index once when visiting /'); - }); - } + this.application.testHelpers.slowHelper(); - [`@test test must not finish while asyncHelpers are pending`](assert) { - assert.expect(2); + window.andThen(() => { + innerRan = true; + }); - let async = 0; - let innerRan = false; + assert.equal(innerRan, false, 'should not have run yet'); + assert.ok(async > 0, 'should have told the adapter to pause'); - Test.adapter = QUnitAdapter.extend({ - asyncStart() { - async++; - this._super(); - }, - asyncEnd() { - async--; - this._super(); + if (async === 0) { + // If we failed the test, prevent zalgo from escaping and breaking + // our other tests. + Test.adapter.asyncStart(); + Test.resolve().then(() => { + Test.adapter.asyncEnd(); + }); } - }).create(); - - this.application.testHelpers.slowHelper(); + } - window.andThen(() => { - innerRan = true; - }); + [`@test visiting a URL that causes another transition should yield the correct URL`]( + assert + ) { + assert.expect(1); - assert.equal(innerRan, false, 'should not have run yet'); - assert.ok(async > 0, 'should have told the adapter to pause'); + window.visit('/redirect'); - if (async === 0) { - // If we failed the test, prevent zalgo from escaping and breaking - // our other tests. - Test.adapter.asyncStart(); - Test.resolve().then(() => { - Test.adapter.asyncEnd(); + window.andThen(() => { + assert.equal( + window.currentURL(), + '/comments', + 'Redirected to Comments URL' + ); }); } - } - [`@test visiting a URL that causes another transition should yield the correct URL`](assert) { - assert.expect(1); + [`@test visiting a URL and then visiting a second URL with a transition should yield the correct URL`]( + assert + ) { + assert.expect(2); - window.visit('/redirect'); + window.visit('/posts'); - window.andThen(() => { - assert.equal(window.currentURL(), '/comments', 'Redirected to Comments URL'); - }); - } - - [`@test visiting a URL and then visiting a second URL with a transition should yield the correct URL`](assert) { - assert.expect(2); - - window.visit('/posts'); - - window.andThen(function () { - assert.equal(window.currentURL(), '/posts', 'First visited URL is correct'); - }); + window.andThen(function() { + assert.equal( + window.currentURL(), + '/posts', + 'First visited URL is correct' + ); + }); - window.visit('/redirect'); + window.visit('/redirect'); - window.andThen(() => { - assert.equal(window.currentURL(), '/comments', 'Redirected to Comments URL'); - }); + window.andThen(() => { + assert.equal( + window.currentURL(), + '/comments', + 'Redirected to Comments URL' + ); + }); + } } + ); - }); - - moduleFor('ember-testing Acceptance - teardown', class extends AutobootApplicationTestCase { + moduleFor( + 'ember-testing Acceptance - teardown', + class extends AutobootApplicationTestCase { + [`@test that the setup/teardown happens correctly`](assert) { + assert.expect(2); - [`@test that the setup/teardown happens correctly`](assert) { - assert.expect(2); - - this.runTask(() => { - this.createApplication(); - }); - this.application.injectTestHelpers(); + this.runTask(() => { + this.createApplication(); + }); + this.application.injectTestHelpers(); - assert.ok(typeof Test.Promise.prototype.click === 'function'); + assert.ok(typeof Test.Promise.prototype.click === 'function'); - this.runTask(() => { - this.application.destroy(); - }); + this.runTask(() => { + this.application.destroy(); + }); - assert.equal(Test.Promise.prototype.click, undefined); + assert.equal(Test.Promise.prototype.click, undefined); + } } - - }); + ); } diff --git a/packages/ember-testing/tests/adapters/adapter_test.js b/packages/ember-testing/tests/adapters/adapter_test.js index b3ecaacbbdf..36cc1f93156 100644 --- a/packages/ember-testing/tests/adapters/adapter_test.js +++ b/packages/ember-testing/tests/adapters/adapter_test.js @@ -4,27 +4,28 @@ import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; var adapter; -moduleFor('ember-testing Adapter', class extends AbstractTestCase { - constructor() { - super(); - adapter = new Adapter(); - } +moduleFor( + 'ember-testing Adapter', + class extends AbstractTestCase { + constructor() { + super(); + adapter = new Adapter(); + } - teardown() { - run(adapter, adapter.destroy); - } + teardown() { + run(adapter, adapter.destroy); + } - ['@test exception throws'](assert) { - var error = 'Hai'; - var thrown; + ['@test exception throws'](assert) { + var error = 'Hai'; + var thrown; - try { - adapter.exception(error); - } catch (e) { - thrown = e; + try { + adapter.exception(error); + } catch (e) { + thrown = e; + } + assert.equal(thrown, error); } - assert.equal(thrown, error); } - -}); - +); diff --git a/packages/ember-testing/tests/adapters/qunit_test.js b/packages/ember-testing/tests/adapters/qunit_test.js index dcad01ef120..f464333a894 100644 --- a/packages/ember-testing/tests/adapters/qunit_test.js +++ b/packages/ember-testing/tests/adapters/qunit_test.js @@ -4,45 +4,49 @@ import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; var adapter; -moduleFor('ember-testing QUnitAdapter: QUnit 2.x', class extends AbstractTestCase { - constructor() { - super(); - this.originalStart = QUnit.start; - this.originalStop = QUnit.stop; - - delete QUnit.start; - delete QUnit.stop; - - adapter = new QUnitAdapter(); - } - - teardown() { - run(adapter, adapter.destroy); - - QUnit.start = this.originalStart; - QUnit.stop = this.originalStop; - } - - ['@test asyncStart waits for asyncEnd to finish a test'](assert) { - adapter.asyncStart(); - - setTimeout(function() { - assert.ok(true); +moduleFor( + 'ember-testing QUnitAdapter: QUnit 2.x', + class extends AbstractTestCase { + constructor() { + super(); + this.originalStart = QUnit.start; + this.originalStop = QUnit.stop; + + delete QUnit.start; + delete QUnit.stop; + + adapter = new QUnitAdapter(); + } + + teardown() { + run(adapter, adapter.destroy); + + QUnit.start = this.originalStart; + QUnit.stop = this.originalStop; + } + + ['@test asyncStart waits for asyncEnd to finish a test'](assert) { + adapter.asyncStart(); + + setTimeout(function() { + assert.ok(true); + adapter.asyncEnd(); + }, 50); + } + + ['@test asyncStart waits for equal numbers of asyncEnd to finish a test']( + assert + ) { + let adapter = QUnitAdapter.create(); + + adapter.asyncStart(); + adapter.asyncStart(); adapter.asyncEnd(); - }, 50); - } - - ['@test asyncStart waits for equal numbers of asyncEnd to finish a test'](assert) { - let adapter = QUnitAdapter.create(); - adapter.asyncStart(); - adapter.asyncStart(); - adapter.asyncEnd(); - - setTimeout(function() { - assert.ok(true); - adapter.asyncEnd(); - }, 50); + setTimeout(function() { + assert.ok(true); + adapter.asyncEnd(); + }, 50); + } } -}); - +); diff --git a/packages/ember-testing/tests/adapters_test.js b/packages/ember-testing/tests/adapters_test.js index 35466160219..4b93b672687 100644 --- a/packages/ember-testing/tests/adapters_test.js +++ b/packages/ember-testing/tests/adapters_test.js @@ -8,7 +8,7 @@ import { RSVP } from 'ember-runtime'; import { getDebugFunction, setDebugFunction } from 'ember-debug'; const originalDebug = getDebugFunction('debug'); -const noop = function(){}; +const noop = function() {}; var App, originalAdapter, originalQUnit, originalWindowOnerror; @@ -36,7 +36,7 @@ class AdapterSetupAndTearDown extends AbstractTestCase { } afterEach() { - console.error = originalConsoleError;// eslint-disable-line no-console + console.error = originalConsoleError; // eslint-disable-line no-console } teardown() { @@ -54,170 +54,223 @@ class AdapterSetupAndTearDown extends AbstractTestCase { } } -moduleFor('ember-testing Adapters', class extends AdapterSetupAndTearDown { - ['@test Setting a test adapter manually'](assert) { - assert.expect(1); - var CustomAdapter; +moduleFor( + 'ember-testing Adapters', + class extends AdapterSetupAndTearDown { + ['@test Setting a test adapter manually'](assert) { + assert.expect(1); + var CustomAdapter; - CustomAdapter = Adapter.extend({ - asyncStart() { - assert.ok(true, 'Correct adapter was used'); - } - }); + CustomAdapter = Adapter.extend({ + asyncStart() { + assert.ok(true, 'Correct adapter was used'); + } + }); - run(function () { - App = EmberApplication.create(); - Test.adapter = CustomAdapter.create(); - App.setupForTesting(); - }); + run(function() { + App = EmberApplication.create(); + Test.adapter = CustomAdapter.create(); + App.setupForTesting(); + }); - Test.adapter.asyncStart(); - } + Test.adapter.asyncStart(); + } - ['@test QUnitAdapter is used by default (if QUnit is available)'](assert) { - assert.expect(1); + ['@test QUnitAdapter is used by default (if QUnit is available)'](assert) { + assert.expect(1); - Test.adapter = null; + Test.adapter = null; - run(function () { - App = EmberApplication.create(); - App.setupForTesting(); - }); + run(function() { + App = EmberApplication.create(); + App.setupForTesting(); + }); - assert.ok(Test.adapter instanceof QUnitAdapter); - } + assert.ok(Test.adapter instanceof QUnitAdapter); + } - ['@test Adapter is used by default (if QUnit is not available)'](assert) { - assert.expect(2); + ['@test Adapter is used by default (if QUnit is not available)'](assert) { + assert.expect(2); - delete window.QUnit; + delete window.QUnit; - Test.adapter = null; + Test.adapter = null; - run(function () { - App = EmberApplication.create(); - App.setupForTesting(); - }); + run(function() { + App = EmberApplication.create(); + App.setupForTesting(); + }); - assert.ok(Test.adapter instanceof Adapter); - assert.ok(!(Test.adapter instanceof QUnitAdapter)); - } + assert.ok(Test.adapter instanceof Adapter); + assert.ok(!(Test.adapter instanceof QUnitAdapter)); + } - ['@test With Ember.Test.adapter set, errors in synchronous Ember.run are bubbled out'](assert) { - let thrown = new Error('Boom!'); + ['@test With Ember.Test.adapter set, errors in synchronous Ember.run are bubbled out']( + assert + ) { + let thrown = new Error('Boom!'); - let caughtInAdapter, caughtInCatch; - Test.adapter = QUnitAdapter.create({ - exception(error) { - caughtInAdapter = error; + let caughtInAdapter, caughtInCatch; + Test.adapter = QUnitAdapter.create({ + exception(error) { + caughtInAdapter = error; + } + }); + + try { + run(() => { + throw thrown; + }); + } catch (e) { + caughtInCatch = e; } - }); - try { - run(() => { throw thrown; }); - } catch (e) { - caughtInCatch = e; + assert.equal( + caughtInAdapter, + undefined, + 'test adapter should never receive synchronous errors' + ); + assert.equal( + caughtInCatch, + thrown, + 'a "normal" try/catch should catch errors in sync run' + ); } - assert.equal(caughtInAdapter, undefined, 'test adapter should never receive synchronous errors'); - assert.equal(caughtInCatch, thrown, 'a "normal" try/catch should catch errors in sync run'); - } + ['@test when both Ember.onerror (which rethrows) and TestAdapter are registered - sync run']( + assert + ) { + assert.expect(2); - ['@test when both Ember.onerror (which rethrows) and TestAdapter are registered - sync run'](assert) { - assert.expect(2); + Test.adapter = { + exception() { + assert.notOk( + true, + 'adapter is not called for errors thrown in sync run loops' + ); + } + }; - Test.adapter = { - exception() { - assert.notOk(true, 'adapter is not called for errors thrown in sync run loops'); - } - }; + setOnerror(function(error) { + assert.ok( + true, + 'onerror is called for sync errors even if TestAdapter is setup' + ); + throw error; + }); - setOnerror(function(error) { - assert.ok(true, 'onerror is called for sync errors even if TestAdapter is setup'); - throw error; - }); + assert.throws(runThatThrowsSync, Error, 'error is thrown'); + } - assert.throws(runThatThrowsSync, Error, 'error is thrown'); - } + ['@test when both Ember.onerror (which does not rethrow) and TestAdapter are registered - sync run']( + assert + ) { + assert.expect(2); - ['@test when both Ember.onerror (which does not rethrow) and TestAdapter are registered - sync run'](assert) { - assert.expect(2); + Test.adapter = { + exception() { + assert.notOk( + true, + 'adapter is not called for errors thrown in sync run loops' + ); + } + }; - Test.adapter = { - exception() { - assert.notOk(true, 'adapter is not called for errors thrown in sync run loops'); - } - }; + setOnerror(function() { + assert.ok( + true, + 'onerror is called for sync errors even if TestAdapter is setup' + ); + }); - setOnerror(function() { - assert.ok(true, 'onerror is called for sync errors even if TestAdapter is setup'); - }); + runThatThrowsSync(); + assert.ok( + true, + 'no error was thrown, Ember.onerror can intercept errors' + ); + } - runThatThrowsSync(); - assert.ok(true, 'no error was thrown, Ember.onerror can intercept errors'); - } + ['@test when TestAdapter is registered and error is thrown - async run']( + assert + ) { + assert.expect(3); + let done = assert.async(); - ['@test when TestAdapter is registered and error is thrown - async run'](assert) { - assert.expect(3); - let done = assert.async(); + let caughtInAdapter, caughtInCatch, caughtByWindowOnerror; + Test.adapter = { + exception(error) { + caughtInAdapter = error; + } + }; + + window.onerror = function(message) { + caughtByWindowOnerror = message; + // prevent "bubbling" and therefore failing the test + return true; + }; - let caughtInAdapter, caughtInCatch, caughtByWindowOnerror; - Test.adapter = { - exception(error) { - caughtInAdapter = error; + try { + runThatThrowsAsync(); + } catch (e) { + caughtInCatch = e; } - }; - window.onerror = function(message) { - caughtByWindowOnerror = message; - // prevent "bubbling" and therefore failing the test - return true; - }; + setTimeout(() => { + assert.equal( + caughtInAdapter, + undefined, + 'test adapter should never catch errors in run loops' + ); + assert.equal( + caughtInCatch, + undefined, + 'a "normal" try/catch should never catch errors in an async run' + ); - try { - runThatThrowsAsync(); - } catch(e) { - caughtInCatch = e; + assert.pushResult({ + result: /Error for testing error handling/.test( + caughtByWindowOnerror + ), + actual: caughtByWindowOnerror, + expected: 'to include `Error for testing error handling`', + message: + 'error should bubble out to window.onerror, and therefore fail tests (due to QUnit implementing window.onerror)' + }); + + done(); + }, 20); } - setTimeout(() => { - assert.equal(caughtInAdapter, undefined, 'test adapter should never catch errors in run loops'); - assert.equal(caughtInCatch, undefined, 'a "normal" try/catch should never catch errors in an async run'); + ['@test when both Ember.onerror and TestAdapter are registered - async run']( + assert + ) { + assert.expect(1); + let done = assert.async(); + + Test.adapter = { + exception() { + assert.notOk( + true, + 'Adapter.exception is not called for errors thrown in next' + ); + } + }; - assert.pushResult({ - result: /Error for testing error handling/.test(caughtByWindowOnerror), - actual: caughtByWindowOnerror, - expected: 'to include `Error for testing error handling`', - message: 'error should bubble out to window.onerror, and therefore fail tests (due to QUnit implementing window.onerror)' + setOnerror(function() { + assert.ok(true, 'onerror is invoked for errors thrown in next/later'); }); - done(); - }, 20); - } - - ['@test when both Ember.onerror and TestAdapter are registered - async run'](assert) { - assert.expect(1); - let done = assert.async(); - - Test.adapter ={ - exception() { - assert.notOk(true, 'Adapter.exception is not called for errors thrown in next'); - } - }; - - setOnerror(function() { - assert.ok(true, 'onerror is invoked for errors thrown in next/later'); - }); - - runThatThrowsAsync(); - setTimeout(done, 10); + runThatThrowsAsync(); + setTimeout(done, 10); + } } -}); - +); function testAdapter(message, generatePromise, timeout = 10) { return class PromiseFailureTests extends AdapterSetupAndTearDown { - [`@test ${message} when TestAdapter without \`exception\` method is present - rsvp`](assert) { + [`@test ${message} when TestAdapter without \`exception\` method is present - rsvp`]( + assert + ) { assert.expect(1); let thrown = new Error('the error'); @@ -230,7 +283,8 @@ function testAdapter(message, generatePromise, timeout = 10) { result: /the error/.test(message), actual: message, expected: 'to include `the error`', - message: 'error should bubble out to window.onerror, and therefore fail tests (due to QUnit implementing window.onerror)' + message: + 'error should bubble out to window.onerror, and therefore fail tests (due to QUnit implementing window.onerror)' }); // prevent "bubbling" and therefore failing the test @@ -241,10 +295,12 @@ function testAdapter(message, generatePromise, timeout = 10) { // RSVP.Promise's are configured to settle within the run loop, this // ensures that run loop has completed - return new RSVP.Promise((resolve) => setTimeout(resolve, timeout)); + return new RSVP.Promise(resolve => setTimeout(resolve, timeout)); } - [`@test ${message} when both Ember.onerror and TestAdapter without \`exception\` method are present - rsvp`](assert) { + [`@test ${message} when both Ember.onerror and TestAdapter without \`exception\` method are present - rsvp`]( + assert + ) { assert.expect(1); let thrown = new Error('the error'); @@ -257,7 +313,8 @@ function testAdapter(message, generatePromise, timeout = 10) { result: /the error/.test(error.message), actual: error.message, expected: 'to include `the error`', - message: 'error should bubble out to window.onerror, and therefore fail tests (due to QUnit implementing window.onerror)' + message: + 'error should bubble out to window.onerror, and therefore fail tests (due to QUnit implementing window.onerror)' }); }); @@ -265,7 +322,7 @@ function testAdapter(message, generatePromise, timeout = 10) { // RSVP.Promise's are configured to settle within the run loop, this // ensures that run loop has completed - return new RSVP.Promise((resolve) => setTimeout(resolve, timeout)); + return new RSVP.Promise(resolve => setTimeout(resolve, timeout)); } [`@test ${message} when TestAdapter is present - rsvp`](assert) { @@ -275,7 +332,11 @@ function testAdapter(message, generatePromise, timeout = 10) { let thrown = new Error('the error'); Test.adapter = QUnitAdapter.create({ exception(error) { - assert.strictEqual(error, thrown, 'Adapter.exception is called for errors thrown in RSVP promises'); + assert.strictEqual( + error, + thrown, + 'Adapter.exception is called for errors thrown in RSVP promises' + ); } }); @@ -283,68 +344,100 @@ function testAdapter(message, generatePromise, timeout = 10) { // RSVP.Promise's are configured to settle within the run loop, this // ensures that run loop has completed - return new RSVP.Promise((resolve) => setTimeout(resolve, timeout)); + return new RSVP.Promise(resolve => setTimeout(resolve, timeout)); } - [`@test ${message} when both Ember.onerror and TestAdapter are present - rsvp`](assert) { + [`@test ${message} when both Ember.onerror and TestAdapter are present - rsvp`]( + assert + ) { assert.expect(1); let thrown = new Error('the error'); Test.adapter = QUnitAdapter.create({ exception(error) { - assert.strictEqual(error, thrown, 'Adapter.exception is called for errors thrown in RSVP promises'); + assert.strictEqual( + error, + thrown, + 'Adapter.exception is called for errors thrown in RSVP promises' + ); } }); setOnerror(function() { - assert.notOk(true, 'Ember.onerror is not called if Test.adapter does not rethrow'); + assert.notOk( + true, + 'Ember.onerror is not called if Test.adapter does not rethrow' + ); }); generatePromise(thrown); // RSVP.Promise's are configured to settle within the run loop, this // ensures that run loop has completed - return new RSVP.Promise((resolve) => setTimeout(resolve, timeout)); + return new RSVP.Promise(resolve => setTimeout(resolve, timeout)); } - [`@test ${message} when both Ember.onerror and TestAdapter are present - rsvp`](assert) { + [`@test ${message} when both Ember.onerror and TestAdapter are present - rsvp`]( + assert + ) { assert.expect(2); let thrown = new Error('the error'); Test.adapter = QUnitAdapter.create({ exception(error) { - assert.strictEqual(error, thrown, 'Adapter.exception is called for errors thrown in RSVP promises'); + assert.strictEqual( + error, + thrown, + 'Adapter.exception is called for errors thrown in RSVP promises' + ); throw error; } }); setOnerror(function(error) { - assert.strictEqual(error, thrown, 'Ember.onerror is called for errors thrown in RSVP promises if Test.adapter rethrows'); + assert.strictEqual( + error, + thrown, + 'Ember.onerror is called for errors thrown in RSVP promises if Test.adapter rethrows' + ); }); generatePromise(thrown); // RSVP.Promise's are configured to settle within the run loop, this // ensures that run loop has completed - return new RSVP.Promise((resolve) => setTimeout(resolve, timeout)); + return new RSVP.Promise(resolve => setTimeout(resolve, timeout)); } }; } -moduleFor('Adapter Errors: .then callback', testAdapter('errors in promise constructor', (error) => { - new RSVP.Promise(() => { - throw error; - }); -})); - -moduleFor('Adapter Errors: Promise Contructor', testAdapter('errors in promise constructor', (error) => { - RSVP.resolve().then(() => { - throw error; - }); -})); +moduleFor( + 'Adapter Errors: .then callback', + testAdapter('errors in promise constructor', error => { + new RSVP.Promise(() => { + throw error; + }); + }) +); -moduleFor('Adapter Errors: Promise chain .then callback', testAdapter('errors in promise constructor', (error) => { - new RSVP.Promise((resolve) => setTimeout(resolve, 10)).then(() => { - throw error; - }); -}, 20)); +moduleFor( + 'Adapter Errors: Promise Contructor', + testAdapter('errors in promise constructor', error => { + RSVP.resolve().then(() => { + throw error; + }); + }) +); + +moduleFor( + 'Adapter Errors: Promise chain .then callback', + testAdapter( + 'errors in promise constructor', + error => { + new RSVP.Promise(resolve => setTimeout(resolve, 10)).then(() => { + throw error; + }); + }, + 20 + ) +); diff --git a/packages/ember-testing/tests/ext/rsvp_test.js b/packages/ember-testing/tests/ext/rsvp_test.js index f5f8e354dde..b40572d2fd1 100644 --- a/packages/ember-testing/tests/ext/rsvp_test.js +++ b/packages/ember-testing/tests/ext/rsvp_test.js @@ -11,107 +11,114 @@ const originalTestingFlag = isTesting(); let asyncStarted = 0; let asyncEnded = 0; -moduleFor('ember-testing RSVP', class extends AbstractTestCase { - constructor() { - super(); - setTesting(true); - setAdapter({ - asyncStart() { - asyncStarted++; - }, - asyncEnd() { - asyncEnded++; - } - }); - } - - teardown() { - asyncStarted = 0; - asyncEnded = 0; - setAdapter(originalTestAdapter); - setTesting(originalTestingFlag); - } - - ['@test given `Ember.testing = true`, correctly informs the test suite about async steps'](assert) { - let done = assert.async(); - assert.expect(19); - - assert.ok(!getCurrentRunLoop(), 'expect no run-loop'); +moduleFor( + 'ember-testing RSVP', + class extends AbstractTestCase { + constructor() { + super(); + setTesting(true); + setAdapter({ + asyncStart() { + asyncStarted++; + }, + asyncEnd() { + asyncEnded++; + } + }); + } - setTesting(true); + teardown() { + asyncStarted = 0; + asyncEnded = 0; + setAdapter(originalTestAdapter); + setTesting(originalTestingFlag); + } - assert.equal(asyncStarted, 0); - assert.equal(asyncEnded, 0); + ['@test given `Ember.testing = true`, correctly informs the test suite about async steps']( + assert + ) { + let done = assert.async(); + assert.expect(19); - let user = RSVP.Promise.resolve({ name: 'tomster' }); + assert.ok(!getCurrentRunLoop(), 'expect no run-loop'); - assert.equal(asyncStarted, 0); - assert.equal(asyncEnded, 0); + setTesting(true); - user.then(function(user) { - assert.equal(asyncStarted, 1); - assert.equal(asyncEnded, 1); + assert.equal(asyncStarted, 0); + assert.equal(asyncEnded, 0); - assert.equal(user.name, 'tomster'); + let user = RSVP.Promise.resolve({ name: 'tomster' }); - return RSVP.Promise.resolve(1).then(function() { - assert.equal(asyncStarted, 1); - assert.equal(asyncEnded, 1); - }); - }).then(function() { - assert.equal(asyncStarted, 1); - assert.equal(asyncEnded, 1); + assert.equal(asyncStarted, 0); + assert.equal(asyncEnded, 0); - return new RSVP.Promise(function(resolve) { - setTimeout(function() { + user + .then(function(user) { assert.equal(asyncStarted, 1); assert.equal(asyncEnded, 1); - resolve({ name: 'async tomster' }); + assert.equal(user.name, 'tomster'); - assert.equal(asyncStarted, 2); + return RSVP.Promise.resolve(1).then(function() { + assert.equal(asyncStarted, 1); + assert.equal(asyncEnded, 1); + }); + }) + .then(function() { + assert.equal(asyncStarted, 1); assert.equal(asyncEnded, 1); - }, 0); - }); - }).then(function(user) { - assert.equal(user.name, 'async tomster'); - assert.equal(asyncStarted, 2); - assert.equal(asyncEnded, 2); - done(); - }); - } -}); + return new RSVP.Promise(function(resolve) { + setTimeout(function() { + assert.equal(asyncStarted, 1); + assert.equal(asyncEnded, 1); -moduleFor('TestPromise', class extends AbstractTestCase { + resolve({ name: 'async tomster' }); - ['does not throw error when falsy value passed to then'](assert) { - assert.expect(1); - return new TestPromise(function(resolve) { - resolve(); - }) - .then(null) - .then(function() { - assert.ok(true); - }); + assert.equal(asyncStarted, 2); + assert.equal(asyncEnded, 1); + }, 0); + }); + }) + .then(function(user) { + assert.equal(user.name, 'async tomster'); + assert.equal(asyncStarted, 2); + assert.equal(asyncEnded, 2); + done(); + }); + } } +); + +moduleFor( + 'TestPromise', + class extends AbstractTestCase { + ['does not throw error when falsy value passed to then'](assert) { + assert.expect(1); + return new TestPromise(function(resolve) { + resolve(); + }) + .then(null) + .then(function() { + assert.ok(true); + }); + } + + ['able to get last Promise'](assert) { + assert.expect(2); + + var p1 = new TestPromise(function(resolve) { + resolve(); + }).then(function() { + assert.ok(true); + }); - ['able to get last Promise'](assert) { - assert.expect(2); - - var p1 = new TestPromise(function(resolve) { - resolve(); - }) - .then(function() { - assert.ok(true); - }); - - var p2 = new TestPromise(function(resolve) { - resolve(); - }); + var p2 = new TestPromise(function(resolve) { + resolve(); + }); - assert.deepEqual(getLastPromise(), p2); - return p1; + assert.deepEqual(getLastPromise(), p2); + return p1; + } } - -}); +); diff --git a/packages/ember-testing/tests/helper_registration_test.js b/packages/ember-testing/tests/helper_registration_test.js index 27e672e1a91..9ce5e862adb 100644 --- a/packages/ember-testing/tests/helper_registration_test.js +++ b/packages/ember-testing/tests/helper_registration_test.js @@ -37,51 +37,60 @@ function destroyApp() { } } -moduleFor('Test - registerHelper/unregisterHelper', class extends AbstractTestCase { - teardown() { - Test.adapter = originalAdapter; - destroyApp(); +moduleFor( + 'Test - registerHelper/unregisterHelper', + class extends AbstractTestCase { + teardown() { + Test.adapter = originalAdapter; + destroyApp(); + } + + ['@test Helper gets registered'](assert) { + assert.expect(2); + + registerHelper(); + setupApp(); + + assert.ok(App.testHelpers.boot); + assert.ok(helperContainer.boot); + } + + ['@test Helper is ran when called'](assert) { + let done = assert.async(); + assert.expect(1); + + registerHelper(); + setupApp(); + + App.testHelpers + .boot() + .then(function() { + assert.ok(appBooted); + }) + .finally(done); + } + + ['@test Helper can be unregistered'](assert) { + assert.expect(4); + + registerHelper(); + setupApp(); + + assert.ok(App.testHelpers.boot); + assert.ok(helperContainer.boot); + + unregisterHelper(); + + setupApp(); + + assert.ok( + !App.testHelpers.boot, + 'once unregistered the helper is not added to App.testHelpers' + ); + assert.ok( + !helperContainer.boot, + 'once unregistered the helper is not added to the helperContainer' + ); + } } - - ['@test Helper gets registered'](assert) { - assert.expect(2); - - registerHelper(); - setupApp(); - - assert.ok(App.testHelpers.boot); - assert.ok(helperContainer.boot); - } - - ['@test Helper is ran when called'](assert) { - let done = assert.async(); - assert.expect(1); - - registerHelper(); - setupApp(); - - App.testHelpers.boot() - .then(function() { - assert.ok(appBooted); - }) - .finally(done); - } - - ['@test Helper can be unregistered'](assert) { - assert.expect(4); - - registerHelper(); - setupApp(); - - assert.ok(App.testHelpers.boot); - assert.ok(helperContainer.boot); - - unregisterHelper(); - - setupApp(); - - assert.ok(!App.testHelpers.boot, 'once unregistered the helper is not added to App.testHelpers'); - assert.ok(!helperContainer.boot, 'once unregistered the helper is not added to the helperContainer'); - } -}); - +); diff --git a/packages/ember-testing/tests/helpers_test.js b/packages/ember-testing/tests/helpers_test.js index 24cf0cfec4f..0f9c25d0c0b 100644 --- a/packages/ember-testing/tests/helpers_test.js +++ b/packages/ember-testing/tests/helpers_test.js @@ -5,14 +5,9 @@ import { } from 'internal-test-helpers'; import { Route } from 'ember-routing'; -import { - Controller, - RSVP -} from 'ember-runtime'; +import { Controller, RSVP } from 'ember-runtime'; import { later } from 'ember-metal'; -import { - Component, -} from 'ember-glimmer'; +import { Component } from 'ember-glimmer'; import { jQueryDisabled } from 'ember-views'; import Test from '../test'; @@ -22,20 +17,14 @@ import { pendingRequests, incrementPendingRequests, decrementPendingRequests, - clearPendingRequests, + clearPendingRequests } from '../test/pending_requests'; -import { - setAdapter, - getAdapter -} from '../test/adapter'; -import { - registerWaiter, - unregisterWaiter -} from '../test/waiters'; +import { setAdapter, getAdapter } from '../test/adapter'; +import { registerWaiter, unregisterWaiter } from '../test/waiters'; import { getDebugFunction, setDebugFunction } from 'ember-debug'; var originalInfo = getDebugFunction('info'); -var noop = function(){}; +var noop = function() {}; function registerHelper() { Test.registerHelper('LeakyMcLeakLeak', () => {}); @@ -48,8 +37,12 @@ function customEvent(name, xhr) { } function assertHelpers(assert, application, helperContainer, expected) { - if (!helperContainer) { helperContainer = window; } - if (expected === undefined) { expected = true; } + if (!helperContainer) { + helperContainer = window; + } + if (expected === undefined) { + expected = true; + } function checkHelperPresent(helper, expected) { var presentInHelperContainer = !!helperContainer[helper]; @@ -57,11 +50,13 @@ function assertHelpers(assert, application, helperContainer, expected) { assert.ok( presentInHelperContainer === expected, - 'Expected \'' + helper + '\' to be present in the helper container (defaults to window).' + "Expected '" + + helper + + "' to be present in the helper container (defaults to window)." ); assert.ok( presentInTestHelpers === expected, - 'Expected \'' + helper + '\' to be present in App.testHelpers.' + "Expected '" + helper + "' to be present in App.testHelpers." ); } @@ -78,7 +73,6 @@ function assertNoHelpers(assert, application, helperContainer) { } class HelpersTestCase extends AutobootApplicationTestCase { - constructor() { super(); this._originalAdapter = getAdapter(); @@ -94,7 +88,6 @@ class HelpersTestCase extends AutobootApplicationTestCase { } super.teardown(); } - } class HelpersApplicationTestCase extends HelpersTestCase { @@ -109,1155 +102,1318 @@ class HelpersApplicationTestCase extends HelpersTestCase { } if (!jQueryDisabled) { - moduleFor('ember-testing: Helper setup', class extends HelpersTestCase { + moduleFor( + 'ember-testing: Helper setup', + class extends HelpersTestCase { + [`@test Ember.Application#injectTestHelpers/#removeTestHelper`](assert) { + this.runTask(() => { + this.createApplication(); + }); - [`@test Ember.Application#injectTestHelpers/#removeTestHelper`](assert) { - this.runTask(() => { - this.createApplication(); - }); + assertNoHelpers(assert, this.application); - assertNoHelpers(assert, this.application); + registerHelper(); - registerHelper(); + this.application.injectTestHelpers(); - this.application.injectTestHelpers(); + assertHelpers(assert, this.application); - assertHelpers(assert, this.application); + assert.ok( + Test.Promise.prototype.LeakyMcLeakLeak, + 'helper in question SHOULD be present' + ); - assert.ok( - Test.Promise.prototype.LeakyMcLeakLeak, - 'helper in question SHOULD be present' - ); + this.application.removeTestHelpers(); - this.application.removeTestHelpers(); + assertNoHelpers(assert, this.application); - assertNoHelpers(assert, this.application); + assert.equal( + Test.Promise.prototype.LeakyMcLeakLeak, + undefined, + 'should NOT leak test promise extensions' + ); + } - assert.equal( - Test.Promise.prototype.LeakyMcLeakLeak, undefined, - 'should NOT leak test promise extensions' - ); - } + [`@test Ember.Application#setupForTesting`](assert) { + this.runTask(() => { + this.createApplication(); + this.application.setupForTesting(); + }); - [`@test Ember.Application#setupForTesting`](assert) { - this.runTask(() => { - this.createApplication(); - this.application.setupForTesting(); - }); + let routerInstance = this.applicationInstance.lookup('router:main'); + assert.equal(routerInstance.location, 'none'); + } - let routerInstance = this.applicationInstance.lookup('router:main'); - assert.equal(routerInstance.location, 'none'); - } + [`@test Ember.Application.setupForTesting sets the application to 'testing'`]( + assert + ) { + this.runTask(() => { + this.createApplication(); + this.application.setupForTesting(); + }); - [`@test Ember.Application.setupForTesting sets the application to 'testing'`](assert) { - this.runTask(() => { - this.createApplication(); - this.application.setupForTesting(); - }); + assert.equal( + this.application.testing, + true, + 'Application instance is set to testing.' + ); + } - assert.equal( - this.application.testing, true, - 'Application instance is set to testing.' - ); - } + [`@test Ember.Application.setupForTesting leaves the system in a deferred state.`]( + assert + ) { + this.runTask(() => { + this.createApplication(); + this.application.setupForTesting(); + }); - [`@test Ember.Application.setupForTesting leaves the system in a deferred state.`](assert) { - this.runTask(() => { - this.createApplication(); - this.application.setupForTesting(); - }); + assert.equal( + this.application._readinessDeferrals, + 1, + 'App is in deferred state after setupForTesting.' + ); + } - assert.equal( - this.application._readinessDeferrals, 1, - 'App is in deferred state after setupForTesting.' - ); - } + [`@test App.reset() after Application.setupForTesting leaves the system in a deferred state.`]( + assert + ) { + this.runTask(() => { + this.createApplication(); + this.application.setupForTesting(); + }); - [`@test App.reset() after Application.setupForTesting leaves the system in a deferred state.`](assert) { - this.runTask(() => { - this.createApplication(); - this.application.setupForTesting(); - }); + assert.equal( + this.application._readinessDeferrals, + 1, + 'App is in deferred state after setupForTesting.' + ); - assert.equal( - this.application._readinessDeferrals, 1, - 'App is in deferred state after setupForTesting.' - ); + this.application.reset(); - this.application.reset(); + assert.equal( + this.application._readinessDeferrals, + 1, + 'App is in deferred state after setupForTesting.' + ); + } - 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 Ember.Application#injectTestHelpers calls callbacks registered with onInjectHelpers`](assert) { - let injected = 0; + Test.onInjectHelpers(() => { + injected++; + }); - Test.onInjectHelpers(() => { - injected++; - }); + this.runTask(() => { + this.createApplication(); + this.application.setupForTesting(); + }); - this.runTask(() => { - this.createApplication(); - this.application.setupForTesting(); - }); + assert.equal( + injected, + 0, + 'onInjectHelpers are not called before injectTestHelpers' + ); - assert.equal( - injected, 0, - 'onInjectHelpers are not called before injectTestHelpers' - ); + this.application.injectTestHelpers(); - this.application.injectTestHelpers(); + assert.equal( + injected, + 1, + 'onInjectHelpers are called after injectTestHelpers' + ); + } - assert.equal( - injected, 1, - 'onInjectHelpers are called after injectTestHelpers' - ); - } + [`@test Ember.Application#injectTestHelpers adds helpers to provided object.`]( + assert + ) { + let helpers = {}; - [`@test Ember.Application#injectTestHelpers adds helpers to provided object.`](assert) { - let helpers = {}; + this.runTask(() => { + this.createApplication(); + this.application.setupForTesting(); + }); - this.runTask(() => { - this.createApplication(); - this.application.setupForTesting(); - }); + this.application.injectTestHelpers(helpers); - this.application.injectTestHelpers(helpers); + assertHelpers(assert, this.application, helpers); - assertHelpers(assert, this.application, helpers); + this.application.removeTestHelpers(); - this.application.removeTestHelpers(); - - assertNoHelpers(assert, this.application, helpers); - } + assertNoHelpers(assert, this.application, helpers); + } - [`@test Ember.Application#removeTestHelpers resets the helperContainer\'s original values`](assert) { - let helpers = { visit: 'snazzleflabber' }; + [`@test Ember.Application#removeTestHelpers resets the helperContainer\'s original values`]( + assert + ) { + let helpers = { visit: 'snazzleflabber' }; - this.runTask(() => { - this.createApplication(); - this.application.setupForTesting(); - }); + this.runTask(() => { + this.createApplication(); + this.application.setupForTesting(); + }); - this.application.injectTestHelpers(helpers); + this.application.injectTestHelpers(helpers); - assert.notEqual( - helpers.visit, 'snazzleflabber', - 'helper added to container' - ); - this.application.removeTestHelpers(); + assert.notEqual( + helpers.visit, + 'snazzleflabber', + 'helper added to container' + ); + this.application.removeTestHelpers(); - assert.equal( - helpers.visit, 'snazzleflabber', - 'original value added back to container' - ); + 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); - moduleFor('ember-testing: Helper methods', class extends HelpersApplicationTestCase { + let counter = 0; + function waiter() { + return ++counter > 2; + } - [`@test 'wait' respects registerWaiters`](assert) { - assert.expect(3); + let other = 0; + function otherWaiter() { + return ++other > 2; + } - let counter = 0; - function waiter() { - return ++counter > 2; - } + this.runTask(() => { + this.application.advanceReadiness(); + }); - let other = 0; - function otherWaiter() { - return ++other > 2; + 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); + }); } - this.runTask(() => { - this.application.advanceReadiness(); - }); - - registerWaiter(waiter); - registerWaiter(otherWaiter); + [`@test 'visit' advances readiness.`](assert) { + assert.expect(2); - 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' + this.application._readinessDeferrals, + 1, + 'App is in deferred state after setupForTesting.' ); - }).finally(() => { - unregisterWaiter(otherWaiter); - }); - } - [`@test 'visit' advances readiness.`](assert) { - assert.expect(2); + return this.application.testHelpers.visit('/').then(() => { + assert.equal( + this.application._readinessDeferrals, + 0, + `App's readiness was advanced by visit.` + ); + }); + } - assert.equal( - this.application._readinessDeferrals, 1, - 'App is in deferred state after setupForTesting.' - ); + [`@test 'wait' helper can be passed a resolution value`](assert) { + assert.expect(4); - return this.application.testHelpers.visit('/').then(() => { - assert.equal( - this.application._readinessDeferrals, 0, - `App's readiness was advanced by visit.` - ); - }); - } - - [`@test 'wait' helper can be passed a resolution value`](assert) { - assert.expect(4); + this.runTask(() => { + this.application.advanceReadiness(); + }); - this.runTask(() => { - this.application.advanceReadiness(); - }); + let promiseObjectValue = {}; + let objectValue = {}; + let { application: { testHelpers } } = this; + return testHelpers + .wait('text') + .then(val => { + assert.equal(val, 'text', 'can resolve to a string'); + return testHelpers.wait(1); + }) + .then(val => { + assert.equal(val, 1, 'can resolve to an integer'); + return testHelpers.wait(objectValue); + }) + .then(val => { + assert.equal(val, objectValue, 'can resolve to an object'); + return testHelpers.wait(RSVP.resolve(promiseObjectValue)); + }) + .then(val => { + assert.equal( + val, + promiseObjectValue, + 'can resolve to a promise resolution value' + ); + }); + } - 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); + } + }); + } + }) ); - }); - } - [`@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.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', ` + this.addTemplate( + 'index', + ` {{#index-wrapper}} {{input type="text"}} {{x-checkbox type="checkbox"}} {{textarea}}
{{/index-wrapper}}')); - `); - - this.runTask(() => { - this.application.advanceReadiness(); - }); - - let events; - let {application: {testHelpers}} = this; - return testHelpers.wait().then(() => { - events = []; - return testHelpers.click('.index-wrapper'); - }).then(() => { - assert.deepEqual( - events, ['mousedown', 'mouseup', 'click'], - 'fires events in order' - ); - }).then(() => { - events = []; - return testHelpers.click('.index-wrapper input[type=text]'); - }).then(() => { - assert.deepEqual( - events, ['mousedown', 'focusin', 'mouseup', 'click'], - 'fires focus events on inputs' + ` ); - }).then(() => { - events = []; - return testHelpers.click('.index-wrapper textarea'); - }).then(() => { - assert.deepEqual( - events, ['mousedown', 'focusin', 'mouseup', 'click'], - 'fires focus events on textareas' - ); - }).then(() => { - events = []; - return testHelpers.click('.index-wrapper div'); - }).then(() => { - assert.deepEqual( - events, ['mousedown', 'focusin', 'mouseup', 'click'], - 'fires focus events on contenteditable' - ); - }).then(() => { - events = []; - return testHelpers.click('.index-wrapper input[type=checkbox]'); - }).then(() => { - // i.e. mousedown, mouseup, change:true, click, click:true - // Firefox differs so we can't assert the exact ordering here. - // See https://bugzilla.mozilla.org/show_bug.cgi?id=843554. - assert.equal( - events.length, 5, - 'fires click and change on checkboxes' - ); - }); - } - [`@test 'click' triggers native events with simulated X/Y coordinates`](assert) { - assert.expect(15); + this.runTask(() => { + this.application.advanceReadiness(); + }); - this.add('component:index-wrapper', Component.extend({ - classNames: 'index-wrapper', + 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' + ); + }); + } - didInsertElement() { - let pushEvent = e => events.push(e); - this.element.addEventListener('mousedown', pushEvent); - this.element.addEventListener('mouseup', pushEvent); - this.element.addEventListener('click', pushEvent); - } - })); + [`@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', ` + this.addTemplate( + 'index', + ` {{#index-wrapper}}some text{{/index-wrapper}} - `); - - this.runTask(() => { - this.application.advanceReadiness(); - }); - - let events; - let {application: {testHelpers: {wait, click}}} = this; - return wait().then(() => { - events = []; - return click('.index-wrapper'); - }).then(() => { - events.forEach(e => { - assert.ok( - e instanceof window.Event, - 'The event is an instance of MouseEvent' - ); - assert.ok( - typeof e.screenX === 'number', - 'screenX is correct' - ); - assert.ok( - typeof e.screenY === 'number', - 'screenY is correct' - ); - assert.ok( - typeof e.clientX === 'number', - 'clientX is correct' - ); - assert.ok( - typeof e.clientY === 'number', - 'clientY is correct' - ); + ` + ); + + this.runTask(() => { + this.application.advanceReadiness(); }); - }); - } - [`@test 'triggerEvent' with mouseenter triggers native events with simulated X/Y coordinates`](assert) { - assert.expect(5); + 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'); + }); + }); + } - let evt; - this.add('component:index-wrapper', Component.extend({ - classNames: 'index-wrapper', - didInsertElement() { - this.element.addEventListener('mouseenter', e => evt = e); - } - })); + [`@test 'triggerEvent' with mouseenter triggers native events with simulated X/Y coordinates`]( + assert + ) { + assert.expect(5); + + let evt; + this.add( + 'component:index-wrapper', + Component.extend({ + classNames: 'index-wrapper', + didInsertElement() { + this.element.addEventListener('mouseenter', e => (evt = e)); + } + }) + ); - this.addTemplate('index', `{{#index-wrapper}}some text{{/index-wrapper}}`); + this.addTemplate( + 'index', + `{{#index-wrapper}}some text{{/index-wrapper}}` + ); - this.runTask(() => { - this.application.advanceReadiness(); - }); + this.runTask(() => { + this.application.advanceReadiness(); + }); - let {application: {testHelpers: {wait, triggerEvent}}} = this; - return wait().then(() => { - return triggerEvent('.index-wrapper', 'mouseenter'); - }).then(() => { - assert.ok( - evt instanceof window.Event, - 'The event is an instance of MouseEvent' - ); - assert.ok( - typeof evt.screenX === 'number', - 'screenX is correct' - ); - assert.ok( - typeof evt.screenY === 'number', - 'screenY is correct' - ); - assert.ok( - typeof evt.clientX === 'number', - 'clientX is correct' - ); - assert.ok( - typeof evt.clientY === 'number', - 'clientY is correct' - ); - }); - } + 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); - [`@test 'wait' waits for outstanding timers`](assert) { - assert.expect(1); + this.runTask(() => { + this.application.advanceReadiness(); + }); - this.runTask(() => { - this.application.advanceReadiness(); - }); + let waitDone = false; + later(() => { + waitDone = true; + }, 20); - 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.' + ); + }); + } - 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); - [`@test 'wait' respects registerWaiters with optional context`](assert) { - assert.expect(3); + let obj = { + counter: 0, + ready() { + return ++this.counter > 2; + } + }; - let obj = { - counter: 0, - ready() { - return ++this.counter > 2; + let other = 0; + function otherWaiter() { + return ++other > 2; } - }; - let other = 0; - function otherWaiter() { - return ++other > 2; + this.runTask(() => { + this.application.advanceReadiness(); + }); + + registerWaiter(obj, obj.ready); + registerWaiter(otherWaiter); + + let { application: { testHelpers: { wait } } } = this; + return wait() + .then(() => { + assert.equal( + obj.ready(), + true, + 'should not resolve until our waiter is ready' + ); + unregisterWaiter(obj, obj.ready); + obj.counter = 0; + return wait(); + }) + .then(() => { + assert.equal( + obj.counter, + 0, + 'the unregistered waiter should still be at 0' + ); + assert.equal( + otherWaiter(), + true, + 'other waiter should still be registered' + ); + }) + .finally(() => { + unregisterWaiter(otherWaiter); + }); } - this.runTask(() => { - this.application.advanceReadiness(); - }); + [`@test 'wait' does not error if routing has not begun`](assert) { + assert.expect(1); - registerWaiter(obj, obj.ready); - registerWaiter(otherWaiter); + return this.application.testHelpers.wait().then(() => { + assert.ok(true, 'should not error without `visit`'); + }); + } - 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' + [`@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)); + } + }) ); - }).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); + this.addTemplate('index', `{{index-wrapper}}`); + this.addTemplate( + 'components/index-wrapper', + ` + {{input type="text" id="scope" class="input"}} + ` + ); - 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.runTask(() => { + this.application.advanceReadiness(); + }); - this.addTemplate('index', `{{index-wrapper}}`); - this.addTemplate('components/index-wrapper', ` - {{input type="text" id="scope" class="input"}} - `); - - this.runTask(() => { - this.application.advanceReadiness(); - }); - - let {application: {testHelpers: {wait, triggerEvent}}} = this; - return wait().then(() => { - return triggerEvent('.input', 'keydown', { keyCode: 13 }); - }).then(() => { - assert.equal(event.keyCode, 13, 'options were passed'); - assert.equal(event.type, 'keydown', 'correct event was triggered'); - assert.equal(event.target.getAttribute('id'), 'scope', 'triggered on the correct element'); - }); - } + 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); - } - })); + [`@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', ` + this.addTemplate( + 'components/index-wrapper', + ` {{input type="text" id="outside-scope" class="input"}}
{{input type="text" id="inside-scope" class="input"}}
- `); - this.addTemplate('index', `{{index-wrapper}}`); - - this.runTask(() => { - this.application.advanceReadiness(); - }); - - let {application: {testHelpers: {wait, triggerEvent}}} = this; - return wait().then(() => { - return triggerEvent('.input', '#limited', 'blur'); - }).then(() => { - assert.equal( - event.type, 'blur', - 'correct event was triggered' - ); - assert.equal( - event.target.getAttribute('id'), 'inside-scope', - 'triggered on the correct element' + ` ); - }); - } + this.addTemplate('index', `{{index-wrapper}}`); - [`@test 'triggerEvent' can be used to trigger arbitrary events`](assert) { - assert.expect(2); + this.runTask(() => { + this.application.advanceReadiness(); + }); - 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); - } - })); + 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', ` + this.addTemplate( + 'components/index-wrapper', + ` {{input type="text" id="foo"}} - `); - this.addTemplate('index', `{{index-wrapper}}`); + ` + ); + this.addTemplate('index', `{{index-wrapper}}`); - this.runTask(() => { - this.application.advanceReadiness(); - }); + this.runTask(() => { + this.application.advanceReadiness(); + }); - let {application: {testHelpers: {wait, triggerEvent}}} = this; - return wait().then(() => { - return triggerEvent('#foo', 'blur'); - }).then(() => { - assert.equal( - event.type, 'blur', - 'correct event was triggered' - ); - assert.equal( - event.target.getAttribute('id'), 'foo', - 'triggered on the correct element' - ); - }); - } + 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); + [`@test 'fillIn' takes context into consideration`](assert) { + assert.expect(2); - this.addTemplate('index', ` + this.addTemplate( + 'index', + `
{{input type="text" id="first" class="current"}}
{{input type="text" id="second" class="current"}} - `); + ` + ); - this.runTask(() => { - this.application.advanceReadiness(); - }); + this.runTask(() => { + this.application.advanceReadiness(); + }); - let {application: {testHelpers: {visit, fillIn, andThen, find}}} = this; - visit('/'); - fillIn('.current', '#parent', 'current value'); + 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, ''); - }); - } + 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; + [`@test 'fillIn' focuses on the element`](assert) { + let wasFocused = false; - this.add('route:application', Route.extend({ - actions: { - wasFocused() { - wasFocused = true; - } - } - })); + this.add( + 'route:application', + Route.extend({ + actions: { + wasFocused() { + wasFocused = true; + } + } + }) + ); - this.addTemplate('index', ` + this.addTemplate( + 'index', + `
{{input type="text" id="first" focus-in="wasFocused"}}
' - `); + ` + ); - this.runTask(() => { - this.application.advanceReadiness(); - }); + this.runTask(() => { + this.application.advanceReadiness(); + }); - let {application: {testHelpers: {visit, fillIn, andThen, find, wait}}} = this; - visit('/'); - fillIn('#first', 'current value'); - andThen(() => { - assert.ok(wasFocused, 'focusIn event was triggered'); + 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' - ); - }); + assert.equal(find('#first')[0].value, 'current value'); + }); - return wait(); - } + 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); - } - } - })); + [`@test 'fillIn' fires 'input' and 'change' events in the proper order`]( + assert + ) { + assert.expect(1); + + let events = []; + this.add( + 'controller:index', + Controller.extend({ + actions: { + oninputHandler(e) { + events.push(e.type); + }, + onchangeHandler(e) { + events.push(e.type); + } + } + }) + ); - this.addTemplate('index', ` + this.addTemplate( + 'index', + ` - `); - - this.runTask(() => { - this.application.advanceReadiness(); - }); + ` + ); - let {application: {testHelpers: {visit, fillIn, andThen, wait}}} = this; + this.runTask(() => { + this.application.advanceReadiness(); + }); - visit('/'); - fillIn('#first', 'current value'); - andThen(() => { - assert.deepEqual(events, ['input', 'change'], '`input` and `change` events are fired in the proper order'); - }); + 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(); - } + return wait(); + } - [`@test 'fillIn' only sets the value in the first matched element`](assert) { - this.addTemplate('index', ` + [`@test 'fillIn' only sets the value in the first matched element`]( + assert + ) { + this.addTemplate( + 'index', + ` - `); + ` + ); - this.runTask(() => { - this.application.advanceReadiness(); - }); + this.runTask(() => { + this.application.advanceReadiness(); + }); - let {application: {testHelpers: {visit, fillIn, find, andThen, wait}}} = this; + 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, '' - ); - }); + visit('/'); + fillIn('input.in-test', 'new value'); + andThen(() => { + assert.equal(find('#first')[0].value, 'new value'); + assert.equal(find('#second')[0].value, ''); + }); - return wait(); - } + 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); - } - })); + [`@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', ` + this.addTemplate( + 'components/index-wrapper', + ` {{input type="text" id="outside-scope" class="input"}}
{{input type="text" id="inside-scope" class="input"}}
- `); - this.addTemplate('index', `{{index-wrapper}}`); - - this.runTask(() => { - this.application.advanceReadiness(); - }); - - let {application: {testHelpers: {wait, triggerEvent}}} = this; - return wait().then(() => { - return triggerEvent('.input', '#limited', 'keydown', { keyCode: 13 }); - }).then(() => { - assert.equal(event.keyCode, 13, 'options were passed'); - assert.equal(event.type, 'keydown', 'correct event was triggered'); - assert.equal(event.target.getAttribute('id'), 'inside-scope', 'triggered on the correct element'); - }); - } + ` + ); + this.addTemplate('index', `{{index-wrapper}}`); - }); + this.runTask(() => { + this.application.advanceReadiness(); + }); - moduleFor('ember-testing: debugging helpers', class extends HelpersApplicationTestCase { - afterEach() { - setDebugFunction('info', originalInfo); + 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' + ); + }); + } } + ); - constructor() { - super(); - this.runTask(() => { - this.application.advanceReadiness(); - }); - } + moduleFor( + 'ember-testing: debugging helpers', + class extends HelpersApplicationTestCase { + afterEach() { + setDebugFunction('info', originalInfo); + } - [`@test pauseTest pauses`](assert) { - assert.expect(1); - // overwrite info to supress the console output (see https://github.com/emberjs/ember.js/issues/16391) - setDebugFunction('info', noop); + constructor() { + super(); + this.runTask(() => { + this.application.advanceReadiness(); + }); + } - let { andThen, pauseTest } = this.application.testHelpers; + [`@test pauseTest pauses`](assert) { + assert.expect(1); + // overwrite info to supress the console output (see https://github.com/emberjs/ember.js/issues/16391) + setDebugFunction('info', noop); - andThen(() => { - Test.adapter.asyncStart = () => { - assert.ok( - true, - 'Async start should be called after waiting for other helpers' - ); - }; - }); + let { andThen, pauseTest } = this.application.testHelpers; - pauseTest(); - } + andThen(() => { + Test.adapter.asyncStart = () => { + assert.ok( + true, + 'Async start should be called after waiting for other helpers' + ); + }; + }); - [`@test resumeTest resumes paused tests`](assert) { - assert.expect(1); - // overwrite info to supress the console output (see https://github.com/emberjs/ember.js/issues/16391) - setDebugFunction('info', noop); + pauseTest(); + } - let {application: {testHelpers: {pauseTest, resumeTest}}} = this; + [`@test resumeTest resumes paused tests`](assert) { + assert.expect(1); + // overwrite info to supress the console output (see https://github.com/emberjs/ember.js/issues/16391) + setDebugFunction('info', noop); - later(() => resumeTest(), 20); - return pauseTest().then(() => { - assert.ok(true, 'pauseTest promise was resolved'); - }); - } + 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); + [`@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./); + assert.throws(() => { + this.application.testHelpers.resumeTest(); + }, /Testing has not been paused. There is nothing to resume./); + } } + ); + + moduleFor( + 'ember-testing: routing helpers', + class extends HelpersTestCase { + constructor() { + super(); + this.runTask(() => { + this.createApplication(); + this.application.setupForTesting(); + this.application.injectTestHelpers(); + this.router.map(function() { + this.route('posts', { resetNamespace: true }, function() { + this.route('new'); + this.route('edit', { resetNamespace: true }); + }); + }); + }); + this.runTask(() => { + this.application.advanceReadiness(); + }); + } + + [`@test currentRouteName for '/'`](assert) { + assert.expect(3); - }); + let { application: { testHelpers } } = this; + return testHelpers.visit('/').then(() => { + assert.equal( + testHelpers.currentRouteName(), + 'index', + `should equal 'index'.` + ); + assert.equal( + testHelpers.currentPath(), + 'index', + `should equal 'index'.` + ); + assert.equal(testHelpers.currentURL(), '/', `should equal '/'.`); + }); + } - moduleFor('ember-testing: routing helpers', class extends HelpersTestCase { + [`@test currentRouteName for '/posts'`](assert) { + assert.expect(3); - constructor() { - super(); - this.runTask(() => { - this.createApplication(); - this.application.setupForTesting(); - this.application.injectTestHelpers(); - this.router.map(function() { - this.route('posts', {resetNamespace: true}, function() { - this.route('new'); - this.route('edit', { resetNamespace: true }); - }); + 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'.` + ); }); - }); - this.runTask(() => { - this.application.advanceReadiness(); - }); - } + } - [`@test currentRouteName for '/'`](assert) { - assert.expect(3); + [`@test currentRouteName for '/posts/new'`](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 '/'.` - ); - }); - } + 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'`](assert) { - assert.expect(3); + [`@test currentRouteName for '/posts/edit'`](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'.` - ); - }); + 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 { + [`@test pendingRequests is maintained for ajaxSend and ajaxComplete events`]( + assert + ) { + assert.equal(pendingRequests(), 0); - [`@test currentRouteName for '/posts/new'`](assert) { - assert.expect(3); + let xhr = { some: 'xhr' }; - let {application: {testHelpers}} = this; - return testHelpers.visit('/posts/new').then(() => { + customEvent('ajaxSend', xhr); assert.equal( - testHelpers.currentRouteName(), 'posts.new', - `should equal 'posts.new'.` + pendingRequests(), + 1, + 'Ember.Test.pendingRequests was incremented' ); + + customEvent('ajaxComplete', xhr); assert.equal( - testHelpers.currentPath(), 'posts.new', - `should equal 'posts.new'.` + pendingRequests(), + 0, + 'Ember.Test.pendingRequests was decremented' ); + } + + [`@test pendingRequests is ignores ajaxComplete events from past setupForTesting calls`]( + assert + ) { + assert.equal(pendingRequests(), 0); + + let xhr = { some: 'xhr' }; + + customEvent('ajaxSend', xhr); assert.equal( - testHelpers.currentURL(), '/posts/new', - `should equal '/posts/new'.` + pendingRequests(), + 1, + 'Ember.Test.pendingRequests was incremented' ); - }); - } - [`@test currentRouteName for '/posts/edit'`](assert) { - assert.expect(3); + setupForTesting(); - let {application: {testHelpers}} = this; - return testHelpers.visit('/posts/edit').then(() => { assert.equal( - testHelpers.currentRouteName(), 'edit', - `should equal 'edit'.` + pendingRequests(), + 0, + 'Ember.Test.pendingRequests was reset' ); + + let altXhr = { some: 'more xhr' }; + + customEvent('ajaxSend', altXhr); assert.equal( - testHelpers.currentPath(), 'posts.edit', - `should equal 'posts.edit'.` + pendingRequests(), + 1, + 'Ember.Test.pendingRequests was incremented' ); + + customEvent('ajaxComplete', xhr); assert.equal( - testHelpers.currentURL(), '/posts/edit', - `should equal '/posts/edit'.` + pendingRequests(), + 1, + 'Ember.Test.pendingRequests is not impressed with your unexpected complete' ); - }); - } - - }); - - moduleFor('ember-testing: pendingRequests', class extends HelpersApplicationTestCase { - - [`@test pendingRequests is maintained for ajaxSend and ajaxComplete events`](assert) { - assert.equal( - pendingRequests(), 0 - ); - - let xhr = { some: 'xhr' }; - - customEvent('ajaxSend', xhr); - assert.equal( - pendingRequests(), 1, - 'Ember.Test.pendingRequests was incremented' - ); - - customEvent('ajaxComplete', xhr); - assert.equal( - pendingRequests(), 0, - 'Ember.Test.pendingRequests was decremented' - ); - } - - [`@test pendingRequests is ignores ajaxComplete events from past setupForTesting calls`](assert) { - assert.equal( - pendingRequests(), 0 - ); - - let xhr = { some: 'xhr' }; - - customEvent('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' }; - - customEvent('ajaxSend', altXhr); - assert.equal( - pendingRequests(), 1, - 'Ember.Test.pendingRequests was incremented' - ); - - customEvent('ajaxComplete', xhr); - assert.equal( - pendingRequests(), 1, - 'Ember.Test.pendingRequests is not impressed with your unexpected complete' - ); - } + } - [`@test pendingRequests is reset by setupForTesting`](assert) { - incrementPendingRequests(); + [`@test pendingRequests is reset by setupForTesting`](assert) { + incrementPendingRequests(); - setupForTesting(); + setupForTesting(); - assert.equal( - pendingRequests(), 0, - 'pendingRequests is reset' - ); + assert.equal(pendingRequests(), 0, 'pendingRequests is reset'); + } } - - }); - - moduleFor('ember-testing: async router', class extends HelpersTestCase { - constructor() { - super(); - - this.runTask(() => { - this.createApplication(); - - this.router.map(function() { - this.route('user', { resetNamespace: true }, function() { - this.route('profile'); - this.route('edit'); + ); + + moduleFor( + 'ember-testing: async router', + class extends HelpersTestCase { + constructor() { + super(); + + this.runTask(() => { + this.createApplication(); + + this.router.map(function() { + this.route('user', { resetNamespace: true }, function() { + this.route('profile'); + this.route('edit'); + }); }); - }); - // Emulate a long-running unscheduled async operation. - let resolveLater = () => new RSVP.Promise(resolve => { - /* + // Emulate a long-running unscheduled async operation. + let resolveLater = () => + new RSVP.Promise(resolve => { + /* * The wait() helper has a 10ms tick. We should resolve() after * at least one tick to test whether wait() held off while the * async router was still loading. 20ms should be enough. */ - later(resolve, {firstName: 'Tom'}, 20); - }); - - this.add('route:user', Route.extend({ - model() { - return resolveLater(); - } - })); - - this.add('route:user.profile', Route.extend({ - beforeModel() { - return resolveLater().then(() => this.transitionTo('user.edit')); - } - })); - - this.application.setupForTesting(); - }); - - this.application.injectTestHelpers(); - this.runTask(() => { - this.application.advanceReadiness(); - }); - } + later(resolve, { firstName: 'Tom' }, 20); + }); + + this.add( + 'route:user', + Route.extend({ + model() { + return resolveLater(); + } + }) + ); - [`@test currentRouteName for '/user'`](assert) { - assert.expect(4); + this.add( + 'route:user.profile', + Route.extend({ + beforeModel() { + return resolveLater().then(() => + this.transitionTo('user.edit') + ); + } + }) + ); - 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'.` - ); - }); - } + this.application.setupForTesting(); + }); - [`@test currentRouteName for '/user/profile'`](assert) { - assert.expect(4); + this.application.injectTestHelpers(); + this.runTask(() => { + this.application.advanceReadiness(); + }); + } - 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'.` - ); - }); - } + [`@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'.` + ); + }); + } - moduleFor('ember-testing: can override built-in helpers', class extends HelpersTestCase { + [`@test currentRouteName for '/user/profile'`](assert) { + assert.expect(4); - constructor() { - super(); - this.runTask(() => { - this.createApplication(); - this.application.setupForTesting(); - }); - this._originalVisitHelper = Test._helpers.visit; - this._originalFindHelper = Test._helpers.find; + let { application: { testHelpers } } = this; + return testHelpers.visit('/user/profile').then(() => { + assert.equal( + testHelpers.currentRouteName(), + 'user.edit', + `should equal 'user.edit'.` + ); + assert.equal( + testHelpers.currentPath(), + 'user.edit', + `should equal 'user.edit'.` + ); + assert.equal( + testHelpers.currentURL(), + '/user/edit', + `should equal '/user/edit'.` + ); + let userRoute = this.applicationInstance.lookup('route:user'); + assert.equal( + userRoute.get('controller.model.firstName'), + 'Tom', + `should equal 'Tom'.` + ); + }); + } } + ); + + moduleFor( + 'ember-testing: can override built-in helpers', + class extends HelpersTestCase { + constructor() { + super(); + this.runTask(() => { + this.createApplication(); + this.application.setupForTesting(); + }); + this._originalVisitHelper = Test._helpers.visit; + this._originalFindHelper = Test._helpers.find; + } - teardown() { - Test._helpers.visit = this._originalVisitHelper; - Test._helpers.find = this._originalFindHelper; - super.teardown(); - } + teardown() { + Test._helpers.visit = this._originalVisitHelper; + Test._helpers.find = this._originalFindHelper; + super.teardown(); + } - [`@test can override visit helper`](assert) { - assert.expect(1); + [`@test can override visit helper`](assert) { + assert.expect(1); - Test.registerHelper('visit', () => { - assert.ok(true, 'custom visit helper was called'); - }); + Test.registerHelper('visit', () => { + assert.ok(true, 'custom visit helper was called'); + }); - this.application.injectTestHelpers(); + this.application.injectTestHelpers(); - return this.application.testHelpers.visit(); - } + return this.application.testHelpers.visit(); + } - [`@test can override find helper`](assert) { - assert.expect(1); + [`@test can override find helper`](assert) { + assert.expect(1); - Test.registerHelper('find', () => { - assert.ok(true, 'custom find helper was called'); + Test.registerHelper('find', () => { + assert.ok(true, 'custom find helper was called'); - return ['not empty array']; - }); + return ['not empty array']; + }); - this.application.injectTestHelpers(); + this.application.injectTestHelpers(); - return this.application.testHelpers.findWithAssert('.who-cares'); + return this.application.testHelpers.findWithAssert('.who-cares'); + } } - - }); + ); } diff --git a/packages/ember-testing/tests/integration_test.js b/packages/ember-testing/tests/integration_test.js index 69025867450..b0a687c7853 100644 --- a/packages/ember-testing/tests/integration_test.js +++ b/packages/ember-testing/tests/integration_test.js @@ -1,108 +1,114 @@ -import { - moduleFor, - AutobootApplicationTestCase -} from 'internal-test-helpers'; +import { moduleFor, AutobootApplicationTestCase } from 'internal-test-helpers'; import Test from '../test'; -import { - A as emberA -} from 'ember-runtime'; +import { A as emberA } from 'ember-runtime'; import { Route } from 'ember-routing'; import { jQueryDisabled } from 'ember-views'; -moduleFor('ember-testing Integration tests of acceptance', class extends AutobootApplicationTestCase { +moduleFor( + 'ember-testing Integration tests of acceptance', + class extends AutobootApplicationTestCase { + constructor() { + super(); - constructor() { - super(); + this.modelContent = []; + this._originalAdapter = Test.adapter; - this.modelContent = []; - this._originalAdapter = Test.adapter; + this.runTask(() => { + this.createApplication(); - this.runTask(() => { - this.createApplication(); - - this.addTemplate('people', ` + this.addTemplate( + 'people', + `
{{#each model as |person|}}
{{person.firstName}}
{{/each}}
- `); - - this.router.map(function() { - this.route('people', { path: '/' }); - }); + ` + ); - this.add('route:people', Route.extend({ - model: () => this.modelContent - })); + this.router.map(function() { + this.route('people', { path: '/' }); + }); - this.application.setupForTesting(); - }); + this.add( + 'route:people', + Route.extend({ + model: () => this.modelContent + }) + ); - this.runTask(() => { - this.application.reset(); - }); + this.application.setupForTesting(); + }); - this.application.injectTestHelpers(); - } + this.runTask(() => { + this.application.reset(); + }); - teardown() { - super.teardown(); - Test.adapter = this._originalAdapter; - } + this.application.injectTestHelpers(); + } - [`@test template is bound to empty array of people`](assert) { - if (!jQueryDisabled) { - this.runTask(() => this.application.advanceReadiness()); - window.visit('/').then(() => { - let rows = window.find('.name').length; - assert.equal( - rows, 0, - 'successfully stubbed an empty array of people' - ); - }); - } else { - this.runTask(() => this.application.advanceReadiness()); - window.visit('/').then(() => { - expectAssertion(() => window.find('.name'), - 'If jQuery is disabled, please import and use helpers from @ember/test-helpers [https://github.com/emberjs/ember-test-helpers]. Note: `find` is not an available helper.' - ); - }); + teardown() { + super.teardown(); + Test.adapter = this._originalAdapter; } - } - [`@test template is bound to array of 2 people`](assert) { - if (!jQueryDisabled) { - this.modelContent = emberA([]); - this.modelContent.pushObject({ firstName: 'x' }); - this.modelContent.pushObject({ firstName: 'y' }); + [`@test template is bound to empty array of people`](assert) { + if (!jQueryDisabled) { + this.runTask(() => this.application.advanceReadiness()); + window.visit('/').then(() => { + let rows = window.find('.name').length; + assert.equal( + rows, + 0, + 'successfully stubbed an empty array of people' + ); + }); + } else { + this.runTask(() => this.application.advanceReadiness()); + window.visit('/').then(() => { + expectAssertion( + () => window.find('.name'), + 'If jQuery is disabled, please import and use helpers from @ember/test-helpers [https://github.com/emberjs/ember-test-helpers]. Note: `find` is not an available helper.' + ); + }); + } + } - this.runTask(() => this.application.advanceReadiness()); - window.visit('/').then(() => { - let rows = window.find('.name').length; - assert.equal( - rows, 2, - 'successfully stubbed a non empty array of people' - ); - }); - } else { - assert.expect(0); + [`@test template is bound to array of 2 people`](assert) { + if (!jQueryDisabled) { + this.modelContent = emberA([]); + this.modelContent.pushObject({ firstName: 'x' }); + this.modelContent.pushObject({ firstName: 'y' }); + + this.runTask(() => this.application.advanceReadiness()); + window.visit('/').then(() => { + let rows = window.find('.name').length; + assert.equal( + rows, + 2, + 'successfully stubbed a non empty array of people' + ); + }); + } else { + assert.expect(0); + } } - } - [`@test 'visit' can be called without advanceReadiness.`](assert) { - if (!jQueryDisabled) { - window.visit('/').then(() => { - let rows = window.find('.name').length; - assert.equal( - rows, 0, - 'stubbed an empty array of people without calling advanceReadiness.' - ); - }); - } else { - assert.expect(0); + [`@test 'visit' can be called without advanceReadiness.`](assert) { + if (!jQueryDisabled) { + window.visit('/').then(() => { + let rows = window.find('.name').length; + assert.equal( + rows, + 0, + 'stubbed an empty array of people without calling advanceReadiness.' + ); + }); + } else { + assert.expect(0); + } } } - -}); +); diff --git a/packages/ember-testing/tests/reexports_test.js b/packages/ember-testing/tests/reexports_test.js index 1644c597ead..7ef75891d8b 100644 --- a/packages/ember-testing/tests/reexports_test.js +++ b/packages/ember-testing/tests/reexports_test.js @@ -18,7 +18,9 @@ class ReexportsTestCase extends AbstractTestCase {} exportName = path; } - ReexportsTestCase.prototype[`@test Ember.${path} exports correctly`] = function(assert) { + ReexportsTestCase.prototype[ + `@test Ember.${path} exports correctly` + ] = function(assert) { confirmExport(Ember, assert, path, moduleId, exportName); }; }); diff --git a/packages/ember-testing/tests/test/waiters-test.js b/packages/ember-testing/tests/test/waiters-test.js index 43533fc5593..e7c9fbad87d 100644 --- a/packages/ember-testing/tests/test/waiters-test.js +++ b/packages/ember-testing/tests/test/waiters-test.js @@ -43,106 +43,116 @@ class Waiters { } } -moduleFor('ember-testing: waiters', class extends AbstractTestCase { - constructor() { - super(); - this.waiters = new Waiters(); - } +moduleFor( + 'ember-testing: waiters', + class extends AbstractTestCase { + constructor() { + super(); + this.waiters = new Waiters(); + } - teardown() { - this.waiters.unregister(); - } + teardown() { + this.waiters.unregister(); + } - ['@test registering a waiter'](assert) { - assert.expect(2); + ['@test registering a waiter'](assert) { + assert.expect(2); - let obj = { foo: true }; + let obj = { foo: true }; - this.waiters.add(obj, function() { - assert.ok(this.foo, 'has proper `this` context'); - return true; - }); + this.waiters.add(obj, function() { + assert.ok(this.foo, 'has proper `this` context'); + return true; + }); - this.waiters.add(function() { - assert.ok(true, 'is called'); - return true; - }); + this.waiters.add(function() { + assert.ok(true, 'is called'); + return true; + }); - this.waiters.check(); - } - - ['@test unregistering a waiter'](assert) { - assert.expect(2); + this.waiters.check(); + } - let obj = { foo: true }; + ['@test unregistering a waiter'](assert) { + assert.expect(2); - this.waiters.add(obj, function() { - assert.ok(true, 'precond - waiter with context is registered'); - return true; - }); + let obj = { foo: true }; - this.waiters.add(function() { - assert.ok(true, 'precond - waiter without context is registered'); - return true; - }); + this.waiters.add(obj, function() { + assert.ok(true, 'precond - waiter with context is registered'); + return true; + }); + this.waiters.add(function() { + assert.ok(true, 'precond - waiter without context is registered'); + return true; + }); - this.waiters.check(); - this.waiters.unregister(); + this.waiters.check(); + this.waiters.unregister(); - checkWaiters(); - } + checkWaiters(); + } - ['@test checkWaiters returns false if all waiters return true'](assert) { - assert.expect(3); + ['@test checkWaiters returns false if all waiters return true'](assert) { + assert.expect(3); - this.waiters.add(function() { - assert.ok(true, 'precond - waiter is registered'); + this.waiters.add(function() { + assert.ok(true, 'precond - waiter is registered'); - return true; - }); + return true; + }); - this.waiters.add(function() { - assert.ok(true, 'precond - waiter is registered'); + this.waiters.add(function() { + assert.ok(true, 'precond - waiter is registered'); - return true; - }); + return true; + }); - assert.notOk(this.waiters.check(), 'checkWaiters returns true if all waiters return true'); - } + assert.notOk( + this.waiters.check(), + 'checkWaiters returns true if all waiters return true' + ); + } - ['@test checkWaiters returns true if any waiters return false'](assert) { - assert.expect(3); + ['@test checkWaiters returns true if any waiters return false'](assert) { + assert.expect(3); - this.waiters.add(function() { - assert.ok(true, 'precond - waiter is registered'); + this.waiters.add(function() { + assert.ok(true, 'precond - waiter is registered'); - return true; - }); + return true; + }); - this.waiters.add(function() { - assert.ok(true, 'precond - waiter is registered'); + this.waiters.add(function() { + assert.ok(true, 'precond - waiter is registered'); - return false; - }); + return false; + }); - assert.ok(this.waiters.check(), 'checkWaiters returns false if any waiters return false'); - } + assert.ok( + this.waiters.check(), + 'checkWaiters returns false if any waiters return false' + ); + } - ['@test checkWaiters short circuits after first falsey waiter'](assert) { - assert.expect(2); + ['@test checkWaiters short circuits after first falsey waiter'](assert) { + assert.expect(2); - this.waiters.add(function() { - assert.ok(true, 'precond - waiter is registered'); + this.waiters.add(function() { + assert.ok(true, 'precond - waiter is registered'); - return false; - }); + return false; + }); - this.waiters.add(function() { - assert.notOk(true, 'waiter should not be called'); - }); + this.waiters.add(function() { + assert.notOk(true, 'waiter should not be called'); + }); - assert.ok(this.waiters.check(), 'checkWaiters returns false if any waiters return false'); + assert.ok( + this.waiters.check(), + 'checkWaiters returns false if any waiters return false' + ); + } } -}); - +); diff --git a/packages/ember-utils/lib/assign.js b/packages/ember-utils/lib/assign.js index b98e64b5994..2b1208e4d6a 100644 --- a/packages/ember-utils/lib/assign.js +++ b/packages/ember-utils/lib/assign.js @@ -24,7 +24,9 @@ export function assign(original) { for (let i = 1; i < arguments.length; i++) { let arg = arguments[i]; - if (!arg) { continue; } + if (!arg) { + continue; + } let updates = Object.keys(arg); diff --git a/packages/ember-utils/lib/guid.js b/packages/ember-utils/lib/guid.js index a15a1200179..412c6b32321 100644 --- a/packages/ember-utils/lib/guid.js +++ b/packages/ember-utils/lib/guid.js @@ -53,7 +53,7 @@ const NON_OBJECT_GUIDS = new Map(); @type String @final */ -export const GUID_KEY = intern(`__ember${+ new Date()}`); +export const GUID_KEY = intern(`__ember${+new Date()}`); /** Generates a new guid, optionally saving the guid to the object that you diff --git a/packages/ember-utils/lib/inspect.js b/packages/ember-utils/lib/inspect.js index 7b0f370c021..73d64d048b0 100644 --- a/packages/ember-utils/lib/inspect.js +++ b/packages/ember-utils/lib/inspect.js @@ -42,8 +42,12 @@ export default function inspect(obj) { for (let key in obj) { if (obj.hasOwnProperty(key)) { v = obj[key]; - if (v === 'toString') { continue; } // ignore useless items - if (typeof v === 'function') { v = 'function() { ... }'; } + if (v === 'toString') { + continue; + } // ignore useless items + if (typeof v === 'function') { + v = 'function() { ... }'; + } if (v && typeof v.toString !== 'function') { ret.push(`${key}: ${objectToString.call(v)}`); diff --git a/packages/ember-utils/lib/invoke.js b/packages/ember-utils/lib/invoke.js index 0c33d587dd0..b82e479b770 100644 --- a/packages/ember-utils/lib/invoke.js +++ b/packages/ember-utils/lib/invoke.js @@ -17,7 +17,9 @@ @private */ export function canInvoke(obj, methodName) { - return obj !== null && obj !== undefined && typeof obj[methodName] === 'function'; + return ( + obj !== null && obj !== undefined && typeof obj[methodName] === 'function' + ); } /** diff --git a/packages/ember-utils/lib/make-array.js b/packages/ember-utils/lib/make-array.js index 636085f64b3..5691ce82118 100644 --- a/packages/ember-utils/lib/make-array.js +++ b/packages/ember-utils/lib/make-array.js @@ -30,6 +30,8 @@ const { isArray } = Array; @private */ export default function makeArray(obj) { - if (obj === null || obj === undefined) { return []; } + if (obj === null || obj === undefined) { + return []; + } return isArray(obj) ? obj : [obj]; } diff --git a/packages/ember-utils/lib/spec.js b/packages/ember-utils/lib/spec.js index cf10ae1196b..5d7df523b3c 100644 --- a/packages/ember-utils/lib/spec.js +++ b/packages/ember-utils/lib/spec.js @@ -10,5 +10,7 @@ @function isObject */ export function isObject(value) { - return value !== null && (typeof value === 'object' || typeof value === 'function'); + return ( + value !== null && (typeof value === 'object' || typeof value === 'function') + ); } diff --git a/packages/ember-utils/lib/super.js b/packages/ember-utils/lib/super.js index d38a9fc9947..08a96894302 100644 --- a/packages/ember-utils/lib/super.js +++ b/packages/ember-utils/lib/super.js @@ -1,10 +1,13 @@ const HAS_SUPER_PATTERN = /\.(_super|call\(this|apply\(this)/; const fnToString = Function.prototype.toString; -export const checkHasSuper = ((() => { - let sourceAvailable = fnToString.call(function() { - return this; - }).indexOf('return this') > -1; +export const checkHasSuper = (() => { + let sourceAvailable = + fnToString + .call(function() { + return this; + }) + .indexOf('return this') > -1; if (sourceAvailable) { return function checkHasSuper(func) { @@ -15,7 +18,7 @@ export const checkHasSuper = ((() => { return function checkHasSuper() { return true; }; -})()); +})(); export function ROOT() {} ROOT.__hasSuper = false; diff --git a/packages/ember-utils/lib/to-string.js b/packages/ember-utils/lib/to-string.js index 2d5f0ae23ed..a5f0b02dbb5 100644 --- a/packages/ember-utils/lib/to-string.js +++ b/packages/ember-utils/lib/to-string.js @@ -10,7 +10,9 @@ function isNone(obj) { */ export default function toString(obj) { let type = typeof obj; - if (type === "string") { return obj; } + if (type === 'string') { + return obj; + } if (Array.isArray(obj)) { // Reimplement Array.prototype.join according to spec (22.1.3.13) diff --git a/packages/ember-utils/tests/assign_test.js b/packages/ember-utils/tests/assign_test.js index 4ba9a7eb66e..31e19b85504 100644 --- a/packages/ember-utils/tests/assign_test.js +++ b/packages/ember-utils/tests/assign_test.js @@ -1,41 +1,61 @@ import { assignPolyfill as assign } from '..'; -import { - moduleFor, - AbstractTestCase as TestCase -} from 'internal-test-helpers'; - -moduleFor('Ember.assign', class extends TestCase { - ['@test merging objects'](assert) { - let trgt = { a: 1 }; - let src1 = { b: 2 }; - let src2 = { c: 3 }; - assign(trgt, src1, src2); - - assert.deepEqual(trgt, { a: 1, b: 2, c: 3 }, 'assign copies values from one or more source objects to a target object'); - assert.deepEqual(src1, { b: 2 }, 'assign does not change source object 1'); - assert.deepEqual(src2, { c: 3 }, 'assign does not change source object 2'); +import { moduleFor, AbstractTestCase as TestCase } from 'internal-test-helpers'; + +moduleFor( + 'Ember.assign', + class extends TestCase { + ['@test merging objects'](assert) { + let trgt = { a: 1 }; + let src1 = { b: 2 }; + let src2 = { c: 3 }; + assign(trgt, src1, src2); + + assert.deepEqual( + trgt, + { a: 1, b: 2, c: 3 }, + 'assign copies values from one or more source objects to a target object' + ); + assert.deepEqual( + src1, + { b: 2 }, + 'assign does not change source object 1' + ); + assert.deepEqual( + src2, + { c: 3 }, + 'assign does not change source object 2' + ); + } + + ['@test merging objects with same property'](assert) { + let trgt = { a: 1, b: 1 }; + let src1 = { a: 2, b: 2 }; + let src2 = { a: 3 }; + assign(trgt, src1, src2); + + assert.deepEqual( + trgt, + { a: 3, b: 2 }, + 'properties are overwritten by other objects that have the same properties later in the parameters order' + ); + } + + ['@test null'](assert) { + let trgt = { a: 1 }; + assign(trgt, null); + + assert.deepEqual(trgt, { a: 1 }, 'null as a source parameter is ignored'); + } + + ['@test undefined'](assert) { + let trgt = { a: 1 }; + assign(trgt, null); + + assert.deepEqual( + trgt, + { a: 1 }, + 'undefined as a source parameter is ignored' + ); + } } - - ['@test merging objects with same property'](assert) { - let trgt = { a: 1, b: 1 }; - let src1 = { a: 2, b: 2 }; - let src2 = { a: 3 }; - assign(trgt, src1, src2); - - assert.deepEqual(trgt, { a: 3, b: 2 }, 'properties are overwritten by other objects that have the same properties later in the parameters order'); - } - - ['@test null'](assert) { - let trgt = { a: 1 }; - assign(trgt, null); - - assert.deepEqual(trgt, { a: 1 }, 'null as a source parameter is ignored'); - } - - ['@test undefined'](assert) { - let trgt = { a: 1 }; - assign(trgt, null); - - assert.deepEqual(trgt, { a: 1 }, 'undefined as a source parameter is ignored'); - } -}); +); diff --git a/packages/ember-utils/tests/can_invoke_test.js b/packages/ember-utils/tests/can_invoke_test.js index 07b5fc739c7..f2b72f08681 100644 --- a/packages/ember-utils/tests/can_invoke_test.js +++ b/packages/ember-utils/tests/can_invoke_test.js @@ -1,45 +1,48 @@ import { canInvoke } from '..'; -import { - moduleFor, - AbstractTestCase as TestCase -} from 'internal-test-helpers'; +import { moduleFor, AbstractTestCase as TestCase } from 'internal-test-helpers'; let obj; -moduleFor('Ember.canInvoke', class extends TestCase { - constructor() { - super(); - - obj = { - foobar: 'foobar', - aMethodThatExists() {} - }; - } - - teardown() { - obj = undefined; - } - - ['@test should return false if the object doesn\'t exist'](assert) { - assert.equal(canInvoke(undefined, 'aMethodThatDoesNotExist'), false); - } - - ['@test should return true for falsy values that have methods'](assert) { - assert.equal(canInvoke(false, 'valueOf'), true); - assert.equal(canInvoke('', 'charAt'), true); - assert.equal(canInvoke(0, 'toFixed'), true); +moduleFor( + 'Ember.canInvoke', + class extends TestCase { + constructor() { + super(); + + obj = { + foobar: 'foobar', + aMethodThatExists() {} + }; + } + + teardown() { + obj = undefined; + } + + ["@test should return false if the object doesn't exist"](assert) { + assert.equal(canInvoke(undefined, 'aMethodThatDoesNotExist'), false); + } + + ['@test should return true for falsy values that have methods'](assert) { + assert.equal(canInvoke(false, 'valueOf'), true); + assert.equal(canInvoke('', 'charAt'), true); + assert.equal(canInvoke(0, 'toFixed'), true); + } + + ['@test should return true if the method exists on the object'](assert) { + assert.equal(canInvoke(obj, 'aMethodThatExists'), true); + } + + ["@test should return false if the method doesn't exist on the object"]( + assert + ) { + assert.equal(canInvoke(obj, 'aMethodThatDoesNotExist'), false); + } + + ['@test should return false if the property exists on the object but is a non-function']( + assert + ) { + assert.equal(canInvoke(obj, 'foobar'), false); + } } - - ['@test should return true if the method exists on the object'](assert) { - assert.equal(canInvoke(obj, 'aMethodThatExists'), true); - } - - ['@test should return false if the method doesn\'t exist on the object'](assert) { - assert.equal(canInvoke(obj, 'aMethodThatDoesNotExist'), false); - } - - ['@test should return false if the property exists on the object but is a non-function'](assert) { - assert.equal(canInvoke(obj, 'foobar'), false); - } -}); - +); diff --git a/packages/ember-utils/tests/checkHasSuper_test.js b/packages/ember-utils/tests/checkHasSuper_test.js index 70239dcee03..19a62f2639b 100644 --- a/packages/ember-utils/tests/checkHasSuper_test.js +++ b/packages/ember-utils/tests/checkHasSuper_test.js @@ -1,17 +1,20 @@ import { environment } from 'ember-environment'; import { checkHasSuper } from '..'; -import { - moduleFor, - AbstractTestCase as TestCase -} from 'internal-test-helpers'; +import { moduleFor, AbstractTestCase as TestCase } from 'internal-test-helpers'; // Only run this test on browsers that we are certain should have function // source available. This allows the test suite to continue to pass on other // platforms that correctly (for them) fall back to the "always wrap" code. if (environment.isChrome || environment.isFirefox) { - moduleFor('checkHasSuper', class extends TestCase { - ['@test does not super wrap needlessly [GH #12462]'](assert) { - assert.notOk(checkHasSuper(function() {}), 'empty function does not have super'); + moduleFor( + 'checkHasSuper', + class extends TestCase { + ['@test does not super wrap needlessly [GH #12462]'](assert) { + assert.notOk( + checkHasSuper(function() {}), + 'empty function does not have super' + ); + } } - }); + ); } diff --git a/packages/ember-utils/tests/generate_guid_test.js b/packages/ember-utils/tests/generate_guid_test.js index 1d17666894a..298b095688a 100644 --- a/packages/ember-utils/tests/generate_guid_test.js +++ b/packages/ember-utils/tests/generate_guid_test.js @@ -1,13 +1,16 @@ import { generateGuid } from '..'; -import { - moduleFor, - AbstractTestCase as TestCase -} from 'internal-test-helpers'; +import { moduleFor, AbstractTestCase as TestCase } from 'internal-test-helpers'; -moduleFor('Ember.generateGuid', class extends TestCase { - ['@test Prefix'](assert) { - let a = {}; +moduleFor( + 'Ember.generateGuid', + class extends TestCase { + ['@test Prefix'](assert) { + let a = {}; - assert.ok(generateGuid(a, 'tyrell').indexOf('tyrell') > -1, 'guid can be prefixed'); + assert.ok( + generateGuid(a, 'tyrell').indexOf('tyrell') > -1, + 'guid can be prefixed' + ); + } } -}); +); diff --git a/packages/ember-utils/tests/guid_for_test.js b/packages/ember-utils/tests/guid_for_test.js index 707f36d5724..0b8bb1a0de3 100644 --- a/packages/ember-utils/tests/guid_for_test.js +++ b/packages/ember-utils/tests/guid_for_test.js @@ -1,10 +1,5 @@ -import { - guidFor -} from '..'; -import { - moduleFor, - AbstractTestCase as TestCase -} from 'internal-test-helpers'; +import { guidFor } from '..'; +import { moduleFor, AbstractTestCase as TestCase } from 'internal-test-helpers'; function sameGuid(assert, a, b, message) { assert.equal(guidFor(a), guidFor(b), message); @@ -16,88 +11,114 @@ function diffGuid(assert, a, b, message) { function nanGuid(assert, obj) { let type = typeof obj; - assert.ok(isNaN(parseInt(guidFor(obj), 0)), 'guids for ' + type + 'don\'t parse to numbers'); + assert.ok( + isNaN(parseInt(guidFor(obj), 0)), + 'guids for ' + type + "don't parse to numbers" + ); } -moduleFor('guidFor', class extends TestCase { - ['@test Object'](assert) { - let a = {}; - let b = {}; +moduleFor( + 'guidFor', + class extends TestCase { + ['@test Object'](assert) { + let a = {}; + let b = {}; - sameGuid(assert, a, a, 'same object always yields same guid'); - diffGuid(assert, a, b, 'different objects yield different guids'); - nanGuid(assert, a); - } - - ['@test strings'](assert) { - let a = 'string A'; - let aprime = 'string A'; - let b = 'String B'; - - sameGuid(assert, a, a, 'same string always yields same guid'); - sameGuid(assert, a, aprime, 'identical strings always yield the same guid'); - diffGuid(assert, a, b, 'different strings yield different guids'); - nanGuid(assert, a); - } - - ['@test numbers'](assert) { - let a = 23; - let aprime = 23; - let b = 34; - - sameGuid(assert, a, a, 'same numbers always yields same guid'); - sameGuid(assert, a, aprime, 'identical numbers always yield the same guid'); - diffGuid(assert, a, b, 'different numbers yield different guids'); - nanGuid(assert, a); - } + sameGuid(assert, a, a, 'same object always yields same guid'); + diffGuid(assert, a, b, 'different objects yield different guids'); + nanGuid(assert, a); + } - ['@test symbols'](assert) { - if (typeof Symbol === 'undefined') { - assert.ok(true, 'symbols are not supported on this browser'); - return; + ['@test strings'](assert) { + let a = 'string A'; + let aprime = 'string A'; + let b = 'String B'; + + sameGuid(assert, a, a, 'same string always yields same guid'); + sameGuid( + assert, + a, + aprime, + 'identical strings always yield the same guid' + ); + diffGuid(assert, a, b, 'different strings yield different guids'); + nanGuid(assert, a); } - let a = Symbol('a'); - let b = Symbol('b'); + ['@test numbers'](assert) { + let a = 23; + let aprime = 23; + let b = 34; + + sameGuid(assert, a, a, 'same numbers always yields same guid'); + sameGuid( + assert, + a, + aprime, + 'identical numbers always yield the same guid' + ); + diffGuid(assert, a, b, 'different numbers yield different guids'); + nanGuid(assert, a); + } - sameGuid(assert, a, a, 'same symbols always yields same guid'); - diffGuid(assert, a, b, 'different symbols yield different guids'); - nanGuid(assert, a); - } + ['@test symbols'](assert) { + if (typeof Symbol === 'undefined') { + assert.ok(true, 'symbols are not supported on this browser'); + return; + } - ['@test booleans'](assert) { - let a = true; - let aprime = true; - let b = false; + let a = Symbol('a'); + let b = Symbol('b'); - sameGuid(assert, a, a, 'same booleans always yields same guid'); - sameGuid(assert, a, aprime, 'identical booleans always yield the same guid'); - diffGuid(assert, a, b, 'different boolean yield different guids'); - nanGuid(assert, a); - nanGuid(assert, b); - } + sameGuid(assert, a, a, 'same symbols always yields same guid'); + diffGuid(assert, a, b, 'different symbols yield different guids'); + nanGuid(assert, a); + } - ['@test null and undefined'](assert) { - let a = null; - let aprime = null; - let b; - - sameGuid(assert, a, a, 'null always returns the same guid'); - sameGuid(assert, b, b, 'undefined always returns the same guid'); - sameGuid(assert, a, aprime, 'different nulls return the same guid'); - diffGuid(assert, a, b, 'null and undefined return different guids'); - nanGuid(assert, a); - nanGuid(assert, b); - } + ['@test booleans'](assert) { + let a = true; + let aprime = true; + let b = false; + + sameGuid(assert, a, a, 'same booleans always yields same guid'); + sameGuid( + assert, + a, + aprime, + 'identical booleans always yield the same guid' + ); + diffGuid(assert, a, b, 'different boolean yield different guids'); + nanGuid(assert, a); + nanGuid(assert, b); + } - ['@test arrays'](assert) { - let a = ['a', 'b', 'c']; - let aprime = ['a', 'b', 'c']; - let b = ['1', '2', '3']; + ['@test null and undefined'](assert) { + let a = null; + let aprime = null; + let b; + + sameGuid(assert, a, a, 'null always returns the same guid'); + sameGuid(assert, b, b, 'undefined always returns the same guid'); + sameGuid(assert, a, aprime, 'different nulls return the same guid'); + diffGuid(assert, a, b, 'null and undefined return different guids'); + nanGuid(assert, a); + nanGuid(assert, b); + } - sameGuid(assert, a, a, 'same instance always yields same guid'); - diffGuid(assert, a, aprime, 'identical arrays always yield the same guid'); - diffGuid(assert, a, b, 'different arrays yield different guids'); - nanGuid(assert, a); + ['@test arrays'](assert) { + let a = ['a', 'b', 'c']; + let aprime = ['a', 'b', 'c']; + let b = ['1', '2', '3']; + + sameGuid(assert, a, a, 'same instance always yields same guid'); + diffGuid( + assert, + a, + aprime, + 'identical arrays always yield the same guid' + ); + diffGuid(assert, a, b, 'different arrays yield different guids'); + nanGuid(assert, a); + } } -}); +); diff --git a/packages/ember-utils/tests/inspect_test.js b/packages/ember-utils/tests/inspect_test.js index 628399a7217..23bc970a5e0 100644 --- a/packages/ember-utils/tests/inspect_test.js +++ b/packages/ember-utils/tests/inspect_test.js @@ -1,67 +1,79 @@ import { HAS_NATIVE_SYMBOL, inspect } from '..'; -import { - moduleFor, - AbstractTestCase as TestCase -} from 'internal-test-helpers'; +import { moduleFor, AbstractTestCase as TestCase } from 'internal-test-helpers'; -moduleFor('Ember.inspect', class extends TestCase { - ['@test strings'](assert) { - assert.equal(inspect('foo'), 'foo'); - } +moduleFor( + 'Ember.inspect', + class extends TestCase { + ['@test strings'](assert) { + assert.equal(inspect('foo'), 'foo'); + } - ['@test numbers'](assert) { - assert.equal(inspect(2.6), '2.6'); - } + ['@test numbers'](assert) { + assert.equal(inspect(2.6), '2.6'); + } - ['@test null'](assert) { - assert.equal(inspect(null), 'null'); - } + ['@test null'](assert) { + assert.equal(inspect(null), 'null'); + } - ['@test undefined'](assert) { - assert.equal(inspect(undefined), 'undefined'); - } + ['@test undefined'](assert) { + assert.equal(inspect(undefined), 'undefined'); + } - ['@test true'](assert) { - assert.equal(inspect(true), 'true'); - } + ['@test true'](assert) { + assert.equal(inspect(true), 'true'); + } - ['@test false'](assert) { - assert.equal(inspect(false), 'false'); - } + ['@test false'](assert) { + assert.equal(inspect(false), 'false'); + } - ['@test object'](assert) { - assert.equal(inspect({}), '{}'); - assert.equal(inspect({ foo: 'bar' }), '{foo: bar}'); - assert.equal(inspect({ foo() { return this; } }), '{foo: function() { ... }}'); - } + ['@test object'](assert) { + assert.equal(inspect({}), '{}'); + assert.equal(inspect({ foo: 'bar' }), '{foo: bar}'); + assert.equal( + inspect({ + foo() { + return this; + } + }), + '{foo: function() { ... }}' + ); + } - ['@test objects without a prototype'](assert) { - let prototypelessObj = Object.create(null); - assert.equal(inspect({ foo: prototypelessObj }), '{foo: [object Object]}'); - } + ['@test objects without a prototype'](assert) { + let prototypelessObj = Object.create(null); + assert.equal( + inspect({ foo: prototypelessObj }), + '{foo: [object Object]}' + ); + } - ['@test array'](assert) { - assert.equal(inspect([1, 2, 3]), '[1,2,3]'); - } + ['@test array'](assert) { + assert.equal(inspect([1, 2, 3]), '[1,2,3]'); + } - ['@test regexp'](assert) { - assert.equal(inspect(/regexp/), '/regexp/'); - } + ['@test regexp'](assert) { + assert.equal(inspect(/regexp/), '/regexp/'); + } - ['@test date'](assert) { - let inspected = inspect(new Date('Sat Apr 30 2011 13:24:11')); - assert.ok(inspected.match(/Sat Apr 30/), 'The inspected date has its date'); - assert.ok(inspected.match(/2011/), 'The inspected date has its year'); - assert.ok(inspected.match(/13:24:11/), 'The inspected date has its time'); - } + ['@test date'](assert) { + let inspected = inspect(new Date('Sat Apr 30 2011 13:24:11')); + assert.ok( + inspected.match(/Sat Apr 30/), + 'The inspected date has its date' + ); + assert.ok(inspected.match(/2011/), 'The inspected date has its year'); + assert.ok(inspected.match(/13:24:11/), 'The inspected date has its time'); + } - ['@test inspect outputs the toString() representation of Symbols'](assert) { - if (HAS_NATIVE_SYMBOL) { - let symbol = Symbol('test'); - assert.equal(inspect(symbol), 'Symbol(test)'); - } else { - assert.expect(0); + ['@test inspect outputs the toString() representation of Symbols'](assert) { + if (HAS_NATIVE_SYMBOL) { + let symbol = Symbol('test'); + assert.equal(inspect(symbol), 'Symbol(test)'); + } else { + assert.expect(0); + } } } -}); - +); diff --git a/packages/ember-utils/tests/make_array_test.js b/packages/ember-utils/tests/make_array_test.js index d6e86c7f9fa..8d297cf785f 100644 --- a/packages/ember-utils/tests/make_array_test.js +++ b/packages/ember-utils/tests/make_array_test.js @@ -1,42 +1,41 @@ import { makeArray } from '..'; -import { - moduleFor, - AbstractTestCase as TestCase -} from 'internal-test-helpers'; - -moduleFor('Ember.makeArray', class extends TestCase { - ['@test undefined'](assert) { - assert.deepEqual(makeArray(), []); - assert.deepEqual(makeArray(undefined), []); - } - - ['@test null'](assert) { - assert.deepEqual(makeArray(null), []); - } - - ['@test string'](assert) { - assert.deepEqual(makeArray('lindsay'), ['lindsay']); - } - - ['@test number'](assert) { - assert.deepEqual(makeArray(0), [0]); - assert.deepEqual(makeArray(1), [1]); - } - - ['@test array'](assert) { - assert.deepEqual(makeArray([1, 2, 42]), [1, 2, 42]); - } - - ['@test true'](assert) { - assert.deepEqual(makeArray(true), [true]); - } - - ['@test false'](assert) { - assert.deepEqual(makeArray(false), [false]); - } - - ['@test object'](assert) { - assert.deepEqual(makeArray({}), [{}]); - } -}); - +import { moduleFor, AbstractTestCase as TestCase } from 'internal-test-helpers'; + +moduleFor( + 'Ember.makeArray', + class extends TestCase { + ['@test undefined'](assert) { + assert.deepEqual(makeArray(), []); + assert.deepEqual(makeArray(undefined), []); + } + + ['@test null'](assert) { + assert.deepEqual(makeArray(null), []); + } + + ['@test string'](assert) { + assert.deepEqual(makeArray('lindsay'), ['lindsay']); + } + + ['@test number'](assert) { + assert.deepEqual(makeArray(0), [0]); + assert.deepEqual(makeArray(1), [1]); + } + + ['@test array'](assert) { + assert.deepEqual(makeArray([1, 2, 42]), [1, 2, 42]); + } + + ['@test true'](assert) { + assert.deepEqual(makeArray(true), [true]); + } + + ['@test false'](assert) { + assert.deepEqual(makeArray(false), [false]); + } + + ['@test object'](assert) { + assert.deepEqual(makeArray({}), [{}]); + } + } +); diff --git a/packages/ember-utils/tests/to-string-test.js b/packages/ember-utils/tests/to-string-test.js index 499d0bd5ad0..71bb6cdb38f 100644 --- a/packages/ember-utils/tests/to-string-test.js +++ b/packages/ember-utils/tests/to-string-test.js @@ -1,30 +1,32 @@ import { toString } from '..'; -import { - moduleFor, - AbstractTestCase as TestCase -} from 'internal-test-helpers'; +import { moduleFor, AbstractTestCase as TestCase } from 'internal-test-helpers'; -moduleFor('ember-utils toString', class extends TestCase { - [`@test toString uses an object's toString method when available`](assert) { - let obj = { - toString() { - return 'bob'; - } - }; +moduleFor( + 'ember-utils toString', + class extends TestCase { + [`@test toString uses an object's toString method when available`](assert) { + let obj = { + toString() { + return 'bob'; + } + }; - assert.strictEqual(toString(obj), 'bob'); - } + assert.strictEqual(toString(obj), 'bob'); + } - ['@test toString falls back to Object.prototype.toString'](assert) { - let obj = Object.create(null); + ['@test toString falls back to Object.prototype.toString'](assert) { + let obj = Object.create(null); - assert.strictEqual(toString(obj), {}.toString()); - } + assert.strictEqual(toString(obj), {}.toString()); + } - ['@test toString does not fail when called on Arrays with objects without toString method'](assert) { - let obj = Object.create(null); - let arr = [obj, 2]; + ['@test toString does not fail when called on Arrays with objects without toString method']( + assert + ) { + let obj = Object.create(null); + let arr = [obj, 2]; - assert.strictEqual(toString(arr), `${({}).toString()},2`); + assert.strictEqual(toString(arr), `${{}.toString()},2`); + } } -}); +); diff --git a/packages/ember-utils/tests/try_invoke_test.js b/packages/ember-utils/tests/try_invoke_test.js index bc659c87eaa..a4fc35967ca 100644 --- a/packages/ember-utils/tests/try_invoke_test.js +++ b/packages/ember-utils/tests/try_invoke_test.js @@ -1,39 +1,51 @@ import { tryInvoke } from '..'; -import { - moduleFor, - AbstractTestCase as TestCase -} from 'internal-test-helpers'; +import { moduleFor, AbstractTestCase as TestCase } from 'internal-test-helpers'; let obj; -moduleFor('Ember.tryInvoke', class extends TestCase { - constructor() { - super(); - - obj = { - aMethodThatExists() { return true; }, - aMethodThatTakesArguments(arg1, arg2) { return arg1 === arg2; } - }; - } - - teardown() { - obj = undefined; - } - - ['@test should return undefined when the object doesn\'t exist'](assert) { - assert.equal(tryInvoke(undefined, 'aMethodThatDoesNotExist'), undefined); - } - - ['@test should return undefined when asked to perform a method that doesn\'t exist on the object'](assert) { - assert.equal(tryInvoke(obj, 'aMethodThatDoesNotExist'), undefined); - } - - ['@test should return what the method returns when asked to perform a method that exists on the object'](assert) { - assert.equal(tryInvoke(obj, 'aMethodThatExists'), true); +moduleFor( + 'Ember.tryInvoke', + class extends TestCase { + constructor() { + super(); + + obj = { + aMethodThatExists() { + return true; + }, + aMethodThatTakesArguments(arg1, arg2) { + return arg1 === arg2; + } + }; + } + + teardown() { + obj = undefined; + } + + ["@test should return undefined when the object doesn't exist"](assert) { + assert.equal(tryInvoke(undefined, 'aMethodThatDoesNotExist'), undefined); + } + + ["@test should return undefined when asked to perform a method that doesn't exist on the object"]( + assert + ) { + assert.equal(tryInvoke(obj, 'aMethodThatDoesNotExist'), undefined); + } + + ['@test should return what the method returns when asked to perform a method that exists on the object']( + assert + ) { + assert.equal(tryInvoke(obj, 'aMethodThatExists'), true); + } + + ['@test should return what the method returns when asked to perform a method that takes arguments and exists on the object']( + assert + ) { + assert.equal( + tryInvoke(obj, 'aMethodThatTakesArguments', [true, true]), + true + ); + } } - - ['@test should return what the method returns when asked to perform a method that takes arguments and exists on the object'](assert) { - assert.equal(tryInvoke(obj, 'aMethodThatTakesArguments', [true, true]), true); - } -}); - +); diff --git a/packages/ember-views/lib/component_lookup.js b/packages/ember-views/lib/component_lookup.js index e62af4fbc8f..e6ed863e4a0 100644 --- a/packages/ember-views/lib/component_lookup.js +++ b/packages/ember-views/lib/component_lookup.js @@ -3,13 +3,19 @@ import { Object as EmberObject } from 'ember-runtime'; export default EmberObject.extend({ componentFor(name, owner, options) { - assert(`You cannot use '${name}' as a component name. Component names must contain a hyphen.`, ~name.indexOf('-')); + assert( + `You cannot use '${name}' as a component name. Component names must contain a hyphen.`, + ~name.indexOf('-') + ); let fullName = `component:${name}`; return owner.factoryFor(fullName, options); }, layoutFor(name, owner, options) { - assert(`You cannot use '${name}' as a component name. Component names must contain a hyphen.`, ~name.indexOf('-')); + assert( + `You cannot use '${name}' as a component name. Component names must contain a hyphen.`, + ~name.indexOf('-') + ); let templateFullName = `template:components/${name}`; return owner.lookup(templateFullName, options); diff --git a/packages/ember-views/lib/index.js b/packages/ember-views/lib/index.js index 068c4bbd451..dd84972a30a 100644 --- a/packages/ember-views/lib/index.js +++ b/packages/ember-views/lib/index.js @@ -1,4 +1,3 @@ - export { default as jQuery, jQueryDisabled } from './system/jquery'; export { addChildView, @@ -22,13 +21,10 @@ export { default as ChildViewsSupport } from './mixins/child_views_support'; export { default as ViewStateSupport } from './mixins/view_state_support'; export { default as ViewMixin } from './mixins/view_support'; export { default as ActionSupport } from './mixins/action_support'; -export { - MUTABLE_CELL -} from './compat/attrs'; -export { - default as lookupPartial, - hasPartial -} from './system/lookup_partial'; +export { MUTABLE_CELL } from './compat/attrs'; +export { default as lookupPartial, hasPartial } from './system/lookup_partial'; export { default as lookupComponent } from './utils/lookup-component'; export { default as ActionManager } from './system/action_manager'; -export { default as fallbackViewRegistry } from './compat/fallback-view-registry'; +export { + default as fallbackViewRegistry +} from './compat/fallback-view-registry'; diff --git a/packages/ember-views/lib/mixins/action_support.js b/packages/ember-views/lib/mixins/action_support.js index 27daa327d59..686abe357d7 100644 --- a/packages/ember-views/lib/mixins/action_support.js +++ b/packages/ember-views/lib/mixins/action_support.js @@ -13,7 +13,9 @@ function validateAction(component, actionName) { assert( `The default action was triggered on the component ${component.toString()}, but the action name (${actionName}) was not a string.`, - isNone(actionName) || typeof actionName === 'string' || typeof actionName === 'function' + isNone(actionName) || + typeof actionName === 'string' || + typeof actionName === 'function' ); return actionName; } @@ -124,7 +126,9 @@ export default Mixin.create({ actionName = validateAction(this, actionName); // If no action name for that action could be found, just abort. - if (actionName === undefined) { return; } + if (actionName === undefined) { + return; + } if (typeof actionName === 'function') { actionName(...contexts); @@ -146,7 +150,9 @@ export default Mixin.create({ if (action) { let shouldBubble = action.apply(this, args) === true; - if (!shouldBubble) { return; } + if (!shouldBubble) { + return; + } } let target = get(this, 'target'); @@ -157,7 +163,10 @@ export default Mixin.create({ ); target.send(...arguments); } else { - assert(`${inspect(this)} had no action handler for: ${actionName}`, action); + assert( + `${inspect(this)} had no action handler for: ${actionName}`, + action + ); } } }); diff --git a/packages/ember-views/lib/mixins/child_views_support.js b/packages/ember-views/lib/mixins/child_views_support.js index 0925a2fbcc0..0f0b638af5b 100644 --- a/packages/ember-views/lib/mixins/child_views_support.js +++ b/packages/ember-views/lib/mixins/child_views_support.js @@ -1,14 +1,8 @@ /** @module ember */ -import { - Mixin, - descriptor -} from 'ember-metal'; -import { - getChildViews, - addChildView -} from '../system/utils'; +import { Mixin, descriptor } from 'ember-metal'; +import { getChildViews, addChildView } from '../system/utils'; export default Mixin.create({ /** diff --git a/packages/ember-views/lib/mixins/class_names_support.js b/packages/ember-views/lib/mixins/class_names_support.js index d85e8ee9fb6..cae535e7b9e 100644 --- a/packages/ember-views/lib/mixins/class_names_support.js +++ b/packages/ember-views/lib/mixins/class_names_support.js @@ -18,8 +18,16 @@ export default Mixin.create({ init() { this._super(...arguments); - assert(`Only arrays are allowed for 'classNameBindings'`, descriptorFor(this, 'classNameBindings') === undefined && Array.isArray(this.classNameBindings)); - assert(`Only arrays of static class strings are allowed for 'classNames'. For dynamic classes, use 'classNameBindings'.`, descriptorFor(this, 'classNames') === undefined && Array.isArray(this.classNames)); + assert( + `Only arrays are allowed for 'classNameBindings'`, + descriptorFor(this, 'classNameBindings') === undefined && + Array.isArray(this.classNameBindings) + ); + assert( + `Only arrays of static class strings are allowed for 'classNames'. For dynamic classes, use 'classNameBindings'.`, + descriptorFor(this, 'classNames') === undefined && + Array.isArray(this.classNames) + ); }, /** diff --git a/packages/ember-views/lib/mixins/text_support.js b/packages/ember-views/lib/mixins/text_support.js index 54c3fc19195..2ce1c154552 100644 --- a/packages/ember-views/lib/mixins/text_support.js +++ b/packages/ember-views/lib/mixins/text_support.js @@ -2,11 +2,7 @@ @module ember */ -import { - get, - set, - Mixin -} from 'ember-metal'; +import { get, set, Mixin } from 'ember-metal'; import { TargetActionSupport } from 'ember-runtime'; const KEY_EVENTS = { @@ -167,7 +163,9 @@ export default Mixin.create(TargetActionSupport, { let method = map[event.keyCode]; this._elementValueDidChange(); - if (method) { return this[method](event); } + if (method) { + return this[method](event); + } }, _elementValueDidChange() { diff --git a/packages/ember-views/lib/mixins/view_state_support.js b/packages/ember-views/lib/mixins/view_state_support.js index bf836e13075..c5845d6e0f7 100644 --- a/packages/ember-views/lib/mixins/view_state_support.js +++ b/packages/ember-views/lib/mixins/view_state_support.js @@ -6,10 +6,14 @@ import { Mixin } from 'ember-metal'; export default Mixin.create({ _transitionTo(state) { let priorState = this._currentState; - let currentState = this._currentState = this._states[state]; + let currentState = (this._currentState = this._states[state]); this._state = state; - if (priorState && priorState.exit) { priorState.exit(this); } - if (currentState.enter) { currentState.enter(this); } + if (priorState && priorState.exit) { + priorState.exit(this); + } + if (currentState.enter) { + currentState.enter(this); + } } }); diff --git a/packages/ember-views/lib/mixins/view_support.js b/packages/ember-views/lib/mixins/view_support.js index d7dc004db91..4e6997d84ff 100644 --- a/packages/ember-views/lib/mixins/view_support.js +++ b/packages/ember-views/lib/mixins/view_support.js @@ -5,7 +5,9 @@ import { environment } from 'ember-environment'; import { matches } from '../system/utils'; import { default as jQuery, jQueryDisabled } from '../system/jquery'; -function K() { return this; } +function K() { + return this; +} /** @class ViewMixin @@ -84,12 +86,15 @@ export default Mixin.create({ */ nearestOfType(klass) { let view = this.parentView; - let isOfType = klass instanceof Mixin ? - view => klass.detect(view) : - view => klass.detect(view.constructor); + let isOfType = + klass instanceof Mixin + ? view => klass.detect(view) + : view => klass.detect(view.constructor); while (view) { - if (isOfType(view)) { return view; } + if (isOfType(view)) { + return view; + } view = view.parentView; } }, @@ -107,7 +112,9 @@ export default Mixin.create({ let view = this.parentView; while (view) { - if (property in view) { return view; } + if (property in view) { + return view; + } view = view.parentView; } }, @@ -166,8 +173,14 @@ export default Mixin.create({ @public */ $(sel) { - assert('You cannot access this.$() on a component with `tagName: \'\'` specified.', this.tagName !== ''); - assert('You cannot access this.$() with `jQuery` disabled.', !jQueryDisabled); + assert( + "You cannot access this.$() on a component with `tagName: ''` specified.", + this.tagName !== '' + ); + assert( + 'You cannot access this.$() with `jQuery` disabled.', + !jQueryDisabled + ); if (this.element) { return sel ? jQuery(sel, this.element) : jQuery(this.element); } @@ -195,27 +208,45 @@ export default Mixin.create({ let target; if (env.hasDOM) { - target = typeof selector === 'string' ? document.querySelector(selector) : selector; - - assert(`You tried to append to (${selector}) but that isn't in the DOM`, target); - assert('You cannot append to an existing Ember.View.', !matches(target, '.ember-view')); - assert('You cannot append to an existing Ember.View.', ((() => { - let node = target.parentNode; - while (node) { - if (node.nodeType !== 9 && matches(node, '.ember-view')) { - return false; + target = + typeof selector === 'string' + ? document.querySelector(selector) + : selector; + + assert( + `You tried to append to (${selector}) but that isn't in the DOM`, + target + ); + assert( + 'You cannot append to an existing Ember.View.', + !matches(target, '.ember-view') + ); + assert( + 'You cannot append to an existing Ember.View.', + (() => { + let node = target.parentNode; + while (node) { + if (node.nodeType !== 9 && matches(node, '.ember-view')) { + return false; + } + + node = node.parentNode; } - node = node.parentNode; - } - - return true; - }))()); + return true; + })() + ); } else { target = selector; - assert(`You tried to append to a selector string (${selector}) in an environment without jQuery`, typeof target !== 'string'); - assert(`You tried to append to a non-Element (${selector}) in an environment without jQuery`, typeof selector.appendChild === 'function'); + assert( + `You tried to append to a selector string (${selector}) in an environment without jQuery`, + typeof target !== 'string' + ); + assert( + `You tried to append to a non-Element (${selector}) in an environment without jQuery`, + typeof selector.appendChild === 'function' + ); } this.renderer.appendTo(this, target); @@ -399,10 +430,16 @@ export default Mixin.create({ this._super(...arguments); // tslint:disable-next-line:max-line-length - assert(`You cannot use a computed property for the component's \`elementId\` (${this}).`, descriptorFor(this, 'elementId') === undefined); + assert( + `You cannot use a computed property for the component's \`elementId\` (${this}).`, + descriptorFor(this, 'elementId') === undefined + ); // tslint:disable-next-line:max-line-length - assert(`You cannot use a computed property for the component's \`tagName\` (${this}).`, descriptorFor(this, 'tagName') === undefined); + assert( + `You cannot use a computed property for the component's \`tagName\` (${this}).`, + descriptorFor(this, 'tagName') === undefined + ); if (!this.elementId && this.tagName !== '') { this.elementId = guidFor(this); @@ -411,15 +448,19 @@ export default Mixin.create({ if (environment._ENABLE_DID_INIT_ATTRS_SUPPORT) { deprecate( `[DEPRECATED] didInitAttrs called in ${this.toString()}.`, - typeof(this.didInitAttrs) !== 'function', + typeof this.didInitAttrs !== 'function', { id: 'ember-views.did-init-attrs', until: '3.0.0', - url: 'https://emberjs.com/deprecations/v2.x#toc_ember-component-didinitattrs' + url: + 'https://emberjs.com/deprecations/v2.x#toc_ember-component-didinitattrs' } ); } else { - assert(`didInitAttrs called in ${this.toString()} is no longer supported.`, typeof(this.didInitAttrs) !== 'function'); + assert( + `didInitAttrs called in ${this.toString()} is no longer supported.`, + typeof this.didInitAttrs !== 'function' + ); } assert( diff --git a/packages/ember-views/lib/system/event_dispatcher.js b/packages/ember-views/lib/system/event_dispatcher.js index aac3f71684d..71a97d3b7de 100644 --- a/packages/ember-views/lib/system/event_dispatcher.js +++ b/packages/ember-views/lib/system/event_dispatcher.js @@ -26,7 +26,6 @@ const ROOT_ELEMENT_SELECTOR = `.${ROOT_ELEMENT_CLASS}`; @extends Ember.Object */ export default EmberObject.extend({ - /** The set of events names (and associated handler function names) to be setup and dispatched by the `EventDispatcher`. Modifications to this list can be done @@ -61,33 +60,33 @@ export default EmberObject.extend({ @private */ events: { - touchstart: 'touchStart', - touchmove: 'touchMove', - touchend: 'touchEnd', + touchstart: 'touchStart', + touchmove: 'touchMove', + touchend: 'touchEnd', touchcancel: 'touchCancel', - keydown: 'keyDown', - keyup: 'keyUp', - keypress: 'keyPress', - mousedown: 'mouseDown', - mouseup: 'mouseUp', + keydown: 'keyDown', + keyup: 'keyUp', + keypress: 'keyPress', + mousedown: 'mouseDown', + mouseup: 'mouseUp', contextmenu: 'contextMenu', - click: 'click', - dblclick: 'doubleClick', - mousemove: 'mouseMove', - focusin: 'focusIn', - focusout: 'focusOut', - mouseenter: 'mouseEnter', - mouseleave: 'mouseLeave', - submit: 'submit', - input: 'input', - change: 'change', - dragstart: 'dragStart', - drag: 'drag', - dragenter: 'dragEnter', - dragleave: 'dragLeave', - dragover: 'dragOver', - drop: 'drop', - dragend: 'dragEnd' + click: 'click', + dblclick: 'doubleClick', + mousemove: 'mouseMove', + focusin: 'focusIn', + focusout: 'focusOut', + mouseenter: 'mouseEnter', + mouseleave: 'mouseLeave', + submit: 'submit', + input: 'input', + change: 'change', + dragstart: 'dragStart', + drag: 'drag', + dragenter: 'dragEnter', + dragleave: 'dragLeave', + dragover: 'dragOver', + drop: 'drop', + dragend: 'dragEnd' }, /** @@ -109,12 +108,15 @@ export default EmberObject.extend({ init() { this._super(); - assert('EventDispatcher should never be instantiated in fastboot mode. Please report this as an Ember bug.', (() => { - let owner = getOwner(this); - let environment = owner.lookup('-environment:main'); + assert( + 'EventDispatcher should never be instantiated in fastboot mode. Please report this as an Ember bug.', + (() => { + let owner = getOwner(this); + let environment = owner.lookup('-environment:main'); - return environment.isInteractive; - })()); + return environment.isInteractive; + })() + ); this._eventHandlers = Object.create(null); }, @@ -133,7 +135,11 @@ export default EmberObject.extend({ */ setup(addedEvents, _rootElement) { let event, rootElement; - let events = this._finalEvents = assign({}, get(this, 'events'), addedEvents); + let events = (this._finalEvents = assign( + {}, + get(this, 'events'), + addedEvents + )); if (!isNone(_rootElement)) { set(this, 'rootElement', _rootElement); @@ -142,14 +148,28 @@ export default EmberObject.extend({ let rootElementSelector = get(this, 'rootElement'); if (HAS_JQUERY) { rootElement = jQuery(rootElementSelector); - assert(`You cannot use the same root element (${rootElement.selector || rootElement[0].tagName}) multiple times in an Ember.Application`, !rootElement.is(ROOT_ELEMENT_SELECTOR)); - assert('You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', !rootElement.closest(ROOT_ELEMENT_SELECTOR).length); - assert('You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', !rootElement.find(ROOT_ELEMENT_SELECTOR).length); + assert( + `You cannot use the same root element (${rootElement.selector || + rootElement[0].tagName}) multiple times in an Ember.Application`, + !rootElement.is(ROOT_ELEMENT_SELECTOR) + ); + assert( + 'You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', + !rootElement.closest(ROOT_ELEMENT_SELECTOR).length + ); + assert( + 'You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', + !rootElement.find(ROOT_ELEMENT_SELECTOR).length + ); rootElement.addClass(ROOT_ELEMENT_CLASS); if (!rootElement.is(ROOT_ELEMENT_SELECTOR)) { - throw new TypeError(`Unable to add '${ROOT_ELEMENT_CLASS}' class to root element (${rootElement.selector || rootElement[0].tagName}). Make sure you set rootElement to the body or an element in the body.`); + throw new TypeError( + `Unable to add '${ROOT_ELEMENT_CLASS}' class to root element (${rootElement.selector || + rootElement[0] + .tagName}). Make sure you set rootElement to the body or an element in the body.` + ); } } else { if (typeof rootElementSelector !== 'string') { @@ -158,24 +178,41 @@ export default EmberObject.extend({ rootElement = document.querySelector(rootElementSelector); } - assert(`You cannot use the same root element (${get(this, 'rootElement') || rootElement.tagName}) multiple times in an Ember.Application`, !rootElement.classList.contains(ROOT_ELEMENT_CLASS)); - assert('You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', (() => { - let target = rootElement.parentNode; - do { - if (target.classList.contains(ROOT_ELEMENT_CLASS)) { - return false; - } + assert( + `You cannot use the same root element (${get(this, 'rootElement') || + rootElement.tagName}) multiple times in an Ember.Application`, + !rootElement.classList.contains(ROOT_ELEMENT_CLASS) + ); + assert( + 'You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', + (() => { + let target = rootElement.parentNode; + do { + if (target.classList.contains(ROOT_ELEMENT_CLASS)) { + return false; + } - target = target.parentNode; - } while(target && target.nodeType === 1); + target = target.parentNode; + } while (target && target.nodeType === 1); - return true; - })()); - assert('You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', !rootElement.querySelector(ROOT_ELEMENT_SELECTOR)); + return true; + })() + ); + assert( + 'You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', + !rootElement.querySelector(ROOT_ELEMENT_SELECTOR) + ); rootElement.classList.add(ROOT_ELEMENT_CLASS); - assert(`Unable to add '${ROOT_ELEMENT_CLASS}' class to root element (${get(this, 'rootElement') || rootElement.tagName}). Make sure you set rootElement to the body or an element in the body.`, rootElement.classList.contains(ROOT_ELEMENT_CLASS)); + assert( + `Unable to add '${ROOT_ELEMENT_CLASS}' class to root element (${get( + this, + 'rootElement' + ) || + rootElement.tagName}). Make sure you set rootElement to the body or an element in the body.`, + rootElement.classList.contains(ROOT_ELEMENT_CLASS) + ); } let viewRegistry = this._getViewRegistry(); @@ -233,7 +270,11 @@ export default EmberObject.extend({ // We have to check for action here since in some cases, jQuery will trigger // an event on `removeChild` (i.e. focusout) after we've already torn down the // action handlers for the view. - if (action && action.eventName === eventName && handledActions.indexOf(action) === -1) { + if ( + action && + action.eventName === eventName && + handledActions.indexOf(action) === -1 + ) { action.handler(evt); // Action handlers can mutate state which in turn creates new attributes on the element. // This effect could cause the `data-ember-action` attribute to shift down and be invoked twice. @@ -274,7 +315,9 @@ export default EmberObject.extend({ let attrName = attr.name; if (attrName.indexOf('data-ember-action-') === 0) { - actions = actions.concat(ActionManager.registeredActions[attr.value]); + actions = actions.concat( + ActionManager.registeredActions[attr.value] + ); } } } @@ -295,7 +338,7 @@ export default EmberObject.extend({ } }; - let handleEvent = this._eventHandlers[event] = (event) => { + let handleEvent = (this._eventHandlers[event] = event => { let target = event.target; do { @@ -312,8 +355,8 @@ export default EmberObject.extend({ } target = target.parentNode; - } while(target && target.nodeType === 1); - }; + } while (target && target.nodeType === 1); + }); rootElement.addEventListener(event, handleEvent); } @@ -321,7 +364,8 @@ export default EmberObject.extend({ _getViewRegistry() { let owner = getOwner(this); - let viewRegistry = owner && owner.lookup('-view-registry:main') || fallbackViewRegistry; + let viewRegistry = + (owner && owner.lookup('-view-registry:main')) || fallbackViewRegistry; return viewRegistry; }, @@ -335,7 +379,9 @@ export default EmberObject.extend({ rootElement = document.querySelector(rootElementSelector); } - if (!rootElement) { return; } + if (!rootElement) { + return; + } if (HAS_JQUERY) { jQuery(rootElementSelector).off('.ember', '**'); diff --git a/packages/ember-views/lib/system/lookup_partial.js b/packages/ember-views/lib/system/lookup_partial.js index 45da797dc18..006854ae7bf 100644 --- a/packages/ember-views/lib/system/lookup_partial.js +++ b/packages/ember-views/lib/system/lookup_partial.js @@ -10,37 +10,54 @@ function parseUnderscoredName(templateName) { } export default function lookupPartial(templateName, owner) { - if (templateName == null) { return; } - - let template = templateFor(owner, parseUnderscoredName(templateName), templateName); + if (templateName == null) { + return; + } - assert( - `Unable to find partial with name "${templateName}"`, - !!template + let template = templateFor( + owner, + parseUnderscoredName(templateName), + templateName ); + assert(`Unable to find partial with name "${templateName}"`, !!template); + return template; } export function hasPartial(name, owner) { if (!owner) { - throw new EmberError('Container was not found when looking up a views template. ' + - 'This is most likely due to manually instantiating an Ember.View. ' + - 'See: http://git.io/EKPpnA'); + throw new EmberError( + 'Container was not found when looking up a views template. ' + + 'This is most likely due to manually instantiating an Ember.View. ' + + 'See: http://git.io/EKPpnA' + ); } - return owner.hasRegistration(`template:${parseUnderscoredName(name)}`) || owner.hasRegistration(`template:${name}`); + return ( + owner.hasRegistration(`template:${parseUnderscoredName(name)}`) || + owner.hasRegistration(`template:${name}`) + ); } function templateFor(owner, underscored, name) { - if (!name) { return; } - assert(`templateNames are not allowed to contain periods: ${name}`, name.indexOf('.') === -1); + if (!name) { + return; + } + assert( + `templateNames are not allowed to contain periods: ${name}`, + name.indexOf('.') === -1 + ); if (!owner) { - throw new EmberError('Container was not found when looking up a views template. ' + - 'This is most likely due to manually instantiating an Ember.View. ' + - 'See: http://git.io/EKPpnA'); + throw new EmberError( + 'Container was not found when looking up a views template. ' + + 'This is most likely due to manually instantiating an Ember.View. ' + + 'See: http://git.io/EKPpnA' + ); } - return owner.lookup(`template:${underscored}`) || owner.lookup(`template:${name}`); + return ( + owner.lookup(`template:${underscored}`) || owner.lookup(`template:${name}`) + ); } diff --git a/packages/ember-views/lib/system/utils.js b/packages/ember-views/lib/system/utils.js index 0ebc43a3503..26bf20d95e2 100644 --- a/packages/ember-views/lib/system/utils.js +++ b/packages/ember-views/lib/system/utils.js @@ -6,19 +6,24 @@ import { guidFor, symbol, getOwner } from 'ember-utils'; */ export function isSimpleClick(event) { - let modifier = event.shiftKey || event.metaKey || event.altKey || event.ctrlKey; + let modifier = + event.shiftKey || event.metaKey || event.altKey || event.ctrlKey; let secondaryClick = event.which > 1; // IE9 may return undefined return !modifier && !secondaryClick; } export function constructStyleDeprecationMessage(affectedStyle) { - return '' + + return ( + '' + 'Binding style attributes may introduce cross-site scripting vulnerabilities; ' + 'please ensure that values being bound are properly escaped. For more information, ' + 'including how to disable this warning, see ' + 'https://emberjs.com/deprecations/v1.x/#toc_binding-style-attributes. ' + - 'Style affected: "' + affectedStyle + '"'; + 'Style affected: "' + + affectedStyle + + '"' + ); } /** @@ -71,7 +76,7 @@ export function initViewElement(view) { } export function setViewElement(view, element) { - return view[VIEW_ELEMENT] = element; + return (view[VIEW_ELEMENT] = element); } const CHILD_VIEW_IDS = new WeakMap(); @@ -182,13 +187,14 @@ export function getViewBoundingClientRect(view) { @param {DOMElement} el @param {String} selector */ -export const elMatches = typeof Element !== 'undefined' && +export const elMatches = + typeof Element !== 'undefined' && (Element.prototype.matches || - Element.prototype.matchesSelector || - Element.prototype.mozMatchesSelector || - Element.prototype.msMatchesSelector || - Element.prototype.oMatchesSelector || - Element.prototype.webkitMatchesSelector); + Element.prototype.matchesSelector || + Element.prototype.mozMatchesSelector || + Element.prototype.msMatchesSelector || + Element.prototype.oMatchesSelector || + Element.prototype.webkitMatchesSelector); export function matches(el, selector) { return elMatches.call(el, selector); diff --git a/packages/ember-views/lib/utils/lookup-component.js b/packages/ember-views/lib/utils/lookup-component.js index b93a401d122..eeb2a4ecce3 100644 --- a/packages/ember-views/lib/utils/lookup-component.js +++ b/packages/ember-views/lib/utils/lookup-component.js @@ -1,18 +1,26 @@ import { privatize as P } from 'container'; import { ENV } from 'ember-environment'; -import { - EMBER_MODULE_UNIFICATION, -} from 'ember/features'; - -function lookupModuleUnificationComponentPair(componentLookup, owner, name, options) { +import { EMBER_MODULE_UNIFICATION } from 'ember/features'; + +function lookupModuleUnificationComponentPair( + componentLookup, + owner, + name, + options +) { let localComponent = componentLookup.componentFor(name, owner, options); let localLayout = componentLookup.layoutFor(name, owner, options); let globalComponent = componentLookup.componentFor(name, owner); let globalLayout = componentLookup.layoutFor(name, owner); - let localAndUniqueComponent = !!localComponent && (!globalComponent || localComponent.class !== globalComponent.class); - let localAndUniqueLayout = !!localLayout && (!globalLayout || localLayout.referrer.moduleName !== globalLayout.referrer.moduleName); + let localAndUniqueComponent = + !!localComponent && + (!globalComponent || localComponent.class !== globalComponent.class); + let localAndUniqueLayout = + !!localLayout && + (!globalLayout || + localLayout.referrer.moduleName !== globalLayout.referrer.moduleName); if (localAndUniqueComponent && localAndUniqueLayout) { return { layout: localLayout, component: localComponent }; @@ -38,7 +46,12 @@ function lookupModuleUnificationComponentPair(componentLookup, owner, name, opti function lookupComponentPair(componentLookup, owner, name, options) { if (EMBER_MODULE_UNIFICATION) { - return lookupModuleUnificationComponentPair(componentLookup, owner, name, options); + return lookupModuleUnificationComponentPair( + componentLookup, + owner, + name, + options + ); } let component = componentLookup.componentFor(name, owner, options); @@ -57,7 +70,12 @@ export default function lookupComponent(owner, name, options) { let componentLookup = owner.lookup('component-lookup:main'); if (options && (options.source || options.namespace)) { - let localResult = lookupComponentPair(componentLookup, owner, name, options); + let localResult = lookupComponentPair( + componentLookup, + owner, + name, + options + ); if (localResult.component || localResult.layout) { return localResult; diff --git a/packages/ember-views/lib/views/core_view.js b/packages/ember-views/lib/views/core_view.js index ada2f6299b5..4b34298aead 100644 --- a/packages/ember-views/lib/views/core_view.js +++ b/packages/ember-views/lib/views/core_view.js @@ -1,8 +1,4 @@ -import { - ActionHandler, - Evented, - FrameworkObject -} from 'ember-runtime'; +import { ActionHandler, Evented, FrameworkObject } from 'ember-runtime'; import { initViewElement } from '../system/utils'; import { cloneStates, states } from './states'; @@ -35,7 +31,9 @@ const CoreView = FrameworkObject.extend(Evented, ActionHandler, { initViewElement(this); if (!this.renderer) { - throw new Error(`Cannot instantiate a component without a renderer. Please ensure that you are creating ${this} with a proper container/registry.`); + throw new Error( + `Cannot instantiate a component without a renderer. Please ensure that you are creating ${this} with a proper container/registry.` + ); } }, diff --git a/packages/ember-views/lib/views/states.js b/packages/ember-views/lib/views/states.js index 1ca23f209fc..b057c768425 100644 --- a/packages/ember-views/lib/views/states.js +++ b/packages/ember-views/lib/views/states.js @@ -15,7 +15,9 @@ export function cloneStates(from) { into.inDOM = Object.create(into.hasElement); for (let stateName in from) { - if (!from.hasOwnProperty(stateName)) { continue; } + if (!from.hasOwnProperty(stateName)) { + continue; + } assign(into[stateName], from[stateName]); } diff --git a/packages/ember-views/lib/views/states/destroying.js b/packages/ember-views/lib/views/states/destroying.js index b2ef4dbc9cd..d67b5925a72 100644 --- a/packages/ember-views/lib/views/states/destroying.js +++ b/packages/ember-views/lib/views/states/destroying.js @@ -6,10 +6,12 @@ const destroying = Object.create(_default); assign(destroying, { appendChild() { - throw new EmberError('You can\'t call appendChild on a view being destroyed'); + throw new EmberError( + "You can't call appendChild on a view being destroyed" + ); }, rerender() { - throw new EmberError('You can\'t call rerender on a view being destroyed'); + throw new EmberError("You can't call rerender on a view being destroyed"); } }); diff --git a/packages/ember-views/lib/views/states/has_element.js b/packages/ember-views/lib/views/states/has_element.js index c3009ac9355..0738b6b3b1e 100644 --- a/packages/ember-views/lib/views/states/has_element.js +++ b/packages/ember-views/lib/views/states/has_element.js @@ -5,7 +5,6 @@ import { join, flaggedInstrument } from 'ember-metal'; const hasElement = Object.create(_default); assign(hasElement, { - rerender(view) { view.renderer.rerender(view); }, @@ -19,9 +18,13 @@ assign(hasElement, { if (view.has(eventName)) { // Handler should be able to re-dispatch events, so we don't // preventDefault or stopPropagation. - return flaggedInstrument(`interaction.${eventName}`, { event, view }, () => { - return join(view, view.trigger, eventName, event); - }); + return flaggedInstrument( + `interaction.${eventName}`, + { event, view }, + () => { + return join(view, view.trigger, eventName, event); + } + ); } else { return true; // continue event propagation } diff --git a/packages/ember-views/lib/views/states/in_dom.js b/packages/ember-views/lib/views/states/in_dom.js index fa0f6406b8e..256f3d45c41 100644 --- a/packages/ember-views/lib/views/states/in_dom.js +++ b/packages/ember-views/lib/views/states/in_dom.js @@ -15,7 +15,9 @@ assign(inDOM, { if (DEBUG) { addObserver(view, 'elementId', () => { - throw new EmberError('Changing a view\'s elementId after creation is not allowed'); + throw new EmberError( + "Changing a view's elementId after creation is not allowed" + ); }); } }, diff --git a/packages/ember/tests/application_lifecycle_test.js b/packages/ember/tests/application_lifecycle_test.js index 9b45497d29c..257c880daa7 100644 --- a/packages/ember/tests/application_lifecycle_test.js +++ b/packages/ember/tests/application_lifecycle_test.js @@ -1,178 +1,206 @@ -import { - moduleFor, - AutobootApplicationTestCase -} from 'internal-test-helpers'; +import { moduleFor, AutobootApplicationTestCase } from 'internal-test-helpers'; import { Application } from 'ember-application'; import { Route, Router } from 'ember-routing'; -import { - Component, -} from 'ember-glimmer'; +import { Component } from 'ember-glimmer'; import { getDebugFunction, setDebugFunction } from 'ember-debug'; const originalDebug = getDebugFunction('debug'); -const noop = function(){}; - -moduleFor('Application Lifecycle - route hooks', class extends AutobootApplicationTestCase { +const noop = function() {}; + +moduleFor( + 'Application Lifecycle - route hooks', + class extends AutobootApplicationTestCase { + createApplication() { + let application = super.createApplication(...arguments); + this.add( + 'router:main', + Router.extend({ + location: 'none' + }) + ); + return application; + } + + constructor() { + setDebugFunction('debug', noop); + super(); + let menuItem = (this.menuItem = {}); + + this.runTask(() => { + this.createApplication(); + + let SettingRoute = Route.extend({ + setupController() { + this.controller.set('selectedMenuItem', menuItem); + }, + deactivate() { + this.controller.set('selectedMenuItem', null); + } + }); + this.add('route:index', SettingRoute); + this.add('route:application', SettingRoute); + }); + } + + teardown() { + setDebugFunction('debug', originalDebug); + } + + get indexController() { + return this.applicationInstance.lookup('controller:index'); + } + + get applicationController() { + return this.applicationInstance.lookup('controller:application'); + } + + [`@test Resetting the application allows controller properties to be set when a route deactivates`]( + assert + ) { + let { indexController, applicationController } = this; + assert.equal(indexController.get('selectedMenuItem'), this.menuItem); + assert.equal( + applicationController.get('selectedMenuItem'), + this.menuItem + ); + + this.application.reset(); + + assert.equal(indexController.get('selectedMenuItem'), null); + assert.equal(applicationController.get('selectedMenuItem'), null); + } + + [`@test Destroying the application resets the router before the appInstance is destroyed`]( + assert + ) { + let { indexController, applicationController } = this; + assert.equal(indexController.get('selectedMenuItem'), this.menuItem); + assert.equal( + applicationController.get('selectedMenuItem'), + this.menuItem + ); + + this.runTask(() => { + this.application.destroy(); + }); - createApplication() { - let application = super.createApplication(...arguments); - this.add('router:main', Router.extend({ - location: 'none' - })); - return application; + assert.equal(indexController.get('selectedMenuItem'), null); + assert.equal(applicationController.get('selectedMenuItem'), null); + } } +); + +moduleFor( + 'Application Lifecycle', + class extends AutobootApplicationTestCase { + createApplication() { + let application = super.createApplication(...arguments); + this.add( + 'router:main', + Router.extend({ + location: 'none' + }) + ); + return application; + } + + [`@test Destroying a route after the router does create an undestroyed 'toplevelView'`]( + assert + ) { + this.runTask(() => { + this.createApplication(); + this.addTemplate('index', `Index!`); + this.addTemplate('application', `Application! {{outlet}}`); + }); - constructor() { - setDebugFunction('debug', noop); - super(); - let menuItem = this.menuItem = {}; - - this.runTask(() => { - this.createApplication(); - - let SettingRoute = Route.extend({ - setupController() { - this.controller.set('selectedMenuItem', menuItem); - }, - deactivate() { - this.controller.set('selectedMenuItem', null); + let router = this.applicationInstance.lookup('router:main'); + let route = this.applicationInstance.lookup('route:index'); + + this.runTask(() => router.destroy()); + assert.equal(router._toplevelView, null, 'the toplevelView was cleared'); + + this.runTask(() => route.destroy()); + assert.equal( + router._toplevelView, + null, + 'the toplevelView was not reinitialized' + ); + + this.runTask(() => this.application.destroy()); + assert.equal( + router._toplevelView, + null, + 'the toplevelView was not reinitialized' + ); + } + + [`@test initializers can augment an applications customEvents hash`]( + assert + ) { + assert.expect(1); + + let MyApplication = Application.extend(); + + MyApplication.initializer({ + name: 'customize-things', + initialize(application) { + application.customEvents = { + wowza: 'wowza' + }; } }); - this.add('route:index', SettingRoute); - this.add('route:application', SettingRoute); - }); - } - - teardown() { - setDebugFunction('debug', originalDebug); - } - - get indexController() { - return this.applicationInstance.lookup('controller:index'); - } - - get applicationController() { - return this.applicationInstance.lookup('controller:application'); - } - - [`@test Resetting the application allows controller properties to be set when a route deactivates`](assert) { - let { - indexController, - applicationController - } = this; - assert.equal(indexController.get('selectedMenuItem'), this.menuItem); - assert.equal(applicationController.get('selectedMenuItem'), this.menuItem); - - this.application.reset(); - - assert.equal(indexController.get('selectedMenuItem'), null); - assert.equal(applicationController.get('selectedMenuItem'), null); - } - - [`@test Destroying the application resets the router before the appInstance is destroyed`](assert) { - let { - indexController, - applicationController - } = this; - assert.equal(indexController.get('selectedMenuItem'), this.menuItem); - assert.equal(applicationController.get('selectedMenuItem'), this.menuItem); - - this.runTask(() => { - this.application.destroy(); - }); - assert.equal(indexController.get('selectedMenuItem'), null); - assert.equal(applicationController.get('selectedMenuItem'), null); - } - -}); - -moduleFor('Application Lifecycle', class extends AutobootApplicationTestCase { - - createApplication() { - let application = super.createApplication(...arguments); - this.add('router:main', Router.extend({ - location: 'none' - })); - return application; - } + this.runTask(() => { + this.createApplication({}, MyApplication); - [`@test Destroying a route after the router does create an undestroyed 'toplevelView'`](assert) { - this.runTask(() => { - this.createApplication(); - this.addTemplate('index', `Index!`); - this.addTemplate('application', `Application! {{outlet}}`); - }); - - let router = this.applicationInstance.lookup('router:main'); - let route = this.applicationInstance.lookup('route:index'); - - this.runTask(() => router.destroy()); - assert.equal(router._toplevelView, null, 'the toplevelView was cleared'); - - this.runTask(() => route.destroy()); - assert.equal(router._toplevelView, null, 'the toplevelView was not reinitialized'); - - this.runTask(() => this.application.destroy()); - assert.equal(router._toplevelView, null, 'the toplevelView was not reinitialized'); - } + this.add( + 'component:foo-bar', + Component.extend({ + wowza() { + assert.ok(true, 'fired the event!'); + } + }) + ); - [`@test initializers can augment an applications customEvents hash`](assert) { - assert.expect(1); + this.addTemplate('application', `{{foo-bar}}`); + this.addTemplate('components/foo-bar', `
`); + }); - let MyApplication = Application.extend(); + this.$('#wowza-thingy').trigger('wowza'); + } - MyApplication.initializer({ - name: 'customize-things', - initialize(application) { - application.customEvents = { - wowza: 'wowza' - }; - } - }); + [`@test instanceInitializers can augment an the customEvents hash`]( + assert + ) { + assert.expect(1); - this.runTask(() => { - this.createApplication({}, MyApplication); + let MyApplication = Application.extend(); - this.add('component:foo-bar', Component.extend({ - wowza() { - assert.ok(true, 'fired the event!'); + MyApplication.instanceInitializer({ + name: 'customize-things', + initialize(application) { + application.customEvents = { + herky: 'jerky' + }; } - })); - - this.addTemplate('application', `{{foo-bar}}`); - this.addTemplate('components/foo-bar', `
`); - }); - - this.$('#wowza-thingy').trigger('wowza'); - } - - [`@test instanceInitializers can augment an the customEvents hash`](assert) { - assert.expect(1); - - let MyApplication = Application.extend(); - - MyApplication.instanceInitializer({ - name: 'customize-things', - initialize(application) { - application.customEvents = { - herky: 'jerky' - }; - } - }); - this.runTask(() => { - this.createApplication({}, MyApplication); - - this.add('component:foo-bar', Component.extend({ - jerky() { - assert.ok(true, 'fired the event!'); - } - })); - - this.addTemplate('application', `{{foo-bar}}`); - this.addTemplate('components/foo-bar', `
`); - }); + }); + this.runTask(() => { + this.createApplication({}, MyApplication); + + this.add( + 'component:foo-bar', + Component.extend({ + jerky() { + assert.ok(true, 'fired the event!'); + } + }) + ); + + this.addTemplate('application', `{{foo-bar}}`); + this.addTemplate('components/foo-bar', `
`); + }); - this.$('#herky-thingy').trigger('herky'); + this.$('#herky-thingy').trigger('herky'); + } } -}); +); diff --git a/packages/ember/tests/component_context_test.js b/packages/ember/tests/component_context_test.js index ba3ae7c92a7..fd4aa79b75f 100644 --- a/packages/ember/tests/component_context_test.js +++ b/packages/ember/tests/component_context_test.js @@ -1,189 +1,277 @@ import { Controller } from 'ember-runtime'; import { Component } from 'ember-glimmer'; -import { moduleFor, ApplicationTestCase, getTextOf } from 'internal-test-helpers'; +import { + moduleFor, + ApplicationTestCase, + getTextOf +} from 'internal-test-helpers'; -moduleFor('Application Lifecycle - Component Context', class extends ApplicationTestCase { - ['@test Components with a block should have the proper content when a template is provided'](assert) { - this.addTemplate('application', ` +moduleFor( + 'Application Lifecycle - Component Context', + class extends ApplicationTestCase { + ['@test Components with a block should have the proper content when a template is provided']( + assert + ) { + this.addTemplate( + 'application', + `
{{#my-component}}{{text}}{{/my-component}}
- `); - - this.add('controller:application', Controller.extend({ - 'text': 'outer' - })); - this.addComponent('my-component', { - ComponentClass: Component.extend({ - text: 'inner' - }), - template: `{{text}}-{{yield}}` - }); - - return this.visit('/').then(() => { - let text = getTextOf(this.element.querySelector('#wrapper')); - assert.equal(text, 'inner-outer', 'The component is composed correctly'); - }); - } + ` + ); + + this.add( + 'controller:application', + Controller.extend({ + text: 'outer' + }) + ); + this.addComponent('my-component', { + ComponentClass: Component.extend({ + text: 'inner' + }), + template: `{{text}}-{{yield}}` + }); - ['@test Components with a block should yield the proper content without a template provided'](assert) { - this.addTemplate('application', ` + return this.visit('/').then(() => { + let text = getTextOf(this.element.querySelector('#wrapper')); + assert.equal( + text, + 'inner-outer', + 'The component is composed correctly' + ); + }); + } + + ['@test Components with a block should yield the proper content without a template provided']( + assert + ) { + this.addTemplate( + 'application', + `
{{#my-component}}{{text}}{{/my-component}}
- `); - - this.add('controller:application', Controller.extend({ - 'text': 'outer' - })); - this.addComponent('my-component', { - ComponentClass: Component.extend({ - text: 'inner' - }) - }); - - return this.visit('/').then(() => { - let text = getTextOf(this.element.querySelector('#wrapper')); - assert.equal(text, 'outer', 'The component is composed correctly'); - }); - } - ['@test Components without a block should have the proper content when a template is provided'](assert) { - this.addTemplate('application', ` + ` + ); + + this.add( + 'controller:application', + Controller.extend({ + text: 'outer' + }) + ); + this.addComponent('my-component', { + ComponentClass: Component.extend({ + text: 'inner' + }) + }); + + return this.visit('/').then(() => { + let text = getTextOf(this.element.querySelector('#wrapper')); + assert.equal(text, 'outer', 'The component is composed correctly'); + }); + } + ['@test Components without a block should have the proper content when a template is provided']( + assert + ) { + this.addTemplate( + 'application', + `
{{my-component}}
- `); - - this.add('controller:application', Controller.extend({ - 'text': 'outer' - })); - this.addComponent('my-component', { - ComponentClass: Component.extend({ - text: 'inner' - }), - template: '{{text}}' - }); - - return this.visit('/').then(() => { - let text = getTextOf(this.element.querySelector('#wrapper')); - assert.equal(text, 'inner', 'The component is composed correctly'); - }); - } + ` + ); - ['@test Components without a block should have the proper content'](assert) { - this.addTemplate('application', ` + this.add( + 'controller:application', + Controller.extend({ + text: 'outer' + }) + ); + this.addComponent('my-component', { + ComponentClass: Component.extend({ + text: 'inner' + }), + template: '{{text}}' + }); + + return this.visit('/').then(() => { + let text = getTextOf(this.element.querySelector('#wrapper')); + assert.equal(text, 'inner', 'The component is composed correctly'); + }); + } + + ['@test Components without a block should have the proper content']( + assert + ) { + this.addTemplate( + 'application', + `
{{my-component}}
- `); - - this.add('controller:application', Controller.extend({ - 'text': 'outer' - })); - this.addComponent('my-component', { - ComponentClass: Component.extend({ - didInsertElement() { - this.element.innerHTML = 'Some text inserted'; - } - }) - }); - - return this.visit('/').then(() => { - let text = getTextOf(this.element.querySelector('#wrapper')); - assert.equal(text, 'Some text inserted', 'The component is composed correctly'); - }); - } + ` + ); - ['@test properties of a component without a template should not collide with internal structures [DEPRECATED]'](assert) { - this.addTemplate('application', ` + this.add( + 'controller:application', + Controller.extend({ + text: 'outer' + }) + ); + this.addComponent('my-component', { + ComponentClass: Component.extend({ + didInsertElement() { + this.element.innerHTML = 'Some text inserted'; + } + }) + }); + + return this.visit('/').then(() => { + let text = getTextOf(this.element.querySelector('#wrapper')); + assert.equal( + text, + 'Some text inserted', + 'The component is composed correctly' + ); + }); + } + + ['@test properties of a component without a template should not collide with internal structures [DEPRECATED]']( + assert + ) { + this.addTemplate( + 'application', + `
{{my-component data=foo}}
` - ); - - this.add('controller:application', Controller.extend({ - 'text': 'outer', - 'foo': 'Some text inserted' - })); - this.addComponent('my-component', { - ComponentClass: Component.extend({ - didInsertElement() { - this.element.innerHTML = this.get('data'); - } - }) - }); - - return this.visit('/').then(() => { - let text = getTextOf(this.element.querySelector('#wrapper')); - assert.equal(text, 'Some text inserted', 'The component is composed correctly'); - }); - } + ); - ['@test attrs property of a component without a template should not collide with internal structures'](assert) { - this.addTemplate('application', ` + this.add( + 'controller:application', + Controller.extend({ + text: 'outer', + foo: 'Some text inserted' + }) + ); + this.addComponent('my-component', { + ComponentClass: Component.extend({ + didInsertElement() { + this.element.innerHTML = this.get('data'); + } + }) + }); + + return this.visit('/').then(() => { + let text = getTextOf(this.element.querySelector('#wrapper')); + assert.equal( + text, + 'Some text inserted', + 'The component is composed correctly' + ); + }); + } + + ['@test attrs property of a component without a template should not collide with internal structures']( + assert + ) { + this.addTemplate( + 'application', + `
{{my-component attrs=foo}}
- `); - - this.add('controller:application', Controller.extend({ - 'text': 'outer', - 'foo': 'Some text inserted' - })); - this.addComponent('my-component', { - ComponentClass: Component.extend({ - didInsertElement() { - this.element.innerHTML = this.get('attrs.attrs.value'); - } - }) - }); - - return this.visit('/').then(() => { - let text = getTextOf(this.element.querySelector('#wrapper')); - assert.equal(text, 'Some text inserted', 'The component is composed correctly'); - }); - } + ` + ); + + this.add( + 'controller:application', + Controller.extend({ + text: 'outer', + foo: 'Some text inserted' + }) + ); + this.addComponent('my-component', { + ComponentClass: Component.extend({ + didInsertElement() { + this.element.innerHTML = this.get('attrs.attrs.value'); + } + }) + }); + + return this.visit('/').then(() => { + let text = getTextOf(this.element.querySelector('#wrapper')); + assert.equal( + text, + 'Some text inserted', + 'The component is composed correctly' + ); + }); + } - ['@test Components trigger actions in the parents context when called from within a block'](assert) { - this.addTemplate('application', ` + ['@test Components trigger actions in the parents context when called from within a block']( + assert + ) { + this.addTemplate( + 'application', + `
{{#my-component}} Fizzbuzz {{/my-component}}
- `); - - this.add('controller:application', Controller.extend({ - actions: { - fizzbuzz() { - assert.ok(true, 'action triggered on parent'); - } - } - })); - this.addComponent('my-component', { ComponentClass: Component.extend({}) }); - - return this.visit('/').then(() => { - this.$('#fizzbuzz', '#wrapper').click(); - }); - } + ` + ); + + this.add( + 'controller:application', + Controller.extend({ + actions: { + fizzbuzz() { + assert.ok(true, 'action triggered on parent'); + } + } + }) + ); + this.addComponent('my-component', { + ComponentClass: Component.extend({}) + }); + + return this.visit('/').then(() => { + this.$('#fizzbuzz', '#wrapper').click(); + }); + } - ['@test Components trigger actions in the components context when called from within its template'](assert) { - this.addTemplate('application', ` + ['@test Components trigger actions in the components context when called from within its template']( + assert + ) { + this.addTemplate( + 'application', + `
{{#my-component}}{{text}}{{/my-component}}
- `); - - this.add('controller:application', Controller.extend({ - actions: { - fizzbuzz() { - assert.ok(false, 'action on the wrong context'); - } - } - })); - this.addComponent('my-component', { - ComponentClass: Component.extend({ - actions: { - fizzbuzz() { - assert.ok(true, 'action triggered on component'); + ` + ); + + this.add( + 'controller:application', + Controller.extend({ + actions: { + fizzbuzz() { + assert.ok(false, 'action on the wrong context'); + } + } + }) + ); + this.addComponent('my-component', { + ComponentClass: Component.extend({ + actions: { + fizzbuzz() { + assert.ok(true, 'action triggered on component'); + } } - } - }), - template: `Fizzbuzz` - }); - - return this.visit('/').then(() => { - this.$('#fizzbuzz', '#wrapper').click(); - }); + }), + template: `Fizzbuzz` + }); + + return this.visit('/').then(() => { + this.$('#fizzbuzz', '#wrapper').click(); + }); + } } -}); +); diff --git a/packages/ember/tests/component_registration_test.js b/packages/ember/tests/component_registration_test.js index 376fc4ac2db..792b398ecf1 100644 --- a/packages/ember/tests/component_registration_test.js +++ b/packages/ember/tests/component_registration_test.js @@ -4,177 +4,279 @@ import { Component } from 'ember-glimmer'; import { compile } from 'ember-template-compiler'; import { moduleFor, ApplicationTestCase } from 'internal-test-helpers'; -moduleFor('Application Lifecycle - Component Registration', class extends ApplicationTestCase { +moduleFor( + 'Application Lifecycle - Component Registration', + class extends ApplicationTestCase { + // This is necessary for this.application.instanceInitializer to not leak between tests + createApplication(options) { + return super.createApplication(options, Application.extend()); + } - // This is necessary for this.application.instanceInitializer to not leak between tests - createApplication(options) { - return super.createApplication(options, Application.extend()); - } + ['@feature(!ember-glimmer-template-only-components) The helper becomes the body of the component']() { + this.addTemplate('components/expand-it', '

hello {{yield}}

'); + this.addTemplate( + 'application', + 'Hello world {{#expand-it}}world{{/expand-it}}' + ); - ['@feature(!ember-glimmer-template-only-components) The helper becomes the body of the component']() { - this.addTemplate('components/expand-it', '

hello {{yield}}

'); - this.addTemplate('application', 'Hello world {{#expand-it}}world{{/expand-it}}'); + return this.visit('/').then(() => { + this.assertText('Hello world hello world'); + this.assertComponentElement(this.element.firstElementChild, { + tagName: 'div', + content: '

hello world

' + }); + }); + } - return this.visit('/').then(() => { - this.assertText('Hello world hello world'); - this.assertComponentElement(this.element.firstElementChild, { tagName: 'div', content: '

hello world

' }); - }); - } + ['@feature(ember-glimmer-template-only-components) The helper becomes the body of the component']() { + this.addTemplate('components/expand-it', '

hello {{yield}}

'); + this.addTemplate( + 'application', + 'Hello world {{#expand-it}}world{{/expand-it}}' + ); - ['@feature(ember-glimmer-template-only-components) The helper becomes the body of the component']() { - this.addTemplate('components/expand-it', '

hello {{yield}}

'); - this.addTemplate('application', 'Hello world {{#expand-it}}world{{/expand-it}}'); + return this.visit('/').then(() => { + this.assertInnerHTML('Hello world

hello world

'); + }); + } - return this.visit('/').then(() => { - this.assertInnerHTML('Hello world

hello world

'); - }); - } + ['@test If a component is registered, it is used'](assert) { + this.addTemplate('components/expand-it', '

hello {{yield}}

'); + this.addTemplate( + 'application', + `Hello world {{#expand-it}}world{{/expand-it}}` + ); - ['@test If a component is registered, it is used'](assert) { - this.addTemplate('components/expand-it', '

hello {{yield}}

'); - this.addTemplate('application', `Hello world {{#expand-it}}world{{/expand-it}}`); - - this.application.instanceInitializer({ - name: 'expand-it-component', - initialize(applicationInstance) { - applicationInstance.register('component:expand-it', Component.extend({ - classNames: 'testing123' - })); - } - }); - - return this.visit('/').then(() => { - let text = this.$('div.testing123').text().trim(); - assert.equal(text, 'hello world', 'The component is composed correctly'); - }); - } + this.application.instanceInitializer({ + name: 'expand-it-component', + initialize(applicationInstance) { + applicationInstance.register( + 'component:expand-it', + Component.extend({ + classNames: 'testing123' + }) + ); + } + }); - ['@test Late-registered components can be rendered with custom `layout` property'](assert) { - this.addTemplate('application', `
there goes {{my-hero}}
`); - - this.application.instanceInitializer({ - name: 'my-hero-component', - initialize(applicationInstance) { - applicationInstance.register('component:my-hero', Component.extend({ - classNames: 'testing123', - layout: compile('watch him as he GOES') - })); - } - }); - - return this.visit('/').then(() => { - let text = this.$('#wrapper').text().trim(); - assert.equal(text, 'there goes watch him as he GOES', 'The component is composed correctly'); - }); - } + return this.visit('/').then(() => { + let text = this.$('div.testing123') + .text() + .trim(); + assert.equal( + text, + 'hello world', + 'The component is composed correctly' + ); + }); + } - ['@test Late-registered components can be rendered with template registered on the container'](assert) { - this.addTemplate('application', `
hello world {{sally-rutherford}}-{{#sally-rutherford}}!!!{{/sally-rutherford}}
`); - - this.application.instanceInitializer({ - name: 'sally-rutherford-component-template', - initialize(applicationInstance) { - applicationInstance.register('template:components/sally-rutherford', compile('funkytowny{{yield}}')); - } - }); - this.application.instanceInitializer({ - name: 'sally-rutherford-component', - initialize(applicationInstance) { - applicationInstance.register('component:sally-rutherford', Component); - } - }); - - return this.visit('/').then(() => { - let text = this.$('#wrapper').text().trim(); - assert.equal(text, 'hello world funkytowny-funkytowny!!!', 'The component is composed correctly'); - }); - } + ['@test Late-registered components can be rendered with custom `layout` property']( + assert + ) { + this.addTemplate( + 'application', + `
there goes {{my-hero}}
` + ); - ['@test Late-registered components can be rendered with ONLY the template registered on the container'](assert) { - this.addTemplate('application', `
hello world {{borf-snorlax}}-{{#borf-snorlax}}!!!{{/borf-snorlax}}
`); + this.application.instanceInitializer({ + name: 'my-hero-component', + initialize(applicationInstance) { + applicationInstance.register( + 'component:my-hero', + Component.extend({ + classNames: 'testing123', + layout: compile('watch him as he GOES') + }) + ); + } + }); - this.application.instanceInitializer({ - name: 'borf-snorlax-component-template', - initialize(applicationInstance) { - applicationInstance.register('template:components/borf-snorlax', compile('goodfreakingTIMES{{yield}}')); - } - }); + return this.visit('/').then(() => { + let text = this.$('#wrapper') + .text() + .trim(); + assert.equal( + text, + 'there goes watch him as he GOES', + 'The component is composed correctly' + ); + }); + } - return this.visit('/').then(() => { - let text = this.$('#wrapper').text().trim(); - assert.equal(text, 'hello world goodfreakingTIMES-goodfreakingTIMES!!!', 'The component is composed correctly'); - }); - } + ['@test Late-registered components can be rendered with template registered on the container']( + assert + ) { + this.addTemplate( + 'application', + `
hello world {{sally-rutherford}}-{{#sally-rutherford}}!!!{{/sally-rutherford}}
` + ); - ['@test Assigning layoutName to a component should setup the template as a layout'](assert) { - assert.expect(1); - - this.addTemplate('application', `
{{#my-component}}{{text}}{{/my-component}}
`); - this.addTemplate('foo-bar-baz', '{{text}}-{{yield}}'); - - this.application.instanceInitializer({ - name: 'application-controller', - initialize(applicationInstance) { - applicationInstance.register('controller:application', Controller.extend({ - text: 'outer' - })); - } - }); - this.application.instanceInitializer({ - name: 'my-component-component', - initialize(applicationInstance) { - applicationInstance.register('component:my-component', Component.extend({ - text: 'inner', - layoutName: 'foo-bar-baz' - })); - } - }); - - return this.visit('/').then(() => { - let text = this.$('#wrapper').text().trim(); - assert.equal(text, 'inner-outer', 'The component is composed correctly'); - }); - } + this.application.instanceInitializer({ + name: 'sally-rutherford-component-template', + initialize(applicationInstance) { + applicationInstance.register( + 'template:components/sally-rutherford', + compile('funkytowny{{yield}}') + ); + } + }); + this.application.instanceInitializer({ + name: 'sally-rutherford-component', + initialize(applicationInstance) { + applicationInstance.register('component:sally-rutherford', Component); + } + }); - ['@test Assigning layoutName and layout to a component should use the `layout` value'](assert) { - assert.expect(1); - - this.addTemplate('application', `
{{#my-component}}{{text}}{{/my-component}}
`); - this.addTemplate('foo-bar-baz', 'No way!'); - - this.application.instanceInitializer({ - name: 'application-controller-layout', - initialize(applicationInstance) { - applicationInstance.register('controller:application', Controller.extend({ - text: 'outer' - })); - } - }); - this.application.instanceInitializer({ - name: 'my-component-component-layout', - initialize(applicationInstance) { - applicationInstance.register('component:my-component', Component.extend({ - text: 'inner', - layoutName: 'foo-bar-baz', - layout: compile('{{text}}-{{yield}}') - })); - } - }); - - return this.visit('/').then(() => { - let text = this.$('#wrapper').text().trim(); - assert.equal(text, 'inner-outer', 'The component is composed correctly'); - }); - } + return this.visit('/').then(() => { + let text = this.$('#wrapper') + .text() + .trim(); + assert.equal( + text, + 'hello world funkytowny-funkytowny!!!', + 'The component is composed correctly' + ); + }); + } + + ['@test Late-registered components can be rendered with ONLY the template registered on the container']( + assert + ) { + this.addTemplate( + 'application', + `
hello world {{borf-snorlax}}-{{#borf-snorlax}}!!!{{/borf-snorlax}}
` + ); + + this.application.instanceInitializer({ + name: 'borf-snorlax-component-template', + initialize(applicationInstance) { + applicationInstance.register( + 'template:components/borf-snorlax', + compile('goodfreakingTIMES{{yield}}') + ); + } + }); + + return this.visit('/').then(() => { + let text = this.$('#wrapper') + .text() + .trim(); + assert.equal( + text, + 'hello world goodfreakingTIMES-goodfreakingTIMES!!!', + 'The component is composed correctly' + ); + }); + } + + ['@test Assigning layoutName to a component should setup the template as a layout']( + assert + ) { + assert.expect(1); + + this.addTemplate( + 'application', + `
{{#my-component}}{{text}}{{/my-component}}
` + ); + this.addTemplate('foo-bar-baz', '{{text}}-{{yield}}'); + + this.application.instanceInitializer({ + name: 'application-controller', + initialize(applicationInstance) { + applicationInstance.register( + 'controller:application', + Controller.extend({ + text: 'outer' + }) + ); + } + }); + this.application.instanceInitializer({ + name: 'my-component-component', + initialize(applicationInstance) { + applicationInstance.register( + 'component:my-component', + Component.extend({ + text: 'inner', + layoutName: 'foo-bar-baz' + }) + ); + } + }); + + return this.visit('/').then(() => { + let text = this.$('#wrapper') + .text() + .trim(); + assert.equal( + text, + 'inner-outer', + 'The component is composed correctly' + ); + }); + } + + ['@test Assigning layoutName and layout to a component should use the `layout` value']( + assert + ) { + assert.expect(1); + + this.addTemplate( + 'application', + `
{{#my-component}}{{text}}{{/my-component}}
` + ); + this.addTemplate('foo-bar-baz', 'No way!'); + + this.application.instanceInitializer({ + name: 'application-controller-layout', + initialize(applicationInstance) { + applicationInstance.register( + 'controller:application', + Controller.extend({ + text: 'outer' + }) + ); + } + }); + this.application.instanceInitializer({ + name: 'my-component-component-layout', + initialize(applicationInstance) { + applicationInstance.register( + 'component:my-component', + Component.extend({ + text: 'inner', + layoutName: 'foo-bar-baz', + layout: compile('{{text}}-{{yield}}') + }) + ); + } + }); + + return this.visit('/').then(() => { + let text = this.$('#wrapper') + .text() + .trim(); + assert.equal( + text, + 'inner-outer', + 'The component is composed correctly' + ); + }); + } - ['@test Using name of component that does not exist']() { - this.addTemplate('application', `
{{#no-good}} {{/no-good}}
`); + ['@test Using name of component that does not exist']() { + this.addTemplate( + 'application', + `
{{#no-good}} {{/no-good}}
` + ); - // TODO: Use the async form of expectAssertion here when it is available - expectAssertion(() => { - this.visit('/'); - }, /.* named "no-good" .*/); + // TODO: Use the async form of expectAssertion here when it is available + expectAssertion(() => { + this.visit('/'); + }, /.* named "no-good" .*/); - return this.runLoopSettled(); + return this.runLoopSettled(); + } } -}); +); diff --git a/packages/ember/tests/controller_test.js b/packages/ember/tests/controller_test.js index f081ff0de96..3fb3a00b824 100644 --- a/packages/ember/tests/controller_test.js +++ b/packages/ember/tests/controller_test.js @@ -10,29 +10,38 @@ import { Component } from 'ember-glimmer'; from the runtime up to the templating layer. */ -moduleFor('Template scoping examples', class extends ApplicationTestCase { - ['@test Actions inside an outlet go to the associated controller'](assert) { - this.add('controller:index', Controller.extend({ - actions: { - componentAction() { - assert.ok(true, 'controller received the action'); - } - } - })); +moduleFor( + 'Template scoping examples', + class extends ApplicationTestCase { + ['@test Actions inside an outlet go to the associated controller'](assert) { + this.add( + 'controller:index', + Controller.extend({ + actions: { + componentAction() { + assert.ok(true, 'controller received the action'); + } + } + }) + ); - this.addComponent('component-with-action', { - ComponentClass: Component.extend({ - classNames: ['component-with-action'], - click() { - this.sendAction(); - } - }), - }); + this.addComponent('component-with-action', { + ComponentClass: Component.extend({ + classNames: ['component-with-action'], + click() { + this.sendAction(); + } + }) + }); - this.addTemplate('index', '{{component-with-action action="componentAction"}}'); + this.addTemplate( + 'index', + '{{component-with-action action="componentAction"}}' + ); - return this.visit('/').then(() => { - this.runTask(() => this.$('.component-with-action').click()); - }); + return this.visit('/').then(() => { + this.runTask(() => this.$('.component-with-action').click()); + }); + } } -}); +); diff --git a/packages/ember/tests/error_handler_test.js b/packages/ember/tests/error_handler_test.js index d7fc345fb12..912a6fdfdf4 100644 --- a/packages/ember/tests/error_handler_test.js +++ b/packages/ember/tests/error_handler_test.js @@ -4,7 +4,6 @@ import RSVP from 'rsvp'; let WINDOW_ONERROR; - QUnit.module('error_handler', { beforeEach() { // capturing this outside of module scope to ensure we grab @@ -27,268 +26,348 @@ function runThatThrowsSync(message = 'Error for testing error handling') { } QUnit.test('by default there is no onerror - sync run', function(assert) { - assert.strictEqual(getOnerror(), undefined, 'precond - there should be no Ember.onerror set by default'); + assert.strictEqual( + getOnerror(), + undefined, + 'precond - there should be no Ember.onerror set by default' + ); assert.throws(runThatThrowsSync, Error, 'errors thrown sync are catchable'); }); -QUnit.test('when Ember.onerror (which rethrows) is registered - sync run', function(assert) { - assert.expect(2); - setOnerror(function(error) { - assert.ok(true, 'onerror called'); - throw error; - }); - assert.throws(runThatThrowsSync, Error, 'error is thrown'); -}); - -QUnit.test('when Ember.onerror (which does not rethrow) is registered - sync run', function(assert) { - assert.expect(2); - setOnerror(function() { - assert.ok(true, 'onerror called'); - }); - runThatThrowsSync(); - assert.ok(true, 'no error was thrown, Ember.onerror can intercept errors'); -}); - -QUnit.test('does not swallow exceptions by default (Ember.testing = true, no Ember.onerror) - sync run', function(assert) { - setTesting(true); - - let error = new Error('the error'); - assert.throws(() => { - run(() => { - throw error; - }); - }, error); -}); - -QUnit.test('does not swallow exceptions by default (Ember.testing = false, no Ember.onerror) - sync run', function(assert) { - setTesting(false); - let error = new Error('the error'); - assert.throws(() => { - run(() => { - throw error; - }); - }, error); -}); - -QUnit.test('does not swallow exceptions (Ember.testing = false, Ember.onerror which rethrows) - sync run', function(assert) { - assert.expect(2); - setTesting(false); - - setOnerror(function(error) { - assert.ok(true, 'Ember.onerror was called'); - throw error; - }); - - let error = new Error('the error'); - assert.throws(() => { - run(() => { +QUnit.test( + 'when Ember.onerror (which rethrows) is registered - sync run', + function(assert) { + assert.expect(2); + setOnerror(function(error) { + assert.ok(true, 'onerror called'); throw error; }); - }, error); -}); - -QUnit.test('Ember.onerror can intercept errors (aka swallow) by not rethrowing (Ember.testing = false) - sync run', function(assert) { - assert.expect(1); - setTesting(false); - - setOnerror(function() { - assert.ok(true, 'Ember.onerror was called'); - }); + assert.throws(runThatThrowsSync, Error, 'error is thrown'); + } +); - let error = new Error('the error'); - try { - run(() => { - throw error; +QUnit.test( + 'when Ember.onerror (which does not rethrow) is registered - sync run', + function(assert) { + assert.expect(2); + setOnerror(function() { + assert.ok(true, 'onerror called'); }); - } catch(e) { - assert.notOk(true, 'Ember.onerror that does not rethrow is intentionally swallowing errors, try / catch wrapping does not see error'); + runThatThrowsSync(); + assert.ok(true, 'no error was thrown, Ember.onerror can intercept errors'); } -}); +); +QUnit.test( + 'does not swallow exceptions by default (Ember.testing = true, no Ember.onerror) - sync run', + function(assert) { + setTesting(true); -QUnit.test('does not swallow exceptions by default (Ember.testing = true, no Ember.onerror) - async run', function(assert) { - let done = assert.async(); - let caughtByWindowOnerror; - - setTesting(true); + let error = new Error('the error'); + assert.throws(() => { + run(() => { + throw error; + }); + }, error); + } +); - window.onerror = function(message) { - caughtByWindowOnerror = message; - // prevent "bubbling" and therefore failing the test - return true; - }; +QUnit.test( + 'does not swallow exceptions by default (Ember.testing = false, no Ember.onerror) - sync run', + function(assert) { + setTesting(false); + let error = new Error('the error'); + assert.throws(() => { + run(() => { + throw error; + }); + }, error); + } +); - later(() => { - throw new Error('the error'); - }, 10); +QUnit.test( + 'does not swallow exceptions (Ember.testing = false, Ember.onerror which rethrows) - sync run', + function(assert) { + assert.expect(2); + setTesting(false); - setTimeout(() => { - assert.pushResult({ - result: /the error/.test(caughtByWindowOnerror), - actual: caughtByWindowOnerror, - expected: 'to include `the error`', - message: 'error should bubble out to window.onerror, and therefore fail tests (due to QUnit implementing window.onerror)' + setOnerror(function(error) { + assert.ok(true, 'Ember.onerror was called'); + throw error; }); - done(); - }, 20); -}); - -QUnit.test('does not swallow exceptions by default (Ember.testing = false, no Ember.onerror) - async run', function(assert) { - let done = assert.async(); - let caughtByWindowOnerror; - - setTesting(false); - - window.onerror = function(message) { - caughtByWindowOnerror = message; - // prevent "bubbling" and therefore failing the test - return true; - }; + let error = new Error('the error'); + assert.throws(() => { + run(() => { + throw error; + }); + }, error); + } +); - later(() => { - throw new Error('the error'); - }, 10); +QUnit.test( + 'Ember.onerror can intercept errors (aka swallow) by not rethrowing (Ember.testing = false) - sync run', + function(assert) { + assert.expect(1); + setTesting(false); - setTimeout(() => { - assert.pushResult({ - result: /the error/.test(caughtByWindowOnerror), - actual: caughtByWindowOnerror, - expected: 'to include `the error`', - message: 'error should bubble out to window.onerror, and therefore fail tests (due to QUnit implementing window.onerror)' + setOnerror(function() { + assert.ok(true, 'Ember.onerror was called'); }); - done(); - }, 20); -}); - -QUnit.test('Ember.onerror can intercept errors (aka swallow) by not rethrowing (Ember.testing = false) - async run', function(assert) { - let done = assert.async(); - - setTesting(false); + let error = new Error('the error'); + try { + run(() => { + throw error; + }); + } catch (e) { + assert.notOk( + true, + 'Ember.onerror that does not rethrow is intentionally swallowing errors, try / catch wrapping does not see error' + ); + } + } +); - window.onerror = function() { - assert.notOk(true, 'window.onerror is never invoked when Ember.onerror intentionally swallows errors'); - // prevent "bubbling" and therefore failing the test - return true; - }; +QUnit.test( + 'does not swallow exceptions by default (Ember.testing = true, no Ember.onerror) - async run', + function(assert) { + let done = assert.async(); + let caughtByWindowOnerror; - let thrown = new Error('the error'); - setOnerror(function(error) { - assert.strictEqual(error, thrown, 'Ember.onerror is called with the error'); - }); + setTesting(true); - later(() => { - throw thrown; - }, 10); + window.onerror = function(message) { + caughtByWindowOnerror = message; + // prevent "bubbling" and therefore failing the test + return true; + }; - setTimeout(done, 20); -}); + later(() => { + throw new Error('the error'); + }, 10); -function generateRSVPErrorHandlingTests(message, generatePromise, timeout = 10) { - QUnit.test(`${message} when Ember.onerror which does not rethrow is present - rsvp`, function(assert) { - assert.expect(1); + setTimeout(() => { + assert.pushResult({ + result: /the error/.test(caughtByWindowOnerror), + actual: caughtByWindowOnerror, + expected: 'to include `the error`', + message: + 'error should bubble out to window.onerror, and therefore fail tests (due to QUnit implementing window.onerror)' + }); - let thrown = new Error('the error'); - setOnerror(function(error) { - assert.strictEqual(error, thrown, 'Ember.onerror is called for errors thrown in RSVP promises'); - }); + done(); + }, 20); + } +); - generatePromise(thrown); +QUnit.test( + 'does not swallow exceptions by default (Ember.testing = false, no Ember.onerror) - async run', + function(assert) { + let done = assert.async(); + let caughtByWindowOnerror; - // RSVP.Promise's are configured to settle within the run loop, this - // ensures that run loop has completed - return new RSVP.Promise((resolve) => setTimeout(resolve, timeout)); - }); + setTesting(false); - QUnit.test(`${message} when Ember.onerror which does rethrow is present - rsvp`, function(assert) { - assert.expect(2); + window.onerror = function(message) { + caughtByWindowOnerror = message; + // prevent "bubbling" and therefore failing the test + return true; + }; - let thrown = new Error('the error'); - setOnerror(function(error) { - assert.strictEqual(error, thrown, 'Ember.onerror is called for errors thrown in RSVP promises'); - throw error; - }); + later(() => { + throw new Error('the error'); + }, 10); - window.onerror = function(message) { + setTimeout(() => { assert.pushResult({ - result: /the error/.test(message), - actual: message, + result: /the error/.test(caughtByWindowOnerror), + actual: caughtByWindowOnerror, expected: 'to include `the error`', - message: 'error should bubble out to window.onerror, and therefore fail tests (due to QUnit implementing window.onerror)' + message: + 'error should bubble out to window.onerror, and therefore fail tests (due to QUnit implementing window.onerror)' }); - // prevent "bubbling" and therefore failing the test - return true; - }; + done(); + }, 20); + } +); - generatePromise(thrown); +QUnit.test( + 'Ember.onerror can intercept errors (aka swallow) by not rethrowing (Ember.testing = false) - async run', + function(assert) { + let done = assert.async(); - // RSVP.Promise's are configured to settle within the run loop, this - // ensures that run loop has completed - return new RSVP.Promise((resolve) => setTimeout(resolve, timeout)); - }); + setTesting(false); - QUnit.test(`${message} when Ember.onerror which does not rethrow is present (Ember.testing = false) - rsvp`, function(assert) { - assert.expect(1); + window.onerror = function() { + assert.notOk( + true, + 'window.onerror is never invoked when Ember.onerror intentionally swallows errors' + ); + // prevent "bubbling" and therefore failing the test + return true; + }; - setTesting(false); let thrown = new Error('the error'); setOnerror(function(error) { - assert.strictEqual(error, thrown, 'Ember.onerror is called for errors thrown in RSVP promises'); + assert.strictEqual( + error, + thrown, + 'Ember.onerror is called with the error' + ); }); - generatePromise(thrown); - - // RSVP.Promise's are configured to settle within the run loop, this - // ensures that run loop has completed - return new RSVP.Promise((resolve) => setTimeout(resolve, timeout)); - }); - - QUnit.test(`${message} when Ember.onerror which does rethrow is present (Ember.testing = false) - rsvp`, function(assert) { - assert.expect(2); + later(() => { + throw thrown; + }, 10); - setTesting(false); - let thrown = new Error('the error'); - setOnerror(function(error) { - assert.strictEqual(error, thrown, 'Ember.onerror is called for errors thrown in RSVP promises'); - throw error; - }); + setTimeout(done, 20); + } +); + +function generateRSVPErrorHandlingTests( + message, + generatePromise, + timeout = 10 +) { + QUnit.test( + `${message} when Ember.onerror which does not rethrow is present - rsvp`, + function(assert) { + assert.expect(1); + + let thrown = new Error('the error'); + setOnerror(function(error) { + assert.strictEqual( + error, + thrown, + 'Ember.onerror is called for errors thrown in RSVP promises' + ); + }); - window.onerror = function(message) { - assert.pushResult({ - result: /the error/.test(message), - actual: message, - expected: 'to include `the error`', - message: 'error should bubble out to window.onerror, and therefore fail tests (due to QUnit implementing window.onerror)' + generatePromise(thrown); + + // RSVP.Promise's are configured to settle within the run loop, this + // ensures that run loop has completed + return new RSVP.Promise(resolve => setTimeout(resolve, timeout)); + } + ); + + QUnit.test( + `${message} when Ember.onerror which does rethrow is present - rsvp`, + function(assert) { + assert.expect(2); + + let thrown = new Error('the error'); + setOnerror(function(error) { + assert.strictEqual( + error, + thrown, + 'Ember.onerror is called for errors thrown in RSVP promises' + ); + throw error; }); - // prevent "bubbling" and therefore failing the test - return true; - }; + window.onerror = function(message) { + assert.pushResult({ + result: /the error/.test(message), + actual: message, + expected: 'to include `the error`', + message: + 'error should bubble out to window.onerror, and therefore fail tests (due to QUnit implementing window.onerror)' + }); + + // prevent "bubbling" and therefore failing the test + return true; + }; + + generatePromise(thrown); + + // RSVP.Promise's are configured to settle within the run loop, this + // ensures that run loop has completed + return new RSVP.Promise(resolve => setTimeout(resolve, timeout)); + } + ); + + QUnit.test( + `${message} when Ember.onerror which does not rethrow is present (Ember.testing = false) - rsvp`, + function(assert) { + assert.expect(1); + + setTesting(false); + let thrown = new Error('the error'); + setOnerror(function(error) { + assert.strictEqual( + error, + thrown, + 'Ember.onerror is called for errors thrown in RSVP promises' + ); + }); - generatePromise(thrown); + generatePromise(thrown); + + // RSVP.Promise's are configured to settle within the run loop, this + // ensures that run loop has completed + return new RSVP.Promise(resolve => setTimeout(resolve, timeout)); + } + ); + + QUnit.test( + `${message} when Ember.onerror which does rethrow is present (Ember.testing = false) - rsvp`, + function(assert) { + assert.expect(2); + + setTesting(false); + let thrown = new Error('the error'); + setOnerror(function(error) { + assert.strictEqual( + error, + thrown, + 'Ember.onerror is called for errors thrown in RSVP promises' + ); + throw error; + }); - // RSVP.Promise's are configured to settle within the run loop, this - // ensures that run loop has completed - return new RSVP.Promise((resolve) => setTimeout(resolve, timeout)); - }); + window.onerror = function(message) { + assert.pushResult({ + result: /the error/.test(message), + actual: message, + expected: 'to include `the error`', + message: + 'error should bubble out to window.onerror, and therefore fail tests (due to QUnit implementing window.onerror)' + }); + + // prevent "bubbling" and therefore failing the test + return true; + }; + + generatePromise(thrown); + + // RSVP.Promise's are configured to settle within the run loop, this + // ensures that run loop has completed + return new RSVP.Promise(resolve => setTimeout(resolve, timeout)); + } + ); } -generateRSVPErrorHandlingTests('errors in promise constructor', (error) => { +generateRSVPErrorHandlingTests('errors in promise constructor', error => { new RSVP.Promise(() => { throw error; }); }); -generateRSVPErrorHandlingTests('errors in promise .then callback', (error) => { +generateRSVPErrorHandlingTests('errors in promise .then callback', error => { RSVP.resolve().then(() => { throw error; }); }); -generateRSVPErrorHandlingTests('errors in async promise .then callback', (error) => { - new RSVP.Promise((resolve) => setTimeout(resolve, 10)).then(() => { - throw error; - }); -}, 20); +generateRSVPErrorHandlingTests( + 'errors in async promise .then callback', + error => { + new RSVP.Promise(resolve => setTimeout(resolve, 10)).then(() => { + throw error; + }); + }, + 20 +); diff --git a/packages/ember/tests/global-api-test.js b/packages/ember/tests/global-api-test.js index 68bded4ee52..2fd3251f4c7 100644 --- a/packages/ember/tests/global-api-test.js +++ b/packages/ember/tests/global-api-test.js @@ -1,59 +1,58 @@ import { get } from 'ember-metal'; import { isArray } from 'ember-runtime'; -import { - moduleFor, - AbstractTestCase -} from 'internal-test-helpers'; - - -moduleFor('Global API Tests', class extends AbstractTestCase { - ['@test confirm Ember.DefaultResolver is exported'](assert) { - let internal = undefined; - let theExport = get(window, 'Ember.DefaultResolver'); - assert.ok(`${theExport} is exported`); - - if (internal !== undefined) { - assert.equal(theExport, internal, `${theExport} is exported properly`); +import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; + +moduleFor( + 'Global API Tests', + class extends AbstractTestCase { + ['@test confirm Ember.DefaultResolver is exported'](assert) { + let internal = undefined; + let theExport = get(window, 'Ember.DefaultResolver'); + assert.ok(`${theExport} is exported`); + + if (internal !== undefined) { + assert.equal(theExport, internal, `${theExport} is exported properly`); + } } - } - ['@test confirm Ember.generateController is exported'](assert) { - let internal = undefined; - let theExport = get(window, 'Ember.generateController'); - assert.ok(`${theExport} is exported`); + ['@test confirm Ember.generateController is exported'](assert) { + let internal = undefined; + let theExport = get(window, 'Ember.generateController'); + assert.ok(`${theExport} is exported`); - if (internal !== undefined) { - assert.equal(theExport, internal, `${theExport} is exported properly`); + if (internal !== undefined) { + assert.equal(theExport, internal, `${theExport} is exported properly`); + } } - } - ['@test confirm Ember.Helper is exported'](assert) { - let internal = undefined; - let theExport = get(window, 'Ember.Helper'); - assert.ok(`${theExport} is exported`); + ['@test confirm Ember.Helper is exported'](assert) { + let internal = undefined; + let theExport = get(window, 'Ember.Helper'); + assert.ok(`${theExport} is exported`); - if (internal !== undefined) { - assert.equal(theExport, internal, `${theExport} is exported properly`); + if (internal !== undefined) { + assert.equal(theExport, internal, `${theExport} is exported properly`); + } } - } - ['@test confirm Ember.Helper.helper is exported'](assert) { - let internal = undefined; - let theExport = get(window, 'Ember.Helper.helper'); - assert.ok(`${theExport} is exported`); + ['@test confirm Ember.Helper.helper is exported'](assert) { + let internal = undefined; + let theExport = get(window, 'Ember.Helper.helper'); + assert.ok(`${theExport} is exported`); - if (internal !== undefined) { - assert.equal(theExport, internal, `${theExport} is exported properly`); + if (internal !== undefined) { + assert.equal(theExport, internal, `${theExport} is exported properly`); + } } - } - ['@test confirm Ember.isArray is exported'](assert) { - let internal = isArray; - let theExport = get(window, 'Ember.isArray'); - assert.ok(`${theExport} is exported`); + ['@test confirm Ember.isArray is exported'](assert) { + let internal = isArray; + let theExport = get(window, 'Ember.isArray'); + assert.ok(`${theExport} is exported`); - if (internal !== undefined) { - assert.equal(theExport, internal, `${theExport} is exported properly`); + if (internal !== undefined) { + assert.equal(theExport, internal, `${theExport} is exported properly`); + } } } -}); +); diff --git a/packages/ember/tests/helpers/helper_registration_test.js b/packages/ember/tests/helpers/helper_registration_test.js index f52b4d0da10..b0c8b483765 100644 --- a/packages/ember/tests/helpers/helper_registration_test.js +++ b/packages/ember/tests/helpers/helper_registration_test.js @@ -2,66 +2,113 @@ import { moduleFor, ApplicationTestCase } from 'internal-test-helpers'; import { Controller, Service, inject } from 'ember-runtime'; import { Helper, helper } from 'ember-glimmer'; -moduleFor('Application Lifecycle - Helper Registration', class extends ApplicationTestCase { - ['@test Unbound dashed helpers registered on the container can be late-invoked'](assert) { - this.addTemplate('application', `
{{x-borf}} {{x-borf 'YES'}}
`); - - let myHelper = helper(params => params[0] || 'BORF'); - this.application.register('helper:x-borf', myHelper); - - return this.visit('/').then(() => { - assert.equal(this.$('#wrapper').text(), 'BORF YES', 'The helper was invoked from the container'); - }); - } - - ['@test Bound helpers registered on the container can be late-invoked'](assert) { - this.addTemplate('application', `
{{x-reverse}} {{x-reverse foo}}
`); - - this.add('controller:application', Controller.extend({ - foo: 'alex' - })); - - this.application.register('helper:x-reverse', helper(function([ value ]) { - return value ? value.split('').reverse().join('') : '--'; - })); - - return this.visit('/').then(() => { - assert.equal(this.$('#wrapper').text(), '-- xela', 'The bound helper was invoked from the container'); - }); - } - - ['@test Undashed helpers registered on the container can be invoked'](assert) { - this.addTemplate('application', `
{{omg}}|{{yorp 'boo'}}|{{yorp 'ya'}}
`); - - this.application.register('helper:omg', helper(() => 'OMG')); - - this.application.register('helper:yorp', helper(([ value ]) => value)); - - return this.visit('/').then(() => { - assert.equal(this.$('#wrapper').text(), 'OMG|boo|ya', 'The helper was invoked from the container'); - }); - } - - ['@test Helpers can receive injections'](assert) { - this.addTemplate('application', `
{{full-name}}
`); - - let serviceCalled = false; - - this.add('service:name-builder', Service.extend({ - build() { - serviceCalled = true; - } - })); - - this.add('helper:full-name', Helper.extend({ - nameBuilder: inject.service('name-builder'), - compute() { - this.get('nameBuilder').build(); - } - })); - - return this.visit('/').then(() => { - assert.ok(serviceCalled, 'service was injected, method called'); - }); +moduleFor( + 'Application Lifecycle - Helper Registration', + class extends ApplicationTestCase { + ['@test Unbound dashed helpers registered on the container can be late-invoked']( + assert + ) { + this.addTemplate( + 'application', + `
{{x-borf}} {{x-borf 'YES'}}
` + ); + + let myHelper = helper(params => params[0] || 'BORF'); + this.application.register('helper:x-borf', myHelper); + + return this.visit('/').then(() => { + assert.equal( + this.$('#wrapper').text(), + 'BORF YES', + 'The helper was invoked from the container' + ); + }); + } + + ['@test Bound helpers registered on the container can be late-invoked']( + assert + ) { + this.addTemplate( + 'application', + `
{{x-reverse}} {{x-reverse foo}}
` + ); + + this.add( + 'controller:application', + Controller.extend({ + foo: 'alex' + }) + ); + + this.application.register( + 'helper:x-reverse', + helper(function([value]) { + return value + ? value + .split('') + .reverse() + .join('') + : '--'; + }) + ); + + return this.visit('/').then(() => { + assert.equal( + this.$('#wrapper').text(), + '-- xela', + 'The bound helper was invoked from the container' + ); + }); + } + + ['@test Undashed helpers registered on the container can be invoked']( + assert + ) { + this.addTemplate( + 'application', + `
{{omg}}|{{yorp 'boo'}}|{{yorp 'ya'}}
` + ); + + this.application.register('helper:omg', helper(() => 'OMG')); + + this.application.register('helper:yorp', helper(([value]) => value)); + + return this.visit('/').then(() => { + assert.equal( + this.$('#wrapper').text(), + 'OMG|boo|ya', + 'The helper was invoked from the container' + ); + }); + } + + ['@test Helpers can receive injections'](assert) { + this.addTemplate('application', `
{{full-name}}
`); + + let serviceCalled = false; + + this.add( + 'service:name-builder', + Service.extend({ + build() { + serviceCalled = true; + } + }) + ); + + this.add( + 'helper:full-name', + Helper.extend({ + nameBuilder: inject.service('name-builder'), + compute() { + this.get('nameBuilder').build(); + } + }) + ); + + return this.visit('/').then(() => { + assert.ok(serviceCalled, 'service was injected, method called'); + }); + } } -}); +); diff --git a/packages/ember/tests/helpers/link_to_test.js b/packages/ember/tests/helpers/link_to_test.js index 4b0846f3f4e..0332769d12c 100644 --- a/packages/ember/tests/helpers/link_to_test.js +++ b/packages/ember/tests/helpers/link_to_test.js @@ -1,13 +1,6 @@ -import { - moduleFor, - ApplicationTestCase -} from 'internal-test-helpers'; +import { moduleFor, ApplicationTestCase } from 'internal-test-helpers'; -import { - Controller, - inject, - A as emberA -} from 'ember-runtime'; +import { Controller, inject, A as emberA } from 'ember-runtime'; import { instrumentationSubscribe as subscribe, instrumentationReset as reset, @@ -31,677 +24,1029 @@ function shouldBeActive(assert, element) { function checkActive(assert, element, active) { let classList = element.attr('class'); - assert.equal(classList.indexOf('active') > -1, active, `${element} active should be ${active}`); + assert.equal( + classList.indexOf('active') > -1, + active, + `${element} active should be ${active}` + ); } -moduleFor('The {{link-to}} helper - basic tests', class extends ApplicationTestCase { - - constructor() { - super(); +moduleFor( + 'The {{link-to}} helper - basic tests', + class extends ApplicationTestCase { + constructor() { + super(); - this.router.map(function() { - this.route('about'); - }); + this.router.map(function() { + this.route('about'); + }); - this.addTemplate('index', ` + this.addTemplate( + 'index', + `

Home

{{#link-to 'about' id='about-link'}}About{{/link-to}} {{#link-to 'index' id='self-link'}}Self{{/link-to}} - `); - this.addTemplate('about', ` + ` + ); + this.addTemplate( + 'about', + `

About

{{#link-to 'index' id='home-link'}}Home{{/link-to}} {{#link-to 'about' id='self-link'}}Self{{/link-to}} - `); - } - - ['@test The {{link-to}} helper moves into the named route'](assert) { - return this.visit('/') - .then(() => { - assert.equal(this.$('h3.home').length, 1, 'The home template was rendered'); - assert.equal(this.$('#self-link.active').length, 1, 'The self-link was rendered with active class'); - assert.equal(this.$('#about-link:not(.active)').length, 1, 'The other link was rendered without active class'); + ` + ); + } - return this.click('#about-link'); - }) - .then(() => { - assert.equal(this.$('h3.about').length, 1, 'The about template was rendered'); - assert.equal(this.$('#self-link.active').length, 1, 'The self-link was rendered with active class'); - assert.equal(this.$('#home-link:not(.active)').length, 1, 'The other link was rendered without active class'); - }); - } + ['@test The {{link-to}} helper moves into the named route'](assert) { + return this.visit('/') + .then(() => { + assert.equal( + this.$('h3.home').length, + 1, + 'The home template was rendered' + ); + assert.equal( + this.$('#self-link.active').length, + 1, + 'The self-link was rendered with active class' + ); + assert.equal( + this.$('#about-link:not(.active)').length, + 1, + 'The other link was rendered without active class' + ); + + return this.click('#about-link'); + }) + .then(() => { + assert.equal( + this.$('h3.about').length, + 1, + 'The about template was rendered' + ); + assert.equal( + this.$('#self-link.active').length, + 1, + 'The self-link was rendered with active class' + ); + assert.equal( + this.$('#home-link:not(.active)').length, + 1, + 'The other link was rendered without active class' + ); + }); + } - [`@test the {{link-to}} helper doesn't add an href when the tagName isn't 'a'`](assert) { - this.addTemplate('index', ` + [`@test the {{link-to}} helper doesn't add an href when the tagName isn't 'a'`]( + assert + ) { + this.addTemplate( + 'index', + ` {{#link-to 'about' id='about-link' tagName='div'}}About{{/link-to}} - `); + ` + ); - return this.visit('/').then(() => { - assert.equal(this.$('#about-link').attr('href'), undefined, 'there is no href attribute'); - }); - } + return this.visit('/').then(() => { + assert.equal( + this.$('#about-link').attr('href'), + undefined, + 'there is no href attribute' + ); + }); + } - [`@test the {{link-to}} applies a 'disabled' class when disabled`](assert) { - this.addTemplate('index', ` + [`@test the {{link-to}} applies a 'disabled' class when disabled`](assert) { + this.addTemplate( + 'index', + ` {{#link-to "about" id="about-link-static" disabledWhen="shouldDisable"}}About{{/link-to}} {{#link-to "about" id="about-link-dynamic" disabledWhen=dynamicDisabledWhen}}About{{/link-to}} - `); - - this.add('controller:index', Controller.extend({ - shouldDisable: true, - dynamicDisabledWhen: 'shouldDisable' - })); - - return this.visit('/').then(() => { - assert.equal(this.$('#about-link-static.disabled').length, 1, 'The static link is disabled when its disabledWhen is true'); - assert.equal(this.$('#about-link-dynamic.disabled').length, 1, 'The dynamic link is disabled when its disabledWhen is true'); - - let controller = this.applicationInstance.lookup('controller:index'); - this.runTask(() => controller.set('dynamicDisabledWhen', false)); + ` + ); + + this.add( + 'controller:index', + Controller.extend({ + shouldDisable: true, + dynamicDisabledWhen: 'shouldDisable' + }) + ); + + return this.visit('/').then(() => { + assert.equal( + this.$('#about-link-static.disabled').length, + 1, + 'The static link is disabled when its disabledWhen is true' + ); + assert.equal( + this.$('#about-link-dynamic.disabled').length, + 1, + 'The dynamic link is disabled when its disabledWhen is true' + ); - assert.equal(this.$('#about-link-dynamic.disabled').length, 0, 'The dynamic link is re-enabled when its disabledWhen becomes false'); - }); - } + let controller = this.applicationInstance.lookup('controller:index'); + this.runTask(() => controller.set('dynamicDisabledWhen', false)); - [`@test the {{link-to}} doesn't apply a 'disabled' class if disabledWhen is not provided`](assert) { - this.addTemplate('index', `{{#link-to "about" id="about-link"}}About{{/link-to}}`); + assert.equal( + this.$('#about-link-dynamic.disabled').length, + 0, + 'The dynamic link is re-enabled when its disabledWhen becomes false' + ); + }); + } - return this.visit('/').then(() => { - assert.ok(!this.$('#about-link').hasClass('disabled'), 'The link is not disabled if disabledWhen not provided'); - }); - } + [`@test the {{link-to}} doesn't apply a 'disabled' class if disabledWhen is not provided`]( + assert + ) { + this.addTemplate( + 'index', + `{{#link-to "about" id="about-link"}}About{{/link-to}}` + ); + + return this.visit('/').then(() => { + assert.ok( + !this.$('#about-link').hasClass('disabled'), + 'The link is not disabled if disabledWhen not provided' + ); + }); + } - [`@test the {{link-to}} helper supports a custom disabledClass`](assert) { - this.addTemplate('index', ` + [`@test the {{link-to}} helper supports a custom disabledClass`](assert) { + this.addTemplate( + 'index', + ` {{#link-to "about" id="about-link" disabledWhen=true disabledClass="do-not-want"}}About{{/link-to}} - `); + ` + ); - return this.visit('/').then(() => { - assert.equal(this.$('#about-link.do-not-want').length, 1, 'The link can apply a custom disabled class'); - }); - } + return this.visit('/').then(() => { + assert.equal( + this.$('#about-link.do-not-want').length, + 1, + 'The link can apply a custom disabled class' + ); + }); + } - [`@test the {{link-to}} helper supports a custom disabledClass set via bound param`](assert) { - this.addTemplate('index', ` + [`@test the {{link-to}} helper supports a custom disabledClass set via bound param`]( + assert + ) { + this.addTemplate( + 'index', + ` {{#link-to "about" id="about-link" disabledWhen=true disabledClass=disabledClass}}About{{/link-to}} - `); + ` + ); - this.add('controller:index', Controller.extend({ - disabledClass: 'do-not-want' - })); + this.add( + 'controller:index', + Controller.extend({ + disabledClass: 'do-not-want' + }) + ); - return this.visit('/').then(() => { - assert.equal(this.$('#about-link.do-not-want').length, 1, 'The link can apply a custom disabled class via bound param'); - }); - } + return this.visit('/').then(() => { + assert.equal( + this.$('#about-link.do-not-want').length, + 1, + 'The link can apply a custom disabled class via bound param' + ); + }); + } - [`@test the {{link-to}} helper does not respond to clicks when disabledWhen`](assert) { - this.addTemplate('index', ` + [`@test the {{link-to}} helper does not respond to clicks when disabledWhen`]( + assert + ) { + this.addTemplate( + 'index', + ` {{#link-to "about" id="about-link" disabledWhen=true}}About{{/link-to}} - `); - - return this.visit('/') - .then(() => { - return this.click('#about-link'); - }) - .then(() => { - assert.equal(this.$('h3.about').length, 0, 'Transitioning did not occur'); - }); - } + ` + ); + + return this.visit('/') + .then(() => { + return this.click('#about-link'); + }) + .then(() => { + assert.equal( + this.$('h3.about').length, + 0, + 'Transitioning did not occur' + ); + }); + } - [`@test the {{link-to}} helper does not respond to clicks when disabled`](assert) { - this.addTemplate('index', ` + [`@test the {{link-to}} helper does not respond to clicks when disabled`]( + assert + ) { + this.addTemplate( + 'index', + ` {{#link-to "about" id="about-link" disabled=true}}About{{/link-to}} - `); - - return this.visit('/') - .then(() => { - return this.click('#about-link'); - }) - .then(() => { - assert.equal(this.$('h3.about').length, 0, 'Transitioning did not occur'); - }); - } + ` + ); + + return this.visit('/') + .then(() => { + return this.click('#about-link'); + }) + .then(() => { + assert.equal( + this.$('h3.about').length, + 0, + 'Transitioning did not occur' + ); + }); + } - [`@test the {{link-to}} helper responds to clicks according to its disabledWhen bound param`](assert) { - this.addTemplate('index', ` + [`@test the {{link-to}} helper responds to clicks according to its disabledWhen bound param`]( + assert + ) { + this.addTemplate( + 'index', + ` {{#link-to "about" id="about-link" disabledWhen=disabledWhen}}About{{/link-to}} - `); - - this.add('controller:index', Controller.extend({ - disabledWhen: true - })); - - return this.visit('/') - .then(() => { - return this.click('#about-link'); - }) - .then(() => { - assert.equal(this.$('h3.about').length, 0, 'Transitioning did not occur'); - - let controller = this.applicationInstance.lookup('controller:index'); - controller.set('disabledWhen', false); - - return this.runLoopSettled(); - }) - .then(() => { - return this.click('#about-link'); - }) - .then(() => { - assert.equal(this.$('h3.about').length, 1, 'Transitioning did occur when disabledWhen became false'); - }); - } + ` + ); + + this.add( + 'controller:index', + Controller.extend({ + disabledWhen: true + }) + ); + + return this.visit('/') + .then(() => { + return this.click('#about-link'); + }) + .then(() => { + assert.equal( + this.$('h3.about').length, + 0, + 'Transitioning did not occur' + ); + + let controller = this.applicationInstance.lookup('controller:index'); + controller.set('disabledWhen', false); + + return this.runLoopSettled(); + }) + .then(() => { + return this.click('#about-link'); + }) + .then(() => { + assert.equal( + this.$('h3.about').length, + 1, + 'Transitioning did occur when disabledWhen became false' + ); + }); + } - [`@test The {{link-to}} helper supports a custom activeClass`](assert) { - this.addTemplate('index', ` + [`@test The {{link-to}} helper supports a custom activeClass`](assert) { + this.addTemplate( + 'index', + `

Home

{{#link-to 'about' id='about-link'}}About{{/link-to}} {{#link-to 'index' id='self-link' activeClass='zomg-active'}}Self{{/link-to}} - `); + ` + ); - return this.visit('/').then(() => { - assert.equal(this.$('h3.home').length, 1, 'The home template was rendered'); - assert.equal(this.$('#self-link.zomg-active').length, 1, 'The self-link was rendered with active class'); - assert.equal(this.$('#about-link:not(.active)').length, 1, 'The other link was rendered without active class'); - }); - } + return this.visit('/').then(() => { + assert.equal( + this.$('h3.home').length, + 1, + 'The home template was rendered' + ); + assert.equal( + this.$('#self-link.zomg-active').length, + 1, + 'The self-link was rendered with active class' + ); + assert.equal( + this.$('#about-link:not(.active)').length, + 1, + 'The other link was rendered without active class' + ); + }); + } - [`@test The {{link-to}} helper supports a custom activeClass from a bound param`](assert) { - this.addTemplate('index', ` + [`@test The {{link-to}} helper supports a custom activeClass from a bound param`]( + assert + ) { + this.addTemplate( + 'index', + `

Home

{{#link-to 'about' id='about-link'}}About{{/link-to}} {{#link-to 'index' id='self-link' activeClass=activeClass}}Self{{/link-to}} - `); + ` + ); - this.add('controller:index', Controller.extend({ - activeClass: 'zomg-active' - })); + this.add( + 'controller:index', + Controller.extend({ + activeClass: 'zomg-active' + }) + ); - return this.visit('/').then(() => { - assert.equal(this.$('h3.home').length, 1, 'The home template was rendered'); - assert.equal(this.$('#self-link.zomg-active').length, 1, 'The self-link was rendered with active class'); - assert.equal(this.$('#about-link:not(.active)').length, 1, 'The other link was rendered without active class'); - }); - } + return this.visit('/').then(() => { + assert.equal( + this.$('h3.home').length, + 1, + 'The home template was rendered' + ); + assert.equal( + this.$('#self-link.zomg-active').length, + 1, + 'The self-link was rendered with active class' + ); + assert.equal( + this.$('#about-link:not(.active)').length, + 1, + 'The other link was rendered without active class' + ); + }); + } - [`@test The {{link-to}} helper supports 'classNameBindings' with custom values [GH #11699]`](assert) { - this.addTemplate('index', ` + [`@test The {{link-to}} helper supports 'classNameBindings' with custom values [GH #11699]`]( + assert + ) { + this.addTemplate( + 'index', + `

Home

{{#link-to 'about' id='about-link' classNameBindings='foo:foo-is-true:foo-is-false'}}About{{/link-to}} - `); + ` + ); - this.add('controller:index', Controller.extend({ - foo: false - })); + this.add( + 'controller:index', + Controller.extend({ + foo: false + }) + ); - return this.visit('/').then(() => { - assert.equal(this.$('#about-link.foo-is-false').length, 1, 'The about-link was rendered with the falsy class'); + return this.visit('/').then(() => { + assert.equal( + this.$('#about-link.foo-is-false').length, + 1, + 'The about-link was rendered with the falsy class' + ); - let controller = this.applicationInstance.lookup('controller:index'); - this.runTask(() => controller.set('foo', true)); + let controller = this.applicationInstance.lookup('controller:index'); + this.runTask(() => controller.set('foo', true)); - assert.equal(this.$('#about-link.foo-is-true').length, 1, 'The about-link was rendered with the truthy class after toggling the property'); - }); + assert.equal( + this.$('#about-link.foo-is-true').length, + 1, + 'The about-link was rendered with the truthy class after toggling the property' + ); + }); + } } -}); - -moduleFor('The {{link-to}} helper - location hooks', class extends ApplicationTestCase { +); - constructor() { - super(); - - this.updateCount = 0; - this.replaceCount = 0; +moduleFor( + 'The {{link-to}} helper - location hooks', + class extends ApplicationTestCase { + constructor() { + super(); - let testContext = this; - this.add('location:none', NoneLocation.extend({ - setURL() { - testContext.updateCount++; - return this._super(...arguments); - }, - replaceURL() { - testContext.replaceCount++; - return this._super(...arguments); - } - })); + this.updateCount = 0; + this.replaceCount = 0; + + let testContext = this; + this.add( + 'location:none', + NoneLocation.extend({ + setURL() { + testContext.updateCount++; + return this._super(...arguments); + }, + replaceURL() { + testContext.replaceCount++; + return this._super(...arguments); + } + }) + ); - this.router.map(function() { - this.route('about'); - }); + this.router.map(function() { + this.route('about'); + }); - this.addTemplate('index', ` + this.addTemplate( + 'index', + `

Home

{{#link-to 'about' id='about-link'}}About{{/link-to}} {{#link-to 'index' id='self-link'}}Self{{/link-to}} - `); - this.addTemplate('about', ` + ` + ); + this.addTemplate( + 'about', + `

About

{{#link-to 'index' id='home-link'}}Home{{/link-to}} {{#link-to 'about' id='self-link'}}Self{{/link-to}} - `); - } + ` + ); + } - visit() { - return super.visit(...arguments).then(() => { - this.updateCountAfterVisit = this.updateCount; - this.replaceCountAfterVisit = this.replaceCount; - }); - } + visit() { + return super.visit(...arguments).then(() => { + this.updateCountAfterVisit = this.updateCount; + this.replaceCountAfterVisit = this.replaceCount; + }); + } - ['@test The {{link-to}} helper supports URL replacement'](assert) { - this.addTemplate('index', ` + ['@test The {{link-to}} helper supports URL replacement'](assert) { + this.addTemplate( + 'index', + `

Home

{{#link-to 'about' id='about-link' replace=true}}About{{/link-to}} - `); - - return this.visit('/') - .then(() => { - return this.click('#about-link'); - }) - .then(() => { - assert.equal( - this.updateCount, this.updateCountAfterVisit, - 'setURL should not be called' - ); - assert.equal( - this.replaceCount, this.replaceCountAfterVisit + 1, - 'replaceURL should be called once' - ); - }); - } + ` + ); + + return this.visit('/') + .then(() => { + return this.click('#about-link'); + }) + .then(() => { + assert.equal( + this.updateCount, + this.updateCountAfterVisit, + 'setURL should not be called' + ); + assert.equal( + this.replaceCount, + this.replaceCountAfterVisit + 1, + 'replaceURL should be called once' + ); + }); + } - ['@test The {{link-to}} helper supports URL replacement via replace=boundTruthyThing'](assert) { - this.addTemplate('index', ` + ['@test The {{link-to}} helper supports URL replacement via replace=boundTruthyThing']( + assert + ) { + this.addTemplate( + 'index', + `

Home

{{#link-to 'about' id='about-link' replace=boundTruthyThing}}About{{/link-to}} - `); - - this.add('controller:index', Controller.extend({ - boundTruthyThing: true - })); - - return this.visit('/') - .then(() => { - return this.click('#about-link'); - }) - .then(() => { - assert.equal( - this.updateCount, this.updateCountAfterVisit, - 'setURL should not be called' - ); - assert.equal( - this.replaceCount, this.replaceCountAfterVisit + 1, - 'replaceURL should be called once' - ); - }); - } + ` + ); + + this.add( + 'controller:index', + Controller.extend({ + boundTruthyThing: true + }) + ); + + return this.visit('/') + .then(() => { + return this.click('#about-link'); + }) + .then(() => { + assert.equal( + this.updateCount, + this.updateCountAfterVisit, + 'setURL should not be called' + ); + assert.equal( + this.replaceCount, + this.replaceCountAfterVisit + 1, + 'replaceURL should be called once' + ); + }); + } - ['@test The {{link-to}} helper supports setting replace=boundFalseyThing'](assert) { - this.addTemplate('index', ` + ['@test The {{link-to}} helper supports setting replace=boundFalseyThing']( + assert + ) { + this.addTemplate( + 'index', + `

Home

{{#link-to 'about' id='about-link' replace=boundFalseyThing}}About{{/link-to}} - `); - - this.add('controller:index', Controller.extend({ - boundFalseyThing: false - })); - - return this.visit('/') - .then(() => { - return this.click('#about-link'); - }) - .then(() => { - assert.equal( - this.updateCount, this.updateCountAfterVisit + 1, - 'setURL should be called' - ); - assert.equal( - this.replaceCount, this.replaceCountAfterVisit, - 'replaceURL should not be called' - ); - }); + ` + ); + + this.add( + 'controller:index', + Controller.extend({ + boundFalseyThing: false + }) + ); + + return this.visit('/') + .then(() => { + return this.click('#about-link'); + }) + .then(() => { + assert.equal( + this.updateCount, + this.updateCountAfterVisit + 1, + 'setURL should be called' + ); + assert.equal( + this.replaceCount, + this.replaceCountAfterVisit, + 'replaceURL should not be called' + ); + }); + } } - -}); +); if (EMBER_IMPROVED_INSTRUMENTATION) { - moduleFor('The {{link-to}} helper with EMBER_IMPROVED_INSTRUMENTATION', class extends ApplicationTestCase { - - constructor() { - super(); - - this.router.map(function() { - this.route('about'); - }); + moduleFor( + 'The {{link-to}} helper with EMBER_IMPROVED_INSTRUMENTATION', + class extends ApplicationTestCase { + constructor() { + super(); + + this.router.map(function() { + this.route('about'); + }); - this.addTemplate('index', ` + this.addTemplate( + 'index', + `

Home

{{#link-to 'about' id='about-link'}}About{{/link-to}} {{#link-to 'index' id='self-link'}}Self{{/link-to}} - `); - this.addTemplate('about', ` + ` + ); + this.addTemplate( + 'about', + `

About

{{#link-to 'index' id='home-link'}}Home{{/link-to}} {{#link-to 'about' id='self-link'}}Self{{/link-to}} - `); - } - - beforeEach() { - return this.visit('/'); - } + ` + ); + } - afterEach() { - reset(); + beforeEach() { + return this.visit('/'); + } - return super.afterEach(); - } + afterEach() { + reset(); - ['@test The {{link-to}} helper fires an interaction event'](assert) { - assert.expect(2); - - subscribe('interaction.link-to', { - before() { - assert.ok(true, 'instrumentation subscriber was called'); - }, - after() { - assert.ok(true, 'instrumentation subscriber was called'); - } - }); + return super.afterEach(); + } - return this.click('#about-link'); - } + ['@test The {{link-to}} helper fires an interaction event'](assert) { + assert.expect(2); - ['@test The {{link-to}} helper interaction event includes the route name'](assert) { - assert.expect(2); + subscribe('interaction.link-to', { + before() { + assert.ok(true, 'instrumentation subscriber was called'); + }, + after() { + assert.ok(true, 'instrumentation subscriber was called'); + } + }); - subscribe('interaction.link-to', { - before(name, timestamp, { routeName }) { - assert.equal(routeName, 'about', 'instrumentation subscriber was passed route name'); - }, - after(name, timestamp, { routeName }) { - assert.equal(routeName, 'about', 'instrumentation subscriber was passed route name'); - } - }); + return this.click('#about-link'); + } - return this.click('#about-link'); - } + ['@test The {{link-to}} helper interaction event includes the route name']( + assert + ) { + assert.expect(2); + + subscribe('interaction.link-to', { + before(name, timestamp, { routeName }) { + assert.equal( + routeName, + 'about', + 'instrumentation subscriber was passed route name' + ); + }, + after(name, timestamp, { routeName }) { + assert.equal( + routeName, + 'about', + 'instrumentation subscriber was passed route name' + ); + } + }); - ['@test The {{link-to}} helper interaction event includes the transition in the after hook'](assert) { - assert.expect(1); + return this.click('#about-link'); + } - subscribe('interaction.link-to', { - before() {}, - after(name, timestamp, { transition }) { - assert.equal(transition.targetName, 'about', 'instrumentation subscriber was passed route name'); - } - }); + ['@test The {{link-to}} helper interaction event includes the transition in the after hook']( + assert + ) { + assert.expect(1); + + subscribe('interaction.link-to', { + before() {}, + after(name, timestamp, { transition }) { + assert.equal( + transition.targetName, + 'about', + 'instrumentation subscriber was passed route name' + ); + } + }); - return this.click('#about-link'); + return this.click('#about-link'); + } } - }); + ); } -moduleFor('The {{link-to}} helper - nested routes and link-to arguments', class extends ApplicationTestCase { - - ['@test The {{link-to}} helper supports leaving off .index for nested routes'](assert) { - this.router.map(function() { - this.route('about', function() { - this.route('item'); +moduleFor( + 'The {{link-to}} helper - nested routes and link-to arguments', + class extends ApplicationTestCase { + ['@test The {{link-to}} helper supports leaving off .index for nested routes']( + assert + ) { + this.router.map(function() { + this.route('about', function() { + this.route('item'); + }); }); - }); - this.addTemplate('about', `

About

{{outlet}}`); - this.addTemplate('about.index', `
Index
`); - this.addTemplate('about.item', `
{{#link-to 'about'}}About{{/link-to}}
`); - - return this.visit('/about/item').then(() => { - assert.equal(normalizeUrl(this.$('#item a').attr('href')), '/about'); - }); - } + this.addTemplate('about', `

About

{{outlet}}`); + this.addTemplate('about.index', `
Index
`); + this.addTemplate( + 'about.item', + `
{{#link-to 'about'}}About{{/link-to}}
` + ); - [`@test The {{link-to}} helper supports custom, nested, current-when`](assert) { - this.router.map(function() { - this.route('index', { path: '/' }, function() { - this.route('about'); + return this.visit('/about/item').then(() => { + assert.equal(normalizeUrl(this.$('#item a').attr('href')), '/about'); }); + } - this.route('item'); - }); - - this.addTemplate('index', `

Home

{{outlet}}`); - this.addTemplate('index.about', ` - {{#link-to 'item' id='other-link' current-when='index'}}ITEM{{/link-to}} - `); - - return this.visit('/about').then(() => { - assert.equal(this.$('#other-link.active').length, 1, 'The link is active since current-when is a parent route'); - }); - } - - [`@test The {{link-to}} helper does not disregard current-when when it is given explicitly for a route`](assert) { - this.router.map(function() { - this.route('index', { path: '/' }, function() { - this.route('about'); - }); + [`@test The {{link-to}} helper supports custom, nested, current-when`]( + assert + ) { + this.router.map(function() { + this.route('index', { path: '/' }, function() { + this.route('about'); + }); - this.route('items', function() { this.route('item'); }); - }); - - this.addTemplate('index', `

Home

{{outlet}}`); - this.addTemplate('index.about', ` - {{#link-to 'items' id='other-link' current-when='index'}}ITEM{{/link-to}} - `); - return this.visit('/about').then(() => { - assert.equal(this.$('#other-link.active').length, 1, 'The link is active when current-when is given for explicitly for a route'); - }); - } + this.addTemplate('index', `

Home

{{outlet}}`); + this.addTemplate( + 'index.about', + ` + {{#link-to 'item' id='other-link' current-when='index'}}ITEM{{/link-to}} + ` + ); - ['@test The {{link-to}} helper does not disregard current-when when it is set via a bound param'](assert) { - this.router.map(function() { - this.route('index', { path: '/' }, function() { - this.route('about'); + return this.visit('/about').then(() => { + assert.equal( + this.$('#other-link.active').length, + 1, + 'The link is active since current-when is a parent route' + ); }); + } - this.route('items', function() { - this.route('item'); + [`@test The {{link-to}} helper does not disregard current-when when it is given explicitly for a route`]( + assert + ) { + this.router.map(function() { + this.route('index', { path: '/' }, function() { + this.route('about'); + }); + + this.route('items', function() { + this.route('item'); + }); }); - }); - this.add('controller:index.about', Controller.extend({ - currentWhen: 'index' - })); + this.addTemplate('index', `

Home

{{outlet}}`); + this.addTemplate( + 'index.about', + ` + {{#link-to 'items' id='other-link' current-when='index'}}ITEM{{/link-to}} + ` + ); - this.addTemplate('index', `

Home

{{outlet}}`); - this.addTemplate('index.about', `{{#link-to 'items' id='other-link' current-when=currentWhen}}ITEM{{/link-to}}`); + return this.visit('/about').then(() => { + assert.equal( + this.$('#other-link.active').length, + 1, + 'The link is active when current-when is given for explicitly for a route' + ); + }); + } - return this.visit('/about').then(() => { - assert.equal(this.$('#other-link.active').length, 1, 'The link is active when current-when is given for explicitly for a route'); - }); - } + ['@test The {{link-to}} helper does not disregard current-when when it is set via a bound param']( + assert + ) { + this.router.map(function() { + this.route('index', { path: '/' }, function() { + this.route('about'); + }); - ['@test The {{link-to}} helper supports multiple current-when routes'](assert) { - this.router.map(function() { - this.route('index', { path: '/' }, function() { - this.route('about'); + this.route('items', function() { + this.route('item'); + }); }); - this.route('item'); - this.route('foo'); - }); - this.addTemplate('index', `

Home

{{outlet}}`); - this.addTemplate('index.about', `{{#link-to 'item' id='link1' current-when='item index'}}ITEM{{/link-to}}`); - this.addTemplate('item', `{{#link-to 'item' id='link2' current-when='item index'}}ITEM{{/link-to}}`); - this.addTemplate('foo', `{{#link-to 'item' id='link3' current-when='item index'}}ITEM{{/link-to}}`); + this.add( + 'controller:index.about', + Controller.extend({ + currentWhen: 'index' + }) + ); - return this.visit('/about') - .then(() => { - assert.equal(this.$('#link1.active').length, 1, 'The link is active since current-when contains the parent route'); + this.addTemplate('index', `

Home

{{outlet}}`); + this.addTemplate( + 'index.about', + `{{#link-to 'items' id='other-link' current-when=currentWhen}}ITEM{{/link-to}}` + ); - return this.visit('/item'); - }) - .then(() => { - assert.equal(this.$('#link2.active').length, 1, 'The link is active since you are on the active route'); + return this.visit('/about').then(() => { + assert.equal( + this.$('#other-link.active').length, + 1, + 'The link is active when current-when is given for explicitly for a route' + ); + }); + } - return this.visit('/foo'); - }) - .then(() => { - assert.equal(this.$('#link3.active').length, 0, 'The link is not active since current-when does not contain the active route'); + ['@test The {{link-to}} helper supports multiple current-when routes']( + assert + ) { + this.router.map(function() { + this.route('index', { path: '/' }, function() { + this.route('about'); + }); + this.route('item'); + this.route('foo'); }); - } - ['@test The {{link-to}} helper supports boolean values for current-when'](assert) { - this.router.map(function() { - this.route('index', { path: '/' }, function() { - this.route('about'); + this.addTemplate('index', `

Home

{{outlet}}`); + this.addTemplate( + 'index.about', + `{{#link-to 'item' id='link1' current-when='item index'}}ITEM{{/link-to}}` + ); + this.addTemplate( + 'item', + `{{#link-to 'item' id='link2' current-when='item index'}}ITEM{{/link-to}}` + ); + this.addTemplate( + 'foo', + `{{#link-to 'item' id='link3' current-when='item index'}}ITEM{{/link-to}}` + ); + + return this.visit('/about') + .then(() => { + assert.equal( + this.$('#link1.active').length, + 1, + 'The link is active since current-when contains the parent route' + ); + + return this.visit('/item'); + }) + .then(() => { + assert.equal( + this.$('#link2.active').length, + 1, + 'The link is active since you are on the active route' + ); + + return this.visit('/foo'); + }) + .then(() => { + assert.equal( + this.$('#link3.active').length, + 0, + 'The link is not active since current-when does not contain the active route' + ); + }); + } + + ['@test The {{link-to}} helper supports boolean values for current-when']( + assert + ) { + this.router.map(function() { + this.route('index', { path: '/' }, function() { + this.route('about'); + }); + this.route('item'); }); - this.route('item'); - }); - this.addTemplate('index.about', ` + this.addTemplate( + 'index.about', + ` {{#link-to 'index' id='index-link' current-when=isCurrent}}index{{/link-to}} {{#link-to 'item' id='about-link' current-when=true}}ITEM{{/link-to}} - `); - - this.add('controller:index.about', Controller.extend({ isCurrent: false })); - - return this.visit('/about').then(() => { - assert.ok(this.$('#about-link').hasClass('active'), 'The link is active since current-when is true'); - assert.notOk(this.$('#index-link').hasClass('active'), 'The link is not active since current-when is false'); + ` + ); + + this.add( + 'controller:index.about', + Controller.extend({ isCurrent: false }) + ); + + return this.visit('/about').then(() => { + assert.ok( + this.$('#about-link').hasClass('active'), + 'The link is active since current-when is true' + ); + assert.notOk( + this.$('#index-link').hasClass('active'), + 'The link is not active since current-when is false' + ); - let controller = this.applicationInstance.lookup('controller:index.about'); - this.runTask(() => controller.set('isCurrent', true)); + let controller = this.applicationInstance.lookup( + 'controller:index.about' + ); + this.runTask(() => controller.set('isCurrent', true)); - assert.ok(this.$('#index-link').hasClass('active'), 'The link is active since current-when is true'); - }); - } + assert.ok( + this.$('#index-link').hasClass('active'), + 'The link is active since current-when is true' + ); + }); + } - ['@test The {{link-to}} helper defaults to bubbling'](assert) { - this.addTemplate('about', ` + ['@test The {{link-to}} helper defaults to bubbling'](assert) { + this.addTemplate( + 'about', + `
{{#link-to 'about.contact' id='about-contact'}}About{{/link-to}}
{{outlet}} - `); - this.addTemplate('about.contact', ` + ` + ); + this.addTemplate( + 'about.contact', + `

Contact

- `); + ` + ); - this.router.map(function() { - this.route('about', function() { - this.route('contact'); + this.router.map(function() { + this.route('about', function() { + this.route('contact'); + }); }); - }); - let hidden = 0; - - this.add('route:about', Route.extend({ - actions: { - hide() { - hidden++; - } - } - })); - - return this.visit('/about') - .then(() => { - return this.click('#about-contact'); - }) - .then(() => { - assert.equal(this.$('#contact').text(), 'Contact', 'precond - the link worked'); - - assert.equal(hidden, 1, 'The link bubbles'); - }); - } + let hidden = 0; + + this.add( + 'route:about', + Route.extend({ + actions: { + hide() { + hidden++; + } + } + }) + ); + + return this.visit('/about') + .then(() => { + return this.click('#about-contact'); + }) + .then(() => { + assert.equal( + this.$('#contact').text(), + 'Contact', + 'precond - the link worked' + ); + + assert.equal(hidden, 1, 'The link bubbles'); + }); + } - [`@test The {{link-to}} helper supports bubbles=false`](assert) { - this.addTemplate('about', ` + [`@test The {{link-to}} helper supports bubbles=false`](assert) { + this.addTemplate( + 'about', + `
{{#link-to 'about.contact' id='about-contact' bubbles=false}} About {{/link-to}}
{{outlet}} - `); - this.addTemplate('about.contact', `

Contact

`); + ` + ); + this.addTemplate('about.contact', `

Contact

`); - this.router.map(function() { - this.route('about', function() { - this.route('contact'); + this.router.map(function() { + this.route('about', function() { + this.route('contact'); + }); }); - }); - - let hidden = 0; - - this.add('route:about', Route.extend({ - actions: { - hide() { - hidden++; - } - } - })); - - return this.visit('/about') - .then(() => { - return this.click('#about-contact'); - }) - .then(() => { - assert.equal(this.$('#contact').text(), 'Contact', 'precond - the link worked'); - assert.equal(hidden, 0, "The link didn't bubble"); - }); - } + let hidden = 0; + + this.add( + 'route:about', + Route.extend({ + actions: { + hide() { + hidden++; + } + } + }) + ); + + return this.visit('/about') + .then(() => { + return this.click('#about-contact'); + }) + .then(() => { + assert.equal( + this.$('#contact').text(), + 'Contact', + 'precond - the link worked' + ); + + assert.equal(hidden, 0, "The link didn't bubble"); + }); + } - [`@test The {{link-to}} helper supports bubbles=boundFalseyThing`](assert) { - this.addTemplate('about', ` + [`@test The {{link-to}} helper supports bubbles=boundFalseyThing`](assert) { + this.addTemplate( + 'about', + `
{{#link-to 'about.contact' id='about-contact' bubbles=boundFalseyThing}} About {{/link-to}}
{{outlet}} - `); - this.addTemplate('about.contact', `

Contact

`); + ` + ); + this.addTemplate('about.contact', `

Contact

`); - this.add('controller:about', Controller.extend({ - boundFalseyThing: false - })); + this.add( + 'controller:about', + Controller.extend({ + boundFalseyThing: false + }) + ); - this.router.map(function() { - this.route('about', function() { - this.route('contact'); + this.router.map(function() { + this.route('about', function() { + this.route('contact'); + }); }); - }); - let hidden = 0; - - this.add('route:about', Route.extend({ - actions: { - hide() { - hidden++; - } - } - })); + let hidden = 0; + + this.add( + 'route:about', + Route.extend({ + actions: { + hide() { + hidden++; + } + } + }) + ); + + return this.visit('/about') + .then(() => { + return this.click('#about-contact'); + }) + .then(() => { + assert.equal( + this.$('#contact').text(), + 'Contact', + 'precond - the link worked' + ); + assert.equal(hidden, 0, "The link didn't bubble"); + }); + } - return this.visit('/about') - .then(() => { - return this.click('#about-contact'); - }) - .then(() => { - assert.equal(this.$('#contact').text(), 'Contact', 'precond - the link worked'); - assert.equal(hidden, 0, "The link didn't bubble"); + [`@test The {{link-to}} helper moves into the named route with context`]( + assert + ) { + this.router.map(function() { + this.route('about'); + this.route('item', { path: '/item/:id' }); }); - } - - [`@test The {{link-to}} helper moves into the named route with context`](assert) { - this.router.map(function() { - this.route('about'); - this.route('item', { path: '/item/:id' }); - }); - this.addTemplate('about', ` + this.addTemplate( + 'about', + `

List

    {{#each model as |person|}} @@ -713,346 +1058,541 @@ moduleFor('The {{link-to}} helper - nested routes and link-to arguments', class {{/each}}
{{#link-to 'index' id='home-link'}}Home{{/link-to}} - `); + ` + ); - this.addTemplate('item', ` + this.addTemplate( + 'item', + `

Item

{{model.name}}

{{#link-to 'index' id='home-link'}}Home{{/link-to}} - `); + ` + ); - this.addTemplate('index', ` + this.addTemplate( + 'index', + `

Home

{{#link-to 'about' id='about-link'}}About{{/link-to}} - `); - - this.add('route:about', Route.extend({ - model() { - return [ - { id: 'yehuda', name: 'Yehuda Katz' }, - { id: 'tom', name: 'Tom Dale' }, - { id: 'erik', name: 'Erik Brynroflsson' } - ]; - } - })); - - return this.visit('/about') - .then(() => { - assert.equal(this.$('h3.list').length, 1, 'The home template was rendered'); - assert.equal(normalizeUrl(this.$('#home-link').attr('href')), '/', 'The home link points back at /'); - - return this.click('#yehuda'); - }) - .then(() => { - assert.equal(this.$('h3.item').length, 1, 'The item template was rendered'); - assert.equal(this.$('p').text(), 'Yehuda Katz', 'The name is correct'); - - return this.click('#home-link'); - }) - .then(() => { - return this.click('#about-link'); - }) - .then(() => { - assert.equal(normalizeUrl(this.$('li a#yehuda').attr('href')), '/item/yehuda'); - assert.equal(normalizeUrl(this.$('li a#tom').attr('href')), '/item/tom'); - assert.equal(normalizeUrl(this.$('li a#erik').attr('href')), '/item/erik'); - - return this.click('#erik'); - }) - .then(() => { - assert.equal(this.$('h3.item').length, 1, 'The item template was rendered'); - assert.equal(this.$('p').text(), 'Erik Brynroflsson', 'The name is correct'); - }); - } + ` + ); + + this.add( + 'route:about', + Route.extend({ + model() { + return [ + { id: 'yehuda', name: 'Yehuda Katz' }, + { id: 'tom', name: 'Tom Dale' }, + { id: 'erik', name: 'Erik Brynroflsson' } + ]; + } + }) + ); + + return this.visit('/about') + .then(() => { + assert.equal( + this.$('h3.list').length, + 1, + 'The home template was rendered' + ); + assert.equal( + normalizeUrl(this.$('#home-link').attr('href')), + '/', + 'The home link points back at /' + ); + + return this.click('#yehuda'); + }) + .then(() => { + assert.equal( + this.$('h3.item').length, + 1, + 'The item template was rendered' + ); + assert.equal( + this.$('p').text(), + 'Yehuda Katz', + 'The name is correct' + ); + + return this.click('#home-link'); + }) + .then(() => { + return this.click('#about-link'); + }) + .then(() => { + assert.equal( + normalizeUrl(this.$('li a#yehuda').attr('href')), + '/item/yehuda' + ); + assert.equal( + normalizeUrl(this.$('li a#tom').attr('href')), + '/item/tom' + ); + assert.equal( + normalizeUrl(this.$('li a#erik').attr('href')), + '/item/erik' + ); + + return this.click('#erik'); + }) + .then(() => { + assert.equal( + this.$('h3.item').length, + 1, + 'The item template was rendered' + ); + assert.equal( + this.$('p').text(), + 'Erik Brynroflsson', + 'The name is correct' + ); + }); + } - [`@test The {{link-to}} helper binds some anchor html tag common attributes`](assert) { - this.addTemplate('index', ` + [`@test The {{link-to}} helper binds some anchor html tag common attributes`]( + assert + ) { + this.addTemplate( + 'index', + `

Home

{{#link-to 'index' id='self-link' title='title-attr' rel='rel-attr' tabindex='-1'}} Self {{/link-to}} - `); - - return this.visit('/').then(() => { - let link = this.$('#self-link'); - assert.equal(link.attr('title'), 'title-attr', 'The self-link contains title attribute'); - assert.equal(link.attr('rel'), 'rel-attr', 'The self-link contains rel attribute'); - assert.equal(link.attr('tabindex'), '-1', 'The self-link contains tabindex attribute'); - }); - } + ` + ); + + return this.visit('/').then(() => { + let link = this.$('#self-link'); + assert.equal( + link.attr('title'), + 'title-attr', + 'The self-link contains title attribute' + ); + assert.equal( + link.attr('rel'), + 'rel-attr', + 'The self-link contains rel attribute' + ); + assert.equal( + link.attr('tabindex'), + '-1', + 'The self-link contains tabindex attribute' + ); + }); + } - [`@test The {{link-to}} helper supports 'target' attribute`](assert) { - this.addTemplate('index', ` + [`@test The {{link-to}} helper supports 'target' attribute`](assert) { + this.addTemplate( + 'index', + `

Home

{{#link-to 'index' id='self-link' target='_blank'}}Self{{/link-to}} - `); - - return this.visit('/').then(() => { - let link = this.$('#self-link'); - assert.equal(link.attr('target'), '_blank', 'The self-link contains `target` attribute'); - }); - } - - [`@test The {{link-to}} helper supports 'target' attribute specified as a bound param`](assert) { - this.addTemplate('index', `

Home

{{#link-to 'index' id='self-link' target=boundLinkTarget}}Self{{/link-to}}`); + ` + ); - this.add('controller:index', Controller.extend({ - boundLinkTarget: '_blank' - })); + return this.visit('/').then(() => { + let link = this.$('#self-link'); + assert.equal( + link.attr('target'), + '_blank', + 'The self-link contains `target` attribute' + ); + }); + } - return this.visit('/').then(() => { - let link = this.$('#self-link'); - assert.equal(link.attr('target'), '_blank', 'The self-link contains `target` attribute'); - }); - } + [`@test The {{link-to}} helper supports 'target' attribute specified as a bound param`]( + assert + ) { + this.addTemplate( + 'index', + `

Home

{{#link-to 'index' id='self-link' target=boundLinkTarget}}Self{{/link-to}}` + ); + + this.add( + 'controller:index', + Controller.extend({ + boundLinkTarget: '_blank' + }) + ); + + return this.visit('/').then(() => { + let link = this.$('#self-link'); + assert.equal( + link.attr('target'), + '_blank', + 'The self-link contains `target` attribute' + ); + }); + } - [`@test the {{link-to}} helper calls preventDefault`]() { - this.router.map(function() { - this.route('about'); - }); + [`@test the {{link-to}} helper calls preventDefault`]() { + this.router.map(function() { + this.route('about'); + }); - this.addTemplate('index', ` + this.addTemplate( + 'index', + ` {{#link-to 'about' id='about-link'}}About{{/link-to}} - `); + ` + ); - return this.visit('/').then(() => { - assertNav({ prevented: true }, () => this.$('#about-link').click()); - }); - } + return this.visit('/').then(() => { + assertNav({ prevented: true }, () => this.$('#about-link').click()); + }); + } - [`@test the {{link-to}} helper does not call preventDefault if 'preventDefault=false' is passed as an option`]() { - this.router.map(function() { - this.route('about'); - }); + [`@test the {{link-to}} helper does not call preventDefault if 'preventDefault=false' is passed as an option`]() { + this.router.map(function() { + this.route('about'); + }); - this.addTemplate('index', ` + this.addTemplate( + 'index', + ` {{#link-to 'about' id='about-link' preventDefault=false}}About{{/link-to}} - `); + ` + ); - return this.visit('/').then(() => { - assertNav({ prevented: false }, () => this.$('#about-link').trigger('click')); - }); - } + return this.visit('/').then(() => { + assertNav({ prevented: false }, () => + this.$('#about-link').trigger('click') + ); + }); + } - [`@test the {{link-to}} helper does not call preventDefault if 'preventDefault=boundFalseyThing' is passed as an option`]() { - this.router.map(function() { - this.route('about'); - }); + [`@test the {{link-to}} helper does not call preventDefault if 'preventDefault=boundFalseyThing' is passed as an option`]() { + this.router.map(function() { + this.route('about'); + }); - this.addTemplate('index', ` + this.addTemplate( + 'index', + ` {{#link-to 'about' id='about-link' preventDefault=boundFalseyThing}}About{{/link-to}} - `); - - this.add('controller:index', Controller.extend({ - boundFalseyThing: false - })); - - return this.visit('/').then(() => { - assertNav({ prevented: false }, () => this.$('#about-link').trigger('click')); - }); - } + ` + ); + + this.add( + 'controller:index', + Controller.extend({ + boundFalseyThing: false + }) + ); + + return this.visit('/').then(() => { + assertNav({ prevented: false }, () => + this.$('#about-link').trigger('click') + ); + }); + } - [`@test The {{link-to}} helper does not call preventDefault if 'target' attribute is provided`]() { - this.addTemplate('index', ` + [`@test The {{link-to}} helper does not call preventDefault if 'target' attribute is provided`]() { + this.addTemplate( + 'index', + `

Home

{{#link-to 'index' id='self-link' target='_blank'}}Self{{/link-to}} - `); + ` + ); - return this.visit('/').then(() => { - assertNav({ prevented: false }, () => this.$('#self-link').click()); - }); - } + return this.visit('/').then(() => { + assertNav({ prevented: false }, () => this.$('#self-link').click()); + }); + } - [`@test The {{link-to}} helper should preventDefault when 'target = _self'`]() { - this.addTemplate('index', ` + [`@test The {{link-to}} helper should preventDefault when 'target = _self'`]() { + this.addTemplate( + 'index', + `

Home

{{#link-to 'index' id='self-link' target='_self'}}Self{{/link-to}} - `); + ` + ); - return this.visit('/').then(() => { - assertNav({ prevented: true }, () => this.$('#self-link').click()); - }); - } + return this.visit('/').then(() => { + assertNav({ prevented: true }, () => this.$('#self-link').click()); + }); + } - [`@test The {{link-to}} helper should not transition if target is not equal to _self or empty`](assert) { - this.addTemplate('index', ` + [`@test The {{link-to}} helper should not transition if target is not equal to _self or empty`]( + assert + ) { + this.addTemplate( + 'index', + ` {{#link-to 'about' id='about-link' replace=true target='_blank'}} About {{/link-to}} - `); - - this.router.map(function() { - this.route('about'); - }); - - return this.visit('/') - .then(() => this.click('#about-link')) - .then(() => { - let currentRouteName = this.applicationInstance.lookup('controller:application').get('currentRouteName'); - assert.notEqual(currentRouteName, 'about', 'link-to should not transition if target is not equal to _self or empty'); - }); - } + ` + ); - [`@test The {{link-to}} helper accepts string/numeric arguments`](assert) { - this.router.map(function() { - this.route('filter', { path: '/filters/:filter' }); - this.route('post', { path: '/post/:post_id' }); - this.route('repo', { path: '/repo/:owner/:name' }); - }); + this.router.map(function() { + this.route('about'); + }); + + return this.visit('/') + .then(() => this.click('#about-link')) + .then(() => { + let currentRouteName = this.applicationInstance + .lookup('controller:application') + .get('currentRouteName'); + assert.notEqual( + currentRouteName, + 'about', + 'link-to should not transition if target is not equal to _self or empty' + ); + }); + } - this.add('controller:filter', Controller.extend({ - filter: 'unpopular', - repo: { owner: 'ember', name: 'ember.js' }, - post_id: 123 - })); + [`@test The {{link-to}} helper accepts string/numeric arguments`](assert) { + this.router.map(function() { + this.route('filter', { path: '/filters/:filter' }); + this.route('post', { path: '/post/:post_id' }); + this.route('repo', { path: '/repo/:owner/:name' }); + }); - this.addTemplate('filter', ` + this.add( + 'controller:filter', + Controller.extend({ + filter: 'unpopular', + repo: { owner: 'ember', name: 'ember.js' }, + post_id: 123 + }) + ); + + this.addTemplate( + 'filter', + `

{{filter}}

{{#link-to "filter" "unpopular" id="link"}}Unpopular{{/link-to}} {{#link-to "filter" filter id="path-link"}}Unpopular{{/link-to}} {{#link-to "post" post_id id="post-path-link"}}Post{{/link-to}} {{#link-to "post" 123 id="post-number-link"}}Post{{/link-to}} {{#link-to "repo" repo id="repo-object-link"}}Repo{{/link-to}} - `); - - return this.visit('/filters/popular').then(() => { - assert.equal(normalizeUrl(this.$('#link').attr('href')), '/filters/unpopular'); - assert.equal(normalizeUrl(this.$('#path-link').attr('href')), '/filters/unpopular'); - assert.equal(normalizeUrl(this.$('#post-path-link').attr('href')), '/post/123'); - assert.equal(normalizeUrl(this.$('#post-number-link').attr('href')), '/post/123'); - assert.equal(normalizeUrl(this.$('#repo-object-link').attr('href')), '/repo/ember/ember.js'); - }); - } + ` + ); - [`@test Issue 4201 - Shorthand for route.index shouldn't throw errors about context arguments`](assert) { - assert.expect(2); - this.router.map(function() { - this.route('lobby', function() { - this.route('index', { path: ':lobby_id' }); - this.route('list'); + return this.visit('/filters/popular').then(() => { + assert.equal( + normalizeUrl(this.$('#link').attr('href')), + '/filters/unpopular' + ); + assert.equal( + normalizeUrl(this.$('#path-link').attr('href')), + '/filters/unpopular' + ); + assert.equal( + normalizeUrl(this.$('#post-path-link').attr('href')), + '/post/123' + ); + assert.equal( + normalizeUrl(this.$('#post-number-link').attr('href')), + '/post/123' + ); + assert.equal( + normalizeUrl(this.$('#repo-object-link').attr('href')), + '/repo/ember/ember.js' + ); }); - }); + } - this.add('route:lobby.index', Route.extend({ - model(params) { - assert.equal(params.lobby_id, 'foobar'); - return params.lobby_id; - } - })); + [`@test Issue 4201 - Shorthand for route.index shouldn't throw errors about context arguments`]( + assert + ) { + assert.expect(2); + this.router.map(function() { + this.route('lobby', function() { + this.route('index', { path: ':lobby_id' }); + this.route('list'); + }); + }); - this.addTemplate('lobby.index', ` + this.add( + 'route:lobby.index', + Route.extend({ + model(params) { + assert.equal(params.lobby_id, 'foobar'); + return params.lobby_id; + } + }) + ); + + this.addTemplate( + 'lobby.index', + ` {{#link-to 'lobby' 'foobar' id='lobby-link'}}Lobby{{/link-to}} - `); - this.addTemplate('lobby.list', ` + ` + ); + this.addTemplate( + 'lobby.list', + ` {{#link-to 'lobby' 'foobar' id='lobby-link'}}Lobby{{/link-to}} - `); + ` + ); - return this.visit('/lobby/list') - .then(() => this.click('#lobby-link')) - .then(() => shouldBeActive(assert, this.$('#lobby-link'))); - } + return this.visit('/lobby/list') + .then(() => this.click('#lobby-link')) + .then(() => shouldBeActive(assert, this.$('#lobby-link'))); + } - [`@test Quoteless route param performs property lookup`](assert) { - this.router.map(function() { - this.route('about'); - }); + [`@test Quoteless route param performs property lookup`](assert) { + this.router.map(function() { + this.route('about'); + }); - this.addTemplate('index', ` + this.addTemplate( + 'index', + ` {{#link-to 'index' id='string-link'}}string{{/link-to}} {{#link-to foo id='path-link'}}path{{/link-to}} - `); + ` + ); - this.add('controller:index', Controller.extend({ - foo: 'index' - })); + this.add( + 'controller:index', + Controller.extend({ + foo: 'index' + }) + ); - let assertEquality = href => { - assert.equal(normalizeUrl(this.$('#string-link').attr('href')), '/'); - assert.equal(normalizeUrl(this.$('#path-link').attr('href')), href); - }; + let assertEquality = href => { + assert.equal(normalizeUrl(this.$('#string-link').attr('href')), '/'); + assert.equal(normalizeUrl(this.$('#path-link').attr('href')), href); + }; - return this.visit('/').then(() => { - assertEquality('/'); + return this.visit('/').then(() => { + assertEquality('/'); - let controller = this.applicationInstance.lookup('controller:index'); - this.runTask(() => controller.set('foo', 'about')); + let controller = this.applicationInstance.lookup('controller:index'); + this.runTask(() => controller.set('foo', 'about')); - assertEquality('/about'); - }); - } + assertEquality('/about'); + }); + } - [`@test The {{link-to}} helper refreshes href element when one of params changes`](assert) { - this.router.map(function() { - this.route('post', { path: '/posts/:post_id' }); - }); + [`@test The {{link-to}} helper refreshes href element when one of params changes`]( + assert + ) { + this.router.map(function() { + this.route('post', { path: '/posts/:post_id' }); + }); - let post = { id: '1' }; - let secondPost = { id: '2' }; + let post = { id: '1' }; + let secondPost = { id: '2' }; - this.addTemplate('index', ` + this.addTemplate( + 'index', + ` {{#link-to "post" post id="post"}}post{{/link-to}} - `); + ` + ); - this.add('controller:index', Controller.extend()); + this.add('controller:index', Controller.extend()); - return this.visit('/').then(() => { - let indexController = this.applicationInstance.lookup('controller:index'); - this.runTask(() => indexController.set('post', post)); + return this.visit('/').then(() => { + let indexController = this.applicationInstance.lookup( + 'controller:index' + ); + this.runTask(() => indexController.set('post', post)); - assert.equal(normalizeUrl(this.$('#post').attr('href')), '/posts/1', 'precond - Link has rendered href attr properly'); + assert.equal( + normalizeUrl(this.$('#post').attr('href')), + '/posts/1', + 'precond - Link has rendered href attr properly' + ); - this.runTask(() => indexController.set('post', secondPost)); + this.runTask(() => indexController.set('post', secondPost)); - assert.equal(this.$('#post').attr('href'), '/posts/2', 'href attr was updated after one of the params had been changed'); + assert.equal( + this.$('#post').attr('href'), + '/posts/2', + 'href attr was updated after one of the params had been changed' + ); - this.runTask(() => indexController.set('post', null)); + this.runTask(() => indexController.set('post', null)); - assert.equal(this.$('#post').attr('href'), '#', 'href attr becomes # when one of the arguments in nullified'); - }); - } + assert.equal( + this.$('#post').attr('href'), + '#', + 'href attr becomes # when one of the arguments in nullified' + ); + }); + } - [`@test The {{link-to}} helper is active when a route is active`](assert) { - this.router.map(function() { - this.route('about', function() { - this.route('item'); + [`@test The {{link-to}} helper is active when a route is active`](assert) { + this.router.map(function() { + this.route('about', function() { + this.route('item'); + }); }); - }); - this.addTemplate('about', ` + this.addTemplate( + 'about', + `
{{#link-to 'about' id='about-link'}}About{{/link-to}} {{#link-to 'about.item' id='item-link'}}Item{{/link-to}} {{outlet}}
- `); - - return this.visit('/about') - .then(() => { - assert.equal(this.$('#about-link.active').length, 1, 'The about route link is active'); - assert.equal(this.$('#item-link.active').length, 0, 'The item route link is inactive'); + ` + ); + + return this.visit('/about') + .then(() => { + assert.equal( + this.$('#about-link.active').length, + 1, + 'The about route link is active' + ); + assert.equal( + this.$('#item-link.active').length, + 0, + 'The item route link is inactive' + ); + + return this.visit('/about/item'); + }) + .then(() => { + assert.equal( + this.$('#about-link.active').length, + 1, + 'The about route link is active' + ); + assert.equal( + this.$('#item-link.active').length, + 1, + 'The item route link is active' + ); + }); + } - return this.visit('/about/item'); - }) - .then(() => { - assert.equal(this.$('#about-link.active').length, 1, 'The about route link is active'); - assert.equal(this.$('#item-link.active').length, 1, 'The item route link is active'); + [`@test The {{link-to}} helper works in an #each'd array of string route names`]( + assert + ) { + this.router.map(function() { + this.route('foo'); + this.route('bar'); + this.route('rar'); }); - } - - [`@test The {{link-to}} helper works in an #each'd array of string route names`](assert) { - this.router.map(function() { - this.route('foo'); - this.route('bar'); - this.route('rar'); - }); - - this.add('controller:index', Controller.extend({ - routeNames: emberA(['foo', 'bar', 'rar']), - route1: 'bar', - route2: 'foo' - })); - this.addTemplate('index', ` + this.add( + 'controller:index', + Controller.extend({ + routeNames: emberA(['foo', 'bar', 'rar']), + route1: 'bar', + route2: 'foo' + }) + ); + + this.addTemplate( + 'index', + ` {{#each routeNames as |routeName|}} {{#link-to routeName}}{{routeName}}{{/link-to}} {{/each}} @@ -1061,128 +1601,234 @@ moduleFor('The {{link-to}} helper - nested routes and link-to arguments', class {{/each}} {{#link-to route1}}a{{/link-to}} {{#link-to route2}}b{{/link-to}} - `); + ` + ); - let linksEqual = (links, expected) => { - assert.equal(links.length, expected.length, 'Has correct number of links'); - - let idx; - for (idx = 0; idx < links.length; idx++) { - let href = this.$(links[idx]).attr('href'); - // Old IE includes the whole hostname as well - assert.equal(href.slice(-expected[idx].length), expected[idx], `Expected link to be '${expected[idx]}', but was '${href}'`); - } - }; + let linksEqual = (links, expected) => { + assert.equal( + links.length, + expected.length, + 'Has correct number of links' + ); - return this.visit('/').then(() => { - linksEqual(this.$('a'), ['/foo', '/bar', '/rar', '/foo', '/bar', '/rar', '/bar', '/foo']); + let idx; + for (idx = 0; idx < links.length; idx++) { + let href = this.$(links[idx]).attr('href'); + // Old IE includes the whole hostname as well + assert.equal( + href.slice(-expected[idx].length), + expected[idx], + `Expected link to be '${expected[idx]}', but was '${href}'` + ); + } + }; - let indexController = this.applicationInstance.lookup('controller:index'); - this.runTask(() => indexController.set('route1', 'rar')); + return this.visit('/').then(() => { + linksEqual(this.$('a'), [ + '/foo', + '/bar', + '/rar', + '/foo', + '/bar', + '/rar', + '/bar', + '/foo' + ]); - linksEqual(this.$('a'), ['/foo', '/bar', '/rar', '/foo', '/bar', '/rar', '/rar', '/foo']); + let indexController = this.applicationInstance.lookup( + 'controller:index' + ); + this.runTask(() => indexController.set('route1', 'rar')); + + linksEqual(this.$('a'), [ + '/foo', + '/bar', + '/rar', + '/foo', + '/bar', + '/rar', + '/rar', + '/foo' + ]); - this.runTask(() => indexController.routeNames.shiftObject()); + this.runTask(() => indexController.routeNames.shiftObject()); - linksEqual(this.$('a'), ['/bar', '/rar', '/bar', '/rar', '/rar', '/foo']); - }); - } + linksEqual(this.$('a'), [ + '/bar', + '/rar', + '/bar', + '/rar', + '/rar', + '/foo' + ]); + }); + } - [`@test The non-block form {{link-to}} helper moves into the named route`](assert) { - assert.expect(3); - this.router.map(function() { - this.route('contact'); - }); + [`@test The non-block form {{link-to}} helper moves into the named route`]( + assert + ) { + assert.expect(3); + this.router.map(function() { + this.route('contact'); + }); - this.addTemplate('index', ` + this.addTemplate( + 'index', + `

Home

{{link-to 'Contact us' 'contact' id='contact-link'}} {{#link-to 'index' id='self-link'}}Self{{/link-to}} - `); - this.addTemplate('contact', ` + ` + ); + this.addTemplate( + 'contact', + `

Contact

{{link-to 'Home' 'index' id='home-link'}} {{link-to 'Self' 'contact' id='self-link'}} - `); + ` + ); + + return this.visit('/') + .then(() => { + return this.click('#contact-link'); + }) + .then(() => { + assert.equal( + this.$('h3.contact').length, + 1, + 'The contact template was rendered' + ); + assert.equal( + this.$('#self-link.active').length, + 1, + 'The self-link was rendered with active class' + ); + assert.equal( + this.$('#home-link:not(.active)').length, + 1, + 'The other link was rendered without active class' + ); + }); + } - return this.visit('/') - .then(() => { - return this.click('#contact-link'); - }) - .then(() => { - assert.equal(this.$('h3.contact').length, 1, 'The contact template was rendered'); - assert.equal(this.$('#self-link.active').length, 1, 'The self-link was rendered with active class'); - assert.equal(this.$('#home-link:not(.active)').length, 1, 'The other link was rendered without active class'); + [`@test The non-block form {{link-to}} helper updates the link text when it is a binding`]( + assert + ) { + assert.expect(8); + this.router.map(function() { + this.route('contact'); }); - } - - [`@test The non-block form {{link-to}} helper updates the link text when it is a binding`](assert) { - assert.expect(8); - this.router.map(function() { - this.route('contact'); - }); - this.add('controller:index', Controller.extend({ - contactName: 'Jane' - })); + this.add( + 'controller:index', + Controller.extend({ + contactName: 'Jane' + }) + ); - this.addTemplate('index', ` + this.addTemplate( + 'index', + `

Home

{{link-to contactName 'contact' id='contact-link'}} {{#link-to 'index' id='self-link'}}Self{{/link-to}} - `); - this.addTemplate('contact', ` + ` + ); + this.addTemplate( + 'contact', + `

Contact

{{link-to 'Home' 'index' id='home-link'}} {{link-to 'Self' 'contact' id='self-link'}} - `); - - return this.visit('/') - .then(() => { - assert.equal(this.$('#contact-link').text(), 'Jane', 'The link title is correctly resolved'); - - let controller = this.applicationInstance.lookup('controller:index'); - this.runTask(() => controller.set('contactName', 'Joe')); - - assert.equal(this.$('#contact-link').text(), 'Joe', 'The link title is correctly updated when the bound property changes'); - - this.runTask(() => controller.set('contactName', 'Robert')); - - assert.equal(this.$('#contact-link').text(), 'Robert', 'The link title is correctly updated when the bound property changes a second time'); + ` + ); + + return this.visit('/') + .then(() => { + assert.equal( + this.$('#contact-link').text(), + 'Jane', + 'The link title is correctly resolved' + ); + + let controller = this.applicationInstance.lookup('controller:index'); + this.runTask(() => controller.set('contactName', 'Joe')); + + assert.equal( + this.$('#contact-link').text(), + 'Joe', + 'The link title is correctly updated when the bound property changes' + ); + + this.runTask(() => controller.set('contactName', 'Robert')); + + assert.equal( + this.$('#contact-link').text(), + 'Robert', + 'The link title is correctly updated when the bound property changes a second time' + ); + + return this.click('#contact-link'); + }) + .then(() => { + assert.equal( + this.$('h3.contact').length, + 1, + 'The contact template was rendered' + ); + assert.equal( + this.$('#self-link.active').length, + 1, + 'The self-link was rendered with active class' + ); + assert.equal( + this.$('#home-link:not(.active)').length, + 1, + 'The other link was rendered without active class' + ); + + return this.click('#home-link'); + }) + .then(() => { + assert.equal( + this.$('h3.home').length, + 1, + 'The index template was rendered' + ); + assert.equal( + this.$('#contact-link').text(), + 'Robert', + 'The link title is correctly updated when the route changes' + ); + }); + } - return this.click('#contact-link'); - }) - .then(() => { - assert.equal(this.$('h3.contact').length, 1, 'The contact template was rendered'); - assert.equal(this.$('#self-link.active').length, 1, 'The self-link was rendered with active class'); - assert.equal(this.$('#home-link:not(.active)').length, 1, 'The other link was rendered without active class'); + [`@test The non-block form {{link-to}} helper moves into the named route with context`]( + assert + ) { + assert.expect(5); - return this.click('#home-link'); - }) - .then(() => { - assert.equal(this.$('h3.home').length, 1, 'The index template was rendered'); - assert.equal(this.$('#contact-link').text(), 'Robert', 'The link title is correctly updated when the route changes'); + this.router.map(function() { + this.route('item', { path: '/item/:id' }); }); - } - - [`@test The non-block form {{link-to}} helper moves into the named route with context`](assert) { - assert.expect(5); - - this.router.map(function() { - this.route('item', { path: '/item/:id' }); - }); - - this.add('route:index', Route.extend({ - model() { - return [ - { id: 'yehuda', name: 'Yehuda Katz' }, - { id: 'tom', name: 'Tom Dale' }, - { id: 'erik', name: 'Erik Brynroflsson' } - ]; - } - })); - this.addTemplate('index', ` + this.add( + 'route:index', + Route.extend({ + model() { + return [ + { id: 'yehuda', name: 'Yehuda Katz' }, + { id: 'tom', name: 'Tom Dale' }, + { id: 'erik', name: 'Erik Brynroflsson' } + ]; + } + }) + ); + + this.addTemplate( + 'index', + `

Home

    {{#each model as |person|}} @@ -1191,409 +1837,550 @@ moduleFor('The {{link-to}} helper - nested routes and link-to arguments', class {{/each}}
- `); - this.addTemplate('item', ` + ` + ); + this.addTemplate( + 'item', + `

Item

{{model.name}}

{{#link-to 'index' id='home-link'}}Home{{/link-to}} - `); - - return this.visit('/') - .then(() => { - return this.click('#yehuda'); - }) - .then(() => { - - assert.equal(this.$('h3.item').length, 1, 'The item template was rendered'); - assert.equal(this.$('p').text(), 'Yehuda Katz', 'The name is correct'); + ` + ); + + return this.visit('/') + .then(() => { + return this.click('#yehuda'); + }) + .then(() => { + assert.equal( + this.$('h3.item').length, + 1, + 'The item template was rendered' + ); + assert.equal( + this.$('p').text(), + 'Yehuda Katz', + 'The name is correct' + ); + + return this.click('#home-link'); + }) + .then(() => { + assert.equal( + normalizeUrl(this.$('li a#yehuda').attr('href')), + '/item/yehuda' + ); + assert.equal( + normalizeUrl(this.$('li a#tom').attr('href')), + '/item/tom' + ); + assert.equal( + normalizeUrl(this.$('li a#erik').attr('href')), + '/item/erik' + ); + }); + } - return this.click('#home-link'); - }) - .then(() => { - assert.equal(normalizeUrl(this.$('li a#yehuda').attr('href')), '/item/yehuda'); - assert.equal(normalizeUrl(this.$('li a#tom').attr('href')), '/item/tom'); - assert.equal(normalizeUrl(this.$('li a#erik').attr('href')), '/item/erik'); + [`@test The non-block form {{link-to}} performs property lookup`](assert) { + this.router.map(function() { + this.route('about'); }); - } - - [`@test The non-block form {{link-to}} performs property lookup`](assert) { - this.router.map(function() { - this.route('about'); - }); - this.addTemplate('index', ` + this.addTemplate( + 'index', + ` {{link-to 'string' 'index' id='string-link'}} {{link-to path foo id='path-link'}} - `); + ` + ); - this.add('controller:index', Controller.extend({ - foo: 'index' - })); + this.add( + 'controller:index', + Controller.extend({ + foo: 'index' + }) + ); - return this.visit('/').then(() => { - let assertEquality = href => { - assert.equal(normalizeUrl(this.$('#string-link').attr('href')), '/'); - assert.equal(normalizeUrl(this.$('#path-link').attr('href')), href); - }; + return this.visit('/').then(() => { + let assertEquality = href => { + assert.equal(normalizeUrl(this.$('#string-link').attr('href')), '/'); + assert.equal(normalizeUrl(this.$('#path-link').attr('href')), href); + }; - assertEquality('/'); + assertEquality('/'); - let controller = this.applicationInstance.lookup('controller:index'); - this.runTask(() => controller.set('foo', 'about')); + let controller = this.applicationInstance.lookup('controller:index'); + this.runTask(() => controller.set('foo', 'about')); - assertEquality('/about'); - }); - } + assertEquality('/about'); + }); + } - [`@test The non-block form {{link-to}} protects against XSS`](assert) { - this.addTemplate('application', `{{link-to display 'index' id='link'}}`); + [`@test The non-block form {{link-to}} protects against XSS`](assert) { + this.addTemplate('application', `{{link-to display 'index' id='link'}}`); - this.add('controller:application', Controller.extend({ - display: 'blahzorz' - })); + this.add( + 'controller:application', + Controller.extend({ + display: 'blahzorz' + }) + ); - return this.visit('/').then(() => { - assert.equal(this.$('#link').text(), 'blahzorz'); + return this.visit('/').then(() => { + assert.equal(this.$('#link').text(), 'blahzorz'); - let controller = this.applicationInstance.lookup('controller:application'); - this.runTask(() => controller.set('display', 'BLAMMO')); + let controller = this.applicationInstance.lookup( + 'controller:application' + ); + this.runTask(() => controller.set('display', 'BLAMMO')); - assert.equal(this.$('#link').text(), 'BLAMMO'); - assert.equal(this.$('b').length, 0); - }); - } + assert.equal(this.$('#link').text(), 'BLAMMO'); + assert.equal(this.$('b').length, 0); + }); + } - [`@test the {{link-to}} helper throws a useful error if you invoke it wrong`](assert) { - assert.expect(1); + [`@test the {{link-to}} helper throws a useful error if you invoke it wrong`]( + assert + ) { + assert.expect(1); - this.router.map(function() { - this.route('post', { path: 'post/:post_id' }); - }); + this.router.map(function() { + this.route('post', { path: 'post/:post_id' }); + }); - this.addTemplate('application', `{{#link-to 'post'}}Post{{/link-to}}`); + this.addTemplate('application', `{{#link-to 'post'}}Post{{/link-to}}`); - assert.throws(() => { - this.visit('/'); - }, /(You attempted to define a `\{\{link-to "post"\}\}` but did not pass the parameters required for generating its dynamic segments.|You must provide param `post_id` to `generate`)/); + assert.throws(() => { + this.visit('/'); + }, /(You attempted to define a `\{\{link-to "post"\}\}` but did not pass the parameters required for generating its dynamic segments.|You must provide param `post_id` to `generate`)/); - return this.runLoopSettled(); - } + return this.runLoopSettled(); + } - [`@test the {{link-to}} helper does not throw an error if its route has exited`](assert) { - assert.expect(0); + [`@test the {{link-to}} helper does not throw an error if its route has exited`]( + assert + ) { + assert.expect(0); - this.router.map(function() { - this.route('post', { path: 'post/:post_id' }); - }); + this.router.map(function() { + this.route('post', { path: 'post/:post_id' }); + }); - this.addTemplate('application', ` + this.addTemplate( + 'application', + ` {{#link-to 'index' id='home-link'}}Home{{/link-to}} {{#link-to 'post' defaultPost id='default-post-link'}}Default Post{{/link-to}} {{#if currentPost}} {{#link-to 'post' currentPost id='current-post-link'}}Current Post{{/link-to}} {{/if}} - `); - - this.add('controller:application', Controller.extend({ - defaultPost: { id: 1 }, - postController: inject.controller('post'), - currentPost: alias('postController.model') - })); - - this.add('controller:post', Controller.extend()); - - this.add('route:post', Route.extend({ - model() { - return { id: 2 }; - }, - serialize(model) { - return { post_id: model.id }; - } - })); - - return this.visit('/') - .then(() => this.click('#default-post-link')) - .then(() => this.click('#home-link')) - .then(() => this.click('#current-post-link')) - .then(() => this.click('#home-link')); - } + ` + ); + + this.add( + 'controller:application', + Controller.extend({ + defaultPost: { id: 1 }, + postController: inject.controller('post'), + currentPost: alias('postController.model') + }) + ); + + this.add('controller:post', Controller.extend()); + + this.add( + 'route:post', + Route.extend({ + model() { + return { id: 2 }; + }, + serialize(model) { + return { post_id: model.id }; + } + }) + ); + + return this.visit('/') + .then(() => this.click('#default-post-link')) + .then(() => this.click('#home-link')) + .then(() => this.click('#current-post-link')) + .then(() => this.click('#home-link')); + } - [`@test {{link-to}} active property respects changing parent route context`](assert) { - this.router.map(function() { - this.route('things', { path: '/things/:name' }, function() { - this.route('other'); + [`@test {{link-to}} active property respects changing parent route context`]( + assert + ) { + this.router.map(function() { + this.route('things', { path: '/things/:name' }, function() { + this.route('other'); + }); }); - }); - this.addTemplate('application', ` + this.addTemplate( + 'application', + ` {{link-to 'OMG' 'things' 'omg' id='omg-link'}} {{link-to 'LOL' 'things' 'lol' id='lol-link'}} - `); - - return this.visit('/things/omg') - .then(() => { - shouldBeActive(assert, this.$('#omg-link')); - shouldNotBeActive(assert, this.$('#lol-link')); + ` + ); + + return this.visit('/things/omg') + .then(() => { + shouldBeActive(assert, this.$('#omg-link')); + shouldNotBeActive(assert, this.$('#lol-link')); + + return this.visit('/things/omg/other'); + }) + .then(() => { + shouldBeActive(assert, this.$('#omg-link')); + shouldNotBeActive(assert, this.$('#lol-link')); + }); + } - return this.visit('/things/omg/other'); - }) - .then(() => { - shouldBeActive(assert, this.$('#omg-link')); - shouldNotBeActive(assert, this.$('#lol-link')); + [`@test {{link-to}} populates href with default query param values even without query-params object`]( + assert + ) { + this.add( + 'controller:index', + Controller.extend({ + queryParams: ['foo'], + foo: '123' + }) + ); + + this.addTemplate( + 'index', + `{{#link-to 'index' id='the-link'}}Index{{/link-to}}` + ); + + return this.visit('/').then(() => { + assert.equal( + this.$('#the-link').attr('href'), + '/', + 'link has right href' + ); }); - } - - [`@test {{link-to}} populates href with default query param values even without query-params object`](assert) { - this.add('controller:index', Controller.extend({ - queryParams: ['foo'], - foo: '123' - })); - - this.addTemplate('index', `{{#link-to 'index' id='the-link'}}Index{{/link-to}}`); - - return this.visit('/').then(() => { - assert.equal(this.$('#the-link').attr('href'), '/', 'link has right href'); - }); - } - - [`@test {{link-to}} populates href with default query param values with empty query-params object`](assert) { - this.add('controller:index', Controller.extend({ - queryParams: ['foo'], - foo: '123' - })); + } - this.addTemplate('index', ` + [`@test {{link-to}} populates href with default query param values with empty query-params object`]( + assert + ) { + this.add( + 'controller:index', + Controller.extend({ + queryParams: ['foo'], + foo: '123' + }) + ); + + this.addTemplate( + 'index', + ` {{#link-to 'index' (query-params) id='the-link'}}Index{{/link-to}} - `); - - return this.visit('/').then(() => { - assert.equal(this.$('#the-link').attr('href'), '/', 'link has right href'); - }); - } + ` + ); - [`@test {{link-to}} with only query-params and a block updates when route changes`](assert) { - this.router.map(function() { - this.route('about'); - }); + return this.visit('/').then(() => { + assert.equal( + this.$('#the-link').attr('href'), + '/', + 'link has right href' + ); + }); + } - this.add('controller:application', Controller.extend({ - queryParams: ['foo', 'bar'], - foo: '123', - bar: 'yes' - })); + [`@test {{link-to}} with only query-params and a block updates when route changes`]( + assert + ) { + this.router.map(function() { + this.route('about'); + }); - this.addTemplate('application', ` + this.add( + 'controller:application', + Controller.extend({ + queryParams: ['foo', 'bar'], + foo: '123', + bar: 'yes' + }) + ); + + this.addTemplate( + 'application', + ` {{#link-to (query-params foo='456' bar='NAW') id='the-link'}}Index{{/link-to}} - `); - - return this.visit('/') - .then(() => { - assert.equal(this.$('#the-link').attr('href'), '/?bar=NAW&foo=456', 'link has right href'); + ` + ); + + return this.visit('/') + .then(() => { + assert.equal( + this.$('#the-link').attr('href'), + '/?bar=NAW&foo=456', + 'link has right href' + ); + + return this.visit('/about'); + }) + .then(() => { + assert.equal( + this.$('#the-link').attr('href'), + '/about?bar=NAW&foo=456', + 'link has right href' + ); + }); + } - return this.visit('/about'); - }) - .then(() => { - assert.equal(this.$('#the-link').attr('href'), '/about?bar=NAW&foo=456', 'link has right href'); + [`@test Block-less {{link-to}} with only query-params updates when route changes`]( + assert + ) { + this.router.map(function() { + this.route('about'); }); - } - [`@test Block-less {{link-to}} with only query-params updates when route changes`](assert) { - this.router.map(function() { - this.route('about'); - }); - - this.add('controller:application', Controller.extend({ - queryParams: ['foo', 'bar'], - foo: '123', - bar: 'yes' - })); - - this.addTemplate('application', ` + this.add( + 'controller:application', + Controller.extend({ + queryParams: ['foo', 'bar'], + foo: '123', + bar: 'yes' + }) + ); + + this.addTemplate( + 'application', + ` {{link-to "Index" (query-params foo='456' bar='NAW') id='the-link'}} - `); - - return this.visit('/') - .then(() => { - assert.equal(this.$('#the-link').attr('href'), '/?bar=NAW&foo=456', 'link has right href'); + ` + ); + + return this.visit('/') + .then(() => { + assert.equal( + this.$('#the-link').attr('href'), + '/?bar=NAW&foo=456', + 'link has right href' + ); + + return this.visit('/about'); + }) + .then(() => { + assert.equal( + this.$('#the-link').attr('href'), + '/about?bar=NAW&foo=456', + 'link has right href' + ); + }); + } - return this.visit('/about'); - }) - .then(() => { - assert.equal(this.$('#the-link').attr('href'), '/about?bar=NAW&foo=456', 'link has right href'); + [`@test The {{link-to}} helper can use dynamic params`](assert) { + this.router.map(function() { + this.route('foo', { path: 'foo/:some/:thing' }); + this.route('bar', { path: 'bar/:some/:thing/:else' }); }); - } - - [`@test The {{link-to}} helper can use dynamic params`](assert) { - this.router.map(function() { - this.route('foo', { path: 'foo/:some/:thing' }); - this.route('bar', { path: 'bar/:some/:thing/:else' }); - }); - - this.add('controller:index', Controller.extend({ - init() { - this._super(...arguments); - this.dynamicLinkParams = [ - 'foo', - 'one', - 'two' - ]; - } - })); - this.addTemplate('index', ` + this.add( + 'controller:index', + Controller.extend({ + init() { + this._super(...arguments); + this.dynamicLinkParams = ['foo', 'one', 'two']; + } + }) + ); + + this.addTemplate( + 'index', + `

Home

{{#link-to params=dynamicLinkParams id="dynamic-link"}}Dynamic{{/link-to}} - `); + ` + ); - return this.visit('/').then(() => { - let link = this.$('#dynamic-link'); + return this.visit('/').then(() => { + let link = this.$('#dynamic-link'); - assert.equal(link.attr('href'), '/foo/one/two'); + assert.equal(link.attr('href'), '/foo/one/two'); - let controller = this.applicationInstance.lookup('controller:index'); - this.runTask(() => { - controller.set('dynamicLinkParams', [ - 'bar', - 'one', - 'two', - 'three' - ]); - }); + let controller = this.applicationInstance.lookup('controller:index'); + this.runTask(() => { + controller.set('dynamicLinkParams', ['bar', 'one', 'two', 'three']); + }); - assert.equal(link.attr('href'), '/bar/one/two/three'); - }); - } + assert.equal(link.attr('href'), '/bar/one/two/three'); + }); + } - [`@test GJ: {{link-to}} to a parent root model hook which performs a 'transitionTo' has correct active class #13256`](assert) { - assert.expect(1); + [`@test GJ: {{link-to}} to a parent root model hook which performs a 'transitionTo' has correct active class #13256`]( + assert + ) { + assert.expect(1); - this.router.map(function() { - this.route('parent', function() { - this.route('child'); + this.router.map(function() { + this.route('parent', function() { + this.route('child'); + }); }); - }); - this.add('route:parent', Route.extend({ - afterModel() { - this.transitionTo('parent.child'); - } - })); - - this.addTemplate('application', ` + this.add( + 'route:parent', + Route.extend({ + afterModel() { + this.transitionTo('parent.child'); + } + }) + ); + + this.addTemplate( + 'application', + ` {{link-to 'Parent' 'parent' id='parent-link'}} - `); - - return this.visit('/') - .then(() => { - return this.click('#parent-link'); - }) - .then(() => { - shouldBeActive(assert, this.$('#parent-link')); - }); + ` + ); + + return this.visit('/') + .then(() => { + return this.click('#parent-link'); + }) + .then(() => { + shouldBeActive(assert, this.$('#parent-link')); + }); + } } +); + +moduleFor( + 'The {{link-to}} helper - loading states and warnings', + class extends ApplicationTestCase { + [`@test link-to with null/undefined dynamic parameters are put in a loading state`]( + assert + ) { + assert.expect(19); + let warningMessage = + 'This link-to is in an inactive loading state because at least one of its parameters presently has a null/undefined value, or the provided route name is invalid.'; -}); - -moduleFor('The {{link-to}} helper - loading states and warnings', class extends ApplicationTestCase { - - [`@test link-to with null/undefined dynamic parameters are put in a loading state`](assert) { - assert.expect(19); - let warningMessage = 'This link-to is in an inactive loading state because at least one of its parameters presently has a null/undefined value, or the provided route name is invalid.'; - - this.router.map(function() { - this.route('thing', { path: '/thing/:thing_id' }); - this.route('about'); - }); + this.router.map(function() { + this.route('thing', { path: '/thing/:thing_id' }); + this.route('about'); + }); - this.addTemplate('index', ` + this.addTemplate( + 'index', + ` {{#link-to destinationRoute routeContext loadingClass='i-am-loading' id='context-link'}} string {{/link-to}} {{#link-to secondRoute loadingClass=loadingClass id='static-link'}} string {{/link-to}} - `); - - this.add('controller:index', Controller.extend({ - destinationRoute: null, - routeContext: null, - loadingClass: 'i-am-loading' - })); - - this.add('route:about', Route.extend({ - activate() { - assert.ok(true, 'About was entered'); - } - })); - - function assertLinkStatus(link, url) { - if (url) { - assert.equal(normalizeUrl(link.attr('href')), url, 'loaded link-to has expected href'); - assert.ok(!link.hasClass('i-am-loading'), 'loaded linkComponent has no loadingClass'); - } else { - assert.equal(normalizeUrl(link.attr('href')), '#', "unloaded link-to has href='#'"); - assert.ok(link.hasClass('i-am-loading'), 'loading linkComponent has loadingClass'); + ` + ); + + this.add( + 'controller:index', + Controller.extend({ + destinationRoute: null, + routeContext: null, + loadingClass: 'i-am-loading' + }) + ); + + this.add( + 'route:about', + Route.extend({ + activate() { + assert.ok(true, 'About was entered'); + } + }) + ); + + function assertLinkStatus(link, url) { + if (url) { + assert.equal( + normalizeUrl(link.attr('href')), + url, + 'loaded link-to has expected href' + ); + assert.ok( + !link.hasClass('i-am-loading'), + 'loaded linkComponent has no loadingClass' + ); + } else { + assert.equal( + normalizeUrl(link.attr('href')), + '#', + "unloaded link-to has href='#'" + ); + assert.ok( + link.hasClass('i-am-loading'), + 'loading linkComponent has loadingClass' + ); + } } - } - - let contextLink, staticLink, controller; - - return this.visit('/') - .then(() => { - contextLink = this.$('#context-link'); - staticLink = this.$('#static-link'); - controller = this.applicationInstance.lookup('controller:index'); - - assertLinkStatus(contextLink); - assertLinkStatus(staticLink); - - return expectWarning(()=> { - return this.click(contextLink[0]); - }, warningMessage); - }) - .then(() => { - - // Set the destinationRoute (context is still null). - this.runTask(() => controller.set('destinationRoute', 'thing')); - assertLinkStatus(contextLink); - - // Set the routeContext to an id - this.runTask(() => controller.set('routeContext', '456')); - assertLinkStatus(contextLink, '/thing/456'); - - // Test that 0 isn't interpreted as falsy. - this.runTask(() => controller.set('routeContext', 0)); - assertLinkStatus(contextLink, '/thing/0'); - // Set the routeContext to an object - this.runTask(() => { - controller.set('routeContext', { id: 123 }); - }); - assertLinkStatus(contextLink, '/thing/123'); - - // Set the destinationRoute back to null. - this.runTask(() => controller.set('destinationRoute', null)); - assertLinkStatus(contextLink); - - return expectWarning(()=> { + let contextLink, staticLink, controller; + + return this.visit('/') + .then(() => { + contextLink = this.$('#context-link'); + staticLink = this.$('#static-link'); + controller = this.applicationInstance.lookup('controller:index'); + + assertLinkStatus(contextLink); + assertLinkStatus(staticLink); + + return expectWarning(() => { + return this.click(contextLink[0]); + }, warningMessage); + }) + .then(() => { + // Set the destinationRoute (context is still null). + this.runTask(() => controller.set('destinationRoute', 'thing')); + assertLinkStatus(contextLink); + + // Set the routeContext to an id + this.runTask(() => controller.set('routeContext', '456')); + assertLinkStatus(contextLink, '/thing/456'); + + // Test that 0 isn't interpreted as falsy. + this.runTask(() => controller.set('routeContext', 0)); + assertLinkStatus(contextLink, '/thing/0'); + + // Set the routeContext to an object + this.runTask(() => { + controller.set('routeContext', { id: 123 }); + }); + assertLinkStatus(contextLink, '/thing/123'); + + // Set the destinationRoute back to null. + this.runTask(() => controller.set('destinationRoute', null)); + assertLinkStatus(contextLink); + + return expectWarning(() => { + return this.click(staticLink[0]); + }, warningMessage); + }) + .then(() => { + this.runTask(() => controller.set('secondRoute', 'about')); + assertLinkStatus(staticLink, '/about'); + + // Click the now-active link return this.click(staticLink[0]); - }, warningMessage); - }) - .then(() => { - this.runTask(() => controller.set('secondRoute', 'about')); - assertLinkStatus(staticLink, '/about'); - - // Click the now-active link - return this.click(staticLink[0]); - }); + }); + } } -}); +); function assertNav(options, callback) { let nav = false; function check(event) { - QUnit.assert.equal(event.defaultPrevented, options.prevented, `expected defaultPrevented=${options.prevented}`); + QUnit.assert.equal( + event.defaultPrevented, + options.prevented, + `expected defaultPrevented=${options.prevented}` + ); nav = true; event.preventDefault(); } diff --git a/packages/ember/tests/helpers/link_to_test/link_to_transitioning_classes_test.js b/packages/ember/tests/helpers/link_to_test/link_to_transitioning_classes_test.js index c9a217bf412..f2967d3a0ae 100644 --- a/packages/ember/tests/helpers/link_to_test/link_to_transitioning_classes_test.js +++ b/packages/ember/tests/helpers/link_to_test/link_to_transitioning_classes_test.js @@ -14,155 +14,179 @@ function assertHasNoClass(assert, selector, label) { assert.equal(selector.hasClass(label), false, testLabel); } -moduleFor('The {{link-to}} helper: .transitioning-in .transitioning-out CSS classes', class extends ApplicationTestCase { - constructor() { - super(); - - this.aboutDefer = RSVP.defer(); - this.otherDefer = RSVP.defer(); - this.newsDefer = RSVP.defer(); - let _this = this; - - this.router.map(function() { - this.route('about'); - this.route('other'); - this.route('news'); - }); - - this.add('route:about', Route.extend({ - model() { - return _this.aboutDefer.promise; - } - })); - - this.add('route:other', Route.extend({ - model() { - return _this.otherDefer.promise; - } - })); - - this.add('route:news', Route.extend({ - model() { - return _this.newsDefer.promise; - } - })); - - this.addTemplate('application',` +moduleFor( + 'The {{link-to}} helper: .transitioning-in .transitioning-out CSS classes', + class extends ApplicationTestCase { + constructor() { + super(); + + this.aboutDefer = RSVP.defer(); + this.otherDefer = RSVP.defer(); + this.newsDefer = RSVP.defer(); + let _this = this; + + this.router.map(function() { + this.route('about'); + this.route('other'); + this.route('news'); + }); + + this.add( + 'route:about', + Route.extend({ + model() { + return _this.aboutDefer.promise; + } + }) + ); + + this.add( + 'route:other', + Route.extend({ + model() { + return _this.otherDefer.promise; + } + }) + ); + + this.add( + 'route:news', + Route.extend({ + model() { + return _this.newsDefer.promise; + } + }) + ); + + this.addTemplate( + 'application', + ` {{outlet}} {{link-to 'Index' 'index' id='index-link'}} {{link-to 'About' 'about' id='about-link'}} {{link-to 'Other' 'other' id='other-link'}} {{link-to 'News' 'news' activeClass=false id='news-link'}} - `); - } + ` + ); + } - beforeEach() { - return this.visit('/'); - } + beforeEach() { + return this.visit('/'); + } - afterEach() { - super.afterEach(); - this.aboutDefer = null; - this.otherDefer = null; - this.newsDefer = null; - } + afterEach() { + super.afterEach(); + this.aboutDefer = null; + this.otherDefer = null; + this.newsDefer = null; + } - ['@test while a transition is underway'](assert) { - let $index = this.$('#index-link'); - let $about = this.$('#about-link'); - let $other = this.$('#other-link'); + ['@test while a transition is underway'](assert) { + let $index = this.$('#index-link'); + let $about = this.$('#about-link'); + let $other = this.$('#other-link'); - $about.click(); + $about.click(); - assertHasClass(assert, $index, 'active'); - assertHasNoClass(assert, $about, 'active'); - assertHasNoClass(assert, $other, 'active'); + assertHasClass(assert, $index, 'active'); + assertHasNoClass(assert, $about, 'active'); + assertHasNoClass(assert, $other, 'active'); - assertHasNoClass(assert, $index, 'ember-transitioning-in'); - assertHasClass(assert, $about, 'ember-transitioning-in'); - assertHasNoClass(assert, $other, 'ember-transitioning-in'); + assertHasNoClass(assert, $index, 'ember-transitioning-in'); + assertHasClass(assert, $about, 'ember-transitioning-in'); + assertHasNoClass(assert, $other, 'ember-transitioning-in'); - assertHasClass(assert, $index, 'ember-transitioning-out'); - assertHasNoClass(assert, $about, 'ember-transitioning-out'); - assertHasNoClass(assert, $other, 'ember-transitioning-out'); + assertHasClass(assert, $index, 'ember-transitioning-out'); + assertHasNoClass(assert, $about, 'ember-transitioning-out'); + assertHasNoClass(assert, $other, 'ember-transitioning-out'); - this.runTask(() => this.aboutDefer.resolve()); + this.runTask(() => this.aboutDefer.resolve()); - assertHasNoClass(assert, $index, 'active'); - assertHasClass(assert, $about, 'active'); - assertHasNoClass(assert, $other, 'active'); + assertHasNoClass(assert, $index, 'active'); + assertHasClass(assert, $about, 'active'); + assertHasNoClass(assert, $other, 'active'); - assertHasNoClass(assert, $index, 'ember-transitioning-in'); - assertHasNoClass(assert, $about, 'ember-transitioning-in'); - assertHasNoClass(assert, $other, 'ember-transitioning-in'); + assertHasNoClass(assert, $index, 'ember-transitioning-in'); + assertHasNoClass(assert, $about, 'ember-transitioning-in'); + assertHasNoClass(assert, $other, 'ember-transitioning-in'); - assertHasNoClass(assert, $index, 'ember-transitioning-out'); - assertHasNoClass(assert, $about, 'ember-transitioning-out'); - assertHasNoClass(assert, $other, 'ember-transitioning-out'); - } + assertHasNoClass(assert, $index, 'ember-transitioning-out'); + assertHasNoClass(assert, $about, 'ember-transitioning-out'); + assertHasNoClass(assert, $other, 'ember-transitioning-out'); + } - ['@test while a transition is underway with activeClass is false'](assert) { - let $index = this.$('#index-link'); - let $news = this.$('#news-link'); - let $other = this.$('#other-link'); + ['@test while a transition is underway with activeClass is false'](assert) { + let $index = this.$('#index-link'); + let $news = this.$('#news-link'); + let $other = this.$('#other-link'); - $news.click(); + $news.click(); - assertHasClass(assert, $index, 'active'); - assertHasNoClass(assert, $news, 'active'); - assertHasNoClass(assert, $other, 'active'); + assertHasClass(assert, $index, 'active'); + assertHasNoClass(assert, $news, 'active'); + assertHasNoClass(assert, $other, 'active'); - assertHasNoClass(assert, $index, 'ember-transitioning-in'); - assertHasClass(assert, $news, 'ember-transitioning-in'); - assertHasNoClass(assert, $other, 'ember-transitioning-in'); + assertHasNoClass(assert, $index, 'ember-transitioning-in'); + assertHasClass(assert, $news, 'ember-transitioning-in'); + assertHasNoClass(assert, $other, 'ember-transitioning-in'); - assertHasClass(assert, $index, 'ember-transitioning-out'); - assertHasNoClass(assert, $news, 'ember-transitioning-out'); - assertHasNoClass(assert, $other, 'ember-transitioning-out'); + assertHasClass(assert, $index, 'ember-transitioning-out'); + assertHasNoClass(assert, $news, 'ember-transitioning-out'); + assertHasNoClass(assert, $other, 'ember-transitioning-out'); - this.runTask(() => this.newsDefer.resolve()); + this.runTask(() => this.newsDefer.resolve()); - assertHasNoClass(assert, $index, 'active'); - assertHasNoClass(assert, $news, 'active'); - assertHasNoClass(assert, $other, 'active'); + assertHasNoClass(assert, $index, 'active'); + assertHasNoClass(assert, $news, 'active'); + assertHasNoClass(assert, $other, 'active'); - assertHasNoClass(assert, $index, 'ember-transitioning-in'); - assertHasNoClass(assert, $news, 'ember-transitioning-in'); - assertHasNoClass(assert, $other, 'ember-transitioning-in'); + assertHasNoClass(assert, $index, 'ember-transitioning-in'); + assertHasNoClass(assert, $news, 'ember-transitioning-in'); + assertHasNoClass(assert, $other, 'ember-transitioning-in'); - assertHasNoClass(assert, $index, 'ember-transitioning-out'); - assertHasNoClass(assert, $news, 'ember-transitioning-out'); - assertHasNoClass(assert, $other, 'ember-transitioning-out'); + assertHasNoClass(assert, $index, 'ember-transitioning-out'); + assertHasNoClass(assert, $news, 'ember-transitioning-out'); + assertHasNoClass(assert, $other, 'ember-transitioning-out'); + } } +); -}); - -moduleFor(`The {{link-to}} helper: .transitioning-in .transitioning-out CSS classes - nested link-to's`, class extends ApplicationTestCase { - constructor() { - super(); - this.aboutDefer = RSVP.defer(); - this.otherDefer = RSVP.defer(); - let _this = this; +moduleFor( + `The {{link-to}} helper: .transitioning-in .transitioning-out CSS classes - nested link-to's`, + class extends ApplicationTestCase { + constructor() { + super(); + this.aboutDefer = RSVP.defer(); + this.otherDefer = RSVP.defer(); + let _this = this; - this.router.map(function() { - this.route('parent-route', function() { - this.route('about'); - this.route('other'); + this.router.map(function() { + this.route('parent-route', function() { + this.route('about'); + this.route('other'); + }); }); - }); - this.add('route:parent-route.about', Route.extend({ - model() { - return _this.aboutDefer.promise; - } - })); - - this.add('route:parent-route.other', Route.extend({ - model() { - return _this.otherDefer.promise; - } - })); - - this.addTemplate('application', ` + this.add( + 'route:parent-route.about', + Route.extend({ + model() { + return _this.aboutDefer.promise; + } + }) + ); + + this.add( + 'route:parent-route.other', + Route.extend({ + model() { + return _this.otherDefer.promise; + } + }) + ); + + this.addTemplate( + 'application', + ` {{outlet}} {{#link-to 'index' tagName='li'}} {{link-to 'Index' 'index' id='index-link'}} @@ -173,144 +197,146 @@ moduleFor(`The {{link-to}} helper: .transitioning-in .transitioning-out CSS clas {{#link-to 'parent-route.other' tagName='li'}} {{link-to 'Other' 'parent-route.other' id='other-link'}} {{/link-to}} - `); - } - - beforeEach() { - return this.visit('/'); - } - - resolveAbout() { - return this.runTask(() => { - this.aboutDefer.resolve(); - this.aboutDefer = RSVP.defer(); - }); - } + ` + ); + } + + beforeEach() { + return this.visit('/'); + } + + resolveAbout() { + return this.runTask(() => { + this.aboutDefer.resolve(); + this.aboutDefer = RSVP.defer(); + }); + } - resolveOther() { - return this.runTask(() => { - this.otherDefer.resolve(); - this.otherDefer = RSVP.defer(); - }); - } + resolveOther() { + return this.runTask(() => { + this.otherDefer.resolve(); + this.otherDefer = RSVP.defer(); + }); + } - teardown() { - super.teardown(); - this.aboutDefer = null; - this.otherDefer = null; - } + teardown() { + super.teardown(); + this.aboutDefer = null; + this.otherDefer = null; + } - [`@test while a transition is underway with nested link-to's`](assert) { - // TODO undo changes to this test but currently this test navigates away if navigation - // outlet is not stable and the second $about.click() is triggered. - let $about = this.$('#about-link'); + [`@test while a transition is underway with nested link-to's`](assert) { + // TODO undo changes to this test but currently this test navigates away if navigation + // outlet is not stable and the second $about.click() is triggered. + let $about = this.$('#about-link'); - $about.click(); + $about.click(); - let $index = this.$('#index-link'); - $about = this.$('#about-link'); - let $other = this.$('#other-link'); + let $index = this.$('#index-link'); + $about = this.$('#about-link'); + let $other = this.$('#other-link'); - assertHasClass(assert, $index, 'active'); - assertHasNoClass(assert, $about, 'active'); - assertHasNoClass(assert, $about, 'active'); + assertHasClass(assert, $index, 'active'); + assertHasNoClass(assert, $about, 'active'); + assertHasNoClass(assert, $about, 'active'); - assertHasNoClass(assert, $index, 'ember-transitioning-in'); - assertHasClass(assert, $about, 'ember-transitioning-in'); - assertHasNoClass(assert, $other, 'ember-transitioning-in'); + assertHasNoClass(assert, $index, 'ember-transitioning-in'); + assertHasClass(assert, $about, 'ember-transitioning-in'); + assertHasNoClass(assert, $other, 'ember-transitioning-in'); - assertHasClass(assert, $index, 'ember-transitioning-out'); - assertHasNoClass(assert, $about, 'ember-transitioning-out'); - assertHasNoClass(assert, $other, 'ember-transitioning-out'); + assertHasClass(assert, $index, 'ember-transitioning-out'); + assertHasNoClass(assert, $about, 'ember-transitioning-out'); + assertHasNoClass(assert, $other, 'ember-transitioning-out'); - this.resolveAbout(); + this.resolveAbout(); - $index = this.$('#index-link'); - $about = this.$('#about-link'); - $other = this.$('#other-link'); + $index = this.$('#index-link'); + $about = this.$('#about-link'); + $other = this.$('#other-link'); - assertHasNoClass(assert, $index, 'active'); - assertHasClass(assert, $about, 'active'); - assertHasNoClass(assert, $other, 'active'); + assertHasNoClass(assert, $index, 'active'); + assertHasClass(assert, $about, 'active'); + assertHasNoClass(assert, $other, 'active'); - assertHasNoClass(assert, $index, 'ember-transitioning-in'); - assertHasNoClass(assert, $about, 'ember-transitioning-in'); - assertHasNoClass(assert, $other, 'ember-transitioning-in'); + assertHasNoClass(assert, $index, 'ember-transitioning-in'); + assertHasNoClass(assert, $about, 'ember-transitioning-in'); + assertHasNoClass(assert, $other, 'ember-transitioning-in'); - assertHasNoClass(assert, $index, 'ember-transitioning-out'); - assertHasNoClass(assert, $about, 'ember-transitioning-out'); - assertHasNoClass(assert, $other, 'ember-transitioning-out'); + assertHasNoClass(assert, $index, 'ember-transitioning-out'); + assertHasNoClass(assert, $about, 'ember-transitioning-out'); + assertHasNoClass(assert, $other, 'ember-transitioning-out'); - $other.click(); + $other.click(); - $index = this.$('#index-link'); - $about = this.$('#about-link'); - $other = this.$('#other-link'); + $index = this.$('#index-link'); + $about = this.$('#about-link'); + $other = this.$('#other-link'); - assertHasNoClass(assert, $index, 'active'); - assertHasClass(assert, $about, 'active'); - assertHasNoClass(assert, $other, 'active'); + assertHasNoClass(assert, $index, 'active'); + assertHasClass(assert, $about, 'active'); + assertHasNoClass(assert, $other, 'active'); - assertHasNoClass(assert, $index, 'ember-transitioning-in'); - assertHasNoClass(assert, $about, 'ember-transitioning-in'); - assertHasClass(assert, $other, 'ember-transitioning-in'); + assertHasNoClass(assert, $index, 'ember-transitioning-in'); + assertHasNoClass(assert, $about, 'ember-transitioning-in'); + assertHasClass(assert, $other, 'ember-transitioning-in'); - assertHasNoClass(assert, $index, 'ember-transitioning-out'); - assertHasClass(assert, $about, 'ember-transitioning-out'); - assertHasNoClass(assert, $other, 'ember-transitioning-out'); + assertHasNoClass(assert, $index, 'ember-transitioning-out'); + assertHasClass(assert, $about, 'ember-transitioning-out'); + assertHasNoClass(assert, $other, 'ember-transitioning-out'); - this.resolveOther(); + this.resolveOther(); - $index = this.$('#index-link'); - $about = this.$('#about-link'); - $other = this.$('#other-link'); + $index = this.$('#index-link'); + $about = this.$('#about-link'); + $other = this.$('#other-link'); - assertHasNoClass(assert, $index, 'active'); - assertHasNoClass(assert, $about, 'active'); - assertHasClass(assert, $other, 'active'); + assertHasNoClass(assert, $index, 'active'); + assertHasNoClass(assert, $about, 'active'); + assertHasClass(assert, $other, 'active'); - assertHasNoClass(assert, $index, 'ember-transitioning-in'); - assertHasNoClass(assert, $about, 'ember-transitioning-in'); - assertHasNoClass(assert, $other, 'ember-transitioning-in'); + assertHasNoClass(assert, $index, 'ember-transitioning-in'); + assertHasNoClass(assert, $about, 'ember-transitioning-in'); + assertHasNoClass(assert, $other, 'ember-transitioning-in'); - assertHasNoClass(assert, $index, 'ember-transitioning-out'); - assertHasNoClass(assert, $about, 'ember-transitioning-out'); - assertHasNoClass(assert, $other, 'ember-transitioning-out'); + assertHasNoClass(assert, $index, 'ember-transitioning-out'); + assertHasNoClass(assert, $about, 'ember-transitioning-out'); + assertHasNoClass(assert, $other, 'ember-transitioning-out'); - $about.click(); + $about.click(); - $index = this.$('#index-link'); - $about = this.$('#about-link'); - $other = this.$('#other-link'); + $index = this.$('#index-link'); + $about = this.$('#about-link'); + $other = this.$('#other-link'); - assertHasNoClass(assert, $index, 'active'); - assertHasNoClass(assert, $about, 'active'); - assertHasClass(assert, $other, 'active'); + assertHasNoClass(assert, $index, 'active'); + assertHasNoClass(assert, $about, 'active'); + assertHasClass(assert, $other, 'active'); - assertHasNoClass(assert, $index, 'ember-transitioning-in'); - assertHasClass(assert, $about, 'ember-transitioning-in'); - assertHasNoClass(assert, $other, 'ember-transitioning-in'); + assertHasNoClass(assert, $index, 'ember-transitioning-in'); + assertHasClass(assert, $about, 'ember-transitioning-in'); + assertHasNoClass(assert, $other, 'ember-transitioning-in'); - assertHasNoClass(assert, $index, 'ember-transitioning-out'); - assertHasNoClass(assert, $about, 'ember-transitioning-out'); - assertHasClass(assert, $other, 'ember-transitioning-out'); + assertHasNoClass(assert, $index, 'ember-transitioning-out'); + assertHasNoClass(assert, $about, 'ember-transitioning-out'); + assertHasClass(assert, $other, 'ember-transitioning-out'); - this.resolveAbout(); + this.resolveAbout(); - $index = this.$('#index-link'); - $about = this.$('#about-link'); - $other = this.$('#other-link'); + $index = this.$('#index-link'); + $about = this.$('#about-link'); + $other = this.$('#other-link'); - assertHasNoClass(assert, $index, 'active'); - assertHasClass(assert, $about, 'active'); - assertHasNoClass(assert, $other, 'active'); + assertHasNoClass(assert, $index, 'active'); + assertHasClass(assert, $about, 'active'); + assertHasNoClass(assert, $other, 'active'); - assertHasNoClass(assert, $index, 'ember-transitioning-in'); - assertHasNoClass(assert, $about, 'ember-transitioning-in'); - assertHasNoClass(assert, $other, 'ember-transitioning-in'); + assertHasNoClass(assert, $index, 'ember-transitioning-in'); + assertHasNoClass(assert, $about, 'ember-transitioning-in'); + assertHasNoClass(assert, $other, 'ember-transitioning-in'); - assertHasNoClass(assert, $index, 'ember-transitioning-out'); - assertHasNoClass(assert, $about, 'ember-transitioning-out'); - assertHasNoClass(assert, $other, 'ember-transitioning-out'); + assertHasNoClass(assert, $index, 'ember-transitioning-out'); + assertHasNoClass(assert, $about, 'ember-transitioning-out'); + assertHasNoClass(assert, $other, 'ember-transitioning-out'); + } } -}); +); diff --git a/packages/ember/tests/helpers/link_to_test/link_to_with_query_params_test.js b/packages/ember/tests/helpers/link_to_test/link_to_with_query_params_test.js index 7cdb6138ad5..ce1abf790c7 100644 --- a/packages/ember/tests/helpers/link_to_test/link_to_with_query_params_test.js +++ b/packages/ember/tests/helpers/link_to_test/link_to_with_query_params_test.js @@ -2,267 +2,357 @@ import { Controller, RSVP } from 'ember-runtime'; import { Route } from 'ember-routing'; import { moduleFor, ApplicationTestCase } from 'internal-test-helpers'; -moduleFor('The {{link-to}} helper: invoking with query params', class extends ApplicationTestCase { - constructor() { - super(); - let indexProperties = { - foo: '123', - bar: 'abc' - }; - this.add('controller:index', Controller.extend({ - queryParams: ['foo', 'bar', 'abool'], - foo: indexProperties.foo, - bar: indexProperties.bar, - boundThing: 'OMG', - abool: true - })); - this.add('controller:about', Controller.extend({ - queryParams: ['baz', 'bat'], - baz: 'alex', - bat: 'borf' - })); - this.indexProperties = indexProperties; - } - - shouldNotBeActive(assert, selector) { - this.checkActive(assert, selector, false); - } - - shouldBeActive(assert, selector) { - this.checkActive(assert, selector, true); - } - - getController(name) { - return this.applicationInstance.lookup(`controller:${name}`); - } - - checkActive(assert, selector, active) { - let classList = this.$(selector)[0].className; - assert.equal(classList.indexOf('active') > -1, active, selector + ' active should be ' + active.toString()); - } - - [`@test doesn't update controller QP properties on current route when invoked`](assert) { - this.addTemplate('index', ` +moduleFor( + 'The {{link-to}} helper: invoking with query params', + class extends ApplicationTestCase { + constructor() { + super(); + let indexProperties = { + foo: '123', + bar: 'abc' + }; + this.add( + 'controller:index', + Controller.extend({ + queryParams: ['foo', 'bar', 'abool'], + foo: indexProperties.foo, + bar: indexProperties.bar, + boundThing: 'OMG', + abool: true + }) + ); + this.add( + 'controller:about', + Controller.extend({ + queryParams: ['baz', 'bat'], + baz: 'alex', + bat: 'borf' + }) + ); + this.indexProperties = indexProperties; + } + + shouldNotBeActive(assert, selector) { + this.checkActive(assert, selector, false); + } + + shouldBeActive(assert, selector) { + this.checkActive(assert, selector, true); + } + + getController(name) { + return this.applicationInstance.lookup(`controller:${name}`); + } + + checkActive(assert, selector, active) { + let classList = this.$(selector)[0].className; + assert.equal( + classList.indexOf('active') > -1, + active, + selector + ' active should be ' + active.toString() + ); + } + + [`@test doesn't update controller QP properties on current route when invoked`]( + assert + ) { + this.addTemplate( + 'index', + ` {{#link-to 'index' id='the-link'}}Index{{/link-to}} - `); - - return this.visit('/').then(() => { - this.click('#the-link'); - let indexController = this.getController('index'); - - assert.deepEqual(indexController.getProperties('foo', 'bar'), - this.indexProperties, - 'controller QP properties do not update' + ` ); - }); - } - [`@test doesn't update controller QP properties on current route when invoked (empty query-params obj)`](assert) { - this.addTemplate('index', ` - {{#link-to 'index' (query-params) id='the-link'}}Index{{/link-to}} - `); + return this.visit('/').then(() => { + this.click('#the-link'); + let indexController = this.getController('index'); - return this.visit('/').then(() => { - this.click('#the-link'); - let indexController = this.getController('index'); - - assert.deepEqual(indexController.getProperties('foo', 'bar'), - this.indexProperties, - 'controller QP properties do not update' + assert.deepEqual( + indexController.getProperties('foo', 'bar'), + this.indexProperties, + 'controller QP properties do not update' + ); + }); + } + + [`@test doesn't update controller QP properties on current route when invoked (empty query-params obj)`]( + assert + ) { + this.addTemplate( + 'index', + ` + {{#link-to 'index' (query-params) id='the-link'}}Index{{/link-to}} + ` ); - }); - } - - [`@test doesn't update controller QP properties on current route when invoked (empty query-params obj, inferred route)`](assert) { - this.addTemplate('index', ` - {{#link-to (query-params) id='the-link'}}Index{{/link-to}} - `); - return this.visit('/').then(() => { - this.click('#the-link'); - let indexController = this.getController('index'); + return this.visit('/').then(() => { + this.click('#the-link'); + let indexController = this.getController('index'); - assert.deepEqual(indexController.getProperties('foo', 'bar'), - this.indexProperties, - 'controller QP properties do not update' + assert.deepEqual( + indexController.getProperties('foo', 'bar'), + this.indexProperties, + 'controller QP properties do not update' + ); + }); + } + + [`@test doesn't update controller QP properties on current route when invoked (empty query-params obj, inferred route)`]( + assert + ) { + this.addTemplate( + 'index', + ` + {{#link-to (query-params) id='the-link'}}Index{{/link-to}} + ` ); - }); - } - ['@test updates controller QP properties on current route when invoked'](assert) { - this.addTemplate('index', ` + return this.visit('/').then(() => { + this.click('#the-link'); + let indexController = this.getController('index'); + + assert.deepEqual( + indexController.getProperties('foo', 'bar'), + this.indexProperties, + 'controller QP properties do not update' + ); + }); + } + + ['@test updates controller QP properties on current route when invoked']( + assert + ) { + this.addTemplate( + 'index', + ` {{#link-to 'index' (query-params foo='456') id="the-link"}} Index {{/link-to}} - `); - - return this.visit('/').then(() => { - this.click('#the-link'); - let indexController = this.getController('index'); - - assert.deepEqual(indexController.getProperties('foo', 'bar'), - { foo: '456', bar: 'abc' }, - 'controller QP properties updated' + ` ); - }); - } - ['@test updates controller QP properties on current route when invoked (inferred route)'](assert) { - this.addTemplate('index', ` + return this.visit('/').then(() => { + this.click('#the-link'); + let indexController = this.getController('index'); + + assert.deepEqual( + indexController.getProperties('foo', 'bar'), + { foo: '456', bar: 'abc' }, + 'controller QP properties updated' + ); + }); + } + + ['@test updates controller QP properties on current route when invoked (inferred route)']( + assert + ) { + this.addTemplate( + 'index', + ` {{#link-to (query-params foo='456') id="the-link"}} Index {{/link-to}} - `); + ` + ); - return this.visit('/').then(() => { - this.click('#the-link'); - let indexController = this.getController('index'); + return this.visit('/').then(() => { + this.click('#the-link'); + let indexController = this.getController('index'); - assert.deepEqual(indexController.getProperties('foo', 'bar'), - { foo: '456', bar: 'abc' }, - 'controller QP properties updated' - ); - }); - } + assert.deepEqual( + indexController.getProperties('foo', 'bar'), + { foo: '456', bar: 'abc' }, + 'controller QP properties updated' + ); + }); + } - ['@test updates controller QP properties on other route after transitioning to that route'](assert) { - this.router.map(function() { - this.route('about'); - }); + ['@test updates controller QP properties on other route after transitioning to that route']( + assert + ) { + this.router.map(function() { + this.route('about'); + }); - this.addTemplate('index',` + this.addTemplate( + 'index', + ` {{#link-to 'about' (query-params baz='lol') id='the-link'}} About {{/link-to}} - `); + ` + ); - return this.visit('/').then(() => { - let theLink = this.$('#the-link'); - assert.equal(theLink.attr('href'), '/about?baz=lol'); + return this.visit('/').then(() => { + let theLink = this.$('#the-link'); + assert.equal(theLink.attr('href'), '/about?baz=lol'); - this.runTask(() => this.click('#the-link')); + this.runTask(() => this.click('#the-link')); - let aboutController = this.getController('about'); + let aboutController = this.getController('about'); - assert.deepEqual(aboutController.getProperties('baz', 'bat'), - { baz: 'lol', bat: 'borf' }, - 'about controller QP properties updated' - ); - }); - } + assert.deepEqual( + aboutController.getProperties('baz', 'bat'), + { baz: 'lol', bat: 'borf' }, + 'about controller QP properties updated' + ); + }); + } - ['@test supplied QP properties can be bound'](assert) { - this.addTemplate('index', ` + ['@test supplied QP properties can be bound'](assert) { + this.addTemplate( + 'index', + ` {{#link-to (query-params foo=boundThing) id='the-link'}}Index{{/link-to}} - `); + ` + ); - return this.visit('/').then(() => { - let indexController = this.getController('index'); - let theLink = this.$('#the-link'); + return this.visit('/').then(() => { + let indexController = this.getController('index'); + let theLink = this.$('#the-link'); - assert.equal(theLink.attr('href'), '/?foo=OMG'); + assert.equal(theLink.attr('href'), '/?foo=OMG'); - this.runTask(() => indexController.set('boundThing', 'ASL')); + this.runTask(() => indexController.set('boundThing', 'ASL')); - assert.equal(theLink.attr('href'), '/?foo=ASL'); - }); - } + assert.equal(theLink.attr('href'), '/?foo=ASL'); + }); + } - ['@test supplied QP properties can be bound (booleans)'](assert) { - this.addTemplate('index',` + ['@test supplied QP properties can be bound (booleans)'](assert) { + this.addTemplate( + 'index', + ` {{#link-to (query-params abool=boundThing) id='the-link'}} Index {{/link-to}} - `); + ` + ); - return this.visit('/').then(() => { - let indexController = this.getController('index'); - let theLink = this.$('#the-link'); + return this.visit('/').then(() => { + let indexController = this.getController('index'); + let theLink = this.$('#the-link'); - assert.equal(theLink.attr('href'), '/?abool=OMG'); + assert.equal(theLink.attr('href'), '/?abool=OMG'); - this.runTask(() => indexController.set('boundThing', false)); + this.runTask(() => indexController.set('boundThing', false)); - assert.equal(theLink.attr('href'), '/?abool=false'); + assert.equal(theLink.attr('href'), '/?abool=false'); - this.click('#the-link'); + this.click('#the-link'); - assert.deepEqual(indexController.getProperties('foo', 'bar', 'abool'), - { foo: '123', bar: 'abc', abool: false }, - 'bound bool QP properties update' - ); - }); - } - ['@test href updates when unsupplied controller QP props change'](assert) { - this.addTemplate('index', ` + assert.deepEqual( + indexController.getProperties('foo', 'bar', 'abool'), + { foo: '123', bar: 'abc', abool: false }, + 'bound bool QP properties update' + ); + }); + } + ['@test href updates when unsupplied controller QP props change'](assert) { + this.addTemplate( + 'index', + ` {{#link-to (query-params foo='lol') id='the-link'}}Index{{/link-to}} - `); - - return this.visit('/').then(() => { - let indexController = this.getController('index'); - let theLink = this.$('#the-link'); + ` + ); - assert.equal(theLink.attr('href'), '/?foo=lol'); + return this.visit('/').then(() => { + let indexController = this.getController('index'); + let theLink = this.$('#the-link'); - this.runTask(() => indexController.set('bar', 'BORF')); + assert.equal(theLink.attr('href'), '/?foo=lol'); - assert.equal(theLink.attr('href'), '/?bar=BORF&foo=lol'); + this.runTask(() => indexController.set('bar', 'BORF')); - this.runTask(() => indexController.set('foo', 'YEAH')); + assert.equal(theLink.attr('href'), '/?bar=BORF&foo=lol'); - assert.equal(theLink.attr('href'), '/?bar=BORF&foo=lol'); - }); - } + this.runTask(() => indexController.set('foo', 'YEAH')); - ['@test The {{link-to}} with only query params always transitions to the current route with the query params applied'](assert) { - // Test harness for bug #12033 - this.addTemplate('cars',` + assert.equal(theLink.attr('href'), '/?bar=BORF&foo=lol'); + }); + } + + ['@test The {{link-to}} with only query params always transitions to the current route with the query params applied']( + assert + ) { + // Test harness for bug #12033 + this.addTemplate( + 'cars', + ` {{#link-to 'cars.create' id='create-link'}}Create new car{{/link-to}} {{#link-to (query-params page='2') id='page2-link'}}Page 2{{/link-to}} {{outlet}} - `); - this.addTemplate('cars.create', - `{{#link-to 'cars' id='close-link'}}Close create form{{/link-to}}` - ); - - this.router.map(function() { - this.route('cars', function() { - this.route('create'); - }); - }); - - this.add('controller:cars', Controller.extend({ - queryParams: ['page'], - page: 1 - })); - - return this.visit('/cars/create').then(() => { - let router = this.appRouter; - let carsController = this.getController('cars'); - - assert.equal(router.currentRouteName, 'cars.create'); - - this.runTask(() => this.click('#close-link')); - - assert.equal(router.currentRouteName, 'cars.index'); - assert.equal(router.get('url'), '/cars'); - assert.equal(carsController.get('page'), 1, 'The page query-param is 1'); + ` + ); + this.addTemplate( + 'cars.create', + `{{#link-to 'cars' id='close-link'}}Close create form{{/link-to}}` + ); - this.runTask(() => this.click('#page2-link')); + this.router.map(function() { + this.route('cars', function() { + this.route('create'); + }); + }); - assert.equal(router.currentRouteName, 'cars.index', 'The active route is still cars'); - assert.equal(router.get('url'), '/cars?page=2', 'The url has been updated'); - assert.equal(carsController.get('page'), 2, 'The query params have been updated'); - }); - } + this.add( + 'controller:cars', + Controller.extend({ + queryParams: ['page'], + page: 1 + }) + ); - ['@test the {{link-to}} applies activeClass when query params are not changed'](assert) { - this.addTemplate('index', ` + return this.visit('/cars/create').then(() => { + let router = this.appRouter; + let carsController = this.getController('cars'); + + assert.equal(router.currentRouteName, 'cars.create'); + + this.runTask(() => this.click('#close-link')); + + assert.equal(router.currentRouteName, 'cars.index'); + assert.equal(router.get('url'), '/cars'); + assert.equal( + carsController.get('page'), + 1, + 'The page query-param is 1' + ); + + this.runTask(() => this.click('#page2-link')); + + assert.equal( + router.currentRouteName, + 'cars.index', + 'The active route is still cars' + ); + assert.equal( + router.get('url'), + '/cars?page=2', + 'The url has been updated' + ); + assert.equal( + carsController.get('page'), + 2, + 'The query params have been updated' + ); + }); + } + + ['@test the {{link-to}} applies activeClass when query params are not changed']( + assert + ) { + this.addTemplate( + 'index', + ` {{#link-to (query-params foo='cat') id='cat-link'}}Index{{/link-to}} {{#link-to (query-params foo='dog') id='dog-link'}}Index{{/link-to}} {{#link-to 'index' id='change-nothing'}}Index{{/link-to}} - `); - this.addTemplate('search', ` + ` + ); + this.addTemplate( + 'search', + ` {{#link-to (query-params search='same') id='same-search'}}Index{{/link-to}} {{#link-to (query-params search='change') id='change-search'}}Index{{/link-to}} {{#link-to (query-params search='same' archive=true) id='same-search-add-archive'}}Index{{/link-to}} @@ -271,8 +361,11 @@ moduleFor('The {{link-to}} helper: invoking with query params', class extends Ap {{#link-to (query-params search='different' archive=true) id='change-one'}}Index{{/link-to}} {{#link-to (query-params search='different' archive=false) id='remove-one'}}Index{{/link-to}} {{outlet}} - `); - this.addTemplate('search.results', ` + ` + ); + this.addTemplate( + 'search.results', + ` {{#link-to (query-params sort='title') id='same-sort-child-only'}}Index{{/link-to}} {{#link-to (query-params search='same') id='same-search-parent-only'}}Index{{/link-to}} {{#link-to (query-params search='change') id='change-search-parent-only'}}Index{{/link-to}} @@ -280,275 +373,367 @@ moduleFor('The {{link-to}} helper: invoking with query params', class extends Ap {{#link-to (query-params search='same' sort='author') id='same-search-different-sort-child-and-parent'}}Index{{/link-to}} {{#link-to (query-params search='change' sort='title') id='change-search-same-sort-child-and-parent'}}Index{{/link-to}} {{#link-to (query-params foo='dog') id='dog-link'}}Index{{/link-to}} - `); + ` + ); - this.router.map(function() { - this.route('search', function() { - this.route('results'); + this.router.map(function() { + this.route('search', function() { + this.route('results'); + }); }); - }); - - this.add('controller:search', Controller.extend({ - queryParams: ['search', 'archive'], - search: '', - archive: false - })); - - this.add('controller:search.results', Controller.extend({ - queryParams: ['sort', 'showDetails'], - sort: 'title', - showDetails: true - })); - - return this.visit('/').then(() => { - this.shouldNotBeActive(assert, '#cat-link'); - this.shouldNotBeActive(assert, '#dog-link'); - - return this.visit('/?foo=cat'); - }).then(() => { - this.shouldBeActive(assert, '#cat-link'); - this.shouldNotBeActive(assert, '#dog-link'); - - return this.visit('/?foo=dog'); - }).then(() => { - this.shouldBeActive(assert, '#dog-link'); - this.shouldNotBeActive(assert, '#cat-link'); - this.shouldBeActive(assert, '#change-nothing'); - - return this.visit('/search?search=same'); - }).then(() => { - this.shouldBeActive(assert, '#same-search'); - this.shouldNotBeActive(assert, '#change-search'); - this.shouldNotBeActive(assert, '#same-search-add-archive'); - this.shouldNotBeActive(assert, '#only-add-archive'); - this.shouldNotBeActive(assert, '#remove-one'); - - return this.visit('/search?search=same&archive=true'); - }).then(() => { - this.shouldBeActive(assert, '#both-same'); - this.shouldNotBeActive(assert, '#change-one'); - - return this.visit('/search/results?search=same&sort=title&showDetails=true'); - }).then(() => { - this.shouldBeActive(assert, '#same-sort-child-only'); - this.shouldBeActive(assert, '#same-search-parent-only'); - this.shouldNotBeActive(assert, '#change-search-parent-only'); - this.shouldBeActive(assert, '#same-search-same-sort-child-and-parent'); - this.shouldNotBeActive(assert, '#same-search-different-sort-child-and-parent'); - this.shouldNotBeActive(assert, '#change-search-same-sort-child-and-parent'); - }); - } - ['@test the {{link-to}} applies active class when query-param is a number'](assert) { - this.addTemplate('index', ` + this.add( + 'controller:search', + Controller.extend({ + queryParams: ['search', 'archive'], + search: '', + archive: false + }) + ); + + this.add( + 'controller:search.results', + Controller.extend({ + queryParams: ['sort', 'showDetails'], + sort: 'title', + showDetails: true + }) + ); + + return this.visit('/') + .then(() => { + this.shouldNotBeActive(assert, '#cat-link'); + this.shouldNotBeActive(assert, '#dog-link'); + + return this.visit('/?foo=cat'); + }) + .then(() => { + this.shouldBeActive(assert, '#cat-link'); + this.shouldNotBeActive(assert, '#dog-link'); + + return this.visit('/?foo=dog'); + }) + .then(() => { + this.shouldBeActive(assert, '#dog-link'); + this.shouldNotBeActive(assert, '#cat-link'); + this.shouldBeActive(assert, '#change-nothing'); + + return this.visit('/search?search=same'); + }) + .then(() => { + this.shouldBeActive(assert, '#same-search'); + this.shouldNotBeActive(assert, '#change-search'); + this.shouldNotBeActive(assert, '#same-search-add-archive'); + this.shouldNotBeActive(assert, '#only-add-archive'); + this.shouldNotBeActive(assert, '#remove-one'); + + return this.visit('/search?search=same&archive=true'); + }) + .then(() => { + this.shouldBeActive(assert, '#both-same'); + this.shouldNotBeActive(assert, '#change-one'); + + return this.visit( + '/search/results?search=same&sort=title&showDetails=true' + ); + }) + .then(() => { + this.shouldBeActive(assert, '#same-sort-child-only'); + this.shouldBeActive(assert, '#same-search-parent-only'); + this.shouldNotBeActive(assert, '#change-search-parent-only'); + this.shouldBeActive( + assert, + '#same-search-same-sort-child-and-parent' + ); + this.shouldNotBeActive( + assert, + '#same-search-different-sort-child-and-parent' + ); + this.shouldNotBeActive( + assert, + '#change-search-same-sort-child-and-parent' + ); + }); + } + + ['@test the {{link-to}} applies active class when query-param is a number']( + assert + ) { + this.addTemplate( + 'index', + ` {{#link-to (query-params page=pageNumber) id='page-link'}} Index {{/link-to}} - `); - this.add('controller:index', Controller.extend({ - queryParams: ['page'], - page: 1, - pageNumber: 5 - })); - - return this.visit('/').then(() => { - this.shouldNotBeActive(assert, '#page-link'); - return this.visit('/?page=5'); - }).then(() => { - this.shouldBeActive(assert, '#page-link'); - }); - } + ` + ); + this.add( + 'controller:index', + Controller.extend({ + queryParams: ['page'], + page: 1, + pageNumber: 5 + }) + ); - ['@test the {{link-to}} applies active class when query-param is an array'](assert) { - this.addTemplate('index', ` + return this.visit('/') + .then(() => { + this.shouldNotBeActive(assert, '#page-link'); + return this.visit('/?page=5'); + }) + .then(() => { + this.shouldBeActive(assert, '#page-link'); + }); + } + + ['@test the {{link-to}} applies active class when query-param is an array']( + assert + ) { + this.addTemplate( + 'index', + ` {{#link-to (query-params pages=pagesArray) id='array-link'}}Index{{/link-to}} {{#link-to (query-params pages=biggerArray) id='bigger-link'}}Index{{/link-to}} {{#link-to (query-params pages=emptyArray) id='empty-link'}}Index{{/link-to}} - `); - - this.add('controller:index', Controller.extend({ - queryParams: ['pages'], - pages: [], - pagesArray: [1, 2], - biggerArray: [1, 2, 3], - emptyArray: [] - })); - - return this.visit('/').then(() => { - this.shouldNotBeActive(assert, '#array-link'); - - return this.visit('/?pages=%5B1%2C2%5D'); - }).then(() => { - this.shouldBeActive(assert, '#array-link'); - this.shouldNotBeActive(assert, '#bigger-link'); - this.shouldNotBeActive(assert, '#empty-link'); - - return this.visit('/?pages=%5B2%2C1%5D'); - }).then(() => { - this.shouldNotBeActive(assert, '#array-link'); - this.shouldNotBeActive(assert, '#bigger-link'); - this.shouldNotBeActive(assert, '#empty-link'); - - return this.visit('/?pages=%5B1%2C2%2C3%5D'); - }).then(() => { - this.shouldBeActive(assert, '#bigger-link'); - this.shouldNotBeActive(assert, '#array-link'); - this.shouldNotBeActive(assert, '#empty-link'); - }); - } - ['@test the {{link-to}} helper applies active class to the parent route'](assert) { - this.router.map(function() { - this.route('parent', function() { - this.route('child'); + ` + ); + + this.add( + 'controller:index', + Controller.extend({ + queryParams: ['pages'], + pages: [], + pagesArray: [1, 2], + biggerArray: [1, 2, 3], + emptyArray: [] + }) + ); + + return this.visit('/') + .then(() => { + this.shouldNotBeActive(assert, '#array-link'); + + return this.visit('/?pages=%5B1%2C2%5D'); + }) + .then(() => { + this.shouldBeActive(assert, '#array-link'); + this.shouldNotBeActive(assert, '#bigger-link'); + this.shouldNotBeActive(assert, '#empty-link'); + + return this.visit('/?pages=%5B2%2C1%5D'); + }) + .then(() => { + this.shouldNotBeActive(assert, '#array-link'); + this.shouldNotBeActive(assert, '#bigger-link'); + this.shouldNotBeActive(assert, '#empty-link'); + + return this.visit('/?pages=%5B1%2C2%2C3%5D'); + }) + .then(() => { + this.shouldBeActive(assert, '#bigger-link'); + this.shouldNotBeActive(assert, '#array-link'); + this.shouldNotBeActive(assert, '#empty-link'); + }); + } + ['@test the {{link-to}} helper applies active class to the parent route']( + assert + ) { + this.router.map(function() { + this.route('parent', function() { + this.route('child'); + }); }); - }); - this.addTemplate('application', ` + this.addTemplate( + 'application', + ` {{#link-to 'parent' id='parent-link'}}Parent{{/link-to}} {{#link-to 'parent.child' id='parent-child-link'}}Child{{/link-to}} {{#link-to 'parent' (query-params foo=cat) id='parent-link-qp'}}Parent{{/link-to}} {{outlet}} - `); - - this.add('controller:parent.child', Controller.extend({ - queryParams: ['foo'], - foo: 'bar' - })); - - return this.visit('/').then(() => { - this.shouldNotBeActive(assert, '#parent-link'); - this.shouldNotBeActive(assert, '#parent-child-link'); - this.shouldNotBeActive(assert, '#parent-link-qp'); - return this.visit('/parent/child?foo=dog'); - }).then(() => { - this.shouldBeActive(assert, '#parent-link'); - this.shouldNotBeActive(assert, '#parent-link-qp'); - }); - } + ` + ); - ['@test The {{link-to}} helper disregards query-params in activeness computation when current-when is specified'](assert) { - let appLink; + this.add( + 'controller:parent.child', + Controller.extend({ + queryParams: ['foo'], + foo: 'bar' + }) + ); - this.router.map(function() { - this.route('parent'); - }); - this.addTemplate('application', ` + return this.visit('/') + .then(() => { + this.shouldNotBeActive(assert, '#parent-link'); + this.shouldNotBeActive(assert, '#parent-child-link'); + this.shouldNotBeActive(assert, '#parent-link-qp'); + return this.visit('/parent/child?foo=dog'); + }) + .then(() => { + this.shouldBeActive(assert, '#parent-link'); + this.shouldNotBeActive(assert, '#parent-link-qp'); + }); + } + + ['@test The {{link-to}} helper disregards query-params in activeness computation when current-when is specified']( + assert + ) { + let appLink; + + this.router.map(function() { + this.route('parent'); + }); + this.addTemplate( + 'application', + ` {{#link-to 'parent' (query-params page=1) current-when='parent' id='app-link'}} Parent {{/link-to}} {{outlet}} - `); - this.addTemplate('parent', ` + ` + ); + this.addTemplate( + 'parent', + ` {{#link-to 'parent' (query-params page=1) current-when='parent' id='parent-link'}} Parent {{/link-to}} {{outlet}} - `); - this.add('controller:parent', Controller.extend({ - queryParams: ['page'], - page: 1 - })); + ` + ); + this.add( + 'controller:parent', + Controller.extend({ + queryParams: ['page'], + page: 1 + }) + ); - return this.visit('/').then(() => { - appLink = this.$('#app-link'); + return this.visit('/') + .then(() => { + appLink = this.$('#app-link'); - assert.equal(appLink.attr('href'), '/parent'); - this.shouldNotBeActive(assert, '#app-link'); + assert.equal(appLink.attr('href'), '/parent'); + this.shouldNotBeActive(assert, '#app-link'); - return this.visit('/parent?page=2'); - }).then(() => { - appLink = this.$('#app-link'); - let router = this.appRouter; + return this.visit('/parent?page=2'); + }) + .then(() => { + appLink = this.$('#app-link'); + let router = this.appRouter; - assert.equal(appLink.attr('href'), '/parent'); - this.shouldBeActive(assert, '#app-link'); - assert.equal(this.$('#parent-link').attr('href'), '/parent'); - this.shouldBeActive(assert, '#parent-link'); + assert.equal(appLink.attr('href'), '/parent'); + this.shouldBeActive(assert, '#app-link'); + assert.equal(this.$('#parent-link').attr('href'), '/parent'); + this.shouldBeActive(assert, '#parent-link'); - let parentController = this.getController('parent'); + let parentController = this.getController('parent'); - assert.equal(parentController.get('page'), 2); + assert.equal(parentController.get('page'), 2); - this.runTask(() => parentController.set('page', 3)); + this.runTask(() => parentController.set('page', 3)); - assert.equal(router.get('location.path'), '/parent?page=3'); - this.shouldBeActive(assert, '#app-link'); - this.shouldBeActive(assert, '#parent-link'); + assert.equal(router.get('location.path'), '/parent?page=3'); + this.shouldBeActive(assert, '#app-link'); + this.shouldBeActive(assert, '#parent-link'); - this.runTask(() => this.click('#app-link')); + this.runTask(() => this.click('#app-link')); - assert.equal(router.get('location.path'), '/parent'); - }); - } + assert.equal(router.get('location.path'), '/parent'); + }); + } - ['@test link-to default query params while in active transition regression test'](assert) { - this.router.map(function() { - this.route('foos'); - this.route('bars'); - }); - let foos = RSVP.defer(); - let bars = RSVP.defer(); + ['@test link-to default query params while in active transition regression test']( + assert + ) { + this.router.map(function() { + this.route('foos'); + this.route('bars'); + }); + let foos = RSVP.defer(); + let bars = RSVP.defer(); - this.addTemplate('application', ` + this.addTemplate( + 'application', + ` {{link-to 'Foos' 'foos' id='foos-link'}} {{link-to 'Baz Foos' 'foos' (query-params baz=true) id='baz-foos-link'}} {{link-to 'Quux Bars' 'bars' (query-params quux=true) id='bars-link'}} - `); - this.add('controller:foos', Controller.extend({ - queryParams: ['status'], - baz: false - })); - this.add('route:foos', Route.extend({ - model() { - return foos.promise; - } - })); - this.add('controller:bars', Controller.extend({ - queryParams: ['status'], - quux: false - })); - this.add('route:bars', Route.extend({ - model() { - return bars.promise; - } - })); - - return this.visit('/').then(() => { - let router = this.appRouter; - let foosLink = this.$('#foos-link'); - let barsLink = this.$('#bars-link'); - let bazLink = this.$('#baz-foos-link'); - - assert.equal(foosLink.attr('href'), '/foos'); - assert.equal(bazLink.attr('href'), '/foos?baz=true'); - assert.equal(barsLink.attr('href'), '/bars?quux=true'); - assert.equal(router.get('location.path'), '/'); - this.shouldNotBeActive(assert, '#foos-link'); - this.shouldNotBeActive(assert, '#baz-foos-link'); - this.shouldNotBeActive(assert, '#bars-link'); - - this.runTask(() => barsLink.click()); - this.shouldNotBeActive(assert, '#bars-link'); - - this.runTask(() => foosLink.click()); - this.shouldNotBeActive(assert, '#foos-link'); - - this.runTask(() => foos.resolve()); - - assert.equal(router.get('location.path'), '/foos'); - this.shouldBeActive(assert, '#foos-link'); - }); - } + ` + ); + this.add( + 'controller:foos', + Controller.extend({ + queryParams: ['status'], + baz: false + }) + ); + this.add( + 'route:foos', + Route.extend({ + model() { + return foos.promise; + } + }) + ); + this.add( + 'controller:bars', + Controller.extend({ + queryParams: ['status'], + quux: false + }) + ); + this.add( + 'route:bars', + Route.extend({ + model() { + return bars.promise; + } + }) + ); + + return this.visit('/').then(() => { + let router = this.appRouter; + let foosLink = this.$('#foos-link'); + let barsLink = this.$('#bars-link'); + let bazLink = this.$('#baz-foos-link'); + + assert.equal(foosLink.attr('href'), '/foos'); + assert.equal(bazLink.attr('href'), '/foos?baz=true'); + assert.equal(barsLink.attr('href'), '/bars?quux=true'); + assert.equal(router.get('location.path'), '/'); + this.shouldNotBeActive(assert, '#foos-link'); + this.shouldNotBeActive(assert, '#baz-foos-link'); + this.shouldNotBeActive(assert, '#bars-link'); - [`@test the {{link-to}} helper throws a useful error if you invoke it wrong`](assert) { - assert.expect(1); + this.runTask(() => barsLink.click()); + this.shouldNotBeActive(assert, '#bars-link'); - this.addTemplate('application', `{{#link-to id='the-link'}}Index{{/link-to}}`); + this.runTask(() => foosLink.click()); + this.shouldNotBeActive(assert, '#foos-link'); + + this.runTask(() => foos.resolve()); + + assert.equal(router.get('location.path'), '/foos'); + this.shouldBeActive(assert, '#foos-link'); + }); + } + + [`@test the {{link-to}} helper throws a useful error if you invoke it wrong`]( + assert + ) { + assert.expect(1); + + this.addTemplate( + 'application', + `{{#link-to id='the-link'}}Index{{/link-to}}` + ); - expectAssertion(() => { - this.visit('/'); - }, /You must provide one or more parameters to the link-to component/); + expectAssertion(() => { + this.visit('/'); + }, /You must provide one or more parameters to the link-to component/); - return this.runLoopSettled(); + return this.runLoopSettled(); + } } -}); +); diff --git a/packages/ember/tests/homepage_example_test.js b/packages/ember/tests/homepage_example_test.js index 9e00bcbac15..6c238dffe81 100644 --- a/packages/ember/tests/homepage_example_test.js +++ b/packages/ember/tests/homepage_example_test.js @@ -4,35 +4,47 @@ import { Object as EmberObject, A as emberA } from 'ember-runtime'; import { moduleFor, ApplicationTestCase } from 'internal-test-helpers'; -moduleFor('The example renders correctly', class extends ApplicationTestCase { - ['@test Render index template into application outlet'](assert) { - this.addTemplate('application', '{{outlet}}'); - this.addTemplate('index', '

People

    {{#each model as |person|}}
  • Hello, {{person.fullName}}!
  • {{/each}}
'); +moduleFor( + 'The example renders correctly', + class extends ApplicationTestCase { + ['@test Render index template into application outlet'](assert) { + this.addTemplate('application', '{{outlet}}'); + this.addTemplate( + 'index', + '

People

    {{#each model as |person|}}
  • Hello, {{person.fullName}}!
  • {{/each}}
' + ); - let Person = EmberObject.extend({ - firstName: null, - lastName: null, - fullName: computed('firstName', 'lastName', function() { - return `${this.get('firstName')} ${this.get('lastName')}`; - }) - }); + let Person = EmberObject.extend({ + firstName: null, + lastName: null, + fullName: computed('firstName', 'lastName', function() { + return `${this.get('firstName')} ${this.get('lastName')}`; + }) + }); - this.add('route:index', Route.extend({ - model() { - return emberA([ - Person.create({ firstName: 'Tom', lastName: 'Dale' }), - Person.create({ firstName: 'Yehuda', lastName: 'Katz' }) - ]); - } - })); + this.add( + 'route:index', + Route.extend({ + model() { + return emberA([ + Person.create({ firstName: 'Tom', lastName: 'Dale' }), + Person.create({ firstName: 'Yehuda', lastName: 'Katz' }) + ]); + } + }) + ); - return this.visit('/').then(() => { - let $ = this.$(); + return this.visit('/').then(() => { + let $ = this.$(); - assert.equal($.findAll('h1').text(), 'People'); - assert.equal($.findAll('li').length, 2); - assert.equal($.findAll('li:nth-of-type(1)').text(), 'Hello, Tom Dale!'); - assert.equal($.findAll('li:nth-of-type(2)').text(), 'Hello, Yehuda Katz!'); - }); + assert.equal($.findAll('h1').text(), 'People'); + assert.equal($.findAll('li').length, 2); + assert.equal($.findAll('li:nth-of-type(1)').text(), 'Hello, Tom Dale!'); + assert.equal( + $.findAll('li:nth-of-type(2)').text(), + 'Hello, Yehuda Katz!' + ); + }); + } } -}); +); diff --git a/packages/ember/tests/integration/multiple-app-test.js b/packages/ember/tests/integration/multiple-app-test.js index a1139929833..a83e4e6ed1b 100644 --- a/packages/ember/tests/integration/multiple-app-test.js +++ b/packages/ember/tests/integration/multiple-app-test.js @@ -1,94 +1,104 @@ -import { - moduleFor, - ApplicationTestCase -} from 'internal-test-helpers'; +import { moduleFor, ApplicationTestCase } from 'internal-test-helpers'; import { Application } from 'ember-application'; import { Component } from 'ember-glimmer'; import { assign, getOwner } from 'ember-utils'; import { resolve } from 'rsvp'; -moduleFor('View Integration', class extends ApplicationTestCase { - - constructor() { - document.getElementById('qunit-fixture').innerHTML = ` +moduleFor( + 'View Integration', + class extends ApplicationTestCase { + constructor() { + document.getElementById('qunit-fixture').innerHTML = `
`; - super(); - this.runTask(() => { - this.createSecondApplication(); - }); - } + super(); + this.runTask(() => { + this.createSecondApplication(); + }); + } - get applicationOptions() { - return assign(super.applicationOptions, { - rootElement: '#one', - router: null - }); - } + get applicationOptions() { + return assign(super.applicationOptions, { + rootElement: '#one', + router: null + }); + } - createSecondApplication(options) { - let {applicationOptions} = this; - let secondApplicationOptions = {rootElement: '#two'}; - let myOptions = assign(applicationOptions, secondApplicationOptions, options); - this.secondApp = Application.create(myOptions); - this.secondResolver = myOptions.Resolver.lastInstance; - return this.secondApp; - } + createSecondApplication(options) { + let { applicationOptions } = this; + let secondApplicationOptions = { rootElement: '#two' }; + let myOptions = assign( + applicationOptions, + secondApplicationOptions, + options + ); + this.secondApp = Application.create(myOptions); + this.secondResolver = myOptions.Resolver.lastInstance; + return this.secondApp; + } - teardown() { - super.teardown(); + teardown() { + super.teardown(); - if (this.secondApp) { - this.runTask(() => { - this.secondApp.destroy(); - }); + if (this.secondApp) { + this.runTask(() => { + this.secondApp.destroy(); + }); + } } - } - addFactoriesToResolver(actions, resolver) { - resolver.add('component:special-button', Component.extend({ - actions: { - doStuff() { - let rootElement = getOwner(this).application.rootElement; - actions.push(rootElement); - } - } - })); + addFactoriesToResolver(actions, resolver) { + resolver.add( + 'component:special-button', + Component.extend({ + actions: { + doStuff() { + let rootElement = getOwner(this).application.rootElement; + actions.push(rootElement); + } + } + }) + ); - resolver.add( - 'template:index', - this.compile(` + resolver.add( + 'template:index', + this.compile( + `

Node 1

{{special-button}} - `, { - moduleName: 'my-app/templates/index.hbs' - }) - ); - resolver.add( - 'template:components/special-button', - this.compile(` + `, + { + moduleName: 'my-app/templates/index.hbs' + } + ) + ); + resolver.add( + 'template:components/special-button', + this.compile( + ` - `, { - moduleName: 'my-app/templates/components/special-button.hbs' - }) - ); - } - - [`@test booting multiple applications can properly handle events`](assert) { - let actions = []; - this.addFactoriesToResolver(actions, this.resolver); - this.addFactoriesToResolver(actions, this.secondResolver); + `, + { + moduleName: 'my-app/templates/components/special-button.hbs' + } + ) + ); + } + [`@test booting multiple applications can properly handle events`](assert) { + let actions = []; + this.addFactoriesToResolver(actions, this.resolver); + this.addFactoriesToResolver(actions, this.secondResolver); - return resolve() - .then(() => this.application.visit('/')) - .then(() => this.secondApp.visit('/')) - .then(() => { - document.querySelector('#two .do-stuff').click(); - document.querySelector('#one .do-stuff').click(); + return resolve() + .then(() => this.application.visit('/')) + .then(() => this.secondApp.visit('/')) + .then(() => { + document.querySelector('#two .do-stuff').click(); + document.querySelector('#one .do-stuff').click(); - assert.deepEqual(actions, ['#two', '#one']); - }); + assert.deepEqual(actions, ['#two', '#one']); + }); + } } - -}); +); diff --git a/packages/ember/tests/production_build_test.js b/packages/ember/tests/production_build_test.js index 272293526fa..9d7d80009b6 100644 --- a/packages/ember/tests/production_build_test.js +++ b/packages/ember/tests/production_build_test.js @@ -1,8 +1,5 @@ import { DEBUG } from 'ember-env-flags'; -import { - assert as emberAssert, - runInDebug -} from 'ember-debug'; +import { assert as emberAssert, runInDebug } from 'ember-debug'; QUnit.module('production builds'); @@ -18,10 +15,13 @@ if (!DEBUG) { } }); - QUnit.test('runInDebug does not run the callback in production builds', function(assert) { - let fired = false; - runInDebug(() => fired = true); + QUnit.test( + 'runInDebug does not run the callback in production builds', + function(assert) { + let fired = false; + runInDebug(() => (fired = true)); - assert.equal(fired, false, 'runInDebug callback should not be ran'); - }); + assert.equal(fired, false, 'runInDebug callback should not be ran'); + } + ); } diff --git a/packages/ember/tests/routing/decoupled_basic_test.js b/packages/ember/tests/routing/decoupled_basic_test.js index a7b2809b7cf..58b8ea22b2a 100644 --- a/packages/ember/tests/routing/decoupled_basic_test.js +++ b/packages/ember/tests/routing/decoupled_basic_test.js @@ -3,11 +3,7 @@ import { getOwner } from 'ember-utils'; import RSVP from 'rsvp'; import { compile } from 'ember-template-compiler'; import { ENV } from 'ember-environment'; -import { - Route, - NoneLocation, - HistoryLocation -} from 'ember-routing'; +import { Route, NoneLocation, HistoryLocation } from 'ember-routing'; import { Controller, Object as EmberObject, @@ -15,14 +11,7 @@ import { copy } from 'ember-runtime'; import { moduleFor, ApplicationTestCase } from 'internal-test-helpers'; -import { - Mixin, - computed, - run, - set, - addObserver, - observer -} from 'ember-metal'; +import { Mixin, computed, run, set, addObserver, observer } from 'ember-metal'; import { getTextOf } from 'internal-test-helpers'; import { Component } from 'ember-glimmer'; import { Engine } from 'ember-application'; @@ -31,3635 +20,4905 @@ import { Transition } from 'router'; let originalRenderSupport; let originalConsoleError; -moduleFor('Basic Routing - Decoupled from global resolver', class extends ApplicationTestCase { - constructor() { - super(); - this.addTemplate('home', '

Hours

'); - this.addTemplate('camelot', '

Is a silly place

'); - this.addTemplate('homepage', '

Megatroll

{{model.home}}

'); - - this.router.map(function() { - this.route('home', { path: '/' }); - }); - originalRenderSupport = ENV._ENABLE_RENDER_SUPPORT; - ENV._ENABLE_RENDER_SUPPORT = true; - originalConsoleError = console.error; - } - - teardown() { - super.teardown(); - ENV._ENABLE_RENDER_SUPPORT = originalRenderSupport; - console.error = originalConsoleError; - } - - getController(name) { - return this.applicationInstance.lookup(`controller:${name}`); - } +moduleFor( + 'Basic Routing - Decoupled from global resolver', + class extends ApplicationTestCase { + constructor() { + super(); + this.addTemplate('home', '

Hours

'); + this.addTemplate( + 'camelot', + '

Is a silly place

' + ); + this.addTemplate( + 'homepage', + '

Megatroll

{{model.home}}

' + ); - handleURLAborts(assert, path) { - run(() => { - let router = this.applicationInstance.lookup('router:main'); - router.handleURL(path).then(function () { - assert.ok(false, 'url: `' + path + '` was NOT to be handled'); - }, function (reason) { - assert.ok(reason && reason.message === 'TransitionAborted', 'url: `' + path + '` was to be aborted'); + this.router.map(function() { + this.route('home', { path: '/' }); }); - }); - } + originalRenderSupport = ENV._ENABLE_RENDER_SUPPORT; + ENV._ENABLE_RENDER_SUPPORT = true; + originalConsoleError = console.error; + } - get currentPath() { - return this.getController('application').get('currentPath'); - } + teardown() { + super.teardown(); + ENV._ENABLE_RENDER_SUPPORT = originalRenderSupport; + console.error = originalConsoleError; + } - get currentURL() { - return this.appRouter.get('currentURL'); - } + getController(name) { + return this.applicationInstance.lookup(`controller:${name}`); + } - handleURLRejectsWith(context, assert, path, expectedReason) { - return context.visit(path).then(() => { - assert.ok(false, 'expected handleURLing: `' + path + '` to fail'); - }).catch(reason => { - assert.equal(reason, expectedReason); - }); - } + handleURLAborts(assert, path) { + run(() => { + let router = this.applicationInstance.lookup('router:main'); + router.handleURL(path).then( + function() { + assert.ok(false, 'url: `' + path + '` was NOT to be handled'); + }, + function(reason) { + assert.ok( + reason && reason.message === 'TransitionAborted', + 'url: `' + path + '` was to be aborted' + ); + } + ); + }); + } - ['@test warn on URLs not included in the route set']() { - return this.visit('/').then(() => { - expectAssertion(() => { - this.visit('/what-is-this-i-dont-even'); - }, /'\/what-is-this-i-dont-even' did not match any routes/); - }); - } + get currentPath() { + return this.getController('application').get('currentPath'); + } - ['@test The Homepage'](assert) { - return this.visit('/').then(() => { - assert.equal(this.currentPath, 'home', 'currently on the home route'); + get currentURL() { + return this.appRouter.get('currentURL'); + } - let text = this.$('.hours').text(); - assert.equal(text, "Hours", 'the home template was rendered'); - }); - } + handleURLRejectsWith(context, assert, path, expectedReason) { + return context + .visit(path) + .then(() => { + assert.ok(false, 'expected handleURLing: `' + path + '` to fail'); + }) + .catch(reason => { + assert.equal(reason, expectedReason); + }); + } - [`@test The Homepage and the Camelot page with multiple Router.map calls`](assert) { - this.router.map(function() { - this.route('camelot', { path: '/camelot' }); - }); + ['@test warn on URLs not included in the route set']() { + return this.visit('/').then(() => { + expectAssertion(() => { + this.visit('/what-is-this-i-dont-even'); + }, /'\/what-is-this-i-dont-even' did not match any routes/); + }); + } - return this.visit('/camelot').then(() => { - assert.equal(this.currentPath, 'camelot'); + ['@test The Homepage'](assert) { + return this.visit('/').then(() => { + assert.equal(this.currentPath, 'home', 'currently on the home route'); - let text = this.$('#camelot').text(); - assert.equal(text, "Is a silly place", - 'the camelot template was rendered' - ); + let text = this.$('.hours').text(); + assert.equal(text, 'Hours', 'the home template was rendered'); + }); + } - return this.visit('/'); - }).then(() => { - assert.equal(this.currentPath, 'home'); + [`@test The Homepage and the Camelot page with multiple Router.map calls`]( + assert + ) { + this.router.map(function() { + this.route('camelot', { path: '/camelot' }); + }); - let text = this.$('.hours').text(); - assert.equal(text, "Hours", 'the home template was rendered'); - }); - } + return this.visit('/camelot') + .then(() => { + assert.equal(this.currentPath, 'camelot'); - [`@test The Homepage with explicit template name in renderTemplate`](assert) { - this.add('route:home', Route.extend({ - renderTemplate() { - this.render('homepage'); - } - })); + let text = this.$('#camelot').text(); + assert.equal( + text, + 'Is a silly place', + 'the camelot template was rendered' + ); - return this.visit('/').then(() => { - let text = this.$('#troll').text(); - assert.equal(text, "Megatroll", 'the homepage template was rendered'); - }); - } + return this.visit('/'); + }) + .then(() => { + assert.equal(this.currentPath, 'home'); - [`@test an alternate template will pull in an alternate controller`](assert) { - this.add('route:home', Route.extend({ - renderTemplate() { - this.render('homepage'); - } - })); - this.add('controller:homepage', Controller.extend({ - model: { - home: 'Comes from homepage' - } - })); + let text = this.$('.hours').text(); + assert.equal(text, 'Hours', 'the home template was rendered'); + }); + } - return this.visit('/').then(() => { - let text = this.$('p').text(); + [`@test The Homepage with explicit template name in renderTemplate`]( + assert + ) { + this.add( + 'route:home', + Route.extend({ + renderTemplate() { + this.render('homepage'); + } + }) + ); + + return this.visit('/').then(() => { + let text = this.$('#troll').text(); + assert.equal(text, 'Megatroll', 'the homepage template was rendered'); + }); + } - assert.equal(text, 'Comes from homepage', - 'the homepage template was rendered' + [`@test an alternate template will pull in an alternate controller`]( + assert + ) { + this.add( + 'route:home', + Route.extend({ + renderTemplate() { + this.render('homepage'); + } + }) + ); + this.add( + 'controller:homepage', + Controller.extend({ + model: { + home: 'Comes from homepage' + } + }) ); - }); - } - [`@test An alternate template will pull in an alternate controller instead of controllerName`](assert) { - this.add('route:home', Route.extend({ - controllerName: 'foo', - renderTemplate() { - this.render('homepage'); - } - })); - this.add('controller:foo', Controller.extend({ - model: { - home: 'Comes from foo' - } - })); - this.add('controller:homepage', Controller.extend({ - model: { - home: 'Comes from homepage' - } - })); + return this.visit('/').then(() => { + let text = this.$('p').text(); - return this.visit('/').then(() => { - let text = this.$('p').text(); + assert.equal( + text, + 'Comes from homepage', + 'the homepage template was rendered' + ); + }); + } - assert.equal(text, 'Comes from homepage', - 'the homepage template was rendered' + [`@test An alternate template will pull in an alternate controller instead of controllerName`]( + assert + ) { + this.add( + 'route:home', + Route.extend({ + controllerName: 'foo', + renderTemplate() { + this.render('homepage'); + } + }) + ); + this.add( + 'controller:foo', + Controller.extend({ + model: { + home: 'Comes from foo' + } + }) + ); + this.add( + 'controller:homepage', + Controller.extend({ + model: { + home: 'Comes from homepage' + } + }) ); - }); - } - [`@test The template will pull in an alternate controller via key/value`](assert) { - this.router.map(function() { - this.route('homepage', { path: '/' }); - }); + return this.visit('/').then(() => { + let text = this.$('p').text(); - this.add('route:homepage', Route.extend({ - renderTemplate() { - this.render({ controller: 'home' }); - } - })); - this.add('controller:home', Controller.extend({ - model: { - home: 'Comes from home.' - } - })); + assert.equal( + text, + 'Comes from homepage', + 'the homepage template was rendered' + ); + }); + } - return this.visit('/').then(() => { - let text = this.$('p').text(); + [`@test The template will pull in an alternate controller via key/value`]( + assert + ) { + this.router.map(function() { + this.route('homepage', { path: '/' }); + }); - assert.equal(text, 'Comes from home.', - 'the homepage template was rendered from data from the HomeController' + this.add( + 'route:homepage', + Route.extend({ + renderTemplate() { + this.render({ controller: 'home' }); + } + }) + ); + this.add( + 'controller:home', + Controller.extend({ + model: { + home: 'Comes from home.' + } + }) ); - }); - } - [`@test The Homepage with explicit template name in renderTemplate and controller`](assert) { - this.add('controller:home', Controller.extend({ - model: { - home: 'YES I AM HOME' - } - })); - this.add('route:home', Route.extend({ - renderTemplate() { - this.render('homepage'); - } - })); + return this.visit('/').then(() => { + let text = this.$('p').text(); - return this.visit('/').then(() => { - let text = this.$('p').text(); + assert.equal( + text, + 'Comes from home.', + 'the homepage template was rendered from data from the HomeController' + ); + }); + } - assert.equal(text, 'YES I AM HOME', - 'The homepage template was rendered' + [`@test The Homepage with explicit template name in renderTemplate and controller`]( + assert + ) { + this.add( + 'controller:home', + Controller.extend({ + model: { + home: 'YES I AM HOME' + } + }) + ); + this.add( + 'route:home', + Route.extend({ + renderTemplate() { + this.render('homepage'); + } + }) ); - }); - } - [`@test Model passed via renderTemplate model is set as controller's model`](assert) { - this.addTemplate('bio', '

{{model.name}}

'); - this.add('route:home', Route.extend({ - renderTemplate() { - this.render('bio', { - model: { name: 'emberjs' } - }); - } - })); + return this.visit('/').then(() => { + let text = this.$('p').text(); - return this.visit('/').then(() => { - let text = this.$('p').text(); + assert.equal( + text, + 'YES I AM HOME', + 'The homepage template was rendered' + ); + }); + } - assert.equal(text, 'emberjs', - `Passed model was set as controller's model` + [`@test Model passed via renderTemplate model is set as controller's model`]( + assert + ) { + this.addTemplate('bio', '

{{model.name}}

'); + this.add( + 'route:home', + Route.extend({ + renderTemplate() { + this.render('bio', { + model: { name: 'emberjs' } + }); + } + }) ); - }); - } - ['@test render uses templateName from route'](assert) { - this.addTemplate('the_real_home_template', - '

THIS IS THE REAL HOME

' - ); - this.add('route:home', Route.extend({ - templateName: 'the_real_home_template' - })); + return this.visit('/').then(() => { + let text = this.$('p').text(); - return this.visit('/').then(() => { - let text = this.$('p').text(); + assert.equal( + text, + 'emberjs', + `Passed model was set as controller's model` + ); + }); + } - assert.equal(text, 'THIS IS THE REAL HOME', - 'the homepage template was rendered' + ['@test render uses templateName from route'](assert) { + this.addTemplate( + 'the_real_home_template', + '

THIS IS THE REAL HOME

' + ); + this.add( + 'route:home', + Route.extend({ + templateName: 'the_real_home_template' + }) ); - }); - } - ['@test defining templateName allows other templates to be rendered'](assert) { - this.addTemplate('alert', `
Invader!
`); - this.addTemplate('the_real_home_template', - `

THIS IS THE REAL HOME

{{outlet 'alert'}}` - ); - this.add('route:home', Route.extend({ - templateName: 'the_real_home_template', - actions: { - showAlert() { - this.render('alert', { - into: 'home', - outlet: 'alert' - }); - } - } - })); + return this.visit('/').then(() => { + let text = this.$('p').text(); + + assert.equal( + text, + 'THIS IS THE REAL HOME', + 'the homepage template was rendered' + ); + }); + } - return this.visit('/').then(() => { - let text = this.$('p').text(); - assert.equal(text, 'THIS IS THE REAL HOME', - 'the homepage template was rendered' + ['@test defining templateName allows other templates to be rendered']( + assert + ) { + this.addTemplate('alert', `
Invader!
`); + this.addTemplate( + 'the_real_home_template', + `

THIS IS THE REAL HOME

{{outlet 'alert'}}` + ); + this.add( + 'route:home', + Route.extend({ + templateName: 'the_real_home_template', + actions: { + showAlert() { + this.render('alert', { + into: 'home', + outlet: 'alert' + }); + } + } + }) ); - return this.runTask(() => this.appRouter.send('showAlert')); - }).then(() => { - let text = this.$('.alert-box').text(); + return this.visit('/') + .then(() => { + let text = this.$('p').text(); + assert.equal( + text, + 'THIS IS THE REAL HOME', + 'the homepage template was rendered' + ); + + return this.runTask(() => this.appRouter.send('showAlert')); + }) + .then(() => { + let text = this.$('.alert-box').text(); + + assert.equal( + text, + 'Invader!', + 'Template for alert was rendered into the outlet' + ); + }); + } - assert.equal(text, 'Invader!', - 'Template for alert was rendered into the outlet' + ['@test templateName is still used when calling render with no name and options']( + assert + ) { + this.addTemplate('alert', `
Invader!
`); + this.addTemplate( + 'home', + `

THIS IS THE REAL HOME

{{outlet 'alert'}}` ); - }); - } - - ['@test templateName is still used when calling render with no name and options'](assert) { - this.addTemplate('alert', `
Invader!
`); - this.addTemplate('home', `

THIS IS THE REAL HOME

{{outlet 'alert'}}`); - this.add('route:home', Route.extend({ - templateName: 'alert', - renderTemplate() { - this.render({}); - } - })); + this.add( + 'route:home', + Route.extend({ + templateName: 'alert', + renderTemplate() { + this.render({}); + } + }) + ); - return this.visit('/').then(() => { - let text = this.$('.alert-box').text(); + return this.visit('/').then(() => { + let text = this.$('.alert-box').text(); - assert.equal(text, 'Invader!', - 'default templateName was rendered into outlet' - ); - }); - } + assert.equal( + text, + 'Invader!', + 'default templateName was rendered into outlet' + ); + }); + } - ['@test The Homepage with a `setupController` hook'](assert) { - this.addTemplate('home', - `
    {{#each hours as |entry|}} + ['@test The Homepage with a `setupController` hook'](assert) { + this.addTemplate( + 'home', + `
      {{#each hours as |entry|}}
    • {{entry}}
    • {{/each}}
    - `); - - this.add('route:home', Route.extend({ - setupController(controller) { - controller.set('hours', [ - 'Monday through Friday: 9am to 5pm', - 'Saturday: Noon to Midnight', - 'Sunday: Noon to 6pm' - ]); - } - })); - return this.visit('/').then(() => { - let text = this.$('ul li:nth-child(3)').text(); + ` + ); - assert.equal(text, 'Sunday: Noon to 6pm', - 'The template was rendered with the hours context' + this.add( + 'route:home', + Route.extend({ + setupController(controller) { + controller.set('hours', [ + 'Monday through Friday: 9am to 5pm', + 'Saturday: Noon to Midnight', + 'Sunday: Noon to 6pm' + ]); + } + }) ); - }); - } + return this.visit('/').then(() => { + let text = this.$('ul li:nth-child(3)').text(); + + assert.equal( + text, + 'Sunday: Noon to 6pm', + 'The template was rendered with the hours context' + ); + }); + } - [`@test The route controller is still set when overriding the setupController hook`](assert) { - this.add('route:home', Route.extend({ - setupController() { - // no-op - // importantly, we are not calling this._super - } - })); + [`@test The route controller is still set when overriding the setupController hook`]( + assert + ) { + this.add( + 'route:home', + Route.extend({ + setupController() { + // no-op + // importantly, we are not calling this._super + } + }) + ); - this.add('controller:home', Controller.extend()); + this.add('controller:home', Controller.extend()); - return this.visit('/').then(() => { - let homeRoute = this.applicationInstance.lookup('route:home'); - let homeController = this.applicationInstance.lookup('controller:home'); + return this.visit('/').then(() => { + let homeRoute = this.applicationInstance.lookup('route:home'); + let homeController = this.applicationInstance.lookup('controller:home'); - assert.equal(homeRoute.controller, homeController, - 'route controller is the home controller' + assert.equal( + homeRoute.controller, + homeController, + 'route controller is the home controller' + ); + }); + } + + ['@test the route controller can be specified via controllerName'](assert) { + this.addTemplate('home', '

    {{myValue}}

    '); + this.add( + 'route:home', + Route.extend({ + controllerName: 'myController' + }) + ); + this.add( + 'controller:myController', + Controller.extend({ + myValue: 'foo' + }) ); - }); - } - ['@test the route controller can be specified via controllerName'](assert) { - this.addTemplate('home', '

    {{myValue}}

    '); - this.add('route:home', Route.extend({ - controllerName: 'myController' - })); - this.add('controller:myController', Controller.extend({ - myValue: 'foo' - })); + return this.visit('/').then(() => { + let homeRoute = this.applicationInstance.lookup('route:home'); + let myController = this.applicationInstance.lookup( + 'controller:myController' + ); + let text = this.$('p').text(); + + assert.equal( + homeRoute.controller, + myController, + 'route controller is set by controllerName' + ); + assert.equal( + text, + 'foo', + 'The homepage template was rendered with data from the custom controller' + ); + }); + } - return this.visit('/').then(() => { - let homeRoute = this.applicationInstance.lookup('route:home'); - let myController = this.applicationInstance.lookup('controller:myController'); - let text = this.$('p').text(); + [`@test The route controller specified via controllerName is used in render`]( + assert + ) { + this.router.map(function() { + this.route('home', { path: '/' }); + }); - assert.equal(homeRoute.controller, myController, - 'route controller is set by controllerName' + this.add( + 'route:home', + Route.extend({ + controllerName: 'myController', + renderTemplate() { + this.render('alternative_home'); + } + }) ); - assert.equal(text, 'foo', - 'The homepage template was rendered with data from the custom controller' + + this.add( + 'controller:myController', + Controller.extend({ + myValue: 'foo' + }) ); - }); - } - [`@test The route controller specified via controllerName is used in render`](assert) { - this.router.map(function() { - this.route('home', { path: '/' }); - }); + this.addTemplate( + 'alternative_home', + '

    alternative home: {{myValue}}

    ' + ); - this.add('route:home', Route.extend({ - controllerName: 'myController', - renderTemplate() { - this.render('alternative_home'); - } - })); + return this.visit('/').then(() => { + let homeRoute = this.applicationInstance.lookup('route:home'); + let myController = this.applicationInstance.lookup( + 'controller:myController' + ); + let text = this.$('p').text(); + + assert.equal( + homeRoute.controller, + myController, + 'route controller is set by controllerName' + ); + + assert.equal( + text, + 'alternative home: foo', + 'The homepage template was rendered with data from the custom controller' + ); + }); + } - this.add('controller:myController', Controller.extend({ - myValue: 'foo' - })); + [`@test The route controller specified via controllerName is used in render even when a controller with the routeName is available`]( + assert + ) { + this.router.map(function() { + this.route('home', { path: '/' }); + }); - this.addTemplate('alternative_home', '

    alternative home: {{myValue}}

    '); + this.addTemplate('home', '

    home: {{myValue}}

    '); + this.add( + 'route:home', + Route.extend({ + controllerName: 'myController' + }) + ); - return this.visit('/').then(() => { - let homeRoute = this.applicationInstance.lookup('route:home'); - let myController = this.applicationInstance.lookup('controller:myController'); - let text = this.$('p').text(); + this.add( + 'controller:home', + Controller.extend({ + myValue: 'home' + }) + ); - assert.equal(homeRoute.controller, myController, - 'route controller is set by controllerName'); + this.add( + 'controller:myController', + Controller.extend({ + myValue: 'myController' + }) + ); - assert.equal(text, 'alternative home: foo', - 'The homepage template was rendered with data from the custom controller'); - }); + return this.visit('/').then(() => { + let homeRoute = this.applicationInstance.lookup('route:home'); + let myController = this.applicationInstance.lookup( + 'controller:myController' + ); + let text = this.$('p').text(); + + assert.equal( + homeRoute.controller, + myController, + 'route controller is set by controllerName' + ); + + assert.equal( + text, + 'home: myController', + 'The homepage template was rendered with data from the custom controller' + ); + }); + } - } + [`@test The Homepage with a 'setupController' hook modifying other controllers`]( + assert + ) { + this.router.map(function() { + this.route('home', { path: '/' }); + }); - [`@test The route controller specified via controllerName is used in render even when a controller with the routeName is available`](assert) { - this.router.map(function() { - this.route('home', { path: '/' }); - }); + this.add( + 'route:home', + Route.extend({ + setupController(/* controller */) { + this.controllerFor('home').set('hours', [ + 'Monday through Friday: 9am to 5pm', + 'Saturday: Noon to Midnight', + 'Sunday: Noon to 6pm' + ]); + } + }) + ); - this.addTemplate('home', '

    home: {{myValue}}

    '); + this.addTemplate( + 'home', + '
      {{#each hours as |entry|}}
    • {{entry}}
    • {{/each}}
    ' + ); - this.add('route:home', Route.extend({ - controllerName: 'myController' - })); + return this.visit('/').then(() => { + let text = this.$('ul li:nth-child(3)').text(); - this.add('controller:home', Controller.extend({ - myValue: 'home' - })); + assert.equal( + text, + 'Sunday: Noon to 6pm', + 'The template was rendered with the hours context' + ); + }); + } - this.add('controller:myController', Controller.extend({ - myValue: 'myController' - })); + [`@test The Homepage with a computed model that does not get overridden`]( + assert + ) { + this.router.map(function() { + this.route('home', { path: '/' }); + }); - return this.visit('/').then(() => { - let homeRoute = this.applicationInstance.lookup('route:home'); - let myController = this.applicationInstance.lookup('controller:myController'); - let text = this.$('p').text(); + this.add( + 'controller:home', + Controller.extend({ + model: computed(function() { + return [ + 'Monday through Friday: 9am to 5pm', + 'Saturday: Noon to Midnight', + 'Sunday: Noon to 6pm' + ]; + }) + }) + ); - assert.equal(homeRoute.controller, myController, - 'route controller is set by controllerName'); + this.addTemplate( + 'home', + '
      {{#each model as |passage|}}
    • {{passage}}
    • {{/each}}
    ' + ); - assert.equal(text, 'home: myController', - 'The homepage template was rendered with data from the custom controller'); - }); - } + return this.visit('/').then(() => { + let text = this.$('ul li:nth-child(3)').text(); - [`@test The Homepage with a 'setupController' hook modifying other controllers`](assert) { - this.router.map(function() { - this.route('home', { path: '/' }); - }); - - this.add('route:home', Route.extend({ - setupController(/* controller */) { - this.controllerFor('home').set('hours', [ - 'Monday through Friday: 9am to 5pm', - 'Saturday: Noon to Midnight', - 'Sunday: Noon to 6pm' - ]); - } - })); + assert.equal( + text, + 'Sunday: Noon to 6pm', + 'The template was rendered with the context intact' + ); + }); + } - this.addTemplate('home', '
      {{#each hours as |entry|}}
    • {{entry}}
    • {{/each}}
    '); + [`@test The Homepage getting its controller context via model`](assert) { + this.router.map(function() { + this.route('home', { path: '/' }); + }); - return this.visit('/').then(() => { - let text = this.$('ul li:nth-child(3)').text(); + this.add( + 'route:home', + Route.extend({ + model() { + return [ + 'Monday through Friday: 9am to 5pm', + 'Saturday: Noon to Midnight', + 'Sunday: Noon to 6pm' + ]; + }, + + setupController(controller, model) { + assert.equal(this.controllerFor('home'), controller); + + this.controllerFor('home').set('hours', model); + } + }) + ); - assert.equal(text, 'Sunday: Noon to 6pm', - 'The template was rendered with the hours context'); - }); - } + this.addTemplate( + 'home', + '
      {{#each hours as |entry|}}
    • {{entry}}
    • {{/each}}
    ' + ); - [`@test The Homepage with a computed model that does not get overridden`](assert) { - this.router.map(function() { - this.route('home', { path: '/' }); - }); - - this.add('controller:home', Controller.extend({ - model: computed(function() { - return [ - 'Monday through Friday: 9am to 5pm', - 'Saturday: Noon to Midnight', - 'Sunday: Noon to 6pm' - ]; - }) - })); - - this.addTemplate('home', '
      {{#each model as |passage|}}
    • {{passage}}
    • {{/each}}
    '); - - return this.visit('/').then(() => { - let text = this.$('ul li:nth-child(3)').text(); - - assert.equal(text, 'Sunday: Noon to 6pm', - 'The template was rendered with the context intact'); - }); - } + return this.visit('/').then(() => { + let text = this.$('ul li:nth-child(3)').text(); - [`@test The Homepage getting its controller context via model`](assert) { - this.router.map(function() { - this.route('home', { path: '/' }); - }); + assert.equal( + text, + 'Sunday: Noon to 6pm', + 'The template was rendered with the hours context' + ); + }); + } - this.add('route:home', Route.extend({ - model() { - return [ - 'Monday through Friday: 9am to 5pm', - 'Saturday: Noon to Midnight', - 'Sunday: Noon to 6pm' - ]; - }, + [`@test The Specials Page getting its controller context by deserializing the params hash`]( + assert + ) { + this.router.map(function() { + this.route('home', { path: '/' }); + this.route('special', { path: '/specials/:menu_item_id' }); + }); - setupController(controller, model) { - assert.equal(this.controllerFor('home'), controller); + this.add( + 'route:special', + Route.extend({ + model(params) { + return EmberObject.create({ + menuItemId: params.menu_item_id + }); + } + }) + ); - this.controllerFor('home').set('hours', model); - } - })); + this.addTemplate('special', '

    {{model.menuItemId}}

    '); - this.addTemplate('home', '
      {{#each hours as |entry|}}
    • {{entry}}
    • {{/each}}
    '); + return this.visit('/specials/1').then(() => { + let text = this.$('p').text(); - return this.visit('/').then(() => { - let text = this.$('ul li:nth-child(3)').text(); + assert.equal(text, '1', 'The model was used to render the template'); + }); + } - assert.equal(text, 'Sunday: Noon to 6pm', - 'The template was rendered with the hours context'); - }); + ['@test The Specials Page defaults to looking models up via `find`']() { + let MenuItem = EmberObject.extend(); + MenuItem.reopenClass({ + find(id) { + return MenuItem.create({ id }); + } + }); + this.add('model:menu_item', MenuItem); - } + this.router.map(function() { + this.route('home', { path: '/' }); + this.route('special', { path: '/specials/:menu_item_id' }); + }); - [`@test The Specials Page getting its controller context by deserializing the params hash`](assert) { - this.router.map(function() { - this.route('home', { path: '/' }); - this.route('special', { path: '/specials/:menu_item_id' }); - }); + this.addTemplate('special', '{{model.id}}'); - this.add('route:special', Route.extend({ - model(params) { - return EmberObject.create({ - menuItemId: params.menu_item_id - }); - } - })); + return this.visit('/specials/1').then(() => { + this.assertText('1', 'The model was used to render the template'); + }); + } - this.addTemplate('special', '

    {{model.menuItemId}}

    '); + ['@test The Special Page returning a promise puts the app into a loading state until the promise is resolved']() { + this.router.map(function() { + this.route('home', { path: '/' }); + this.route('special', { path: '/specials/:menu_item_id' }); + }); - return this.visit('/specials/1').then(() => { - let text = this.$('p').text(); + let menuItem, resolve; - assert.equal(text, '1', - 'The model was used to render the template'); - }); - } + let MenuItem = EmberObject.extend(); + MenuItem.reopenClass({ + find(id) { + menuItem = MenuItem.create({ id: id }); - ['@test The Specials Page defaults to looking models up via `find`']() { - let MenuItem = EmberObject.extend(); - MenuItem.reopenClass({ - find(id) { - return MenuItem.create({id}); - } - }); - this.add('model:menu_item', MenuItem); + return new RSVP.Promise(function(res) { + resolve = res; + }); + } + }); - this.router.map(function() { - this.route('home', { path: '/' }); - this.route('special', { path: '/specials/:menu_item_id' }); - }); + this.add('model:menu_item', MenuItem); - this.addTemplate('special', '{{model.id}}'); + this.addTemplate('special', '

    {{model.id}}

    '); + this.addTemplate('loading', '

    LOADING!

    '); - return this.visit('/specials/1').then(() => { - this.assertText('1', 'The model was used to render the template'); - }); - } + let visited = this.visit('/specials/1'); + this.assertText('LOADING!', 'The app is in the loading state'); - ['@test The Special Page returning a promise puts the app into a loading state until the promise is resolved']() { - this.router.map(function() { - this.route('home', { path: '/' }); - this.route('special', { path: '/specials/:menu_item_id' }); - }); + resolve(menuItem); - let menuItem, resolve; + return visited.then(() => { + this.assertText('1', 'The app is now in the specials state'); + }); + } - let MenuItem = EmberObject.extend(); - MenuItem.reopenClass({ - find(id) { - menuItem = MenuItem.create({ id: id }); + [`@test The loading state doesn't get entered for promises that resolve on the same run loop`]( + assert + ) { + this.router.map(function() { + this.route('home', { path: '/' }); + this.route('special', { path: '/specials/:menu_item_id' }); + }); - return new RSVP.Promise(function(res) { - resolve = res; - }); - } - }); + let MenuItem = EmberObject.extend(); + MenuItem.reopenClass({ + find(id) { + return { id: id }; + } + }); - this.add('model:menu_item', MenuItem); + this.add('model:menu_item', MenuItem); - this.addTemplate('special', '

    {{model.id}}

    '); - this.addTemplate('loading', '

    LOADING!

    '); + this.add( + 'route:loading', + Route.extend({ + enter() { + assert.ok(false, "LoadingRoute shouldn't have been entered."); + } + }) + ); - let visited = this.visit('/specials/1'); - this.assertText('LOADING!', 'The app is in the loading state'); + this.addTemplate('special', '

    {{model.id}}

    '); + this.addTemplate('loading', '

    LOADING!

    '); - resolve(menuItem); + return this.visit('/specials/1').then(() => { + let text = this.$('p').text(); - return visited.then(() => { - this.assertText('1', 'The app is now in the specials state'); - }); - } + assert.equal(text, '1', 'The app is now in the specials state'); + }); + } - [`@test The loading state doesn't get entered for promises that resolve on the same run loop`](assert) { - this.router.map(function() { - this.route('home', { path: '/' }); - this.route('special', { path: '/specials/:menu_item_id' }); - }); + ["@test The Special page returning an error invokes SpecialRoute's error handler"]( + assert + ) { + this.router.map(function() { + this.route('home', { path: '/' }); + this.route('special', { path: '/specials/:menu_item_id' }); + }); - let MenuItem = EmberObject.extend(); - MenuItem.reopenClass({ - find(id) { - return { id: id }; - } - }); + let menuItem, promise, resolve; - this.add('model:menu_item', MenuItem); + let MenuItem = EmberObject.extend(); + MenuItem.reopenClass({ + find(id) { + menuItem = MenuItem.create({ id: id }); + promise = new RSVP.Promise(res => (resolve = res)); + return promise; + } + }); - this.add('route:loading', Route.extend({ - enter() { - assert.ok(false, 'LoadingRoute shouldn\'t have been entered.'); - } - })); + this.add('model:menu_item', MenuItem); + + this.add( + 'route:special', + Route.extend({ + setup() { + throw 'Setup error'; + }, + actions: { + error(reason) { + assert.equal( + reason, + 'Setup error', + 'SpecialRoute#error received the error thrown from setup' + ); + return true; + } + } + }) + ); - this.addTemplate('special', '

    {{model.id}}

    '); - this.addTemplate('loading', '

    LOADING!

    '); + this.handleURLRejectsWith(this, assert, 'specials/1', 'Setup error'); - return this.visit('/specials/1').then(() => { - let text = this.$('p').text(); + run(() => resolve(menuItem)); + } - assert.equal(text, '1', 'The app is now in the specials state'); - }); - } + ["@test ApplicationRoute's default error handler can be overridden"]( + assert + ) { + assert.expect(2); - ['@test The Special page returning an error invokes SpecialRoute\'s error handler'](assert) { - this.router.map(function() { - this.route('home', { path: '/' }); - this.route('special', { path: '/specials/:menu_item_id' }); - }); + this.router.map(function() { + this.route('home', { path: '/' }); + this.route('special', { path: '/specials/:menu_item_id' }); + }); - let menuItem, promise, resolve; + let menuItem, resolve; - let MenuItem = EmberObject.extend(); - MenuItem.reopenClass({ - find(id) { - menuItem = MenuItem.create({ id: id }); - promise = new RSVP.Promise(res => resolve = res); + let MenuItem = EmberObject.extend(); - return promise; - } - }); + MenuItem.reopenClass({ + find(id) { + menuItem = MenuItem.create({ id: id }); + return new RSVP.Promise(res => (resolve = res)); + } + }); + this.add('model:menu_item', MenuItem); + + this.add( + 'route:application', + Route.extend({ + actions: { + error(reason) { + assert.equal( + reason, + 'Setup error', + 'error was correctly passed to custom ApplicationRoute handler' + ); + return true; + } + } + }) + ); - this.add('model:menu_item', MenuItem); + this.add( + 'route:special', + Route.extend({ + setup() { + throw 'Setup error'; + } + }) + ); + this.handleURLRejectsWith(this, assert, '/specials/1', 'Setup error'); - this.add('route:special', Route.extend({ - setup() { - throw 'Setup error'; - }, - actions: { - error(reason) { - assert.equal(reason, 'Setup error', 'SpecialRoute#error received the error thrown from setup'); - return true; - } - } - })); + run(() => resolve(menuItem)); + } - this.handleURLRejectsWith(this, assert, 'specials/1', 'Setup error'); + ['@test Moving from one page to another triggers the correct callbacks']( + assert + ) { + assert.expect(3); - run(() => resolve(menuItem)); - } + this.router.map(function() { + this.route('home', { path: '/' }); + this.route('special', { path: '/specials/:menu_item_id' }); + }); - ['@test ApplicationRoute\'s default error handler can be overridden'](assert) { - assert.expect(2); + let MenuItem = EmberObject.extend(); + MenuItem.reopenClass({ + find(id) { + return MenuItem.create({ id: id }); + } + }); + this.add('model:menu_item', MenuItem); - this.router.map(function() { - this.route('home', { path: '/' }); - this.route('special', { path: '/specials/:menu_item_id' }); - }); + this.addTemplate('home', '

    Home

    '); + this.addTemplate('special', '

    {{model.id}}

    '); - let menuItem, resolve; + return this.visit('/') + .then(() => { + this.assertText('Home', 'The app is now in the initial state'); - let MenuItem = EmberObject.extend(); + let promiseContext = MenuItem.create({ id: 1 }); - MenuItem.reopenClass({ - find(id) { - menuItem = MenuItem.create({ id: id }); - return new RSVP.Promise(res => resolve = res); - } - }); - this.add('model:menu_item', MenuItem); + return this.visit('/specials/1', promiseContext); + }) + .then(() => { + assert.equal(this.currentURL, '/specials/1'); + this.assertText('1', 'The app is now transitioned'); + }); + } - this.add('route:application', Route.extend({ - actions: { - error(reason) { - assert.equal(reason, 'Setup error', 'error was correctly passed to custom ApplicationRoute handler'); - return true; + ['@test Nested callbacks are not exited when moving to siblings'](assert) { + let rootSetup = 0; + let rootRender = 0; + let rootModel = 0; + let rootSerialize = 0; + let menuItem; + let rootElement; + + let MenuItem = EmberObject.extend(); + MenuItem.reopenClass({ + find(id) { + menuItem = MenuItem.create({ id: id }); + return menuItem; } - } - })); + }); - this.add('route:special', Route.extend({ - setup() { - throw 'Setup error'; - } - })); + this.router.map(function() { + this.route('root', { path: '/' }, function() { + this.route('special', { + path: '/specials/:menu_item_id', + resetNamespace: true + }); + }); + }); - this.handleURLRejectsWith(this, assert, '/specials/1', 'Setup error'); + this.add( + 'route:root', + Route.extend({ + model() { + rootModel++; + return this._super(...arguments); + }, + + setupController() { + rootSetup++; + }, + + renderTemplate() { + rootRender++; + }, + + serialize() { + rootSerialize++; + return this._super(...arguments); + } + }) + ); - run(() => resolve(menuItem)); - } + this.add('route:loading', Route.extend({})); + this.add('route:home', Route.extend({})); + this.add( + 'route:special', + Route.extend({ + model({ menu_item_id }) { + return MenuItem.find(menu_item_id); + }, + setupController(controller, model) { + set(controller, 'model', model); + } + }) + ); - ['@test Moving from one page to another triggers the correct callbacks'](assert) { - assert.expect(3); + this.addTemplate('root.index', '

    Home

    '); + this.addTemplate('special', '

    {{model.id}}

    '); + this.addTemplate('loading', '

    LOADING!

    '); - this.router.map(function() { - this.route('home', { path: '/' }); - this.route('special', { path: '/specials/:menu_item_id' }); - }); + return this.visit('/').then(() => { + rootElement = document.getElementById('qunit-fixture'); - let MenuItem = EmberObject.extend(); - MenuItem.reopenClass({ - find(id) { - return MenuItem.create({ id: id }); - } - }); - this.add('model:menu_item', MenuItem); + assert.equal( + getTextOf(rootElement.querySelector('h3')), + 'Home', + 'The app is now in the initial state' + ); + assert.equal(rootSetup, 1, 'The root setup was triggered'); + assert.equal(rootRender, 1, 'The root render was triggered'); + assert.equal(rootSerialize, 0, 'The root serialize was not called'); + assert.equal(rootModel, 1, 'The root model was called'); - this.addTemplate('home', '

    Home

    '); - this.addTemplate('special', '

    {{model.id}}

    '); + let router = this.applicationInstance.lookup('router:main'); + let menuItem = MenuItem.create({ id: 1 }); - return this.visit('/').then(() => { - this.assertText('Home', 'The app is now in the initial state'); + return router.transitionTo('special', menuItem).then(function() { + assert.equal(rootSetup, 1, 'The root setup was not triggered again'); + assert.equal( + rootRender, + 1, + 'The root render was not triggered again' + ); + assert.equal(rootSerialize, 0, 'The root serialize was not called'); - let promiseContext = MenuItem.create({ id: 1 }); + // TODO: Should this be changed? + assert.equal(rootModel, 1, 'The root model was called again'); - return this.visit('/specials/1', promiseContext); - }).then(() => { - assert.equal(this.currentURL, '/specials/1'); - this.assertText('1', 'The app is now transitioned'); - }); - } + assert.deepEqual(router.location.path, '/specials/1'); + assert.equal(router.currentPath, 'root.special'); + }); + }); + } - ['@test Nested callbacks are not exited when moving to siblings'](assert) { - let rootSetup = 0; - let rootRender = 0; - let rootModel = 0; - let rootSerialize = 0; - let menuItem; - let rootElement; - - let MenuItem = EmberObject.extend(); - MenuItem.reopenClass({ - find(id) { - menuItem = MenuItem.create({ id: id }); - return menuItem; - } - }); + ['@test Events are triggered on the controller if a matching action name is implemented']( + assert + ) { + let done = assert.async(); - this.router.map(function () { - this.route('root', { path: '/' }, function () { - this.route('special', { path: '/specials/:menu_item_id', resetNamespace: true }); + this.router.map(function() { + this.route('home', { path: '/' }); }); - }); - this.add('route:root', Route.extend({ - model() { - rootModel++; - return this._super(...arguments); - }, + let model = { name: 'Tom Dale' }; + let stateIsNotCalled = true; - setupController() { - rootSetup++; - }, + this.add( + 'route:home', + Route.extend({ + model() { + return model; + }, - renderTemplate() { - rootRender++; - }, + actions: { + showStuff() { + stateIsNotCalled = false; + } + } + }) + ); - serialize() { - rootSerialize++; - return this._super(...arguments); - } - })); - - this.add('route:loading', Route.extend({})); - this.add('route:home', Route.extend({})); - this.add('route:special', Route.extend({ - model({ menu_item_id }) { - return MenuItem.find(menu_item_id); - }, - setupController(controller, model) { - set(controller, 'model', model); - } - })); + this.addTemplate('home', '{{name}}'); + this.add( + 'controller:home', + Controller.extend({ + actions: { + showStuff(context) { + assert.ok( + stateIsNotCalled, + 'an event on the state is not triggered' + ); + assert.deepEqual( + context, + { name: 'Tom Dale' }, + 'an event with context is passed' + ); + done(); + } + } + }) + ); - this.addTemplate('root.index', '

    Home

    '); - this.addTemplate('special', '

    {{model.id}}

    '); - this.addTemplate('loading', '

    LOADING!

    '); + this.visit('/').then(() => { + document + .getElementById('qunit-fixture') + .querySelector('a') + .click(); + }); + } - return this.visit('/').then(() => { - rootElement = document.getElementById('qunit-fixture'); + ['@test Events are triggered on the current state when defined in `actions` object']( + assert + ) { + let done = assert.async(); - assert.equal(getTextOf(rootElement.querySelector('h3')), 'Home', 'The app is now in the initial state'); - assert.equal(rootSetup, 1, 'The root setup was triggered'); - assert.equal(rootRender, 1, 'The root render was triggered'); - assert.equal(rootSerialize, 0, 'The root serialize was not called'); - assert.equal(rootModel, 1, 'The root model was called'); + this.router.map(function() { + this.route('home', { path: '/' }); + }); - let router = this.applicationInstance.lookup('router:main'); - let menuItem = MenuItem.create({ id: 1 }); + let model = { name: 'Tom Dale' }; + let HomeRoute = Route.extend({ + model() { + return model; + }, - return router.transitionTo('special', menuItem).then(function() { - assert.equal(rootSetup, 1, 'The root setup was not triggered again'); - assert.equal(rootRender, 1, 'The root render was not triggered again'); - assert.equal(rootSerialize, 0, 'The root serialize was not called'); + actions: { + showStuff(obj) { + assert.ok( + this instanceof HomeRoute, + 'the handler is an App.HomeRoute' + ); + // Using Ember.copy removes any private Ember vars which older IE would be confused by + assert.deepEqual( + copy(obj, true), + { name: 'Tom Dale' }, + 'the context is correct' + ); + done(); + } + } + }); - // TODO: Should this be changed? - assert.equal(rootModel, 1, 'The root model was called again'); + this.add('route:home', HomeRoute); + this.addTemplate( + 'home', + '{{model.name}}' + ); - assert.deepEqual(router.location.path, '/specials/1'); - assert.equal(router.currentPath, 'root.special'); + this.visit('/').then(() => { + document + .getElementById('qunit-fixture') + .querySelector('a') + .click(); }); - }); - } - - ['@test Events are triggered on the controller if a matching action name is implemented'](assert) { - let done = assert.async(); - - this.router.map(function () { - this.route('home', { path: '/' }); - }); - - let model = { name: 'Tom Dale' }; - let stateIsNotCalled = true; - - this.add('route:home', Route.extend({ - model() { - return model; - }, - - actions: { - showStuff() { - stateIsNotCalled = false; - } - } - })); - - this.addTemplate('home', '{{name}}'); - this.add('controller:home', Controller.extend({ - actions: { - showStuff(context) { - assert.ok(stateIsNotCalled, 'an event on the state is not triggered'); - assert.deepEqual(context, { name: 'Tom Dale' }, 'an event with context is passed'); - done(); - } - } - })); - - this.visit('/').then(() => { - document.getElementById('qunit-fixture').querySelector('a').click(); - }); - } - - ['@test Events are triggered on the current state when defined in `actions` object'](assert) { - let done = assert.async(); - - this.router.map(function () { - this.route('home', { path: '/' }); - }); - - let model = { name: 'Tom Dale' }; - let HomeRoute = Route.extend({ - model() { - return model; - }, - - actions: { - showStuff(obj) { - assert.ok(this instanceof HomeRoute, 'the handler is an App.HomeRoute'); - // Using Ember.copy removes any private Ember vars which older IE would be confused by - assert.deepEqual(copy(obj, true), { name: 'Tom Dale' }, 'the context is correct'); - done(); - } - } - }); - - this.add('route:home', HomeRoute); - this.addTemplate('home', '{{model.name}}'); - - this.visit('/').then(() => { - document.getElementById('qunit-fixture').querySelector('a').click(); - }); - } + } - ['@test Events defined in `actions` object are triggered on the current state when routes are nested'](assert) { - let done = assert.async(); + ['@test Events defined in `actions` object are triggered on the current state when routes are nested']( + assert + ) { + let done = assert.async(); - this.router.map(function () { - this.route('root', { path: '/' }, function () { - this.route('index', { path: '/' }); + this.router.map(function() { + this.route('root', { path: '/' }, function() { + this.route('index', { path: '/' }); + }); }); - }); - let model = { name: 'Tom Dale' }; - - let RootRoute = Route.extend({ - actions: { - showStuff(obj) { - assert.ok(this instanceof RootRoute, 'the handler is an App.HomeRoute'); - // Using Ember.copy removes any private Ember vars which older IE would be confused by - assert.deepEqual(copy(obj, true), { name: 'Tom Dale' }, 'the context is correct'); - done(); + let model = { name: 'Tom Dale' }; + + let RootRoute = Route.extend({ + actions: { + showStuff(obj) { + assert.ok( + this instanceof RootRoute, + 'the handler is an App.HomeRoute' + ); + // Using Ember.copy removes any private Ember vars which older IE would be confused by + assert.deepEqual( + copy(obj, true), + { name: 'Tom Dale' }, + 'the context is correct' + ); + done(); + } } - } - }); - this.add('route:root', RootRoute); - this.add('route:root.index', Route.extend({ - model() { - return model; - } - })); + }); + this.add('route:root', RootRoute); + this.add( + 'route:root.index', + Route.extend({ + model() { + return model; + } + }) + ); - this.addTemplate('root.index', '{{model.name}}'); + this.addTemplate( + 'root.index', + '{{model.name}}' + ); - this.visit('/').then(() => { - document.getElementById('qunit-fixture').querySelector('a').click(); - }); - } + this.visit('/').then(() => { + document + .getElementById('qunit-fixture') + .querySelector('a') + .click(); + }); + } - ['@test Events can be handled by inherited event handlers'](assert) { - assert.expect(4); + ['@test Events can be handled by inherited event handlers'](assert) { + assert.expect(4); - let SuperRoute = Route.extend({ - actions: { - foo() { - assert.ok(true, 'foo'); - }, - bar(msg) { - assert.equal(msg, 'HELLO', 'bar hander in super route'); + let SuperRoute = Route.extend({ + actions: { + foo() { + assert.ok(true, 'foo'); + }, + bar(msg) { + assert.equal(msg, 'HELLO', 'bar hander in super route'); + } } - } - }); + }); - let RouteMixin = Mixin.create({ - actions: { - bar(msg) { - assert.equal(msg, 'HELLO', 'bar handler in mixin'); - this._super(msg); + let RouteMixin = Mixin.create({ + actions: { + bar(msg) { + assert.equal(msg, 'HELLO', 'bar handler in mixin'); + this._super(msg); + } } - } - }); + }); - this.add('route:home', SuperRoute.extend(RouteMixin, { - actions: { - baz() { - assert.ok(true, 'baz', 'baz hander in route'); - } - } - })); - this.addTemplate('home', ` + this.add( + 'route:home', + SuperRoute.extend(RouteMixin, { + actions: { + baz() { + assert.ok(true, 'baz', 'baz hander in route'); + } + } + }) + ); + this.addTemplate( + 'home', + ` Do foo Do bar with arg Do bar - `); + ` + ); - return this.visit('/').then(() => { - let rootElement = document.getElementById('qunit-fixture'); - rootElement.querySelector('.do-foo').click(); - rootElement.querySelector('.do-bar-with-arg').click(); - rootElement.querySelector('.do-baz').click(); - }); - } + return this.visit('/').then(() => { + let rootElement = document.getElementById('qunit-fixture'); + rootElement.querySelector('.do-foo').click(); + rootElement.querySelector('.do-bar-with-arg').click(); + rootElement.querySelector('.do-baz').click(); + }); + } + + ['@test Actions are not triggered on the controller if a matching action name is implemented as a method']( + assert + ) { + let done = assert.async(); - ['@test Actions are not triggered on the controller if a matching action name is implemented as a method'](assert) { - let done = assert.async(); + this.router.map(function() { + this.route('home', { path: '/' }); + }); + + let model = { name: 'Tom Dale' }; + let stateIsNotCalled = true; + + this.add( + 'route:home', + Route.extend({ + model() { + return model; + }, + + actions: { + showStuff(context) { + assert.ok( + stateIsNotCalled, + 'an event on the state is not triggered' + ); + assert.deepEqual( + context, + { name: 'Tom Dale' }, + 'an event with context is passed' + ); + done(); + } + } + }) + ); - this.router.map(function () { - this.route('home', { path: '/' }); - }); + this.addTemplate('home', '{{name}}'); + + this.add( + 'controller:home', + Controller.extend({ + showStuff() { + stateIsNotCalled = false; + assert.ok( + stateIsNotCalled, + 'an event on the state is not triggered' + ); + } + }) + ); - let model = { name: 'Tom Dale' }; - let stateIsNotCalled = true; + this.visit('/').then(() => { + document + .getElementById('qunit-fixture') + .querySelector('a') + .click(); + }); + } - this.add('route:home', Route.extend({ - model() { - return model; - }, + ['@test actions can be triggered with multiple arguments'](assert) { + let done = assert.async(); + this.router.map(function() { + this.route('root', { path: '/' }, function() { + this.route('index', { path: '/' }); + }); + }); - actions: { - showStuff(context) { - assert.ok(stateIsNotCalled, 'an event on the state is not triggered'); - assert.deepEqual(context, { name: 'Tom Dale' }, 'an event with context is passed'); - done(); + let model1 = { name: 'Tilde' }; + let model2 = { name: 'Tom Dale' }; + + let RootRoute = Route.extend({ + actions: { + showStuff(obj1, obj2) { + assert.ok( + this instanceof RootRoute, + 'the handler is an App.HomeRoute' + ); + // Using Ember.copy removes any private Ember vars which older IE would be confused by + assert.deepEqual( + copy(obj1, true), + { name: 'Tilde' }, + 'the first context is correct' + ); + assert.deepEqual( + copy(obj2, true), + { name: 'Tom Dale' }, + 'the second context is correct' + ); + done(); + } } - } - })); + }); - this.addTemplate('home', '{{name}}'); + this.add('route:root', RootRoute); - this.add('controller:home', Controller.extend({ - showStuff() { - stateIsNotCalled = false; - assert.ok(stateIsNotCalled, 'an event on the state is not triggered'); - } - })); + this.add( + 'controller:root.index', + Controller.extend({ + model1: model1, + model2: model2 + }) + ); - this.visit('/').then(() => { - document.getElementById('qunit-fixture').querySelector('a').click(); - }); - } + this.addTemplate( + 'root.index', + '{{model1.name}}' + ); - ['@test actions can be triggered with multiple arguments'](assert) { - let done = assert.async(); - this.router.map(function () { - this.route('root', { path: '/' }, function () { - this.route('index', { path: '/' }); + this.visit('/').then(() => { + document + .getElementById('qunit-fixture') + .querySelector('a') + .click(); }); - }); - - let model1 = { name: 'Tilde' }; - let model2 = { name: 'Tom Dale' }; + } - let RootRoute = Route.extend({ - actions: { - showStuff(obj1, obj2) { - assert.ok(this instanceof RootRoute, 'the handler is an App.HomeRoute'); - // Using Ember.copy removes any private Ember vars which older IE would be confused by - assert.deepEqual(copy(obj1, true), { name: 'Tilde' }, 'the first context is correct'); - assert.deepEqual(copy(obj2, true), { name: 'Tom Dale' }, 'the second context is correct'); - done(); - } - } - }); + ['@test transitioning multiple times in a single run loop only sets the URL once']( + assert + ) { + this.router.map(function() { + this.route('root', { path: '/' }); + this.route('foo'); + this.route('bar'); + }); - this.add('route:root', RootRoute); + return this.visit('/').then(() => { + let urlSetCount = 0; + let router = this.applicationInstance.lookup('router:main'); - this.add('controller:root.index', Controller.extend({ - model1: model1, - model2: model2 - })); + router.get('location').setURL = function(path) { + urlSetCount++; + set(this, 'path', path); + }; - this.addTemplate('root.index', '{{model1.name}}'); + assert.equal(urlSetCount, 0); - this.visit('/').then(() => { - document.getElementById('qunit-fixture').querySelector('a').click(); - }); - } + run(function() { + router.transitionTo('foo'); + router.transitionTo('bar'); + }); - ['@test transitioning multiple times in a single run loop only sets the URL once'](assert) { - this.router.map(function () { - this.route('root', { path: '/' }); - this.route('foo'); - this.route('bar'); - }); + assert.equal(urlSetCount, 1); + assert.equal(router.get('location').getURL(), '/bar'); + }); + } - return this.visit('/').then(() => { - let urlSetCount = 0; - let router = this.applicationInstance.lookup('router:main'); + ['@test navigating away triggers a url property change'](assert) { + assert.expect(3); - router.get('location').setURL = function (path) { - urlSetCount++; - set(this, 'path', path); - }; + this.router.map(function() { + this.route('root', { path: '/' }); + this.route('foo', { path: '/foo' }); + this.route('bar', { path: '/bar' }); + }); - assert.equal(urlSetCount, 0); + return this.visit('/').then(() => { + let router = this.applicationInstance.lookup('router:main'); - run(function () { - router.transitionTo('foo'); - router.transitionTo('bar'); + addObserver(router, 'url', function() { + assert.ok(true, 'url change event was fired'); + }); + ['foo', 'bar', '/foo'].forEach(destination => + run(router, 'transitionTo', destination) + ); }); + } - assert.equal(urlSetCount, 1); - assert.equal(router.get('location').getURL(), '/bar'); - }); - } + ['@test using replaceWith calls location.replaceURL if available'](assert) { + let setCount = 0; + let replaceCount = 0; + this.router.reopen({ + location: NoneLocation.create({ + setURL(path) { + setCount++; + set(this, 'path', path); + }, + + replaceURL(path) { + replaceCount++; + set(this, 'path', path); + } + }) + }); - ['@test navigating away triggers a url property change'](assert) { - assert.expect(3); + this.router.map(function() { + this.route('root', { path: '/' }); + this.route('foo'); + }); - this.router.map(function () { - this.route('root', { path: '/' }); - this.route('foo', { path: '/foo' }); - this.route('bar', { path: '/bar' }); - }); + return this.visit('/').then(() => { + let router = this.applicationInstance.lookup('router:main'); + assert.equal(setCount, 1); + assert.equal(replaceCount, 0); - return this.visit('/').then(() => { - let router = this.applicationInstance.lookup('router:main'); + run(() => router.replaceWith('foo')); - addObserver(router, 'url', function () { - assert.ok(true, 'url change event was fired'); + assert.equal(setCount, 1, 'should not call setURL'); + assert.equal(replaceCount, 1, 'should call replaceURL once'); + assert.equal(router.get('location').getURL(), '/foo'); }); - ['foo', 'bar', '/foo'].forEach(destination => run(router, 'transitionTo', destination)); - }); - } + } - ['@test using replaceWith calls location.replaceURL if available'](assert) { - let setCount = 0; - let replaceCount = 0; - this.router.reopen({ - location: NoneLocation.create({ - setURL(path) { - setCount++; - set(this, 'path', path); - }, + ['@test using replaceWith calls setURL if location.replaceURL is not defined']( + assert + ) { + let setCount = 0; - replaceURL(path) { - replaceCount++; - set(this, 'path', path); - } - }) - }); + this.router.reopen({ + location: NoneLocation.create({ + setURL(path) { + setCount++; + set(this, 'path', path); + } + }) + }); - this.router.map(function () { - this.route('root', { path: '/' }); - this.route('foo'); - }); + this.router.map(function() { + this.route('root', { path: '/' }); + this.route('foo'); + }); - return this.visit('/').then(() => { - let router = this.applicationInstance.lookup('router:main'); - assert.equal(setCount, 1); - assert.equal(replaceCount, 0); + return this.visit('/').then(() => { + let router = this.applicationInstance.lookup('router:main'); - run(() => router.replaceWith('foo')); + assert.equal(setCount, 1); + run(() => router.replaceWith('foo')); + assert.equal(setCount, 2, 'should call setURL once'); + assert.equal(router.get('location').getURL(), '/foo'); + }); + } - assert.equal(setCount, 1, 'should not call setURL'); - assert.equal(replaceCount, 1, 'should call replaceURL once'); - assert.equal(router.get('location').getURL(), '/foo'); - }); - } + ['@test Route inherits model from parent route'](assert) { + assert.expect(9); - ['@test using replaceWith calls setURL if location.replaceURL is not defined'](assert) { - let setCount = 0; + this.router.map(function() { + this.route('the-post', { path: '/posts/:post_id' }, function() { + this.route('comments'); - this.router.reopen({ - location: NoneLocation.create({ - setURL(path) { - setCount++; - set(this, 'path', path); - } - }) - }); - - this.router.map(function () { - this.route('root', { path: '/' }); - this.route('foo'); - }); - - return this.visit('/').then(() => { - let router = this.applicationInstance.lookup('router:main'); - - assert.equal(setCount, 1); - run(() => router.replaceWith('foo')); - assert.equal(setCount, 2, 'should call setURL once'); - assert.equal(router.get('location').getURL(), '/foo'); - }); - } + this.route( + 'shares', + { path: '/shares/:share_id', resetNamespace: true }, + function() { + this.route('share'); + } + ); + }); + }); - ['@test Route inherits model from parent route'](assert) { - assert.expect(9); + let post1 = {}; + let post2 = {}; + let post3 = {}; + let share1 = {}; + let share2 = {}; + let share3 = {}; + + let posts = { + 1: post1, + 2: post2, + 3: post3 + }; + let shares = { + 1: share1, + 2: share2, + 3: share3 + }; - this.router.map(function () { - this.route('the-post', { path: '/posts/:post_id' }, function () { - this.route('comments'); + this.add( + 'route:the-post', + Route.extend({ + model(params) { + return posts[params.post_id]; + } + }) + ); - this.route('shares', { path: '/shares/:share_id', resetNamespace: true }, function () { - this.route('share'); - }); - }); - }); - - let post1 = {}; - let post2 = {}; - let post3 = {}; - let share1 = {}; - let share2 = {}; - let share3 = {}; - - let posts = { - 1: post1, - 2: post2, - 3: post3 - }; - let shares = { - 1: share1, - 2: share2, - 3: share3 - }; - - this.add('route:the-post', Route.extend({ - model(params) { - return posts[params.post_id]; - } - })); + this.add( + 'route:the-post.comments', + Route.extend({ + afterModel(post /*, transition */) { + let parent_model = this.modelFor('the-post'); - this.add('route:the-post.comments', Route.extend({ - afterModel(post /*, transition */) { - let parent_model = this.modelFor('the-post'); + assert.equal(post, parent_model); + } + }) + ); - assert.equal(post, parent_model); - } - })); + this.add( + 'route:shares', + Route.extend({ + model(params) { + return shares[params.share_id]; + } + }) + ); - this.add('route:shares', Route.extend({ - model(params) { - return shares[params.share_id]; - } - })); + this.add( + 'route:shares.share', + Route.extend({ + afterModel(share /*, transition */) { + let parent_model = this.modelFor('shares'); - this.add('route:shares.share', Route.extend({ - afterModel(share /*, transition */) { - let parent_model = this.modelFor('shares'); + assert.equal(share, parent_model); + } + }) + ); - assert.equal(share, parent_model); - } - })); - - return this.visit('/posts/1/comments').then(() => { - assert.ok(true, 'url: /posts/1/comments was handled'); - return this.visit('/posts/1/shares/1'); - }).then(() => { - assert.ok(true, 'url: /posts/1/shares/1 was handled'); - return this.visit('/posts/2/comments'); - }).then(() => { - assert.ok(true, 'url: /posts/2/comments was handled'); - return this.visit('/posts/2/shares/2'); - }).then(() => { - assert.ok(true, 'url: /posts/2/shares/2 was handled'); - return this.visit('/posts/3/comments'); - }).then(() => { - assert.ok(true, 'url: /posts/3/shares was handled'); - return this.visit('/posts/3/shares/3'); - }).then(() => { - assert.ok(true, 'url: /posts/3/shares/3 was handled'); - }); - } + return this.visit('/posts/1/comments') + .then(() => { + assert.ok(true, 'url: /posts/1/comments was handled'); + return this.visit('/posts/1/shares/1'); + }) + .then(() => { + assert.ok(true, 'url: /posts/1/shares/1 was handled'); + return this.visit('/posts/2/comments'); + }) + .then(() => { + assert.ok(true, 'url: /posts/2/comments was handled'); + return this.visit('/posts/2/shares/2'); + }) + .then(() => { + assert.ok(true, 'url: /posts/2/shares/2 was handled'); + return this.visit('/posts/3/comments'); + }) + .then(() => { + assert.ok(true, 'url: /posts/3/shares was handled'); + return this.visit('/posts/3/shares/3'); + }) + .then(() => { + assert.ok(true, 'url: /posts/3/shares/3 was handled'); + }); + } - ['@test Routes with { resetNamespace: true } inherits model from parent route'](assert) { - assert.expect(6); + ['@test Routes with { resetNamespace: true } inherits model from parent route']( + assert + ) { + assert.expect(6); - this.router.map(function () { - this.route('the-post', { path: '/posts/:post_id' }, function () { - this.route('comments', { resetNamespace: true }, function () { + this.router.map(function() { + this.route('the-post', { path: '/posts/:post_id' }, function() { + this.route('comments', { resetNamespace: true }, function() {}); }); }); - }); - let post1 = {}; - let post2 = {}; - let post3 = {}; + let post1 = {}; + let post2 = {}; + let post3 = {}; - let posts = { - 1: post1, - 2: post2, - 3: post3 - }; + let posts = { + 1: post1, + 2: post2, + 3: post3 + }; - this.add('route:the-post', Route.extend({ - model(params) { - return posts[params.post_id]; - } - })); + this.add( + 'route:the-post', + Route.extend({ + model(params) { + return posts[params.post_id]; + } + }) + ); - this.add('route:comments', Route.extend({ - afterModel(post /*, transition */) { - let parent_model = this.modelFor('the-post'); + this.add( + 'route:comments', + Route.extend({ + afterModel(post /*, transition */) { + let parent_model = this.modelFor('the-post'); - assert.equal(post, parent_model); - } - })); - - return this.visit('/posts/1/comments').then(()=> { - assert.ok(true, '/posts/1/comments'); - return this.visit('/posts/2/comments'); - }).then(() => { - assert.ok(true, '/posts/2/comments'); - return this.visit('/posts/3/comments'); - }).then(() => { - assert.ok(true, '/posts/3/comments'); - }); - } + assert.equal(post, parent_model); + } + }) + ); - ['@test It is possible to get the model from a parent route'](assert) { - assert.expect(6); + return this.visit('/posts/1/comments') + .then(() => { + assert.ok(true, '/posts/1/comments'); + return this.visit('/posts/2/comments'); + }) + .then(() => { + assert.ok(true, '/posts/2/comments'); + return this.visit('/posts/3/comments'); + }) + .then(() => { + assert.ok(true, '/posts/3/comments'); + }); + } - this.router.map(function () { - this.route('the-post', { path: '/posts/:post_id' }, function () { - this.route('comments', { resetNamespace: true }); + ['@test It is possible to get the model from a parent route'](assert) { + assert.expect(6); + + this.router.map(function() { + this.route('the-post', { path: '/posts/:post_id' }, function() { + this.route('comments', { resetNamespace: true }); + }); }); - }); - let post1 = {}; - let post2 = {}; - let post3 = {}; - let currentPost; + let post1 = {}; + let post2 = {}; + let post3 = {}; + let currentPost; - let posts = { - 1: post1, - 2: post2, - 3: post3 - }; + let posts = { + 1: post1, + 2: post2, + 3: post3 + }; - this.add('route:the-post', Route.extend({ - model(params) { - return posts[params.post_id]; - } - })); + this.add( + 'route:the-post', + Route.extend({ + model(params) { + return posts[params.post_id]; + } + }) + ); - this.add('route:comments', Route.extend({ - model() { - assert.equal(this.modelFor('the-post'), currentPost); - } - })); - - currentPost = post1; - return this.visit('/posts/1/comments').then(() => { - assert.ok(true, '/posts/1/comments has been handled'); - currentPost = post2; - return this.visit('/posts/2/comments'); - }).then(() => { - assert.ok(true, '/posts/2/comments has been handled'); - currentPost = post3; - return this.visit('/posts/3/comments'); - }).then(() => { - assert.ok(true, '/posts/3/comments has been handled'); - }); - } + this.add( + 'route:comments', + Route.extend({ + model() { + assert.equal(this.modelFor('the-post'), currentPost); + } + }) + ); - ['@test A redirection hook is provided'](assert) { - this.router.map(function () { - this.route('choose', { path: '/' }); - this.route('home'); - }); + currentPost = post1; + return this.visit('/posts/1/comments') + .then(() => { + assert.ok(true, '/posts/1/comments has been handled'); + currentPost = post2; + return this.visit('/posts/2/comments'); + }) + .then(() => { + assert.ok(true, '/posts/2/comments has been handled'); + currentPost = post3; + return this.visit('/posts/3/comments'); + }) + .then(() => { + assert.ok(true, '/posts/3/comments has been handled'); + }); + } - let chooseFollowed = 0; - let destination = 'home'; + ['@test A redirection hook is provided'](assert) { + this.router.map(function() { + this.route('choose', { path: '/' }); + this.route('home'); + }); - this.add('route:choose', Route.extend({ - redirect() { - if (destination) { - this.transitionTo(destination); - } - }, + let chooseFollowed = 0; + let destination = 'home'; - setupController() { - chooseFollowed++; - } - })); + this.add( + 'route:choose', + Route.extend({ + redirect() { + if (destination) { + this.transitionTo(destination); + } + }, - return this.visit('/').then(() => { - let rootElement = document.getElementById('qunit-fixture'); - assert.equal(chooseFollowed, 0, 'The choose route wasn\'t entered since a transition occurred'); - assert.equal(rootElement.querySelectorAll('h3.hours').length, 1, 'The home template was rendered'); - assert.equal(this.applicationInstance.lookup('controller:application').get('currentPath'), 'home'); - }); - } + setupController() { + chooseFollowed++; + } + }) + ); - ['@test Redirecting from the middle of a route aborts the remainder of the routes'](assert) { - assert.expect(3); + return this.visit('/').then(() => { + let rootElement = document.getElementById('qunit-fixture'); + assert.equal( + chooseFollowed, + 0, + "The choose route wasn't entered since a transition occurred" + ); + assert.equal( + rootElement.querySelectorAll('h3.hours').length, + 1, + 'The home template was rendered' + ); + assert.equal( + this.applicationInstance + .lookup('controller:application') + .get('currentPath'), + 'home' + ); + }); + } - this.router.map(function () { - this.route('home'); - this.route('foo', function () { - this.route('bar', { resetNamespace: true }, function () { - this.route('baz'); + ['@test Redirecting from the middle of a route aborts the remainder of the routes']( + assert + ) { + assert.expect(3); + + this.router.map(function() { + this.route('home'); + this.route('foo', function() { + this.route('bar', { resetNamespace: true }, function() { + this.route('baz'); + }); }); }); - }); - - this.add('route:bar', Route.extend({ - redirect() { - this.transitionTo('home'); - }, - setupController() { - assert.ok(false, 'Should transition before setupController'); - } - })); - this.add('route:bar-baz', Route.extend({ - enter() { - assert.ok(false, 'Should abort transition getting to next route'); - } - })); - - return this.visit('/').then(() => { - let router = this.applicationInstance.lookup('router:main'); - this.handleURLAborts(assert, '/foo/bar/baz'); - assert.equal(this.applicationInstance.lookup('controller:application').get('currentPath'), 'home'); - assert.equal(router.get('location').getURL(), '/home'); - }); - } + this.add( + 'route:bar', + Route.extend({ + redirect() { + this.transitionTo('home'); + }, + setupController() { + assert.ok(false, 'Should transition before setupController'); + } + }) + ); - ['@test Redirecting to the current target in the middle of a route does not abort initial routing'](assert) { - assert.expect(5); + this.add( + 'route:bar-baz', + Route.extend({ + enter() { + assert.ok(false, 'Should abort transition getting to next route'); + } + }) + ); - this.router.map(function () { - this.route('home'); - this.route('foo', function () { - this.route('bar', { resetNamespace: true }, function () { - this.route('baz'); - }); + return this.visit('/').then(() => { + let router = this.applicationInstance.lookup('router:main'); + this.handleURLAborts(assert, '/foo/bar/baz'); + assert.equal( + this.applicationInstance + .lookup('controller:application') + .get('currentPath'), + 'home' + ); + assert.equal(router.get('location').getURL(), '/home'); }); - }); + } - let successCount = 0; + ['@test Redirecting to the current target in the middle of a route does not abort initial routing']( + assert + ) { + assert.expect(5); - this.add('route:bar', Route.extend({ - redirect() { - return this.transitionTo('bar.baz').then(function () { - successCount++; + this.router.map(function() { + this.route('home'); + this.route('foo', function() { + this.route('bar', { resetNamespace: true }, function() { + this.route('baz'); + }); }); - }, + }); - setupController() { - assert.ok(true, 'Should still invoke bar\'s setupController'); - } - })); + let successCount = 0; - this.add('route:bar.baz', Route.extend({ - setupController() { - assert.ok(true, 'Should still invoke bar.baz\'s setupController'); - } - })); + this.add( + 'route:bar', + Route.extend({ + redirect() { + return this.transitionTo('bar.baz').then(function() { + successCount++; + }); + }, - return this.visit('/foo/bar/baz').then(() => { - assert.ok(true, '/foo/bar/baz has been handled'); - assert.equal(this.applicationInstance.lookup('controller:application').get('currentPath'), 'foo.bar.baz'); - assert.equal(successCount, 1, 'transitionTo success handler was called once'); - }); - } + setupController() { + assert.ok(true, "Should still invoke bar's setupController"); + } + }) + ); - ['@test Redirecting to the current target with a different context aborts the remainder of the routes'](assert) { - assert.expect(4); + this.add( + 'route:bar.baz', + Route.extend({ + setupController() { + assert.ok(true, "Should still invoke bar.baz's setupController"); + } + }) + ); - this.router.map(function () { - this.route('home'); - this.route('foo', function () { - this.route('bar', { path: 'bar/:id', resetNamespace: true }, function () { - this.route('baz'); + return this.visit('/foo/bar/baz').then(() => { + assert.ok(true, '/foo/bar/baz has been handled'); + assert.equal( + this.applicationInstance + .lookup('controller:application') + .get('currentPath'), + 'foo.bar.baz' + ); + assert.equal( + successCount, + 1, + 'transitionTo success handler was called once' + ); + }); + } + + ['@test Redirecting to the current target with a different context aborts the remainder of the routes']( + assert + ) { + assert.expect(4); + + this.router.map(function() { + this.route('home'); + this.route('foo', function() { + this.route( + 'bar', + { path: 'bar/:id', resetNamespace: true }, + function() { + this.route('baz'); + } + ); }); }); - }); - let model = { id: 2 }; + let model = { id: 2 }; - let count = 0; + let count = 0; - this.add('route:bar', Route.extend({ - afterModel() { - if (count++ > 10) { - assert.ok(false, 'infinite loop'); - } else { - this.transitionTo('bar.baz', model); - } - } - })); + this.add( + 'route:bar', + Route.extend({ + afterModel() { + if (count++ > 10) { + assert.ok(false, 'infinite loop'); + } else { + this.transitionTo('bar.baz', model); + } + } + }) + ); - this.add('route:bar.baz', Route.extend({ - setupController() { - assert.ok(true, 'Should still invoke setupController'); - } - })); + this.add( + 'route:bar.baz', + Route.extend({ + setupController() { + assert.ok(true, 'Should still invoke setupController'); + } + }) + ); - return this.visit('/').then(() => { - this.handleURLAborts(assert, '/foo/bar/1/baz'); - assert.equal(this.applicationInstance.lookup('controller:application').get('currentPath'), 'foo.bar.baz'); - assert.equal(this.applicationInstance.lookup('router:main').get('location').getURL(), '/foo/bar/2/baz'); - }); - } + return this.visit('/').then(() => { + this.handleURLAborts(assert, '/foo/bar/1/baz'); + assert.equal( + this.applicationInstance + .lookup('controller:application') + .get('currentPath'), + 'foo.bar.baz' + ); + assert.equal( + this.applicationInstance + .lookup('router:main') + .get('location') + .getURL(), + '/foo/bar/2/baz' + ); + }); + } - ['@test Transitioning from a parent event does not prevent currentPath from being set'](assert) { - this.router.map(function () { - this.route('foo', function () { - this.route('bar', { resetNamespace: true }, function () { - this.route('baz'); + ['@test Transitioning from a parent event does not prevent currentPath from being set']( + assert + ) { + this.router.map(function() { + this.route('foo', function() { + this.route('bar', { resetNamespace: true }, function() { + this.route('baz'); + }); + this.route('qux'); }); - this.route('qux'); }); - }); - this.add('route:foo', Route.extend({ - actions: { - goToQux() { - this.transitionTo('foo.qux'); - } - } - })); - - return this.visit('/foo/bar/baz').then(() => { - assert.ok(true, '/foo/bar/baz has been handled'); - let applicationController = this.applicationInstance.lookup('controller:application'); - let router = this.applicationInstance.lookup('router:main'); - assert.equal(applicationController.get('currentPath'), 'foo.bar.baz'); - run(() => router.send('goToQux')); - assert.equal(applicationController.get('currentPath'), 'foo.qux'); - assert.equal(router.get('location').getURL(), '/foo/qux'); - }); - } + this.add( + 'route:foo', + Route.extend({ + actions: { + goToQux() { + this.transitionTo('foo.qux'); + } + } + }) + ); - ['@test Generated names can be customized when providing routes with dot notation'](assert) { - assert.expect(4); + return this.visit('/foo/bar/baz').then(() => { + assert.ok(true, '/foo/bar/baz has been handled'); + let applicationController = this.applicationInstance.lookup( + 'controller:application' + ); + let router = this.applicationInstance.lookup('router:main'); + assert.equal(applicationController.get('currentPath'), 'foo.bar.baz'); + run(() => router.send('goToQux')); + assert.equal(applicationController.get('currentPath'), 'foo.qux'); + assert.equal(router.get('location').getURL(), '/foo/qux'); + }); + } - this.addTemplate('index', '
    Index
    '); - this.addTemplate('application', '

    Home

    {{outlet}}
    '); - this.addTemplate('foo', '
    {{outlet}}
    '); - this.addTemplate('bar', '
    {{outlet}}
    '); - this.addTemplate('bar.baz', '

    {{name}}Bottom!

    '); + ['@test Generated names can be customized when providing routes with dot notation']( + assert + ) { + assert.expect(4); - this.router.map(function () { - this.route('foo', { path: '/top' }, function () { - this.route('bar', { path: '/middle', resetNamespace: true }, function () { - this.route('baz', { path: '/bottom' }); + this.addTemplate('index', '
    Index
    '); + this.addTemplate( + 'application', + "

    Home

    {{outlet}}
    " + ); + this.addTemplate('foo', "
    {{outlet}}
    "); + this.addTemplate('bar', "
    {{outlet}}
    "); + this.addTemplate('bar.baz', '

    {{name}}Bottom!

    '); + + this.router.map(function() { + this.route('foo', { path: '/top' }, function() { + this.route( + 'bar', + { path: '/middle', resetNamespace: true }, + function() { + this.route('baz', { path: '/bottom' }); + } + ); }); }); - }); - this.add('route:foo', Route.extend({ - renderTemplate() { - assert.ok(true, 'FooBarRoute was called'); - return this._super(...arguments); - } - })); + this.add( + 'route:foo', + Route.extend({ + renderTemplate() { + assert.ok(true, 'FooBarRoute was called'); + return this._super(...arguments); + } + }) + ); - this.add('route:bar.baz', Route.extend({ - renderTemplate() { - assert.ok(true, 'BarBazRoute was called'); - return this._super(...arguments); - } - })); + this.add( + 'route:bar.baz', + Route.extend({ + renderTemplate() { + assert.ok(true, 'BarBazRoute was called'); + return this._super(...arguments); + } + }) + ); - this.add('controller:bar', Controller.extend({ - name: 'Bar' - })); + this.add( + 'controller:bar', + Controller.extend({ + name: 'Bar' + }) + ); - this.add('controller:bar.baz', Controller.extend({ - name: 'BarBaz' - })); + this.add( + 'controller:bar.baz', + Controller.extend({ + name: 'BarBaz' + }) + ); - return this.visit('/top/middle/bottom').then(() => { - assert.ok(true, '/top/middle/bottom has been handled'); - let rootElement = document.getElementById('qunit-fixture'); - assert.equal(getTextOf(rootElement.querySelector('.main .middle .bottom p')), 'BarBazBottom!', 'The templates were rendered into their appropriate parents'); - }); - } + return this.visit('/top/middle/bottom').then(() => { + assert.ok(true, '/top/middle/bottom has been handled'); + let rootElement = document.getElementById('qunit-fixture'); + assert.equal( + getTextOf(rootElement.querySelector('.main .middle .bottom p')), + 'BarBazBottom!', + 'The templates were rendered into their appropriate parents' + ); + }); + } - ['@test Child routes render into their parent route\'s template by default'](assert) { - this.addTemplate('index', '
    Index
    '); - this.addTemplate('application', '

    Home

    {{outlet}}
    '); - this.addTemplate('top', '
    {{outlet}}
    '); - this.addTemplate('middle', '
    {{outlet}}
    '); - this.addTemplate('middle.bottom', '

    Bottom!

    '); - - this.router.map(function () { - this.route('top', function () { - this.route('middle', { resetNamespace: true }, function () { - this.route('bottom'); + ["@test Child routes render into their parent route's template by default"]( + assert + ) { + this.addTemplate('index', '
    Index
    '); + this.addTemplate( + 'application', + "

    Home

    {{outlet}}
    " + ); + this.addTemplate('top', "
    {{outlet}}
    "); + this.addTemplate('middle', "
    {{outlet}}
    "); + this.addTemplate('middle.bottom', '

    Bottom!

    '); + + this.router.map(function() { + this.route('top', function() { + this.route('middle', { resetNamespace: true }, function() { + this.route('bottom'); + }); }); }); - }); - return this.visit('/top/middle/bottom').then(() => { - assert.ok(true, '/top/middle/bottom has been handled'); - let rootElement = document.getElementById('qunit-fixture'); - assert.equal(getTextOf(rootElement.querySelector('.main .middle .bottom p')), 'Bottom!', 'The templates were rendered into their appropriate parents'); - }); - } + return this.visit('/top/middle/bottom').then(() => { + assert.ok(true, '/top/middle/bottom has been handled'); + let rootElement = document.getElementById('qunit-fixture'); + assert.equal( + getTextOf(rootElement.querySelector('.main .middle .bottom p')), + 'Bottom!', + 'The templates were rendered into their appropriate parents' + ); + }); + } - ['@test Child routes render into specified template'](assert) { - this.addTemplate('index', '
    Index
    '); - this.addTemplate('application', '

    Home

    {{outlet}}
    '); - this.addTemplate('top', '
    {{outlet}}
    '); - this.addTemplate('middle', '
    {{outlet}}
    '); - this.addTemplate('middle.bottom', '

    Bottom!

    '); - - this.router.map(function () { - this.route('top', function () { - this.route('middle', { resetNamespace: true }, function () { - this.route('bottom'); + ['@test Child routes render into specified template'](assert) { + this.addTemplate('index', '
    Index
    '); + this.addTemplate( + 'application', + "

    Home

    {{outlet}}
    " + ); + this.addTemplate('top', "
    {{outlet}}
    "); + this.addTemplate('middle', "
    {{outlet}}
    "); + this.addTemplate('middle.bottom', '

    Bottom!

    '); + + this.router.map(function() { + this.route('top', function() { + this.route('middle', { resetNamespace: true }, function() { + this.route('bottom'); + }); }); }); - }); - - this.add('route:middle.bottom', Route.extend({ - renderTemplate() { - this.render('middle/bottom', { into: 'top' }); - } - })); - - return this.visit('/top/middle/bottom').then(() => { - assert.ok(true, '/top/middle/bottom has been handled'); - let rootElement = document.getElementById('qunit-fixture'); - assert.equal(rootElement.querySelectorAll('.main .middle .bottom p').length, 0, 'should not render into the middle template'); - assert.equal(getTextOf(rootElement.querySelector('.main .middle > p')), 'Bottom!', 'The template was rendered into the top template'); - }); - } - ['@test Rendering into specified template with slash notation'](assert) { - this.addTemplate('person.profile', 'profile {{outlet}}'); - this.addTemplate('person.details', 'details!'); + this.add( + 'route:middle.bottom', + Route.extend({ + renderTemplate() { + this.render('middle/bottom', { into: 'top' }); + } + }) + ); - this.router.map(function () { - this.route('home', { path: '/' }); - }); + return this.visit('/top/middle/bottom').then(() => { + assert.ok(true, '/top/middle/bottom has been handled'); + let rootElement = document.getElementById('qunit-fixture'); + assert.equal( + rootElement.querySelectorAll('.main .middle .bottom p').length, + 0, + 'should not render into the middle template' + ); + assert.equal( + getTextOf(rootElement.querySelector('.main .middle > p')), + 'Bottom!', + 'The template was rendered into the top template' + ); + }); + } - this.add('route:home', Route.extend({ - renderTemplate() { - this.render('person/profile'); - this.render('person/details', { into: 'person/profile' }); - } - })); + ['@test Rendering into specified template with slash notation'](assert) { + this.addTemplate('person.profile', 'profile {{outlet}}'); + this.addTemplate('person.details', 'details!'); - return this.visit('/').then(() => { - let rootElement = document.getElementById('qunit-fixture'); - assert.equal(rootElement.textContent.trim(), 'profile details!', 'The templates were rendered'); - }); - } + this.router.map(function() { + this.route('home', { path: '/' }); + }); - ['@test Parent route context change'](assert) { - let editCount = 0; - let editedPostIds = emberA(); + this.add( + 'route:home', + Route.extend({ + renderTemplate() { + this.render('person/profile'); + this.render('person/details', { into: 'person/profile' }); + } + }) + ); - this.addTemplate('application', '{{outlet}}'); - this.addTemplate('posts', '{{outlet}}'); - this.addTemplate('post', '{{outlet}}'); - this.addTemplate('post/index', 'showing'); - this.addTemplate('post/edit', 'editing'); + return this.visit('/').then(() => { + let rootElement = document.getElementById('qunit-fixture'); + assert.equal( + rootElement.textContent.trim(), + 'profile details!', + 'The templates were rendered' + ); + }); + } - this.router.map(function () { - this.route('posts', function () { - this.route('post', { path: '/:postId', resetNamespace: true }, function () { - this.route('edit'); + ['@test Parent route context change'](assert) { + let editCount = 0; + let editedPostIds = emberA(); + + this.addTemplate('application', '{{outlet}}'); + this.addTemplate('posts', '{{outlet}}'); + this.addTemplate('post', '{{outlet}}'); + this.addTemplate('post/index', 'showing'); + this.addTemplate('post/edit', 'editing'); + + this.router.map(function() { + this.route('posts', function() { + this.route( + 'post', + { path: '/:postId', resetNamespace: true }, + function() { + this.route('edit'); + } + ); }); }); - }); - this.add('route:posts', Route.extend({ - actions: { - showPost(context) { - this.transitionTo('post', context); - } - } - })); - - this.add('route:post', Route.extend({ - model(params) { - return { id: params.postId }; - }, + this.add( + 'route:posts', + Route.extend({ + actions: { + showPost(context) { + this.transitionTo('post', context); + } + } + }) + ); - serialize(model) { - return { postId: model.id }; - }, + this.add( + 'route:post', + Route.extend({ + model(params) { + return { id: params.postId }; + }, + + serialize(model) { + return { postId: model.id }; + }, + + actions: { + editPost() { + this.transitionTo('post.edit'); + } + } + }) + ); - actions: { - editPost() { - this.transitionTo('post.edit'); - } - } - })); - - this.add('route:post.edit', Route.extend({ - model() { - let postId = this.modelFor('post').id; - editedPostIds.push(postId); - return null; - }, - setup() { - this._super(...arguments); - editCount++; - } - })); - - return this.visit('/posts/1').then(() => { - assert.ok(true, '/posts/1 has been handled'); - let router = this.applicationInstance.lookup('router:main'); - run(() => router.send('editPost')); - run(() => router.send('showPost', { id: '2' })); - run(() => router.send('editPost')); - assert.equal(editCount, 2, 'set up the edit route twice without failure'); - assert.deepEqual(editedPostIds, ['1', '2'], 'modelFor posts.post returns the right context'); - }); - } + this.add( + 'route:post.edit', + Route.extend({ + model() { + let postId = this.modelFor('post').id; + editedPostIds.push(postId); + return null; + }, + setup() { + this._super(...arguments); + editCount++; + } + }) + ); - ['@test Router accounts for rootURL on page load when using history location'](assert) { - let rootURL = window.location.pathname + '/app'; - let postsTemplateRendered = false; - let setHistory; + return this.visit('/posts/1').then(() => { + assert.ok(true, '/posts/1 has been handled'); + let router = this.applicationInstance.lookup('router:main'); + run(() => router.send('editPost')); + run(() => router.send('showPost', { id: '2' })); + run(() => router.send('editPost')); + assert.equal( + editCount, + 2, + 'set up the edit route twice without failure' + ); + assert.deepEqual( + editedPostIds, + ['1', '2'], + 'modelFor posts.post returns the right context' + ); + }); + } - setHistory = function (obj, path) { - obj.set('history', { state: { path: path } }); - }; + ['@test Router accounts for rootURL on page load when using history location']( + assert + ) { + let rootURL = window.location.pathname + '/app'; + let postsTemplateRendered = false; + let setHistory; + setHistory = function(obj, path) { + obj.set('history', { state: { path: path } }); + }; - this.router.reopen({ - // location: 'historyTest', - location: HistoryLocation.create({ - initState() { - let path = rootURL + '/posts'; + this.router.reopen({ + // location: 'historyTest', + location: HistoryLocation.create({ + initState() { + let path = rootURL + '/posts'; - setHistory(this, path); - this.set('location', { - pathname: path, - href: 'http://localhost/' + path - }); - }, + setHistory(this, path); + this.set('location', { + pathname: path, + href: 'http://localhost/' + path + }); + }, - replaceState(path) { - setHistory(this, path); - }, + replaceState(path) { + setHistory(this, path); + }, - pushState(path) { - setHistory(this, path); - } - }), - rootURL: rootURL - }); - - this.router.map(function () { - this.route('posts', { path: '/posts' }); - }); - - this.add('route:posts', Route.extend({ - model() { }, - renderTemplate() { - postsTemplateRendered = true; - } - })); - - return this.visit('/').then(() => { - assert.ok(postsTemplateRendered, 'Posts route successfully stripped from rootURL'); - }); - } + pushState(path) { + setHistory(this, path); + } + }), + rootURL: rootURL + }); - ['@test The rootURL is passed properly to the location implementation'](assert) { - assert.expect(1); - let rootURL = '/blahzorz'; - this.add('location:history-test', HistoryLocation.extend({ - rootURL: 'this is not the URL you are looking for', - history: { - pushState() { } - }, - initState() { - assert.equal(this.get('rootURL'), rootURL); - } - })); - - this.router.reopen({ - location: 'history-test', - rootURL: rootURL, - // if we transition in this test we will receive failures - // if the tests are run from a static file - _doURLTransition() { - return RSVP.resolve(''); - } - }); + this.router.map(function() { + this.route('posts', { path: '/posts' }); + }); - return this.visit('/'); - } + this.add( + 'route:posts', + Route.extend({ + model() {}, + renderTemplate() { + postsTemplateRendered = true; + } + }) + ); - ['@test Only use route rendered into main outlet for default into property on child'](assert) { - this.addTemplate('application', '{{outlet \'menu\'}}{{outlet}}'); - this.addTemplate('posts', '{{outlet}}'); - this.addTemplate('posts.index', '

    postsIndex

    '); - this.addTemplate('posts.menu', '
    postsMenu
    '); - - this.router.map(function () { - this.route('posts', function () { }); - }); - - this.add('route:posts', Route.extend({ - renderTemplate() { - this.render(); - this.render('posts/menu', { - into: 'application', - outlet: 'menu' - }); - } - })); + return this.visit('/').then(() => { + assert.ok( + postsTemplateRendered, + 'Posts route successfully stripped from rootURL' + ); + }); + } - return this.visit('/posts').then(() => { - assert.ok(true, '/posts has been handled'); - let rootElement = document.getElementById('qunit-fixture'); - assert.equal(getTextOf(rootElement.querySelector('div.posts-menu')), 'postsMenu', 'The posts/menu template was rendered'); - assert.equal(getTextOf(rootElement.querySelector('p.posts-index')), 'postsIndex', 'The posts/index template was rendered'); - }); - } + ['@test The rootURL is passed properly to the location implementation']( + assert + ) { + assert.expect(1); + let rootURL = '/blahzorz'; + this.add( + 'location:history-test', + HistoryLocation.extend({ + rootURL: 'this is not the URL you are looking for', + history: { + pushState() {} + }, + initState() { + assert.equal(this.get('rootURL'), rootURL); + } + }) + ); - ['@test Generating a URL should not affect currentModel'](assert) { - this.router.map(function () { - this.route('post', { path: '/posts/:post_id' }); - }); + this.router.reopen({ + location: 'history-test', + rootURL: rootURL, + // if we transition in this test we will receive failures + // if the tests are run from a static file + _doURLTransition() { + return RSVP.resolve(''); + } + }); - let posts = { - 1: { id: 1 }, - 2: { id: 2 } - }; + return this.visit('/'); + } - this.add('route:post', Route.extend({ - model(params) { - return posts[params.post_id]; - } - })); + ['@test Only use route rendered into main outlet for default into property on child']( + assert + ) { + this.addTemplate('application', "{{outlet 'menu'}}{{outlet}}"); + this.addTemplate('posts', '{{outlet}}'); + this.addTemplate('posts.index', '

    postsIndex

    '); + this.addTemplate('posts.menu', '
    postsMenu
    '); - return this.visit('/posts/1').then(() => { - assert.ok(true, '/posts/1 has been handled'); + this.router.map(function() { + this.route('posts', function() {}); + }); - let route = this.applicationInstance.lookup('route:post'); - assert.equal(route.modelFor('post'), posts[1]); + this.add( + 'route:posts', + Route.extend({ + renderTemplate() { + this.render(); + this.render('posts/menu', { + into: 'application', + outlet: 'menu' + }); + } + }) + ); - let url = this.applicationInstance.lookup('router:main').generate('post', posts[2]); - assert.equal(url, '/posts/2'); - assert.equal(route.modelFor('post'), posts[1]); - }); - } + return this.visit('/posts').then(() => { + assert.ok(true, '/posts has been handled'); + let rootElement = document.getElementById('qunit-fixture'); + assert.equal( + getTextOf(rootElement.querySelector('div.posts-menu')), + 'postsMenu', + 'The posts/menu template was rendered' + ); + assert.equal( + getTextOf(rootElement.querySelector('p.posts-index')), + 'postsIndex', + 'The posts/index template was rendered' + ); + }); + } - ['@test Nested index route is not overridden by parent\'s implicit index route'](assert) { - this.router.map(function () { - this.route('posts', function () { - this.route('index', { path: ':category' }); + ['@test Generating a URL should not affect currentModel'](assert) { + this.router.map(function() { + this.route('post', { path: '/posts/:post_id' }); }); - }); - return this.visit('/').then(() => { - let router = this.applicationInstance.lookup('router:main'); - return router.transitionTo('posts', { category: 'emberjs' }); - }).then(() => { - let router = this.applicationInstance.lookup('router:main'); - assert.deepEqual(router.location.path, '/posts/emberjs'); - }); - } + let posts = { + 1: { id: 1 }, + 2: { id: 2 } + }; - ['@test Application template does not duplicate when re-rendered'](assert) { - this.addTemplate('application', '

    I render once

    {{outlet}}'); + this.add( + 'route:post', + Route.extend({ + model(params) { + return posts[params.post_id]; + } + }) + ); - this.router.map(function() { - this.route('posts'); - }); + return this.visit('/posts/1').then(() => { + assert.ok(true, '/posts/1 has been handled'); - this.add('route:application', Route.extend({ - model() { - return emberA(); - } - })); + let route = this.applicationInstance.lookup('route:post'); + assert.equal(route.modelFor('post'), posts[1]); - return this.visit('/posts').then(() => { - assert.ok(true, '/posts has been handled'); - let rootElement = document.getElementById('qunit-fixture'); - assert.equal(getTextOf(rootElement.querySelector('h3.render-once')), "I render once"); - }); - } + let url = this.applicationInstance + .lookup('router:main') + .generate('post', posts[2]); + assert.equal(url, '/posts/2'); + assert.equal(route.modelFor('post'), posts[1]); + }); + } - ['@test Child routes should render inside the application template if the application template causes a redirect'](assert) { - this.addTemplate('application', '

    App

    {{outlet}}'); - this.addTemplate('posts', 'posts'); + ["@test Nested index route is not overridden by parent's implicit index route"]( + assert + ) { + this.router.map(function() { + this.route('posts', function() { + this.route('index', { path: ':category' }); + }); + }); - this.router.map(function() { - this.route('posts'); - this.route('photos'); - }); + return this.visit('/') + .then(() => { + let router = this.applicationInstance.lookup('router:main'); + return router.transitionTo('posts', { category: 'emberjs' }); + }) + .then(() => { + let router = this.applicationInstance.lookup('router:main'); + assert.deepEqual(router.location.path, '/posts/emberjs'); + }); + } - this.add('route:application', Route.extend({ - afterModel() { - this.transitionTo('posts'); - } - })); + ['@test Application template does not duplicate when re-rendered'](assert) { + this.addTemplate( + 'application', + '

    I render once

    {{outlet}}' + ); - return this.visit('/posts').then(() => { - let rootElement = document.getElementById('qunit-fixture'); - assert.equal(rootElement.textContent.trim(), 'App posts'); - }); - } + this.router.map(function() { + this.route('posts'); + }); - ['@test The template is not re-rendered when the route\'s context changes'](assert) { - this.router.map(function() { - this.route('page', { path: '/page/:name' }); - }); + this.add( + 'route:application', + Route.extend({ + model() { + return emberA(); + } + }) + ); - this.add('route:page', Route.extend({ - model(params) { - return EmberObject.create({ name: params.name }); - } - })); + return this.visit('/posts').then(() => { + assert.ok(true, '/posts has been handled'); + let rootElement = document.getElementById('qunit-fixture'); + assert.equal( + getTextOf(rootElement.querySelector('h3.render-once')), + 'I render once' + ); + }); + } - let insertionCount = 0; - this.add('component:foo-bar', Component.extend({ - didInsertElement() { - insertionCount += 1; - } - })); - - this.addTemplate('page', '

    {{model.name}}{{foo-bar}}

    '); - - let rootElement = document.getElementById('qunit-fixture'); - return this.visit('/page/first').then(() => { - assert.ok(true, '/page/first has been handled'); - assert.equal(getTextOf(rootElement.querySelector('p')), 'first'); - assert.equal(insertionCount, 1); - return this.visit('/page/second'); - }).then(() => { - assert.ok(true, '/page/second has been handled'); - assert.equal(getTextOf(rootElement.querySelector('p')), 'second'); - assert.equal(insertionCount, 1, 'view should have inserted only once'); - let router = this.applicationInstance.lookup('router:main'); - return run(() => router.transitionTo('page', EmberObject.create({ name: 'third' }))); - }).then(() => { - assert.equal(getTextOf(rootElement.querySelector('p')), 'third'); - assert.equal(insertionCount, 1, 'view should still have inserted only once'); - }); - } + ['@test Child routes should render inside the application template if the application template causes a redirect']( + assert + ) { + this.addTemplate('application', '

    App

    {{outlet}}'); + this.addTemplate('posts', 'posts'); + + this.router.map(function() { + this.route('posts'); + this.route('photos'); + }); - ['@test The template is not re-rendered when two routes present the exact same template & controller'](assert) { - this.router.map(function () { - this.route('first'); - this.route('second'); - this.route('third'); - this.route('fourth'); - }); + this.add( + 'route:application', + Route.extend({ + afterModel() { + this.transitionTo('posts'); + } + }) + ); - // Note add a component to test insertion + return this.visit('/posts').then(() => { + let rootElement = document.getElementById('qunit-fixture'); + assert.equal(rootElement.textContent.trim(), 'App posts'); + }); + } - let insertionCount = 0; - this.add('component:x-input', Component.extend({ - didInsertElement() { - insertionCount += 1; - } - })); + ["@test The template is not re-rendered when the route's context changes"]( + assert + ) { + this.router.map(function() { + this.route('page', { path: '/page/:name' }); + }); - let SharedRoute = Route.extend({ - setupController() { - this.controllerFor('shared').set('message', 'This is the ' + this.routeName + ' message'); - }, + this.add( + 'route:page', + Route.extend({ + model(params) { + return EmberObject.create({ name: params.name }); + } + }) + ); - renderTemplate() { - this.render('shared', { controller: 'shared' }); - } - }); - - this.add('route:shared', SharedRoute); - this.add('route:first', SharedRoute.extend()); - this.add('route:second', SharedRoute.extend()); - this.add('route:third', SharedRoute.extend()); - this.add('route:fourth', SharedRoute.extend()); - - this.add('controller:shared', Controller.extend()); - - this.addTemplate('shared', '

    {{message}}{{x-input}}

    '); - - let rootElement = document.getElementById('qunit-fixture'); - return this.visit('/first').then(() => { - assert.ok(true, '/first has been handled'); - assert.equal(getTextOf(rootElement.querySelector('p')), 'This is the first message'); - assert.equal(insertionCount, 1, 'expected one assertion'); - return this.visit('/second'); - }).then(() => { - assert.ok(true, '/second has been handled'); - assert.equal(getTextOf(rootElement.querySelector('p')), 'This is the second message'); - assert.equal(insertionCount, 1, 'expected one assertion'); - return run(() => { - this.applicationInstance.lookup('router:main').transitionTo('third').then(function () { - assert.ok(true, 'expected transition'); - }, function (reason) { - assert.ok(false, 'unexpected transition failure: ', QUnit.jsDump.parse(reason)); + let insertionCount = 0; + this.add( + 'component:foo-bar', + Component.extend({ + didInsertElement() { + insertionCount += 1; + } + }) + ); + + this.addTemplate('page', '

    {{model.name}}{{foo-bar}}

    '); + + let rootElement = document.getElementById('qunit-fixture'); + return this.visit('/page/first') + .then(() => { + assert.ok(true, '/page/first has been handled'); + assert.equal(getTextOf(rootElement.querySelector('p')), 'first'); + assert.equal(insertionCount, 1); + return this.visit('/page/second'); + }) + .then(() => { + assert.ok(true, '/page/second has been handled'); + assert.equal(getTextOf(rootElement.querySelector('p')), 'second'); + assert.equal( + insertionCount, + 1, + 'view should have inserted only once' + ); + let router = this.applicationInstance.lookup('router:main'); + return run(() => + router.transitionTo('page', EmberObject.create({ name: 'third' })) + ); + }) + .then(() => { + assert.equal(getTextOf(rootElement.querySelector('p')), 'third'); + assert.equal( + insertionCount, + 1, + 'view should still have inserted only once' + ); }); + } + + ['@test The template is not re-rendered when two routes present the exact same template & controller']( + assert + ) { + this.router.map(function() { + this.route('first'); + this.route('second'); + this.route('third'); + this.route('fourth'); }); - }).then(() => { - assert.equal(getTextOf(rootElement.querySelector('p')), 'This is the third message'); - assert.equal(insertionCount, 1, 'expected one assertion'); - return this.visit('fourth'); - }).then(() => { - assert.ok(true, '/fourth has been handled'); - assert.equal(insertionCount, 1, 'expected one assertion'); - assert.equal(getTextOf(rootElement.querySelector('p')), 'This is the fourth message'); - }); - } - ['@test ApplicationRoute with model does not proxy the currentPath'](assert) { - let model = {}; - let currentPath; + // Note add a component to test insertion - this.router.map(function () { - this.route('index', { path: '/' }); - }); + let insertionCount = 0; + this.add( + 'component:x-input', + Component.extend({ + didInsertElement() { + insertionCount += 1; + } + }) + ); - this.add('route:application', Route.extend({ - model() { return model; } - })); + let SharedRoute = Route.extend({ + setupController() { + this.controllerFor('shared').set( + 'message', + 'This is the ' + this.routeName + ' message' + ); + }, - this.add('controller:application', Controller.extend({ - currentPathDidChange: observer('currentPath', function () { - currentPath = this.currentPath; - }) - })); + renderTemplate() { + this.render('shared', { controller: 'shared' }); + } + }); - return this.visit('/').then(() => { - assert.equal(currentPath, 'index', 'currentPath is index'); - assert.equal('currentPath' in model, false, 'should have defined currentPath on controller'); - }); - } + this.add('route:shared', SharedRoute); + this.add('route:first', SharedRoute.extend()); + this.add('route:second', SharedRoute.extend()); + this.add('route:third', SharedRoute.extend()); + this.add('route:fourth', SharedRoute.extend()); - ['@test Promises encountered on app load put app into loading state until resolved'](assert) { - assert.expect(2); + this.add('controller:shared', Controller.extend()); - let deferred = RSVP.defer(); - this.router.map(function () { - this.route('index', { path: '/' }); - }); + this.addTemplate('shared', '

    {{message}}{{x-input}}

    '); - this.add('route:index', Route.extend({ - model() { - return deferred.promise; - } - })); + let rootElement = document.getElementById('qunit-fixture'); + return this.visit('/first') + .then(() => { + assert.ok(true, '/first has been handled'); + assert.equal( + getTextOf(rootElement.querySelector('p')), + 'This is the first message' + ); + assert.equal(insertionCount, 1, 'expected one assertion'); + return this.visit('/second'); + }) + .then(() => { + assert.ok(true, '/second has been handled'); + assert.equal( + getTextOf(rootElement.querySelector('p')), + 'This is the second message' + ); + assert.equal(insertionCount, 1, 'expected one assertion'); + return run(() => { + this.applicationInstance + .lookup('router:main') + .transitionTo('third') + .then( + function() { + assert.ok(true, 'expected transition'); + }, + function(reason) { + assert.ok( + false, + 'unexpected transition failure: ', + QUnit.jsDump.parse(reason) + ); + } + ); + }); + }) + .then(() => { + assert.equal( + getTextOf(rootElement.querySelector('p')), + 'This is the third message' + ); + assert.equal(insertionCount, 1, 'expected one assertion'); + return this.visit('fourth'); + }) + .then(() => { + assert.ok(true, '/fourth has been handled'); + assert.equal(insertionCount, 1, 'expected one assertion'); + assert.equal( + getTextOf(rootElement.querySelector('p')), + 'This is the fourth message' + ); + }); + } - this.addTemplate('index', '

    INDEX

    '); - this.addTemplate('loading', '

    LOADING

    '); + ['@test ApplicationRoute with model does not proxy the currentPath']( + assert + ) { + let model = {}; + let currentPath; - run(() => this.visit('/')); - let rootElement = document.getElementById('qunit-fixture'); - assert.equal(getTextOf(rootElement.querySelector('p')), 'LOADING', 'The loading state is displaying.'); - run(deferred.resolve); - assert.equal(getTextOf(rootElement.querySelector('p')), 'INDEX', 'The index route is display.'); - } + this.router.map(function() { + this.route('index', { path: '/' }); + }); - ['@test Route should tear down multiple outlets'](assert) { - this.addTemplate('application', '{{outlet \'menu\'}}{{outlet}}{{outlet \'footer\'}}'); - this.addTemplate('posts', '{{outlet}}'); - this.addTemplate('users', 'users'); - this.addTemplate('posts.index', '

    postsIndex

    '); - this.addTemplate('posts.menu', '
    postsMenu
    '); - this.addTemplate('posts.footer', ''); - - this.router.map(function() { - this.route('posts', function() {}); - this.route('users', function() {}); - }); - - this.add('route:posts', Route.extend({ - renderTemplate() { - this.render('posts/menu', { - into: 'application', - outlet: 'menu' - }); + this.add( + 'route:application', + Route.extend({ + model() { + return model; + } + }) + ); - this.render(); + this.add( + 'controller:application', + Controller.extend({ + currentPathDidChange: observer('currentPath', function() { + currentPath = this.currentPath; + }) + }) + ); - this.render('posts/footer', { - into: 'application', - outlet: 'footer' - }); - } - })); - - let rootElement = document.getElementById('qunit-fixture'); - return this.visit('/posts').then(() => { - assert.ok(true, '/posts has been handled'); - assert.equal(getTextOf(rootElement.querySelector('div.posts-menu')), 'postsMenu', 'The posts/menu template was rendered'); - assert.equal(getTextOf(rootElement.querySelector('p.posts-index')), 'postsIndex', 'The posts/index template was rendered'); - assert.equal(getTextOf(rootElement.querySelector('div.posts-footer')), 'postsFooter', 'The posts/footer template was rendered'); - - return this.visit('/users'); - }).then(() => { - assert.ok(true, '/users has been handled'); - assert.equal(rootElement.querySelector('div.posts-menu'), null, 'The posts/menu template was removed'); - assert.equal(rootElement.querySelector('p.posts-index'), null, 'The posts/index template was removed'); - assert.equal(rootElement.querySelector('div.posts-footer'), null, 'The posts/footer template was removed'); - }); + return this.visit('/').then(() => { + assert.equal(currentPath, 'index', 'currentPath is index'); + assert.equal( + 'currentPath' in model, + false, + 'should have defined currentPath on controller' + ); + }); + } - } + ['@test Promises encountered on app load put app into loading state until resolved']( + assert + ) { + assert.expect(2); - ['@test Route will assert if you try to explicitly render {into: ...} a missing template']() { - expectDeprecation(/Rendering into a {{render}} helper that resolves to an {{outlet}} is deprecated./); + let deferred = RSVP.defer(); + this.router.map(function() { + this.route('index', { path: '/' }); + }); - this.router.map(function() { - this.route('home', { path: '/' }); - }); + this.add( + 'route:index', + Route.extend({ + model() { + return deferred.promise; + } + }) + ); - this.add('route:home', Route.extend({ - renderTemplate() { - this.render({ into: 'nonexistent' }); - } - })); + this.addTemplate('index', '

    INDEX

    '); + this.addTemplate('loading', '

    LOADING

    '); - expectAssertion(() => this.visit('/'), 'You attempted to render into \'nonexistent\' but it was not found'); - } + run(() => this.visit('/')); + let rootElement = document.getElementById('qunit-fixture'); + assert.equal( + getTextOf(rootElement.querySelector('p')), + 'LOADING', + 'The loading state is displaying.' + ); + run(deferred.resolve); + assert.equal( + getTextOf(rootElement.querySelector('p')), + 'INDEX', + 'The index route is display.' + ); + } - ['@test Route supports clearing outlet explicitly'](assert) { - this.addTemplate('application', '{{outlet}}{{outlet \'modal\'}}'); - this.addTemplate('posts', '{{outlet}}'); - this.addTemplate('users', 'users'); - this.addTemplate('posts.index', '
    postsIndex {{outlet}}
    '); - this.addTemplate('posts.modal', '
    postsModal
    '); - this.addTemplate('posts.extra', '
    postsExtra
    '); - - this.router.map(function() { - this.route('posts', function() {}); - this.route('users', function() {}); - }); - - this.add('route:posts', Route.extend({ - actions: { - showModal() { - this.render('posts/modal', { - into: 'application', - outlet: 'modal' - }); - }, - hideModal() { - this.disconnectOutlet({ outlet: 'modal', parentView: 'application' }); - } - } - })); + ['@test Route should tear down multiple outlets'](assert) { + this.addTemplate( + 'application', + "{{outlet 'menu'}}{{outlet}}{{outlet 'footer'}}" + ); + this.addTemplate('posts', '{{outlet}}'); + this.addTemplate('users', 'users'); + this.addTemplate('posts.index', '

    postsIndex

    '); + this.addTemplate('posts.menu', '
    postsMenu
    '); + this.addTemplate( + 'posts.footer', + '' + ); - this.add('route:posts.index', Route.extend({ - actions: { - showExtra() { - this.render('posts/extra', { - into: 'posts/index' - }); - }, - hideExtra() { - this.disconnectOutlet({ parentView: 'posts/index' }); - } - } - })); + this.router.map(function() { + this.route('posts', function() {}); + this.route('users', function() {}); + }); - let rootElement = document.getElementById('qunit-fixture'); + this.add( + 'route:posts', + Route.extend({ + renderTemplate() { + this.render('posts/menu', { + into: 'application', + outlet: 'menu' + }); - return this.visit('/posts').then(() => { - let router = this.applicationInstance.lookup('router:main'); + this.render(); - assert.equal(getTextOf(rootElement.querySelector('div.posts-index')), 'postsIndex', 'The posts/index template was rendered'); - run(() => router.send('showModal')); - assert.equal(getTextOf(rootElement.querySelector('div.posts-modal')), 'postsModal', 'The posts/modal template was rendered'); - run(() => router.send('showExtra')); + this.render('posts/footer', { + into: 'application', + outlet: 'footer' + }); + } + }) + ); - assert.equal(getTextOf(rootElement.querySelector('div.posts-extra')), 'postsExtra', 'The posts/extra template was rendered'); - run(() => router.send('hideModal')); + let rootElement = document.getElementById('qunit-fixture'); + return this.visit('/posts') + .then(() => { + assert.ok(true, '/posts has been handled'); + assert.equal( + getTextOf(rootElement.querySelector('div.posts-menu')), + 'postsMenu', + 'The posts/menu template was rendered' + ); + assert.equal( + getTextOf(rootElement.querySelector('p.posts-index')), + 'postsIndex', + 'The posts/index template was rendered' + ); + assert.equal( + getTextOf(rootElement.querySelector('div.posts-footer')), + 'postsFooter', + 'The posts/footer template was rendered' + ); + + return this.visit('/users'); + }) + .then(() => { + assert.ok(true, '/users has been handled'); + assert.equal( + rootElement.querySelector('div.posts-menu'), + null, + 'The posts/menu template was removed' + ); + assert.equal( + rootElement.querySelector('p.posts-index'), + null, + 'The posts/index template was removed' + ); + assert.equal( + rootElement.querySelector('div.posts-footer'), + null, + 'The posts/footer template was removed' + ); + }); + } - assert.equal(rootElement.querySelector('div.posts-modal'), null, 'The posts/modal template was removed'); - run(() => router.send('hideExtra')); + ['@test Route will assert if you try to explicitly render {into: ...} a missing template']() { + expectDeprecation( + /Rendering into a {{render}} helper that resolves to an {{outlet}} is deprecated./ + ); - assert.equal(rootElement.querySelector('div.posts-extra'), null, 'The posts/extra template was removed'); - run(function() { - router.send('showModal'); + this.router.map(function() { + this.route('home', { path: '/' }); }); - assert.equal(getTextOf(rootElement.querySelector('div.posts-modal')), 'postsModal', 'The posts/modal template was rendered'); - run(function() { - router.send('showExtra'); + + this.add( + 'route:home', + Route.extend({ + renderTemplate() { + this.render({ into: 'nonexistent' }); + } + }) + ); + + expectAssertion( + () => this.visit('/'), + "You attempted to render into 'nonexistent' but it was not found" + ); + } + + ['@test Route supports clearing outlet explicitly'](assert) { + this.addTemplate('application', "{{outlet}}{{outlet 'modal'}}"); + this.addTemplate('posts', '{{outlet}}'); + this.addTemplate('users', 'users'); + this.addTemplate( + 'posts.index', + '
    postsIndex {{outlet}}
    ' + ); + this.addTemplate( + 'posts.modal', + '
    postsModal
    ' + ); + this.addTemplate( + 'posts.extra', + '
    postsExtra
    ' + ); + + this.router.map(function() { + this.route('posts', function() {}); + this.route('users', function() {}); }); - assert.equal(getTextOf(rootElement.querySelector('div.posts-extra')), 'postsExtra', 'The posts/extra template was rendered'); - return this.visit('/users'); - }).then(() => { - assert.equal(rootElement.querySelector('div.posts-index'), null, 'The posts/index template was removed'); - assert.equal(rootElement.querySelector('div.posts-modal'), null, 'The posts/modal template was removed'); - assert.equal(rootElement.querySelector('div.posts-extra'), null, 'The posts/extra template was removed'); - }); - } - ['@test Route supports clearing outlet using string parameter'](assert) { - this.addTemplate('application', '{{outlet}}{{outlet \'modal\'}}'); - this.addTemplate('posts', '{{outlet}}'); - this.addTemplate('users', 'users'); - this.addTemplate('posts.index', '
    postsIndex {{outlet}}
    '); - this.addTemplate('posts.modal', '
    postsModal
    '); - - this.router.map(function() { - this.route('posts', function() {}); - this.route('users', function() {}); - }); - - this.add('route:posts', Route.extend({ - actions: { - showModal() { - this.render('posts/modal', { - into: 'application', - outlet: 'modal' - }); - }, - hideModal() { - this.disconnectOutlet('modal'); - } - } - })); - - let rootElement = document.getElementById('qunit-fixture'); - return this.visit('/posts').then(() => { - let router = this.applicationInstance.lookup('router:main'); - assert.equal(getTextOf(rootElement.querySelector('div.posts-index')), 'postsIndex', 'The posts/index template was rendered'); - run(() => router.send('showModal')); - assert.equal(getTextOf(rootElement.querySelector('div.posts-modal')), 'postsModal', 'The posts/modal template was rendered'); - run(() => router.send('hideModal')); - assert.equal(rootElement.querySelector('div.posts-modal'), null, 'The posts/modal template was removed'); - return this.visit('/users'); - }).then(() => { - assert.equal(rootElement.querySelector('div.posts-index'), null, 'The posts/index template was removed'); - assert.equal(rootElement.querySelector('div.posts-modal'), null, 'The posts/modal template was removed'); - }); - } + this.add( + 'route:posts', + Route.extend({ + actions: { + showModal() { + this.render('posts/modal', { + into: 'application', + outlet: 'modal' + }); + }, + hideModal() { + this.disconnectOutlet({ + outlet: 'modal', + parentView: 'application' + }); + } + } + }) + ); - ['@test Route silently fails when cleaning an outlet from an inactive view'](assert) { - assert.expect(1); // handleURL + this.add( + 'route:posts.index', + Route.extend({ + actions: { + showExtra() { + this.render('posts/extra', { + into: 'posts/index' + }); + }, + hideExtra() { + this.disconnectOutlet({ parentView: 'posts/index' }); + } + } + }) + ); - this.addTemplate('application', '{{outlet}}'); - this.addTemplate('posts', '{{outlet \'modal\'}}'); - this.addTemplate('modal', 'A Yo.'); + let rootElement = document.getElementById('qunit-fixture'); - this.router.map(function() { - this.route('posts'); - }); + return this.visit('/posts') + .then(() => { + let router = this.applicationInstance.lookup('router:main'); + + assert.equal( + getTextOf(rootElement.querySelector('div.posts-index')), + 'postsIndex', + 'The posts/index template was rendered' + ); + run(() => router.send('showModal')); + assert.equal( + getTextOf(rootElement.querySelector('div.posts-modal')), + 'postsModal', + 'The posts/modal template was rendered' + ); + run(() => router.send('showExtra')); + + assert.equal( + getTextOf(rootElement.querySelector('div.posts-extra')), + 'postsExtra', + 'The posts/extra template was rendered' + ); + run(() => router.send('hideModal')); + + assert.equal( + rootElement.querySelector('div.posts-modal'), + null, + 'The posts/modal template was removed' + ); + run(() => router.send('hideExtra')); + + assert.equal( + rootElement.querySelector('div.posts-extra'), + null, + 'The posts/extra template was removed' + ); + run(function() { + router.send('showModal'); + }); + assert.equal( + getTextOf(rootElement.querySelector('div.posts-modal')), + 'postsModal', + 'The posts/modal template was rendered' + ); + run(function() { + router.send('showExtra'); + }); + assert.equal( + getTextOf(rootElement.querySelector('div.posts-extra')), + 'postsExtra', + 'The posts/extra template was rendered' + ); + return this.visit('/users'); + }) + .then(() => { + assert.equal( + rootElement.querySelector('div.posts-index'), + null, + 'The posts/index template was removed' + ); + assert.equal( + rootElement.querySelector('div.posts-modal'), + null, + 'The posts/modal template was removed' + ); + assert.equal( + rootElement.querySelector('div.posts-extra'), + null, + 'The posts/extra template was removed' + ); + }); + } - this.add('route:posts', Route.extend({ - actions: { - hideSelf() { - this.disconnectOutlet({ outlet: 'main', parentView: 'application' }); - }, - showModal() { - this.render('modal', { into: 'posts', outlet: 'modal' }); - }, - hideModal() { - this.disconnectOutlet({ outlet: 'modal', parentView: 'posts' }); - } - } - })); - - return this.visit('/posts').then(() => { - assert.ok(true, '/posts has been handled'); - let router = this.applicationInstance.lookup('router:main'); - run(() => router.send('showModal')); - run(() => router.send('hideSelf')); - run(() => router.send('hideModal')); - }); - } + ['@test Route supports clearing outlet using string parameter'](assert) { + this.addTemplate('application', "{{outlet}}{{outlet 'modal'}}"); + this.addTemplate('posts', '{{outlet}}'); + this.addTemplate('users', 'users'); + this.addTemplate( + 'posts.index', + '
    postsIndex {{outlet}}
    ' + ); + this.addTemplate( + 'posts.modal', + '
    postsModal
    ' + ); - ['@test Router `willTransition` hook passes in cancellable transition'](assert) { - // Should hit willTransition 3 times, once for the initial route, and then 2 more times - // for the two handleURL calls below - assert.expect(5); - - this.router.map(function() { - this.route('nork'); - this.route('about'); - }); - - this.router.reopen({ - willTransition(_, _2, transition) { - assert.ok(true, 'willTransition was called'); - if (transition.intent.url !== '/') { - transition.abort(); - } - } - }); + this.router.map(function() { + this.route('posts', function() {}); + this.route('users', function() {}); + }); - this.add('route:loading', Route.extend({ - activate() { - assert.ok(false, 'LoadingRoute was not entered'); - } - })); + this.add( + 'route:posts', + Route.extend({ + actions: { + showModal() { + this.render('posts/modal', { + into: 'application', + outlet: 'modal' + }); + }, + hideModal() { + this.disconnectOutlet('modal'); + } + } + }) + ); - this.add('route:nork', Route.extend({ - activate() { - assert.ok(false, 'NorkRoute was not entered'); - } - })); + let rootElement = document.getElementById('qunit-fixture'); + return this.visit('/posts') + .then(() => { + let router = this.applicationInstance.lookup('router:main'); + assert.equal( + getTextOf(rootElement.querySelector('div.posts-index')), + 'postsIndex', + 'The posts/index template was rendered' + ); + run(() => router.send('showModal')); + assert.equal( + getTextOf(rootElement.querySelector('div.posts-modal')), + 'postsModal', + 'The posts/modal template was rendered' + ); + run(() => router.send('hideModal')); + assert.equal( + rootElement.querySelector('div.posts-modal'), + null, + 'The posts/modal template was removed' + ); + return this.visit('/users'); + }) + .then(() => { + assert.equal( + rootElement.querySelector('div.posts-index'), + null, + 'The posts/index template was removed' + ); + assert.equal( + rootElement.querySelector('div.posts-modal'), + null, + 'The posts/modal template was removed' + ); + }); + } - this.add('route:about', Route.extend({ - activate() { - assert.ok(false, 'AboutRoute was not entered'); - } - })); + ['@test Route silently fails when cleaning an outlet from an inactive view']( + assert + ) { + assert.expect(1); // handleURL - return this.visit('/').then(() => { - this.handleURLAborts(assert, '/nork'); - this.handleURLAborts(assert, '/about'); - }); - } + this.addTemplate('application', '{{outlet}}'); + this.addTemplate('posts', "{{outlet 'modal'}}"); + this.addTemplate('modal', 'A Yo.'); + + this.router.map(function() { + this.route('posts'); + }); - ['@test Aborting/redirecting the transition in `willTransition` prevents LoadingRoute from being entered'](assert) { - assert.expect(5); + this.add( + 'route:posts', + Route.extend({ + actions: { + hideSelf() { + this.disconnectOutlet({ + outlet: 'main', + parentView: 'application' + }); + }, + showModal() { + this.render('modal', { into: 'posts', outlet: 'modal' }); + }, + hideModal() { + this.disconnectOutlet({ outlet: 'modal', parentView: 'posts' }); + } + } + }) + ); + + return this.visit('/posts').then(() => { + assert.ok(true, '/posts has been handled'); + let router = this.applicationInstance.lookup('router:main'); + run(() => router.send('showModal')); + run(() => router.send('hideSelf')); + run(() => router.send('hideModal')); + }); + } - this.router.map(function () { - this.route('index'); - this.route('nork'); - this.route('about'); - }); + ['@test Router `willTransition` hook passes in cancellable transition']( + assert + ) { + // Should hit willTransition 3 times, once for the initial route, and then 2 more times + // for the two handleURL calls below + assert.expect(5); - let redirect = false; + this.router.map(function() { + this.route('nork'); + this.route('about'); + }); - this.add('route:index', Route.extend({ - actions: { - willTransition(transition) { + this.router.reopen({ + willTransition(_, _2, transition) { assert.ok(true, 'willTransition was called'); - if (redirect) { - // router.js won't refire `willTransition` for this redirect - this.transitionTo('about'); - } else { + if (transition.intent.url !== '/') { transition.abort(); } } - } - })); - - let deferred = null; - - this.add('route:loading', Route.extend({ - activate() { - assert.ok(deferred, 'LoadingRoute should be entered at this time'); - }, - deactivate() { - assert.ok(true, 'LoadingRoute was exited'); - } - })); + }); - this.add('route:nork', Route.extend({ - activate() { - assert.ok(true, 'NorkRoute was entered'); - } - })); - - this.add('route:about', Route.extend({ - activate() { - assert.ok(true, 'AboutRoute was entered'); - }, - model() { - if (deferred) { return deferred.promise; } - } - })); - - return this.visit('/').then(() => { - let router = this.applicationInstance.lookup('router:main'); - // Attempted transitions out of index should abort. - run(router, 'transitionTo', 'nork'); - run(router, 'handleURL', '/nork'); - - // Attempted transitions out of index should redirect to about - redirect = true; - run(router, 'transitionTo', 'nork'); - run(router, 'transitionTo', 'index'); - - // Redirected transitions out of index to a route with a - // promise model should pause the transition and - // activate LoadingRoute - deferred = RSVP.defer(); - run(router, 'transitionTo', 'nork'); - run(deferred.resolve); - }); + this.add( + 'route:loading', + Route.extend({ + activate() { + assert.ok(false, 'LoadingRoute was not entered'); + } + }) + ); - } + this.add( + 'route:nork', + Route.extend({ + activate() { + assert.ok(false, 'NorkRoute was not entered'); + } + }) + ); + this.add( + 'route:about', + Route.extend({ + activate() { + assert.ok(false, 'AboutRoute was not entered'); + } + }) + ); - ['@test `didTransition` event fires on the router'](assert) { - assert.expect(3); + return this.visit('/').then(() => { + this.handleURLAborts(assert, '/nork'); + this.handleURLAborts(assert, '/about'); + }); + } - this.router.map(function() { - this.route('nork'); - }); + ['@test Aborting/redirecting the transition in `willTransition` prevents LoadingRoute from being entered']( + assert + ) { + assert.expect(5); - return this.visit('/').then(() => { - let router = this.applicationInstance.lookup('router:main'); - router.one('didTransition', function() { - assert.ok(true, 'didTransition fired on initial routing'); - }); - this.visit('/'); - }).then(() => { - let router = this.applicationInstance.lookup('router:main'); - router.one('didTransition', function() { - assert.ok(true, 'didTransition fired on the router'); - assert.equal(router.get('url'), '/nork', 'The url property is updated by the time didTransition fires'); + this.router.map(function() { + this.route('index'); + this.route('nork'); + this.route('about'); }); - return this.visit('/nork'); - }); - } + let redirect = false; + + this.add( + 'route:index', + Route.extend({ + actions: { + willTransition(transition) { + assert.ok(true, 'willTransition was called'); + if (redirect) { + // router.js won't refire `willTransition` for this redirect + this.transitionTo('about'); + } else { + transition.abort(); + } + } + } + }) + ); - ['@test `didTransition` can be reopened'](assert) { - assert.expect(1); + let deferred = null; - this.router.map(function() { - this.route('nork'); - }); + this.add( + 'route:loading', + Route.extend({ + activate() { + assert.ok(deferred, 'LoadingRoute should be entered at this time'); + }, + deactivate() { + assert.ok(true, 'LoadingRoute was exited'); + } + }) + ); - this.router.reopen({ - didTransition() { - this._super(...arguments); - assert.ok(true, 'reopened didTransition was called'); - } - }); + this.add( + 'route:nork', + Route.extend({ + activate() { + assert.ok(true, 'NorkRoute was entered'); + } + }) + ); - return this.visit('/'); - } + this.add( + 'route:about', + Route.extend({ + activate() { + assert.ok(true, 'AboutRoute was entered'); + }, + model() { + if (deferred) { + return deferred.promise; + } + } + }) + ); - ['@test `activate` event fires on the route'](assert) { - assert.expect(2); + return this.visit('/').then(() => { + let router = this.applicationInstance.lookup('router:main'); + // Attempted transitions out of index should abort. + run(router, 'transitionTo', 'nork'); + run(router, 'handleURL', '/nork'); + + // Attempted transitions out of index should redirect to about + redirect = true; + run(router, 'transitionTo', 'nork'); + run(router, 'transitionTo', 'index'); + + // Redirected transitions out of index to a route with a + // promise model should pause the transition and + // activate LoadingRoute + deferred = RSVP.defer(); + run(router, 'transitionTo', 'nork'); + run(deferred.resolve); + }); + } - let eventFired = 0; + ['@test `didTransition` event fires on the router'](assert) { + assert.expect(3); - this.router.map(function () { - this.route('nork'); - }); + this.router.map(function() { + this.route('nork'); + }); - this.add('route:nork', Route.extend({ - init() { - this._super(...arguments); + return this.visit('/') + .then(() => { + let router = this.applicationInstance.lookup('router:main'); + router.one('didTransition', function() { + assert.ok(true, 'didTransition fired on initial routing'); + }); + this.visit('/'); + }) + .then(() => { + let router = this.applicationInstance.lookup('router:main'); + router.one('didTransition', function() { + assert.ok(true, 'didTransition fired on the router'); + assert.equal( + router.get('url'), + '/nork', + 'The url property is updated by the time didTransition fires' + ); + }); - this.on('activate', function () { - assert.equal(++eventFired, 1, 'activate event is fired once'); + return this.visit('/nork'); }); - }, + } - activate() { - assert.ok(true, 'activate hook is called'); - } - })); + ['@test `didTransition` can be reopened'](assert) { + assert.expect(1); - return this.visit('/nork'); - } + this.router.map(function() { + this.route('nork'); + }); - ['@test `deactivate` event fires on the route'](assert) { - assert.expect(2); + this.router.reopen({ + didTransition() { + this._super(...arguments); + assert.ok(true, 'reopened didTransition was called'); + } + }); - let eventFired = 0; + return this.visit('/'); + } - this.router.map(function () { - this.route('nork'); - this.route('dork'); - }); + ['@test `activate` event fires on the route'](assert) { + assert.expect(2); - this.add('route:nork', Route.extend({ - init() { - this._super(...arguments); + let eventFired = 0; - this.on('deactivate', function () { - assert.equal(++eventFired, 1, 'deactivate event is fired once'); - }); - }, + this.router.map(function() { + this.route('nork'); + }); - deactivate() { - assert.ok(true, 'deactivate hook is called'); - } - })); + this.add( + 'route:nork', + Route.extend({ + init() { + this._super(...arguments); - return this.visit('/nork').then(() => this.visit('/dork')); - } + this.on('activate', function() { + assert.equal(++eventFired, 1, 'activate event is fired once'); + }); + }, - ['@test Actions can be handled by inherited action handlers'](assert) { - assert.expect(4); + activate() { + assert.ok(true, 'activate hook is called'); + } + }) + ); - let SuperRoute = Route.extend({ - actions: { - foo() { - assert.ok(true, 'foo'); - }, - bar(msg) { - assert.equal(msg, 'HELLO'); - } - } - }); + return this.visit('/nork'); + } - let RouteMixin = Mixin.create({ - actions: { - bar(msg) { - assert.equal(msg, 'HELLO'); - this._super(msg); - } - } - }); + ['@test `deactivate` event fires on the route'](assert) { + assert.expect(2); - this.add('route:home', SuperRoute.extend(RouteMixin, { - actions: { - baz() { - assert.ok(true, 'baz'); - } - } - })); + let eventFired = 0; - this.addTemplate('home', ` - Do foo - Do bar with arg - Do bar - `); + this.router.map(function() { + this.route('nork'); + this.route('dork'); + }); - return this.visit('/').then(() => { - let rootElement = document.getElementById('qunit-fixture'); - rootElement.querySelector('.do-foo').click(); - rootElement.querySelector('.do-bar-with-arg').click(); - rootElement.querySelector('.do-baz').click(); - }); - } + this.add( + 'route:nork', + Route.extend({ + init() { + this._super(...arguments); - ['@test transitionTo returns Transition when passed a route name'](assert) { - assert.expect(1); + this.on('deactivate', function() { + assert.equal(++eventFired, 1, 'deactivate event is fired once'); + }); + }, - this.router.map(function () { - this.route('root', { path: '/' }); - this.route('bar'); - }); + deactivate() { + assert.ok(true, 'deactivate hook is called'); + } + }) + ); - return this.visit('/').then(() => { - let router = this.applicationInstance.lookup('router:main'); - let transition = run(() => router.transitionTo('bar')); - assert.equal(transition instanceof Transition, true); - }); - } + return this.visit('/nork').then(() => this.visit('/dork')); + } - ['@test transitionTo returns Transition when passed a url'](assert) { - assert.expect(1); + ['@test Actions can be handled by inherited action handlers'](assert) { + assert.expect(4); - this.router.map(function () { - this.route('root', { path: '/' }); - this.route('bar', function () { - this.route('baz'); + let SuperRoute = Route.extend({ + actions: { + foo() { + assert.ok(true, 'foo'); + }, + bar(msg) { + assert.equal(msg, 'HELLO'); + } + } }); - }); - return this.visit('/').then(() => { - let router = this.applicationInstance.lookup('router:main'); - let transition = run(() => router.transitionTo('/bar/baz')); - assert.equal(transition instanceof Transition, true); - }); - } + let RouteMixin = Mixin.create({ + actions: { + bar(msg) { + assert.equal(msg, 'HELLO'); + this._super(msg); + } + } + }); - ['@test currentRouteName is a property installed on ApplicationController that can be used in transitionTo'](assert) { - assert.expect(24); + this.add( + 'route:home', + SuperRoute.extend(RouteMixin, { + actions: { + baz() { + assert.ok(true, 'baz'); + } + } + }) + ); - this.router.map(function () { - this.route('index', { path: '/' }); - this.route('be', function () { - this.route('excellent', { resetNamespace: true }, function () { - this.route('to', { resetNamespace: true }, function () { - this.route('each', { resetNamespace: true }, function () { - this.route('other'); - }); - }); - }); - }); - }); + this.addTemplate( + 'home', + ` + Do foo + Do bar with arg + Do bar + ` + ); - return this.visit('/').then(() => { - let appController = this.applicationInstance.lookup('controller:application'); - let router = this.applicationInstance.lookup('router:main'); + return this.visit('/').then(() => { + let rootElement = document.getElementById('qunit-fixture'); + rootElement.querySelector('.do-foo').click(); + rootElement.querySelector('.do-bar-with-arg').click(); + rootElement.querySelector('.do-baz').click(); + }); + } - function transitionAndCheck(path, expectedPath, expectedRouteName) { - if (path) { run(router, 'transitionTo', path); } - assert.equal(appController.get('currentPath'), expectedPath); - assert.equal(appController.get('currentRouteName'), expectedRouteName); - } + ['@test transitionTo returns Transition when passed a route name'](assert) { + assert.expect(1); - transitionAndCheck(null, 'index', 'index'); - transitionAndCheck('/be', 'be.index', 'be.index'); - transitionAndCheck('/be/excellent', 'be.excellent.index', 'excellent.index'); - transitionAndCheck('/be/excellent/to', 'be.excellent.to.index', 'to.index'); - transitionAndCheck('/be/excellent/to/each', 'be.excellent.to.each.index', 'each.index'); - transitionAndCheck('/be/excellent/to/each/other', 'be.excellent.to.each.other', 'each.other'); - - transitionAndCheck('index', 'index', 'index'); - transitionAndCheck('be', 'be.index', 'be.index'); - transitionAndCheck('excellent', 'be.excellent.index', 'excellent.index'); - transitionAndCheck('to.index', 'be.excellent.to.index', 'to.index'); - transitionAndCheck('each', 'be.excellent.to.each.index', 'each.index'); - transitionAndCheck('each.other', 'be.excellent.to.each.other', 'each.other'); - }); - } + this.router.map(function() { + this.route('root', { path: '/' }); + this.route('bar'); + }); - ['@test Route model hook finds the same model as a manual find'](assert) { - let post; - let Post = EmberObject.extend(); - this.add('model:post', Post); - Post.reopenClass({ - find() { - post = this; - return {}; - } - }); + return this.visit('/').then(() => { + let router = this.applicationInstance.lookup('router:main'); + let transition = run(() => router.transitionTo('bar')); + assert.equal(transition instanceof Transition, true); + }); + } - this.router.map(function () { - this.route('post', { path: '/post/:post_id' }); - }); + ['@test transitionTo returns Transition when passed a url'](assert) { + assert.expect(1); - return this.visit('/post/1').then(() => { - assert.equal(Post, post); - }); - } + this.router.map(function() { + this.route('root', { path: '/' }); + this.route('bar', function() { + this.route('baz'); + }); + }); - ['@test Routes can refresh themselves causing their model hooks to be re-run'](assert) { - this.router.map(function () { - this.route('parent', { path: '/parent/:parent_id' }, function () { - this.route('child'); + return this.visit('/').then(() => { + let router = this.applicationInstance.lookup('router:main'); + let transition = run(() => router.transitionTo('/bar/baz')); + assert.equal(transition instanceof Transition, true); }); - }); + } - let appcount = 0; - this.add('route:application', Route.extend({ - model() { - ++appcount; - } - })); - - let parentcount = 0; - this.add('route:parent', Route.extend({ - model(params) { - assert.equal(params.parent_id, '123'); - ++parentcount; - }, - actions: { - refreshParent() { - this.refresh(); - } - } - })); + ['@test currentRouteName is a property installed on ApplicationController that can be used in transitionTo']( + assert + ) { + assert.expect(24); - let childcount = 0; - this.add('route:parent.child', Route.extend({ - model() { - ++childcount; - } - })); - - let router; - return this.visit('/').then(() => { - router = this.applicationInstance.lookup('router:main'); - assert.equal(appcount, 1); - assert.equal(parentcount, 0); - assert.equal(childcount, 0); - return run(router, 'transitionTo', 'parent.child', '123'); - }).then(() => { - assert.equal(appcount, 1); - assert.equal(parentcount, 1); - assert.equal(childcount, 1); - return run(router, 'send', 'refreshParent'); - }).then(() => { - assert.equal(appcount, 1); - assert.equal(parentcount, 2); - assert.equal(childcount, 2); - }); - } + this.router.map(function() { + this.route('index', { path: '/' }); + this.route('be', function() { + this.route('excellent', { resetNamespace: true }, function() { + this.route('to', { resetNamespace: true }, function() { + this.route('each', { resetNamespace: true }, function() { + this.route('other'); + }); + }); + }); + }); + }); - ['@test Specifying non-existent controller name in route#render throws'](assert) { - assert.expect(1); + return this.visit('/').then(() => { + let appController = this.applicationInstance.lookup( + 'controller:application' + ); + let router = this.applicationInstance.lookup('router:main'); - this.router.map(function () { - this.route('home', { path: '/' }); - }); + function transitionAndCheck(path, expectedPath, expectedRouteName) { + if (path) { + run(router, 'transitionTo', path); + } + assert.equal(appController.get('currentPath'), expectedPath); + assert.equal( + appController.get('currentRouteName'), + expectedRouteName + ); + } - this.add('route:home', Route.extend({ - renderTemplate() { - expectAssertion(() => { - this.render('homepage', { controller: 'stefanpenneristhemanforme' }); - }, 'You passed `controller: \'stefanpenneristhemanforme\'` into the `render` method, but no such controller could be found.'); - } - })); + transitionAndCheck(null, 'index', 'index'); + transitionAndCheck('/be', 'be.index', 'be.index'); + transitionAndCheck( + '/be/excellent', + 'be.excellent.index', + 'excellent.index' + ); + transitionAndCheck( + '/be/excellent/to', + 'be.excellent.to.index', + 'to.index' + ); + transitionAndCheck( + '/be/excellent/to/each', + 'be.excellent.to.each.index', + 'each.index' + ); + transitionAndCheck( + '/be/excellent/to/each/other', + 'be.excellent.to.each.other', + 'each.other' + ); + + transitionAndCheck('index', 'index', 'index'); + transitionAndCheck('be', 'be.index', 'be.index'); + transitionAndCheck( + 'excellent', + 'be.excellent.index', + 'excellent.index' + ); + transitionAndCheck('to.index', 'be.excellent.to.index', 'to.index'); + transitionAndCheck('each', 'be.excellent.to.each.index', 'each.index'); + transitionAndCheck( + 'each.other', + 'be.excellent.to.each.other', + 'each.other' + ); + }); + } - return this.visit('/'); - } + ['@test Route model hook finds the same model as a manual find'](assert) { + let post; + let Post = EmberObject.extend(); + this.add('model:post', Post); + Post.reopenClass({ + find() { + post = this; + return {}; + } + }); - ['@test Redirecting with null model doesn\'t error out'](assert) { - this.router.map(function () { - this.route('home', { path: '/' }); - this.route('about', { path: '/about/:hurhurhur' }); - }); + this.router.map(function() { + this.route('post', { path: '/post/:post_id' }); + }); - this.add('route:about', Route.extend({ - serialize: function (model) { - if (model === null) { - return { hurhurhur: 'TreeklesMcGeekles' }; - } - } - })); + return this.visit('/post/1').then(() => { + assert.equal(Post, post); + }); + } - this.add('route:home', Route.extend({ - beforeModel() { - this.transitionTo('about', null); - } - })); + ['@test Routes can refresh themselves causing their model hooks to be re-run']( + assert + ) { + this.router.map(function() { + this.route('parent', { path: '/parent/:parent_id' }, function() { + this.route('child'); + }); + }); - return this.visit('/').then(() => { - let router = this.applicationInstance.lookup('router:main'); - assert.equal(router.get('location.path'), '/about/TreeklesMcGeekles'); - }); - } + let appcount = 0; + this.add( + 'route:application', + Route.extend({ + model() { + ++appcount; + } + }) + ); - ['@test rejecting the model hooks promise with a non-error prints the `message` property'](assert) { - assert.expect(5); + let parentcount = 0; + this.add( + 'route:parent', + Route.extend({ + model(params) { + assert.equal(params.parent_id, '123'); + ++parentcount; + }, + actions: { + refreshParent() { + this.refresh(); + } + } + }) + ); - let rejectedMessage = 'OMG!! SOOOOOO BAD!!!!'; - let rejectedStack = 'Yeah, buddy: stack gets printed too.'; + let childcount = 0; + this.add( + 'route:parent.child', + Route.extend({ + model() { + ++childcount; + } + }) + ); - this.router.map(function () { - this.route('yippie', { path: '/' }); - }); + let router; + return this.visit('/') + .then(() => { + router = this.applicationInstance.lookup('router:main'); + assert.equal(appcount, 1); + assert.equal(parentcount, 0); + assert.equal(childcount, 0); + return run(router, 'transitionTo', 'parent.child', '123'); + }) + .then(() => { + assert.equal(appcount, 1); + assert.equal(parentcount, 1); + assert.equal(childcount, 1); + return run(router, 'send', 'refreshParent'); + }) + .then(() => { + assert.equal(appcount, 1); + assert.equal(parentcount, 2); + assert.equal(childcount, 2); + }); + } - console.error = function (initialMessage, errorMessage, errorStack) { - assert.equal(initialMessage, 'Error while processing route: yippie', 'a message with the current route name is printed'); - assert.equal(errorMessage, rejectedMessage, 'the rejected reason\'s message property is logged'); - assert.equal(errorStack, rejectedStack, 'the rejected reason\'s stack property is logged'); - }; + ['@test Specifying non-existent controller name in route#render throws']( + assert + ) { + assert.expect(1); - this.add('route:yippie', Route.extend({ - model() { - return RSVP.reject({ message: rejectedMessage, stack: rejectedStack }); - } - })); + this.router.map(function() { + this.route('home', { path: '/' }); + }); + + this.add( + 'route:home', + Route.extend({ + renderTemplate() { + expectAssertion(() => { + this.render('homepage', { + controller: 'stefanpenneristhemanforme' + }); + }, "You passed `controller: 'stefanpenneristhemanforme'` into the `render` method, but no such controller could be found."); + } + }) + ); - return assert.throws(() => { return this.visit('/'); - }, function (err) { - assert.equal(err.message, rejectedMessage); - return true; - }, 'expected an exception'); - } + } - ['@test rejecting the model hooks promise with an error with `errorThrown` property prints `errorThrown.message` property'](assert) { - assert.expect(5); - let rejectedMessage = 'OMG!! SOOOOOO BAD!!!!'; - let rejectedStack = 'Yeah, buddy: stack gets printed too.'; - - this.router.map(function () { - this.route('yippie', { path: '/' }); - }); - - console.error = function (initialMessage, errorMessage, errorStack) { - assert.equal(initialMessage, 'Error while processing route: yippie', 'a message with the current route name is printed'); - assert.equal(errorMessage, rejectedMessage, 'the rejected reason\'s message property is logged'); - assert.equal(errorStack, rejectedStack, 'the rejected reason\'s stack property is logged'); - }; - - this.add('route:yippie', Route.extend({ - model() { - return RSVP.reject({ - errorThrown: { message: rejectedMessage, stack: rejectedStack } - }); - } - })); + ["@test Redirecting with null model doesn't error out"](assert) { + this.router.map(function() { + this.route('home', { path: '/' }); + this.route('about', { path: '/about/:hurhurhur' }); + }); - assert.throws(() => this.visit('/'), function (err) { - assert.equal(err.message, rejectedMessage); - return true; - }, 'expected an exception'); - } + this.add( + 'route:about', + Route.extend({ + serialize: function(model) { + if (model === null) { + return { hurhurhur: 'TreeklesMcGeekles' }; + } + } + }) + ); - ['@test rejecting the model hooks promise with no reason still logs error'](assert) { - assert.expect(2); - this.router.map(function() { - this.route('wowzers', { path: '/' }); - }); + this.add( + 'route:home', + Route.extend({ + beforeModel() { + this.transitionTo('about', null); + } + }) + ); - console.error = function(initialMessage) { - assert.equal(initialMessage, 'Error while processing route: wowzers', 'a message with the current route name is printed'); - }; + return this.visit('/').then(() => { + let router = this.applicationInstance.lookup('router:main'); + assert.equal(router.get('location.path'), '/about/TreeklesMcGeekles'); + }); + } - this.add('route:wowzers', Route.extend({ - model() { - return RSVP.reject(); - } - })); + ['@test rejecting the model hooks promise with a non-error prints the `message` property']( + assert + ) { + assert.expect(5); - return assert.throws(() => this.visit('/')); - } + let rejectedMessage = 'OMG!! SOOOOOO BAD!!!!'; + let rejectedStack = 'Yeah, buddy: stack gets printed too.'; - ['@test rejecting the model hooks promise with a string shows a good error'](assert) { - assert.expect(3); - let rejectedMessage = 'Supercalifragilisticexpialidocious'; + this.router.map(function() { + this.route('yippie', { path: '/' }); + }); - this.router.map(function() { - this.route('yondo', { path: '/' }); - }); + console.error = function(initialMessage, errorMessage, errorStack) { + assert.equal( + initialMessage, + 'Error while processing route: yippie', + 'a message with the current route name is printed' + ); + assert.equal( + errorMessage, + rejectedMessage, + "the rejected reason's message property is logged" + ); + assert.equal( + errorStack, + rejectedStack, + "the rejected reason's stack property is logged" + ); + }; - console.error = function(initialMessage, errorMessage) { - assert.equal(initialMessage, 'Error while processing route: yondo', 'a message with the current route name is printed'); - assert.equal(errorMessage, rejectedMessage, 'the rejected reason\'s message property is logged'); - }; + this.add( + 'route:yippie', + Route.extend({ + model() { + return RSVP.reject({ + message: rejectedMessage, + stack: rejectedStack + }); + } + }) + ); - this.add('route:yondo', Route.extend({ - model() { - return RSVP.reject(rejectedMessage); - } - })); + return assert.throws( + () => { + return this.visit('/'); + }, + function(err) { + assert.equal(err.message, rejectedMessage); + return true; + }, + 'expected an exception' + ); + } - assert.throws(() => this.visit('/'), new RegExp(rejectedMessage), 'expected an exception'); - } + ['@test rejecting the model hooks promise with an error with `errorThrown` property prints `errorThrown.message` property']( + assert + ) { + assert.expect(5); + let rejectedMessage = 'OMG!! SOOOOOO BAD!!!!'; + let rejectedStack = 'Yeah, buddy: stack gets printed too.'; + + this.router.map(function() { + this.route('yippie', { path: '/' }); + }); - ['@test willLeave, willChangeContext, willChangeModel actions don\'t fire unless feature flag enabled'](assert) { - assert.expect(1); + console.error = function(initialMessage, errorMessage, errorStack) { + assert.equal( + initialMessage, + 'Error while processing route: yippie', + 'a message with the current route name is printed' + ); + assert.equal( + errorMessage, + rejectedMessage, + "the rejected reason's message property is logged" + ); + assert.equal( + errorStack, + rejectedStack, + "the rejected reason's stack property is logged" + ); + }; - this.router.map(function() { - this.route('about'); - }); + this.add( + 'route:yippie', + Route.extend({ + model() { + return RSVP.reject({ + errorThrown: { message: rejectedMessage, stack: rejectedStack } + }); + } + }) + ); - function shouldNotFire() { - assert.ok(false, 'this action shouldn\'t have been received'); + assert.throws( + () => this.visit('/'), + function(err) { + assert.equal(err.message, rejectedMessage); + return true; + }, + 'expected an exception' + ); } - this.add('route:index', Route.extend({ - actions: { - willChangeModel: shouldNotFire, - willChangeContext: shouldNotFire, - willLeave: shouldNotFire - } - })); + ['@test rejecting the model hooks promise with no reason still logs error']( + assert + ) { + assert.expect(2); + this.router.map(function() { + this.route('wowzers', { path: '/' }); + }); - this.add('route:about', Route.extend({ - setupController() { - assert.ok(true, 'about route was entered'); - } - })); + console.error = function(initialMessage) { + assert.equal( + initialMessage, + 'Error while processing route: wowzers', + 'a message with the current route name is printed' + ); + }; - return this.visit('/about'); - } + this.add( + 'route:wowzers', + Route.extend({ + model() { + return RSVP.reject(); + } + }) + ); - ['@test Errors in transitionTo within redirect hook are logged'](assert) { - assert.expect(4); - let actual = []; + return assert.throws(() => this.visit('/')); + } - this.router.map(function() { - this.route('yondo', { path: '/' }); - this.route('stink-bomb'); - }); + ['@test rejecting the model hooks promise with a string shows a good error']( + assert + ) { + assert.expect(3); + let rejectedMessage = 'Supercalifragilisticexpialidocious'; - this.add('route:yondo', Route.extend({ - redirect() { - this.transitionTo('stink-bomb', { something: 'goes boom' }); - } - })); + this.router.map(function() { + this.route('yondo', { path: '/' }); + }); - console.error = function() { - // push the arguments onto an array so we can detect if the error gets logged twice - actual.push(arguments); - }; + console.error = function(initialMessage, errorMessage) { + assert.equal( + initialMessage, + 'Error while processing route: yondo', + 'a message with the current route name is printed' + ); + assert.equal( + errorMessage, + rejectedMessage, + "the rejected reason's message property is logged" + ); + }; - assert.throws(() => this.visit('/'), /More context objects were passed/); + this.add( + 'route:yondo', + Route.extend({ + model() { + return RSVP.reject(rejectedMessage); + } + }) + ); - assert.equal(actual.length, 1, 'the error is only logged once'); - assert.equal(actual[0][0], 'Error while processing route: yondo', 'source route is printed'); - assert.ok(actual[0][1].match(/More context objects were passed than there are dynamic segments for the route: stink-bomb/), 'the error is printed'); - } + assert.throws( + () => this.visit('/'), + new RegExp(rejectedMessage), + 'expected an exception' + ); + } - ['@test Errors in transition show error template if available'](assert) { - this.addTemplate('error', '
    Error!
    '); + ["@test willLeave, willChangeContext, willChangeModel actions don't fire unless feature flag enabled"]( + assert + ) { + assert.expect(1); - this.router.map(function() { - this.route('yondo', { path: '/' }); - this.route('stink-bomb'); - }); + this.router.map(function() { + this.route('about'); + }); - this.add('route:yondo', Route.extend({ - redirect() { - this.transitionTo('stink-bomb', { something: 'goes boom' }); + function shouldNotFire() { + assert.ok(false, "this action shouldn't have been received"); } - })); - this.visit('/').then(() => { - let rootElement = document.querySelector('#qunit-fixture'); - assert.equal(rootElement.querySelectorAll('#error').length, 1, 'Error template was rendered.'); - }); - } + this.add( + 'route:index', + Route.extend({ + actions: { + willChangeModel: shouldNotFire, + willChangeContext: shouldNotFire, + willLeave: shouldNotFire + } + }) + ); + + this.add( + 'route:about', + Route.extend({ + setupController() { + assert.ok(true, 'about route was entered'); + } + }) + ); + + return this.visit('/about'); + } - ['@test Route#resetController gets fired when changing models and exiting routes'](assert) { - assert.expect(4); + ['@test Errors in transitionTo within redirect hook are logged'](assert) { + assert.expect(4); + let actual = []; - this.router.map(function() { - this.route('a', function() { - this.route('b', { path: '/b/:id', resetNamespace: true }, function() { }); - this.route('c', { path: '/c/:id', resetNamespace: true }, function() { }); + this.router.map(function() { + this.route('yondo', { path: '/' }); + this.route('stink-bomb'); }); - this.route('out'); - }); - let calls = []; + this.add( + 'route:yondo', + Route.extend({ + redirect() { + this.transitionTo('stink-bomb', { something: 'goes boom' }); + } + }) + ); - let SpyRoute = Route.extend({ - setupController(/* controller, model, transition */) { - calls.push(['setup', this.routeName]); - }, + console.error = function() { + // push the arguments onto an array so we can detect if the error gets logged twice + actual.push(arguments); + }; - resetController(/* controller */) { - calls.push(['reset', this.routeName]); - } - }); - - this.add('route:a', SpyRoute.extend()); - this.add('route:b', SpyRoute.extend()); - this.add('route:c', SpyRoute.extend()); - this.add('route:out', SpyRoute.extend()); - - let router; - return this.visit('/').then(() => { - router = this.applicationInstance.lookup('router:main'); - assert.deepEqual(calls, []); - return run(router, 'transitionTo', 'b', 'b-1'); - }).then(() => { - assert.deepEqual(calls, [['setup', 'a'], ['setup', 'b']]); - calls.length = 0; - return run(router, 'transitionTo', 'c', 'c-1'); - }).then(() => { - assert.deepEqual(calls, [['reset', 'b'], ['setup', 'c']]); - calls.length = 0; - return run(router, 'transitionTo', 'out'); - }).then(() => { - assert.deepEqual(calls, [['reset', 'c'], ['reset', 'a'], ['setup', 'out']]); - }); - } + assert.throws(() => this.visit('/'), /More context objects were passed/); - ['@test Exception during initialization of non-initial route is not swallowed'](assert) { - this.router.map(function() { - this.route('boom'); - }); - this.add('route:boom', Route.extend({ - init() { - throw new Error('boom!'); - } - })); + assert.equal(actual.length, 1, 'the error is only logged once'); + assert.equal( + actual[0][0], + 'Error while processing route: yondo', + 'source route is printed' + ); + assert.ok( + actual[0][1].match( + /More context objects were passed than there are dynamic segments for the route: stink-bomb/ + ), + 'the error is printed' + ); + } - return assert.throws(() => this.visit('/boom'), /\bboom\b/); - } + ['@test Errors in transition show error template if available'](assert) { + this.addTemplate('error', "
    Error!
    "); - ['@test Exception during initialization of initial route is not swallowed'](assert) { - this.router.map(function() { - this.route('boom', { path: '/' }); - }); - this.add('route:boom', Route.extend({ - init() { - throw new Error('boom!'); - } - })); - return assert.throws(() => this.visit('/'), /\bboom\b/); - } + this.router.map(function() { + this.route('yondo', { path: '/' }); + this.route('stink-bomb'); + }); - ['@test {{outlet}} works when created after initial render'](assert) { - this.addTemplate('sample', 'Hi{{#if showTheThing}}{{outlet}}{{/if}}Bye'); - this.addTemplate('sample.inner', 'Yay'); - this.addTemplate('sample.inner2', 'Boo'); - this.router.map(function() { - this.route('sample', { path: '/' }, function() { - this.route('inner', { path: '/' }); - this.route('inner2', { path: '/2' }); - }); - }); - - let rootElement; - return this.visit('/').then(() => { - rootElement = document.getElementById('qunit-fixture'); - assert.equal(rootElement.textContent.trim(), 'HiBye', 'initial render'); - - run(() => this.applicationInstance.lookup('controller:sample').set('showTheThing', true)); - - assert.equal(rootElement.textContent.trim(), 'HiYayBye', 'second render'); - return this.visit('/2'); - }).then(() => { - assert.equal(rootElement.textContent.trim(), 'HiBooBye', 'third render'); - }); - } + this.add( + 'route:yondo', + Route.extend({ + redirect() { + this.transitionTo('stink-bomb', { something: 'goes boom' }); + } + }) + ); + + this.visit('/').then(() => { + let rootElement = document.querySelector('#qunit-fixture'); + assert.equal( + rootElement.querySelectorAll('#error').length, + 1, + 'Error template was rendered.' + ); + }); + } - ['@test Can render into a named outlet at the top level'](assert) { - this.addTemplate('application', 'A-{{outlet}}-B-{{outlet "other"}}-C'); - this.addTemplate('modal', 'Hello world'); - this.addTemplate('index', 'The index'); - this.router.map(function() { - this.route('index', { path: '/' }); - }); - this.add('route:application', Route.extend({ - renderTemplate() { - this.render(); - this.render('modal', { - into: 'application', - outlet: 'other' + ['@test Route#resetController gets fired when changing models and exiting routes']( + assert + ) { + assert.expect(4); + + this.router.map(function() { + this.route('a', function() { + this.route( + 'b', + { path: '/b/:id', resetNamespace: true }, + function() {} + ); + this.route( + 'c', + { path: '/c/:id', resetNamespace: true }, + function() {} + ); }); - } - })); + this.route('out'); + }); - return this.visit('/').then(() => { - let rootElement = document.getElementById('qunit-fixture'); - assert.equal(rootElement.textContent.trim(), 'A-The index-B-Hello world-C', 'initial render'); - }); - } + let calls = []; - ['@test Can disconnect a named outlet at the top level'](assert) { - this.addTemplate('application', 'A-{{outlet}}-B-{{outlet "other"}}-C'); - this.addTemplate('modal', 'Hello world'); - this.addTemplate('index', 'The index'); - this.router.map(function () { - this.route('index', { path: '/' }); - }); - this.add('route:application', Route.extend({ - renderTemplate() { - this.render(); - this.render('modal', { - into: 'application', - outlet: 'other' - }); - }, - actions: { - banish() { - this.disconnectOutlet({ - parentView: 'application', - outlet: 'other' - }); + let SpyRoute = Route.extend({ + setupController(/* controller, model, transition */) { + calls.push(['setup', this.routeName]); + }, + + resetController(/* controller */) { + calls.push(['reset', this.routeName]); } - } - })); + }); - return this.visit('/').then(() => { - let rootElement = document.getElementById('qunit-fixture'); - assert.equal(rootElement.textContent.trim(), 'A-The index-B-Hello world-C', 'initial render'); + this.add('route:a', SpyRoute.extend()); + this.add('route:b', SpyRoute.extend()); + this.add('route:c', SpyRoute.extend()); + this.add('route:out', SpyRoute.extend()); + + let router; + return this.visit('/') + .then(() => { + router = this.applicationInstance.lookup('router:main'); + assert.deepEqual(calls, []); + return run(router, 'transitionTo', 'b', 'b-1'); + }) + .then(() => { + assert.deepEqual(calls, [['setup', 'a'], ['setup', 'b']]); + calls.length = 0; + return run(router, 'transitionTo', 'c', 'c-1'); + }) + .then(() => { + assert.deepEqual(calls, [['reset', 'b'], ['setup', 'c']]); + calls.length = 0; + return run(router, 'transitionTo', 'out'); + }) + .then(() => { + assert.deepEqual(calls, [ + ['reset', 'c'], + ['reset', 'a'], + ['setup', 'out'] + ]); + }); + } - run(this.applicationInstance.lookup('router:main'), 'send', 'banish'); + ['@test Exception during initialization of non-initial route is not swallowed']( + assert + ) { + this.router.map(function() { + this.route('boom'); + }); + this.add( + 'route:boom', + Route.extend({ + init() { + throw new Error('boom!'); + } + }) + ); - assert.equal(rootElement.textContent.trim(), 'A-The index-B--C', 'second render'); - }); - } + return assert.throws(() => this.visit('/boom'), /\bboom\b/); + } - ['@test Can render into a named outlet at the top level, with empty main outlet'](assert) { - this.addTemplate('application', 'A-{{outlet}}-B-{{outlet "other"}}-C'); - this.addTemplate('modal', 'Hello world'); + ['@test Exception during initialization of initial route is not swallowed']( + assert + ) { + this.router.map(function() { + this.route('boom', { path: '/' }); + }); + this.add( + 'route:boom', + Route.extend({ + init() { + throw new Error('boom!'); + } + }) + ); + return assert.throws(() => this.visit('/'), /\bboom\b/); + } - this.router.map(function() { - this.route('hasNoTemplate', { path: '/' }); - }); + ['@test {{outlet}} works when created after initial render'](assert) { + this.addTemplate('sample', 'Hi{{#if showTheThing}}{{outlet}}{{/if}}Bye'); + this.addTemplate('sample.inner', 'Yay'); + this.addTemplate('sample.inner2', 'Boo'); + this.router.map(function() { + this.route('sample', { path: '/' }, function() { + this.route('inner', { path: '/' }); + this.route('inner2', { path: '/2' }); + }); + }); - this.add('route:application', Route.extend({ - renderTemplate() { - this.render(); - this.render('modal', { - into: 'application', - outlet: 'other' + let rootElement; + return this.visit('/') + .then(() => { + rootElement = document.getElementById('qunit-fixture'); + assert.equal( + rootElement.textContent.trim(), + 'HiBye', + 'initial render' + ); + + run(() => + this.applicationInstance + .lookup('controller:sample') + .set('showTheThing', true) + ); + + assert.equal( + rootElement.textContent.trim(), + 'HiYayBye', + 'second render' + ); + return this.visit('/2'); + }) + .then(() => { + assert.equal( + rootElement.textContent.trim(), + 'HiBooBye', + 'third render' + ); }); - } - })); + } - return this.visit('/').then(() => { - let rootElement = document.getElementById('qunit-fixture'); - assert.equal(rootElement.textContent.trim(), 'A--B-Hello world-C', 'initial render'); - }); - } + ['@test Can render into a named outlet at the top level'](assert) { + this.addTemplate('application', 'A-{{outlet}}-B-{{outlet "other"}}-C'); + this.addTemplate('modal', 'Hello world'); + this.addTemplate('index', 'The index'); + this.router.map(function() { + this.route('index', { path: '/' }); + }); + this.add( + 'route:application', + Route.extend({ + renderTemplate() { + this.render(); + this.render('modal', { + into: 'application', + outlet: 'other' + }); + } + }) + ); - ['@test Can render into a named outlet at the top level, later'](assert) { - this.addTemplate('application', 'A-{{outlet}}-B-{{outlet "other"}}-C'); - this.addTemplate('modal', 'Hello world'); - this.addTemplate('index', 'The index'); - this.router.map(function () { - this.route('index', { path: '/' }); - }); - this.add('route:application', Route.extend({ - actions: { - launch() { - this.render('modal', { - into: 'application', - outlet: 'other' - }); - } - } - })); + return this.visit('/').then(() => { + let rootElement = document.getElementById('qunit-fixture'); + assert.equal( + rootElement.textContent.trim(), + 'A-The index-B-Hello world-C', + 'initial render' + ); + }); + } - return this.visit('/').then(() => { - let rootElement = document.getElementById('qunit-fixture'); - assert.equal(rootElement.textContent.trim(), 'A-The index-B--C', 'initial render'); - run(this.applicationInstance.lookup('router:main'), 'send', 'launch'); - assert.equal(rootElement.textContent.trim(), 'A-The index-B-Hello world-C', 'second render'); - }); - } + ['@test Can disconnect a named outlet at the top level'](assert) { + this.addTemplate('application', 'A-{{outlet}}-B-{{outlet "other"}}-C'); + this.addTemplate('modal', 'Hello world'); + this.addTemplate('index', 'The index'); + this.router.map(function() { + this.route('index', { path: '/' }); + }); + this.add( + 'route:application', + Route.extend({ + renderTemplate() { + this.render(); + this.render('modal', { + into: 'application', + outlet: 'other' + }); + }, + actions: { + banish() { + this.disconnectOutlet({ + parentView: 'application', + outlet: 'other' + }); + } + } + }) + ); - ['@test Can render routes with no \'main\' outlet and their children'](assert) { - this.addTemplate('application', '
    {{outlet "app"}}
    '); - this.addTemplate('app', '
    {{outlet "common"}}
    {{outlet "sub"}}
    '); - this.addTemplate('common', '
    '); - this.addTemplate('sub', '
    '); + return this.visit('/').then(() => { + let rootElement = document.getElementById('qunit-fixture'); + assert.equal( + rootElement.textContent.trim(), + 'A-The index-B-Hello world-C', + 'initial render' + ); + + run(this.applicationInstance.lookup('router:main'), 'send', 'banish'); + + assert.equal( + rootElement.textContent.trim(), + 'A-The index-B--C', + 'second render' + ); + }); + } + + ['@test Can render into a named outlet at the top level, with empty main outlet']( + assert + ) { + this.addTemplate('application', 'A-{{outlet}}-B-{{outlet "other"}}-C'); + this.addTemplate('modal', 'Hello world'); - this.router.map(function() { - this.route('app', { path: '/app' }, function() { - this.route('sub', { path: '/sub', resetNamespace: true }); + this.router.map(function() { + this.route('hasNoTemplate', { path: '/' }); }); - }); - this.add('route:app', Route.extend({ - renderTemplate() { - this.render('app', { - outlet: 'app', - into: 'application' - }); - this.render('common', { - outlet: 'common', - into: 'app' + this.add( + 'route:application', + Route.extend({ + renderTemplate() { + this.render(); + this.render('modal', { + into: 'application', + outlet: 'other' + }); + } + }) + ); + + return this.visit('/').then(() => { + let rootElement = document.getElementById('qunit-fixture'); + assert.equal( + rootElement.textContent.trim(), + 'A--B-Hello world-C', + 'initial render' + ); + }); + } + + ['@test Can render into a named outlet at the top level, later'](assert) { + this.addTemplate('application', 'A-{{outlet}}-B-{{outlet "other"}}-C'); + this.addTemplate('modal', 'Hello world'); + this.addTemplate('index', 'The index'); + this.router.map(function() { + this.route('index', { path: '/' }); + }); + this.add( + 'route:application', + Route.extend({ + actions: { + launch() { + this.render('modal', { + into: 'application', + outlet: 'other' + }); + } + } + }) + ); + + return this.visit('/').then(() => { + let rootElement = document.getElementById('qunit-fixture'); + assert.equal( + rootElement.textContent.trim(), + 'A-The index-B--C', + 'initial render' + ); + run(this.applicationInstance.lookup('router:main'), 'send', 'launch'); + assert.equal( + rootElement.textContent.trim(), + 'A-The index-B-Hello world-C', + 'second render' + ); + }); + } + + ["@test Can render routes with no 'main' outlet and their children"]( + assert + ) { + this.addTemplate( + 'application', + '
    {{outlet "app"}}
    ' + ); + this.addTemplate( + 'app', + '
    {{outlet "common"}}
    {{outlet "sub"}}
    ' + ); + this.addTemplate('common', '
    '); + this.addTemplate('sub', '
    '); + + this.router.map(function() { + this.route('app', { path: '/app' }, function() { + this.route('sub', { path: '/sub', resetNamespace: true }); }); - } - })); + }); + + this.add( + 'route:app', + Route.extend({ + renderTemplate() { + this.render('app', { + outlet: 'app', + into: 'application' + }); + this.render('common', { + outlet: 'common', + into: 'app' + }); + } + }) + ); - this.add('route:sub', Route.extend({ - renderTemplate() { - this.render('sub', { - outlet: 'sub', - into: 'app' + this.add( + 'route:sub', + Route.extend({ + renderTemplate() { + this.render('sub', { + outlet: 'sub', + into: 'app' + }); + } + }) + ); + + let rootElement; + return this.visit('/app') + .then(() => { + rootElement = document.getElementById('qunit-fixture'); + assert.equal( + rootElement.querySelectorAll('#app-common #common').length, + 1, + 'Finds common while viewing /app' + ); + return this.visit('/app/sub'); + }) + .then(() => { + assert.equal( + rootElement.querySelectorAll('#app-common #common').length, + 1, + 'Finds common while viewing /app/sub' + ); + assert.equal( + rootElement.querySelectorAll('#app-sub #sub').length, + 1, + 'Finds sub while viewing /app/sub' + ); }); - } - })); - - let rootElement; - return this.visit('/app').then(() => { - rootElement = document.getElementById('qunit-fixture'); - assert.equal(rootElement.querySelectorAll('#app-common #common').length, 1, 'Finds common while viewing /app'); - return this.visit('/app/sub'); - }).then(() => { - assert.equal(rootElement.querySelectorAll('#app-common #common').length, 1, 'Finds common while viewing /app/sub'); - assert.equal(rootElement.querySelectorAll('#app-sub #sub').length, 1, 'Finds sub while viewing /app/sub'); - }); - } + } - ['@test Tolerates stacked renders'](assert) { - this.addTemplate('application', '{{outlet}}{{outlet "modal"}}'); - this.addTemplate('index', 'hi'); - this.addTemplate('layer', 'layer'); - this.router.map(function () { - this.route('index', { path: '/' }); - }); - this.add('route:application', Route.extend({ - actions: { - openLayer() { - this.render('layer', { - into: 'application', - outlet: 'modal' - }); - }, - close() { - this.disconnectOutlet({ - outlet: 'modal', - parentView: 'application' - }); - } - } - })); + ['@test Tolerates stacked renders'](assert) { + this.addTemplate('application', '{{outlet}}{{outlet "modal"}}'); + this.addTemplate('index', 'hi'); + this.addTemplate('layer', 'layer'); + this.router.map(function() { + this.route('index', { path: '/' }); + }); + this.add( + 'route:application', + Route.extend({ + actions: { + openLayer() { + this.render('layer', { + into: 'application', + outlet: 'modal' + }); + }, + close() { + this.disconnectOutlet({ + outlet: 'modal', + parentView: 'application' + }); + } + } + }) + ); - return this.visit('/').then(() => { - let rootElement = document.getElementById('qunit-fixture'); - let router = this.applicationInstance.lookup('router:main'); - assert.equal(rootElement.textContent.trim(), 'hi'); - run(router, 'send', 'openLayer'); - assert.equal(rootElement.textContent.trim(), 'hilayer'); - run(router, 'send', 'openLayer'); - assert.equal(rootElement.textContent.trim(), 'hilayer'); - run(router, 'send', 'close'); - assert.equal(rootElement.textContent.trim(), 'hi'); - }); - } + return this.visit('/').then(() => { + let rootElement = document.getElementById('qunit-fixture'); + let router = this.applicationInstance.lookup('router:main'); + assert.equal(rootElement.textContent.trim(), 'hi'); + run(router, 'send', 'openLayer'); + assert.equal(rootElement.textContent.trim(), 'hilayer'); + run(router, 'send', 'openLayer'); + assert.equal(rootElement.textContent.trim(), 'hilayer'); + run(router, 'send', 'close'); + assert.equal(rootElement.textContent.trim(), 'hi'); + }); + } - ['@test Renders child into parent with non-default template name'](assert) { - this.addTemplate('application', '
    {{outlet}}
    '); - this.addTemplate('exports.root', '
    {{outlet}}
    '); - this.addTemplate('exports.index', '
    '); + ['@test Renders child into parent with non-default template name'](assert) { + this.addTemplate('application', '
    {{outlet}}
    '); + this.addTemplate('exports.root', '
    {{outlet}}
    '); + this.addTemplate('exports.index', '
    '); - this.router.map(function() { - this.route('root', function() { + this.router.map(function() { + this.route('root', function() {}); }); - }); - this.add('route:root', Route.extend({ - renderTemplate() { - this.render('exports/root'); - } - })); + this.add( + 'route:root', + Route.extend({ + renderTemplate() { + this.render('exports/root'); + } + }) + ); - this.add('route:root.index', Route.extend({ - renderTemplate() { - this.render('exports/index'); - } - })); + this.add( + 'route:root.index', + Route.extend({ + renderTemplate() { + this.render('exports/index'); + } + }) + ); - return this.visit('/root').then(() => { - let rootElement = document.getElementById('qunit-fixture'); - assert.equal(rootElement.querySelectorAll('.a .b .c').length, 1); - }); - } + return this.visit('/root').then(() => { + let rootElement = document.getElementById('qunit-fixture'); + assert.equal(rootElement.querySelectorAll('.a .b .c').length, 1); + }); + } - ['@test Allows any route to disconnectOutlet another route\'s templates'](assert) { - this.addTemplate('application', '{{outlet}}{{outlet "modal"}}'); - this.addTemplate('index', 'hi'); - this.addTemplate('layer', 'layer'); - this.router.map(function () { - this.route('index', { path: '/' }); - }); - this.add('route:application', Route.extend({ - actions: { - openLayer() { - this.render('layer', { - into: 'application', - outlet: 'modal' - }); - } - } - })); - this.add('route:index', Route.extend({ - actions: { - close() { - this.disconnectOutlet({ - parentView: 'application', - outlet: 'modal' - }); - } - } - })); + ["@test Allows any route to disconnectOutlet another route's templates"]( + assert + ) { + this.addTemplate('application', '{{outlet}}{{outlet "modal"}}'); + this.addTemplate('index', 'hi'); + this.addTemplate('layer', 'layer'); + this.router.map(function() { + this.route('index', { path: '/' }); + }); + this.add( + 'route:application', + Route.extend({ + actions: { + openLayer() { + this.render('layer', { + into: 'application', + outlet: 'modal' + }); + } + } + }) + ); + this.add( + 'route:index', + Route.extend({ + actions: { + close() { + this.disconnectOutlet({ + parentView: 'application', + outlet: 'modal' + }); + } + } + }) + ); - return this.visit('/').then(() => { - let rootElement = document.getElementById('qunit-fixture'); - let router = this.applicationInstance.lookup('router:main'); - assert.equal(rootElement.textContent.trim(), 'hi'); - run(router, 'send', 'openLayer'); - assert.equal(rootElement.textContent.trim(), 'hilayer'); - run(router, 'send', 'close'); - assert.equal(rootElement.textContent.trim(), 'hi'); - }); - } + return this.visit('/').then(() => { + let rootElement = document.getElementById('qunit-fixture'); + let router = this.applicationInstance.lookup('router:main'); + assert.equal(rootElement.textContent.trim(), 'hi'); + run(router, 'send', 'openLayer'); + assert.equal(rootElement.textContent.trim(), 'hilayer'); + run(router, 'send', 'close'); + assert.equal(rootElement.textContent.trim(), 'hi'); + }); + } - ['@test Can this.render({into:...}) the render helper'](assert) { - expectDeprecation(/Rendering into a {{render}} helper that resolves to an {{outlet}} is deprecated./); - - expectDeprecation(() => { - this.addTemplate('application', '{{render "sidebar"}}'); - }, /Please refactor [\w\{\}"` ]+ to a component/); - this.router.map(function () { - this.route('index', { path: '/' }); - }); - this.addTemplate('sidebar', ''); - this.addTemplate('index', 'other'); - this.addTemplate('bar', 'bar'); - - this.add('route:index', Route.extend({ - renderTemplate() { - this.render({ into: 'sidebar' }); - }, - actions: { - changeToBar() { - this.disconnectOutlet({ - parentView: 'sidebar', - outlet: 'main' - }); - this.render('bar', { into: 'sidebar' }); - } - } - })); + ['@test Can this.render({into:...}) the render helper'](assert) { + expectDeprecation( + /Rendering into a {{render}} helper that resolves to an {{outlet}} is deprecated./ + ); - return this.visit('/').then(() => { - let rootElement = document.getElementById('qunit-fixture'); - let router = this.applicationInstance.lookup('router:main'); - assert.equal(getTextOf(rootElement.querySelector('.sidebar')), 'other'); - run(router, 'send', 'changeToBar'); - assert.equal(getTextOf(rootElement.querySelector('.sidebar')), 'bar'); - }); - } + expectDeprecation(() => { + this.addTemplate('application', '{{render "sidebar"}}'); + }, /Please refactor [\w\{\}"` ]+ to a component/); + this.router.map(function() { + this.route('index', { path: '/' }); + }); + this.addTemplate('sidebar', ''); + this.addTemplate('index', 'other'); + this.addTemplate('bar', 'bar'); + + this.add( + 'route:index', + Route.extend({ + renderTemplate() { + this.render({ into: 'sidebar' }); + }, + actions: { + changeToBar() { + this.disconnectOutlet({ + parentView: 'sidebar', + outlet: 'main' + }); + this.render('bar', { into: 'sidebar' }); + } + } + }) + ); - ['@test Can disconnect from the render helper'](assert) { - expectDeprecation(/Rendering into a {{render}} helper that resolves to an {{outlet}} is deprecated./); - - expectDeprecation(() => { - this.addTemplate('application', '{{render "sidebar"}}'); - }, /Please refactor [\w\{\}"` ]+ to a component/); - this.router.map(function () { - this.route('index', { path: '/' }); - }); - this.addTemplate('sidebar', ''); - this.addTemplate('index', 'other'); - - this.add('route:index', Route.extend({ - renderTemplate() { - this.render({ into: 'sidebar' }); - }, - actions: { - disconnect: function() { - this.disconnectOutlet({ - parentView: 'sidebar', - outlet: 'main' - }); - } - } - })); + return this.visit('/').then(() => { + let rootElement = document.getElementById('qunit-fixture'); + let router = this.applicationInstance.lookup('router:main'); + assert.equal(getTextOf(rootElement.querySelector('.sidebar')), 'other'); + run(router, 'send', 'changeToBar'); + assert.equal(getTextOf(rootElement.querySelector('.sidebar')), 'bar'); + }); + } - return this.visit('/').then(() => { - let rootElement = document.getElementById('qunit-fixture'); - let router = this.applicationInstance.lookup('router:main'); - assert.equal(getTextOf(rootElement.querySelector('.sidebar')), 'other'); - run(router, 'send', 'disconnect'); - assert.equal(getTextOf(rootElement.querySelector('.sidebar')), ''); - }); - } + ['@test Can disconnect from the render helper'](assert) { + expectDeprecation( + /Rendering into a {{render}} helper that resolves to an {{outlet}} is deprecated./ + ); - ["@test Can this.render({into:...}) the render helper's children"](assert) { - expectDeprecation(/Rendering into a {{render}} helper that resolves to an {{outlet}} is deprecated./); - - expectDeprecation(() => { - this.addTemplate('application', '{{render "sidebar"}}'); - }, /Please refactor [\w\{\}"` ]+ to a component/); - - this.addTemplate('sidebar', ''); - this.addTemplate('index', '
    {{outlet}}
    '); - this.addTemplate('other', 'other'); - this.addTemplate('bar', 'bar'); - this.router.map(function() { - this.route('index', { path: '/' }); - }); - this.add('route:index', Route.extend({ - renderTemplate() { - this.render({ into: 'sidebar' }); - this.render('other', { into: 'index' }); - }, - actions: { - changeToBar() { - this.disconnectOutlet({ - parentView: 'index', - outlet: 'main' - }); - this.render('bar', { into: 'index' }); - } - } - })); + expectDeprecation(() => { + this.addTemplate('application', '{{render "sidebar"}}'); + }, /Please refactor [\w\{\}"` ]+ to a component/); + this.router.map(function() { + this.route('index', { path: '/' }); + }); + this.addTemplate('sidebar', ''); + this.addTemplate('index', 'other'); + + this.add( + 'route:index', + Route.extend({ + renderTemplate() { + this.render({ into: 'sidebar' }); + }, + actions: { + disconnect: function() { + this.disconnectOutlet({ + parentView: 'sidebar', + outlet: 'main' + }); + } + } + }) + ); - return this.visit('/').then(() => { - let rootElement = document.getElementById('qunit-fixture'); - let router = this.applicationInstance.lookup('router:main'); - assert.equal(getTextOf(rootElement.querySelector('.sidebar .index')), 'other'); - run(router, 'send', 'changeToBar'); - assert.equal(getTextOf(rootElement.querySelector('.sidebar .index')), 'bar'); - }); - } + return this.visit('/').then(() => { + let rootElement = document.getElementById('qunit-fixture'); + let router = this.applicationInstance.lookup('router:main'); + assert.equal(getTextOf(rootElement.querySelector('.sidebar')), 'other'); + run(router, 'send', 'disconnect'); + assert.equal(getTextOf(rootElement.querySelector('.sidebar')), ''); + }); + } - ['@test Can disconnect from the render helper\'s children'](assert) { - expectDeprecation(/Rendering into a {{render}} helper that resolves to an {{outlet}} is deprecated./); - - expectDeprecation(() => { - this.addTemplate('application', '{{render "sidebar"}}'); - }, /Please refactor [\w\{\}"` ]+ to a component/); - this.router.map(function () { - this.route('index', { path: '/' }); - }); - this.addTemplate('sidebar', ''); - this.addTemplate('index', '
    {{outlet}}
    '); - this.addTemplate('other', 'other'); - - this.add('route:index', Route.extend({ - renderTemplate() { - this.render({ into: 'sidebar' }); - this.render('other', { into: 'index' }); - }, - actions: { - disconnect() { - this.disconnectOutlet({ - parentView: 'index', - outlet: 'main' - }); - } - } - })); + ["@test Can this.render({into:...}) the render helper's children"](assert) { + expectDeprecation( + /Rendering into a {{render}} helper that resolves to an {{outlet}} is deprecated./ + ); - return this.visit('/').then(() => { - let rootElement = document.getElementById('qunit-fixture'); - let router = this.applicationInstance.lookup('router:main'); - assert.equal(getTextOf(rootElement.querySelector('.sidebar .index')), 'other'); - run(router, 'send', 'disconnect'); - assert.equal(getTextOf(rootElement.querySelector('.sidebar .index')), ''); - }); - } + expectDeprecation(() => { + this.addTemplate('application', '{{render "sidebar"}}'); + }, /Please refactor [\w\{\}"` ]+ to a component/); - ['@test Can this.render({into:...}) nested render helpers'](assert) { - expectDeprecation(/Rendering into a {{render}} helper that resolves to an {{outlet}} is deprecated./); - - expectDeprecation(() => { - this.addTemplate('application', '{{render "sidebar"}}'); - }, /Please refactor [\w\{\}"` ]+ to a component/); - - expectDeprecation(() => { - this.addTemplate('sidebar', ''); - }, /Please refactor [\w\{\}"` ]+ to a component/); - this.router.map(function () { - this.route('index', { path: '/' }); - }); - this.addTemplate('cart', '
    {{outlet}}
    '); - this.addTemplate('index', 'other'); - this.addTemplate('baz', 'baz'); - - this.add('route:index', Route.extend({ - renderTemplate() { - this.render({ into: 'cart' }); - }, - actions: { - changeToBaz() { - this.disconnectOutlet({ - parentView: 'cart', - outlet: 'main' - }); - this.render('baz', { into: 'cart' }); - } - } - })); + this.addTemplate('sidebar', ''); + this.addTemplate('index', '
    {{outlet}}
    '); + this.addTemplate('other', 'other'); + this.addTemplate('bar', 'bar'); + this.router.map(function() { + this.route('index', { path: '/' }); + }); + this.add( + 'route:index', + Route.extend({ + renderTemplate() { + this.render({ into: 'sidebar' }); + this.render('other', { into: 'index' }); + }, + actions: { + changeToBar() { + this.disconnectOutlet({ + parentView: 'index', + outlet: 'main' + }); + this.render('bar', { into: 'index' }); + } + } + }) + ); - return this.visit('/').then(() => { - let rootElement = document.getElementById('qunit-fixture'); - let router = this.applicationInstance.lookup('router:main'); - assert.equal(getTextOf(rootElement.querySelector('.cart')), 'other'); - run(router, 'send', 'changeToBaz'); - assert.equal(getTextOf(rootElement.querySelector('.cart')), 'baz'); - }); - } + return this.visit('/').then(() => { + let rootElement = document.getElementById('qunit-fixture'); + let router = this.applicationInstance.lookup('router:main'); + assert.equal( + getTextOf(rootElement.querySelector('.sidebar .index')), + 'other' + ); + run(router, 'send', 'changeToBar'); + assert.equal( + getTextOf(rootElement.querySelector('.sidebar .index')), + 'bar' + ); + }); + } - ['@test Can disconnect from nested render helpers'](assert) { - expectDeprecation(/Rendering into a {{render}} helper that resolves to an {{outlet}} is deprecated./); - - expectDeprecation(() => { - this.addTemplate('application', '{{render "sidebar"}}'); - }, /Please refactor [\w\{\}"` ]+ to a component/); - - expectDeprecation(() => { - this.addTemplate('sidebar', ''); - }, /Please refactor [\w\{\}"` ]+ to a component/); - this.router.map(function () { - this.route('index', { path: '/' }); - }); - this.addTemplate('cart', '
    {{outlet}}
    '); - this.addTemplate('index', 'other'); - - this.add('route:index', Route.extend({ - renderTemplate() { - this.render({ into: 'cart' }); - }, - actions: { - disconnect() { - this.disconnectOutlet({ - parentView: 'cart', - outlet: 'main' - }); - } - } - })); + ["@test Can disconnect from the render helper's children"](assert) { + expectDeprecation( + /Rendering into a {{render}} helper that resolves to an {{outlet}} is deprecated./ + ); - return this.visit('/').then(() => { - let rootElement = document.getElementById('qunit-fixture'); - let router = this.applicationInstance.lookup('router:main'); - assert.equal(getTextOf(rootElement.querySelector('.cart')), 'other'); - run(router, 'send', 'disconnect'); - assert.equal(getTextOf(rootElement.querySelector('.cart')), ''); - }); - } + expectDeprecation(() => { + this.addTemplate('application', '{{render "sidebar"}}'); + }, /Please refactor [\w\{\}"` ]+ to a component/); + this.router.map(function() { + this.route('index', { path: '/' }); + }); + this.addTemplate('sidebar', ''); + this.addTemplate('index', '
    {{outlet}}
    '); + this.addTemplate('other', 'other'); + + this.add( + 'route:index', + Route.extend({ + renderTemplate() { + this.render({ into: 'sidebar' }); + this.render('other', { into: 'index' }); + }, + actions: { + disconnect() { + this.disconnectOutlet({ + parentView: 'index', + outlet: 'main' + }); + } + } + }) + ); - ['@test Components inside an outlet have their didInsertElement hook invoked when the route is displayed'](assert) { - this.addTemplate('index', '{{#if showFirst}}{{my-component}}{{else}}{{other-component}}{{/if}}'); + return this.visit('/').then(() => { + let rootElement = document.getElementById('qunit-fixture'); + let router = this.applicationInstance.lookup('router:main'); + assert.equal( + getTextOf(rootElement.querySelector('.sidebar .index')), + 'other' + ); + run(router, 'send', 'disconnect'); + assert.equal( + getTextOf(rootElement.querySelector('.sidebar .index')), + '' + ); + }); + } - let myComponentCounter = 0; - let otherComponentCounter = 0; - let indexController; + ['@test Can this.render({into:...}) nested render helpers'](assert) { + expectDeprecation( + /Rendering into a {{render}} helper that resolves to an {{outlet}} is deprecated./ + ); - this.router.map(function() { - this.route('index', { path: '/' }); - }); + expectDeprecation(() => { + this.addTemplate('application', '{{render "sidebar"}}'); + }, /Please refactor [\w\{\}"` ]+ to a component/); + + expectDeprecation(() => { + this.addTemplate( + 'sidebar', + '' + ); + }, /Please refactor [\w\{\}"` ]+ to a component/); + this.router.map(function() { + this.route('index', { path: '/' }); + }); + this.addTemplate('cart', '
    {{outlet}}
    '); + this.addTemplate('index', 'other'); + this.addTemplate('baz', 'baz'); + + this.add( + 'route:index', + Route.extend({ + renderTemplate() { + this.render({ into: 'cart' }); + }, + actions: { + changeToBaz() { + this.disconnectOutlet({ + parentView: 'cart', + outlet: 'main' + }); + this.render('baz', { into: 'cart' }); + } + } + }) + ); - this.add('controller:index', Controller.extend({ - showFirst: true - })); + return this.visit('/').then(() => { + let rootElement = document.getElementById('qunit-fixture'); + let router = this.applicationInstance.lookup('router:main'); + assert.equal(getTextOf(rootElement.querySelector('.cart')), 'other'); + run(router, 'send', 'changeToBaz'); + assert.equal(getTextOf(rootElement.querySelector('.cart')), 'baz'); + }); + } - this.add('route:index', Route.extend({ - setupController(controller) { - indexController = controller; - } - })); + ['@test Can disconnect from nested render helpers'](assert) { + expectDeprecation( + /Rendering into a {{render}} helper that resolves to an {{outlet}} is deprecated./ + ); - this.add('component:my-component', Component.extend({ - didInsertElement() { - myComponentCounter++; - } - })); + expectDeprecation(() => { + this.addTemplate('application', '{{render "sidebar"}}'); + }, /Please refactor [\w\{\}"` ]+ to a component/); + + expectDeprecation(() => { + this.addTemplate( + 'sidebar', + '' + ); + }, /Please refactor [\w\{\}"` ]+ to a component/); + this.router.map(function() { + this.route('index', { path: '/' }); + }); + this.addTemplate('cart', '
    {{outlet}}
    '); + this.addTemplate('index', 'other'); + + this.add( + 'route:index', + Route.extend({ + renderTemplate() { + this.render({ into: 'cart' }); + }, + actions: { + disconnect() { + this.disconnectOutlet({ + parentView: 'cart', + outlet: 'main' + }); + } + } + }) + ); - this.add('component:other-component', Component.extend({ - didInsertElement() { - otherComponentCounter++; - } - })); + return this.visit('/').then(() => { + let rootElement = document.getElementById('qunit-fixture'); + let router = this.applicationInstance.lookup('router:main'); + assert.equal(getTextOf(rootElement.querySelector('.cart')), 'other'); + run(router, 'send', 'disconnect'); + assert.equal(getTextOf(rootElement.querySelector('.cart')), ''); + }); + } - return this.visit('/').then(() => { - assert.strictEqual(myComponentCounter, 1, 'didInsertElement invoked on displayed component'); - assert.strictEqual(otherComponentCounter, 0, 'didInsertElement not invoked on displayed component'); + ['@test Components inside an outlet have their didInsertElement hook invoked when the route is displayed']( + assert + ) { + this.addTemplate( + 'index', + '{{#if showFirst}}{{my-component}}{{else}}{{other-component}}{{/if}}' + ); - run(() => indexController.set('showFirst', false)); + let myComponentCounter = 0; + let otherComponentCounter = 0; + let indexController; - assert.strictEqual(myComponentCounter, 1, 'didInsertElement not invoked on displayed component'); - assert.strictEqual(otherComponentCounter, 1, 'didInsertElement invoked on displayed component'); - }); - } + this.router.map(function() { + this.route('index', { path: '/' }); + }); + + this.add( + 'controller:index', + Controller.extend({ + showFirst: true + }) + ); + + this.add( + 'route:index', + Route.extend({ + setupController(controller) { + indexController = controller; + } + }) + ); + + this.add( + 'component:my-component', + Component.extend({ + didInsertElement() { + myComponentCounter++; + } + }) + ); + + this.add( + 'component:other-component', + Component.extend({ + didInsertElement() { + otherComponentCounter++; + } + }) + ); - ['@test Doesnt swallow exception thrown from willTransition'](assert) { - assert.expect(1); - this.addTemplate('application', '{{outlet}}'); - this.addTemplate('index', 'index'); - this.addTemplate('other', 'other'); + return this.visit('/').then(() => { + assert.strictEqual( + myComponentCounter, + 1, + 'didInsertElement invoked on displayed component' + ); + assert.strictEqual( + otherComponentCounter, + 0, + 'didInsertElement not invoked on displayed component' + ); + + run(() => indexController.set('showFirst', false)); + + assert.strictEqual( + myComponentCounter, + 1, + 'didInsertElement not invoked on displayed component' + ); + assert.strictEqual( + otherComponentCounter, + 1, + 'didInsertElement invoked on displayed component' + ); + }); + } - this.router.map(function() { - this.route('index', { path: '/' }); - this.route('other', function() { + ['@test Doesnt swallow exception thrown from willTransition'](assert) { + assert.expect(1); + this.addTemplate('application', '{{outlet}}'); + this.addTemplate('index', 'index'); + this.addTemplate('other', 'other'); + + this.router.map(function() { + this.route('index', { path: '/' }); + this.route('other', function() {}); }); - }); - this.add('route:index', Route.extend({ - actions: { - willTransition() { - throw new Error('boom'); - } - } - })); + this.add( + 'route:index', + Route.extend({ + actions: { + willTransition() { + throw new Error('boom'); + } + } + }) + ); - return this.visit('/').then(() => { - return assert.throws(() => { - return this.visit('/other'); - }, /boom/, 'expected an exception but none was thrown'); - }); - } + return this.visit('/').then(() => { + return assert.throws( + () => { + return this.visit('/other'); + }, + /boom/, + 'expected an exception but none was thrown' + ); + }); + } - ['@test Exception if outlet name is undefined in render and disconnectOutlet']() { - this.add('route:application', Route.extend({ - actions: { - showModal() { - this.render({ - outlet: undefined, - parentView: 'application' - }); - }, - hideModal() { - this.disconnectOutlet({ - outlet: undefined, - parentView: 'application' - }); - } - } - })); + ['@test Exception if outlet name is undefined in render and disconnectOutlet']() { + this.add( + 'route:application', + Route.extend({ + actions: { + showModal() { + this.render({ + outlet: undefined, + parentView: 'application' + }); + }, + hideModal() { + this.disconnectOutlet({ + outlet: undefined, + parentView: 'application' + }); + } + } + }) + ); - return this.visit('/').then(() => { - let router = this.applicationInstance.lookup('router:main'); - expectAssertion(() => { - run(() => router.send('showModal')); - }, /You passed undefined as the outlet name/); + return this.visit('/').then(() => { + let router = this.applicationInstance.lookup('router:main'); + expectAssertion(() => { + run(() => router.send('showModal')); + }, /You passed undefined as the outlet name/); - expectAssertion(() => { - run(() => router.send('hideModal')); - }, /You passed undefined as the outlet name/); - }); - } + expectAssertion(() => { + run(() => router.send('hideModal')); + }, /You passed undefined as the outlet name/); + }); + } - ['@test Route serializers work for Engines'](assert) { - assert.expect(2); + ['@test Route serializers work for Engines'](assert) { + assert.expect(2); - // Register engine - let BlogEngine = Engine.extend(); - this.add('engine:blog', BlogEngine); + // Register engine + let BlogEngine = Engine.extend(); + this.add('engine:blog', BlogEngine); - // Register engine route map - let postSerialize = function(params) { - assert.ok(true, 'serialize hook runs'); - return { - post_id: params.id + // Register engine route map + let postSerialize = function(params) { + assert.ok(true, 'serialize hook runs'); + return { + post_id: params.id + }; }; - }; - let BlogMap = function() { - this.route('post', { path: '/post/:post_id', serialize: postSerialize }); - }; - this.add('route-map:blog', BlogMap); - - this.router.map(function() { - this.mount('blog'); - }); - - return this.visit('/').then(() => { - let router = this.applicationInstance.lookup('router:main'); - assert.equal(router._routerMicrolib.generate('blog.post', { id: '13' }), '/blog/post/13', 'url is generated properly'); - }); - } + let BlogMap = function() { + this.route('post', { + path: '/post/:post_id', + serialize: postSerialize + }); + }; + this.add('route-map:blog', BlogMap); - ['@test Defining a Route#serialize method in an Engine throws an error'](assert) { - assert.expect(1); + this.router.map(function() { + this.mount('blog'); + }); - // Register engine - let BlogEngine = Engine.extend(); - this.add('engine:blog', BlogEngine); + return this.visit('/').then(() => { + let router = this.applicationInstance.lookup('router:main'); + assert.equal( + router._routerMicrolib.generate('blog.post', { id: '13' }), + '/blog/post/13', + 'url is generated properly' + ); + }); + } - // Register engine route map - let BlogMap = function() { - this.route('post'); - }; - this.add('route-map:blog', BlogMap); + ['@test Defining a Route#serialize method in an Engine throws an error']( + assert + ) { + assert.expect(1); - this.router.map(function() { - this.mount('blog'); - }); + // Register engine + let BlogEngine = Engine.extend(); + this.add('engine:blog', BlogEngine); - return this.visit('/').then(() => { - let router = this.applicationInstance.lookup('router:main'); - let PostRoute = Route.extend({ serialize() {} }); - this.applicationInstance.lookup('engine:blog').register('route:post', PostRoute); + // Register engine route map + let BlogMap = function() { + this.route('post'); + }; + this.add('route-map:blog', BlogMap); - assert.throws(() => router.transitionTo('blog.post'), /Defining a custom serialize method on an Engine route is not supported/); - }); - } + this.router.map(function() { + this.mount('blog'); + }); - ['@test App.destroy does not leave undestroyed views after clearing engines'](assert) { - assert.expect(4); - - let engineInstance; - // Register engine - let BlogEngine = Engine.extend(); - this.add('engine:blog', BlogEngine); - let EngineIndexRoute = Route.extend({ - init() { - this._super(...arguments); - engineInstance = getOwner(this); - } - }); - - // Register engine route map - let BlogMap = function() { - this.route('post'); - }; - this.add('route-map:blog', BlogMap); - - this.router.map(function() { - this.mount('blog'); - }); - - return this.visit('/').then(() => { - let engine = this.applicationInstance.lookup('engine:blog'); - engine.register('route:index', EngineIndexRoute); - engine.register('template:index', compile('Engine Post!')); - return this.visit('/blog'); - }).then(() => { - assert.ok(true, '/blog has been handled'); - let route = engineInstance.lookup('route:index'); - let router = this.applicationInstance.lookup('router:main'); - - run(router, 'destroy'); - assert.equal(router._toplevelView, null, 'the toplevelView was cleared'); - - run(route, 'destroy'); - assert.equal(router._toplevelView, null, 'the toplevelView was not reinitialized'); - - run(this.applicationInstance, 'destroy'); - assert.equal(router._toplevelView, null, 'the toplevelView was not reinitialized'); - }); - } + return this.visit('/').then(() => { + let router = this.applicationInstance.lookup('router:main'); + let PostRoute = Route.extend({ serialize() {} }); + this.applicationInstance + .lookup('engine:blog') + .register('route:post', PostRoute); + + assert.throws( + () => router.transitionTo('blog.post'), + /Defining a custom serialize method on an Engine route is not supported/ + ); + }); + } - ['@test Generated route should be an instance of App\'s default route if provided'](assert) { - let generatedRoute; + ['@test App.destroy does not leave undestroyed views after clearing engines']( + assert + ) { + assert.expect(4); + + let engineInstance; + // Register engine + let BlogEngine = Engine.extend(); + this.add('engine:blog', BlogEngine); + let EngineIndexRoute = Route.extend({ + init() { + this._super(...arguments); + engineInstance = getOwner(this); + } + }); + + // Register engine route map + let BlogMap = function() { + this.route('post'); + }; + this.add('route-map:blog', BlogMap); + + this.router.map(function() { + this.mount('blog'); + }); + + return this.visit('/') + .then(() => { + let engine = this.applicationInstance.lookup('engine:blog'); + engine.register('route:index', EngineIndexRoute); + engine.register('template:index', compile('Engine Post!')); + return this.visit('/blog'); + }) + .then(() => { + assert.ok(true, '/blog has been handled'); + let route = engineInstance.lookup('route:index'); + let router = this.applicationInstance.lookup('router:main'); + + run(router, 'destroy'); + assert.equal( + router._toplevelView, + null, + 'the toplevelView was cleared' + ); + + run(route, 'destroy'); + assert.equal( + router._toplevelView, + null, + 'the toplevelView was not reinitialized' + ); + + run(this.applicationInstance, 'destroy'); + assert.equal( + router._toplevelView, + null, + 'the toplevelView was not reinitialized' + ); + }); + } + + ["@test Generated route should be an instance of App's default route if provided"]( + assert + ) { + let generatedRoute; - this.router.map(function () { - this.route('posts'); - }); + this.router.map(function() { + this.route('posts'); + }); - let AppRoute = Route.extend(); - this.add('route:basic', AppRoute); + let AppRoute = Route.extend(); + this.add('route:basic', AppRoute); - return this.visit('/posts').then(() => { - generatedRoute = this.applicationInstance.lookup('route:posts'); + return this.visit('/posts').then(() => { + generatedRoute = this.applicationInstance.lookup('route:posts'); - assert.ok(generatedRoute instanceof AppRoute, 'should extend the correct route'); - }); + assert.ok( + generatedRoute instanceof AppRoute, + 'should extend the correct route' + ); + }); + } } -}); +); diff --git a/packages/ember/tests/routing/query_params_test.js b/packages/ember/tests/routing/query_params_test.js index c226ddf21ef..02bfb41ee0a 100644 --- a/packages/ember/tests/routing/query_params_test.js +++ b/packages/ember/tests/routing/query_params_test.js @@ -5,1342 +5,1694 @@ import { A as emberA, String as StringUtils } from 'ember-runtime'; -import { - run, - get, - computed, - peekMeta -} from 'ember-metal'; +import { run, get, computed, peekMeta } from 'ember-metal'; import { Route } from 'ember-routing'; -import { QueryParamTestCase, moduleFor, getTextOf } from 'internal-test-helpers'; - -moduleFor('Query Params - main', class extends QueryParamTestCase { - refreshModelWhileLoadingTest(loadingReturn) { - let assert = this.assert; - - assert.expect(9); - - let appModelCount = 0; - let promiseResolve; - - this.add('route:application', Route.extend({ - queryParams: { - appomg: { - defaultValue: 'applol' - } - }, - model(/* params */) { - appModelCount++; - } - })); - - this.setSingleQPController('index', 'omg', undefined, { - omg: undefined - }); - - let actionName = typeof loadingReturn !== 'undefined' ? 'loading' : 'ignore'; - let indexModelCount = 0; - this.add('route:index', Route.extend({ - queryParams: { - omg: { - refreshModel: true - } - }, - actions: { - [actionName]: function() { - return loadingReturn; - } - }, - model(params) { - indexModelCount++; - if (indexModelCount === 2) { - assert.deepEqual(params, { omg: 'lex' }); - return new RSVP.Promise(function(resolve) { - promiseResolve = resolve; - return; - }); - } else if (indexModelCount === 3) { - assert.deepEqual(params, { omg: 'hello' }, 'Model hook reruns even if the previous one didn\'t finish'); - } - } - })); - - return this.visit('/').then(() => { - assert.equal(appModelCount, 1, 'appModelCount is 1'); - assert.equal(indexModelCount, 1); - - let indexController = this.getController('index'); - this.setAndFlush(indexController, 'omg', 'lex'); - - assert.equal(appModelCount, 1, 'appModelCount is 1'); - assert.equal(indexModelCount, 2); - - this.setAndFlush(indexController, 'omg', 'hello'); - assert.equal(appModelCount, 1, 'appModelCount is 1'); - assert.equal(indexModelCount, 3); - - run(function() { - promiseResolve(); +import { + QueryParamTestCase, + moduleFor, + getTextOf +} from 'internal-test-helpers'; + +moduleFor( + 'Query Params - main', + class extends QueryParamTestCase { + refreshModelWhileLoadingTest(loadingReturn) { + let assert = this.assert; + + assert.expect(9); + + let appModelCount = 0; + let promiseResolve; + + this.add( + 'route:application', + Route.extend({ + queryParams: { + appomg: { + defaultValue: 'applol' + } + }, + model(/* params */) { + appModelCount++; + } + }) + ); + + this.setSingleQPController('index', 'omg', undefined, { + omg: undefined }); - assert.equal(get(indexController, 'omg'), 'hello', 'At the end last value prevails'); - }); - } - - ['@test No replaceURL occurs on startup because default values don\'t show up in URL'](assert) { - assert.expect(1); - - this.setSingleQPController('index'); - - return this.visitAndAssert('/'); - } - - ['@test Calling transitionTo does not lose query params already on the activeTransition'](assert) { - assert.expect(2); - - this.router.map(function() { - this.route('parent', function() { - this.route('child'); - this.route('sibling'); + let actionName = + typeof loadingReturn !== 'undefined' ? 'loading' : 'ignore'; + let indexModelCount = 0; + this.add( + 'route:index', + Route.extend({ + queryParams: { + omg: { + refreshModel: true + } + }, + actions: { + [actionName]: function() { + return loadingReturn; + } + }, + model(params) { + indexModelCount++; + if (indexModelCount === 2) { + assert.deepEqual(params, { omg: 'lex' }); + return new RSVP.Promise(function(resolve) { + promiseResolve = resolve; + return; + }); + } else if (indexModelCount === 3) { + assert.deepEqual( + params, + { omg: 'hello' }, + "Model hook reruns even if the previous one didn't finish" + ); + } + } + }) + ); + + return this.visit('/').then(() => { + assert.equal(appModelCount, 1, 'appModelCount is 1'); + assert.equal(indexModelCount, 1); + + let indexController = this.getController('index'); + this.setAndFlush(indexController, 'omg', 'lex'); + + assert.equal(appModelCount, 1, 'appModelCount is 1'); + assert.equal(indexModelCount, 2); + + this.setAndFlush(indexController, 'omg', 'hello'); + assert.equal(appModelCount, 1, 'appModelCount is 1'); + assert.equal(indexModelCount, 3); + + run(function() { + promiseResolve(); + }); + + assert.equal( + get(indexController, 'omg'), + 'hello', + 'At the end last value prevails' + ); }); - }); - - this.add('route:parent.child', Route.extend({ - afterModel() { - this.transitionTo('parent.sibling'); - } - })); - - this.setSingleQPController('parent'); - - return this.visit('/parent/child?foo=lol').then(() => { - this.assertCurrentPath('/parent/sibling?foo=lol', 'redirected to the sibling route, instead of child route'); - assert.equal(this.getController('parent').get('foo'), 'lol', 'controller has value from the active transition'); - }); - } - - ['@test Single query params can be set on the controller and reflected in the url'](assert) { - assert.expect(3); - - this.router.map(function() { - this.route('home', { path: '/' }); - }); - - this.setSingleQPController('home'); - - return this.visitAndAssert('/').then(() => { - let controller = this.getController('home'); - - this.setAndFlush(controller, 'foo', '456'); - this.assertCurrentPath('/?foo=456'); - - this.setAndFlush(controller, 'foo', '987'); - this.assertCurrentPath('/?foo=987'); - }); - } - - ['@test Query params can map to different url keys configured on the controller'](assert) { - assert.expect(6); - - this.add('controller:index', Controller.extend({ - queryParams: [{ foo: 'other_foo', bar: { as: 'other_bar' } }], - foo: 'FOO', - bar: 'BAR' - })); - - return this.visitAndAssert('/').then(() => { - let controller = this.getController('index'); - - this.setAndFlush(controller, 'foo', 'LEX'); - this.assertCurrentPath('/?other_foo=LEX', 'QP mapped correctly without \'as\''); - - this.setAndFlush(controller, 'foo', 'WOO'); - this.assertCurrentPath('/?other_foo=WOO', 'QP updated correctly without \'as\''); - - this.transitionTo('/?other_foo=NAW'); - assert.equal(controller.get('foo'), 'NAW', 'QP managed correctly on URL transition'); - - this.setAndFlush(controller, 'bar', 'NERK'); - this.assertCurrentPath('/?other_bar=NERK&other_foo=NAW', 'QP mapped correctly with \'as\''); - - this.setAndFlush(controller, 'bar', 'NUKE'); - this.assertCurrentPath('/?other_bar=NUKE&other_foo=NAW', 'QP updated correctly with \'as\''); - }); - } - - ['@test Routes have a private overridable serializeQueryParamKey hook'](assert) { - assert.expect(2); - - this.add('route:index', Route.extend({ - serializeQueryParamKey: StringUtils.dasherize - })); - - this.setSingleQPController('index', 'funTimes', ''); - - return this.visitAndAssert('/').then(() => { - let controller = this.getController('index'); - - this.setAndFlush(controller, 'funTimes', 'woot'); - this.assertCurrentPath('/?fun-times=woot'); - }); - } - - ['@test Can override inherited QP behavior by specifying queryParams as a computed property'](assert) { - assert.expect(3); - - this.setSingleQPController('index', 'a', 0, { - queryParams: computed(function() { - return ['c']; - }), - c: true - }); - - return this.visitAndAssert('/').then(() => { - let indexController = this.getController('index'); - - this.setAndFlush(indexController, 'a', 1); - this.assertCurrentPath('/', 'QP did not update due to being overriden'); - - this.setAndFlush(indexController, 'c', false); - this.assertCurrentPath('/?c=false', 'QP updated with overridden param'); - }); - } - - ['@test Can concatenate inherited QP behavior by specifying queryParams as an array'](assert) { - assert.expect(3); - - this.setSingleQPController('index', 'a', 0, { - queryParams: ['c'], - c: true - }); - - return this.visitAndAssert('/').then(() => { - let indexController = this.getController('index'); - - this.setAndFlush(indexController, 'a', 1); - this.assertCurrentPath('/?a=1', 'Inherited QP did update'); - - this.setAndFlush(indexController, 'c', false); - this.assertCurrentPath('/?a=1&c=false', 'New QP did update'); - }); - } - - ['@test model hooks receives query params'](assert) { - assert.expect(2); - - this.setSingleQPController('index'); - - this.add('route:index', Route.extend({ - model(params) { - assert.deepEqual(params, { foo: 'bar' }); - } - })); - - return this.visitAndAssert('/'); - } - - ['@test model hooks receives query params with dynamic segment params'](assert) { - assert.expect(2); - - this.router.map(function() { - this.route('index', { path: '/:id' }); - }); - - this.setSingleQPController('index'); - - this.add('route:index', Route.extend({ - model(params) { - assert.deepEqual(params, { foo: 'bar', id: 'baz' }); - } - })); - - return this.visitAndAssert('/baz'); - } - - ['@test model hooks receives query params (overridden by incoming url value)'](assert) { - assert.expect(2); - - this.router.map(function() { - this.route('index', { path: '/:id' }); - }); - - this.setSingleQPController('index'); - - this.add('route:index', Route.extend({ - model(params) { - assert.deepEqual(params, { foo: 'baz', id: 'boo' }); - } - })); - - return this.visitAndAssert('/boo?foo=baz'); - } - - ['@test error is thrown if dynamic segment and query param have same name'](assert) { - assert.expect(1); - - this.router.map(function() { - this.route('index', { path: '/:foo' }); - }); - - this.setSingleQPController('index'); - - expectAssertion(() => { - this.visitAndAssert('/boo?foo=baz'); - }, `The route 'index' has both a dynamic segment and query param with name 'foo'. Please rename one to avoid collisions.`); - } - - ['@test query params have been set by the time setupController is called'](assert) { - assert.expect(2); - - this.setSingleQPController('application'); - - this.add('route:application', Route.extend({ - setupController(controller) { - assert.equal(controller.get('foo'), 'YEAH', 'controller\'s foo QP property set before setupController called'); - } - })); - - return this.visitAndAssert('/?foo=YEAH'); - } - - ['@test mapped query params have been set by the time setupController is called'](assert) { - assert.expect(2); - - this.setSingleQPController('application', { faz: 'foo' }); - - this.add('route:application', Route.extend({ - setupController(controller) { - assert.equal(controller.get('faz'), 'YEAH', 'controller\'s foo QP property set before setupController called'); - } - })); - - return this.visitAndAssert('/?foo=YEAH'); - } - - ['@test Route#paramsFor fetches query params with default value'](assert) { - assert.expect(2); - - this.router.map(function() { - this.route('index', { path: '/:something' }); - }); - - this.setSingleQPController('index'); - - this.add('route:index', Route.extend({ - model(/* params, transition */) { - assert.deepEqual(this.paramsFor('index'), { something: 'baz', foo: 'bar' }, 'could retrieve params for index'); - } - })); - - return this.visitAndAssert('/baz'); - } - - ['@test Route#paramsFor fetches query params with non-default value'](assert) { - assert.expect(2); - - this.router.map(function() { - this.route('index', { path: '/:something' }); - }); - - this.setSingleQPController('index'); - - this.add('route:index', Route.extend({ - model(/* params, transition */) { - assert.deepEqual(this.paramsFor('index'), { something: 'baz', foo: 'boo' }, 'could retrieve params for index'); - } - })); - - return this.visitAndAssert('/baz?foo=boo'); - } - - ['@test Route#paramsFor fetches default falsy query params'](assert) { - assert.expect(2); - - this.router.map(function() { - this.route('index', { path: '/:something' }); - }); - - this.setSingleQPController('index', 'foo', false); - - this.add('route:index', Route.extend({ - model(/* params, transition */) { - assert.deepEqual(this.paramsFor('index'), { something: 'baz', foo: false }, 'could retrieve params for index'); - } - })); - - return this.visitAndAssert('/baz'); - } - - ['@test Route#paramsFor fetches non-default falsy query params'](assert) { - assert.expect(2); - - this.router.map(function() { - this.route('index', { path: '/:something' }); - }); - - this.setSingleQPController('index', 'foo', true); - - this.add('route:index', Route.extend({ - model(/* params, transition */) { - assert.deepEqual(this.paramsFor('index'), { something: 'baz', foo: false }, 'could retrieve params for index'); - } - })); - - return this.visitAndAssert('/baz?foo=false'); - } - - ['@test model hook can query prefix-less application params'](assert) { - assert.expect(4); - - this.setSingleQPController('application', 'appomg', 'applol'); - this.setSingleQPController('index', 'omg', 'lol'); - - this.add('route:application', Route.extend({ - model(params) { - assert.deepEqual(params, { appomg: 'applol' }); - } - })); - - this.add('route:index', Route.extend({ - model(params) { - assert.deepEqual(params, { omg: 'lol' }); - assert.deepEqual(this.paramsFor('application'), { appomg: 'applol' }); - } - })); - - return this.visitAndAssert('/'); - } - - ['@test model hook can query prefix-less application params (overridden by incoming url value)'](assert) { - assert.expect(4); - - this.setSingleQPController('application', 'appomg', 'applol'); - this.setSingleQPController('index', 'omg', 'lol'); - - this.add('route:application', Route.extend({ - model(params) { - assert.deepEqual(params, { appomg: 'appyes' }); - } - })); - - this.add('route:index', Route.extend({ - model(params) { - assert.deepEqual(params, { omg: 'yes' }); - assert.deepEqual(this.paramsFor('application'), { appomg: 'appyes' }); - } - })); - - return this.visitAndAssert('/?appomg=appyes&omg=yes'); - } - - ['@test can opt into full transition by setting refreshModel in route queryParams'](assert) { - assert.expect(7); - - this.setSingleQPController('application', 'appomg', 'applol'); - this.setSingleQPController('index', 'omg', 'lol'); - - let appModelCount = 0; - this.add('route:application', Route.extend({ - model(/* params, transition */) { - appModelCount++; - } - })); - - let indexModelCount = 0; - this.add('route:index', Route.extend({ - queryParams: { - omg: { - refreshModel: true - } - }, - model(params) { - indexModelCount++; - - if (indexModelCount === 1) { - assert.deepEqual(params, { omg: 'lol' }, 'params are correct on first pass'); - } else if (indexModelCount === 2) { - assert.deepEqual(params, { omg: 'lex' }, 'params are correct on second pass'); - } - } - })); - - return this.visitAndAssert('/').then(() => { - assert.equal(appModelCount, 1, 'app model hook ran'); - assert.equal(indexModelCount, 1, 'index model hook ran'); - - let indexController = this.getController('index'); - this.setAndFlush(indexController, 'omg', 'lex'); - - assert.equal(appModelCount, 1, 'app model hook did not run again'); - assert.equal(indexModelCount, 2, 'index model hook ran again due to refreshModel'); - }); - } - - ['@test refreshModel and replace work together'](assert) { - assert.expect(8); - - this.setSingleQPController('application', 'appomg', 'applol'); - this.setSingleQPController('index', 'omg', 'lol'); - - let appModelCount = 0; - this.add('route:application', Route.extend({ - model(/* params */) { - appModelCount++; - } - })); - - let indexModelCount = 0; - this.add('route:index', Route.extend({ - queryParams: { - omg: { - refreshModel: true, - replace: true - } - }, - model(params) { - indexModelCount++; - - if (indexModelCount === 1) { - assert.deepEqual(params, { omg: 'lol' }, 'params are correct on first pass'); - } else if (indexModelCount === 2) { - assert.deepEqual(params, { omg: 'lex' }, 'params are correct on second pass'); - } - } - })); - - return this.visitAndAssert('/').then(() => { - assert.equal(appModelCount, 1, 'app model hook ran'); - assert.equal(indexModelCount, 1, 'index model hook ran'); - - let indexController = this.getController('index'); - this.expectedReplaceURL = '/?omg=lex'; - this.setAndFlush(indexController, 'omg', 'lex'); - - assert.equal(appModelCount, 1, 'app model hook did not run again'); - assert.equal(indexModelCount, 2, 'index model hook ran again due to refreshModel'); - }); - } - - ['@test multiple QP value changes only cause a single model refresh'](assert) { - assert.expect(2); + } - this.setSingleQPController('index', 'alex', 'lol'); - this.setSingleQPController('index', 'steely', 'lel'); + ["@test No replaceURL occurs on startup because default values don't show up in URL"]( + assert + ) { + assert.expect(1); - let refreshCount = 0; - this.add('route:index', Route.extend({ - queryParams: { - alex: { - refreshModel: true - }, - steely: { - refreshModel: true - } - }, - refresh() { - refreshCount++; - } - })); - - return this.visitAndAssert('/').then(() => { - let indexController = this.getController('index'); - run(indexController, 'setProperties', { alex: 'fran', steely: 'david' }); - assert.equal(refreshCount, 1, 'index refresh hook only run once'); - }); - } - - ['@test refreshModel does not cause a second transition during app boot '](assert) { - assert.expect(1); - - this.setSingleQPController('application', 'appomg', 'applol'); - this.setSingleQPController('index', 'omg', 'lol'); - - this.add('route:index', Route.extend({ - queryParams: { - omg: { - refreshModel: true - } - }, - refresh() { - assert.ok(false); - } - })); + this.setSingleQPController('index'); - return this.visitAndAssert('/?appomg=hello&omg=world'); - } + return this.visitAndAssert('/'); + } - ['@test queryParams are updated when a controller property is set and the route is refreshed. Issue #13263 '](assert) { - this.addTemplate('application', '{{foo}}{{outlet}}'); + ['@test Calling transitionTo does not lose query params already on the activeTransition']( + assert + ) { + assert.expect(2); - this.setSingleQPController('application', 'foo', 1, { - actions: { - increment() { - this.incrementProperty('foo'); - this.send('refreshRoute'); - } - } - }); - - this.add('route:application', Route.extend({ - actions: { - refreshRoute() { - this.refresh(); - } - } - })); - - return this.visitAndAssert('/').then(() => { - assert.equal(getTextOf(document.getElementById('test-value')), '1'); - - run(document.getElementById('test-button'), 'click'); - assert.equal(getTextOf(document.getElementById('test-value')), '2'); - this.assertCurrentPath('/?foo=2'); + this.router.map(function() { + this.route('parent', function() { + this.route('child'); + this.route('sibling'); + }); + }); - run(document.getElementById('test-button'), 'click'); - assert.equal(getTextOf(document.getElementById('test-value')), '3'); - this.assertCurrentPath('/?foo=3'); - }); - } + this.add( + 'route:parent.child', + Route.extend({ + afterModel() { + this.transitionTo('parent.sibling'); + } + }) + ); + + this.setSingleQPController('parent'); + + return this.visit('/parent/child?foo=lol').then(() => { + this.assertCurrentPath( + '/parent/sibling?foo=lol', + 'redirected to the sibling route, instead of child route' + ); + assert.equal( + this.getController('parent').get('foo'), + 'lol', + 'controller has value from the active transition' + ); + }); + } - ['@test Use Ember.get to retrieve query params \'refreshModel\' configuration'](assert) { - assert.expect(7); + ['@test Single query params can be set on the controller and reflected in the url']( + assert + ) { + assert.expect(3); - this.setSingleQPController('application', 'appomg', 'applol'); - this.setSingleQPController('index', 'omg', 'lol'); + this.router.map(function() { + this.route('home', { path: '/' }); + }); - let appModelCount = 0; - this.add('route:application', Route.extend({ - model(/* params */) { - appModelCount++; - } - })); + this.setSingleQPController('home'); - let indexModelCount = 0; - this.add('route:index', Route.extend({ - queryParams: EmberObject.create({ - unknownProperty() { - return { refreshModel: true }; - } - }), - model(params) { - indexModelCount++; - - if (indexModelCount === 1) { - assert.deepEqual(params, { omg: 'lol' }); - } else if (indexModelCount === 2) { - assert.deepEqual(params, { omg: 'lex' }); - } - } - })); + return this.visitAndAssert('/').then(() => { + let controller = this.getController('home'); - return this.visitAndAssert('/').then(() => { - assert.equal(appModelCount, 1); - assert.equal(indexModelCount, 1); + this.setAndFlush(controller, 'foo', '456'); + this.assertCurrentPath('/?foo=456'); - let indexController = this.getController('index'); - this.setAndFlush(indexController, 'omg', 'lex'); + this.setAndFlush(controller, 'foo', '987'); + this.assertCurrentPath('/?foo=987'); + }); + } + + ['@test Query params can map to different url keys configured on the controller']( + assert + ) { + assert.expect(6); + + this.add( + 'controller:index', + Controller.extend({ + queryParams: [{ foo: 'other_foo', bar: { as: 'other_bar' } }], + foo: 'FOO', + bar: 'BAR' + }) + ); + + return this.visitAndAssert('/').then(() => { + let controller = this.getController('index'); + + this.setAndFlush(controller, 'foo', 'LEX'); + this.assertCurrentPath( + '/?other_foo=LEX', + "QP mapped correctly without 'as'" + ); + + this.setAndFlush(controller, 'foo', 'WOO'); + this.assertCurrentPath( + '/?other_foo=WOO', + "QP updated correctly without 'as'" + ); + + this.transitionTo('/?other_foo=NAW'); + assert.equal( + controller.get('foo'), + 'NAW', + 'QP managed correctly on URL transition' + ); + + this.setAndFlush(controller, 'bar', 'NERK'); + this.assertCurrentPath( + '/?other_bar=NERK&other_foo=NAW', + "QP mapped correctly with 'as'" + ); + + this.setAndFlush(controller, 'bar', 'NUKE'); + this.assertCurrentPath( + '/?other_bar=NUKE&other_foo=NAW', + "QP updated correctly with 'as'" + ); + }); + } - assert.equal(appModelCount, 1); - assert.equal(indexModelCount, 2); - }); - } + ['@test Routes have a private overridable serializeQueryParamKey hook']( + assert + ) { + assert.expect(2); - ['@test can use refreshModel even with URL changes that remove QPs from address bar'](assert) { - assert.expect(4); + this.add( + 'route:index', + Route.extend({ + serializeQueryParamKey: StringUtils.dasherize + }) + ); - this.setSingleQPController('index', 'omg', 'lol'); + this.setSingleQPController('index', 'funTimes', ''); - let indexModelCount = 0; - this.add('route:index', Route.extend({ - queryParams: { - omg: { - refreshModel: true - } - }, - model(params) { - indexModelCount++; - - let data; - if (indexModelCount === 1) { - data = 'foo'; - } else if (indexModelCount === 2) { - data = 'lol'; - } + return this.visitAndAssert('/').then(() => { + let controller = this.getController('index'); - assert.deepEqual(params, { omg: data }, 'index#model receives right data'); - } - })); + this.setAndFlush(controller, 'funTimes', 'woot'); + this.assertCurrentPath('/?fun-times=woot'); + }); + } + + ['@test Can override inherited QP behavior by specifying queryParams as a computed property']( + assert + ) { + assert.expect(3); + + this.setSingleQPController('index', 'a', 0, { + queryParams: computed(function() { + return ['c']; + }), + c: true + }); - return this.visitAndAssert('/?omg=foo').then(() => { - this.transitionTo('/'); + return this.visitAndAssert('/').then(() => { + let indexController = this.getController('index'); - let indexController = this.getController('index'); - assert.equal(indexController.get('omg'), 'lol'); - }); - } + this.setAndFlush(indexController, 'a', 1); + this.assertCurrentPath('/', 'QP did not update due to being overriden'); - ['@test can opt into a replace query by specifying replace:true in the Route config hash'](assert) { - assert.expect(2); + this.setAndFlush(indexController, 'c', false); + this.assertCurrentPath('/?c=false', 'QP updated with overridden param'); + }); + } - this.setSingleQPController('application', 'alex', 'matchneer'); + ['@test Can concatenate inherited QP behavior by specifying queryParams as an array']( + assert + ) { + assert.expect(3); - this.add('route:application', Route.extend({ - queryParams: { - alex: { - replace: true - } - } - })); - - return this.visitAndAssert('/').then(() => { - let appController = this.getController('application'); - this.expectedReplaceURL = '/?alex=wallace'; - this.setAndFlush(appController, 'alex', 'wallace'); - }); - } + this.setSingleQPController('index', 'a', 0, { + queryParams: ['c'], + c: true + }); - ['@test Route query params config can be configured using property name instead of URL key'](assert) { - assert.expect(2); + return this.visitAndAssert('/').then(() => { + let indexController = this.getController('index'); - this.add('controller:application', Controller.extend({ - queryParams: [{ commitBy: 'commit_by' }] - })); + this.setAndFlush(indexController, 'a', 1); + this.assertCurrentPath('/?a=1', 'Inherited QP did update'); - this.add('route:application', Route.extend({ - queryParams: { - commitBy: { - replace: true - } - } - })); - - return this.visitAndAssert('/').then(() => { - let appController = this.getController('application'); - this.expectedReplaceURL = '/?commit_by=igor_seb'; - this.setAndFlush(appController, 'commitBy', 'igor_seb'); - }); - } + this.setAndFlush(indexController, 'c', false); + this.assertCurrentPath('/?a=1&c=false', 'New QP did update'); + }); + } - ['@test An explicit replace:false on a changed QP always wins and causes a pushState'](assert) { - assert.expect(3); - - this.add('controller:application', Controller.extend({ - queryParams: ['alex', 'steely'], - alex: 'matchneer', - steely: 'dan' - })); - - this.add('route:application', Route.extend({ - queryParams: { - alex: { - replace: true - }, - steely: { - replace: false - } - } - })); + ['@test model hooks receives query params'](assert) { + assert.expect(2); - return this.visit('/').then(() => { - let appController = this.getController('application'); - this.expectedPushURL = '/?alex=wallace&steely=jan'; - run(appController, 'setProperties', { alex: 'wallace', steely: 'jan' }); + this.setSingleQPController('index'); - this.expectedPushURL = '/?alex=wallace&steely=fran'; - run(appController, 'setProperties', { steely: 'fran' }); + this.add( + 'route:index', + Route.extend({ + model(params) { + assert.deepEqual(params, { foo: 'bar' }); + } + }) + ); - this.expectedReplaceURL = '/?alex=sriracha&steely=fran'; - run(appController, 'setProperties', { alex: 'sriracha' }); - }); - } + return this.visitAndAssert('/'); + } - ['@test can opt into full transition by setting refreshModel in route queryParams when transitioning from child to parent'](assert) { - this.addTemplate('parent', '{{outlet}}'); - this.addTemplate('parent.child', '{{link-to \'Parent\' \'parent\' (query-params foo=\'change\') id=\'parent-link\'}}'); + ['@test model hooks receives query params with dynamic segment params']( + assert + ) { + assert.expect(2); - this.router.map(function() { - this.route('parent', function() { - this.route('child'); + this.router.map(function() { + this.route('index', { path: '/:id' }); }); - }); - let parentModelCount = 0; - this.add('route:parent', Route.extend({ - model() { - parentModelCount++; - }, - queryParams: { - foo: { - refreshModel: true - } - } - })); + this.setSingleQPController('index'); - this.setSingleQPController('parent', 'foo', 'abc'); + this.add( + 'route:index', + Route.extend({ + model(params) { + assert.deepEqual(params, { foo: 'bar', id: 'baz' }); + } + }) + ); - return this.visit('/parent/child?foo=lol').then(() => { - assert.equal(parentModelCount, 1); + return this.visitAndAssert('/baz'); + } - run(document.getElementById('parent-link'), 'click'); - assert.equal(parentModelCount, 2); - }); - } + ['@test model hooks receives query params (overridden by incoming url value)']( + assert + ) { + assert.expect(2); - ['@test Use Ember.get to retrieve query params \'replace\' configuration'](assert) { - assert.expect(2); + this.router.map(function() { + this.route('index', { path: '/:id' }); + }); - this.setSingleQPController('application', 'alex', 'matchneer'); + this.setSingleQPController('index'); - this.add('route:application', Route.extend({ - queryParams: EmberObject.create({ - unknownProperty(/* keyName */) { - // We are simulating all qps requiring refresh - return { replace: true }; - } - }) - })); - - return this.visitAndAssert('/').then(() => { - let appController = this.getController('application'); - this.expectedReplaceURL = '/?alex=wallace'; - this.setAndFlush(appController, 'alex', 'wallace'); - }); - } + this.add( + 'route:index', + Route.extend({ + model(params) { + assert.deepEqual(params, { foo: 'baz', id: 'boo' }); + } + }) + ); - ['@test can override incoming QP values in setupController'](assert) { - assert.expect(3); + return this.visitAndAssert('/boo?foo=baz'); + } - this.router.map(function() { - this.route('about'); - }); + ['@test error is thrown if dynamic segment and query param have same name']( + assert + ) { + assert.expect(1); - this.setSingleQPController('index', 'omg', 'lol'); - - this.add('route:index', Route.extend({ - setupController(controller) { - assert.ok(true, 'setupController called'); - controller.set('omg', 'OVERRIDE'); - }, - actions: { - queryParamsDidChange() { - assert.ok(false, 'queryParamsDidChange shouldn\'t fire'); - } - } - })); + this.router.map(function() { + this.route('index', { path: '/:foo' }); + }); - return this.visitAndAssert('/about').then(() => { - this.transitionTo('index'); - this.assertCurrentPath('/?omg=OVERRIDE'); - }); - } + this.setSingleQPController('index'); + + expectAssertion(() => { + this.visitAndAssert('/boo?foo=baz'); + }, `The route 'index' has both a dynamic segment and query param with name 'foo'. Please rename one to avoid collisions.`); + } + + ['@test query params have been set by the time setupController is called']( + assert + ) { + assert.expect(2); + + this.setSingleQPController('application'); + + this.add( + 'route:application', + Route.extend({ + setupController(controller) { + assert.equal( + controller.get('foo'), + 'YEAH', + "controller's foo QP property set before setupController called" + ); + } + }) + ); + + return this.visitAndAssert('/?foo=YEAH'); + } + + ['@test mapped query params have been set by the time setupController is called']( + assert + ) { + assert.expect(2); + + this.setSingleQPController('application', { faz: 'foo' }); + + this.add( + 'route:application', + Route.extend({ + setupController(controller) { + assert.equal( + controller.get('faz'), + 'YEAH', + "controller's foo QP property set before setupController called" + ); + } + }) + ); + + return this.visitAndAssert('/?foo=YEAH'); + } + + ['@test Route#paramsFor fetches query params with default value'](assert) { + assert.expect(2); + + this.router.map(function() { + this.route('index', { path: '/:something' }); + }); - ['@test can override incoming QP array values in setupController'](assert) { - assert.expect(3); + this.setSingleQPController('index'); + + this.add( + 'route:index', + Route.extend({ + model(/* params, transition */) { + assert.deepEqual( + this.paramsFor('index'), + { something: 'baz', foo: 'bar' }, + 'could retrieve params for index' + ); + } + }) + ); + + return this.visitAndAssert('/baz'); + } + + ['@test Route#paramsFor fetches query params with non-default value']( + assert + ) { + assert.expect(2); + + this.router.map(function() { + this.route('index', { path: '/:something' }); + }); - this.router.map(function() { - this.route('about'); - }); + this.setSingleQPController('index'); + + this.add( + 'route:index', + Route.extend({ + model(/* params, transition */) { + assert.deepEqual( + this.paramsFor('index'), + { something: 'baz', foo: 'boo' }, + 'could retrieve params for index' + ); + } + }) + ); + + return this.visitAndAssert('/baz?foo=boo'); + } + + ['@test Route#paramsFor fetches default falsy query params'](assert) { + assert.expect(2); + + this.router.map(function() { + this.route('index', { path: '/:something' }); + }); - this.setSingleQPController('index', 'omg', ['lol']); + this.setSingleQPController('index', 'foo', false); + + this.add( + 'route:index', + Route.extend({ + model(/* params, transition */) { + assert.deepEqual( + this.paramsFor('index'), + { something: 'baz', foo: false }, + 'could retrieve params for index' + ); + } + }) + ); + + return this.visitAndAssert('/baz'); + } + + ['@test Route#paramsFor fetches non-default falsy query params'](assert) { + assert.expect(2); + + this.router.map(function() { + this.route('index', { path: '/:something' }); + }); - this.add('route:index', Route.extend({ - setupController(controller) { - assert.ok(true, 'setupController called'); - controller.set('omg', ['OVERRIDE']); - }, - actions: { - queryParamsDidChange() { - assert.ok(false, 'queryParamsDidChange shouldn\'t fire'); + this.setSingleQPController('index', 'foo', true); + + this.add( + 'route:index', + Route.extend({ + model(/* params, transition */) { + assert.deepEqual( + this.paramsFor('index'), + { something: 'baz', foo: false }, + 'could retrieve params for index' + ); + } + }) + ); + + return this.visitAndAssert('/baz?foo=false'); + } + + ['@test model hook can query prefix-less application params'](assert) { + assert.expect(4); + + this.setSingleQPController('application', 'appomg', 'applol'); + this.setSingleQPController('index', 'omg', 'lol'); + + this.add( + 'route:application', + Route.extend({ + model(params) { + assert.deepEqual(params, { appomg: 'applol' }); + } + }) + ); + + this.add( + 'route:index', + Route.extend({ + model(params) { + assert.deepEqual(params, { omg: 'lol' }); + assert.deepEqual(this.paramsFor('application'), { + appomg: 'applol' + }); + } + }) + ); + + return this.visitAndAssert('/'); + } + + ['@test model hook can query prefix-less application params (overridden by incoming url value)']( + assert + ) { + assert.expect(4); + + this.setSingleQPController('application', 'appomg', 'applol'); + this.setSingleQPController('index', 'omg', 'lol'); + + this.add( + 'route:application', + Route.extend({ + model(params) { + assert.deepEqual(params, { appomg: 'appyes' }); + } + }) + ); + + this.add( + 'route:index', + Route.extend({ + model(params) { + assert.deepEqual(params, { omg: 'yes' }); + assert.deepEqual(this.paramsFor('application'), { + appomg: 'appyes' + }); + } + }) + ); + + return this.visitAndAssert('/?appomg=appyes&omg=yes'); + } + + ['@test can opt into full transition by setting refreshModel in route queryParams']( + assert + ) { + assert.expect(7); + + this.setSingleQPController('application', 'appomg', 'applol'); + this.setSingleQPController('index', 'omg', 'lol'); + + let appModelCount = 0; + this.add( + 'route:application', + Route.extend({ + model(/* params, transition */) { + appModelCount++; + } + }) + ); + + let indexModelCount = 0; + this.add( + 'route:index', + Route.extend({ + queryParams: { + omg: { + refreshModel: true + } + }, + model(params) { + indexModelCount++; + + if (indexModelCount === 1) { + assert.deepEqual( + params, + { omg: 'lol' }, + 'params are correct on first pass' + ); + } else if (indexModelCount === 2) { + assert.deepEqual( + params, + { omg: 'lex' }, + 'params are correct on second pass' + ); + } + } + }) + ); + + return this.visitAndAssert('/').then(() => { + assert.equal(appModelCount, 1, 'app model hook ran'); + assert.equal(indexModelCount, 1, 'index model hook ran'); + + let indexController = this.getController('index'); + this.setAndFlush(indexController, 'omg', 'lex'); + + assert.equal(appModelCount, 1, 'app model hook did not run again'); + assert.equal( + indexModelCount, + 2, + 'index model hook ran again due to refreshModel' + ); + }); + } + + ['@test refreshModel and replace work together'](assert) { + assert.expect(8); + + this.setSingleQPController('application', 'appomg', 'applol'); + this.setSingleQPController('index', 'omg', 'lol'); + + let appModelCount = 0; + this.add( + 'route:application', + Route.extend({ + model(/* params */) { + appModelCount++; + } + }) + ); + + let indexModelCount = 0; + this.add( + 'route:index', + Route.extend({ + queryParams: { + omg: { + refreshModel: true, + replace: true + } + }, + model(params) { + indexModelCount++; + + if (indexModelCount === 1) { + assert.deepEqual( + params, + { omg: 'lol' }, + 'params are correct on first pass' + ); + } else if (indexModelCount === 2) { + assert.deepEqual( + params, + { omg: 'lex' }, + 'params are correct on second pass' + ); + } + } + }) + ); + + return this.visitAndAssert('/').then(() => { + assert.equal(appModelCount, 1, 'app model hook ran'); + assert.equal(indexModelCount, 1, 'index model hook ran'); + + let indexController = this.getController('index'); + this.expectedReplaceURL = '/?omg=lex'; + this.setAndFlush(indexController, 'omg', 'lex'); + + assert.equal(appModelCount, 1, 'app model hook did not run again'); + assert.equal( + indexModelCount, + 2, + 'index model hook ran again due to refreshModel' + ); + }); + } + + ['@test multiple QP value changes only cause a single model refresh']( + assert + ) { + assert.expect(2); + + this.setSingleQPController('index', 'alex', 'lol'); + this.setSingleQPController('index', 'steely', 'lel'); + + let refreshCount = 0; + this.add( + 'route:index', + Route.extend({ + queryParams: { + alex: { + refreshModel: true + }, + steely: { + refreshModel: true + } + }, + refresh() { + refreshCount++; + } + }) + ); + + return this.visitAndAssert('/').then(() => { + let indexController = this.getController('index'); + run(indexController, 'setProperties', { + alex: 'fran', + steely: 'david' + }); + assert.equal(refreshCount, 1, 'index refresh hook only run once'); + }); + } + + ['@test refreshModel does not cause a second transition during app boot ']( + assert + ) { + assert.expect(1); + + this.setSingleQPController('application', 'appomg', 'applol'); + this.setSingleQPController('index', 'omg', 'lol'); + + this.add( + 'route:index', + Route.extend({ + queryParams: { + omg: { + refreshModel: true + } + }, + refresh() { + assert.ok(false); + } + }) + ); + + return this.visitAndAssert('/?appomg=hello&omg=world'); + } + + ['@test queryParams are updated when a controller property is set and the route is refreshed. Issue #13263 ']( + assert + ) { + this.addTemplate( + 'application', + '{{foo}}{{outlet}}' + ); + + this.setSingleQPController('application', 'foo', 1, { + actions: { + increment() { + this.incrementProperty('foo'); + this.send('refreshRoute'); + } } - } - })); - - return this.visitAndAssert('/about').then(() => { - this.transitionTo('index'); - this.assertCurrentPath('/?omg=' + encodeURIComponent(JSON.stringify(['OVERRIDE']))); - }); - } - - ['@test URL transitions that remove QPs still register as QP changes'](assert) { - assert.expect(2); - - this.setSingleQPController('index', 'omg', 'lol'); - - return this.visit('/?omg=borf').then(() => { - let indexController = this.getController('index'); - assert.equal(indexController.get('omg'), 'borf'); - - this.transitionTo('/'); - assert.equal(indexController.get('omg'), 'lol'); - }); - } - - ['@test Subresource naming style is supported'](assert) { - assert.expect(5); - - this.router.map(function() { - this.route('abc.def', { path: '/abcdef' }, function() { - this.route('zoo'); }); - }); - this.addTemplate('application', '{{link-to \'A\' \'abc.def\' (query-params foo=\'123\') id=\'one\'}}{{link-to \'B\' \'abc.def.zoo\' (query-params foo=\'123\' bar=\'456\') id=\'two\'}}{{outlet}}'); - - this.setSingleQPController('abc.def', 'foo', 'lol'); - this.setSingleQPController('abc.def.zoo', 'bar', 'haha'); - - return this.visitAndAssert('/').then(() => { - assert.equal(this.$('#one').attr('href'), '/abcdef?foo=123'); - assert.equal(this.$('#two').attr('href'), '/abcdef/zoo?bar=456&foo=123'); - - run(this.$('#one'), 'click'); - this.assertCurrentPath('/abcdef?foo=123'); + this.add( + 'route:application', + Route.extend({ + actions: { + refreshRoute() { + this.refresh(); + } + } + }) + ); + + return this.visitAndAssert('/').then(() => { + assert.equal(getTextOf(document.getElementById('test-value')), '1'); + + run(document.getElementById('test-button'), 'click'); + assert.equal(getTextOf(document.getElementById('test-value')), '2'); + this.assertCurrentPath('/?foo=2'); + + run(document.getElementById('test-button'), 'click'); + assert.equal(getTextOf(document.getElementById('test-value')), '3'); + this.assertCurrentPath('/?foo=3'); + }); + } + + ["@test Use Ember.get to retrieve query params 'refreshModel' configuration"]( + assert + ) { + assert.expect(7); + + this.setSingleQPController('application', 'appomg', 'applol'); + this.setSingleQPController('index', 'omg', 'lol'); + + let appModelCount = 0; + this.add( + 'route:application', + Route.extend({ + model(/* params */) { + appModelCount++; + } + }) + ); + + let indexModelCount = 0; + this.add( + 'route:index', + Route.extend({ + queryParams: EmberObject.create({ + unknownProperty() { + return { refreshModel: true }; + } + }), + model(params) { + indexModelCount++; + + if (indexModelCount === 1) { + assert.deepEqual(params, { omg: 'lol' }); + } else if (indexModelCount === 2) { + assert.deepEqual(params, { omg: 'lex' }); + } + } + }) + ); + + return this.visitAndAssert('/').then(() => { + assert.equal(appModelCount, 1); + assert.equal(indexModelCount, 1); + + let indexController = this.getController('index'); + this.setAndFlush(indexController, 'omg', 'lex'); + + assert.equal(appModelCount, 1); + assert.equal(indexModelCount, 2); + }); + } + + ['@test can use refreshModel even with URL changes that remove QPs from address bar']( + assert + ) { + assert.expect(4); + + this.setSingleQPController('index', 'omg', 'lol'); + + let indexModelCount = 0; + this.add( + 'route:index', + Route.extend({ + queryParams: { + omg: { + refreshModel: true + } + }, + model(params) { + indexModelCount++; + + let data; + if (indexModelCount === 1) { + data = 'foo'; + } else if (indexModelCount === 2) { + data = 'lol'; + } + + assert.deepEqual( + params, + { omg: data }, + 'index#model receives right data' + ); + } + }) + ); + + return this.visitAndAssert('/?omg=foo').then(() => { + this.transitionTo('/'); + + let indexController = this.getController('index'); + assert.equal(indexController.get('omg'), 'lol'); + }); + } + + ['@test can opt into a replace query by specifying replace:true in the Route config hash']( + assert + ) { + assert.expect(2); + + this.setSingleQPController('application', 'alex', 'matchneer'); + + this.add( + 'route:application', + Route.extend({ + queryParams: { + alex: { + replace: true + } + } + }) + ); + + return this.visitAndAssert('/').then(() => { + let appController = this.getController('application'); + this.expectedReplaceURL = '/?alex=wallace'; + this.setAndFlush(appController, 'alex', 'wallace'); + }); + } + + ['@test Route query params config can be configured using property name instead of URL key']( + assert + ) { + assert.expect(2); + + this.add( + 'controller:application', + Controller.extend({ + queryParams: [{ commitBy: 'commit_by' }] + }) + ); + + this.add( + 'route:application', + Route.extend({ + queryParams: { + commitBy: { + replace: true + } + } + }) + ); + + return this.visitAndAssert('/').then(() => { + let appController = this.getController('application'); + this.expectedReplaceURL = '/?commit_by=igor_seb'; + this.setAndFlush(appController, 'commitBy', 'igor_seb'); + }); + } + + ['@test An explicit replace:false on a changed QP always wins and causes a pushState']( + assert + ) { + assert.expect(3); + + this.add( + 'controller:application', + Controller.extend({ + queryParams: ['alex', 'steely'], + alex: 'matchneer', + steely: 'dan' + }) + ); + + this.add( + 'route:application', + Route.extend({ + queryParams: { + alex: { + replace: true + }, + steely: { + replace: false + } + } + }) + ); + + return this.visit('/').then(() => { + let appController = this.getController('application'); + this.expectedPushURL = '/?alex=wallace&steely=jan'; + run(appController, 'setProperties', { alex: 'wallace', steely: 'jan' }); + + this.expectedPushURL = '/?alex=wallace&steely=fran'; + run(appController, 'setProperties', { steely: 'fran' }); + + this.expectedReplaceURL = '/?alex=sriracha&steely=fran'; + run(appController, 'setProperties', { alex: 'sriracha' }); + }); + } + + ['@test can opt into full transition by setting refreshModel in route queryParams when transitioning from child to parent']( + assert + ) { + this.addTemplate('parent', '{{outlet}}'); + this.addTemplate( + 'parent.child', + "{{link-to 'Parent' 'parent' (query-params foo='change') id='parent-link'}}" + ); + + this.router.map(function() { + this.route('parent', function() { + this.route('child'); + }); + }); - run(this.$('#two'), 'click'); - this.assertCurrentPath('/abcdef/zoo?bar=456&foo=123'); - }); - } + let parentModelCount = 0; + this.add( + 'route:parent', + Route.extend({ + model() { + parentModelCount++; + }, + queryParams: { + foo: { + refreshModel: true + } + } + }) + ); + + this.setSingleQPController('parent', 'foo', 'abc'); + + return this.visit('/parent/child?foo=lol').then(() => { + assert.equal(parentModelCount, 1); + + run(document.getElementById('parent-link'), 'click'); + assert.equal(parentModelCount, 2); + }); + } + + ["@test Use Ember.get to retrieve query params 'replace' configuration"]( + assert + ) { + assert.expect(2); + + this.setSingleQPController('application', 'alex', 'matchneer'); + + this.add( + 'route:application', + Route.extend({ + queryParams: EmberObject.create({ + unknownProperty(/* keyName */) { + // We are simulating all qps requiring refresh + return { replace: true }; + } + }) + }) + ); + + return this.visitAndAssert('/').then(() => { + let appController = this.getController('application'); + this.expectedReplaceURL = '/?alex=wallace'; + this.setAndFlush(appController, 'alex', 'wallace'); + }); + } - ['@test transitionTo supports query params']() { - this.setSingleQPController('index', 'foo', 'lol'); + ['@test can override incoming QP values in setupController'](assert) { + assert.expect(3); - return this.visitAndAssert('/').then(() => { - this.transitionTo({ queryParams: { foo: 'borf' } }); - this.assertCurrentPath('/?foo=borf', 'shorthand supported'); + this.router.map(function() { + this.route('about'); + }); - this.transitionTo({ queryParams: { 'index:foo': 'blaf' } }); - this.assertCurrentPath('/?foo=blaf', 'longform supported'); + this.setSingleQPController('index', 'omg', 'lol'); + + this.add( + 'route:index', + Route.extend({ + setupController(controller) { + assert.ok(true, 'setupController called'); + controller.set('omg', 'OVERRIDE'); + }, + actions: { + queryParamsDidChange() { + assert.ok(false, "queryParamsDidChange shouldn't fire"); + } + } + }) + ); + + return this.visitAndAssert('/about').then(() => { + this.transitionTo('index'); + this.assertCurrentPath('/?omg=OVERRIDE'); + }); + } - this.transitionTo({ queryParams: { 'index:foo': false } }); - this.assertCurrentPath('/?foo=false', 'longform supported (bool)'); + ['@test can override incoming QP array values in setupController'](assert) { + assert.expect(3); - this.transitionTo({ queryParams: { foo: false } }); - this.assertCurrentPath('/?foo=false', 'shorhand supported (bool)'); - }); - } + this.router.map(function() { + this.route('about'); + }); - ['@test transitionTo supports query params (multiple)']() { - this.add('controller:index', Controller.extend({ - queryParams: ['foo', 'bar'], - foo: 'lol', - bar: 'wat' - })); + this.setSingleQPController('index', 'omg', ['lol']); + + this.add( + 'route:index', + Route.extend({ + setupController(controller) { + assert.ok(true, 'setupController called'); + controller.set('omg', ['OVERRIDE']); + }, + actions: { + queryParamsDidChange() { + assert.ok(false, "queryParamsDidChange shouldn't fire"); + } + } + }) + ); + + return this.visitAndAssert('/about').then(() => { + this.transitionTo('index'); + this.assertCurrentPath( + '/?omg=' + encodeURIComponent(JSON.stringify(['OVERRIDE'])) + ); + }); + } - return this.visitAndAssert('/').then(() => { - this.transitionTo({ queryParams: { foo: 'borf' } }); - this.assertCurrentPath('/?foo=borf', 'shorthand supported'); + ['@test URL transitions that remove QPs still register as QP changes']( + assert + ) { + assert.expect(2); - this.transitionTo({ queryParams: { 'index:foo': 'blaf' } }); - this.assertCurrentPath('/?foo=blaf', 'longform supported'); + this.setSingleQPController('index', 'omg', 'lol'); - this.transitionTo({ queryParams: { 'index:foo': false } }); - this.assertCurrentPath('/?foo=false', 'longform supported (bool)'); + return this.visit('/?omg=borf').then(() => { + let indexController = this.getController('index'); + assert.equal(indexController.get('omg'), 'borf'); - this.transitionTo({ queryParams: { foo: false } }); - this.assertCurrentPath('/?foo=false', 'shorhand supported (bool)'); - }); - } + this.transitionTo('/'); + assert.equal(indexController.get('omg'), 'lol'); + }); + } - ['@test setting controller QP to empty string doesn\'t generate null in URL'](assert) { - assert.expect(1); + ['@test Subresource naming style is supported'](assert) { + assert.expect(5); - this.setSingleQPController('index', 'foo', '123'); + this.router.map(function() { + this.route('abc.def', { path: '/abcdef' }, function() { + this.route('zoo'); + }); + }); - return this.visit('/').then(() => { - let controller = this.getController('index'); + this.addTemplate( + 'application', + "{{link-to 'A' 'abc.def' (query-params foo='123') id='one'}}{{link-to 'B' 'abc.def.zoo' (query-params foo='123' bar='456') id='two'}}{{outlet}}" + ); - this.expectedPushURL = '/?foo='; - this.setAndFlush(controller, 'foo', ''); - }); - } + this.setSingleQPController('abc.def', 'foo', 'lol'); + this.setSingleQPController('abc.def.zoo', 'bar', 'haha'); - ['@test setting QP to empty string doesn\'t generate null in URL'](assert) { - assert.expect(1); + return this.visitAndAssert('/').then(() => { + assert.equal(this.$('#one').attr('href'), '/abcdef?foo=123'); + assert.equal( + this.$('#two').attr('href'), + '/abcdef/zoo?bar=456&foo=123' + ); - this.add('route:index', Route.extend({ - queryParams: { - foo: { - defaultValue: '123' - } - } - })); + run(this.$('#one'), 'click'); + this.assertCurrentPath('/abcdef?foo=123'); - return this.visit('/').then(() => { - let controller = this.getController('index'); + run(this.$('#two'), 'click'); + this.assertCurrentPath('/abcdef/zoo?bar=456&foo=123'); + }); + } - this.expectedPushURL = '/?foo='; - this.setAndFlush(controller, 'foo', ''); - }); - } + ['@test transitionTo supports query params']() { + this.setSingleQPController('index', 'foo', 'lol'); - ['@test A default boolean value deserializes QPs as booleans rather than strings'](assert) { - assert.expect(3); + return this.visitAndAssert('/').then(() => { + this.transitionTo({ queryParams: { foo: 'borf' } }); + this.assertCurrentPath('/?foo=borf', 'shorthand supported'); - this.setSingleQPController('index', 'foo', false); + this.transitionTo({ queryParams: { 'index:foo': 'blaf' } }); + this.assertCurrentPath('/?foo=blaf', 'longform supported'); - this.add('route:index', Route.extend({ - model(params) { - assert.equal(params.foo, true, 'model hook received foo as boolean true'); - } - })); + this.transitionTo({ queryParams: { 'index:foo': false } }); + this.assertCurrentPath('/?foo=false', 'longform supported (bool)'); - return this.visit('/?foo=true').then(() => { - let controller = this.getController('index'); - assert.equal(controller.get('foo'), true); + this.transitionTo({ queryParams: { foo: false } }); + this.assertCurrentPath('/?foo=false', 'shorhand supported (bool)'); + }); + } + + ['@test transitionTo supports query params (multiple)']() { + this.add( + 'controller:index', + Controller.extend({ + queryParams: ['foo', 'bar'], + foo: 'lol', + bar: 'wat' + }) + ); + + return this.visitAndAssert('/').then(() => { + this.transitionTo({ queryParams: { foo: 'borf' } }); + this.assertCurrentPath('/?foo=borf', 'shorthand supported'); + + this.transitionTo({ queryParams: { 'index:foo': 'blaf' } }); + this.assertCurrentPath('/?foo=blaf', 'longform supported'); + + this.transitionTo({ queryParams: { 'index:foo': false } }); + this.assertCurrentPath('/?foo=false', 'longform supported (bool)'); + + this.transitionTo({ queryParams: { foo: false } }); + this.assertCurrentPath('/?foo=false', 'shorhand supported (bool)'); + }); + } - this.transitionTo('/?foo=false'); - assert.equal(controller.get('foo'), false); - }); - } + ["@test setting controller QP to empty string doesn't generate null in URL"]( + assert + ) { + assert.expect(1); - ['@test Query param without value are empty string'](assert) { - assert.expect(1); + this.setSingleQPController('index', 'foo', '123'); - this.add('controller:index', Controller.extend({ - queryParams: ['foo'], - foo: '' - })); + return this.visit('/').then(() => { + let controller = this.getController('index'); - return this.visit('/?foo=').then(() => { - let controller = this.getController('index'); - assert.equal(controller.get('foo'), ''); - }); - } + this.expectedPushURL = '/?foo='; + this.setAndFlush(controller, 'foo', ''); + }); + } + + ["@test setting QP to empty string doesn't generate null in URL"](assert) { + assert.expect(1); + + this.add( + 'route:index', + Route.extend({ + queryParams: { + foo: { + defaultValue: '123' + } + } + }) + ); + + return this.visit('/').then(() => { + let controller = this.getController('index'); + + this.expectedPushURL = '/?foo='; + this.setAndFlush(controller, 'foo', ''); + }); + } + + ['@test A default boolean value deserializes QPs as booleans rather than strings']( + assert + ) { + assert.expect(3); + + this.setSingleQPController('index', 'foo', false); + + this.add( + 'route:index', + Route.extend({ + model(params) { + assert.equal( + params.foo, + true, + 'model hook received foo as boolean true' + ); + } + }) + ); + + return this.visit('/?foo=true').then(() => { + let controller = this.getController('index'); + assert.equal(controller.get('foo'), true); + + this.transitionTo('/?foo=false'); + assert.equal(controller.get('foo'), false); + }); + } + + ['@test Query param without value are empty string'](assert) { + assert.expect(1); + + this.add( + 'controller:index', + Controller.extend({ + queryParams: ['foo'], + foo: '' + }) + ); + + return this.visit('/?foo=').then(() => { + let controller = this.getController('index'); + assert.equal(controller.get('foo'), ''); + }); + } - ['@test Array query params can be set'](assert) { - assert.expect(2); + ['@test Array query params can be set'](assert) { + assert.expect(2); - this.router.map(function() { - this.route('home', { path: '/' }); - }); + this.router.map(function() { + this.route('home', { path: '/' }); + }); - this.setSingleQPController('home', 'foo', []); + this.setSingleQPController('home', 'foo', []); - return this.visit('/').then(() => { - let controller = this.getController('home'); + return this.visit('/').then(() => { + let controller = this.getController('home'); - this.setAndFlush(controller, 'foo', [1, 2]); - this.assertCurrentPath('/?foo=%5B1%2C2%5D'); + this.setAndFlush(controller, 'foo', [1, 2]); + this.assertCurrentPath('/?foo=%5B1%2C2%5D'); - this.setAndFlush(controller, 'foo', [3, 4]); - this.assertCurrentPath('/?foo=%5B3%2C4%5D'); - }); - } + this.setAndFlush(controller, 'foo', [3, 4]); + this.assertCurrentPath('/?foo=%5B3%2C4%5D'); + }); + } - ['@test (de)serialization: arrays'](assert) { - assert.expect(4); + ['@test (de)serialization: arrays'](assert) { + assert.expect(4); - this.setSingleQPController('index', 'foo', [1]); + this.setSingleQPController('index', 'foo', [1]); - return this.visitAndAssert('/').then(() => { - this.transitionTo({ queryParams: { foo: [2, 3] } }); - this.assertCurrentPath('/?foo=%5B2%2C3%5D', 'shorthand supported'); - this.transitionTo({ queryParams: { 'index:foo': [4, 5] } }); - this.assertCurrentPath('/?foo=%5B4%2C5%5D', 'longform supported'); - this.transitionTo({ queryParams: { foo: [] } }); - this.assertCurrentPath('/?foo=%5B%5D', 'longform supported'); - }); - } + return this.visitAndAssert('/').then(() => { + this.transitionTo({ queryParams: { foo: [2, 3] } }); + this.assertCurrentPath('/?foo=%5B2%2C3%5D', 'shorthand supported'); + this.transitionTo({ queryParams: { 'index:foo': [4, 5] } }); + this.assertCurrentPath('/?foo=%5B4%2C5%5D', 'longform supported'); + this.transitionTo({ queryParams: { foo: [] } }); + this.assertCurrentPath('/?foo=%5B%5D', 'longform supported'); + }); + } - ['@test Url with array query param sets controller property to array'](assert) { - assert.expect(1); + ['@test Url with array query param sets controller property to array']( + assert + ) { + assert.expect(1); - this.setSingleQPController('index', 'foo', ''); + this.setSingleQPController('index', 'foo', ''); - return this.visit('/?foo[]=1&foo[]=2&foo[]=3').then(() => { - let controller = this.getController('index'); - assert.deepEqual(controller.get('foo'), ['1', '2', '3']); - }); - } + return this.visit('/?foo[]=1&foo[]=2&foo[]=3').then(() => { + let controller = this.getController('index'); + assert.deepEqual(controller.get('foo'), ['1', '2', '3']); + }); + } - ['@test Array query params can be pushed/popped'](assert) { - assert.expect(17); + ['@test Array query params can be pushed/popped'](assert) { + assert.expect(17); - this.router.map(function() { - this.route('home', { path: '/' }); - }); + this.router.map(function() { + this.route('home', { path: '/' }); + }); - this.setSingleQPController('home', 'foo', emberA()); + this.setSingleQPController('home', 'foo', emberA()); - return this.visitAndAssert('/').then(() => { - let controller = this.getController('home'); + return this.visitAndAssert('/').then(() => { + let controller = this.getController('home'); - run(controller.foo, 'pushObject', 1); - this.assertCurrentPath('/?foo=%5B1%5D'); - assert.deepEqual(controller.foo, [1]); + run(controller.foo, 'pushObject', 1); + this.assertCurrentPath('/?foo=%5B1%5D'); + assert.deepEqual(controller.foo, [1]); - run(controller.foo, 'popObject'); - this.assertCurrentPath('/'); - assert.deepEqual(controller.foo, []); + run(controller.foo, 'popObject'); + this.assertCurrentPath('/'); + assert.deepEqual(controller.foo, []); - run(controller.foo, 'pushObject', 1); - this.assertCurrentPath('/?foo=%5B1%5D'); - assert.deepEqual(controller.foo, [1]); + run(controller.foo, 'pushObject', 1); + this.assertCurrentPath('/?foo=%5B1%5D'); + assert.deepEqual(controller.foo, [1]); - run(controller.foo, 'popObject'); - this.assertCurrentPath('/'); - assert.deepEqual(controller.foo, []); + run(controller.foo, 'popObject'); + this.assertCurrentPath('/'); + assert.deepEqual(controller.foo, []); - run(controller.foo, 'pushObject', 1); - this.assertCurrentPath('/?foo=%5B1%5D'); - assert.deepEqual(controller.foo, [1]); + run(controller.foo, 'pushObject', 1); + this.assertCurrentPath('/?foo=%5B1%5D'); + assert.deepEqual(controller.foo, [1]); - run(controller.foo, 'pushObject', 2); - this.assertCurrentPath('/?foo=%5B1%2C2%5D'); - assert.deepEqual(controller.foo, [1, 2]); + run(controller.foo, 'pushObject', 2); + this.assertCurrentPath('/?foo=%5B1%2C2%5D'); + assert.deepEqual(controller.foo, [1, 2]); - run(controller.foo, 'popObject'); - this.assertCurrentPath('/?foo=%5B1%5D'); - assert.deepEqual(controller.foo, [1]); + run(controller.foo, 'popObject'); + this.assertCurrentPath('/?foo=%5B1%5D'); + assert.deepEqual(controller.foo, [1]); - run(controller.foo, 'unshiftObject', 'lol'); - this.assertCurrentPath('/?foo=%5B%22lol%22%2C1%5D'); - assert.deepEqual(controller.foo, ['lol', 1]); - }); - } + run(controller.foo, 'unshiftObject', 'lol'); + this.assertCurrentPath('/?foo=%5B%22lol%22%2C1%5D'); + assert.deepEqual(controller.foo, ['lol', 1]); + }); + } - ['@test Overwriting with array with same content shouldn\'t refire update'](assert) { - assert.expect(4); + ["@test Overwriting with array with same content shouldn't refire update"]( + assert + ) { + assert.expect(4); - this.router.map(function() { - this.route('home', { path: '/' }); - }); + this.router.map(function() { + this.route('home', { path: '/' }); + }); - let modelCount = 0; - this.add('route:home', Route.extend({ - model() { - modelCount++; - } - })); + let modelCount = 0; + this.add( + 'route:home', + Route.extend({ + model() { + modelCount++; + } + }) + ); - this.setSingleQPController('home', 'foo', emberA([1])); + this.setSingleQPController('home', 'foo', emberA([1])); - return this.visitAndAssert('/').then(() => { - assert.equal(modelCount, 1); + return this.visitAndAssert('/').then(() => { + assert.equal(modelCount, 1); - let controller = this.getController('home'); - this.setAndFlush(controller, 'model', emberA([1])); + let controller = this.getController('home'); + this.setAndFlush(controller, 'model', emberA([1])); - assert.equal(modelCount, 1); - this.assertCurrentPath('/'); - }); - } + assert.equal(modelCount, 1); + this.assertCurrentPath('/'); + }); + } - ['@test Defaulting to params hash as the model should not result in that params object being watched'](assert) { - assert.expect(1); - - this.router.map(function() { - this.route('other'); - }); - - // This causes the params hash, which is returned as a route's - // model if no other model could be resolved given the provided - // params (and no custom model hook was defined), to be watched, - // unless we return a copy of the params hash. - this.setSingleQPController('application', 'woot', 'wat'); - - this.add('route:other', Route.extend({ - model(p, trans) { - let m = peekMeta(trans.params.application); - assert.ok(m === undefined, 'A meta object isn\'t constructed for this params POJO'); - } - })); - - return this.visit('/').then(() => { - this.transitionTo('other'); - }); - } + ['@test Defaulting to params hash as the model should not result in that params object being watched']( + assert + ) { + assert.expect(1); - ['@test Setting bound query param property to null or undefined does not serialize to url'](assert) { - assert.expect(9); + this.router.map(function() { + this.route('other'); + }); - this.router.map(function() { - this.route('home'); - }); + // This causes the params hash, which is returned as a route's + // model if no other model could be resolved given the provided + // params (and no custom model hook was defined), to be watched, + // unless we return a copy of the params hash. + this.setSingleQPController('application', 'woot', 'wat'); + + this.add( + 'route:other', + Route.extend({ + model(p, trans) { + let m = peekMeta(trans.params.application); + assert.ok( + m === undefined, + "A meta object isn't constructed for this params POJO" + ); + } + }) + ); + + return this.visit('/').then(() => { + this.transitionTo('other'); + }); + } - this.setSingleQPController('home', 'foo', [1, 2]); + ['@test Setting bound query param property to null or undefined does not serialize to url']( + assert + ) { + assert.expect(9); - return this.visitAndAssert('/home').then(() => { - var controller = this.getController('home'); + this.router.map(function() { + this.route('home'); + }); - assert.deepEqual(controller.get('foo'), [1,2]); - this.assertCurrentPath('/home'); + this.setSingleQPController('home', 'foo', [1, 2]); - this.setAndFlush(controller, 'foo', emberA([1,3])); - this.assertCurrentPath('/home?foo=%5B1%2C3%5D'); + return this.visitAndAssert('/home').then(() => { + var controller = this.getController('home'); - return this.transitionTo('/home').then(() => { - assert.deepEqual(controller.get('foo'), [1,2]); + assert.deepEqual(controller.get('foo'), [1, 2]); this.assertCurrentPath('/home'); - this.setAndFlush(controller, 'foo', null); - this.assertCurrentPath('/home', 'Setting property to null'); - - this.setAndFlush(controller, 'foo', emberA([1,3])); + this.setAndFlush(controller, 'foo', emberA([1, 3])); this.assertCurrentPath('/home?foo=%5B1%2C3%5D'); - this.setAndFlush(controller, 'foo', undefined); - this.assertCurrentPath('/home', 'Setting property to undefined'); - }); - }); - } - - ['@test {{link-to}} with null or undefined QPs does not get serialized into url'](assert) { - assert.expect(3); - - this.addTemplate('home', '{{link-to \'Home\' \'home\' (query-params foo=nullValue) id=\'null-link\'}}{{link-to \'Home\' \'home\' (query-params foo=undefinedValue) id=\'undefined-link\'}}'); - - this.router.map(function() { - this.route('home'); - }); - - this.setSingleQPController('home', 'foo', [], { - nullValue: null, - undefinedValue: undefined - }); - - return this.visitAndAssert('/home').then(() => { - assert.equal(this.$('#null-link').attr('href'), '/home'); - assert.equal(this.$('#undefined-link').attr('href'), '/home'); - }); - } - - ['@test A child of a resource route still defaults to parent route\'s model even if the child route has a query param'](assert) { - assert.expect(2); - - this.setSingleQPController('index', 'woot', undefined, { - woot: undefined - }); - - this.add('route:application', Route.extend({ - model(/* p, trans */) { - return { woot: true }; - } - })); + return this.transitionTo('/home').then(() => { + assert.deepEqual(controller.get('foo'), [1, 2]); + this.assertCurrentPath('/home'); - this.add('route:index', Route.extend({ - setupController(controller, model) { - assert.deepEqual(model, { woot: true }, 'index route inherited model route from parent route'); - } - })); - - return this.visitAndAssert('/'); - } + this.setAndFlush(controller, 'foo', null); + this.assertCurrentPath('/home', 'Setting property to null'); - ['@test opting into replace does not affect transitions between routes'](assert) { - assert.expect(5); + this.setAndFlush(controller, 'foo', emberA([1, 3])); + this.assertCurrentPath('/home?foo=%5B1%2C3%5D'); - this.addTemplate('application', '{{link-to \'Foo\' \'foo\' id=\'foo-link\'}}{{link-to \'Bar\' \'bar\' id=\'bar-no-qp-link\'}}{{link-to \'Bar\' \'bar\' (query-params raytiley=\'isthebest\') id=\'bar-link\'}}{{outlet}}'); + this.setAndFlush(controller, 'foo', undefined); + this.assertCurrentPath('/home', 'Setting property to undefined'); + }); + }); + } - this.router.map(function() { - this.route('foo'); - this.route('bar'); - }); + ['@test {{link-to}} with null or undefined QPs does not get serialized into url']( + assert + ) { + assert.expect(3); - this.setSingleQPController('bar', 'raytiley', 'israd'); + this.addTemplate( + 'home', + "{{link-to 'Home' 'home' (query-params foo=nullValue) id='null-link'}}{{link-to 'Home' 'home' (query-params foo=undefinedValue) id='undefined-link'}}" + ); - this.add('route:bar', Route.extend({ - queryParams: { - raytiley: { - replace: true - } - } - })); + this.router.map(function() { + this.route('home'); + }); - return this.visit('/').then(() => { - let controller = this.getController('bar'); + this.setSingleQPController('home', 'foo', [], { + nullValue: null, + undefinedValue: undefined + }); - this.expectedPushURL = '/foo'; - run(document.getElementById('foo-link'), 'click'); + return this.visitAndAssert('/home').then(() => { + assert.equal(this.$('#null-link').attr('href'), '/home'); + assert.equal(this.$('#undefined-link').attr('href'), '/home'); + }); + } - this.expectedPushURL = '/bar'; - run(document.getElementById('bar-no-qp-link'), 'click'); + ["@test A child of a resource route still defaults to parent route's model even if the child route has a query param"]( + assert + ) { + assert.expect(2); - this.expectedReplaceURL = '/bar?raytiley=woot'; - this.setAndFlush(controller, 'raytiley', 'woot'); + this.setSingleQPController('index', 'woot', undefined, { + woot: undefined + }); - this.expectedPushURL = '/foo'; - run(document.getElementById('foo-link'), 'click'); + this.add( + 'route:application', + Route.extend({ + model(/* p, trans */) { + return { woot: true }; + } + }) + ); + + this.add( + 'route:index', + Route.extend({ + setupController(controller, model) { + assert.deepEqual( + model, + { woot: true }, + 'index route inherited model route from parent route' + ); + } + }) + ); + + return this.visitAndAssert('/'); + } + + ['@test opting into replace does not affect transitions between routes']( + assert + ) { + assert.expect(5); + + this.addTemplate( + 'application', + "{{link-to 'Foo' 'foo' id='foo-link'}}{{link-to 'Bar' 'bar' id='bar-no-qp-link'}}{{link-to 'Bar' 'bar' (query-params raytiley='isthebest') id='bar-link'}}{{outlet}}" + ); + + this.router.map(function() { + this.route('foo'); + this.route('bar'); + }); - this.expectedPushURL = '/bar?raytiley=isthebest'; - run(document.getElementById('bar-link'), 'click'); - }); - } + this.setSingleQPController('bar', 'raytiley', 'israd'); - ['@test undefined isn\'t serialized or deserialized into a string'](assert) { - assert.expect(4); + this.add( + 'route:bar', + Route.extend({ + queryParams: { + raytiley: { + replace: true + } + } + }) + ); - this.router.map(function() { - this.route('example'); - }); + return this.visit('/').then(() => { + let controller = this.getController('bar'); - this.addTemplate('application', '{{link-to \'Example\' \'example\' (query-params foo=undefined) id=\'the-link\'}}'); + this.expectedPushURL = '/foo'; + run(document.getElementById('foo-link'), 'click'); - this.setSingleQPController('example', 'foo', undefined, { - foo: undefined - }); + this.expectedPushURL = '/bar'; + run(document.getElementById('bar-no-qp-link'), 'click'); - this.add('route:example', Route.extend({ - model(params) { - assert.deepEqual(params, { foo: undefined }); - } - })); + this.expectedReplaceURL = '/bar?raytiley=woot'; + this.setAndFlush(controller, 'raytiley', 'woot'); - return this.visitAndAssert('/').then(() => { - assert.equal(this.$('#the-link').attr('href'), '/example', 'renders without undefined qp serialized'); + this.expectedPushURL = '/foo'; + run(document.getElementById('foo-link'), 'click'); - return this.transitionTo('example', { queryParams: { foo: undefined } }).then(() => { - this.assertCurrentPath('/example'); + this.expectedPushURL = '/bar?raytiley=isthebest'; + run(document.getElementById('bar-link'), 'click'); }); - }); - } - - ['@test when refreshModel is true and loading hook is undefined, model hook will rerun when QPs change even if previous did not finish']() { - return this.refreshModelWhileLoadingTest(); - } - - ['@test when refreshModel is true and loading hook returns false, model hook will rerun when QPs change even if previous did not finish']() { - return this.refreshModelWhileLoadingTest(false); - } + } - ['@test when refreshModel is true and loading hook returns true, model hook will rerun when QPs change even if previous did not finish']() { - return this.refreshModelWhileLoadingTest(true); - } + ["@test undefined isn't serialized or deserialized into a string"](assert) { + assert.expect(4); - ['@test warn user that Route\'s queryParams configuration must be an Object, not an Array'](assert) { - assert.expect(1); + this.router.map(function() { + this.route('example'); + }); - this.add('route:application', Route.extend({ - queryParams: [ - { commitBy: { replace: true } } - ] - })); + this.addTemplate( + 'application', + "{{link-to 'Example' 'example' (query-params foo=undefined) id='the-link'}}" + ); - expectAssertion(() => { - this.visit('/'); - }, 'You passed in `[{"commitBy":{"replace":true}}]` as the value for `queryParams` but `queryParams` cannot be an Array'); - } - - ['@test handle route names that clash with Object.prototype properties'](assert) { - assert.expect(1); + this.setSingleQPController('example', 'foo', undefined, { + foo: undefined + }); - this.router.map(function() { - this.route('constructor'); - }); + this.add( + 'route:example', + Route.extend({ + model(params) { + assert.deepEqual(params, { foo: undefined }); + } + }) + ); + + return this.visitAndAssert('/').then(() => { + assert.equal( + this.$('#the-link').attr('href'), + '/example', + 'renders without undefined qp serialized' + ); + + return this.transitionTo('example', { + queryParams: { foo: undefined } + }).then(() => { + this.assertCurrentPath('/example'); + }); + }); + } + + ['@test when refreshModel is true and loading hook is undefined, model hook will rerun when QPs change even if previous did not finish']() { + return this.refreshModelWhileLoadingTest(); + } + + ['@test when refreshModel is true and loading hook returns false, model hook will rerun when QPs change even if previous did not finish']() { + return this.refreshModelWhileLoadingTest(false); + } + + ['@test when refreshModel is true and loading hook returns true, model hook will rerun when QPs change even if previous did not finish']() { + return this.refreshModelWhileLoadingTest(true); + } + + ["@test warn user that Route's queryParams configuration must be an Object, not an Array"]( + assert + ) { + assert.expect(1); + + this.add( + 'route:application', + Route.extend({ + queryParams: [{ commitBy: { replace: true } }] + }) + ); + + expectAssertion(() => { + this.visit('/'); + }, 'You passed in `[{"commitBy":{"replace":true}}]` as the value for `queryParams` but `queryParams` cannot be an Array'); + } + + ['@test handle route names that clash with Object.prototype properties']( + assert + ) { + assert.expect(1); + + this.router.map(function() { + this.route('constructor'); + }); - this.add('route:constructor', Route.extend({ - queryParams: { - foo: { - defaultValue: '123' - } - } - })); - - return this.visit('/').then(() => { - this.transitionTo('constructor', { queryParams: { foo: '999' } }); - let controller = this.getController('constructor'); - assert.equal(get(controller, 'foo'), '999'); - }); + this.add( + 'route:constructor', + Route.extend({ + queryParams: { + foo: { + defaultValue: '123' + } + } + }) + ); + + return this.visit('/').then(() => { + this.transitionTo('constructor', { queryParams: { foo: '999' } }); + let controller = this.getController('constructor'); + assert.equal(get(controller, 'foo'), '999'); + }); + } } -}); +); diff --git a/packages/ember/tests/routing/query_params_test/model_dependent_state_with_query_params_test.js b/packages/ember/tests/routing/query_params_test/model_dependent_state_with_query_params_test.js index 04fa5cc32b7..51e0168fb8a 100644 --- a/packages/ember/tests/routing/query_params_test/model_dependent_state_with_query_params_test.js +++ b/packages/ember/tests/routing/query_params_test/model_dependent_state_with_query_params_test.js @@ -1,7 +1,4 @@ -import { - Controller, - A as emberA -} from 'ember-runtime'; +import { Controller, A as emberA } from 'ember-runtime'; import { Route } from 'ember-routing'; import { run, computed } from 'ember-metal'; import { QueryParamTestCase, moduleFor } from 'internal-test-helpers'; @@ -14,7 +11,10 @@ class ModelDependentQPTestCase extends QueryParamTestCase { teardown() { super.teardown(...arguments); - this.assert.ok(!this.expectedModelHookParams, 'there should be no pending expectation of expected model hook params'); + this.assert.ok( + !this.expectedModelHookParams, + 'there should be no pending expectation of expected model hook params' + ); } reopenController(name, options) { @@ -70,7 +70,11 @@ class ModelDependentQPTestCase extends QueryParamTestCase { this.expectedModelHookParams = { id: 'a-2', q: 'lol', z: 0 }; this.transitionTo(`${urlPrefix}/a-2?q=lol`); - assert.deepEqual(this.controller.get('model'), { id: 'a-2' }, 'controller\'s model changed to a-2'); + assert.deepEqual( + this.controller.get('model'), + { id: 'a-2' }, + "controller's model changed to a-2" + ); assert.equal(this.controller.get('q'), 'lol'); assert.equal(this.controller.get('z'), 0); assert.equal(this.$link1.getAttribute('href'), `${urlPrefix}/a-1?q=lol`); @@ -84,7 +88,10 @@ class ModelDependentQPTestCase extends QueryParamTestCase { assert.equal(this.controller.get('z'), 123); assert.equal(this.$link1.getAttribute('href'), `${urlPrefix}/a-1?q=lol`); assert.equal(this.$link2.getAttribute('href'), `${urlPrefix}/a-2?q=lol`); - assert.equal(this.$link3.getAttribute('href'), `${urlPrefix}/a-3?q=lol&z=123`); + assert.equal( + this.$link3.getAttribute('href'), + `${urlPrefix}/a-3?q=lol&z=123` + ); }); } @@ -93,7 +100,10 @@ class ModelDependentQPTestCase extends QueryParamTestCase { assert.expect(32); - this.addTemplate('application', `{{#each articles as |a|}} {{link-to 'Article' '${articleLookup}' a.id id=a.id}} {{/each}}`); + this.addTemplate( + 'application', + `{{#each articles as |a|}} {{link-to 'Article' '${articleLookup}' a.id id=a.id}} {{/each}}` + ); return this.boot().then(() => { this.expectedModelHookParams = { id: 'a-1', q: 'wat', z: 0 }; @@ -133,7 +143,10 @@ class ModelDependentQPTestCase extends QueryParamTestCase { assert.equal(this.controller.get('q'), 'lol'); assert.equal(this.controller.get('z'), 1); assert.equal(this.$link1.getAttribute('href'), `${urlPrefix}/a-1`); - assert.equal(this.$link2.getAttribute('href'), `${urlPrefix}/a-2?q=lol&z=1`); + assert.equal( + this.$link2.getAttribute('href'), + `${urlPrefix}/a-2?q=lol&z=1` + ); assert.equal(this.$link3.getAttribute('href'), `${urlPrefix}/a-3?q=hay`); }); } @@ -178,13 +191,19 @@ class ModelDependentQPTestCase extends QueryParamTestCase { assert.equal(this.$link1.getAttribute('href'), `${urlPrefix}/a-1?q=haha`); assert.equal(this.$link2.getAttribute('href'), `${urlPrefix}/a-2?q=haha`); - assert.equal(this.$link3.getAttribute('href'), `${urlPrefix}/a-3?q=haha&z=123`); + assert.equal( + this.$link3.getAttribute('href'), + `${urlPrefix}/a-3?q=haha&z=123` + ); this.setAndFlush(this.controller, 'q', 'woot'); assert.equal(this.$link1.getAttribute('href'), `${urlPrefix}/a-1?q=woot`); assert.equal(this.$link2.getAttribute('href'), `${urlPrefix}/a-2?q=woot`); - assert.equal(this.$link3.getAttribute('href'), `${urlPrefix}/a-3?q=woot&z=123`); + assert.equal( + this.$link3.getAttribute('href'), + `${urlPrefix}/a-3?q=woot&z=123` + ); }); } @@ -232,7 +251,10 @@ class ModelDependentQPTestCase extends QueryParamTestCase { } }); - this.addTemplate('about', `{{link-to 'A' '${commentsLookup}' 'a-1' id='one'}} {{link-to 'B' '${commentsLookup}' 'a-2' id='two'}}`); + this.addTemplate( + 'about', + `{{link-to 'A' '${commentsLookup}' 'a-1' id='one'}} {{link-to 'B' '${commentsLookup}' 'a-2' id='two'}}` + ); return this.visitApplication().then(() => { this.transitionTo(commentsLookup, 'a-1'); @@ -254,586 +276,1241 @@ class ModelDependentQPTestCase extends QueryParamTestCase { assert.equal(commentsCtrl.get('page'), 1); this.transitionTo('about'); - assert.equal(document.getElementById('one').getAttribute('href'), `${urlPrefix}/a-1/comments?q=imdone`); - assert.equal(document.getElementById('two').getAttribute('href'), `${urlPrefix}/a-2/comments`); + assert.equal( + document.getElementById('one').getAttribute('href'), + `${urlPrefix}/a-1/comments?q=imdone` + ); + assert.equal( + document.getElementById('two').getAttribute('href'), + `${urlPrefix}/a-2/comments` + ); }); } } -moduleFor('Query Params - model-dependent state', class extends ModelDependentQPTestCase { - setupApplication() { - this.router.map(function() { - this.route('article', { path: '/a/:id' }, function() { - this.route('comments', { resetNamespace: true }); +moduleFor( + 'Query Params - model-dependent state', + class extends ModelDependentQPTestCase { + setupApplication() { + this.router.map(function() { + this.route('article', { path: '/a/:id' }, function() { + this.route('comments', { resetNamespace: true }); + }); + this.route('about'); }); - this.route('about'); - }); - - let articles = emberA([{ id: 'a-1' }, { id: 'a-2' }, { id: 'a-3' }]); - - this.add('controller:application', Controller.extend({ - articles - })); - - let self = this; - let assert = this.assert; - this.add('route:article', Route.extend({ - model(params) { - if (self.expectedModelHookParams) { - assert.deepEqual(params, self.expectedModelHookParams, 'the ArticleRoute model hook received the expected merged dynamic segment + query params hash'); - self.expectedModelHookParams = null; - } - return articles.findBy('id', params.id); - } - })); - this.add('controller:article', Controller.extend({ - queryParams: ['q', 'z'], - q: 'wat', - z: 0 - })); + let articles = emberA([{ id: 'a-1' }, { id: 'a-2' }, { id: 'a-3' }]); - this.add('controller:comments', Controller.extend({ - queryParams: 'page', - page: 1 - })); + this.add( + 'controller:application', + Controller.extend({ + articles + }) + ); - this.addTemplate('application', '{{#each articles as |a|}} 1{{link-to \'Article\' \'article\' a id=a.id}} {{/each}} {{outlet}}'); - } - - visitApplication() { - return this.visit('/').then(() => { + let self = this; let assert = this.assert; + this.add( + 'route:article', + Route.extend({ + model(params) { + if (self.expectedModelHookParams) { + assert.deepEqual( + params, + self.expectedModelHookParams, + 'the ArticleRoute model hook received the expected merged dynamic segment + query params hash' + ); + self.expectedModelHookParams = null; + } + return articles.findBy('id', params.id); + } + }) + ); + + this.add( + 'controller:article', + Controller.extend({ + queryParams: ['q', 'z'], + q: 'wat', + z: 0 + }) + ); + + this.add( + 'controller:comments', + Controller.extend({ + queryParams: 'page', + page: 1 + }) + ); + + this.addTemplate( + 'application', + "{{#each articles as |a|}} 1{{link-to 'Article' 'article' a id=a.id}} {{/each}} {{outlet}}" + ); + } + + visitApplication() { + return this.visit('/').then(() => { + let assert = this.assert; + + this.$link1 = document.getElementById('a-1'); + this.$link2 = document.getElementById('a-2'); + this.$link3 = document.getElementById('a-3'); + + assert.equal(this.$link1.getAttribute('href'), '/a/a-1'); + assert.equal(this.$link2.getAttribute('href'), '/a/a-2'); + assert.equal(this.$link3.getAttribute('href'), '/a/a-3'); + + this.controller = this.getController('article'); + }); + } - this.$link1 = document.getElementById('a-1'); - this.$link2 = document.getElementById('a-2'); - this.$link3 = document.getElementById('a-3'); - - assert.equal(this.$link1.getAttribute('href'), '/a/a-1'); - assert.equal(this.$link2.getAttribute('href'), '/a/a-2'); - assert.equal(this.$link3.getAttribute('href'), '/a/a-3'); + ["@test query params have 'model' stickiness by default"]() { + return this.queryParamsStickyTest1('/a'); + } - this.controller = this.getController('article'); - }); - } + ["@test query params have 'model' stickiness by default (url changes)"]() { + return this.queryParamsStickyTest2('/a'); + } - ['@test query params have \'model\' stickiness by default']() { - return this.queryParamsStickyTest1('/a'); - } + ["@test query params have 'model' stickiness by default (params-based transitions)"]() { + return this.queryParamsStickyTest3('/a', 'article'); + } - ['@test query params have \'model\' stickiness by default (url changes)']() { - return this.queryParamsStickyTest2('/a'); - } + ["@test 'controller' stickiness shares QP state between models"]() { + return this.queryParamsStickyTest4('/a', 'article'); + } - ['@test query params have \'model\' stickiness by default (params-based transitions)']() { - return this.queryParamsStickyTest3('/a', 'article'); - } + ["@test 'model' stickiness is scoped to current or first dynamic parent route"]() { + return this.queryParamsStickyTest5('/a', 'comments'); + } - ['@test \'controller\' stickiness shares QP state between models']() { - return this.queryParamsStickyTest4('/a', 'article'); + ['@test can reset query params using the resetController hook']() { + return this.queryParamsStickyTest6('/a', 'article', 'comments'); + } } - - ['@test \'model\' stickiness is scoped to current or first dynamic parent route']() { - return this.queryParamsStickyTest5('/a', 'comments'); - } - - ['@test can reset query params using the resetController hook']() { - return this.queryParamsStickyTest6('/a', 'article', 'comments'); - } -}); - -moduleFor('Query Params - model-dependent state (nested)', class extends ModelDependentQPTestCase { - setupApplication() { - this.router.map(function() { - this.route('site', function() { - this.route('article', { path: '/a/:id' }, function() { - this.route('comments'); +); + +moduleFor( + 'Query Params - model-dependent state (nested)', + class extends ModelDependentQPTestCase { + setupApplication() { + this.router.map(function() { + this.route('site', function() { + this.route('article', { path: '/a/:id' }, function() { + this.route('comments'); + }); }); + this.route('about'); }); - this.route('about'); - }); - let site_articles = emberA([{ id: 'a-1' }, { id: 'a-2' }, { id: 'a-3' }]); + let site_articles = emberA([{ id: 'a-1' }, { id: 'a-2' }, { id: 'a-3' }]); - this.add('controller:application', Controller.extend({ - articles: site_articles - })); - - let self = this; - let assert = this.assert; - this.add('route:site.article', Route.extend({ - model(params) { - if (self.expectedModelHookParams) { - assert.deepEqual(params, self.expectedModelHookParams, 'the ArticleRoute model hook received the expected merged dynamic segment + query params hash'); - self.expectedModelHookParams = null; - } - return site_articles.findBy('id', params.id); - } - })); - - this.add('controller:site.article', Controller.extend({ - queryParams: ['q', 'z'], - q: 'wat', - z: 0 - })); - - this.add('controller:site.article.comments', Controller.extend({ - queryParams: 'page', - page: 1 - })); - - this.addTemplate('application', '{{#each articles as |a|}} {{link-to \'Article\' \'site.article\' a id=a.id}} {{/each}} {{outlet}}'); - } + this.add( + 'controller:application', + Controller.extend({ + articles: site_articles + }) + ); - visitApplication() { - return this.visit('/').then(() => { + let self = this; let assert = this.assert; - - this.$link1 = document.getElementById('a-1'); - this.$link2 = document.getElementById('a-2'); - this.$link3 = document.getElementById('a-3'); - - assert.equal(this.$link1.getAttribute('href'), '/site/a/a-1'); - assert.equal(this.$link2.getAttribute('href'), '/site/a/a-2'); - assert.equal(this.$link3.getAttribute('href'), '/site/a/a-3'); - - this.controller = this.getController('site.article'); - }); - } - - ['@test query params have \'model\' stickiness by default']() { - return this.queryParamsStickyTest1('/site/a'); - } - - ['@test query params have \'model\' stickiness by default (url changes)']() { - return this.queryParamsStickyTest2('/site/a'); - } - - ['@test query params have \'model\' stickiness by default (params-based transitions)']() { - return this.queryParamsStickyTest3('/site/a', 'site.article'); - } - - ['@test \'controller\' stickiness shares QP state between models']() { - return this.queryParamsStickyTest4('/site/a', 'site.article'); - } - - ['@test \'model\' stickiness is scoped to current or first dynamic parent route']() { - return this.queryParamsStickyTest5('/site/a', 'site.article.comments'); - } - - ['@test can reset query params using the resetController hook']() { - return this.queryParamsStickyTest6('/site/a', 'site.article', 'site.article.comments'); + this.add( + 'route:site.article', + Route.extend({ + model(params) { + if (self.expectedModelHookParams) { + assert.deepEqual( + params, + self.expectedModelHookParams, + 'the ArticleRoute model hook received the expected merged dynamic segment + query params hash' + ); + self.expectedModelHookParams = null; + } + return site_articles.findBy('id', params.id); + } + }) + ); + + this.add( + 'controller:site.article', + Controller.extend({ + queryParams: ['q', 'z'], + q: 'wat', + z: 0 + }) + ); + + this.add( + 'controller:site.article.comments', + Controller.extend({ + queryParams: 'page', + page: 1 + }) + ); + + this.addTemplate( + 'application', + "{{#each articles as |a|}} {{link-to 'Article' 'site.article' a id=a.id}} {{/each}} {{outlet}}" + ); + } + + visitApplication() { + return this.visit('/').then(() => { + let assert = this.assert; + + this.$link1 = document.getElementById('a-1'); + this.$link2 = document.getElementById('a-2'); + this.$link3 = document.getElementById('a-3'); + + assert.equal(this.$link1.getAttribute('href'), '/site/a/a-1'); + assert.equal(this.$link2.getAttribute('href'), '/site/a/a-2'); + assert.equal(this.$link3.getAttribute('href'), '/site/a/a-3'); + + this.controller = this.getController('site.article'); + }); + } + + ["@test query params have 'model' stickiness by default"]() { + return this.queryParamsStickyTest1('/site/a'); + } + + ["@test query params have 'model' stickiness by default (url changes)"]() { + return this.queryParamsStickyTest2('/site/a'); + } + + ["@test query params have 'model' stickiness by default (params-based transitions)"]() { + return this.queryParamsStickyTest3('/site/a', 'site.article'); + } + + ["@test 'controller' stickiness shares QP state between models"]() { + return this.queryParamsStickyTest4('/site/a', 'site.article'); + } + + ["@test 'model' stickiness is scoped to current or first dynamic parent route"]() { + return this.queryParamsStickyTest5('/site/a', 'site.article.comments'); + } + + ['@test can reset query params using the resetController hook']() { + return this.queryParamsStickyTest6( + '/site/a', + 'site.article', + 'site.article.comments' + ); + } } -}); - -moduleFor('Query Params - model-dependent state (nested & more than 1 dynamic segment)', class extends ModelDependentQPTestCase { - setupApplication() { - this.router.map(function() { - this.route('site', { path: '/site/:site_id' }, function() { - this.route('article', { path: '/a/:article_id' }, function() { - this.route('comments'); +); + +moduleFor( + 'Query Params - model-dependent state (nested & more than 1 dynamic segment)', + class extends ModelDependentQPTestCase { + setupApplication() { + this.router.map(function() { + this.route('site', { path: '/site/:site_id' }, function() { + this.route('article', { path: '/a/:article_id' }, function() { + this.route('comments'); + }); }); }); - }); - - let sites = emberA([{ id: 's-1' }, { id: 's-2' }, { id: 's-3' }]); - let site_articles = emberA([{ id: 'a-1' }, { id: 'a-2' }, { id: 'a-3' }]); - - this.add('controller:application', Controller.extend({ - siteArticles: site_articles, - sites, - allSitesAllArticles: computed({ - get() { - let ret = []; - let siteArticles = this.siteArticles; - let sites = this.sites; - sites.forEach(site => { - ret = ret.concat(siteArticles.map((article) => { - return { id: `${site.id}-${article.id}`, site_id: site.id, article_id: article.id }; - })); - }); - return ret; - } - }) - })); - - let self = this; - let assert = this.assert; - this.add('route:site', Route.extend({ - model(params) { - if (self.expectedSiteModelHookParams) { - assert.deepEqual(params, self.expectedSiteModelHookParams, 'the SiteRoute model hook received the expected merged dynamic segment + query params hash'); - self.expectedSiteModelHookParams = null; - } - return sites.findBy('id', params.site_id); - } - })); - - this.add('route:site.article', Route.extend({ - model(params) { - if (self.expectedArticleModelHookParams) { - assert.deepEqual(params, self.expectedArticleModelHookParams, 'the SiteArticleRoute model hook received the expected merged dynamic segment + query params hash'); - self.expectedArticleModelHookParams = null; - } - return site_articles.findBy('id', params.article_id); - } - })); - - this.add('controller:site', Controller.extend({ - queryParams: ['country'], - country: 'au' - })); - - this.add('controller:site.article', Controller.extend({ - queryParams: ['q', 'z'], - q: 'wat', - z: 0 - })); - - this.add('controller:site.article.comments', Controller.extend({ - queryParams: ['page'], - page: 1 - })); - - this.addTemplate('application', '{{#each allSitesAllArticles as |a|}} {{#link-to \'site.article\' a.site_id a.article_id id=a.id}}Article [{{a.site_id}}] [{{a.article_id}}]{{/link-to}} {{/each}} {{outlet}}'); - } - visitApplication() { - return this.visit('/').then(() => { + let sites = emberA([{ id: 's-1' }, { id: 's-2' }, { id: 's-3' }]); + let site_articles = emberA([{ id: 'a-1' }, { id: 'a-2' }, { id: 'a-3' }]); + + this.add( + 'controller:application', + Controller.extend({ + siteArticles: site_articles, + sites, + allSitesAllArticles: computed({ + get() { + let ret = []; + let siteArticles = this.siteArticles; + let sites = this.sites; + sites.forEach(site => { + ret = ret.concat( + siteArticles.map(article => { + return { + id: `${site.id}-${article.id}`, + site_id: site.id, + article_id: article.id + }; + }) + ); + }); + return ret; + } + }) + }) + ); + + let self = this; let assert = this.assert; + this.add( + 'route:site', + Route.extend({ + model(params) { + if (self.expectedSiteModelHookParams) { + assert.deepEqual( + params, + self.expectedSiteModelHookParams, + 'the SiteRoute model hook received the expected merged dynamic segment + query params hash' + ); + self.expectedSiteModelHookParams = null; + } + return sites.findBy('id', params.site_id); + } + }) + ); + + this.add( + 'route:site.article', + Route.extend({ + model(params) { + if (self.expectedArticleModelHookParams) { + assert.deepEqual( + params, + self.expectedArticleModelHookParams, + 'the SiteArticleRoute model hook received the expected merged dynamic segment + query params hash' + ); + self.expectedArticleModelHookParams = null; + } + return site_articles.findBy('id', params.article_id); + } + }) + ); + + this.add( + 'controller:site', + Controller.extend({ + queryParams: ['country'], + country: 'au' + }) + ); + + this.add( + 'controller:site.article', + Controller.extend({ + queryParams: ['q', 'z'], + q: 'wat', + z: 0 + }) + ); + + this.add( + 'controller:site.article.comments', + Controller.extend({ + queryParams: ['page'], + page: 1 + }) + ); + + this.addTemplate( + 'application', + "{{#each allSitesAllArticles as |a|}} {{#link-to 'site.article' a.site_id a.article_id id=a.id}}Article [{{a.site_id}}] [{{a.article_id}}]{{/link-to}} {{/each}} {{outlet}}" + ); + } + + visitApplication() { + return this.visit('/').then(() => { + let assert = this.assert; + + this.links = {}; + this.links['s-1-a-1'] = document.getElementById('s-1-a-1'); + this.links['s-1-a-2'] = document.getElementById('s-1-a-2'); + this.links['s-1-a-3'] = document.getElementById('s-1-a-3'); + this.links['s-2-a-1'] = document.getElementById('s-2-a-1'); + this.links['s-2-a-2'] = document.getElementById('s-2-a-2'); + this.links['s-2-a-3'] = document.getElementById('s-2-a-3'); + this.links['s-3-a-1'] = document.getElementById('s-3-a-1'); + this.links['s-3-a-2'] = document.getElementById('s-3-a-2'); + this.links['s-3-a-3'] = document.getElementById('s-3-a-3'); + + assert.equal( + this.links['s-1-a-1'].getAttribute('href'), + '/site/s-1/a/a-1' + ); + assert.equal( + this.links['s-1-a-2'].getAttribute('href'), + '/site/s-1/a/a-2' + ); + assert.equal( + this.links['s-1-a-3'].getAttribute('href'), + '/site/s-1/a/a-3' + ); + assert.equal( + this.links['s-2-a-1'].getAttribute('href'), + '/site/s-2/a/a-1' + ); + assert.equal( + this.links['s-2-a-2'].getAttribute('href'), + '/site/s-2/a/a-2' + ); + assert.equal( + this.links['s-2-a-3'].getAttribute('href'), + '/site/s-2/a/a-3' + ); + assert.equal( + this.links['s-3-a-1'].getAttribute('href'), + '/site/s-3/a/a-1' + ); + assert.equal( + this.links['s-3-a-2'].getAttribute('href'), + '/site/s-3/a/a-2' + ); + assert.equal( + this.links['s-3-a-3'].getAttribute('href'), + '/site/s-3/a/a-3' + ); + + this.site_controller = this.getController('site'); + this.article_controller = this.getController('site.article'); + }); + } + + ["@test query params have 'model' stickiness by default"](assert) { + assert.expect(59); + + return this.boot().then(() => { + run(this.links['s-1-a-1'], 'click'); + assert.deepEqual(this.site_controller.get('model'), { id: 's-1' }); + assert.deepEqual(this.article_controller.get('model'), { id: 'a-1' }); + this.assertCurrentPath('/site/s-1/a/a-1'); + + this.setAndFlush(this.article_controller, 'q', 'lol'); + + assert.equal( + this.links['s-1-a-1'].getAttribute('href'), + '/site/s-1/a/a-1?q=lol' + ); + assert.equal( + this.links['s-1-a-2'].getAttribute('href'), + '/site/s-1/a/a-2' + ); + assert.equal( + this.links['s-1-a-3'].getAttribute('href'), + '/site/s-1/a/a-3' + ); + assert.equal( + this.links['s-2-a-1'].getAttribute('href'), + '/site/s-2/a/a-1?q=lol' + ); + assert.equal( + this.links['s-2-a-2'].getAttribute('href'), + '/site/s-2/a/a-2' + ); + assert.equal( + this.links['s-2-a-3'].getAttribute('href'), + '/site/s-2/a/a-3' + ); + assert.equal( + this.links['s-3-a-1'].getAttribute('href'), + '/site/s-3/a/a-1?q=lol' + ); + assert.equal( + this.links['s-3-a-2'].getAttribute('href'), + '/site/s-3/a/a-2' + ); + assert.equal( + this.links['s-3-a-3'].getAttribute('href'), + '/site/s-3/a/a-3' + ); + + this.setAndFlush(this.site_controller, 'country', 'us'); + + assert.equal( + this.links['s-1-a-1'].getAttribute('href'), + '/site/s-1/a/a-1?country=us&q=lol' + ); + assert.equal( + this.links['s-1-a-2'].getAttribute('href'), + '/site/s-1/a/a-2?country=us' + ); + assert.equal( + this.links['s-1-a-3'].getAttribute('href'), + '/site/s-1/a/a-3?country=us' + ); + assert.equal( + this.links['s-2-a-1'].getAttribute('href'), + '/site/s-2/a/a-1?q=lol' + ); + assert.equal( + this.links['s-2-a-2'].getAttribute('href'), + '/site/s-2/a/a-2' + ); + assert.equal( + this.links['s-2-a-3'].getAttribute('href'), + '/site/s-2/a/a-3' + ); + assert.equal( + this.links['s-3-a-1'].getAttribute('href'), + '/site/s-3/a/a-1?q=lol' + ); + assert.equal( + this.links['s-3-a-2'].getAttribute('href'), + '/site/s-3/a/a-2' + ); + assert.equal( + this.links['s-3-a-3'].getAttribute('href'), + '/site/s-3/a/a-3' + ); + + run(this.links['s-1-a-2'], 'click'); + + assert.equal(this.site_controller.get('country'), 'us'); + assert.equal(this.article_controller.get('q'), 'wat'); + assert.equal(this.article_controller.get('z'), 0); + assert.deepEqual(this.site_controller.get('model'), { id: 's-1' }); + assert.deepEqual(this.article_controller.get('model'), { id: 'a-2' }); + assert.equal( + this.links['s-1-a-1'].getAttribute('href'), + '/site/s-1/a/a-1?country=us&q=lol' + ); + assert.equal( + this.links['s-1-a-2'].getAttribute('href'), + '/site/s-1/a/a-2?country=us' + ); + assert.equal( + this.links['s-1-a-3'].getAttribute('href'), + '/site/s-1/a/a-3?country=us' + ); + assert.equal( + this.links['s-2-a-1'].getAttribute('href'), + '/site/s-2/a/a-1?q=lol' + ); + assert.equal( + this.links['s-2-a-2'].getAttribute('href'), + '/site/s-2/a/a-2' + ); + assert.equal( + this.links['s-2-a-3'].getAttribute('href'), + '/site/s-2/a/a-3' + ); + assert.equal( + this.links['s-3-a-1'].getAttribute('href'), + '/site/s-3/a/a-1?q=lol' + ); + assert.equal( + this.links['s-3-a-2'].getAttribute('href'), + '/site/s-3/a/a-2' + ); + assert.equal( + this.links['s-3-a-3'].getAttribute('href'), + '/site/s-3/a/a-3' + ); + + run(this.links['s-2-a-2'], 'click'); + + assert.equal(this.site_controller.get('country'), 'au'); + assert.equal(this.article_controller.get('q'), 'wat'); + assert.equal(this.article_controller.get('z'), 0); + assert.deepEqual(this.site_controller.get('model'), { id: 's-2' }); + assert.deepEqual(this.article_controller.get('model'), { id: 'a-2' }); + assert.equal( + this.links['s-1-a-1'].getAttribute('href'), + '/site/s-1/a/a-1?country=us&q=lol' + ); + assert.equal( + this.links['s-1-a-2'].getAttribute('href'), + '/site/s-1/a/a-2?country=us' + ); + assert.equal( + this.links['s-1-a-3'].getAttribute('href'), + '/site/s-1/a/a-3?country=us' + ); + assert.equal( + this.links['s-2-a-1'].getAttribute('href'), + '/site/s-2/a/a-1?q=lol' + ); + assert.equal( + this.links['s-2-a-2'].getAttribute('href'), + '/site/s-2/a/a-2' + ); + assert.equal( + this.links['s-2-a-3'].getAttribute('href'), + '/site/s-2/a/a-3' + ); + assert.equal( + this.links['s-3-a-1'].getAttribute('href'), + '/site/s-3/a/a-1?q=lol' + ); + assert.equal( + this.links['s-3-a-2'].getAttribute('href'), + '/site/s-3/a/a-2' + ); + assert.equal( + this.links['s-3-a-3'].getAttribute('href'), + '/site/s-3/a/a-3' + ); + }); + } + + ["@test query params have 'model' stickiness by default (url changes)"]( + assert + ) { + assert.expect(88); + + return this.boot().then(() => { + this.expectedSiteModelHookParams = { site_id: 's-1', country: 'au' }; + this.expectedArticleModelHookParams = { + article_id: 'a-1', + q: 'lol', + z: 0 + }; + this.transitionTo('/site/s-1/a/a-1?q=lol'); + + assert.deepEqual( + this.site_controller.get('model'), + { id: 's-1' }, + "site controller's model is s-1" + ); + assert.deepEqual( + this.article_controller.get('model'), + { id: 'a-1' }, + "article controller's model is a-1" + ); + assert.equal(this.site_controller.get('country'), 'au'); + assert.equal(this.article_controller.get('q'), 'lol'); + assert.equal(this.article_controller.get('z'), 0); + assert.equal( + this.links['s-1-a-1'].getAttribute('href'), + '/site/s-1/a/a-1?q=lol' + ); + assert.equal( + this.links['s-1-a-2'].getAttribute('href'), + '/site/s-1/a/a-2' + ); + assert.equal( + this.links['s-1-a-3'].getAttribute('href'), + '/site/s-1/a/a-3' + ); + assert.equal( + this.links['s-2-a-1'].getAttribute('href'), + '/site/s-2/a/a-1?q=lol' + ); + assert.equal( + this.links['s-2-a-2'].getAttribute('href'), + '/site/s-2/a/a-2' + ); + assert.equal( + this.links['s-2-a-3'].getAttribute('href'), + '/site/s-2/a/a-3' + ); + assert.equal( + this.links['s-3-a-1'].getAttribute('href'), + '/site/s-3/a/a-1?q=lol' + ); + assert.equal( + this.links['s-3-a-2'].getAttribute('href'), + '/site/s-3/a/a-2' + ); + assert.equal( + this.links['s-3-a-3'].getAttribute('href'), + '/site/s-3/a/a-3' + ); + + this.expectedSiteModelHookParams = { site_id: 's-2', country: 'us' }; + this.expectedArticleModelHookParams = { + article_id: 'a-1', + q: 'lol', + z: 0 + }; + this.transitionTo('/site/s-2/a/a-1?country=us&q=lol'); + + assert.deepEqual( + this.site_controller.get('model'), + { id: 's-2' }, + "site controller's model is s-2" + ); + assert.deepEqual( + this.article_controller.get('model'), + { id: 'a-1' }, + "article controller's model is a-1" + ); + assert.equal(this.site_controller.get('country'), 'us'); + assert.equal(this.article_controller.get('q'), 'lol'); + assert.equal(this.article_controller.get('z'), 0); + assert.equal( + this.links['s-1-a-1'].getAttribute('href'), + '/site/s-1/a/a-1?q=lol' + ); + assert.equal( + this.links['s-1-a-2'].getAttribute('href'), + '/site/s-1/a/a-2' + ); + assert.equal( + this.links['s-1-a-3'].getAttribute('href'), + '/site/s-1/a/a-3' + ); + assert.equal( + this.links['s-2-a-1'].getAttribute('href'), + '/site/s-2/a/a-1?country=us&q=lol' + ); + assert.equal( + this.links['s-2-a-2'].getAttribute('href'), + '/site/s-2/a/a-2?country=us' + ); + assert.equal( + this.links['s-2-a-3'].getAttribute('href'), + '/site/s-2/a/a-3?country=us' + ); + assert.equal( + this.links['s-3-a-1'].getAttribute('href'), + '/site/s-3/a/a-1?q=lol' + ); + assert.equal( + this.links['s-3-a-2'].getAttribute('href'), + '/site/s-3/a/a-2' + ); + assert.equal( + this.links['s-3-a-3'].getAttribute('href'), + '/site/s-3/a/a-3' + ); + + this.expectedSiteModelHookParams = { site_id: 's-2', country: 'us' }; + this.expectedArticleModelHookParams = { + article_id: 'a-2', + q: 'lol', + z: 0 + }; + this.transitionTo('/site/s-2/a/a-2?country=us&q=lol'); + + assert.deepEqual( + this.site_controller.get('model'), + { id: 's-2' }, + "site controller's model is s-2" + ); + assert.deepEqual( + this.article_controller.get('model'), + { id: 'a-2' }, + "article controller's model is a-2" + ); + assert.equal(this.site_controller.get('country'), 'us'); + assert.equal(this.article_controller.get('q'), 'lol'); + assert.equal(this.article_controller.get('z'), 0); + assert.equal( + this.links['s-1-a-1'].getAttribute('href'), + '/site/s-1/a/a-1?q=lol' + ); + assert.equal( + this.links['s-1-a-2'].getAttribute('href'), + '/site/s-1/a/a-2?q=lol' + ); + assert.equal( + this.links['s-1-a-3'].getAttribute('href'), + '/site/s-1/a/a-3' + ); + assert.equal( + this.links['s-2-a-1'].getAttribute('href'), + '/site/s-2/a/a-1?country=us&q=lol' + ); + assert.equal( + this.links['s-2-a-2'].getAttribute('href'), + '/site/s-2/a/a-2?country=us&q=lol' + ); + assert.equal( + this.links['s-2-a-3'].getAttribute('href'), + '/site/s-2/a/a-3?country=us' + ); + assert.equal( + this.links['s-3-a-1'].getAttribute('href'), + '/site/s-3/a/a-1?q=lol' + ); + assert.equal( + this.links['s-3-a-2'].getAttribute('href'), + '/site/s-3/a/a-2?q=lol' + ); + assert.equal( + this.links['s-3-a-3'].getAttribute('href'), + '/site/s-3/a/a-3' + ); + + this.expectedSiteModelHookParams = { site_id: 's-2', country: 'us' }; + this.expectedArticleModelHookParams = { + article_id: 'a-3', + q: 'lol', + z: 123 + }; + this.transitionTo('/site/s-2/a/a-3?country=us&q=lol&z=123'); + + assert.deepEqual( + this.site_controller.get('model'), + { id: 's-2' }, + "site controller's model is s-2" + ); + assert.deepEqual( + this.article_controller.get('model'), + { id: 'a-3' }, + "article controller's model is a-3" + ); + assert.equal(this.site_controller.get('country'), 'us'); + assert.equal(this.article_controller.get('q'), 'lol'); + assert.equal(this.article_controller.get('z'), 123); + assert.equal( + this.links['s-1-a-1'].getAttribute('href'), + '/site/s-1/a/a-1?q=lol' + ); + assert.equal( + this.links['s-1-a-2'].getAttribute('href'), + '/site/s-1/a/a-2?q=lol' + ); + assert.equal( + this.links['s-1-a-3'].getAttribute('href'), + '/site/s-1/a/a-3?q=lol&z=123' + ); + assert.equal( + this.links['s-2-a-1'].getAttribute('href'), + '/site/s-2/a/a-1?country=us&q=lol' + ); + assert.equal( + this.links['s-2-a-2'].getAttribute('href'), + '/site/s-2/a/a-2?country=us&q=lol' + ); + assert.equal( + this.links['s-2-a-3'].getAttribute('href'), + '/site/s-2/a/a-3?country=us&q=lol&z=123' + ); + assert.equal( + this.links['s-3-a-1'].getAttribute('href'), + '/site/s-3/a/a-1?q=lol' + ); + assert.equal( + this.links['s-3-a-2'].getAttribute('href'), + '/site/s-3/a/a-2?q=lol' + ); + assert.equal( + this.links['s-3-a-3'].getAttribute('href'), + '/site/s-3/a/a-3?q=lol&z=123' + ); + + this.expectedSiteModelHookParams = { site_id: 's-3', country: 'nz' }; + this.expectedArticleModelHookParams = { + article_id: 'a-3', + q: 'lol', + z: 123 + }; + this.transitionTo('/site/s-3/a/a-3?country=nz&q=lol&z=123'); + + assert.deepEqual( + this.site_controller.get('model'), + { id: 's-3' }, + "site controller's model is s-3" + ); + assert.deepEqual( + this.article_controller.get('model'), + { id: 'a-3' }, + "article controller's model is a-3" + ); + assert.equal(this.site_controller.get('country'), 'nz'); + assert.equal(this.article_controller.get('q'), 'lol'); + assert.equal(this.article_controller.get('z'), 123); + assert.equal( + this.links['s-1-a-1'].getAttribute('href'), + '/site/s-1/a/a-1?q=lol' + ); + assert.equal( + this.links['s-1-a-2'].getAttribute('href'), + '/site/s-1/a/a-2?q=lol' + ); + assert.equal( + this.links['s-1-a-3'].getAttribute('href'), + '/site/s-1/a/a-3?q=lol&z=123' + ); + assert.equal( + this.links['s-2-a-1'].getAttribute('href'), + '/site/s-2/a/a-1?country=us&q=lol' + ); + assert.equal( + this.links['s-2-a-2'].getAttribute('href'), + '/site/s-2/a/a-2?country=us&q=lol' + ); + assert.equal( + this.links['s-2-a-3'].getAttribute('href'), + '/site/s-2/a/a-3?country=us&q=lol&z=123' + ); + assert.equal( + this.links['s-3-a-1'].getAttribute('href'), + '/site/s-3/a/a-1?country=nz&q=lol' + ); + assert.equal( + this.links['s-3-a-2'].getAttribute('href'), + '/site/s-3/a/a-2?country=nz&q=lol' + ); + assert.equal( + this.links['s-3-a-3'].getAttribute('href'), + '/site/s-3/a/a-3?country=nz&q=lol&z=123' + ); + }); + } + + ["@test query params have 'model' stickiness by default (params-based transitions)"]( + assert + ) { + assert.expect(118); + + return this.boot().then(() => { + this.expectedSiteModelHookParams = { site_id: 's-1', country: 'au' }; + this.expectedArticleModelHookParams = { + article_id: 'a-1', + q: 'wat', + z: 0 + }; + this.transitionTo('site.article', 's-1', 'a-1'); + + assert.deepEqual(this.site_controller.get('model'), { id: 's-1' }); + assert.deepEqual(this.article_controller.get('model'), { id: 'a-1' }); + assert.equal(this.site_controller.get('country'), 'au'); + assert.equal(this.article_controller.get('q'), 'wat'); + assert.equal(this.article_controller.get('z'), 0); + assert.equal( + this.links['s-1-a-1'].getAttribute('href'), + '/site/s-1/a/a-1' + ); + assert.equal( + this.links['s-1-a-2'].getAttribute('href'), + '/site/s-1/a/a-2' + ); + assert.equal( + this.links['s-1-a-3'].getAttribute('href'), + '/site/s-1/a/a-3' + ); + assert.equal( + this.links['s-2-a-1'].getAttribute('href'), + '/site/s-2/a/a-1' + ); + assert.equal( + this.links['s-2-a-2'].getAttribute('href'), + '/site/s-2/a/a-2' + ); + assert.equal( + this.links['s-2-a-3'].getAttribute('href'), + '/site/s-2/a/a-3' + ); + assert.equal( + this.links['s-3-a-1'].getAttribute('href'), + '/site/s-3/a/a-1' + ); + assert.equal( + this.links['s-3-a-2'].getAttribute('href'), + '/site/s-3/a/a-2' + ); + assert.equal( + this.links['s-3-a-3'].getAttribute('href'), + '/site/s-3/a/a-3' + ); + + this.expectedSiteModelHookParams = { site_id: 's-1', country: 'au' }; + this.expectedArticleModelHookParams = { + article_id: 'a-2', + q: 'lol', + z: 0 + }; + this.transitionTo('site.article', 's-1', 'a-2', { + queryParams: { q: 'lol' } + }); - this.links = {}; - this.links['s-1-a-1'] = document.getElementById('s-1-a-1'); - this.links['s-1-a-2'] = document.getElementById('s-1-a-2'); - this.links['s-1-a-3'] = document.getElementById('s-1-a-3'); - this.links['s-2-a-1'] = document.getElementById('s-2-a-1'); - this.links['s-2-a-2'] = document.getElementById('s-2-a-2'); - this.links['s-2-a-3'] = document.getElementById('s-2-a-3'); - this.links['s-3-a-1'] = document.getElementById('s-3-a-1'); - this.links['s-3-a-2'] = document.getElementById('s-3-a-2'); - this.links['s-3-a-3'] = document.getElementById('s-3-a-3'); - - assert.equal(this.links['s-1-a-1'].getAttribute('href'), '/site/s-1/a/a-1'); - assert.equal(this.links['s-1-a-2'].getAttribute('href'), '/site/s-1/a/a-2'); - assert.equal(this.links['s-1-a-3'].getAttribute('href'), '/site/s-1/a/a-3'); - assert.equal(this.links['s-2-a-1'].getAttribute('href'), '/site/s-2/a/a-1'); - assert.equal(this.links['s-2-a-2'].getAttribute('href'), '/site/s-2/a/a-2'); - assert.equal(this.links['s-2-a-3'].getAttribute('href'), '/site/s-2/a/a-3'); - assert.equal(this.links['s-3-a-1'].getAttribute('href'), '/site/s-3/a/a-1'); - assert.equal(this.links['s-3-a-2'].getAttribute('href'), '/site/s-3/a/a-2'); - assert.equal(this.links['s-3-a-3'].getAttribute('href'), '/site/s-3/a/a-3'); - - this.site_controller = this.getController('site'); - this.article_controller = this.getController('site.article'); - }); - } - - ['@test query params have \'model\' stickiness by default'](assert) { - assert.expect(59); + assert.deepEqual(this.site_controller.get('model'), { id: 's-1' }); + assert.deepEqual(this.article_controller.get('model'), { id: 'a-2' }); + assert.equal(this.site_controller.get('country'), 'au'); + assert.equal(this.article_controller.get('q'), 'lol'); + assert.equal(this.article_controller.get('z'), 0); + assert.equal( + this.links['s-1-a-1'].getAttribute('href'), + '/site/s-1/a/a-1' + ); + assert.equal( + this.links['s-1-a-2'].getAttribute('href'), + '/site/s-1/a/a-2?q=lol' + ); + assert.equal( + this.links['s-1-a-3'].getAttribute('href'), + '/site/s-1/a/a-3' + ); + assert.equal( + this.links['s-2-a-1'].getAttribute('href'), + '/site/s-2/a/a-1' + ); + assert.equal( + this.links['s-2-a-2'].getAttribute('href'), + '/site/s-2/a/a-2?q=lol' + ); + assert.equal( + this.links['s-2-a-3'].getAttribute('href'), + '/site/s-2/a/a-3' + ); + assert.equal( + this.links['s-3-a-1'].getAttribute('href'), + '/site/s-3/a/a-1' + ); + assert.equal( + this.links['s-3-a-2'].getAttribute('href'), + '/site/s-3/a/a-2?q=lol' + ); + assert.equal( + this.links['s-3-a-3'].getAttribute('href'), + '/site/s-3/a/a-3' + ); + + this.expectedSiteModelHookParams = { site_id: 's-1', country: 'au' }; + this.expectedArticleModelHookParams = { + article_id: 'a-3', + q: 'hay', + z: 0 + }; + this.transitionTo('site.article', 's-1', 'a-3', { + queryParams: { q: 'hay' } + }); - return this.boot().then(() => { - run(this.links['s-1-a-1'], 'click'); - assert.deepEqual(this.site_controller.get('model'), { id: 's-1' }); - assert.deepEqual(this.article_controller.get('model'), { id: 'a-1' }); - this.assertCurrentPath('/site/s-1/a/a-1'); - - this.setAndFlush(this.article_controller, 'q', 'lol'); - - assert.equal(this.links['s-1-a-1'].getAttribute('href'), '/site/s-1/a/a-1?q=lol'); - assert.equal(this.links['s-1-a-2'].getAttribute('href'), '/site/s-1/a/a-2'); - assert.equal(this.links['s-1-a-3'].getAttribute('href'), '/site/s-1/a/a-3'); - assert.equal(this.links['s-2-a-1'].getAttribute('href'), '/site/s-2/a/a-1?q=lol'); - assert.equal(this.links['s-2-a-2'].getAttribute('href'), '/site/s-2/a/a-2'); - assert.equal(this.links['s-2-a-3'].getAttribute('href'), '/site/s-2/a/a-3'); - assert.equal(this.links['s-3-a-1'].getAttribute('href'), '/site/s-3/a/a-1?q=lol'); - assert.equal(this.links['s-3-a-2'].getAttribute('href'), '/site/s-3/a/a-2'); - assert.equal(this.links['s-3-a-3'].getAttribute('href'), '/site/s-3/a/a-3'); - - this.setAndFlush(this.site_controller, 'country', 'us'); - - assert.equal(this.links['s-1-a-1'].getAttribute('href'), '/site/s-1/a/a-1?country=us&q=lol'); - assert.equal(this.links['s-1-a-2'].getAttribute('href'), '/site/s-1/a/a-2?country=us'); - assert.equal(this.links['s-1-a-3'].getAttribute('href'), '/site/s-1/a/a-3?country=us'); - assert.equal(this.links['s-2-a-1'].getAttribute('href'), '/site/s-2/a/a-1?q=lol'); - assert.equal(this.links['s-2-a-2'].getAttribute('href'), '/site/s-2/a/a-2'); - assert.equal(this.links['s-2-a-3'].getAttribute('href'), '/site/s-2/a/a-3'); - assert.equal(this.links['s-3-a-1'].getAttribute('href'), '/site/s-3/a/a-1?q=lol'); - assert.equal(this.links['s-3-a-2'].getAttribute('href'), '/site/s-3/a/a-2'); - assert.equal(this.links['s-3-a-3'].getAttribute('href'), '/site/s-3/a/a-3'); - - run(this.links['s-1-a-2'], 'click'); - - assert.equal(this.site_controller.get('country'), 'us'); - assert.equal(this.article_controller.get('q'), 'wat'); - assert.equal(this.article_controller.get('z'), 0); - assert.deepEqual(this.site_controller.get('model'), { id: 's-1' }); - assert.deepEqual(this.article_controller.get('model'), { id: 'a-2' }); - assert.equal(this.links['s-1-a-1'].getAttribute('href'), '/site/s-1/a/a-1?country=us&q=lol'); - assert.equal(this.links['s-1-a-2'].getAttribute('href'), '/site/s-1/a/a-2?country=us'); - assert.equal(this.links['s-1-a-3'].getAttribute('href'), '/site/s-1/a/a-3?country=us'); - assert.equal(this.links['s-2-a-1'].getAttribute('href'), '/site/s-2/a/a-1?q=lol'); - assert.equal(this.links['s-2-a-2'].getAttribute('href'), '/site/s-2/a/a-2'); - assert.equal(this.links['s-2-a-3'].getAttribute('href'), '/site/s-2/a/a-3'); - assert.equal(this.links['s-3-a-1'].getAttribute('href'), '/site/s-3/a/a-1?q=lol'); - assert.equal(this.links['s-3-a-2'].getAttribute('href'), '/site/s-3/a/a-2'); - assert.equal(this.links['s-3-a-3'].getAttribute('href'), '/site/s-3/a/a-3'); - - run(this.links['s-2-a-2'], 'click'); - - assert.equal(this.site_controller.get('country'), 'au'); - assert.equal(this.article_controller.get('q'), 'wat'); - assert.equal(this.article_controller.get('z'), 0); - assert.deepEqual(this.site_controller.get('model'), { id: 's-2' }); - assert.deepEqual(this.article_controller.get('model'), { id: 'a-2' }); - assert.equal(this.links['s-1-a-1'].getAttribute('href'), '/site/s-1/a/a-1?country=us&q=lol'); - assert.equal(this.links['s-1-a-2'].getAttribute('href'), '/site/s-1/a/a-2?country=us'); - assert.equal(this.links['s-1-a-3'].getAttribute('href'), '/site/s-1/a/a-3?country=us'); - assert.equal(this.links['s-2-a-1'].getAttribute('href'), '/site/s-2/a/a-1?q=lol'); - assert.equal(this.links['s-2-a-2'].getAttribute('href'), '/site/s-2/a/a-2'); - assert.equal(this.links['s-2-a-3'].getAttribute('href'), '/site/s-2/a/a-3'); - assert.equal(this.links['s-3-a-1'].getAttribute('href'), '/site/s-3/a/a-1?q=lol'); - assert.equal(this.links['s-3-a-2'].getAttribute('href'), '/site/s-3/a/a-2'); - assert.equal(this.links['s-3-a-3'].getAttribute('href'), '/site/s-3/a/a-3'); - }); - } + assert.deepEqual(this.site_controller.get('model'), { id: 's-1' }); + assert.deepEqual(this.article_controller.get('model'), { id: 'a-3' }); + assert.equal(this.site_controller.get('country'), 'au'); + assert.equal(this.article_controller.get('q'), 'hay'); + assert.equal(this.article_controller.get('z'), 0); + assert.equal( + this.links['s-1-a-1'].getAttribute('href'), + '/site/s-1/a/a-1' + ); + assert.equal( + this.links['s-1-a-2'].getAttribute('href'), + '/site/s-1/a/a-2?q=lol' + ); + assert.equal( + this.links['s-1-a-3'].getAttribute('href'), + '/site/s-1/a/a-3?q=hay' + ); + assert.equal( + this.links['s-2-a-1'].getAttribute('href'), + '/site/s-2/a/a-1' + ); + assert.equal( + this.links['s-2-a-2'].getAttribute('href'), + '/site/s-2/a/a-2?q=lol' + ); + assert.equal( + this.links['s-2-a-3'].getAttribute('href'), + '/site/s-2/a/a-3?q=hay' + ); + assert.equal( + this.links['s-3-a-1'].getAttribute('href'), + '/site/s-3/a/a-1' + ); + assert.equal( + this.links['s-3-a-2'].getAttribute('href'), + '/site/s-3/a/a-2?q=lol' + ); + assert.equal( + this.links['s-3-a-3'].getAttribute('href'), + '/site/s-3/a/a-3?q=hay' + ); + + this.expectedSiteModelHookParams = { site_id: 's-1', country: 'au' }; + this.expectedArticleModelHookParams = { + article_id: 'a-2', + q: 'lol', + z: 1 + }; + this.transitionTo('site.article', 's-1', 'a-2', { + queryParams: { z: 1 } + }); - ['@test query params have \'model\' stickiness by default (url changes)'](assert) { - assert.expect(88); + assert.deepEqual(this.site_controller.get('model'), { id: 's-1' }); + assert.deepEqual(this.article_controller.get('model'), { id: 'a-2' }); + assert.equal(this.site_controller.get('country'), 'au'); + assert.equal(this.article_controller.get('q'), 'lol'); + assert.equal(this.article_controller.get('z'), 1); + assert.equal( + this.links['s-1-a-1'].getAttribute('href'), + '/site/s-1/a/a-1' + ); + assert.equal( + this.links['s-1-a-2'].getAttribute('href'), + '/site/s-1/a/a-2?q=lol&z=1' + ); + assert.equal( + this.links['s-1-a-3'].getAttribute('href'), + '/site/s-1/a/a-3?q=hay' + ); + assert.equal( + this.links['s-2-a-1'].getAttribute('href'), + '/site/s-2/a/a-1' + ); + assert.equal( + this.links['s-2-a-2'].getAttribute('href'), + '/site/s-2/a/a-2?q=lol&z=1' + ); + assert.equal( + this.links['s-2-a-3'].getAttribute('href'), + '/site/s-2/a/a-3?q=hay' + ); + assert.equal( + this.links['s-3-a-1'].getAttribute('href'), + '/site/s-3/a/a-1' + ); + assert.equal( + this.links['s-3-a-2'].getAttribute('href'), + '/site/s-3/a/a-2?q=lol&z=1' + ); + assert.equal( + this.links['s-3-a-3'].getAttribute('href'), + '/site/s-3/a/a-3?q=hay' + ); + + this.expectedSiteModelHookParams = { site_id: 's-2', country: 'us' }; + this.expectedArticleModelHookParams = { + article_id: 'a-2', + q: 'lol', + z: 1 + }; + this.transitionTo('site.article', 's-2', 'a-2', { + queryParams: { country: 'us' } + }); - return this.boot().then(() => { - this.expectedSiteModelHookParams = { site_id: 's-1', country: 'au' }; - this.expectedArticleModelHookParams = { article_id: 'a-1', q: 'lol', z: 0 }; - this.transitionTo('/site/s-1/a/a-1?q=lol'); - - assert.deepEqual(this.site_controller.get('model'), { id: 's-1' }, 'site controller\'s model is s-1'); - assert.deepEqual(this.article_controller.get('model'), { id: 'a-1' }, 'article controller\'s model is a-1'); - assert.equal(this.site_controller.get('country'), 'au'); - assert.equal(this.article_controller.get('q'), 'lol'); - assert.equal(this.article_controller.get('z'), 0); - assert.equal(this.links['s-1-a-1'].getAttribute('href'), '/site/s-1/a/a-1?q=lol'); - assert.equal(this.links['s-1-a-2'].getAttribute('href'), '/site/s-1/a/a-2'); - assert.equal(this.links['s-1-a-3'].getAttribute('href'), '/site/s-1/a/a-3'); - assert.equal(this.links['s-2-a-1'].getAttribute('href'), '/site/s-2/a/a-1?q=lol'); - assert.equal(this.links['s-2-a-2'].getAttribute('href'), '/site/s-2/a/a-2'); - assert.equal(this.links['s-2-a-3'].getAttribute('href'), '/site/s-2/a/a-3'); - assert.equal(this.links['s-3-a-1'].getAttribute('href'), '/site/s-3/a/a-1?q=lol'); - assert.equal(this.links['s-3-a-2'].getAttribute('href'), '/site/s-3/a/a-2'); - assert.equal(this.links['s-3-a-3'].getAttribute('href'), '/site/s-3/a/a-3'); - - this.expectedSiteModelHookParams = { site_id: 's-2', country: 'us' }; - this.expectedArticleModelHookParams = { article_id: 'a-1', q: 'lol', z: 0 }; - this.transitionTo('/site/s-2/a/a-1?country=us&q=lol'); - - assert.deepEqual(this.site_controller.get('model'), { id: 's-2' }, 'site controller\'s model is s-2'); - assert.deepEqual(this.article_controller.get('model'), { id: 'a-1' }, 'article controller\'s model is a-1'); - assert.equal(this.site_controller.get('country'), 'us'); - assert.equal(this.article_controller.get('q'), 'lol'); - assert.equal(this.article_controller.get('z'), 0); - assert.equal(this.links['s-1-a-1'].getAttribute('href'), '/site/s-1/a/a-1?q=lol'); - assert.equal(this.links['s-1-a-2'].getAttribute('href'), '/site/s-1/a/a-2'); - assert.equal(this.links['s-1-a-3'].getAttribute('href'), '/site/s-1/a/a-3'); - assert.equal(this.links['s-2-a-1'].getAttribute('href'), '/site/s-2/a/a-1?country=us&q=lol'); - assert.equal(this.links['s-2-a-2'].getAttribute('href'), '/site/s-2/a/a-2?country=us'); - assert.equal(this.links['s-2-a-3'].getAttribute('href'), '/site/s-2/a/a-3?country=us'); - assert.equal(this.links['s-3-a-1'].getAttribute('href'), '/site/s-3/a/a-1?q=lol'); - assert.equal(this.links['s-3-a-2'].getAttribute('href'), '/site/s-3/a/a-2'); - assert.equal(this.links['s-3-a-3'].getAttribute('href'), '/site/s-3/a/a-3'); - - this.expectedSiteModelHookParams = { site_id: 's-2', country: 'us' }; - this.expectedArticleModelHookParams = { article_id: 'a-2', q: 'lol', z: 0 }; - this.transitionTo('/site/s-2/a/a-2?country=us&q=lol'); - - assert.deepEqual(this.site_controller.get('model'), { id: 's-2' }, 'site controller\'s model is s-2'); - assert.deepEqual(this.article_controller.get('model'), { id: 'a-2' }, 'article controller\'s model is a-2'); - assert.equal(this.site_controller.get('country'), 'us'); - assert.equal(this.article_controller.get('q'), 'lol'); - assert.equal(this.article_controller.get('z'), 0); - assert.equal(this.links['s-1-a-1'].getAttribute('href'), '/site/s-1/a/a-1?q=lol'); - assert.equal(this.links['s-1-a-2'].getAttribute('href'), '/site/s-1/a/a-2?q=lol'); - assert.equal(this.links['s-1-a-3'].getAttribute('href'), '/site/s-1/a/a-3'); - assert.equal(this.links['s-2-a-1'].getAttribute('href'), '/site/s-2/a/a-1?country=us&q=lol'); - assert.equal(this.links['s-2-a-2'].getAttribute('href'), '/site/s-2/a/a-2?country=us&q=lol'); - assert.equal(this.links['s-2-a-3'].getAttribute('href'), '/site/s-2/a/a-3?country=us'); - assert.equal(this.links['s-3-a-1'].getAttribute('href'), '/site/s-3/a/a-1?q=lol'); - assert.equal(this.links['s-3-a-2'].getAttribute('href'), '/site/s-3/a/a-2?q=lol'); - assert.equal(this.links['s-3-a-3'].getAttribute('href'), '/site/s-3/a/a-3'); - - this.expectedSiteModelHookParams = { site_id: 's-2', country: 'us' }; - this.expectedArticleModelHookParams = { article_id: 'a-3', q: 'lol', z: 123 }; - this.transitionTo('/site/s-2/a/a-3?country=us&q=lol&z=123'); - - assert.deepEqual(this.site_controller.get('model'), { id: 's-2' }, 'site controller\'s model is s-2'); - assert.deepEqual(this.article_controller.get('model'), { id: 'a-3' }, 'article controller\'s model is a-3'); - assert.equal(this.site_controller.get('country'), 'us'); - assert.equal(this.article_controller.get('q'), 'lol'); - assert.equal(this.article_controller.get('z'), 123); - assert.equal(this.links['s-1-a-1'].getAttribute('href'), '/site/s-1/a/a-1?q=lol'); - assert.equal(this.links['s-1-a-2'].getAttribute('href'), '/site/s-1/a/a-2?q=lol'); - assert.equal(this.links['s-1-a-3'].getAttribute('href'), '/site/s-1/a/a-3?q=lol&z=123'); - assert.equal(this.links['s-2-a-1'].getAttribute('href'), '/site/s-2/a/a-1?country=us&q=lol'); - assert.equal(this.links['s-2-a-2'].getAttribute('href'), '/site/s-2/a/a-2?country=us&q=lol'); - assert.equal(this.links['s-2-a-3'].getAttribute('href'), '/site/s-2/a/a-3?country=us&q=lol&z=123'); - assert.equal(this.links['s-3-a-1'].getAttribute('href'), '/site/s-3/a/a-1?q=lol'); - assert.equal(this.links['s-3-a-2'].getAttribute('href'), '/site/s-3/a/a-2?q=lol'); - assert.equal(this.links['s-3-a-3'].getAttribute('href'), '/site/s-3/a/a-3?q=lol&z=123'); - - this.expectedSiteModelHookParams = { site_id: 's-3', country: 'nz' }; - this.expectedArticleModelHookParams = { article_id: 'a-3', q: 'lol', z: 123 }; - this.transitionTo('/site/s-3/a/a-3?country=nz&q=lol&z=123'); - - assert.deepEqual(this.site_controller.get('model'), { id: 's-3' }, 'site controller\'s model is s-3'); - assert.deepEqual(this.article_controller.get('model'), { id: 'a-3' }, 'article controller\'s model is a-3'); - assert.equal(this.site_controller.get('country'), 'nz'); - assert.equal(this.article_controller.get('q'), 'lol'); - assert.equal(this.article_controller.get('z'), 123); - assert.equal(this.links['s-1-a-1'].getAttribute('href'), '/site/s-1/a/a-1?q=lol'); - assert.equal(this.links['s-1-a-2'].getAttribute('href'), '/site/s-1/a/a-2?q=lol'); - assert.equal(this.links['s-1-a-3'].getAttribute('href'), '/site/s-1/a/a-3?q=lol&z=123'); - assert.equal(this.links['s-2-a-1'].getAttribute('href'), '/site/s-2/a/a-1?country=us&q=lol'); - assert.equal(this.links['s-2-a-2'].getAttribute('href'), '/site/s-2/a/a-2?country=us&q=lol'); - assert.equal(this.links['s-2-a-3'].getAttribute('href'), '/site/s-2/a/a-3?country=us&q=lol&z=123'); - assert.equal(this.links['s-3-a-1'].getAttribute('href'), '/site/s-3/a/a-1?country=nz&q=lol'); - assert.equal(this.links['s-3-a-2'].getAttribute('href'), '/site/s-3/a/a-2?country=nz&q=lol'); - assert.equal(this.links['s-3-a-3'].getAttribute('href'), '/site/s-3/a/a-3?country=nz&q=lol&z=123'); - }); - } + assert.deepEqual(this.site_controller.get('model'), { id: 's-2' }); + assert.deepEqual(this.article_controller.get('model'), { id: 'a-2' }); + assert.equal(this.site_controller.get('country'), 'us'); + assert.equal(this.article_controller.get('q'), 'lol'); + assert.equal(this.article_controller.get('z'), 1); + assert.equal( + this.links['s-1-a-1'].getAttribute('href'), + '/site/s-1/a/a-1' + ); + assert.equal( + this.links['s-1-a-2'].getAttribute('href'), + '/site/s-1/a/a-2?q=lol&z=1' + ); + assert.equal( + this.links['s-1-a-3'].getAttribute('href'), + '/site/s-1/a/a-3?q=hay' + ); + assert.equal( + this.links['s-2-a-1'].getAttribute('href'), + '/site/s-2/a/a-1?country=us' + ); + assert.equal( + this.links['s-2-a-2'].getAttribute('href'), + '/site/s-2/a/a-2?country=us&q=lol&z=1' + ); + assert.equal( + this.links['s-2-a-3'].getAttribute('href'), + '/site/s-2/a/a-3?country=us&q=hay' + ); + assert.equal( + this.links['s-3-a-1'].getAttribute('href'), + '/site/s-3/a/a-1' + ); + assert.equal( + this.links['s-3-a-2'].getAttribute('href'), + '/site/s-3/a/a-2?q=lol&z=1' + ); + assert.equal( + this.links['s-3-a-3'].getAttribute('href'), + '/site/s-3/a/a-3?q=hay' + ); + + this.expectedSiteModelHookParams = { site_id: 's-2', country: 'us' }; + this.expectedArticleModelHookParams = { + article_id: 'a-1', + q: 'yeah', + z: 0 + }; + this.transitionTo('site.article', 's-2', 'a-1', { + queryParams: { q: 'yeah' } + }); - ['@test query params have \'model\' stickiness by default (params-based transitions)'](assert) { - assert.expect(118); + assert.deepEqual(this.site_controller.get('model'), { id: 's-2' }); + assert.deepEqual(this.article_controller.get('model'), { id: 'a-1' }); + assert.equal(this.site_controller.get('country'), 'us'); + assert.equal(this.article_controller.get('q'), 'yeah'); + assert.equal(this.article_controller.get('z'), 0); + assert.equal( + this.links['s-1-a-1'].getAttribute('href'), + '/site/s-1/a/a-1?q=yeah' + ); + assert.equal( + this.links['s-1-a-2'].getAttribute('href'), + '/site/s-1/a/a-2?q=lol&z=1' + ); + assert.equal( + this.links['s-1-a-3'].getAttribute('href'), + '/site/s-1/a/a-3?q=hay' + ); + assert.equal( + this.links['s-2-a-1'].getAttribute('href'), + '/site/s-2/a/a-1?country=us&q=yeah' + ); + assert.equal( + this.links['s-2-a-2'].getAttribute('href'), + '/site/s-2/a/a-2?country=us&q=lol&z=1' + ); + assert.equal( + this.links['s-2-a-3'].getAttribute('href'), + '/site/s-2/a/a-3?country=us&q=hay' + ); + assert.equal( + this.links['s-3-a-1'].getAttribute('href'), + '/site/s-3/a/a-1?q=yeah' + ); + assert.equal( + this.links['s-3-a-2'].getAttribute('href'), + '/site/s-3/a/a-2?q=lol&z=1' + ); + assert.equal( + this.links['s-3-a-3'].getAttribute('href'), + '/site/s-3/a/a-3?q=hay' + ); + + this.expectedSiteModelHookParams = { site_id: 's-3', country: 'nz' }; + this.expectedArticleModelHookParams = { + article_id: 'a-3', + q: 'hay', + z: 3 + }; + this.transitionTo('site.article', 's-3', 'a-3', { + queryParams: { country: 'nz', z: 3 } + }); - return this.boot().then(() => { - this.expectedSiteModelHookParams = { site_id: 's-1', country: 'au' }; - this.expectedArticleModelHookParams = { article_id: 'a-1', q: 'wat', z: 0 }; - this.transitionTo('site.article', 's-1', 'a-1'); - - assert.deepEqual(this.site_controller.get('model'), { id: 's-1' }); - assert.deepEqual(this.article_controller.get('model'), { id: 'a-1' }); - assert.equal(this.site_controller.get('country'), 'au'); - assert.equal(this.article_controller.get('q'), 'wat'); - assert.equal(this.article_controller.get('z'), 0); - assert.equal(this.links['s-1-a-1'].getAttribute('href'), '/site/s-1/a/a-1'); - assert.equal(this.links['s-1-a-2'].getAttribute('href'), '/site/s-1/a/a-2'); - assert.equal(this.links['s-1-a-3'].getAttribute('href'), '/site/s-1/a/a-3'); - assert.equal(this.links['s-2-a-1'].getAttribute('href'), '/site/s-2/a/a-1'); - assert.equal(this.links['s-2-a-2'].getAttribute('href'), '/site/s-2/a/a-2'); - assert.equal(this.links['s-2-a-3'].getAttribute('href'), '/site/s-2/a/a-3'); - assert.equal(this.links['s-3-a-1'].getAttribute('href'), '/site/s-3/a/a-1'); - assert.equal(this.links['s-3-a-2'].getAttribute('href'), '/site/s-3/a/a-2'); - assert.equal(this.links['s-3-a-3'].getAttribute('href'), '/site/s-3/a/a-3'); - - this.expectedSiteModelHookParams = { site_id: 's-1', country: 'au' }; - this.expectedArticleModelHookParams = { article_id: 'a-2', q: 'lol', z: 0 }; - this.transitionTo('site.article', 's-1', 'a-2', { queryParams: { q: 'lol' } }); - - assert.deepEqual(this.site_controller.get('model'), { id: 's-1' }); - assert.deepEqual(this.article_controller.get('model'), { id: 'a-2' }); - assert.equal(this.site_controller.get('country'), 'au'); - assert.equal(this.article_controller.get('q'), 'lol'); - assert.equal(this.article_controller.get('z'), 0); - assert.equal(this.links['s-1-a-1'].getAttribute('href'), '/site/s-1/a/a-1'); - assert.equal(this.links['s-1-a-2'].getAttribute('href'), '/site/s-1/a/a-2?q=lol'); - assert.equal(this.links['s-1-a-3'].getAttribute('href'), '/site/s-1/a/a-3'); - assert.equal(this.links['s-2-a-1'].getAttribute('href'), '/site/s-2/a/a-1'); - assert.equal(this.links['s-2-a-2'].getAttribute('href'), '/site/s-2/a/a-2?q=lol'); - assert.equal(this.links['s-2-a-3'].getAttribute('href'), '/site/s-2/a/a-3'); - assert.equal(this.links['s-3-a-1'].getAttribute('href'), '/site/s-3/a/a-1'); - assert.equal(this.links['s-3-a-2'].getAttribute('href'), '/site/s-3/a/a-2?q=lol'); - assert.equal(this.links['s-3-a-3'].getAttribute('href'), '/site/s-3/a/a-3'); - - this.expectedSiteModelHookParams = { site_id: 's-1', country: 'au' }; - this.expectedArticleModelHookParams = { article_id: 'a-3', q: 'hay', z: 0 }; - this.transitionTo('site.article', 's-1', 'a-3', { queryParams: { q: 'hay' } }); - - assert.deepEqual(this.site_controller.get('model'), { id: 's-1' }); - assert.deepEqual(this.article_controller.get('model'), { id: 'a-3' }); - assert.equal(this.site_controller.get('country'), 'au'); - assert.equal(this.article_controller.get('q'), 'hay'); - assert.equal(this.article_controller.get('z'), 0); - assert.equal(this.links['s-1-a-1'].getAttribute('href'), '/site/s-1/a/a-1'); - assert.equal(this.links['s-1-a-2'].getAttribute('href'), '/site/s-1/a/a-2?q=lol'); - assert.equal(this.links['s-1-a-3'].getAttribute('href'), '/site/s-1/a/a-3?q=hay'); - assert.equal(this.links['s-2-a-1'].getAttribute('href'), '/site/s-2/a/a-1'); - assert.equal(this.links['s-2-a-2'].getAttribute('href'), '/site/s-2/a/a-2?q=lol'); - assert.equal(this.links['s-2-a-3'].getAttribute('href'), '/site/s-2/a/a-3?q=hay'); - assert.equal(this.links['s-3-a-1'].getAttribute('href'), '/site/s-3/a/a-1'); - assert.equal(this.links['s-3-a-2'].getAttribute('href'), '/site/s-3/a/a-2?q=lol'); - assert.equal(this.links['s-3-a-3'].getAttribute('href'), '/site/s-3/a/a-3?q=hay'); - - this.expectedSiteModelHookParams = { site_id: 's-1', country: 'au' }; - this.expectedArticleModelHookParams = { article_id: 'a-2', q: 'lol', z: 1 }; - this.transitionTo('site.article', 's-1', 'a-2', { queryParams: { z: 1 } }); - - assert.deepEqual(this.site_controller.get('model'), { id: 's-1' }); - assert.deepEqual(this.article_controller.get('model'), { id: 'a-2' }); - assert.equal(this.site_controller.get('country'), 'au'); - assert.equal(this.article_controller.get('q'), 'lol'); - assert.equal(this.article_controller.get('z'), 1); - assert.equal(this.links['s-1-a-1'].getAttribute('href'), '/site/s-1/a/a-1'); - assert.equal(this.links['s-1-a-2'].getAttribute('href'), '/site/s-1/a/a-2?q=lol&z=1'); - assert.equal(this.links['s-1-a-3'].getAttribute('href'), '/site/s-1/a/a-3?q=hay'); - assert.equal(this.links['s-2-a-1'].getAttribute('href'), '/site/s-2/a/a-1'); - assert.equal(this.links['s-2-a-2'].getAttribute('href'), '/site/s-2/a/a-2?q=lol&z=1'); - assert.equal(this.links['s-2-a-3'].getAttribute('href'), '/site/s-2/a/a-3?q=hay'); - assert.equal(this.links['s-3-a-1'].getAttribute('href'), '/site/s-3/a/a-1'); - assert.equal(this.links['s-3-a-2'].getAttribute('href'), '/site/s-3/a/a-2?q=lol&z=1'); - assert.equal(this.links['s-3-a-3'].getAttribute('href'), '/site/s-3/a/a-3?q=hay'); - - this.expectedSiteModelHookParams = { site_id: 's-2', country: 'us' }; - this.expectedArticleModelHookParams = { article_id: 'a-2', q: 'lol', z: 1 }; - this.transitionTo('site.article', 's-2', 'a-2', { queryParams: { country: 'us' } }); - - assert.deepEqual(this.site_controller.get('model'), { id: 's-2' }); - assert.deepEqual(this.article_controller.get('model'), { id: 'a-2' }); - assert.equal(this.site_controller.get('country'), 'us'); - assert.equal(this.article_controller.get('q'), 'lol'); - assert.equal(this.article_controller.get('z'), 1); - assert.equal(this.links['s-1-a-1'].getAttribute('href'), '/site/s-1/a/a-1'); - assert.equal(this.links['s-1-a-2'].getAttribute('href'), '/site/s-1/a/a-2?q=lol&z=1'); - assert.equal(this.links['s-1-a-3'].getAttribute('href'), '/site/s-1/a/a-3?q=hay'); - assert.equal(this.links['s-2-a-1'].getAttribute('href'), '/site/s-2/a/a-1?country=us'); - assert.equal(this.links['s-2-a-2'].getAttribute('href'), '/site/s-2/a/a-2?country=us&q=lol&z=1'); - assert.equal(this.links['s-2-a-3'].getAttribute('href'), '/site/s-2/a/a-3?country=us&q=hay'); - assert.equal(this.links['s-3-a-1'].getAttribute('href'), '/site/s-3/a/a-1'); - assert.equal(this.links['s-3-a-2'].getAttribute('href'), '/site/s-3/a/a-2?q=lol&z=1'); - assert.equal(this.links['s-3-a-3'].getAttribute('href'), '/site/s-3/a/a-3?q=hay'); - - this.expectedSiteModelHookParams = { site_id: 's-2', country: 'us' }; - this.expectedArticleModelHookParams = { article_id: 'a-1', q: 'yeah', z: 0 }; - this.transitionTo('site.article', 's-2', 'a-1', { queryParams: { q: 'yeah' } }); - - assert.deepEqual(this.site_controller.get('model'), { id: 's-2' }); - assert.deepEqual(this.article_controller.get('model'), { id: 'a-1' }); - assert.equal(this.site_controller.get('country'), 'us'); - assert.equal(this.article_controller.get('q'), 'yeah'); - assert.equal(this.article_controller.get('z'), 0); - assert.equal(this.links['s-1-a-1'].getAttribute('href'), '/site/s-1/a/a-1?q=yeah'); - assert.equal(this.links['s-1-a-2'].getAttribute('href'), '/site/s-1/a/a-2?q=lol&z=1'); - assert.equal(this.links['s-1-a-3'].getAttribute('href'), '/site/s-1/a/a-3?q=hay'); - assert.equal(this.links['s-2-a-1'].getAttribute('href'), '/site/s-2/a/a-1?country=us&q=yeah'); - assert.equal(this.links['s-2-a-2'].getAttribute('href'), '/site/s-2/a/a-2?country=us&q=lol&z=1'); - assert.equal(this.links['s-2-a-3'].getAttribute('href'), '/site/s-2/a/a-3?country=us&q=hay'); - assert.equal(this.links['s-3-a-1'].getAttribute('href'), '/site/s-3/a/a-1?q=yeah'); - assert.equal(this.links['s-3-a-2'].getAttribute('href'), '/site/s-3/a/a-2?q=lol&z=1'); - assert.equal(this.links['s-3-a-3'].getAttribute('href'), '/site/s-3/a/a-3?q=hay'); - - this.expectedSiteModelHookParams = { site_id: 's-3', country: 'nz' }; - this.expectedArticleModelHookParams = { article_id: 'a-3', q: 'hay', z: 3 }; - this.transitionTo('site.article', 's-3', 'a-3', { queryParams: { country: 'nz', z: 3 } }); - - assert.deepEqual(this.site_controller.get('model'), { id: 's-3' }); - assert.deepEqual(this.article_controller.get('model'), { id: 'a-3' }); - assert.equal(this.site_controller.get('country'), 'nz'); - assert.equal(this.article_controller.get('q'), 'hay'); - assert.equal(this.article_controller.get('z'), 3); - assert.equal(this.links['s-1-a-1'].getAttribute('href'), '/site/s-1/a/a-1?q=yeah'); - assert.equal(this.links['s-1-a-2'].getAttribute('href'), '/site/s-1/a/a-2?q=lol&z=1'); - assert.equal(this.links['s-1-a-3'].getAttribute('href'), '/site/s-1/a/a-3?q=hay&z=3'); - assert.equal(this.links['s-2-a-1'].getAttribute('href'), '/site/s-2/a/a-1?country=us&q=yeah'); - assert.equal(this.links['s-2-a-2'].getAttribute('href'), '/site/s-2/a/a-2?country=us&q=lol&z=1'); - assert.equal(this.links['s-2-a-3'].getAttribute('href'), '/site/s-2/a/a-3?country=us&q=hay&z=3'); - assert.equal(this.links['s-3-a-1'].getAttribute('href'), '/site/s-3/a/a-1?country=nz&q=yeah'); - assert.equal(this.links['s-3-a-2'].getAttribute('href'), '/site/s-3/a/a-2?country=nz&q=lol&z=1'); - assert.equal(this.links['s-3-a-3'].getAttribute('href'), '/site/s-3/a/a-3?country=nz&q=hay&z=3'); - }); + assert.deepEqual(this.site_controller.get('model'), { id: 's-3' }); + assert.deepEqual(this.article_controller.get('model'), { id: 'a-3' }); + assert.equal(this.site_controller.get('country'), 'nz'); + assert.equal(this.article_controller.get('q'), 'hay'); + assert.equal(this.article_controller.get('z'), 3); + assert.equal( + this.links['s-1-a-1'].getAttribute('href'), + '/site/s-1/a/a-1?q=yeah' + ); + assert.equal( + this.links['s-1-a-2'].getAttribute('href'), + '/site/s-1/a/a-2?q=lol&z=1' + ); + assert.equal( + this.links['s-1-a-3'].getAttribute('href'), + '/site/s-1/a/a-3?q=hay&z=3' + ); + assert.equal( + this.links['s-2-a-1'].getAttribute('href'), + '/site/s-2/a/a-1?country=us&q=yeah' + ); + assert.equal( + this.links['s-2-a-2'].getAttribute('href'), + '/site/s-2/a/a-2?country=us&q=lol&z=1' + ); + assert.equal( + this.links['s-2-a-3'].getAttribute('href'), + '/site/s-2/a/a-3?country=us&q=hay&z=3' + ); + assert.equal( + this.links['s-3-a-1'].getAttribute('href'), + '/site/s-3/a/a-1?country=nz&q=yeah' + ); + assert.equal( + this.links['s-3-a-2'].getAttribute('href'), + '/site/s-3/a/a-2?country=nz&q=lol&z=1' + ); + assert.equal( + this.links['s-3-a-3'].getAttribute('href'), + '/site/s-3/a/a-3?country=nz&q=hay&z=3' + ); + }); + } } -}); +); diff --git a/packages/ember/tests/routing/query_params_test/overlapping_query_params_test.js b/packages/ember/tests/routing/query_params_test/overlapping_query_params_test.js index 845adb18ff3..7f69741ed02 100644 --- a/packages/ember/tests/routing/query_params_test/overlapping_query_params_test.js +++ b/packages/ember/tests/routing/query_params_test/overlapping_query_params_test.js @@ -3,164 +3,187 @@ import { Route } from 'ember-routing'; import { run, Mixin } from 'ember-metal'; import { QueryParamTestCase, moduleFor } from 'internal-test-helpers'; -moduleFor('Query Params - overlapping query param property names', class extends QueryParamTestCase { - setupBase() { - this.router.map(function() { - this.route('parent', function() { - this.route('child'); +moduleFor( + 'Query Params - overlapping query param property names', + class extends QueryParamTestCase { + setupBase() { + this.router.map(function() { + this.route('parent', function() { + this.route('child'); + }); }); - }); - return this.visit('/parent/child'); - } - - ['@test can remap same-named qp props'](assert) { - assert.expect(7); - - this.setMappedQPController('parent'); - this.setMappedQPController('parent.child', 'page', 'childPage'); + return this.visit('/parent/child'); + } - return this.setupBase().then(() => { - this.assertCurrentPath('/parent/child'); + ['@test can remap same-named qp props'](assert) { + assert.expect(7); - let parentController = this.getController('parent'); - let parentChildController = this.getController('parent.child'); + this.setMappedQPController('parent'); + this.setMappedQPController('parent.child', 'page', 'childPage'); - this.setAndFlush(parentController, 'page', 2); - this.assertCurrentPath('/parent/child?parentPage=2'); - this.setAndFlush(parentController, 'page', 1); - this.assertCurrentPath('/parent/child'); + return this.setupBase().then(() => { + this.assertCurrentPath('/parent/child'); - this.setAndFlush(parentChildController, 'page', 2); - this.assertCurrentPath('/parent/child?childPage=2'); - this.setAndFlush(parentChildController, 'page', 1); - this.assertCurrentPath('/parent/child'); + let parentController = this.getController('parent'); + let parentChildController = this.getController('parent.child'); - run(() => { - parentController.set('page', 2); - parentChildController.set('page', 2); - }); + this.setAndFlush(parentController, 'page', 2); + this.assertCurrentPath('/parent/child?parentPage=2'); + this.setAndFlush(parentController, 'page', 1); + this.assertCurrentPath('/parent/child'); - this.assertCurrentPath('/parent/child?childPage=2&parentPage=2'); + this.setAndFlush(parentChildController, 'page', 2); + this.assertCurrentPath('/parent/child?childPage=2'); + this.setAndFlush(parentChildController, 'page', 1); + this.assertCurrentPath('/parent/child'); - run(() => { - parentController.set('page', 1); - parentChildController.set('page', 1); - }); + run(() => { + parentController.set('page', 2); + parentChildController.set('page', 2); + }); - this.assertCurrentPath('/parent/child'); - }); - } + this.assertCurrentPath('/parent/child?childPage=2&parentPage=2'); - ['@test query params can be either controller property or url key'](assert) { - assert.expect(3); + run(() => { + parentController.set('page', 1); + parentChildController.set('page', 1); + }); - this.setMappedQPController('parent'); - - return this.setupBase().then(() => { - this.assertCurrentPath('/parent/child'); - - this.transitionTo('parent.child', { queryParams: { page: 2 } }); - this.assertCurrentPath('/parent/child?parentPage=2'); - - this.transitionTo('parent.child', { queryParams: { parentPage: 3 } }); - this.assertCurrentPath('/parent/child?parentPage=3'); - }); - } + this.assertCurrentPath('/parent/child'); + }); + } - ['@test query param matching a url key and controller property'](assert) { - assert.expect(3); + ['@test query params can be either controller property or url key']( + assert + ) { + assert.expect(3); - this.setMappedQPController('parent', 'page', 'parentPage'); - this.setMappedQPController('parent.child', 'index', 'page'); + this.setMappedQPController('parent'); - return this.setupBase().then(() => { - this.transitionTo('parent.child', { queryParams: { page: 2 } }); - this.assertCurrentPath('/parent/child?parentPage=2'); + return this.setupBase().then(() => { + this.assertCurrentPath('/parent/child'); - this.transitionTo('parent.child', { queryParams: { parentPage: 3 } }); - this.assertCurrentPath('/parent/child?parentPage=3'); + this.transitionTo('parent.child', { queryParams: { page: 2 } }); + this.assertCurrentPath('/parent/child?parentPage=2'); - this.transitionTo('parent.child', { queryParams: { index: 2, page: 2 } }); - this.assertCurrentPath('/parent/child?page=2&parentPage=2'); - }); - } + this.transitionTo('parent.child', { queryParams: { parentPage: 3 } }); + this.assertCurrentPath('/parent/child?parentPage=3'); + }); + } - ['@test query param matching same property on two controllers use the urlKey higher in the chain'](assert) { - assert.expect(4); + ['@test query param matching a url key and controller property'](assert) { + assert.expect(3); - this.setMappedQPController('parent', 'page', 'parentPage'); - this.setMappedQPController('parent.child', 'page', 'childPage'); + this.setMappedQPController('parent', 'page', 'parentPage'); + this.setMappedQPController('parent.child', 'index', 'page'); - return this.setupBase().then(() => { - this.transitionTo('parent.child', { queryParams: { page: 2 } }); - this.assertCurrentPath('/parent/child?parentPage=2'); + return this.setupBase().then(() => { + this.transitionTo('parent.child', { queryParams: { page: 2 } }); + this.assertCurrentPath('/parent/child?parentPage=2'); - this.transitionTo('parent.child', { queryParams: { parentPage: 3 } }); - this.assertCurrentPath('/parent/child?parentPage=3'); + this.transitionTo('parent.child', { queryParams: { parentPage: 3 } }); + this.assertCurrentPath('/parent/child?parentPage=3'); - this.transitionTo('parent.child', { queryParams: { childPage: 2, page: 2 } }); - this.assertCurrentPath('/parent/child?childPage=2&parentPage=2'); + this.transitionTo('parent.child', { + queryParams: { index: 2, page: 2 } + }); + this.assertCurrentPath('/parent/child?page=2&parentPage=2'); + }); + } - this.transitionTo('parent.child', { queryParams: { childPage: 3, parentPage: 4 } }); - this.assertCurrentPath('/parent/child?childPage=3&parentPage=4'); - }); - } + ['@test query param matching same property on two controllers use the urlKey higher in the chain']( + assert + ) { + assert.expect(4); - ['@test query params does not error when a query parameter exists for route instances that share a controller'](assert) { - assert.expect(1); + this.setMappedQPController('parent', 'page', 'parentPage'); + this.setMappedQPController('parent.child', 'page', 'childPage'); - let parentController = Controller.extend({ - queryParams: { page: 'page' } - }); - this.add('controller:parent', parentController); - this.add('route:parent.child', Route.extend({controllerName: 'parent'})); + return this.setupBase().then(() => { + this.transitionTo('parent.child', { queryParams: { page: 2 } }); + this.assertCurrentPath('/parent/child?parentPage=2'); - return this.setupBase('/parent').then(() => { - this.transitionTo('parent.child', { queryParams: { page: 2 } }); - this.assertCurrentPath('/parent/child?page=2'); - }); - } - ['@test query params in the same route hierarchy with the same url key get auto-scoped'](assert) { - assert.expect(1); + this.transitionTo('parent.child', { queryParams: { parentPage: 3 } }); + this.assertCurrentPath('/parent/child?parentPage=3'); - this.setMappedQPController('parent'); - this.setMappedQPController('parent.child'); + this.transitionTo('parent.child', { + queryParams: { childPage: 2, page: 2 } + }); + this.assertCurrentPath('/parent/child?childPage=2&parentPage=2'); - expectAssertion(() => { - this.setupBase(); - }, 'You\'re not allowed to have more than one controller property map to the same query param key, but both `parent:page` and `parent.child:page` map to `parentPage`. You can fix this by mapping one of the controller properties to a different query param key via the `as` config option, e.g. `page: { as: \'other-page\' }`'); - } + this.transitionTo('parent.child', { + queryParams: { childPage: 3, parentPage: 4 } + }); + this.assertCurrentPath('/parent/child?childPage=3&parentPage=4'); + }); + } - ['@test Support shared but overridable mixin pattern'](assert) { - assert.expect(7); + ['@test query params does not error when a query parameter exists for route instances that share a controller']( + assert + ) { + assert.expect(1); - let HasPage = Mixin.create({ - queryParams: 'page', - page: 1 - }); + let parentController = Controller.extend({ + queryParams: { page: 'page' } + }); + this.add('controller:parent', parentController); + this.add( + 'route:parent.child', + Route.extend({ controllerName: 'parent' }) + ); + + return this.setupBase('/parent').then(() => { + this.transitionTo('parent.child', { queryParams: { page: 2 } }); + this.assertCurrentPath('/parent/child?page=2'); + }); + } + ['@test query params in the same route hierarchy with the same url key get auto-scoped']( + assert + ) { + assert.expect(1); + + this.setMappedQPController('parent'); + this.setMappedQPController('parent.child'); + + expectAssertion(() => { + this.setupBase(); + }, "You're not allowed to have more than one controller property map to the same query param key, but both `parent:page` and `parent.child:page` map to `parentPage`. You can fix this by mapping one of the controller properties to a different query param key via the `as` config option, e.g. `page: { as: 'other-page' }`"); + } + + ['@test Support shared but overridable mixin pattern'](assert) { + assert.expect(7); + + let HasPage = Mixin.create({ + queryParams: 'page', + page: 1 + }); - this.add('controller:parent', Controller.extend(HasPage, { - queryParams: { page: 'yespage' } - })); + this.add( + 'controller:parent', + Controller.extend(HasPage, { + queryParams: { page: 'yespage' } + }) + ); - this.add('controller:parent.child', Controller.extend(HasPage)); + this.add('controller:parent.child', Controller.extend(HasPage)); - return this.setupBase().then(() => { - this.assertCurrentPath('/parent/child'); + return this.setupBase().then(() => { + this.assertCurrentPath('/parent/child'); - let parentController = this.getController('parent'); - let parentChildController = this.getController('parent.child'); + let parentController = this.getController('parent'); + let parentChildController = this.getController('parent.child'); - this.setAndFlush(parentChildController, 'page', 2); - this.assertCurrentPath('/parent/child?page=2'); - assert.equal(parentController.get('page'), 1); - assert.equal(parentChildController.get('page'), 2); + this.setAndFlush(parentChildController, 'page', 2); + this.assertCurrentPath('/parent/child?page=2'); + assert.equal(parentController.get('page'), 1); + assert.equal(parentChildController.get('page'), 2); - this.setAndFlush(parentController, 'page', 2); - this.assertCurrentPath('/parent/child?page=2&yespage=2'); - assert.equal(parentController.get('page'), 2); - assert.equal(parentChildController.get('page'), 2); - }); + this.setAndFlush(parentController, 'page', 2); + this.assertCurrentPath('/parent/child?page=2&yespage=2'); + assert.equal(parentController.get('page'), 2); + assert.equal(parentChildController.get('page'), 2); + }); + } } -}); +); diff --git a/packages/ember/tests/routing/query_params_test/query_param_async_get_handler_test.js b/packages/ember/tests/routing/query_params_test/query_param_async_get_handler_test.js index 672f88aeaf2..683b3940d67 100644 --- a/packages/ember/tests/routing/query_params_test/query_param_async_get_handler_test.js +++ b/packages/ember/tests/routing/query_params_test/query_param_async_get_handler_test.js @@ -5,221 +5,329 @@ import { Route } from 'ember-routing'; import { QueryParamTestCase, moduleFor } from 'internal-test-helpers'; // These tests mimic what happens with lazily loaded Engines. -moduleFor('Query Params - async get handler', class extends QueryParamTestCase { - get routerOptions() { - let fetchedHandlers = this.fetchedHandlers = []; - - return { - location: 'test', - - init() { - this._super(...arguments); - this._seenHandlers = Object.create(null); - this._handlerPromises = Object.create(null); - }, - - _getQPMeta(handlerInfo) { - let handler = this._seenHandlers[handlerInfo.name]; - if (handler) { - return get(handler, '_qp'); +moduleFor( + 'Query Params - async get handler', + class extends QueryParamTestCase { + get routerOptions() { + let fetchedHandlers = (this.fetchedHandlers = []); + + return { + location: 'test', + + init() { + this._super(...arguments); + this._seenHandlers = Object.create(null); + this._handlerPromises = Object.create(null); + }, + + _getQPMeta(handlerInfo) { + let handler = this._seenHandlers[handlerInfo.name]; + if (handler) { + return get(handler, '_qp'); + } + }, + + _getHandlerFunction() { + let getHandler = this._super(...arguments); + let handlerPromises = this._handlerPromises; + let seenHandlers = this._seenHandlers; + + return routeName => { + fetchedHandlers.push(routeName); + + // Cache the returns so we don't have more than one Promise for a + // given handler. + return ( + handlerPromises[routeName] || + (handlerPromises[routeName] = new RSVP.Promise(resolve => { + setTimeout(() => { + let handler = getHandler(routeName); + + seenHandlers[routeName] = handler; + + resolve(handler); + }, 10); + })) + ); + }; } - }, - - _getHandlerFunction() { - let getHandler = this._super(...arguments); - let handlerPromises = this._handlerPromises; - let seenHandlers = this._seenHandlers; - - return (routeName) => { - fetchedHandlers.push(routeName); - - // Cache the returns so we don't have more than one Promise for a - // given handler. - return handlerPromises[routeName] || (handlerPromises[routeName] = new RSVP.Promise((resolve) => { - setTimeout(() => { - let handler = getHandler(routeName); - - seenHandlers[routeName] = handler; - - resolve(handler); - }, 10); - })); - }; - } - }; - } + }; + } - ['@test can render a link to an asynchronously loaded route without fetching the route'](assert) { - assert.expect(4); + ['@test can render a link to an asynchronously loaded route without fetching the route']( + assert + ) { + assert.expect(4); - this.router.map(function() { - this.route('post', { path: '/post/:id' }); - }); + this.router.map(function() { + this.route('post', { path: '/post/:id' }); + }); - this.setSingleQPController('post'); + this.setSingleQPController('post'); - let setupAppTemplate = () => { - this.addTemplate('application', ` + let setupAppTemplate = () => { + this.addTemplate( + 'application', + ` {{link-to 'Post' 'post' 1337 (query-params foo='bar') class='post-link is-1337'}} {{link-to 'Post' 'post' 7331 (query-params foo='boo') class='post-link is-7331'}} {{outlet}} - `); - }; - - setupAppTemplate(); - - return this.visitAndAssert('/').then(() => { - assert.equal(this.$('.post-link.is-1337').attr('href'), '/post/1337?foo=bar', 'renders correctly with default QP value'); - assert.equal(this.$('.post-link.is-7331').attr('href'), '/post/7331?foo=boo', 'renders correctly with non-default QP value'); - assert.deepEqual(this.fetchedHandlers, ['application', 'index'], `only fetched the handlers for the route we're on`); - }); - } - - ['@test can transitionTo to an asynchronously loaded route with simple query params'](assert) { - assert.expect(6); - - this.router.map(function() { - this.route('post', { path: '/post/:id' }); - this.route('posts'); - }); - - this.setSingleQPController('post'); - - let postController; - return this.visitAndAssert('/').then(() => { - postController = this.getController('post'); - - return this.transitionTo('posts').then(() => { - this.assertCurrentPath('/posts'); - }); - }).then(() => { - return this.transitionTo('post', 1337, { queryParams: { foo: 'boo' } }).then(() => { - assert.equal(postController.get('foo'), 'boo', 'simple QP is correctly set on controller'); - this.assertCurrentPath('/post/1337?foo=boo'); + ` + ); + }; + + setupAppTemplate(); + + return this.visitAndAssert('/').then(() => { + assert.equal( + this.$('.post-link.is-1337').attr('href'), + '/post/1337?foo=bar', + 'renders correctly with default QP value' + ); + assert.equal( + this.$('.post-link.is-7331').attr('href'), + '/post/7331?foo=boo', + 'renders correctly with non-default QP value' + ); + assert.deepEqual( + this.fetchedHandlers, + ['application', 'index'], + `only fetched the handlers for the route we're on` + ); }); - }).then(() => { - return this.transitionTo('post', 1337, { queryParams: { foo: 'bar' } }).then(() => { - assert.equal(postController.get('foo'), 'bar', 'simple QP is correctly set with default value'); - this.assertCurrentPath('/post/1337'); - }); - }); - } + } - ['@test can transitionTo to an asynchronously loaded route with array query params'](assert) { - assert.expect(5); + ['@test can transitionTo to an asynchronously loaded route with simple query params']( + assert + ) { + assert.expect(6); - this.router.map(function() { - this.route('post', { path: '/post/:id' }); - }); - - this.setSingleQPController('post', 'comments', []); - - let postController; - return this.visitAndAssert('/').then(() => { - postController = this.getController('post'); - return this.transitionTo('post', 1337, { queryParams: { comments: [1, 2] } }).then(() => { - assert.deepEqual(postController.get('comments'), [1, 2], 'array QP is correctly set with default value'); - this.assertCurrentPath('/post/1337?comments=%5B1%2C2%5D'); + this.router.map(function() { + this.route('post', { path: '/post/:id' }); + this.route('posts'); }); - }).then(() => { - return this.transitionTo('post', 1338).then(() => { - assert.deepEqual(postController.get('comments'), [], 'array QP is correctly set on controller'); - this.assertCurrentPath('/post/1338'); - }); - }); - } - ['@test can transitionTo to an asynchronously loaded route with mapped query params'](assert) { - assert.expect(7); - - this.router.map(function() { - this.route('post', { path: '/post/:id' }, function() { - this.route('index', { path: '/' }); + this.setSingleQPController('post'); + + let postController; + return this.visitAndAssert('/') + .then(() => { + postController = this.getController('post'); + + return this.transitionTo('posts').then(() => { + this.assertCurrentPath('/posts'); + }); + }) + .then(() => { + return this.transitionTo('post', 1337, { + queryParams: { foo: 'boo' } + }).then(() => { + assert.equal( + postController.get('foo'), + 'boo', + 'simple QP is correctly set on controller' + ); + this.assertCurrentPath('/post/1337?foo=boo'); + }); + }) + .then(() => { + return this.transitionTo('post', 1337, { + queryParams: { foo: 'bar' } + }).then(() => { + assert.equal( + postController.get('foo'), + 'bar', + 'simple QP is correctly set with default value' + ); + this.assertCurrentPath('/post/1337'); + }); + }); + } + + ['@test can transitionTo to an asynchronously loaded route with array query params']( + assert + ) { + assert.expect(5); + + this.router.map(function() { + this.route('post', { path: '/post/:id' }); }); - }); - - this.setSingleQPController('post'); - this.setMappedQPController('post.index', 'comment', 'note'); - - let postController; - let postIndexController; - return this.visitAndAssert('/').then(() => { - postController = this.getController('post'); - postIndexController = this.getController('post.index'); - - return this.transitionTo('post.index', 1337, { queryParams: { note: 6, foo: 'boo' } }).then(() => { - assert.equal(postController.get('foo'), 'boo', 'simple QP is correctly set on controller'); - assert.equal(postIndexController.get('comment'), 6, 'mapped QP is correctly set on controller'); - this.assertCurrentPath('/post/1337?foo=boo¬e=6'); - }); - }).then(() => { - return this.transitionTo('post', 1337, { queryParams: { foo: 'bar' } }).then(() => { - assert.equal(postController.get('foo'), 'bar', 'simple QP is correctly set with default value'); - assert.equal(postIndexController.get('comment'), 6, 'mapped QP retains value scoped to model'); - this.assertCurrentPath('/post/1337?note=6'); + this.setSingleQPController('post', 'comments', []); + + let postController; + return this.visitAndAssert('/') + .then(() => { + postController = this.getController('post'); + return this.transitionTo('post', 1337, { + queryParams: { comments: [1, 2] } + }).then(() => { + assert.deepEqual( + postController.get('comments'), + [1, 2], + 'array QP is correctly set with default value' + ); + this.assertCurrentPath('/post/1337?comments=%5B1%2C2%5D'); + }); + }) + .then(() => { + return this.transitionTo('post', 1338).then(() => { + assert.deepEqual( + postController.get('comments'), + [], + 'array QP is correctly set on controller' + ); + this.assertCurrentPath('/post/1338'); + }); + }); + } + + ['@test can transitionTo to an asynchronously loaded route with mapped query params']( + assert + ) { + assert.expect(7); + + this.router.map(function() { + this.route('post', { path: '/post/:id' }, function() { + this.route('index', { path: '/' }); + }); }); - }); - } - - ['@test can transitionTo with a URL'](assert) { - assert.expect(7); - this.router.map(function() { - this.route('post', { path: '/post/:id' }, function() { - this.route('index', { path: '/' }); + this.setSingleQPController('post'); + this.setMappedQPController('post.index', 'comment', 'note'); + + let postController; + let postIndexController; + + return this.visitAndAssert('/') + .then(() => { + postController = this.getController('post'); + postIndexController = this.getController('post.index'); + + return this.transitionTo('post.index', 1337, { + queryParams: { note: 6, foo: 'boo' } + }).then(() => { + assert.equal( + postController.get('foo'), + 'boo', + 'simple QP is correctly set on controller' + ); + assert.equal( + postIndexController.get('comment'), + 6, + 'mapped QP is correctly set on controller' + ); + this.assertCurrentPath('/post/1337?foo=boo¬e=6'); + }); + }) + .then(() => { + return this.transitionTo('post', 1337, { + queryParams: { foo: 'bar' } + }).then(() => { + assert.equal( + postController.get('foo'), + 'bar', + 'simple QP is correctly set with default value' + ); + assert.equal( + postIndexController.get('comment'), + 6, + 'mapped QP retains value scoped to model' + ); + this.assertCurrentPath('/post/1337?note=6'); + }); + }); + } + + ['@test can transitionTo with a URL'](assert) { + assert.expect(7); + + this.router.map(function() { + this.route('post', { path: '/post/:id' }, function() { + this.route('index', { path: '/' }); + }); }); - }); - - this.setSingleQPController('post'); - this.setMappedQPController('post.index', 'comment', 'note'); - - let postController; - let postIndexController; - return this.visitAndAssert('/').then(() => { - postController = this.getController('post'); - postIndexController = this.getController('post.index'); - - return this.transitionTo('/post/1337?foo=boo¬e=6').then(() => { - assert.equal(postController.get('foo'), 'boo', 'simple QP is correctly deserialized on controller'); - assert.equal(postIndexController.get('comment'), 6, 'mapped QP is correctly deserialized on controller'); - this.assertCurrentPath('/post/1337?foo=boo¬e=6'); - }); - }).then(() => { - return this.transitionTo('/post/1337?note=6').then(() => { - assert.equal(postController.get('foo'), 'bar', 'simple QP is correctly deserialized with default value'); - assert.equal(postIndexController.get('comment'), 6, 'mapped QP retains value scoped to model'); - this.assertCurrentPath('/post/1337?note=6'); + this.setSingleQPController('post'); + this.setMappedQPController('post.index', 'comment', 'note'); + + let postController; + let postIndexController; + + return this.visitAndAssert('/') + .then(() => { + postController = this.getController('post'); + postIndexController = this.getController('post.index'); + + return this.transitionTo('/post/1337?foo=boo¬e=6').then(() => { + assert.equal( + postController.get('foo'), + 'boo', + 'simple QP is correctly deserialized on controller' + ); + assert.equal( + postIndexController.get('comment'), + 6, + 'mapped QP is correctly deserialized on controller' + ); + this.assertCurrentPath('/post/1337?foo=boo¬e=6'); + }); + }) + .then(() => { + return this.transitionTo('/post/1337?note=6').then(() => { + assert.equal( + postController.get('foo'), + 'bar', + 'simple QP is correctly deserialized with default value' + ); + assert.equal( + postIndexController.get('comment'), + 6, + 'mapped QP retains value scoped to model' + ); + this.assertCurrentPath('/post/1337?note=6'); + }); + }); + } + + ["@test undefined isn't serialized or deserialized into a string"](assert) { + assert.expect(4); + + this.router.map(function() { + this.route('example'); }); - }); - } - - ['@test undefined isn\'t serialized or deserialized into a string'](assert) { - assert.expect(4); - this.router.map(function() { - this.route('example'); - }); + this.addTemplate( + 'application', + "{{link-to 'Example' 'example' (query-params foo=undefined) id='the-link'}}" + ); - this.addTemplate('application', '{{link-to \'Example\' \'example\' (query-params foo=undefined) id=\'the-link\'}}'); - - this.setSingleQPController('example', 'foo', undefined, { - foo: undefined - }); - - this.add('route:example', Route.extend({ - model(params) { - assert.deepEqual(params, { foo: undefined }); - } - })); - - return this.visitAndAssert('/').then(() => { - assert.equal(this.$('#the-link').attr('href'), '/example', 'renders without undefined qp serialized'); + this.setSingleQPController('example', 'foo', undefined, { + foo: undefined + }); - return this.transitionTo('example', { queryParams: { foo: undefined } }).then(() => { - this.assertCurrentPath('/example'); + this.add( + 'route:example', + Route.extend({ + model(params) { + assert.deepEqual(params, { foo: undefined }); + } + }) + ); + + return this.visitAndAssert('/').then(() => { + assert.equal( + this.$('#the-link').attr('href'), + '/example', + 'renders without undefined qp serialized' + ); + + return this.transitionTo('example', { + queryParams: { foo: undefined } + }).then(() => { + this.assertCurrentPath('/example'); + }); }); - }); + } } -}); +); diff --git a/packages/ember/tests/routing/query_params_test/query_params_paramless_link_to_test.js b/packages/ember/tests/routing/query_params_test/query_params_paramless_link_to_test.js index 5867fbe1734..edf82ff6a44 100644 --- a/packages/ember/tests/routing/query_params_test/query_params_paramless_link_to_test.js +++ b/packages/ember/tests/routing/query_params_test/query_params_paramless_link_to_test.js @@ -1,27 +1,43 @@ import { Controller } from 'ember-runtime'; import { QueryParamTestCase, moduleFor } from 'internal-test-helpers'; -moduleFor('Query Params - paramless link-to', class extends QueryParamTestCase { - testParamlessLinks(assert, routeName) { - assert.expect(1); +moduleFor( + 'Query Params - paramless link-to', + class extends QueryParamTestCase { + testParamlessLinks(assert, routeName) { + assert.expect(1); - this.addTemplate(routeName, '{{link-to \'index\' \'index\' id=\'index-link\'}}'); + this.addTemplate( + routeName, + "{{link-to 'index' 'index' id='index-link'}}" + ); - this.add(`controller:${routeName}`, Controller.extend({ - queryParams: ['foo'], - foo: 'wat' - })); + this.add( + `controller:${routeName}`, + Controller.extend({ + queryParams: ['foo'], + foo: 'wat' + }) + ); - return this.visit('/?foo=YEAH').then(() => { - assert.equal(document.getElementById('index-link').getAttribute('href'), '/?foo=YEAH'); - }); - } + return this.visit('/?foo=YEAH').then(() => { + assert.equal( + document.getElementById('index-link').getAttribute('href'), + '/?foo=YEAH' + ); + }); + } - ['@test param-less links in an app booted with query params in the URL don\'t reset the query params: application'](assert) { - return this.testParamlessLinks(assert, 'application'); - } + ["@test param-less links in an app booted with query params in the URL don't reset the query params: application"]( + assert + ) { + return this.testParamlessLinks(assert, 'application'); + } - ['@test param-less links in an app booted with query params in the URL don\'t reset the query params: index'](assert) { - return this.testParamlessLinks(assert, 'index'); + ["@test param-less links in an app booted with query params in the URL don't reset the query params: index"]( + assert + ) { + return this.testParamlessLinks(assert, 'index'); + } } -}); +); diff --git a/packages/ember/tests/routing/query_params_test/shared_state_test.js b/packages/ember/tests/routing/query_params_test/shared_state_test.js index c4e14d92fca..809e2e57a7b 100644 --- a/packages/ember/tests/routing/query_params_test/shared_state_test.js +++ b/packages/ember/tests/routing/query_params_test/shared_state_test.js @@ -1,75 +1,88 @@ -import { - Controller, - Service, - inject -} from 'ember-runtime'; +import { Controller, Service, inject } from 'ember-runtime'; import { run } from 'ember-metal'; import { QueryParamTestCase, moduleFor } from 'internal-test-helpers'; -moduleFor('Query Params - shared service state', class extends QueryParamTestCase { +moduleFor( + 'Query Params - shared service state', + class extends QueryParamTestCase { + boot() { + this.setupApplication(); + return this.visitApplication(); + } - boot() { - this.setupApplication(); - return this.visitApplication(); - } - - setupApplication() { - this.router.map(function() { - this.route('home', { path: '/' }); - this.route('dashboard'); - }); + setupApplication() { + this.router.map(function() { + this.route('home', { path: '/' }); + this.route('dashboard'); + }); - this.add('service:filters', Service.extend({ - shared: true - })); + this.add( + 'service:filters', + Service.extend({ + shared: true + }) + ); - this.add('controller:home', Controller.extend({ - filters: inject.service() - })); + this.add( + 'controller:home', + Controller.extend({ + filters: inject.service() + }) + ); - this.add('controller:dashboard', Controller.extend({ - filters: inject.service(), - queryParams: [ - { 'filters.shared': 'shared' } - ] - })); + this.add( + 'controller:dashboard', + Controller.extend({ + filters: inject.service(), + queryParams: [{ 'filters.shared': 'shared' }] + }) + ); - this.addTemplate('application', `{{link-to 'Home' 'home' }}
    {{outlet}}
    `); - this.addTemplate('home', `{{link-to 'Dashboard' 'dashboard' }}{{input type="checkbox" id='filters-checkbox' checked=(mut filters.shared) }}`); - this.addTemplate('dashboard', `{{link-to 'Home' 'home' }}`); - } - visitApplication() { - return this.visit('/'); - } + this.addTemplate( + 'application', + `{{link-to 'Home' 'home' }}
    {{outlet}}
    ` + ); + this.addTemplate( + 'home', + `{{link-to 'Dashboard' 'dashboard' }}{{input type="checkbox" id='filters-checkbox' checked=(mut filters.shared) }}` + ); + this.addTemplate('dashboard', `{{link-to 'Home' 'home' }}`); + } + visitApplication() { + return this.visit('/'); + } - ['@test can modify shared state before transition'](assert) { - assert.expect(1); + ['@test can modify shared state before transition'](assert) { + assert.expect(1); - return this.boot().then(() => { - this.$input = document.getElementById('filters-checkbox'); + return this.boot().then(() => { + this.$input = document.getElementById('filters-checkbox'); - // click the checkbox once to set filters.shared to false - run(this.$input, 'click'); + // click the checkbox once to set filters.shared to false + run(this.$input, 'click'); - return this.visit('/dashboard').then(() => { - assert.ok(true, 'expecting navigating to dashboard to succeed'); + return this.visit('/dashboard').then(() => { + assert.ok(true, 'expecting navigating to dashboard to succeed'); + }); }); - }); - } + } - ['@test can modify shared state back to the default value before transition'](assert) { - assert.expect(1); + ['@test can modify shared state back to the default value before transition']( + assert + ) { + assert.expect(1); - return this.boot().then(() => { - this.$input = document.getElementById('filters-checkbox'); + return this.boot().then(() => { + this.$input = document.getElementById('filters-checkbox'); - // click the checkbox twice to set filters.shared to false and back to true - run(this.$input, 'click'); - run(this.$input, 'click'); + // click the checkbox twice to set filters.shared to false and back to true + run(this.$input, 'click'); + run(this.$input, 'click'); - return this.visit('/dashboard').then(() => { - assert.ok(true, 'expecting navigating to dashboard to succeed'); + return this.visit('/dashboard').then(() => { + assert.ok(true, 'expecting navigating to dashboard to succeed'); + }); }); - }); + } } -}); +); diff --git a/packages/ember/tests/routing/router_map_test.js b/packages/ember/tests/routing/router_map_test.js index 48b1bd2b644..8857df7e9e5 100644 --- a/packages/ember/tests/routing/router_map_test.js +++ b/packages/ember/tests/routing/router_map_test.js @@ -2,39 +2,45 @@ import { moduleFor, ApplicationTestCase } from 'internal-test-helpers'; import { run } from 'ember-metal'; import { Router } from 'ember-routing'; -moduleFor('Router.map', class extends ApplicationTestCase { - ['@test Router.map returns an Ember Router class'](assert) { - assert.expect(1); - - let ret = this.router.map(function() { - this.route('hello'); - }); +moduleFor( + 'Router.map', + class extends ApplicationTestCase { + ['@test Router.map returns an Ember Router class'](assert) { + assert.expect(1); + + let ret = this.router.map(function() { + this.route('hello'); + }); - assert.ok(Router.detect(ret)); - } + assert.ok(Router.detect(ret)); + } - ['@test Router.map can be called multiple times'](assert) { - assert.expect(2); + ['@test Router.map can be called multiple times'](assert) { + assert.expect(2); - this.addTemplate('hello', 'Hello!'); - this.addTemplate('goodbye', 'Goodbye!'); + this.addTemplate('hello', 'Hello!'); + this.addTemplate('goodbye', 'Goodbye!'); - this.router.map(function() { - this.route('hello'); - }); + this.router.map(function() { + this.route('hello'); + }); - this.router.map(function() { - this.route('goodbye'); - }); + this.router.map(function() { + this.route('goodbye'); + }); - return run(() => { - return this.visit('/hello').then(() => { - this.assertText('Hello!'); - }).then(() => { - return this.visit('/goodbye'); - }).then(() => { - this.assertText('Goodbye!'); + return run(() => { + return this.visit('/hello') + .then(() => { + this.assertText('Hello!'); + }) + .then(() => { + return this.visit('/goodbye'); + }) + .then(() => { + this.assertText('Goodbye!'); + }); }); - }); + } } -}); +); diff --git a/packages/ember/tests/routing/router_service_test/basic_test.js b/packages/ember/tests/routing/router_service_test/basic_test.js index d7cea3dd32c..df0d7392f10 100644 --- a/packages/ember/tests/routing/router_service_test/basic_test.js +++ b/packages/ember/tests/routing/router_service_test/basic_test.js @@ -1,94 +1,127 @@ import { Route, NoneLocation } from 'ember-routing'; -import { - set -} from 'ember-metal'; -import { - RouterTestCase, - moduleFor -} from 'internal-test-helpers'; +import { set } from 'ember-metal'; +import { RouterTestCase, moduleFor } from 'internal-test-helpers'; import { EMBER_ROUTING_ROUTER_SERVICE } from 'ember/features'; if (EMBER_ROUTING_ROUTER_SERVICE) { - moduleFor('Router Service - main', class extends RouterTestCase { - ['@test RouterService#currentRouteName is correctly set for top level route'](assert) { - assert.expect(1); - - return this.visit('/').then(() => { - assert.equal(this.routerService.get('currentRouteName'), 'parent.index'); - }); - } - - ['@test RouterService#currentRouteName is correctly set for child route'](assert) { - assert.expect(1); - - return this.visit('/child').then(() => { - assert.equal(this.routerService.get('currentRouteName'), 'parent.child'); - }); - } - - ['@test RouterService#currentRouteName is correctly set after transition'](assert) { - assert.expect(1); - - return this.visit('/child') - .then(() => { - return this.routerService.transitionTo('parent.sister'); - }) - .then(() => { - assert.equal(this.routerService.get('currentRouteName'), 'parent.sister'); + moduleFor( + 'Router Service - main', + class extends RouterTestCase { + ['@test RouterService#currentRouteName is correctly set for top level route']( + assert + ) { + assert.expect(1); + + return this.visit('/').then(() => { + assert.equal( + this.routerService.get('currentRouteName'), + 'parent.index' + ); }); - } - - ['@test RouterService#currentRouteName is correctly set on each transition'](assert) { - assert.expect(3); - - return this.visit('/child') - .then(() => { - assert.equal(this.routerService.get('currentRouteName'), 'parent.child'); - - return this.visit('/sister'); - }) - .then(() => { - assert.equal(this.routerService.get('currentRouteName'), 'parent.sister'); - - return this.visit('/brother'); - }) - .then(() => { - assert.equal(this.routerService.get('currentRouteName'), 'parent.brother'); + } + + ['@test RouterService#currentRouteName is correctly set for child route']( + assert + ) { + assert.expect(1); + + return this.visit('/child').then(() => { + assert.equal( + this.routerService.get('currentRouteName'), + 'parent.child' + ); }); - } - - ['@test RouterService#rootURL is correctly set to the default value'](assert) { - assert.expect(1); - - return this.visit('/').then(() => { - assert.equal(this.routerService.get('rootURL'), '/'); - }); - } - - ['@test RouterService#rootURL is correctly set to a custom value'](assert) { - assert.expect(1); - - this.add('route:parent.index', Route.extend({ - init() { - this._super(); - set(this._router, 'rootURL', '/homepage'); - } - })); - - return this.visit('/').then(() => { - assert.equal(this.routerService.get('rootURL'), '/homepage'); - }); - } + } + + ['@test RouterService#currentRouteName is correctly set after transition']( + assert + ) { + assert.expect(1); + + return this.visit('/child') + .then(() => { + return this.routerService.transitionTo('parent.sister'); + }) + .then(() => { + assert.equal( + this.routerService.get('currentRouteName'), + 'parent.sister' + ); + }); + } + + ['@test RouterService#currentRouteName is correctly set on each transition']( + assert + ) { + assert.expect(3); + + return this.visit('/child') + .then(() => { + assert.equal( + this.routerService.get('currentRouteName'), + 'parent.child' + ); + + return this.visit('/sister'); + }) + .then(() => { + assert.equal( + this.routerService.get('currentRouteName'), + 'parent.sister' + ); + + return this.visit('/brother'); + }) + .then(() => { + assert.equal( + this.routerService.get('currentRouteName'), + 'parent.brother' + ); + }); + } + + ['@test RouterService#rootURL is correctly set to the default value']( + assert + ) { + assert.expect(1); + + return this.visit('/').then(() => { + assert.equal(this.routerService.get('rootURL'), '/'); + }); + } + + ['@test RouterService#rootURL is correctly set to a custom value']( + assert + ) { + assert.expect(1); + + this.add( + 'route:parent.index', + Route.extend({ + init() { + this._super(); + set(this._router, 'rootURL', '/homepage'); + } + }) + ); + + return this.visit('/').then(() => { + assert.equal(this.routerService.get('rootURL'), '/homepage'); + }); + } - ['@test RouterService#location is correctly delegated from router:main'](assert) { - assert.expect(2); + ['@test RouterService#location is correctly delegated from router:main']( + assert + ) { + assert.expect(2); - return this.visit('/').then(() => { - let location = this.routerService.get('location'); - assert.ok(location); - assert.ok(location instanceof NoneLocation); - }); + return this.visit('/').then(() => { + let location = this.routerService.get('location'); + assert.ok(location); + assert.ok(location instanceof NoneLocation); + }); + } } - }); + ); } diff --git a/packages/ember/tests/routing/router_service_test/currenturl_lifecycle_test.js b/packages/ember/tests/routing/router_service_test/currenturl_lifecycle_test.js index 3acd5352fa2..ae1ac1d0b94 100644 --- a/packages/ember/tests/routing/router_service_test/currenturl_lifecycle_test.js +++ b/packages/ember/tests/routing/router_service_test/currenturl_lifecycle_test.js @@ -1,14 +1,8 @@ -import { - inject, - readOnly -} from 'ember-runtime'; +import { inject, readOnly } from 'ember-runtime'; import { Component } from 'ember-glimmer'; import { Route } from 'ember-routing'; import { get } from 'ember-metal'; -import { - RouterTestCase, - moduleFor -} from 'internal-test-helpers'; +import { RouterTestCase, moduleFor } from 'internal-test-helpers'; import { EMBER_ROUTING_ROUTER_SERVICE } from 'ember/features'; @@ -21,129 +15,156 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { beforeModel() { let service = get(this, 'routerService'); - results.push([service.get('currentRouteName'), 'beforeModel', service.get('currentURL')]); + results.push([ + service.get('currentRouteName'), + 'beforeModel', + service.get('currentURL') + ]); }, model() { let service = get(this, 'routerService'); - results.push([service.get('currentRouteName'), 'model', service.get('currentURL')]); + results.push([ + service.get('currentRouteName'), + 'model', + service.get('currentURL') + ]); }, afterModel() { let service = get(this, 'routerService'); - results.push([service.get('currentRouteName'), 'afterModel', service.get('currentURL')]); + results.push([ + service.get('currentRouteName'), + 'afterModel', + service.get('currentURL') + ]); } }); - moduleFor('Router Service - currentURL', class extends RouterTestCase { - constructor() { - super(); - - results = []; - - ROUTE_NAMES.forEach((name) => { - let routeName = `parent.${name}`; - this.add(`route:${routeName}`, InstrumentedRoute.extend()); - this.addTemplate(routeName, '{{current-url}}'); - }); - - this.addComponent('current-url', { - ComponentClass: Component.extend({ - routerService: inject.service('router'), - currentURL: readOnly('routerService.currentURL') - }), - template: '{{currentURL}}' - }); - } - - ['@test RouterService#currentURL is correctly set for top level route'](assert) { - assert.expect(1); - - return this.visit('/').then(() => { - assert.equal(this.routerService.get('currentURL'), '/'); - }); - } - - ['@test RouterService#currentURL is correctly set for child route'](assert) { - assert.expect(1); + moduleFor( + 'Router Service - currentURL', + class extends RouterTestCase { + constructor() { + super(); - return this.visit('/child').then(() => { - assert.equal(this.routerService.get('currentURL'), '/child'); - }); - } + results = []; - ['@test RouterService#currentURL is correctly set after transition'](assert) { - assert.expect(1); - - return this.visit('/child') - .then(() => { - return this.routerService.transitionTo('parent.sister'); - }) - .then(() => { - assert.equal(this.routerService.get('currentURL'), '/sister'); + ROUTE_NAMES.forEach(name => { + let routeName = `parent.${name}`; + this.add(`route:${routeName}`, InstrumentedRoute.extend()); + this.addTemplate(routeName, '{{current-url}}'); }); - } - - ['@test RouterService#currentURL is correctly set on each transition'](assert) { - assert.expect(3); - - return this.visit('/child') - .then(() => { - assert.equal(this.routerService.get('currentURL'), '/child'); - return this.visit('/sister'); - }) - .then(() => { - assert.equal(this.routerService.get('currentURL'), '/sister'); - - return this.visit('/brother'); - }) - .then(() => { - assert.equal(this.routerService.get('currentURL'), '/brother'); - }); - } - - ['@test RouterService#currentURL is not set during lifecycle hooks'](assert) { - assert.expect(2); - - return this.visit('/') - .then(() => { - assert.deepEqual(results, [ - [null, 'beforeModel', null], - [null, 'model', null], - [null, 'afterModel', null] - ]); - - results = []; - - return this.visit('/child'); - }) - .then(() => { - assert.deepEqual(results, [ - ['parent.index', 'beforeModel', '/'], - ['parent.index', 'model', '/'], - ['parent.index', 'afterModel', '/'] - ]); + this.addComponent('current-url', { + ComponentClass: Component.extend({ + routerService: inject.service('router'), + currentURL: readOnly('routerService.currentURL') + }), + template: '{{currentURL}}' }); - } + } - ['@test RouterService#currentURL is correctly set with component after consecutive visits'](assert) { - assert.expect(3); + ['@test RouterService#currentURL is correctly set for top level route']( + assert + ) { + assert.expect(1); - return this.visit('/') - .then(() => { - this.assertText('/'); + return this.visit('/').then(() => { + assert.equal(this.routerService.get('currentURL'), '/'); + }); + } - return this.visit('/child'); - }) - .then(() => { - this.assertText('/child'); + ['@test RouterService#currentURL is correctly set for child route']( + assert + ) { + assert.expect(1); - return this.visit('/'); - }) - .then(() => { - this.assertText('/'); + return this.visit('/child').then(() => { + assert.equal(this.routerService.get('currentURL'), '/child'); }); + } + + ['@test RouterService#currentURL is correctly set after transition']( + assert + ) { + assert.expect(1); + + return this.visit('/child') + .then(() => { + return this.routerService.transitionTo('parent.sister'); + }) + .then(() => { + assert.equal(this.routerService.get('currentURL'), '/sister'); + }); + } + + ['@test RouterService#currentURL is correctly set on each transition']( + assert + ) { + assert.expect(3); + + return this.visit('/child') + .then(() => { + assert.equal(this.routerService.get('currentURL'), '/child'); + + return this.visit('/sister'); + }) + .then(() => { + assert.equal(this.routerService.get('currentURL'), '/sister'); + + return this.visit('/brother'); + }) + .then(() => { + assert.equal(this.routerService.get('currentURL'), '/brother'); + }); + } + + ['@test RouterService#currentURL is not set during lifecycle hooks']( + assert + ) { + assert.expect(2); + + return this.visit('/') + .then(() => { + assert.deepEqual(results, [ + [null, 'beforeModel', null], + [null, 'model', null], + [null, 'afterModel', null] + ]); + + results = []; + + return this.visit('/child'); + }) + .then(() => { + assert.deepEqual(results, [ + ['parent.index', 'beforeModel', '/'], + ['parent.index', 'model', '/'], + ['parent.index', 'afterModel', '/'] + ]); + }); + } + + ['@test RouterService#currentURL is correctly set with component after consecutive visits']( + assert + ) { + assert.expect(3); + + return this.visit('/') + .then(() => { + this.assertText('/'); + + return this.visit('/child'); + }) + .then(() => { + this.assertText('/child'); + + return this.visit('/'); + }) + .then(() => { + this.assertText('/'); + }); + } } - }); + ); } diff --git a/packages/ember/tests/routing/router_service_test/isActive_test.js b/packages/ember/tests/routing/router_service_test/isActive_test.js index bf1c781e38b..54b9bb1ff33 100644 --- a/packages/ember/tests/routing/router_service_test/isActive_test.js +++ b/packages/ember/tests/routing/router_service_test/isActive_test.js @@ -1,101 +1,124 @@ -import { - Controller -} from 'ember-runtime'; -import { - RouterTestCase, - moduleFor -} from 'internal-test-helpers'; +import { Controller } from 'ember-runtime'; +import { RouterTestCase, moduleFor } from 'internal-test-helpers'; import { EMBER_ROUTING_ROUTER_SERVICE } from 'ember/features'; if (EMBER_ROUTING_ROUTER_SERVICE) { - moduleFor('Router Service - isActive', class extends RouterTestCase { - ['@test RouterService#isActive returns true for simple route'](assert) { - assert.expect(1); - - return this.visit('/') - .then(() => { - return this.routerService.transitionTo('parent.child'); - }) - .then(() => { - return this.routerService.transitionTo('parent.sister'); - }) - .then(() => { - assert.ok(this.routerService.isActive('parent.sister')); - }); + moduleFor( + 'Router Service - isActive', + class extends RouterTestCase { + ['@test RouterService#isActive returns true for simple route'](assert) { + assert.expect(1); + + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('parent.child'); + }) + .then(() => { + return this.routerService.transitionTo('parent.sister'); + }) + .then(() => { + assert.ok(this.routerService.isActive('parent.sister')); + }); + } + + ['@test RouterService#isActive returns true for simple route with dynamic segments']( + assert + ) { + assert.expect(1); + + let dynamicModel = { id: 1 }; + + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('dynamic', dynamicModel); + }) + .then(() => { + assert.ok(this.routerService.isActive('dynamic', dynamicModel)); + }); + } + + ['@test RouterService#isActive does not eagerly instantiate controller for query params']( + assert + ) { + assert.expect(1); + + let queryParams = this.buildQueryParams({ sort: 'ASC' }); + + this.add( + 'controller:parent.sister', + Controller.extend({ + queryParams: ['sort'], + sort: 'ASC', + + init() { + assert.ok(false, 'should never create'); + this._super(...arguments); + } + }) + ); + + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('parent.brother'); + }) + .then(() => { + assert.notOk( + this.routerService.isActive('parent.sister', queryParams) + ); + }); + } + + ['@test RouterService#isActive is correct for simple route with basic query params']( + assert + ) { + assert.expect(2); + + let queryParams = this.buildQueryParams({ sort: 'ASC' }); + + this.add( + 'controller:parent.child', + Controller.extend({ + queryParams: ['sort'], + sort: 'ASC' + }) + ); + + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('parent.child', queryParams); + }) + .then(() => { + assert.ok(this.routerService.isActive('parent.child', queryParams)); + assert.notOk( + this.routerService.isActive( + 'parent.child', + this.buildQueryParams({ sort: 'DESC' }) + ) + ); + }); + } + + ['@test RouterService#isActive for simple route with array as query params']( + assert + ) { + assert.expect(1); + + let queryParams = this.buildQueryParams({ sort: ['ascending'] }); + + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('parent.child', queryParams); + }) + .then(() => { + assert.notOk( + this.routerService.isActive( + 'parent.child', + this.buildQueryParams({ sort: 'descending' }) + ) + ); + }); + } } - - ['@test RouterService#isActive returns true for simple route with dynamic segments'](assert) { - assert.expect(1); - - let dynamicModel = { id: 1 }; - - return this.visit('/') - .then(() => { - return this.routerService.transitionTo('dynamic', dynamicModel); - }) - .then(() => { - assert.ok(this.routerService.isActive('dynamic', dynamicModel)); - }); - } - - ['@test RouterService#isActive does not eagerly instantiate controller for query params'](assert) { - assert.expect(1); - - let queryParams = this.buildQueryParams({ sort: 'ASC' }); - - this.add('controller:parent.sister', Controller.extend({ - queryParams: ['sort'], - sort: 'ASC', - - init() { - assert.ok(false, 'should never create'); - this._super(...arguments); - } - })); - - return this.visit('/') - .then(() => { - return this.routerService.transitionTo('parent.brother'); - }) - .then(() => { - assert.notOk(this.routerService.isActive('parent.sister', queryParams)); - }); - } - - ['@test RouterService#isActive is correct for simple route with basic query params'](assert) { - assert.expect(2); - - let queryParams = this.buildQueryParams({ sort: 'ASC' }); - - this.add('controller:parent.child', Controller.extend({ - queryParams: ['sort'], - sort: 'ASC' - }) - ); - - return this.visit('/') - .then(() => { - return this.routerService.transitionTo('parent.child', queryParams); - }) - .then(() => { - assert.ok(this.routerService.isActive('parent.child', queryParams)); - assert.notOk(this.routerService.isActive('parent.child', this.buildQueryParams({ sort: 'DESC' }))); - }); - } - - ['@test RouterService#isActive for simple route with array as query params'](assert) { - assert.expect(1); - - let queryParams = this.buildQueryParams({ sort: ['ascending'] }); - - return this.visit('/') - .then(() => { - return this.routerService.transitionTo('parent.child', queryParams); - }) - .then(() => { - assert.notOk(this.routerService.isActive('parent.child', this.buildQueryParams({ sort: 'descending' }))); - }); - } - }); + ); } diff --git a/packages/ember/tests/routing/router_service_test/replaceWith_test.js b/packages/ember/tests/routing/router_service_test/replaceWith_test.js index 40770d281ba..394885b297a 100644 --- a/packages/ember/tests/routing/router_service_test/replaceWith_test.js +++ b/packages/ember/tests/routing/router_service_test/replaceWith_test.js @@ -1,135 +1,148 @@ import { NoneLocation } from 'ember-routing'; -import { - RouterTestCase, - moduleFor -} from 'internal-test-helpers'; +import { RouterTestCase, moduleFor } from 'internal-test-helpers'; import { Transition } from 'router'; import { Controller } from 'ember-runtime'; import { EMBER_ROUTING_ROUTER_SERVICE } from 'ember/features'; if (EMBER_ROUTING_ROUTER_SERVICE) { - moduleFor('Router Service - replaceWith', class extends RouterTestCase { - constructor() { - super(); - - let testCase = this; - testCase.state = []; - - this.add('location:test', NoneLocation.extend({ - setURL(path) { - testCase.state.push(path); - this.set('path', path); - }, - - replaceURL(path) { - testCase.state.splice(testCase.state.length -1, 1, path); - this.set('path', path); - } - })); - } - - get routerOptions() { - return { - location: 'test' - }; - } - - ['@test RouterService#replaceWith returns a Transition'](assert) { - assert.expect(1); - - let transition; - - return this.visit('/') - .then(() => { + moduleFor( + 'Router Service - replaceWith', + class extends RouterTestCase { + constructor() { + super(); + + let testCase = this; + testCase.state = []; + + this.add( + 'location:test', + NoneLocation.extend({ + setURL(path) { + testCase.state.push(path); + this.set('path', path); + }, + + replaceURL(path) { + testCase.state.splice(testCase.state.length - 1, 1, path); + this.set('path', path); + } + }) + ); + } + + get routerOptions() { + return { + location: 'test' + }; + } + + ['@test RouterService#replaceWith returns a Transition'](assert) { + assert.expect(1); + + let transition; + + return this.visit('/').then(() => { transition = this.routerService.replaceWith('parent.child'); assert.ok(transition instanceof Transition); return transition; }); + } + + ['@test RouterService#replaceWith with basic route replaces location']( + assert + ) { + assert.expect(1); + + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('parent.child'); + }) + .then(() => { + return this.routerService.transitionTo('parent.sister'); + }) + .then(() => { + return this.routerService.replaceWith('parent.brother'); + }) + .then(() => { + assert.deepEqual(this.state, ['/', '/child', '/brother']); + }); + } + + ['@test RouterService#replaceWith with basic route using URLs replaces location']( + assert + ) { + assert.expect(1); + + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('/child'); + }) + .then(() => { + return this.routerService.transitionTo('/sister'); + }) + .then(() => { + return this.routerService.replaceWith('/brother'); + }) + .then(() => { + assert.deepEqual(this.state, ['/', '/child', '/brother']); + }); + } + + ['@test RouterService#replaceWith transitioning back to previously visited route replaces location']( + assert + ) { + assert.expect(1); + + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('parent.child'); + }) + .then(() => { + return this.routerService.transitionTo('parent.sister'); + }) + .then(() => { + return this.routerService.transitionTo('parent.brother'); + }) + .then(() => { + return this.routerService.replaceWith('parent.sister'); + }) + .then(() => { + assert.deepEqual(this.state, ['/', '/child', '/sister', '/sister']); + }); + } + + ['@test RouterService#replaceWith with basic query params does not remove query param defaults']( + assert + ) { + assert.expect(1); + + this.add( + 'controller:parent.child', + Controller.extend({ + queryParams: ['sort'], + sort: 'ASC' + }) + ); + + let queryParams = this.buildQueryParams({ sort: 'ASC' }); + + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('parent.brother'); + }) + .then(() => { + return this.routerService.replaceWith('parent.sister'); + }) + .then(() => { + return this.routerService.replaceWith('parent.child', queryParams); + }) + .then(() => { + assert.deepEqual(this.state, ['/', '/child?sort=ASC']); + }); + } } - - ['@test RouterService#replaceWith with basic route replaces location'](assert) { - assert.expect(1); - - return this.visit('/') - .then(() => { - return this.routerService.transitionTo('parent.child'); - }) - .then(() => { - return this.routerService.transitionTo('parent.sister'); - }) - .then(() => { - return this.routerService.replaceWith('parent.brother'); - }) - .then(() => { - assert.deepEqual(this.state, ['/', '/child', '/brother']); - }); - } - - ['@test RouterService#replaceWith with basic route using URLs replaces location'](assert) { - assert.expect(1); - - return this.visit('/') - .then(() => { - return this.routerService.transitionTo('/child'); - }) - .then(() => { - return this.routerService.transitionTo('/sister'); - }) - .then(() => { - return this.routerService.replaceWith('/brother'); - }) - .then(() => { - assert.deepEqual(this.state, ['/', '/child', '/brother']); - }); - } - - ['@test RouterService#replaceWith transitioning back to previously visited route replaces location'](assert) { - assert.expect(1); - - return this.visit('/') - .then(() => { - return this.routerService.transitionTo('parent.child'); - }) - .then(() => { - return this.routerService.transitionTo('parent.sister'); - }) - .then(() => { - return this.routerService.transitionTo('parent.brother'); - }) - .then(() => { - return this.routerService.replaceWith('parent.sister'); - }) - .then(() => { - assert.deepEqual(this.state, ['/', '/child', '/sister', '/sister']); - }); - } - - ['@test RouterService#replaceWith with basic query params does not remove query param defaults'](assert) { - assert.expect(1); - - this.add('controller:parent.child', Controller.extend({ - queryParams: ['sort'], - sort: 'ASC' - })); - - let queryParams = this.buildQueryParams({ sort: 'ASC' }); - - return this.visit('/') - .then(() => { - return this.routerService.transitionTo('parent.brother'); - }) - .then(() => { - return this.routerService.replaceWith('parent.sister'); - }) - .then(() => { - return this.routerService.replaceWith('parent.child', queryParams); - }) - .then(() => { - assert.deepEqual(this.state, ['/', '/child?sort=ASC']); - }); - } - }); + ); } diff --git a/packages/ember/tests/routing/router_service_test/transitionTo_test.js b/packages/ember/tests/routing/router_service_test/transitionTo_test.js index 04c4532e81c..7eca063aff4 100644 --- a/packages/ember/tests/routing/router_service_test/transitionTo_test.js +++ b/packages/ember/tests/routing/router_service_test/transitionTo_test.js @@ -2,342 +2,408 @@ import { inject } from 'ember-runtime'; import { Component } from 'ember-glimmer'; import { Route, NoneLocation } from 'ember-routing'; import { Controller } from 'ember-runtime'; -import { - run, - get -} from 'ember-metal'; -import { - RouterTestCase, - moduleFor -} from 'internal-test-helpers'; +import { run, get } from 'ember-metal'; +import { RouterTestCase, moduleFor } from 'internal-test-helpers'; import { Transition } from 'router'; import { EMBER_ROUTING_ROUTER_SERVICE } from 'ember/features'; if (EMBER_ROUTING_ROUTER_SERVICE) { - moduleFor('Router Service - transitionTo', class extends RouterTestCase { - constructor() { - super(); - - let testCase = this; - testCase.state = []; - - this.add('location:test', NoneLocation.extend({ - setURL(path) { - testCase.state.push(path); - this.set('path', path); - }, - - replaceURL(path) { - testCase.state.splice(testCase.state.length -1, 1, path); - this.set('path', path); - } - })); - } + moduleFor( + 'Router Service - transitionTo', + class extends RouterTestCase { + constructor() { + super(); + + let testCase = this; + testCase.state = []; + + this.add( + 'location:test', + NoneLocation.extend({ + setURL(path) { + testCase.state.push(path); + this.set('path', path); + }, + + replaceURL(path) { + testCase.state.splice(testCase.state.length - 1, 1, path); + this.set('path', path); + } + }) + ); + } - get routerOptions() { - return { - location: 'test' - }; - } + get routerOptions() { + return { + location: 'test' + }; + } - ['@test RouterService#transitionTo returns a Transition'](assert) { - assert.expect(1); + ['@test RouterService#transitionTo returns a Transition'](assert) { + assert.expect(1); - let transition; + let transition; - return this.visit('/') - .then(() => { + return this.visit('/').then(() => { transition = this.routerService.transitionTo('parent.child'); assert.ok(transition instanceof Transition); return transition; }); - } - - ['@test RouterService#transitionTo with basic route updates location'](assert) { - assert.expect(1); - - return this.visit('/') - .then(() => { - return this.routerService.transitionTo('parent.child'); - }) - .then(() => { - return this.routerService.transitionTo('parent.sister'); - }) - .then(() => { - return this.routerService.transitionTo('parent.brother'); - }) - .then(() => { - assert.deepEqual(this.state, ['/', '/child', '/sister', '/brother']); - }); - } - - ['@test RouterService#transitionTo transitioning back to previously visited route updates location'](assert) { - assert.expect(1); - - return this.visit('/') - .then(() => { - return this.routerService.transitionTo('parent.child'); - }) - .then(() => { - return this.routerService.transitionTo('parent.sister'); - }) - .then(() => { - return this.routerService.transitionTo('parent.brother'); - }) - .then(() => { - return this.routerService.transitionTo('parent.sister'); - }) - .then(() => { - assert.deepEqual(this.state, ['/', '/child', '/sister', '/brother', '/sister']); - }); - } - - ['@test RouterService#transitionTo with basic route'](assert) { - assert.expect(1); - - let componentInstance; - - this.addTemplate('parent.index', '{{foo-bar}}'); - - this.addComponent('foo-bar', { - ComponentClass: Component.extend({ - routerService: inject.service('router'), - init() { - this._super(); - componentInstance = this; - }, - actions: { - transitionToSister() { - get(this, 'routerService').transitionTo('parent.sister'); + } + + ['@test RouterService#transitionTo with basic route updates location']( + assert + ) { + assert.expect(1); + + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('parent.child'); + }) + .then(() => { + return this.routerService.transitionTo('parent.sister'); + }) + .then(() => { + return this.routerService.transitionTo('parent.brother'); + }) + .then(() => { + assert.deepEqual(this.state, [ + '/', + '/child', + '/sister', + '/brother' + ]); + }); + } + + ['@test RouterService#transitionTo transitioning back to previously visited route updates location']( + assert + ) { + assert.expect(1); + + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('parent.child'); + }) + .then(() => { + return this.routerService.transitionTo('parent.sister'); + }) + .then(() => { + return this.routerService.transitionTo('parent.brother'); + }) + .then(() => { + return this.routerService.transitionTo('parent.sister'); + }) + .then(() => { + assert.deepEqual(this.state, [ + '/', + '/child', + '/sister', + '/brother', + '/sister' + ]); + }); + } + + ['@test RouterService#transitionTo with basic route'](assert) { + assert.expect(1); + + let componentInstance; + + this.addTemplate('parent.index', '{{foo-bar}}'); + + this.addComponent('foo-bar', { + ComponentClass: Component.extend({ + routerService: inject.service('router'), + init() { + this._super(); + componentInstance = this; + }, + actions: { + transitionToSister() { + get(this, 'routerService').transitionTo('parent.sister'); + } } - } - }), - template: `foo-bar` - }); - - return this.visit('/').then(() => { - run(function() { - componentInstance.send('transitionToSister'); + }), + template: `foo-bar` }); - assert.equal(this.routerService.get('currentRouteName'), 'parent.sister'); - }); - } - - ['@test RouterService#transitionTo with basic route using URL'](assert) { - assert.expect(1); - - let componentInstance; + return this.visit('/').then(() => { + run(function() { + componentInstance.send('transitionToSister'); + }); - this.addTemplate('parent.index', '{{foo-bar}}'); - - this.addComponent('foo-bar', { - ComponentClass: Component.extend({ - routerService: inject.service('router'), - init() { - this._super(); - componentInstance = this; - }, - actions: { - transitionToSister() { - get(this, 'routerService').transitionTo('/sister'); - } - } - }), - template: `foo-bar` - }); - - return this.visit('/').then(() => { - run(function() { - componentInstance.send('transitionToSister'); + assert.equal( + this.routerService.get('currentRouteName'), + 'parent.sister' + ); }); - - assert.equal(this.routerService.get('currentRouteName'), 'parent.sister'); - }); - } - - ['@test RouterService#transitionTo with dynamic segment'](assert) { - assert.expect(3); - - let componentInstance; - let dynamicModel = { id: 1, contents: 'much dynamicism' }; - - this.addTemplate('parent.index', '{{foo-bar}}'); - this.addTemplate('dynamic', '{{model.contents}}'); - - this.addComponent('foo-bar', { - ComponentClass: Component.extend({ - routerService: inject.service('router'), - init() { - this._super(); - componentInstance = this; - }, - actions: { - transitionToDynamic() { - get(this, 'routerService').transitionTo('dynamic', dynamicModel); + } + + ['@test RouterService#transitionTo with basic route using URL'](assert) { + assert.expect(1); + + let componentInstance; + + this.addTemplate('parent.index', '{{foo-bar}}'); + + this.addComponent('foo-bar', { + ComponentClass: Component.extend({ + routerService: inject.service('router'), + init() { + this._super(); + componentInstance = this; + }, + actions: { + transitionToSister() { + get(this, 'routerService').transitionTo('/sister'); + } } - } - }), - template: `foo-bar` - }); - - return this.visit('/').then(() => { - run(function() { - componentInstance.send('transitionToDynamic'); + }), + template: `foo-bar` }); - assert.equal(this.routerService.get('currentRouteName'), 'dynamic'); - assert.equal(this.routerService.get('currentURL'), '/dynamic/1'); - this.assertText('much dynamicism'); - }); - } + return this.visit('/').then(() => { + run(function() { + componentInstance.send('transitionToSister'); + }); - ['@test RouterService#transitionTo with dynamic segment and model hook'](assert) { - assert.expect(3); - - let componentInstance; - let dynamicModel = { id: 1, contents: 'much dynamicism' }; - - this.add('route:dynamic', Route.extend({ - model() { - return dynamicModel; - } - })); - - this.addTemplate('parent.index', '{{foo-bar}}'); - this.addTemplate('dynamic', '{{model.contents}}'); - - this.addComponent('foo-bar', { - ComponentClass: Component.extend({ - routerService: inject.service('router'), - init() { - this._super(); - componentInstance = this; - }, - actions: { - transitionToDynamic() { - get(this, 'routerService').transitionTo('dynamic', 1); + assert.equal( + this.routerService.get('currentRouteName'), + 'parent.sister' + ); + }); + } + + ['@test RouterService#transitionTo with dynamic segment'](assert) { + assert.expect(3); + + let componentInstance; + let dynamicModel = { id: 1, contents: 'much dynamicism' }; + + this.addTemplate('parent.index', '{{foo-bar}}'); + this.addTemplate('dynamic', '{{model.contents}}'); + + this.addComponent('foo-bar', { + ComponentClass: Component.extend({ + routerService: inject.service('router'), + init() { + this._super(); + componentInstance = this; + }, + actions: { + transitionToDynamic() { + get(this, 'routerService').transitionTo( + 'dynamic', + dynamicModel + ); + } } - } - }), - template: `foo-bar` - }); - - return this.visit('/').then(() => { - run(function() { - componentInstance.send('transitionToDynamic'); + }), + template: `foo-bar` }); - assert.equal(this.routerService.get('currentRouteName'), 'dynamic'); - assert.equal(this.routerService.get('currentURL'), '/dynamic/1'); - this.assertText('much dynamicism'); - }); - } - - ['@test RouterService#transitionTo with basic query params does not remove query param defaults'](assert) { - assert.expect(1); - - this.add('controller:parent.child', Controller.extend({ - queryParams: ['sort'], - sort: 'ASC' - })); - - let queryParams = this.buildQueryParams({ sort: 'ASC' }); + return this.visit('/').then(() => { + run(function() { + componentInstance.send('transitionToDynamic'); + }); - return this.visit('/') - .then(() => { - return this.routerService.transitionTo('parent.child', queryParams); - }) - .then(() => { - assert.equal(this.routerService.get('currentURL'), '/child?sort=ASC'); + assert.equal(this.routerService.get('currentRouteName'), 'dynamic'); + assert.equal(this.routerService.get('currentURL'), '/dynamic/1'); + this.assertText('much dynamicism'); }); - } - - ['@test RouterService#transitionTo passing only queryParams works'](assert) { - assert.expect(2); - - this.add('controller:parent.child', Controller.extend({ - queryParams: ['sort'] - })); - - let queryParams = this.buildQueryParams({ sort: 'DESC' }); - - return this.visit('/') - .then(() => { - return this.routerService.transitionTo('parent.child'); - }) - .then(() => { - assert.equal(this.routerService.get('currentURL'), '/child'); - }) - .then(() => { - return this.routerService.transitionTo(queryParams); - }) - .then(() => { - assert.equal(this.routerService.get('currentURL'), '/child?sort=DESC'); - }); - } - - ['@test RouterService#transitionTo with unspecified query params'](assert) { - assert.expect(1); + } - this.add('controller:parent.child', Controller.extend({ - queryParams: ['sort', 'page', 'category', 'extra'], - sort: 'ASC', - page: null, - category: undefined - })); + ['@test RouterService#transitionTo with dynamic segment and model hook']( + assert + ) { + assert.expect(3); - let queryParams = this.buildQueryParams({ sort: 'ASC' }); + let componentInstance; + let dynamicModel = { id: 1, contents: 'much dynamicism' }; - return this.visit('/') - .then(() => { - return this.routerService.transitionTo('parent.child', queryParams); - }) - .then(() => { - assert.equal(this.routerService.get('currentURL'), '/child?sort=ASC'); + this.add( + 'route:dynamic', + Route.extend({ + model() { + return dynamicModel; + } + }) + ); + + this.addTemplate('parent.index', '{{foo-bar}}'); + this.addTemplate('dynamic', '{{model.contents}}'); + + this.addComponent('foo-bar', { + ComponentClass: Component.extend({ + routerService: inject.service('router'), + init() { + this._super(); + componentInstance = this; + }, + actions: { + transitionToDynamic() { + get(this, 'routerService').transitionTo('dynamic', 1); + } + } + }), + template: `foo-bar` }); - } - ['@test RouterService#transitionTo with aliased query params uses the original provided key'](assert) { - assert.expect(1); + return this.visit('/').then(() => { + run(function() { + componentInstance.send('transitionToDynamic'); + }); - this.add('controller:parent.child', Controller.extend({ - queryParams: { - 'cont_sort': 'url_sort' - }, - cont_sort: 'ASC' - })); - - let queryParams = this.buildQueryParams({ url_sort: 'ASC' }); - - return this.visit('/').then(() => { - return this.routerService.transitionTo('parent.child', queryParams); - }) - .then(() => { - assert.equal(this.routerService.get('currentURL'), '/child?url_sort=ASC'); + assert.equal(this.routerService.get('currentRouteName'), 'dynamic'); + assert.equal(this.routerService.get('currentURL'), '/dynamic/1'); + this.assertText('much dynamicism'); }); + } + + ['@test RouterService#transitionTo with basic query params does not remove query param defaults']( + assert + ) { + assert.expect(1); + + this.add( + 'controller:parent.child', + Controller.extend({ + queryParams: ['sort'], + sort: 'ASC' + }) + ); + + let queryParams = this.buildQueryParams({ sort: 'ASC' }); + + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('parent.child', queryParams); + }) + .then(() => { + assert.equal( + this.routerService.get('currentURL'), + '/child?sort=ASC' + ); + }); + } + + ['@test RouterService#transitionTo passing only queryParams works']( + assert + ) { + assert.expect(2); + + this.add( + 'controller:parent.child', + Controller.extend({ + queryParams: ['sort'] + }) + ); + + let queryParams = this.buildQueryParams({ sort: 'DESC' }); + + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('parent.child'); + }) + .then(() => { + assert.equal(this.routerService.get('currentURL'), '/child'); + }) + .then(() => { + return this.routerService.transitionTo(queryParams); + }) + .then(() => { + assert.equal( + this.routerService.get('currentURL'), + '/child?sort=DESC' + ); + }); + } + + ['@test RouterService#transitionTo with unspecified query params']( + assert + ) { + assert.expect(1); + + this.add( + 'controller:parent.child', + Controller.extend({ + queryParams: ['sort', 'page', 'category', 'extra'], + sort: 'ASC', + page: null, + category: undefined + }) + ); + + let queryParams = this.buildQueryParams({ sort: 'ASC' }); + + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('parent.child', queryParams); + }) + .then(() => { + assert.equal( + this.routerService.get('currentURL'), + '/child?sort=ASC' + ); + }); + } + + ['@test RouterService#transitionTo with aliased query params uses the original provided key']( + assert + ) { + assert.expect(1); + + this.add( + 'controller:parent.child', + Controller.extend({ + queryParams: { + cont_sort: 'url_sort' + }, + cont_sort: 'ASC' + }) + ); + + let queryParams = this.buildQueryParams({ url_sort: 'ASC' }); + + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('parent.child', queryParams); + }) + .then(() => { + assert.equal( + this.routerService.get('currentURL'), + '/child?url_sort=ASC' + ); + }); + } + + ['@test RouterService#transitionTo with aliased query params uses the original provided key when controller property name']( + assert + ) { + assert.expect(1); + + this.add( + 'controller:parent.child', + Controller.extend({ + queryParams: { + cont_sort: 'url_sort' + }, + cont_sort: 'ASC' + }) + ); + + let queryParams = this.buildQueryParams({ cont_sort: 'ASC' }); + + return this.visit('/').then(() => { + expectAssertion(() => { + return this.routerService.transitionTo('parent.child', queryParams); + }, 'You passed the `cont_sort` query parameter during a transition into parent.child, please update to url_sort'); + }); + } } - - ['@test RouterService#transitionTo with aliased query params uses the original provided key when controller property name'](assert) { - assert.expect(1); - - this.add('controller:parent.child', Controller.extend({ - queryParams: { - 'cont_sort': 'url_sort' - }, - cont_sort: 'ASC' - })); - - let queryParams = this.buildQueryParams({ cont_sort: 'ASC' }); - - return this.visit('/').then(() => { - expectAssertion(() => { - return this.routerService.transitionTo('parent.child', queryParams); - }, 'You passed the `cont_sort` query parameter during a transition into parent.child, please update to url_sort'); - }); - } - }); + ); } diff --git a/packages/ember/tests/routing/router_service_test/urlFor_test.js b/packages/ember/tests/routing/router_service_test/urlFor_test.js index 61fca5e3766..d0ada34266a 100644 --- a/packages/ember/tests/routing/router_service_test/urlFor_test.js +++ b/packages/ember/tests/routing/router_service_test/urlFor_test.js @@ -1,15 +1,7 @@ -import { - Controller, - String -} from 'ember-runtime'; +import { Controller, String } from 'ember-runtime'; import { Route } from 'ember-routing'; -import { - get -} from 'ember-metal'; -import { - RouterTestCase, - moduleFor -} from 'internal-test-helpers'; +import { get } from 'ember-metal'; +import { RouterTestCase, moduleFor } from 'internal-test-helpers'; import { EMBER_ROUTING_ROUTER_SERVICE } from 'ember/features'; @@ -18,253 +10,350 @@ function setupController(app, name) { Object.defineProperty(app, controllerName, { get() { - throw new Error(`Generating a URL should not require instantiation of a ${controllerName}.`); + throw new Error( + `Generating a URL should not require instantiation of a ${controllerName}.` + ); } }); } if (EMBER_ROUTING_ROUTER_SERVICE) { - moduleFor('Router Service - urlFor', class extends RouterTestCase { - ['@test RouterService#urlFor returns URL for simple route'](assert) { - assert.expect(1); + moduleFor( + 'Router Service - urlFor', + class extends RouterTestCase { + ['@test RouterService#urlFor returns URL for simple route'](assert) { + assert.expect(1); - return this.visit('/').then(() => { - let expectedURL = this.routerService.urlFor('parent.child'); + return this.visit('/').then(() => { + let expectedURL = this.routerService.urlFor('parent.child'); - assert.equal('/child', expectedURL); - }); - } - - ['@test RouterService#urlFor returns URL for simple route with dynamic segments'](assert) { - assert.expect(1); - - setupController(this.application, 'dynamic'); - - let dynamicModel = { id: 1, contents: 'much dynamicism' }; - - return this.visit('/').then(() => { - let expectedURL = this.routerService.urlFor('dynamic', dynamicModel); - - assert.equal('/dynamic/1', expectedURL); - }); - } - - ['@test RouterService#urlFor returns URL for simple route with basic query params'](assert) { - assert.expect(1); - - let queryParams = this.buildQueryParams({ foo: 'bar' }); - - return this.visit('/').then(() => { - let expectedURL = this.routerService.urlFor('parent.child', queryParams); - - assert.equal('/child?foo=bar', expectedURL); - }); - } - - ['@test RouterService#urlFor returns URL for simple route with basic query params and default value'](assert) { - assert.expect(1); - - this.add('controller:parent.child', Controller.extend({ - queryParams: ['sort'], - sort: 'ASC' - })); - - let queryParams = this.buildQueryParams({ sort: 'ASC' }); - - return this.visit('/').then(() => { - let expectedURL = this.routerService.urlFor('parent.child', queryParams); - - assert.equal('/child?sort=ASC', expectedURL); - }); - } - - ['@test RouterService#urlFor returns URL for simple route with basic query params and default value with stickyness'](assert) { - assert.expect(2); - - this.add('controller:parent.child', Controller.extend({ - queryParams: ['sort', 'foo'], - sort: 'ASC' - })); - - return this.visit('/child/?sort=DESC').then(() => { - let controller = this.applicationInstance.lookup('controller:parent.child'); - assert.equal(get(controller, 'sort'), 'DESC', 'sticky is set'); - - let queryParams = this.buildQueryParams({ foo: 'derp' }); - let actual = this.routerService.urlFor('parent.child', queryParams); - - assert.equal(actual, '/child?foo=derp', 'does not use "stickiness"'); - }); - } - - ['@test RouterService#urlFor returns URL for simple route with array as query params'](assert) { - assert.expect(1); - - let queryParams = this.buildQueryParams({ selectedItems: ['a', 'b', 'c'] }); - - return this.visit('/').then(() => { - let expectedURL = this.routerService.urlFor('parent.child', queryParams); - - assert.equal('/child?selectedItems[]=a&selectedItems[]=b&selectedItems[]=c', expectedURL); - }); - } - - ['@test RouterService#urlFor returns URL for simple route with null query params'](assert) { - assert.expect(1); - - let queryParams = this.buildQueryParams({ foo: null }); + assert.equal('/child', expectedURL); + }); + } - return this.visit('/').then(() => { - let expectedURL = this.routerService.urlFor('parent.child', queryParams); + ['@test RouterService#urlFor returns URL for simple route with dynamic segments']( + assert + ) { + assert.expect(1); - assert.equal('/child', expectedURL); - }); - } + setupController(this.application, 'dynamic'); - ['@test RouterService#urlFor returns URL for simple route with undefined query params'](assert) { - assert.expect(1); + let dynamicModel = { id: 1, contents: 'much dynamicism' }; - let queryParams = this.buildQueryParams({ foo: undefined }); + return this.visit('/').then(() => { + let expectedURL = this.routerService.urlFor('dynamic', dynamicModel); - return this.visit('/').then(() => { - let expectedURL = this.routerService.urlFor('parent.child', queryParams); - - assert.equal('/child', expectedURL); - }); - } + assert.equal('/dynamic/1', expectedURL); + }); + } - ['@test RouterService#urlFor returns URL for simple route with dynamic segments and basic query params'](assert) { - assert.expect(1); + ['@test RouterService#urlFor returns URL for simple route with basic query params']( + assert + ) { + assert.expect(1); - let queryParams = this.buildQueryParams({ foo: 'bar' }); + let queryParams = this.buildQueryParams({ foo: 'bar' }); - return this.visit('/').then(() => { - let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); + return this.visit('/').then(() => { + let expectedURL = this.routerService.urlFor( + 'parent.child', + queryParams + ); - assert.equal('/dynamic/1?foo=bar', expectedURL); - }); - } + assert.equal('/child?foo=bar', expectedURL); + }); + } + + ['@test RouterService#urlFor returns URL for simple route with basic query params and default value']( + assert + ) { + assert.expect(1); + + this.add( + 'controller:parent.child', + Controller.extend({ + queryParams: ['sort'], + sort: 'ASC' + }) + ); + + let queryParams = this.buildQueryParams({ sort: 'ASC' }); + + return this.visit('/').then(() => { + let expectedURL = this.routerService.urlFor( + 'parent.child', + queryParams + ); + + assert.equal('/child?sort=ASC', expectedURL); + }); + } + + ['@test RouterService#urlFor returns URL for simple route with basic query params and default value with stickyness']( + assert + ) { + assert.expect(2); + + this.add( + 'controller:parent.child', + Controller.extend({ + queryParams: ['sort', 'foo'], + sort: 'ASC' + }) + ); + + return this.visit('/child/?sort=DESC').then(() => { + let controller = this.applicationInstance.lookup( + 'controller:parent.child' + ); + assert.equal(get(controller, 'sort'), 'DESC', 'sticky is set'); + + let queryParams = this.buildQueryParams({ foo: 'derp' }); + let actual = this.routerService.urlFor('parent.child', queryParams); + + assert.equal(actual, '/child?foo=derp', 'does not use "stickiness"'); + }); + } - ['@test RouterService#urlFor returns URL for simple route with dynamic segments and array as query params'](assert) { - assert.expect(1); + ['@test RouterService#urlFor returns URL for simple route with array as query params']( + assert + ) { + assert.expect(1); - let queryParams = this.buildQueryParams({ selectedItems: ['a', 'b', 'c'] }); + let queryParams = this.buildQueryParams({ + selectedItems: ['a', 'b', 'c'] + }); - return this.visit('/').then(() => { - let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); + return this.visit('/').then(() => { + let expectedURL = this.routerService.urlFor( + 'parent.child', + queryParams + ); - assert.equal('/dynamic/1?selectedItems[]=a&selectedItems[]=b&selectedItems[]=c', expectedURL); - }); - } + assert.equal( + '/child?selectedItems[]=a&selectedItems[]=b&selectedItems[]=c', + expectedURL + ); + }); + } - ['@test RouterService#urlFor returns URL for simple route with dynamic segments and null query params'](assert) { - assert.expect(1); + ['@test RouterService#urlFor returns URL for simple route with null query params']( + assert + ) { + assert.expect(1); - let queryParams = this.buildQueryParams({ foo: null }); + let queryParams = this.buildQueryParams({ foo: null }); - return this.visit('/').then(() => { - let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); + return this.visit('/').then(() => { + let expectedURL = this.routerService.urlFor( + 'parent.child', + queryParams + ); - assert.equal('/dynamic/1', expectedURL); - }); - } + assert.equal('/child', expectedURL); + }); + } - ['@test RouterService#urlFor returns URL for simple route with dynamic segments and undefined query params'](assert) { - assert.expect(1); + ['@test RouterService#urlFor returns URL for simple route with undefined query params']( + assert + ) { + assert.expect(1); - let queryParams = this.buildQueryParams({ foo: undefined }); + let queryParams = this.buildQueryParams({ foo: undefined }); - return this.visit('/').then(() => { - let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); + return this.visit('/').then(() => { + let expectedURL = this.routerService.urlFor( + 'parent.child', + queryParams + ); - assert.equal('/dynamic/1', expectedURL); - }); - } + assert.equal('/child', expectedURL); + }); + } - ['@test RouterService#urlFor correctly transitions to route via generated path'](assert) { - assert.expect(1); + ['@test RouterService#urlFor returns URL for simple route with dynamic segments and basic query params']( + assert + ) { + assert.expect(1); - let expectedURL; + let queryParams = this.buildQueryParams({ foo: 'bar' }); - return this.visit('/') - .then(() => { - expectedURL = this.routerService.urlFor('parent.child'); + return this.visit('/').then(() => { + let expectedURL = this.routerService.urlFor( + 'dynamic', + { id: 1 }, + queryParams + ); - return this.routerService.transitionTo(expectedURL); - }) - .then(() => { - assert.equal(expectedURL, this.routerService.get('currentURL')); + assert.equal('/dynamic/1?foo=bar', expectedURL); }); - } - - ['@test RouterService#urlFor correctly transitions to route via generated path with dynamic segments'](assert) { - assert.expect(1); - - let expectedURL; - let dynamicModel = { id: 1 }; + } - this.add('route:dynamic', Route.extend({ - model() { - return dynamicModel; - } - })); + ['@test RouterService#urlFor returns URL for simple route with dynamic segments and array as query params']( + assert + ) { + assert.expect(1); - return this.visit('/') - .then(() => { - expectedURL = this.routerService.urlFor('dynamic', dynamicModel); - - return this.routerService.transitionTo(expectedURL); - }) - .then(() => { - assert.equal(expectedURL, this.routerService.get('currentURL')); + let queryParams = this.buildQueryParams({ + selectedItems: ['a', 'b', 'c'] }); - } - ['@test RouterService#urlFor correctly transitions to route via generated path with query params'](assert) { - assert.expect(1); + return this.visit('/').then(() => { + let expectedURL = this.routerService.urlFor( + 'dynamic', + { id: 1 }, + queryParams + ); + + assert.equal( + '/dynamic/1?selectedItems[]=a&selectedItems[]=b&selectedItems[]=c', + expectedURL + ); + }); + } - let expectedURL; - let actualURL; - let queryParams = this.buildQueryParams({ foo: 'bar' }); + ['@test RouterService#urlFor returns URL for simple route with dynamic segments and null query params']( + assert + ) { + assert.expect(1); - return this.visit('/') - .then(() => { - expectedURL = this.routerService.urlFor('parent.child', queryParams); + let queryParams = this.buildQueryParams({ foo: null }); - return this.routerService.transitionTo(expectedURL); - }) - .then(() => { - actualURL = `${this.routerService.get('currentURL')}?foo=bar`; + return this.visit('/').then(() => { + let expectedURL = this.routerService.urlFor( + 'dynamic', + { id: 1 }, + queryParams + ); - assert.equal(expectedURL, actualURL); + assert.equal('/dynamic/1', expectedURL); }); - } + } - ['@test RouterService#urlFor correctly transitions to route via generated path with dynamic segments and query params'](assert) { - assert.expect(1); + ['@test RouterService#urlFor returns URL for simple route with dynamic segments and undefined query params']( + assert + ) { + assert.expect(1); - let expectedURL; - let actualURL; - let queryParams = this.buildQueryParams({ foo: 'bar' }); - let dynamicModel = { id: 1 }; + let queryParams = this.buildQueryParams({ foo: undefined }); - this.add('route:dynamic', Route.extend({ - model() { - return dynamicModel; - } - })); + return this.visit('/').then(() => { + let expectedURL = this.routerService.urlFor( + 'dynamic', + { id: 1 }, + queryParams + ); - return this.visit('/') - .then(() => { - expectedURL = this.routerService.urlFor('dynamic', dynamicModel, queryParams); - - return this.routerService.transitionTo(expectedURL); - }) - .then(() => { - actualURL = `${this.routerService.get('currentURL')}?foo=bar`; - - assert.equal(expectedURL, actualURL); + assert.equal('/dynamic/1', expectedURL); }); + } + + ['@test RouterService#urlFor correctly transitions to route via generated path']( + assert + ) { + assert.expect(1); + + let expectedURL; + + return this.visit('/') + .then(() => { + expectedURL = this.routerService.urlFor('parent.child'); + + return this.routerService.transitionTo(expectedURL); + }) + .then(() => { + assert.equal(expectedURL, this.routerService.get('currentURL')); + }); + } + + ['@test RouterService#urlFor correctly transitions to route via generated path with dynamic segments']( + assert + ) { + assert.expect(1); + + let expectedURL; + let dynamicModel = { id: 1 }; + + this.add( + 'route:dynamic', + Route.extend({ + model() { + return dynamicModel; + } + }) + ); + + return this.visit('/') + .then(() => { + expectedURL = this.routerService.urlFor('dynamic', dynamicModel); + + return this.routerService.transitionTo(expectedURL); + }) + .then(() => { + assert.equal(expectedURL, this.routerService.get('currentURL')); + }); + } + + ['@test RouterService#urlFor correctly transitions to route via generated path with query params']( + assert + ) { + assert.expect(1); + + let expectedURL; + let actualURL; + let queryParams = this.buildQueryParams({ foo: 'bar' }); + + return this.visit('/') + .then(() => { + expectedURL = this.routerService.urlFor( + 'parent.child', + queryParams + ); + + return this.routerService.transitionTo(expectedURL); + }) + .then(() => { + actualURL = `${this.routerService.get('currentURL')}?foo=bar`; + + assert.equal(expectedURL, actualURL); + }); + } + + ['@test RouterService#urlFor correctly transitions to route via generated path with dynamic segments and query params']( + assert + ) { + assert.expect(1); + + let expectedURL; + let actualURL; + let queryParams = this.buildQueryParams({ foo: 'bar' }); + let dynamicModel = { id: 1 }; + + this.add( + 'route:dynamic', + Route.extend({ + model() { + return dynamicModel; + } + }) + ); + + return this.visit('/') + .then(() => { + expectedURL = this.routerService.urlFor( + 'dynamic', + dynamicModel, + queryParams + ); + + return this.routerService.transitionTo(expectedURL); + }) + .then(() => { + actualURL = `${this.routerService.get('currentURL')}?foo=bar`; + + assert.equal(expectedURL, actualURL); + }); + } } - }); + ); } diff --git a/packages/ember/tests/routing/substates_test.js b/packages/ember/tests/routing/substates_test.js index 788f0edb86e..dc6912f416e 100644 --- a/packages/ember/tests/routing/substates_test.js +++ b/packages/ember/tests/routing/substates_test.js @@ -5,1005 +5,1208 @@ import { moduleFor, ApplicationTestCase } from 'internal-test-helpers'; let counter; function step(assert, expectedValue, description) { - assert.equal(counter, expectedValue, 'Step ' + expectedValue + ': ' + description); + assert.equal( + counter, + expectedValue, + 'Step ' + expectedValue + ': ' + description + ); counter++; } -moduleFor('Loading/Error Substates', class extends ApplicationTestCase { - constructor() { - super(); - counter = 1; +moduleFor( + 'Loading/Error Substates', + class extends ApplicationTestCase { + constructor() { + super(); + counter = 1; - this.addTemplate('application', `
    {{outlet}}
    `); - this.addTemplate('index', 'INDEX'); - } + this.addTemplate('application', `
    {{outlet}}
    `); + this.addTemplate('index', 'INDEX'); + } - getController(name) { - return this.applicationInstance.lookup(`controller:${name}`); - } + getController(name) { + return this.applicationInstance.lookup(`controller:${name}`); + } - get currentPath() { - return this.getController('application').get('currentPath'); - } + get currentPath() { + return this.getController('application').get('currentPath'); + } - ['@test Slow promise from a child route of application enters nested loading state'](assert) { - let turtleDeferred = RSVP.defer(); + ['@test Slow promise from a child route of application enters nested loading state']( + assert + ) { + let turtleDeferred = RSVP.defer(); - this.router.map(function() { - this.route('turtle'); - }); + this.router.map(function() { + this.route('turtle'); + }); - this.add('route:application', Route.extend({ - setupController() { - step(assert, 2, 'ApplicationRoute#setupController'); - } - })); + this.add( + 'route:application', + Route.extend({ + setupController() { + step(assert, 2, 'ApplicationRoute#setupController'); + } + }) + ); - this.add('route:turtle', Route.extend({ - model() { - step(assert, 1, 'TurtleRoute#model'); - return turtleDeferred.promise; - } - })); - this.addTemplate('turtle', 'TURTLE'); - this.addTemplate('loading', 'LOADING'); + this.add( + 'route:turtle', + Route.extend({ + model() { + step(assert, 1, 'TurtleRoute#model'); + return turtleDeferred.promise; + } + }) + ); + this.addTemplate('turtle', 'TURTLE'); + this.addTemplate('loading', 'LOADING'); - let promise = this.visit('/turtle').then(() => { - text = this.$('#app').text(); + let promise = this.visit('/turtle').then(() => { + text = this.$('#app').text(); + assert.equal( + text, + 'TURTLE', + `turtle template has loaded and replaced the loading template` + ); + }); + + let text = this.$('#app').text(); assert.equal( text, - 'TURTLE', - `turtle template has loaded and replaced the loading template` + 'LOADING', + `The Loading template is nested in application template's outlet` ); - }); - let text = this.$('#app').text(); - assert.equal( - text, - 'LOADING', - `The Loading template is nested in application template's outlet` - ); + turtleDeferred.resolve(); + return promise; + } - turtleDeferred.resolve(); - return promise; - } + [`@test Slow promises returned from ApplicationRoute#model don't enter LoadingRoute`]( + assert + ) { + let appDeferred = RSVP.defer(); + + this.add( + 'route:application', + Route.extend({ + model() { + return appDeferred.promise; + } + }) + ); + this.add( + 'route:loading', + Route.extend({ + setupController() { + assert.ok(false, `shouldn't get here`); + } + }) + ); - [`@test Slow promises returned from ApplicationRoute#model don't enter LoadingRoute`](assert) { - let appDeferred = RSVP.defer(); + let promise = this.visit('/').then(() => { + let text = this.$('#app').text(); - this.add('route:application', Route.extend({ - model() { - return appDeferred.promise; - } - })); - this.add('route:loading', Route.extend({ - setupController() { - assert.ok(false, `shouldn't get here`); - } - })); + assert.equal(text, 'INDEX', `index template has been rendered`); + }); - let promise = this.visit('/').then(() => { - let text = this.$('#app').text(); + if (this.element) { + assert.equal(this.element.textContent, ''); + } - assert.equal(text, 'INDEX', `index template has been rendered`); - }); + appDeferred.resolve(); - if (this.element) { - assert.equal(this.element.textContent, ''); + return promise; } - appDeferred.resolve(); + [`@test Don't enter loading route unless either route or template defined`]( + assert + ) { + let deferred = RSVP.defer(); - return promise; - } + this.router.map(function() { + this.route('dummy'); + }); + this.add( + 'route:dummy', + Route.extend({ + model() { + return deferred.promise; + } + }) + ); + this.addTemplate('dummy', 'DUMMY'); - [`@test Don't enter loading route unless either route or template defined`](assert) { - let deferred = RSVP.defer(); + return this.visit('/').then(() => { + let promise = this.visit('/dummy').then(() => { + let text = this.$('#app').text(); - this.router.map(function() { - this.route('dummy'); - }); - this.add('route:dummy', Route.extend({ - model() { - return deferred.promise; - } - })); - this.addTemplate('dummy', 'DUMMY'); + assert.equal(text, 'DUMMY', `dummy template has been rendered`); + }); - return this.visit('/').then(() => { - let promise = this.visit('/dummy').then(() => { - let text = this.$('#app').text(); + assert.ok( + this.currentPath !== 'loading', + ` + loading state not entered + ` + ); + deferred.resolve(); - assert.equal(text, 'DUMMY', `dummy template has been rendered`); + return promise; }); + } - assert.ok(this.currentPath !== 'loading', ` - loading state not entered - `); - deferred.resolve(); + ['@test Enter loading route only if loadingRoute is defined'](assert) { + let deferred = RSVP.defer(); - return promise; - }); - } + this.router.map(function() { + this.route('dummy'); + }); - ['@test Enter loading route only if loadingRoute is defined'](assert) { - let deferred = RSVP.defer(); + this.add( + 'route:dummy', + Route.extend({ + model() { + step(assert, 1, 'DummyRoute#model'); + return deferred.promise; + } + }) + ); + this.add( + 'route:loading', + Route.extend({ + setupController() { + step(assert, 2, 'LoadingRoute#setupController'); + } + }) + ); + this.addTemplate('dummy', 'DUMMY'); - this.router.map(function() { - this.route('dummy'); - }); + return this.visit('/').then(() => { + let promise = this.visit('/dummy').then(() => { + let text = this.$('#app').text(); - this.add('route:dummy', Route.extend({ - model() { - step(assert, 1, 'DummyRoute#model'); - return deferred.promise; - } - })); - this.add('route:loading', Route.extend({ - setupController() { - step(assert, 2, 'LoadingRoute#setupController'); - } - })); - this.addTemplate('dummy', 'DUMMY'); + assert.equal(text, 'DUMMY', `dummy template has been rendered`); + }); - return this.visit('/').then(() => { - let promise = this.visit('/dummy').then(() => { - let text = this.$('#app').text(); + assert.equal(this.currentPath, 'loading', `loading state entered`); + deferred.resolve(); - assert.equal(text, 'DUMMY', `dummy template has been rendered`); + return promise; }); + } - assert.equal( - this.currentPath, - 'loading', - `loading state entered` + ['@test Slow promises returned from ApplicationRoute#model enter ApplicationLoadingRoute if present']( + assert + ) { + let appDeferred = RSVP.defer(); + + this.add( + 'route:application', + Route.extend({ + model() { + return appDeferred.promise; + } + }) + ); + let loadingRouteEntered = false; + this.add( + 'route:application_loading', + Route.extend({ + setupController() { + loadingRouteEntered = true; + } + }) ); - deferred.resolve(); + + let promise = this.visit('/').then(() => { + assert.equal(this.$('#app').text(), 'INDEX', 'index route loaded'); + }); + assert.ok(loadingRouteEntered, 'ApplicationLoadingRoute was entered'); + appDeferred.resolve(); return promise; - }); - } + } - ['@test Slow promises returned from ApplicationRoute#model enter ApplicationLoadingRoute if present'](assert) { - let appDeferred = RSVP.defer(); + ['@test Slow promises returned from ApplicationRoute#model enter application_loading if template present']( + assert + ) { + let appDeferred = RSVP.defer(); - this.add('route:application', Route.extend({ - model() { - return appDeferred.promise; - } - })); - let loadingRouteEntered = false; - this.add('route:application_loading', Route.extend({ - setupController() { - loadingRouteEntered = true; - } - })); - - let promise = this.visit('/').then(() => { - assert.equal(this.$('#app').text(), 'INDEX', 'index route loaded'); - }); - assert.ok(loadingRouteEntered, 'ApplicationLoadingRoute was entered'); - appDeferred.resolve(); + this.addTemplate( + 'application_loading', + ` +
    TOPLEVEL LOADING
    + ` + ); + this.add( + 'route:application', + Route.extend({ + model() { + return appDeferred.promise; + } + }) + ); - return promise; - } + let promise = this.visit('/').then(() => { + let length = this.$('#toplevel-loading').length; + text = this.$('#app').text(); - ['@test Slow promises returned from ApplicationRoute#model enter application_loading if template present'](assert) { - let appDeferred = RSVP.defer(); + assert.equal( + length, + 0, + `top-level loading view has been entirely removed from the DOM` + ); + assert.equal(text, 'INDEX', 'index has fully rendered'); + }); + let text = this.$('#toplevel-loading').text(); - this.addTemplate('application_loading', ` -
    TOPLEVEL LOADING
    - `); - this.add('route:application', Route.extend({ - model() { - return appDeferred.promise; - } - })); + assert.equal(text, 'TOPLEVEL LOADING', 'still loading the top level'); + appDeferred.resolve(); - let promise = this.visit('/').then(() => { - let length = this.$('#toplevel-loading').length; - text = this.$('#app').text(); + return promise; + } - assert.equal( - length, - 0, - `top-level loading view has been entirely removed from the DOM` - ); - assert.equal(text, 'INDEX', 'index has fully rendered'); - }); - let text = this.$('#toplevel-loading').text(); + ['@test Prioritized substate entry works with preserved-namespace nested routes']( + assert + ) { + let deferred = RSVP.defer(); - assert.equal(text, 'TOPLEVEL LOADING', 'still loading the top level'); - appDeferred.resolve(); + this.addTemplate('foo.bar_loading', 'FOOBAR LOADING'); + this.addTemplate('foo.bar.index', 'YAY'); - return promise; - } + this.router.map(function() { + this.route('foo', function() { + this.route('bar', { path: '/bar' }, function() {}); + }); + }); - ['@test Prioritized substate entry works with preserved-namespace nested routes'](assert) { - let deferred = RSVP.defer(); + this.add( + 'route:foo.bar', + Route.extend({ + model() { + return deferred.promise; + } + }) + ); - this.addTemplate('foo.bar_loading', 'FOOBAR LOADING'); - this.addTemplate('foo.bar.index', 'YAY'); + return this.visit('/').then(() => { + let promise = this.visit('/foo/bar').then(() => { + text = this.$('#app').text(); - this.router.map(function() { - this.route('foo', function() { - this.route('bar', { path: '/bar' }, function() { + assert.equal(text, 'YAY', 'foo.bar.index fully loaded'); }); + let text = this.$('#app').text(); + + assert.equal( + text, + 'FOOBAR LOADING', + `foo.bar_loading was entered (as opposed to something like foo/foo/bar_loading)` + ); + deferred.resolve(); + + return promise; }); - }); + } - this.add('route:foo.bar', Route.extend({ - model() { - return deferred.promise; - } - })); + ['@test Prioritized substate entry works with reset-namespace nested routes']( + assert + ) { + let deferred = RSVP.defer(); - return this.visit('/').then(() => { - let promise = this.visit('/foo/bar').then(() => { - text = this.$('#app').text(); + this.addTemplate('bar_loading', 'BAR LOADING'); + this.addTemplate('bar.index', 'YAY'); - assert.equal(text, 'YAY', 'foo.bar.index fully loaded'); + this.router.map(function() { + this.route('foo', function() { + this.route( + 'bar', + { path: '/bar', resetNamespace: true }, + function() {} + ); + }); }); - let text = this.$('#app').text(); - assert.equal( - text, - 'FOOBAR LOADING', - `foo.bar_loading was entered (as opposed to something like foo/foo/bar_loading)` + this.add( + 'route:bar', + Route.extend({ + model() { + return deferred.promise; + } + }) ); - deferred.resolve(); - return promise; - }); - } + return this.visit('/').then(() => { + let promise = this.visit('/foo/bar').then(() => { + text = this.$('#app').text(); + + assert.equal(text, 'YAY', 'bar.index fully loaded'); + }); - ['@test Prioritized substate entry works with reset-namespace nested routes'](assert) { - let deferred = RSVP.defer(); + let text = this.$('#app').text(); + + assert.equal( + text, + 'BAR LOADING', + `foo.bar_loading was entered (as opposed to something likefoo/foo/bar_loading)` + ); + deferred.resolve(); + + return promise; + }); + } - this.addTemplate('bar_loading', 'BAR LOADING'); - this.addTemplate('bar.index', 'YAY'); + ['@test Prioritized loading substate entry works with preserved-namespace nested routes']( + assert + ) { + let deferred = RSVP.defer(); - this.router.map(function() { - this.route('foo', function() { - this.route('bar', { path: '/bar', resetNamespace: true }, function() { + this.addTemplate('foo.bar_loading', 'FOOBAR LOADING'); + this.addTemplate('foo.bar', 'YAY'); + + this.router.map(function() { + this.route('foo', function() { + this.route('bar'); }); }); - }); - this.add('route:bar', Route.extend({ - model() { - return deferred.promise; - } - })); + this.add( + 'route:foo.bar', + Route.extend({ + model() { + return deferred.promise; + } + }) + ); - return this.visit('/').then(() => { let promise = this.visit('/foo/bar').then(() => { text = this.$('#app').text(); - assert.equal(text, 'YAY', 'bar.index fully loaded'); + assert.equal(text, 'YAY', 'foo.bar has rendered'); }); - let text = this.$('#app').text(); assert.equal( text, - 'BAR LOADING', - `foo.bar_loading was entered (as opposed to something likefoo/foo/bar_loading)` + 'FOOBAR LOADING', + `foo.bar_loading was entered (as opposed to something like foo/foo/bar_loading)` ); deferred.resolve(); return promise; - }); - } - - ['@test Prioritized loading substate entry works with preserved-namespace nested routes'](assert) { - let deferred = RSVP.defer(); + } - this.addTemplate('foo.bar_loading', 'FOOBAR LOADING'); - this.addTemplate('foo.bar', 'YAY'); + ['@test Prioritized error substate entry works with preserved-namespaec nested routes']( + assert + ) { + this.addTemplate('foo.bar_error', 'FOOBAR ERROR: {{model.msg}}'); + this.addTemplate('foo.bar', 'YAY'); - this.router.map(function() { - this.route('foo', function() { - this.route('bar'); + this.router.map(function() { + this.route('foo', function() { + this.route('bar'); + }); }); - }); - - this.add('route:foo.bar', Route.extend({ - model() { - return deferred.promise; - } - })); - - let promise = this.visit('/foo/bar').then(() => { - text = this.$('#app').text(); - assert.equal(text, 'YAY', 'foo.bar has rendered'); - }); - let text = this.$('#app').text(); - - assert.equal( - text, - 'FOOBAR LOADING', - `foo.bar_loading was entered (as opposed to something like foo/foo/bar_loading)` - ); - deferred.resolve(); - - return promise; - } - - ['@test Prioritized error substate entry works with preserved-namespaec nested routes'](assert) { - this.addTemplate('foo.bar_error', 'FOOBAR ERROR: {{model.msg}}'); - this.addTemplate('foo.bar', 'YAY'); - - this.router.map(function() { - this.route('foo', function() { - this.route('bar'); - }); - }); + this.add( + 'route:foo.bar', + Route.extend({ + model() { + return RSVP.reject({ + msg: 'did it broke?' + }); + } + }) + ); - this.add('route:foo.bar', Route.extend({ - model() { - return RSVP.reject({ - msg: 'did it broke?' + return this.visit('/').then(() => { + return this.visit('/foo/bar').then(() => { + let text = this.$('#app').text(); + assert.equal( + text, + 'FOOBAR ERROR: did it broke?', + `foo.bar_error was entered (as opposed to something like foo/foo/bar_error)` + ); }); - } - })); - - return this.visit('/').then(() => { - return this.visit('/foo/bar').then(() => { - - let text = this.$('#app').text(); - assert.equal( - text, - 'FOOBAR ERROR: did it broke?', - `foo.bar_error was entered (as opposed to something like foo/foo/bar_error)` - ); }); - }); - } - ['@test Prioritized loading substate entry works with auto-generated index routes'](assert) { - let deferred = RSVP.defer(); - this.addTemplate('foo.index_loading', 'FOO LOADING'); - this.addTemplate('foo.index', 'YAY'); - this.addTemplate('foo', '{{outlet}}'); - - this.router.map(function() { - this.route('foo', function() { - this.route('bar'); + } + ['@test Prioritized loading substate entry works with auto-generated index routes']( + assert + ) { + let deferred = RSVP.defer(); + this.addTemplate('foo.index_loading', 'FOO LOADING'); + this.addTemplate('foo.index', 'YAY'); + this.addTemplate('foo', '{{outlet}}'); + + this.router.map(function() { + this.route('foo', function() { + this.route('bar'); + }); }); - }); - this.add('route:foo.index', Route.extend({ - model() { - return deferred.promise; - } - })); - this.add('route:foo', Route.extend({ - model() { - return true; - } - })); - - let promise = this.visit('/foo').then(() => { - text = this.$('#app').text(); + this.add( + 'route:foo.index', + Route.extend({ + model() { + return deferred.promise; + } + }) + ); + this.add( + 'route:foo', + Route.extend({ + model() { + return true; + } + }) + ); - assert.equal(text, 'YAY', 'foo.index was rendered'); - }); - let text = this.$('#app').text(); - assert.equal(text, 'FOO LOADING', 'foo.index_loading was entered'); + let promise = this.visit('/foo').then(() => { + text = this.$('#app').text(); - deferred.resolve(); + assert.equal(text, 'YAY', 'foo.index was rendered'); + }); + let text = this.$('#app').text(); + assert.equal(text, 'FOO LOADING', 'foo.index_loading was entered'); - return promise; - } + deferred.resolve(); - ['@test Prioritized error substate entry works with auto-generated index routes'](assert) { - this.addTemplate('foo.index_error', 'FOO ERROR: {{model.msg}}'); - this.addTemplate('foo.index', 'YAY'); - this.addTemplate('foo', '{{outlet}}'); + return promise; + } - this.router.map(function() { - this.route('foo', function() { - this.route('bar'); - }); - }); + ['@test Prioritized error substate entry works with auto-generated index routes']( + assert + ) { + this.addTemplate('foo.index_error', 'FOO ERROR: {{model.msg}}'); + this.addTemplate('foo.index', 'YAY'); + this.addTemplate('foo', '{{outlet}}'); - this.add('route:foo.index', Route.extend({ - model() { - return RSVP.reject({ - msg: 'did it broke?' + this.router.map(function() { + this.route('foo', function() { + this.route('bar'); }); - } - })); - this.add('route:foo', Route.extend({ - model() { - return true; - } - })); + }); - return this.visit('/').then(() => { + this.add( + 'route:foo.index', + Route.extend({ + model() { + return RSVP.reject({ + msg: 'did it broke?' + }); + } + }) + ); + this.add( + 'route:foo', + Route.extend({ + model() { + return true; + } + }) + ); - return this.visit('/foo').then(() => { - let text = this.$('#app').text(); + return this.visit('/').then(() => { + return this.visit('/foo').then(() => { + let text = this.$('#app').text(); - assert.equal( - text, - 'FOO ERROR: did it broke?', - 'foo.index_error was entered' - ); + assert.equal( + text, + 'FOO ERROR: did it broke?', + 'foo.index_error was entered' + ); + }); }); - }); - } + } - ['@test Rejected promises returned from ApplicationRoute transition into top-level application_error'](assert) { - let reject = true; - - this.addTemplate('index', '
    INDEX
    '); - this.add('route:application', Route.extend({ - init() { - this._super(...arguments); - }, - model() { - if (reject) { - return RSVP.reject({ msg: 'BAD NEWS BEARS' }); - } else { - return {}; - } - } - })); + ['@test Rejected promises returned from ApplicationRoute transition into top-level application_error']( + assert + ) { + let reject = true; + + this.addTemplate('index', '
    INDEX
    '); + this.add( + 'route:application', + Route.extend({ + init() { + this._super(...arguments); + }, + model() { + if (reject) { + return RSVP.reject({ msg: 'BAD NEWS BEARS' }); + } else { + return {}; + } + } + }) + ); - this.addTemplate('application_error', ` + this.addTemplate( + 'application_error', + `

    TOPLEVEL ERROR: {{model.msg}}

    - `); + ` + ); - return this.visit('/').then(() => { - let text = this.$('#toplevel-error').text(); - assert.equal( - text, - 'TOPLEVEL ERROR: BAD NEWS BEARS', - 'toplevel error rendered' - ); - reject = false; - }).then(() => { - return this.visit('/'); - }).then(() => { - let text = this.$('#index').text(); - assert.equal(text, 'INDEX', 'the index route resolved'); - }); + return this.visit('/') + .then(() => { + let text = this.$('#toplevel-error').text(); + assert.equal( + text, + 'TOPLEVEL ERROR: BAD NEWS BEARS', + 'toplevel error rendered' + ); + reject = false; + }) + .then(() => { + return this.visit('/'); + }) + .then(() => { + let text = this.$('#index').text(); + assert.equal(text, 'INDEX', 'the index route resolved'); + }); + } } -}); - -moduleFor('Loading/Error Substates - nested routes', class extends ApplicationTestCase { - constructor() { - super(); - - counter = 1; - - this.addTemplate('application', `
    {{outlet}}
    `); - this.addTemplate('index', 'INDEX'); - this.addTemplate('grandma', 'GRANDMA {{outlet}}'); - this.addTemplate('mom', 'MOM'); - - this.router.map(function() { - this.route('grandma', function() { - this.route('mom', { resetNamespace: true }, function() { - this.route('sally'); - this.route('this-route-throws'); +); + +moduleFor( + 'Loading/Error Substates - nested routes', + class extends ApplicationTestCase { + constructor() { + super(); + + counter = 1; + + this.addTemplate('application', `
    {{outlet}}
    `); + this.addTemplate('index', 'INDEX'); + this.addTemplate('grandma', 'GRANDMA {{outlet}}'); + this.addTemplate('mom', 'MOM'); + + this.router.map(function() { + this.route('grandma', function() { + this.route('mom', { resetNamespace: true }, function() { + this.route('sally'); + this.route('this-route-throws'); + }); + this.route('puppies'); }); - this.route('puppies'); + this.route('memere', { path: '/memere/:seg' }, function() {}); }); - this.route('memere', { path: '/memere/:seg' }, function() {}); - }); - this.visit('/'); - } + this.visit('/'); + } - getController(name) { - return this.applicationInstance.lookup(`controller:${name}`); - } + getController(name) { + return this.applicationInstance.lookup(`controller:${name}`); + } - get currentPath() { - return this.getController('application').get('currentPath'); - } + get currentPath() { + return this.getController('application').get('currentPath'); + } - ['@test ApplicationRoute#currentPath reflects loading state path'](assert) { - let momDeferred = RSVP.defer(); + ['@test ApplicationRoute#currentPath reflects loading state path'](assert) { + let momDeferred = RSVP.defer(); - this.addTemplate('grandma.loading', 'GRANDMALOADING'); + this.addTemplate('grandma.loading', 'GRANDMALOADING'); - this.add('route:mom', Route.extend({ - model() { - return momDeferred.promise; - } - })); + this.add( + 'route:mom', + Route.extend({ + model() { + return momDeferred.promise; + } + }) + ); - let promise = this.visit('/grandma/mom').then(() => { - text = this.$('#app').text(); + let promise = this.visit('/grandma/mom').then(() => { + text = this.$('#app').text(); + + assert.equal( + text, + 'GRANDMA MOM', + `Grandma.mom loaded text is displayed` + ); + assert.equal( + this.currentPath, + 'grandma.mom.index', + `currentPath reflects final state` + ); + }); + let text = this.$('#app').text(); assert.equal( text, - 'GRANDMA MOM', - `Grandma.mom loaded text is displayed` + 'GRANDMA GRANDMALOADING', + `Grandma.mom loading text displayed` ); + assert.equal( this.currentPath, - 'grandma.mom.index', - `currentPath reflects final state` + 'grandma.loading', + `currentPath reflects loading state` ); - }); - let text = this.$('#app').text(); - - assert.equal( - text, - 'GRANDMA GRANDMALOADING', - `Grandma.mom loading text displayed` - ); - - assert.equal( - this.currentPath, - 'grandma.loading', - `currentPath reflects loading state` - ); - - momDeferred.resolve(); - - return promise; - } - [`@test Loading actions bubble to root but don't enter substates above pivot `](assert) { - let sallyDeferred = RSVP.defer(); - let puppiesDeferred = RSVP.defer(); + momDeferred.resolve(); - this.add('route:application', Route.extend({ - actions: { - loading() { - assert.ok(true, 'loading action received on ApplicationRoute'); - } - } - })); - - this.add('route:mom.sally', Route.extend({ - model() { - return sallyDeferred.promise; - } - })); - - this.add('route:grandma.puppies', Route.extend({ - model() { - return puppiesDeferred.promise; - } - })); - - let promise = this.visit('/grandma/mom/sally'); - assert.equal(this.currentPath, 'index', 'Initial route fully loaded'); + return promise; + } - sallyDeferred.resolve(); + [`@test Loading actions bubble to root but don't enter substates above pivot `]( + assert + ) { + let sallyDeferred = RSVP.defer(); + let puppiesDeferred = RSVP.defer(); + + this.add( + 'route:application', + Route.extend({ + actions: { + loading() { + assert.ok(true, 'loading action received on ApplicationRoute'); + } + } + }) + ); - promise.then(() => { - assert.equal(this.currentPath, 'grandma.mom.sally', 'transition completed'); + this.add( + 'route:mom.sally', + Route.extend({ + model() { + return sallyDeferred.promise; + } + }) + ); - let visit = this.visit('/grandma/puppies'); - assert.equal( - this.currentPath, - 'grandma.mom.sally', - 'still in initial state because the only loading state is above the pivot route' + this.add( + 'route:grandma.puppies', + Route.extend({ + model() { + return puppiesDeferred.promise; + } + }) ); - return visit; - }).then(() => { - this.runTask(() => puppiesDeferred.resolve()); + let promise = this.visit('/grandma/mom/sally'); + assert.equal(this.currentPath, 'index', 'Initial route fully loaded'); - assert.equal(this.currentPath, 'grandma.puppies', 'Finished transition'); - }); + sallyDeferred.resolve(); - return promise; - } + promise + .then(() => { + assert.equal( + this.currentPath, + 'grandma.mom.sally', + 'transition completed' + ); - ['@test Default error event moves into nested route'](assert) { - this.addTemplate('grandma.error', 'ERROR: {{model.msg}}'); + let visit = this.visit('/grandma/puppies'); + assert.equal( + this.currentPath, + 'grandma.mom.sally', + 'still in initial state because the only loading state is above the pivot route' + ); - this.add('route:mom.sally', Route.extend({ - model() { - step(assert, 1, 'MomSallyRoute#model'); - return RSVP.reject({ - msg: 'did it broke?' + return visit; + }) + .then(() => { + this.runTask(() => puppiesDeferred.resolve()); + + assert.equal( + this.currentPath, + 'grandma.puppies', + 'Finished transition' + ); }); - }, - actions: { - error() { - step(assert, 2, 'MomSallyRoute#actions.error'); - return true; - } - } - })); + return promise; + } - return this.visit('/grandma/mom/sally').then(() => { - step(assert, 3, 'App finished loading'); + ['@test Default error event moves into nested route'](assert) { + this.addTemplate('grandma.error', 'ERROR: {{model.msg}}'); + + this.add( + 'route:mom.sally', + Route.extend({ + model() { + step(assert, 1, 'MomSallyRoute#model'); + return RSVP.reject({ + msg: 'did it broke?' + }); + }, + actions: { + error() { + step(assert, 2, 'MomSallyRoute#actions.error'); + return true; + } + } + }) + ); - let text = this.$('#app').text(); + return this.visit('/grandma/mom/sally').then(() => { + step(assert, 3, 'App finished loading'); - assert.equal(text, 'GRANDMA ERROR: did it broke?', 'error bubbles'); - assert.equal(this.currentPath, 'grandma.error', 'Initial route fully loaded'); - }); - } + let text = this.$('#app').text(); - [`@test Non-bubbled errors that re-throw aren't swallowed`](assert) { - this.add('route:mom.sally', Route.extend({ - model() { - return RSVP.reject({ - msg: 'did it broke?' - }); - }, - actions: { - error(err) { - // returns undefined which is falsey - throw err; - } - } - })); + assert.equal(text, 'GRANDMA ERROR: did it broke?', 'error bubbles'); + assert.equal( + this.currentPath, + 'grandma.error', + 'Initial route fully loaded' + ); + }); + } - assert.throws( - () => { - this.visit('/grandma/mom/sally'); - }, - function(err) { return err.msg === 'did it broke?'; }, - 'it broke' - ); + [`@test Non-bubbled errors that re-throw aren't swallowed`](assert) { + this.add( + 'route:mom.sally', + Route.extend({ + model() { + return RSVP.reject({ + msg: 'did it broke?' + }); + }, + actions: { + error(err) { + // returns undefined which is falsey + throw err; + } + } + }) + ); - return this.runLoopSettled(); - } + assert.throws( + () => { + this.visit('/grandma/mom/sally'); + }, + function(err) { + return err.msg === 'did it broke?'; + }, + 'it broke' + ); - [`@test Handled errors that re-throw aren't swallowed`](assert) { - let handledError; + return this.runLoopSettled(); + } - this.add('route:mom.sally', Route.extend({ - model() { - step(assert, 1, 'MomSallyRoute#model'); - return RSVP.reject({ - msg: 'did it broke?' - }); - }, - actions: { - error(err) { - step(assert, 2, 'MomSallyRoute#actions.error'); - handledError = err; - this.transitionTo('mom.this-route-throws'); - - return false; - } - } - })); + [`@test Handled errors that re-throw aren't swallowed`](assert) { + let handledError; + + this.add( + 'route:mom.sally', + Route.extend({ + model() { + step(assert, 1, 'MomSallyRoute#model'); + return RSVP.reject({ + msg: 'did it broke?' + }); + }, + actions: { + error(err) { + step(assert, 2, 'MomSallyRoute#actions.error'); + handledError = err; + this.transitionTo('mom.this-route-throws'); + + return false; + } + } + }) + ); - this.add('route:mom.this-route-throws', Route.extend({ - model() { - step(assert, 3, 'MomThisRouteThrows#model'); - throw handledError; - } - })); + this.add( + 'route:mom.this-route-throws', + Route.extend({ + model() { + step(assert, 3, 'MomThisRouteThrows#model'); + throw handledError; + } + }) + ); - assert.throws( - () => { - this.visit('/grandma/mom/sally'); - }, - function(err) { return err.msg === 'did it broke?'; }, - `it broke` - ); + assert.throws( + () => { + this.visit('/grandma/mom/sally'); + }, + function(err) { + return err.msg === 'did it broke?'; + }, + `it broke` + ); - return this.runLoopSettled(); - } + return this.runLoopSettled(); + } - ['@test errors that are bubbled are thrown at a higher level if not handled'](assert) { - this.add('route:mom.sally', Route.extend({ - model() { - step(assert, 1, 'MomSallyRoute#model'); - return RSVP.reject({ - msg: 'did it broke?' - }); - }, - actions: { - error() { - step(assert, 2, 'MomSallyRoute#actions.error'); - return true; - } - } - })); + ['@test errors that are bubbled are thrown at a higher level if not handled']( + assert + ) { + this.add( + 'route:mom.sally', + Route.extend({ + model() { + step(assert, 1, 'MomSallyRoute#model'); + return RSVP.reject({ + msg: 'did it broke?' + }); + }, + actions: { + error() { + step(assert, 2, 'MomSallyRoute#actions.error'); + return true; + } + } + }) + ); - assert.throws( - () => { - this.visit('/grandma/mom/sally'); - }, - function(err) { return err.msg == "did it broke?"; }, - 'Correct error was thrown' - ); + assert.throws( + () => { + this.visit('/grandma/mom/sally'); + }, + function(err) { + return err.msg == 'did it broke?'; + }, + 'Correct error was thrown' + ); - return this.runLoopSettled(); - } + return this.runLoopSettled(); + } - [`@test Handled errors that are thrown through rejection aren't swallowed`](assert) { - let handledError; + [`@test Handled errors that are thrown through rejection aren't swallowed`]( + assert + ) { + let handledError; + + this.add( + 'route:mom.sally', + Route.extend({ + model() { + step(assert, 1, 'MomSallyRoute#model'); + return RSVP.reject({ + msg: 'did it broke?' + }); + }, + actions: { + error(err) { + step(assert, 2, 'MomSallyRoute#actions.error'); + handledError = err; + this.transitionTo('mom.this-route-throws'); + + return false; + } + } + }) + ); - this.add('route:mom.sally', Route.extend({ - model() { - step(assert, 1, 'MomSallyRoute#model'); - return RSVP.reject({ - msg: 'did it broke?' - }); - }, - actions: { - error(err) { - step(assert, 2, 'MomSallyRoute#actions.error'); - handledError = err; - this.transitionTo('mom.this-route-throws'); - - return false; - } - } - })); + this.add( + 'route:mom.this-route-throws', + Route.extend({ + model() { + step(assert, 3, 'MomThisRouteThrows#model'); + return RSVP.reject(handledError); + } + }) + ); - this.add('route:mom.this-route-throws', Route.extend({ - model() { - step(assert, 3, 'MomThisRouteThrows#model'); - return RSVP.reject(handledError); - } - })); + assert.throws( + () => { + this.visit('/grandma/mom/sally'); + }, + function(err) { + return err.msg === 'did it broke?'; + }, + 'it broke' + ); - assert.throws( - () => { - this.visit('/grandma/mom/sally'); - }, - function(err) { return err.msg === 'did it broke?'; }, - 'it broke' - ); + return this.runLoopSettled(); + } - return this.runLoopSettled(); - } + ['@test Default error events move into nested route, prioritizing more specifically named error routes - NEW']( + assert + ) { + this.addTemplate('grandma.error', 'ERROR: {{model.msg}}'); + this.addTemplate('mom_error', 'MOM ERROR: {{model.msg}}'); + + this.add( + 'route:mom.sally', + Route.extend({ + model() { + step(assert, 1, 'MomSallyRoute#model'); + return RSVP.reject({ + msg: 'did it broke?' + }); + }, + actions: { + error() { + step(assert, 2, 'MomSallyRoute#actions.error'); + return true; + } + } + }) + ); - ['@test Default error events move into nested route, prioritizing more specifically named error routes - NEW'](assert) { - this.addTemplate('grandma.error', 'ERROR: {{model.msg}}'); - this.addTemplate('mom_error', 'MOM ERROR: {{model.msg}}'); + return this.visit('/grandma/mom/sally').then(() => { + step(assert, 3, 'Application finished booting'); - this.add('route:mom.sally', Route.extend({ - model() { - step(assert, 1, 'MomSallyRoute#model'); - return RSVP.reject({ - msg: 'did it broke?' - }); - }, - actions: { - error() { - step(assert, 2, 'MomSallyRoute#actions.error'); - return true; - } - } - })); + assert.equal( + this.$('#app').text(), + 'GRANDMA MOM ERROR: did it broke?', + 'the more specifically named mome error substate was entered over the other error route' + ); - return this.visit('/grandma/mom/sally').then(() => { - step(assert, 3, 'Application finished booting'); + assert.equal( + this.currentPath, + 'grandma.mom_error', + 'Initial route fully loaded' + ); + }); + } - assert.equal( - this.$('#app').text(), - 'GRANDMA MOM ERROR: did it broke?', - 'the more specifically named mome error substate was entered over the other error route' + ['@test Slow promises waterfall on startup'](assert) { + let grandmaDeferred = RSVP.defer(); + let sallyDeferred = RSVP.defer(); + + this.addTemplate('loading', 'LOADING'); + this.addTemplate('mom', 'MOM {{outlet}}'); + this.addTemplate('mom.loading', 'MOMLOADING'); + this.addTemplate('mom.sally', 'SALLY'); + + this.add( + 'route:grandma', + Route.extend({ + model() { + step(assert, 1, 'GrandmaRoute#model'); + return grandmaDeferred.promise; + } + }) ); - assert.equal(this.currentPath, 'grandma.mom_error', - 'Initial route fully loaded' + this.add( + 'route:mom', + Route.extend({ + model() { + step(assert, 2, 'MomRoute#model'); + return {}; + } + }) ); - }); - } - ['@test Slow promises waterfall on startup'](assert) { - let grandmaDeferred = RSVP.defer(); - let sallyDeferred = RSVP.defer(); + this.add( + 'route:mom.sally', + Route.extend({ + model() { + step(assert, 3, 'SallyRoute#model'); + return sallyDeferred.promise; + }, + setupController() { + step(assert, 4, 'SallyRoute#setupController'); + } + }) + ); - this.addTemplate('loading', 'LOADING'); - this.addTemplate('mom', 'MOM {{outlet}}'); - this.addTemplate('mom.loading', 'MOMLOADING'); - this.addTemplate('mom.sally', 'SALLY'); + let promise = this.visit('/grandma/mom/sally').then(() => { + text = this.$('#app').text(); - this.add('route:grandma', Route.extend({ - model() { - step(assert, 1, 'GrandmaRoute#model'); - return grandmaDeferred.promise; - } - })); + assert.equal(text, 'GRANDMA MOM SALLY', `Sally template displayed`); + }); + let text = this.$('#app').text(); - this.add('route:mom', Route.extend({ - model() { - step(assert, 2, 'MomRoute#model'); - return {}; - } - })); - - this.add('route:mom.sally', Route.extend({ - model() { - step(assert, 3, 'SallyRoute#model'); - return sallyDeferred.promise; - }, - setupController() { - step(assert, 4, 'SallyRoute#setupController'); - } - })); + assert.equal( + text, + 'LOADING', + `The loading template is nested in application template's outlet` + ); - let promise = this.visit('/grandma/mom/sally').then(() => { + this.runTask(() => grandmaDeferred.resolve()); text = this.$('#app').text(); assert.equal( text, - 'GRANDMA MOM SALLY', - `Sally template displayed` + 'GRANDMA MOM MOMLOADING', + `Mom's child loading route is displayed due to sally's slow promise` ); - }); - let text = this.$('#app').text(); - - assert.equal( - text, - 'LOADING', - `The loading template is nested in application template's outlet` - ); - - this.runTask(() => grandmaDeferred.resolve()); - text = this.$('#app').text(); - assert.equal( - text, - 'GRANDMA MOM MOMLOADING', - `Mom's child loading route is displayed due to sally's slow promise` - ); - - sallyDeferred.resolve(); - - return promise; - } - ['@test Enter child loading state of pivot route'](assert) { - let deferred = RSVP.defer(); - this.addTemplate('grandma.loading', 'GMONEYLOADING'); - - this.add('route:mom.sally', Route.extend({ - setupController() { - step(assert, 1, 'SallyRoute#setupController'); - } - })); + sallyDeferred.resolve(); - this.add('route:grandma.puppies', Route.extend({ - model() { - return deferred.promise; - } - })); + return promise; + } + ['@test Enter child loading state of pivot route'](assert) { + let deferred = RSVP.defer(); + this.addTemplate('grandma.loading', 'GMONEYLOADING'); + + this.add( + 'route:mom.sally', + Route.extend({ + setupController() { + step(assert, 1, 'SallyRoute#setupController'); + } + }) + ); - return this.visit('/grandma/mom/sally').then(() => { - assert.equal( - this.currentPath, - 'grandma.mom.sally', - 'Initial route fully loaded' + this.add( + 'route:grandma.puppies', + Route.extend({ + model() { + return deferred.promise; + } + }) ); - let promise = this.visit('/grandma/puppies').then(() => { + return this.visit('/grandma/mom/sally').then(() => { assert.equal( this.currentPath, - 'grandma.puppies', - 'Finished transition' + 'grandma.mom.sally', + 'Initial route fully loaded' ); - }); - assert.equal( - this.currentPath, - 'grandma.loading', - `in pivot route's child loading state` - ); - deferred.resolve(); + let promise = this.visit('/grandma/puppies').then(() => { + assert.equal( + this.currentPath, + 'grandma.puppies', + 'Finished transition' + ); + }); - return promise; - }); - } + assert.equal( + this.currentPath, + 'grandma.loading', + `in pivot route's child loading state` + ); + deferred.resolve(); - [`@test Error events that aren't bubbled don't throw application assertions`](assert) { - this.add('route:mom.sally', Route.extend({ - model() { - step(assert, 1, 'MomSallyRoute#model'); - return RSVP.reject({ - msg: 'did it broke?' - }); - }, - actions: { - error(err) { - step(assert, 2, 'MomSallyRoute#actions.error'); - assert.equal(err.msg, 'did it broke?', `it didn't break`); - return false; - } - } - })); + return promise; + }); + } - return this.visit('/grandma/mom/sally'); - } + [`@test Error events that aren't bubbled don't throw application assertions`]( + assert + ) { + this.add( + 'route:mom.sally', + Route.extend({ + model() { + step(assert, 1, 'MomSallyRoute#model'); + return RSVP.reject({ + msg: 'did it broke?' + }); + }, + actions: { + error(err) { + step(assert, 2, 'MomSallyRoute#actions.error'); + assert.equal(err.msg, 'did it broke?', `it didn't break`); + return false; + } + } + }) + ); - ['@test Handled errors that bubble can be handled at a higher level'](assert) { - let handledError; + return this.visit('/grandma/mom/sally'); + } - this.add('route:mom', Route.extend({ - actions: { - error(err) { - step(assert, 3, 'MomRoute#actions.error'); - assert.equal( - err, - handledError, - `error handled and rebubbled is handleable at higher route` - ); - } - } - })); + ['@test Handled errors that bubble can be handled at a higher level']( + assert + ) { + let handledError; + + this.add( + 'route:mom', + Route.extend({ + actions: { + error(err) { + step(assert, 3, 'MomRoute#actions.error'); + assert.equal( + err, + handledError, + `error handled and rebubbled is handleable at higher route` + ); + } + } + }) + ); - this.add('route:mom.sally', Route.extend({ - model() { - step(assert, 1, 'MomSallyRoute#model'); - return RSVP.reject({ - msg: 'did it broke?' - }); - }, - actions: { - error(err) { - step(assert, 2, 'MomSallyRoute#actions.error'); - handledError = err; - - return true; - } - } - })); + this.add( + 'route:mom.sally', + Route.extend({ + model() { + step(assert, 1, 'MomSallyRoute#model'); + return RSVP.reject({ + msg: 'did it broke?' + }); + }, + actions: { + error(err) { + step(assert, 2, 'MomSallyRoute#actions.error'); + handledError = err; + + return true; + } + } + }) + ); - return this.visit('/grandma/mom/sally'); - } + return this.visit('/grandma/mom/sally'); + } - ['@test Setting a query param during a slow transition should work'](assert) { - let deferred = RSVP.defer(); - this.addTemplate('memere.loading', 'MMONEYLOADING'); + ['@test Setting a query param during a slow transition should work']( + assert + ) { + let deferred = RSVP.defer(); + this.addTemplate('memere.loading', 'MMONEYLOADING'); + + this.add( + 'route:grandma', + Route.extend({ + beforeModel: function() { + this.transitionTo('memere', 1); + } + }) + ); - this.add('route:grandma', Route.extend({ - beforeModel: function() { - this.transitionTo('memere', 1); - } - })); + this.add( + 'route:memere', + Route.extend({ + queryParams: { + test: { defaultValue: 1 } + } + }) + ); - this.add('route:memere', Route.extend({ - queryParams: { - test: { defaultValue: 1 } - } - })); + this.add( + 'route:memere.index', + Route.extend({ + model() { + return deferred.promise; + } + }) + ); - this.add('route:memere.index', Route.extend({ - model() { - return deferred.promise; - } - })); + let promise = this.visit('/grandma').then(() => { + assert.equal( + this.currentPath, + 'memere.index', + 'Transition should be complete' + ); + }); + let memereController = this.getController('memere'); - let promise = this.visit('/grandma').then(() => { assert.equal( this.currentPath, - 'memere.index', - 'Transition should be complete' + 'memere.loading', + 'Initial route should be loading' ); - }); - let memereController = this.getController('memere'); - - assert.equal( - this.currentPath, - 'memere.loading', - 'Initial route should be loading' - ); - memereController.set('test', 3); + memereController.set('test', 3); - assert.equal( - this.currentPath, - 'memere.loading', - 'Initial route should still be loading' - ); + assert.equal( + this.currentPath, + 'memere.loading', + 'Initial route should still be loading' + ); - assert.equal(memereController.get('test'), 3, - 'Controller query param value should have changed' - ); - deferred.resolve(); + assert.equal( + memereController.get('test'), + 3, + 'Controller query param value should have changed' + ); + deferred.resolve(); - return promise; + return promise; + } } -}); +); diff --git a/packages/ember/tests/routing/toplevel_dom_test.js b/packages/ember/tests/routing/toplevel_dom_test.js index e22e9172dfb..6dceab4fa85 100644 --- a/packages/ember/tests/routing/toplevel_dom_test.js +++ b/packages/ember/tests/routing/toplevel_dom_test.js @@ -1,34 +1,37 @@ import { ENV } from 'ember-environment'; import { moduleFor, ApplicationTestCase } from 'internal-test-helpers'; -moduleFor('Top Level DOM Structure', class extends ApplicationTestCase { - constructor() { - super(); - this._APPLICATION_TEMPLATE_WRAPPER = ENV._APPLICATION_TEMPLATE_WRAPPER; +moduleFor( + 'Top Level DOM Structure', + class extends ApplicationTestCase { + constructor() { + super(); + this._APPLICATION_TEMPLATE_WRAPPER = ENV._APPLICATION_TEMPLATE_WRAPPER; + } + + teardown() { + super.teardown(); + ENV._APPLICATION_TEMPLATE_WRAPPER = this._APPLICATION_TEMPLATE_WRAPPER; + } + + ['@test topmost template with wrapper']() { + ENV._APPLICATION_TEMPLATE_WRAPPER = true; + + this.addTemplate('application', 'hello world'); + + return this.visit('/').then(() => { + this.assertComponentElement(this.element, { content: 'hello world' }); + }); + } + + ['@test topmost template without wrapper']() { + ENV._APPLICATION_TEMPLATE_WRAPPER = false; + + this.addTemplate('application', 'hello world'); + + return this.visit('/').then(() => { + this.assertInnerHTML('hello world'); + }); + } } - - teardown() { - super.teardown(); - ENV._APPLICATION_TEMPLATE_WRAPPER = this._APPLICATION_TEMPLATE_WRAPPER; - } - - ['@test topmost template with wrapper']() { - ENV._APPLICATION_TEMPLATE_WRAPPER = true; - - this.addTemplate('application', 'hello world'); - - return this.visit('/').then(() => { - this.assertComponentElement(this.element, { content: 'hello world' }); - }); - } - - ['@test topmost template without wrapper']() { - ENV._APPLICATION_TEMPLATE_WRAPPER = false; - - this.addTemplate('application', 'hello world'); - - return this.visit('/').then(() => { - this.assertInnerHTML('hello world'); - }); - } -}); +); diff --git a/packages/ember/tests/service_injection_test.js b/packages/ember/tests/service_injection_test.js index bf946c445ee..5765ca83e3c 100644 --- a/packages/ember/tests/service_injection_test.js +++ b/packages/ember/tests/service_injection_test.js @@ -2,135 +2,211 @@ import { Controller } from 'ember-runtime'; import { moduleFor, ApplicationTestCase } from 'internal-test-helpers'; import { inject, Service } from 'ember-runtime'; import { computed } from 'ember-metal'; -import { EMBER_METAL_ES5_GETTERS, EMBER_MODULE_UNIFICATION } from 'ember/features'; - -moduleFor('Service Injection', class extends ApplicationTestCase { - - ['@test Service can be injected and is resolved'](assert) { - this.add('controller:application', Controller.extend({ - myService: inject.service('my-service') - })); - let MyService = Service.extend(); - this.add('service:my-service', MyService); - this.addTemplate('application', ''); - - this.visit('/').then(() => { - let controller = this.applicationInstance.lookup('controller:application'); - assert.ok(controller.get('myService') instanceof MyService); - }); - } -}); - -if (EMBER_METAL_ES5_GETTERS) { - moduleFor('Service Injection with ES5 Getters', class extends ApplicationTestCase { - ['@test Service can be injected and is resolved without calling `get`'](assert) { - this.add('controller:application', Controller.extend({ - myService: inject.service('my-service') - })); - let MyService = Service.extend({ - name: computed(function() { - return 'The service name'; +import { + EMBER_METAL_ES5_GETTERS, + EMBER_MODULE_UNIFICATION +} from 'ember/features'; + +moduleFor( + 'Service Injection', + class extends ApplicationTestCase { + ['@test Service can be injected and is resolved'](assert) { + this.add( + 'controller:application', + Controller.extend({ + myService: inject.service('my-service') }) - }); + ); + let MyService = Service.extend(); this.add('service:my-service', MyService); this.addTemplate('application', ''); this.visit('/').then(() => { - let controller = this.applicationInstance.lookup('controller:application'); - assert.ok(controller.myService instanceof MyService); - assert.equal(controller.myService.name, 'The service name', 'service property accessible'); - }); - } - }); -} - -if (EMBER_MODULE_UNIFICATION) { - moduleFor('Service Injection (MU)', class extends ApplicationTestCase { - ['@test Service can be injected with source and is resolved'](assert) { - let source = 'controller:src/ui/routes/application/controller'; - this.add('controller:application', Controller.extend({ - myService: inject.service('my-service', { source }) - })); - let MyService = Service.extend(); - this.add({ - specifier: 'service:my-service', - source - }, MyService); - - return this.visit('/').then(() => { - let controller = this.applicationInstance.lookup('controller:application'); - + let controller = this.applicationInstance.lookup( + 'controller:application' + ); assert.ok(controller.get('myService') instanceof MyService); }); } + } +); - ['@test Services can be injected with same name, different source, and resolve different instances'](assert) { - // This test implies that there is a file src/ui/routes/route-a/-services/my-service - let routeASource = 'controller:src/ui/routes/route-a/controller'; - // This test implies that there is a file src/ui/routes/route-b/-services/my-service - let routeBSource = 'controller:src/ui/routes/route-b/controller'; - - this.add('controller:route-a', Controller.extend({ - myService: inject.service('my-service', { source: routeASource }) - })); - - this.add('controller:route-b', Controller.extend({ - myService: inject.service('my-service', { source: routeBSource }) - })); - - let LocalLookupService = Service.extend(); - this.add({ - specifier: 'service:my-service', - source: routeASource - }, LocalLookupService); - - let MyService = Service.extend(); - this.add({ - specifier: 'service:my-service', - source: routeBSource - }, MyService); - - return this.visit('/').then(() => { - let controllerA = this.applicationInstance.lookup('controller:route-a'); - let serviceFromControllerA = controllerA.get('myService'); - assert.ok(serviceFromControllerA instanceof LocalLookupService, 'local lookup service is returned'); - - let controllerB = this.applicationInstance.lookup('controller:route-b'); - let serviceFromControllerB = controllerB.get('myService'); - assert.ok(serviceFromControllerB instanceof MyService, 'global service is returned'); - - assert.notStrictEqual(serviceFromControllerA, serviceFromControllerB); - }); - } - - ['@test Services can be injected with same name, different source, but same resolution result, and share an instance'](assert) { - let routeASource = 'controller:src/ui/routes/route-a/controller'; - let routeBSource = 'controller:src/ui/routes/route-b/controller'; - - this.add('controller:route-a', Controller.extend({ - myService: inject.service('my-service', { source: routeASource }) - })); - - this.add('controller:route-b', Controller.extend({ - myService: inject.service('my-service', { source: routeBSource }) - })); - - let MyService = Service.extend(); - this.add({ - specifier: 'service:my-service' - }, MyService); - - return this.visit('/').then(() => { - let controllerA = this.applicationInstance.lookup('controller:route-a'); - let serviceFromControllerA = controllerA.get('myService'); - assert.ok(serviceFromControllerA instanceof MyService); - - let controllerB = this.applicationInstance.lookup('controller:route-b'); - assert.strictEqual(serviceFromControllerA, controllerB.get('myService')); - }); +if (EMBER_METAL_ES5_GETTERS) { + moduleFor( + 'Service Injection with ES5 Getters', + class extends ApplicationTestCase { + ['@test Service can be injected and is resolved without calling `get`']( + assert + ) { + this.add( + 'controller:application', + Controller.extend({ + myService: inject.service('my-service') + }) + ); + let MyService = Service.extend({ + name: computed(function() { + return 'The service name'; + }) + }); + this.add('service:my-service', MyService); + this.addTemplate('application', ''); + + this.visit('/').then(() => { + let controller = this.applicationInstance.lookup( + 'controller:application' + ); + assert.ok(controller.myService instanceof MyService); + assert.equal( + controller.myService.name, + 'The service name', + 'service property accessible' + ); + }); + } } + ); +} - /* +if (EMBER_MODULE_UNIFICATION) { + moduleFor( + 'Service Injection (MU)', + class extends ApplicationTestCase { + ['@test Service can be injected with source and is resolved'](assert) { + let source = 'controller:src/ui/routes/application/controller'; + this.add( + 'controller:application', + Controller.extend({ + myService: inject.service('my-service', { source }) + }) + ); + let MyService = Service.extend(); + this.add( + { + specifier: 'service:my-service', + source + }, + MyService + ); + + return this.visit('/').then(() => { + let controller = this.applicationInstance.lookup( + 'controller:application' + ); + + assert.ok(controller.get('myService') instanceof MyService); + }); + } + + ['@test Services can be injected with same name, different source, and resolve different instances']( + assert + ) { + // This test implies that there is a file src/ui/routes/route-a/-services/my-service + let routeASource = 'controller:src/ui/routes/route-a/controller'; + // This test implies that there is a file src/ui/routes/route-b/-services/my-service + let routeBSource = 'controller:src/ui/routes/route-b/controller'; + + this.add( + 'controller:route-a', + Controller.extend({ + myService: inject.service('my-service', { source: routeASource }) + }) + ); + + this.add( + 'controller:route-b', + Controller.extend({ + myService: inject.service('my-service', { source: routeBSource }) + }) + ); + + let LocalLookupService = Service.extend(); + this.add( + { + specifier: 'service:my-service', + source: routeASource + }, + LocalLookupService + ); + + let MyService = Service.extend(); + this.add( + { + specifier: 'service:my-service', + source: routeBSource + }, + MyService + ); + + return this.visit('/').then(() => { + let controllerA = this.applicationInstance.lookup( + 'controller:route-a' + ); + let serviceFromControllerA = controllerA.get('myService'); + assert.ok( + serviceFromControllerA instanceof LocalLookupService, + 'local lookup service is returned' + ); + + let controllerB = this.applicationInstance.lookup( + 'controller:route-b' + ); + let serviceFromControllerB = controllerB.get('myService'); + assert.ok( + serviceFromControllerB instanceof MyService, + 'global service is returned' + ); + + assert.notStrictEqual(serviceFromControllerA, serviceFromControllerB); + }); + } + + ['@test Services can be injected with same name, different source, but same resolution result, and share an instance']( + assert + ) { + let routeASource = 'controller:src/ui/routes/route-a/controller'; + let routeBSource = 'controller:src/ui/routes/route-b/controller'; + + this.add( + 'controller:route-a', + Controller.extend({ + myService: inject.service('my-service', { source: routeASource }) + }) + ); + + this.add( + 'controller:route-b', + Controller.extend({ + myService: inject.service('my-service', { source: routeBSource }) + }) + ); + + let MyService = Service.extend(); + this.add( + { + specifier: 'service:my-service' + }, + MyService + ); + + return this.visit('/').then(() => { + let controllerA = this.applicationInstance.lookup( + 'controller:route-a' + ); + let serviceFromControllerA = controllerA.get('myService'); + assert.ok(serviceFromControllerA instanceof MyService); + + let controllerB = this.applicationInstance.lookup( + 'controller:route-b' + ); + assert.strictEqual( + serviceFromControllerA, + controllerB.get('myService') + ); + }); + } + + /* * This test demonstrates a failure in the caching system of ember's * container around singletons and and local lookup. The local lookup * is cached and the global injection is then looked up incorrectly. @@ -140,50 +216,78 @@ if (EMBER_MODULE_UNIFICATION) { * just a demonstration of what could go wrong if we permit arbitrary * configuration (such as a singleton type that has local lookup). */ - ['@test Services can be injected with same name, one with source one without, and share an instance'](assert) { - let routeASource = 'controller:src/ui/routes/route-a/controller'; - this.add('controller:route-a', Controller.extend({ - myService: inject.service('my-service', { source: routeASource }) - })); - - this.add('controller:route-b', Controller.extend({ - myService: inject.service('my-service') - })); - - let MyService = Service.extend(); - this.add({ - specifier: 'service:my-service' - }, MyService); - - return this.visit('/').then(() => { - let controllerA = this.applicationInstance.lookup('controller:route-a'); - let serviceFromControllerA = controllerA.get('myService'); - assert.ok(serviceFromControllerA instanceof MyService, 'global service is returned'); - - let controllerB = this.applicationInstance.lookup('controller:route-b'); - let serviceFromControllerB = controllerB.get('myService'); - assert.ok(serviceFromControllerB instanceof MyService, 'global service is returned'); - - assert.strictEqual(serviceFromControllerA, serviceFromControllerB); - }); - } - - ['@test Service with namespace can be injected and is resolved'](assert) { - this.add('controller:application', Controller.extend({ - myService: inject.service('my-namespace::my-service') - })); - let MyService = Service.extend(); - this.add({ - specifier: 'service:my-service', - namespace: 'my-namespace' - }, MyService); - - this.visit('/').then(() => { - let controller = this.applicationInstance.lookup('controller:application'); - assert.ok(controller.get('myService') instanceof MyService); - }); + ['@test Services can be injected with same name, one with source one without, and share an instance']( + assert + ) { + let routeASource = 'controller:src/ui/routes/route-a/controller'; + this.add( + 'controller:route-a', + Controller.extend({ + myService: inject.service('my-service', { source: routeASource }) + }) + ); + + this.add( + 'controller:route-b', + Controller.extend({ + myService: inject.service('my-service') + }) + ); + + let MyService = Service.extend(); + this.add( + { + specifier: 'service:my-service' + }, + MyService + ); + + return this.visit('/').then(() => { + let controllerA = this.applicationInstance.lookup( + 'controller:route-a' + ); + let serviceFromControllerA = controllerA.get('myService'); + assert.ok( + serviceFromControllerA instanceof MyService, + 'global service is returned' + ); + + let controllerB = this.applicationInstance.lookup( + 'controller:route-b' + ); + let serviceFromControllerB = controllerB.get('myService'); + assert.ok( + serviceFromControllerB instanceof MyService, + 'global service is returned' + ); + + assert.strictEqual(serviceFromControllerA, serviceFromControllerB); + }); + } + + ['@test Service with namespace can be injected and is resolved'](assert) { + this.add( + 'controller:application', + Controller.extend({ + myService: inject.service('my-namespace::my-service') + }) + ); + let MyService = Service.extend(); + this.add( + { + specifier: 'service:my-service', + namespace: 'my-namespace' + }, + MyService + ); + + this.visit('/').then(() => { + let controller = this.applicationInstance.lookup( + 'controller:application' + ); + assert.ok(controller.get('myService') instanceof MyService); + }); + } } - - }); - + ); } diff --git a/packages/ember/tests/view_instrumentation_test.js b/packages/ember/tests/view_instrumentation_test.js index 3169d3d5fbd..70632e4244e 100644 --- a/packages/ember/tests/view_instrumentation_test.js +++ b/packages/ember/tests/view_instrumentation_test.js @@ -4,50 +4,58 @@ import { } from 'ember-metal'; import { moduleFor, ApplicationTestCase } from 'internal-test-helpers'; -moduleFor('View Instrumentation', class extends ApplicationTestCase { - constructor() { - super(); - this.addTemplate('application', `{{outlet}}`); - this.addTemplate('index', `

    Index

    `); - this.addTemplate('posts', `

    Posts

    `); +moduleFor( + 'View Instrumentation', + class extends ApplicationTestCase { + constructor() { + super(); + this.addTemplate('application', `{{outlet}}`); + this.addTemplate('index', `

    Index

    `); + this.addTemplate('posts', `

    Posts

    `); - this.router.map(function() { - this.route('posts'); - }); - } - teardown() { - reset(); - super.teardown(); - } + this.router.map(function() { + this.route('posts'); + }); + } + teardown() { + reset(); + super.teardown(); + } - ['@test Nodes without view instances are instrumented'](assert) { - let called = false; + ['@test Nodes without view instances are instrumented'](assert) { + let called = false; - subscribe('render', { - before() { - called = true; - }, - after() {} - }); + subscribe('render', { + before() { + called = true; + }, + after() {} + }); - return this.visit('/').then(() => { - assert.equal(this.textValue(), - 'Index', - 'It rendered the correct template' - ); + return this.visit('/') + .then(() => { + assert.equal( + this.textValue(), + 'Index', + 'It rendered the correct template' + ); - assert.ok(called, 'Instrumentation called on first render'); - called = false; + assert.ok(called, 'Instrumentation called on first render'); + called = false; - return this.visit('/posts'); - }).then(() => { - assert.equal(this.textValue(), - 'Posts', - 'It rendered the correct template' - ); - assert.ok(called, - 'Instrumentation called on transition to non-view backed route' - ); - }); + return this.visit('/posts'); + }) + .then(() => { + assert.equal( + this.textValue(), + 'Posts', + 'It rendered the correct template' + ); + assert.ok( + called, + 'Instrumentation called on transition to non-view backed route' + ); + }); + } } -}); +); diff --git a/packages/external-helpers/lib/external-helpers-dev.js b/packages/external-helpers/lib/external-helpers-dev.js index 835a162fe24..39c53a5eb91 100644 --- a/packages/external-helpers/lib/external-helpers-dev.js +++ b/packages/external-helpers/lib/external-helpers-dev.js @@ -6,7 +6,10 @@ export function classCallCheck(instance, Constructor) { export function inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { - throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); + throw new TypeError( + 'Super expression must either be null or a function, not ' + + typeof superClass + ); } subClass.prototype = Object.create(superClass && superClass.prototype, { @@ -18,7 +21,10 @@ export function inherits(subClass, superClass) { } }); - if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : defaults(subClass, superClass); + if (superClass) + Object.setPrototypeOf + ? Object.setPrototypeOf(subClass, superClass) + : defaults(subClass, superClass); } export function taggedTemplateLiteralLoose(strings, raw) { @@ -54,11 +60,15 @@ export function defaults(obj, defaults) { return obj; } -export const possibleConstructorReturn = (function (self, call) { +export const possibleConstructorReturn = function(self, call) { if (!self) { - throw new ReferenceError(`this hasn't been initialized - super() hasn't been called`); + throw new ReferenceError( + `this hasn't been initialized - super() hasn't been called` + ); } - return call && (typeof call === 'object' || typeof call === 'function') ? call : self; -}); + return call && (typeof call === 'object' || typeof call === 'function') + ? call + : self; +}; export const slice = Array.prototype.slice; diff --git a/packages/external-helpers/lib/external-helpers-prod.js b/packages/external-helpers/lib/external-helpers-prod.js index dc1c93cfd52..72c99587cbe 100644 --- a/packages/external-helpers/lib/external-helpers-prod.js +++ b/packages/external-helpers/lib/external-helpers-prod.js @@ -8,7 +8,10 @@ export function inherits(subClass, superClass) { } }); - if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : defaults(subClass, superClass); + if (superClass) + Object.setPrototypeOf + ? Object.setPrototypeOf(subClass, superClass) + : defaults(subClass, superClass); } export function taggedTemplateLiteralLoose(strings, raw) { @@ -44,8 +47,10 @@ export function defaults(obj, defaults) { return obj; } -export const possibleConstructorReturn = (function (self, call) { - return call && (typeof call === 'object' || typeof call === 'function') ? call : self; -}); +export const possibleConstructorReturn = function(self, call) { + return call && (typeof call === 'object' || typeof call === 'function') + ? call + : self; +}; -export const slice = Array.prototype.slice; \ No newline at end of file +export const slice = Array.prototype.slice; diff --git a/packages/internal-test-helpers/lib/apply-mixins.js b/packages/internal-test-helpers/lib/apply-mixins.js index 20cbf0be4d4..a3e8c2f03f5 100644 --- a/packages/internal-test-helpers/lib/apply-mixins.js +++ b/packages/internal-test-helpers/lib/apply-mixins.js @@ -2,7 +2,7 @@ import { assign } from 'ember-utils'; import getAllPropertyNames from './get-all-property-names'; function isGenerator(mixin) { - return Array.isArray(mixin.cases) && (typeof mixin.generate === 'function'); + return Array.isArray(mixin.cases) && typeof mixin.generate === 'function'; } export default function applyMixins(TestClass, ...mixins) { diff --git a/packages/internal-test-helpers/lib/build-owner.js b/packages/internal-test-helpers/lib/build-owner.js index 3e82021ba53..e20174c3c69 100644 --- a/packages/internal-test-helpers/lib/build-owner.js +++ b/packages/internal-test-helpers/lib/build-owner.js @@ -1,9 +1,6 @@ import { Registry } from 'container'; import { Router } from 'ember-routing'; -import { - Application, - ApplicationInstance -} from 'ember-application'; +import { Application, ApplicationInstance } from 'ember-application'; import { RegistryProxyMixin, ContainerProxyMixin, @@ -18,7 +15,11 @@ export default function buildOwner(options = {}) { let Owner = EmberObject.extend(RegistryProxyMixin, ContainerProxyMixin); let namespace = EmberObject.create({ - Resolver: { create() { return resolver; } } + Resolver: { + create() { + return resolver; + } + } }); let fallbackRegistry = Application.buildRegistry(namespace); @@ -30,10 +31,13 @@ export default function buildOwner(options = {}) { ApplicationInstance.setupRegistry(registry, bootOptions); - let owner = Owner.create({ - __registry__: registry, - __container__: null - }, ownerOptions); + let owner = Owner.create( + { + __registry__: registry, + __container__: null + }, + ownerOptions + ); let container = registry.container({ owner }); owner.__container__ = container; diff --git a/packages/internal-test-helpers/lib/confirm-export.js b/packages/internal-test-helpers/lib/confirm-export.js index c85b7a039b3..774a7fd5fb1 100644 --- a/packages/internal-test-helpers/lib/confirm-export.js +++ b/packages/internal-test-helpers/lib/confirm-export.js @@ -14,21 +14,51 @@ function getDescriptor(obj, path) { return Object.getOwnPropertyDescriptor(value, last); } -export default function confirmExport(Ember, assert, path, moduleId, exportName) { +export default function confirmExport( + Ember, + assert, + path, + moduleId, + exportName +) { let desc = getDescriptor(Ember, path); assert.ok(desc, 'the property exists on the global'); let mod = require(moduleId); if (typeof exportName === 'string') { - assert.equal(desc.value, mod[exportName], `Ember.${path} is exported correctly`); - assert.notEqual(mod[exportName], undefined, `Ember.${path} is not \`undefined\``); + assert.equal( + desc.value, + mod[exportName], + `Ember.${path} is exported correctly` + ); + assert.notEqual( + mod[exportName], + undefined, + `Ember.${path} is not \`undefined\`` + ); } else { - assert.equal(desc.get, mod[exportName.get], `Ember.${path} getter is exported correctly`); - assert.notEqual(desc.get, undefined, `Ember.${path} getter is not undefined`); + assert.equal( + desc.get, + mod[exportName.get], + `Ember.${path} getter is exported correctly` + ); + assert.notEqual( + desc.get, + undefined, + `Ember.${path} getter is not undefined` + ); if (exportName.set) { - assert.equal(desc.set, mod[exportName.set], `Ember.${path} setter is exported correctly`); - assert.notEqual(desc.set, undefined, `Ember.${path} setter is not undefined`); + assert.equal( + desc.set, + mod[exportName.set], + `Ember.${path} setter is exported correctly` + ); + assert.notEqual( + desc.set, + undefined, + `Ember.${path} setter is not undefined` + ); } } } diff --git a/packages/internal-test-helpers/lib/ember-dev/assertion.js b/packages/internal-test-helpers/lib/ember-dev/assertion.js index 2443c985fa5..a7dd752e280 100644 --- a/packages/internal-test-helpers/lib/ember-dev/assertion.js +++ b/packages/internal-test-helpers/lib/ember-dev/assertion.js @@ -24,8 +24,8 @@ export default function AssertionAssert(env) { } AssertionAssert.prototype = { - reset() { }, - assert() { }, + reset() {}, + assert() {}, inject() { let expectAssertion = (func, expectedMessage) => { @@ -44,7 +44,9 @@ AssertionAssert.prototype = { try { callWithStub(this.env, 'assert', func, (message, test) => { sawCall = true; - if (checkTest(test)) { return; } + if (checkTest(test)) { + return; + } actualMessage = message; throw BREAK; }); @@ -57,7 +59,7 @@ AssertionAssert.prototype = { check(assert, sawCall, actualMessage, expectedMessage); }; - let ignoreAssertion = (func) => { + let ignoreAssertion = func => { callWithStub(this.env, 'assert', func); }; @@ -74,15 +76,28 @@ AssertionAssert.prototype = { function check(assert, sawCall, actualMessage, expectedMessage) { // Run assertions in an order that is useful when debugging a test failure. if (!sawCall) { - assert.ok(false, `Expected Ember.assert to be called (Not called with any value).`); + assert.ok( + false, + `Expected Ember.assert to be called (Not called with any value).` + ); } else if (!actualMessage) { - assert.ok(false, `Expected a failing Ember.assert (Ember.assert called, but without a failing test).`); + assert.ok( + false, + `Expected a failing Ember.assert (Ember.assert called, but without a failing test).` + ); } else { if (expectedMessage) { if (expectedMessage instanceof RegExp) { - assert.ok(expectedMessage.test(actualMessage), `Expected failing Ember.assert: '${expectedMessage}', but got '${actualMessage}'.`); + assert.ok( + expectedMessage.test(actualMessage), + `Expected failing Ember.assert: '${expectedMessage}', but got '${actualMessage}'.` + ); } else { - assert.equal(actualMessage, expectedMessage, `Expected failing Ember.assert: '${expectedMessage}', but got '${actualMessage}'.`); + assert.equal( + actualMessage, + expectedMessage, + `Expected failing Ember.assert: '${expectedMessage}', but got '${actualMessage}'.` + ); } } else { // Positive assertion that assert was called diff --git a/packages/internal-test-helpers/lib/ember-dev/debug.js b/packages/internal-test-helpers/lib/ember-dev/debug.js index b0870032290..da964af1293 100644 --- a/packages/internal-test-helpers/lib/ember-dev/debug.js +++ b/packages/internal-test-helpers/lib/ember-dev/debug.js @@ -28,7 +28,7 @@ class DebugAssert { // Run an expectation callback within the context of a new tracker, optionally // accepting a function to run, which asserts immediately - runExpectation(func, callback) { + runExpectation(func, callback) { let originalTracker; // When helpers are passed a callback, they get a new tracker context diff --git a/packages/internal-test-helpers/lib/ember-dev/deprecation.js b/packages/internal-test-helpers/lib/ember-dev/deprecation.js index 79b4b0fcbdb..3ffe5131dd0 100644 --- a/packages/internal-test-helpers/lib/ember-dev/deprecation.js +++ b/packages/internal-test-helpers/lib/ember-dev/deprecation.js @@ -17,14 +17,16 @@ class DeprecationAssert extends DebugAssert { // expectNoDeprecation(); // Ember.deprecate("Old And Busted"); // - let expectNoDeprecation = (func) => { + let expectNoDeprecation = func => { if (typeof func !== 'function') { func = null; } - this.runExpectation(func, (tracker) => { + this.runExpectation(func, tracker => { if (tracker.isExpectingCalls()) { - throw new Error("expectNoDeprecation was called after expectDeprecation was called!"); + throw new Error( + 'expectNoDeprecation was called after expectDeprecation was called!' + ); } tracker.expectNoCalls(); @@ -49,16 +51,18 @@ class DeprecationAssert extends DebugAssert { func = null; } - this.runExpectation(func, (tracker) => { + this.runExpectation(func, tracker => { if (tracker.isExpectingNoCalls()) { - throw new Error("expectDeprecation was called after expectNoDeprecation was called!"); + throw new Error( + 'expectDeprecation was called after expectNoDeprecation was called!' + ); } tracker.expectCall(message); }); }; - let ignoreDeprecation = (func) => { + let ignoreDeprecation = func => { callWithStub(this.env, 'deprecate', func); }; diff --git a/packages/internal-test-helpers/lib/ember-dev/index.js b/packages/internal-test-helpers/lib/ember-dev/index.js index 6765fb682f6..e853cf480ca 100644 --- a/packages/internal-test-helpers/lib/ember-dev/index.js +++ b/packages/internal-test-helpers/lib/ember-dev/index.js @@ -1,9 +1,9 @@ -import DeprecationAssert from "./deprecation"; -import WarningAssert from "./warning"; -import AssertionAssert from "./assertion"; -import RunLoopAssert from "./run-loop"; +import DeprecationAssert from './deprecation'; +import WarningAssert from './warning'; +import AssertionAssert from './assertion'; +import RunLoopAssert from './run-loop'; -import {buildCompositeAssert} from "./utils"; +import { buildCompositeAssert } from './utils'; var EmberDevTestHelperAssert = buildCompositeAssert([ DeprecationAssert, diff --git a/packages/internal-test-helpers/lib/ember-dev/method-call-tracker.js b/packages/internal-test-helpers/lib/ember-dev/method-call-tracker.js index 25ca252f0b6..183cf28303b 100644 --- a/packages/internal-test-helpers/lib/ember-dev/method-call-tracker.js +++ b/packages/internal-test-helpers/lib/ember-dev/method-call-tracker.js @@ -23,7 +23,7 @@ MethodCallTracker.prototype = { env.setDebugFunction(methodName, (message, test) => { let resultOfTest = checkTest(test); - this._actuals.push([ message, resultOfTest ]); + this._actuals.push([message, resultOfTest]); }); }, @@ -65,7 +65,10 @@ MethodCallTracker.prototype = { } if (env.runningProdBuild) { - assert.ok(true, `calls to Ember.${methodName} disabled in production builds.`); + assert.ok( + true, + `calls to Ember.${methodName} disabled in production builds.` + ); return; } @@ -76,7 +79,12 @@ MethodCallTracker.prototype = { actualMessages.push(actuals[i][0]); } } - assert.ok(actualMessages.length === 0, `Expected no Ember.${methodName} calls, got ${actuals.length}: ${actualMessages.join(', ')}`); + assert.ok( + actualMessages.length === 0, + `Expected no Ember.${methodName} calls, got ${ + actuals.length + }: ${actualMessages.join(', ')}` + ); return; } @@ -102,15 +110,36 @@ MethodCallTracker.prototype = { } if (!actual) { - assert.ok(false, `Received no Ember.${methodName} calls at all, expecting: ${expected}`); + assert.ok( + false, + `Received no Ember.${methodName} calls at all, expecting: ${expected}` + ); } else if (match && !match[1]) { - assert.ok(true, `Received failing Ember.${methodName} call with message: ${match[0]}`); + assert.ok( + true, + `Received failing Ember.${methodName} call with message: ${match[0]}` + ); } else if (match && match[1]) { - assert.ok(false, `Expected failing Ember.${methodName} call, got succeeding with message: ${match[0]}`); + assert.ok( + false, + `Expected failing Ember.${methodName} call, got succeeding with message: ${ + match[0] + }` + ); } else if (actual[1]) { - assert.ok(false, `Did not receive failing Ember.${methodName} call matching '${expected}', last was success with '${actual[0]}'`); + assert.ok( + false, + `Did not receive failing Ember.${methodName} call matching '${expected}', last was success with '${ + actual[0] + }'` + ); } else if (!actual[1]) { - assert.ok(false, `Did not receive failing Ember.${methodName} call matching '${expected}', last was failure with '${actual[0]}'`); + assert.ok( + false, + `Did not receive failing Ember.${methodName} call matching '${expected}', last was failure with '${ + actual[0] + }'` + ); } } } diff --git a/packages/internal-test-helpers/lib/ember-dev/run-loop.js b/packages/internal-test-helpers/lib/ember-dev/run-loop.js index 059152be85c..4aeb5428775 100644 --- a/packages/internal-test-helpers/lib/ember-dev/run-loop.js +++ b/packages/internal-test-helpers/lib/ember-dev/run-loop.js @@ -2,32 +2,35 @@ import { getCurrentRunLoop, hasScheduledTimers, cancelTimers, - end, + end } from 'ember-metal'; -function RunLoopAssertion(env){ +function RunLoopAssertion(env) { this.env = env; } RunLoopAssertion.prototype = { - reset: function(){}, - inject: function(){}, - assert: function(){ + reset: function() {}, + inject: function() {}, + assert: function() { let { assert } = QUnit.config.current; if (getCurrentRunLoop()) { - assert.ok(false, "Should not be in a run loop at end of test"); + assert.ok(false, 'Should not be in a run loop at end of test'); while (getCurrentRunLoop()) { end(); } } if (hasScheduledTimers()) { - assert.ok(false, "Ember run should not have scheduled timers at end of test"); + assert.ok( + false, + 'Ember run should not have scheduled timers at end of test' + ); cancelTimers(); } }, - restore: function(){} + restore: function() {} }; export default RunLoopAssertion; diff --git a/packages/internal-test-helpers/lib/ember-dev/setup-qunit.js b/packages/internal-test-helpers/lib/ember-dev/setup-qunit.js index eba5c5a8026..e544dc0b2bf 100644 --- a/packages/internal-test-helpers/lib/ember-dev/setup-qunit.js +++ b/packages/internal-test-helpers/lib/ember-dev/setup-qunit.js @@ -9,8 +9,9 @@ export default function setupQUnit(assertion, _qunitGlobal) { qunitGlobal.module = function(name, _options) { var options = _options || {}; - var originalSetup = options.setup || options.beforeEach || function() { }; - var originalTeardown = options.teardown || options.afterEach || function() { }; + var originalSetup = options.setup || options.beforeEach || function() {}; + var originalTeardown = + options.teardown || options.afterEach || function() {}; delete options.setup; delete options.teardown; diff --git a/packages/internal-test-helpers/lib/ember-dev/utils.js b/packages/internal-test-helpers/lib/ember-dev/utils.js index b2c66d9e880..458e013920b 100644 --- a/packages/internal-test-helpers/lib/ember-dev/utils.js +++ b/packages/internal-test-helpers/lib/ember-dev/utils.js @@ -1,6 +1,6 @@ function callForEach(prop, func) { return function() { - for (var i=0, l=this[prop].length;i { + let expectNoWarning = func => { if (typeof func !== 'function') { func = null; } - this.runExpectation(func, (tracker) => { + this.runExpectation(func, tracker => { if (tracker.isExpectingCalls()) { - throw new Error("expectNoWarning was called after expectWarning was called!"); + throw new Error( + 'expectNoWarning was called after expectWarning was called!' + ); } tracker.expectNoCalls(); @@ -49,16 +51,18 @@ class WarningAssert extends DebugAssert { fn = null; } - this.runExpectation(fn, (tracker) => { + this.runExpectation(fn, tracker => { if (tracker.isExpectingNoCalls()) { - throw new Error("expectWarning was called after expectNoWarning was called!"); + throw new Error( + 'expectWarning was called after expectNoWarning was called!' + ); } tracker.expectCall(message); }); }; - let ignoreWarning = (func) => { + let ignoreWarning = func => { callWithStub(this.env, 'warn', func); }; diff --git a/packages/internal-test-helpers/lib/equal-inner-html.js b/packages/internal-test-helpers/lib/equal-inner-html.js index 09a353c0c61..6481b0d91a7 100644 --- a/packages/internal-test-helpers/lib/equal-inner-html.js +++ b/packages/internal-test-helpers/lib/equal-inner-html.js @@ -1,5 +1,5 @@ // detect side-effects of cloning svg elements in IE9-11 -let ieSVGInnerHTML = ((() => { +let ieSVGInnerHTML = (() => { if (!document.createElementNS) { return false; } @@ -8,7 +8,7 @@ let ieSVGInnerHTML = ((() => { div.appendChild(node); let clone = div.cloneNode(true); return clone.innerHTML === ''; -}))(); +})(); function normalizeInnerHTML(actualHTML) { if (ieSVGInnerHTML) { @@ -16,8 +16,11 @@ function normalizeInnerHTML(actualHTML) { // drop namespace attribute // replace self-closing elements actualHTML = actualHTML - .replace(/ xmlns="[^"]+"/, '') - .replace(/<([^ >]+) [^\/>]*\/>/gi, (tag, tagName) => `${tag.slice(0, tag.length - 3)}>`); + .replace(/ xmlns="[^"]+"/, '') + .replace( + /<([^ >]+) [^\/>]*\/>/gi, + (tag, tagName) => `${tag.slice(0, tag.length - 3)}>` + ); } return actualHTML; diff --git a/packages/internal-test-helpers/lib/equal-tokens.js b/packages/internal-test-helpers/lib/equal-tokens.js index 9c8ec471a72..784c92c492f 100644 --- a/packages/internal-test-helpers/lib/equal-tokens.js +++ b/packages/internal-test-helpers/lib/equal-tokens.js @@ -18,15 +18,23 @@ function normalizeTokens(tokens) { tokens.forEach(token => { if (token.type === 'StartTag') { token.attributes = token.attributes.sort((a, b) => { - if (a[0] > b[0]) { return 1; } - if (a[0] < b[0]) { return -1; } + if (a[0] > b[0]) { + return 1; + } + if (a[0] < b[0]) { + return -1; + } return 0; }); } }); } -export default function equalTokens(actualContainer, expectedHTML, message = null) { +export default function equalTokens( + actualContainer, + expectedHTML, + message = null +) { let actual = generateTokens(actualContainer); let expected = generateTokens(expectedHTML); diff --git a/packages/internal-test-helpers/lib/index.js b/packages/internal-test-helpers/lib/index.js index 3194a17b4fe..85b2d338c3d 100644 --- a/packages/internal-test-helpers/lib/index.js +++ b/packages/internal-test-helpers/lib/index.js @@ -7,30 +7,27 @@ export { default as moduleFor } from './module-for'; export { default as strip } from './strip'; export { default as applyMixins } from './apply-mixins'; export { default as getTextOf } from './get-text-of'; -export { - equalsElement, - classes, - styles, - regex -} from './matchers'; -export { - runAppend, - runDestroy -} from './run'; -export { - testBoth, - testWithDefault -} from './test-groups'; +export { equalsElement, classes, styles, regex } from './matchers'; +export { runAppend, runDestroy } from './run'; +export { testBoth, testWithDefault } from './test-groups'; export { default as AbstractTestCase } from './test-cases/abstract'; -export { default as AbstractApplicationTestCase } from './test-cases/abstract-application'; +export { + default as AbstractApplicationTestCase +} from './test-cases/abstract-application'; export { default as ApplicationTestCase } from './test-cases/application'; export { default as QueryParamTestCase } from './test-cases/query-param'; -export { default as AbstractRenderingTestCase } from './test-cases/abstract-rendering'; +export { + default as AbstractRenderingTestCase +} from './test-cases/abstract-rendering'; export { default as RenderingTestCase } from './test-cases/rendering'; export { default as RouterTestCase } from './test-cases/router'; -export { default as AutobootApplicationTestCase } from './test-cases/autoboot-application'; -export { default as DefaultResolverApplicationTestCase } from './test-cases/default-resolver-application'; +export { + default as AutobootApplicationTestCase +} from './test-cases/autoboot-application'; +export { + default as DefaultResolverApplicationTestCase +} from './test-cases/default-resolver-application'; export { default as TestResolver, diff --git a/packages/internal-test-helpers/lib/matchers.js b/packages/internal-test-helpers/lib/matchers.js index bee01a7354d..d484e100ed0 100644 --- a/packages/internal-test-helpers/lib/matchers.js +++ b/packages/internal-test-helpers/lib/matchers.js @@ -47,7 +47,18 @@ export function classes(expected) { match(actual) { actual = actual.trim(); - return actual && (expected.split(/\s+/).sort().join(' ') === actual.trim().split(/\s+/).sort().join(' ')); + return ( + actual && + expected + .split(/\s+/) + .sort() + .join(' ') === + actual + .trim() + .split(/\s+/) + .sort() + .join(' ') + ); }, expected() { @@ -71,8 +82,18 @@ export function styles(expected) { actual = actual.trim(); return ( - expected.split(';').map(s => s.trim()).filter(s => s).sort().join('; ') === - actual.split(';').map(s => s.trim()).filter(s => s).sort().join('; ') + expected + .split(';') + .map(s => s.trim()) + .filter(s => s) + .sort() + .join('; ') === + actual + .split(';') + .map(s => s.trim()) + .filter(s => s) + .sort() + .join('; ') ); }, diff --git a/packages/internal-test-helpers/lib/module-for.js b/packages/internal-test-helpers/lib/module-for.js index 9256c2a00fc..86908acf1cd 100644 --- a/packages/internal-test-helpers/lib/module-for.js +++ b/packages/internal-test-helpers/lib/module-for.js @@ -72,7 +72,9 @@ export default function moduleFor(description, TestClass, ...mixins) { let features = match[1].replace(/ /g, '').split(','); if (shouldTest(features)) { - QUnit.test(name.slice(match[0].length), assert => context[name](assert)); + QUnit.test(name.slice(match[0].length), assert => + context[name](assert) + ); } } } diff --git a/packages/internal-test-helpers/lib/strip.js b/packages/internal-test-helpers/lib/strip.js index e13f8937dbe..3425a2acf05 100644 --- a/packages/internal-test-helpers/lib/strip.js +++ b/packages/internal-test-helpers/lib/strip.js @@ -1,7 +1,12 @@ export default function strip([...strings], ...values) { - let str = strings.map((string, index) => { - let interpolated = values[index]; - return string + (interpolated !== undefined ? interpolated : ''); - }).join(''); - return str.split('\n').map(s => s.trim()).join(''); + let str = strings + .map((string, index) => { + let interpolated = values[index]; + return string + (interpolated !== undefined ? interpolated : ''); + }) + .join(''); + return str + .split('\n') + .map(s => s.trim()) + .join(''); } diff --git a/packages/internal-test-helpers/lib/system/synthetic-events.js b/packages/internal-test-helpers/lib/system/synthetic-events.js index b8f7dafbcf2..0f5d10bdf2b 100644 --- a/packages/internal-test-helpers/lib/system/synthetic-events.js +++ b/packages/internal-test-helpers/lib/system/synthetic-events.js @@ -13,7 +13,7 @@ const MOUSE_EVENT_TYPES = [ 'mouseleave', 'mousemove', 'mouseout', - 'mouseover', + 'mouseover' ]; export const elMatches = @@ -109,7 +109,7 @@ export function fireEvent(element, type, options = {}) { screenX: x + 5, screenY: y + 95, clientX: x, - clientY: y, + clientY: y }; event = buildMouseEvent(type, merge(simulatedCoordinates, options)); } else { diff --git a/packages/internal-test-helpers/lib/test-cases/abstract-application.js b/packages/internal-test-helpers/lib/test-cases/abstract-application.js index 3005e6fc6fa..6dd99393a0c 100644 --- a/packages/internal-test-helpers/lib/test-cases/abstract-application.js +++ b/packages/internal-test-helpers/lib/test-cases/abstract-application.js @@ -4,18 +4,18 @@ import AbstractTestCase from './abstract'; import { runDestroy } from '../run'; export default class AbstractApplicationTestCase extends AbstractTestCase { - _ensureInstance(bootOptions) { if (this._applicationInstancePromise) { return this._applicationInstancePromise; } - return this._applicationInstancePromise = this.runTask(() => this.application.boot()) - .then((app) => { - this.applicationInstance = app.buildInstance(); + return (this._applicationInstancePromise = this.runTask(() => + this.application.boot() + ).then(app => { + this.applicationInstance = app.buildInstance(); - return this.applicationInstance.boot(bootOptions); - }); + return this.applicationInstance.boot(bootOptions); + })); } visit(url, options) { @@ -23,7 +23,9 @@ export default class AbstractApplicationTestCase extends AbstractTestCase { // the promise returned by `ApplicationInstance.protoype.visit` does **not** // currently guarantee rendering is completed return this.runTask(() => { - return this._ensureInstance(options).then(instance => instance.visit(url)); + return this._ensureInstance(options).then(instance => + instance.visit(url) + ); }); } @@ -31,9 +33,11 @@ export default class AbstractApplicationTestCase extends AbstractTestCase { if (this._element) { return this._element; } else if (ENV._APPLICATION_TEMPLATE_WRAPPER) { - return this._element = document.querySelector('#qunit-fixture > div.ember-view'); + return (this._element = document.querySelector( + '#qunit-fixture > div.ember-view' + )); } else { - return this._element = document.querySelector('#qunit-fixture'); + return (this._element = document.querySelector('#qunit-fixture')); } } @@ -67,5 +71,4 @@ export default class AbstractApplicationTestCase extends AbstractTestCase { compile(/* string, options */) { return compile(...arguments); } - } diff --git a/packages/internal-test-helpers/lib/test-cases/abstract-rendering.js b/packages/internal-test-helpers/lib/test-cases/abstract-rendering.js index c9357c14bfe..0d6c839f19e 100644 --- a/packages/internal-test-helpers/lib/test-cases/abstract-rendering.js +++ b/packages/internal-test-helpers/lib/test-cases/abstract-rendering.js @@ -1,7 +1,7 @@ import { assign } from 'ember-utils'; import { compile } from 'ember-template-compiler'; import { EventDispatcher } from 'ember-views'; -import { helper, Helper, Component, _resetRenderers} from 'ember-glimmer'; +import { helper, Helper, Component, _resetRenderers } from 'ember-glimmer'; import { ModuleBasedResolver } from '../test-resolver'; import AbstractTestCase from './abstract'; @@ -15,20 +15,26 @@ export default class AbstractRenderingTestCase extends AbstractTestCase { super(); let bootOptions = this.getBootOptions(); - let owner = this.owner = buildOwner({ + let owner = (this.owner = buildOwner({ ownerOptions: this.getOwnerOptions(), resolver: this.getResolver(), - bootOptions, - }); + bootOptions + })); this.renderer = this.owner.lookup('renderer:-dom'); this.element = document.querySelector('#qunit-fixture'); this.component = null; owner.register('event_dispatcher:main', EventDispatcher); - owner.inject('event_dispatcher:main', '_viewRegistry', '-view-registry:main'); + owner.inject( + 'event_dispatcher:main', + '_viewRegistry', + '-view-registry:main' + ); if (!bootOptions || bootOptions.isInteractive !== false) { - owner.lookup('event_dispatcher:main').setup(this.getCustomDispatcherEvents(), this.element); + owner + .lookup('event_dispatcher:main') + .setup(this.getCustomDispatcherEvents(), this.element); } } @@ -40,8 +46,8 @@ export default class AbstractRenderingTestCase extends AbstractTestCase { return {}; } - getOwnerOptions() { } - getBootOptions() { } + getOwnerOptions() {} + getBootOptions() {} get resolver() { return this.owner.__registry__.fallback.resolver; @@ -57,13 +63,19 @@ export default class AbstractRenderingTestCase extends AbstractTestCase { addTemplate(templateName, templateString) { if (typeof templateName === 'string') { - this.resolver.add(`template:${templateName}`, this.compile(templateString, { - moduleName: templateName - })); + this.resolver.add( + `template:${templateName}`, + this.compile(templateString, { + moduleName: templateName + }) + ); } else { - this.resolver.add(templateName, this.compile(templateString, { - moduleName: templateName.moduleName - })); + this.resolver.add( + templateName, + this.compile(templateString, { + moduleName: templateName.moduleName + }) + ); } } @@ -73,9 +85,12 @@ export default class AbstractRenderingTestCase extends AbstractTestCase { } if (typeof template === 'string') { - this.resolver.add(`template:components/${name}`, this.compile(template, { - moduleName: `components/${name}` - })); + this.resolver.add( + `template:components/${name}`, + this.compile(template, { + moduleName: `components/${name}` + }) + ); } } @@ -99,9 +114,12 @@ export default class AbstractRenderingTestCase extends AbstractTestCase { render(templateStr, context = {}) { let { owner } = this; - owner.register('template:-top-level', this.compile(templateStr, { - moduleName: '-top-level' - })); + owner.register( + 'template:-top-level', + this.compile(templateStr, { + moduleName: '-top-level' + }) + ); let attrs = assign({}, context, { tagName: '', @@ -134,7 +152,10 @@ export default class AbstractRenderingTestCase extends AbstractTestCase { registerPartial(name, template) { let owner = this.env.owner || this.owner; if (typeof template === 'string') { - owner.register(`template:${name}`, this.compile(template, { moduleName: `my-app/templates/-${name}.hbs` })); + owner.register( + `template:${name}`, + this.compile(template, { moduleName: `my-app/templates/-${name}.hbs` }) + ); } } @@ -146,18 +167,24 @@ export default class AbstractRenderingTestCase extends AbstractTestCase { } if (typeof template === 'string') { - owner.register(`template:components/${name}`, this.compile(template, { - moduleName: `my-app/templates/components/${name}.hbs` - })); + owner.register( + `template:components/${name}`, + this.compile(template, { + moduleName: `my-app/templates/components/${name}.hbs` + }) + ); } } registerTemplate(name, template) { let { owner } = this; if (typeof template === 'string') { - owner.register(`template:${name}`, this.compile(template, { - moduleName: `my-app/templates/${name}.hbs` - })); + owner.register( + `template:${name}`, + this.compile(template, { + moduleName: `my-app/templates/${name}.hbs` + }) + ); } else { throw new Error(`Registered template "${name}" must be a string`); } diff --git a/packages/internal-test-helpers/lib/test-cases/abstract.js b/packages/internal-test-helpers/lib/test-cases/abstract.js index 7cb64d48bdf..f82009793ba 100644 --- a/packages/internal-test-helpers/lib/test-cases/abstract.js +++ b/packages/internal-test-helpers/lib/test-cases/abstract.js @@ -6,11 +6,7 @@ import { run, next, hasScheduledTimers, getCurrentRunLoop } from 'ember-metal'; import NodeQuery from './node-query'; import equalInnerHTML from '../equal-inner-html'; import equalTokens from '../equal-tokens'; -import { - equalsElement, - regex, - classes -} from '../matchers'; +import { equalsElement, regex, classes } from '../matchers'; import { Promise } from 'rsvp'; const TextNode = window.Text; @@ -49,7 +45,7 @@ export default class AbstractTestCase { } runTaskNext() { - return new Promise((resolve) => { + return new Promise(resolve => { return next(resolve); }); } @@ -134,7 +130,9 @@ export default class AbstractTestCase { // Every 5ms, poll for the async thing to have finished let watcher = setInterval(() => { // If there are scheduled timers or we are inside of a run loop, keep polling - if (hasScheduledTimers() || getCurrentRunLoop()) { return; } + if (hasScheduledTimers() || getCurrentRunLoop()) { + return; + } // Stop polling clearInterval(watcher); @@ -150,7 +148,7 @@ export default class AbstractTestCase { } takeSnapshot() { - let snapshot = this.snapshot = []; + let snapshot = (this.snapshot = []); let node = this.element.firstChild; @@ -166,7 +164,11 @@ export default class AbstractTestCase { } assertText(text) { - this.assert.strictEqual(this.textValue(), text, `#qunit-fixture content should be: \`${text}\``); + this.assert.strictEqual( + this.textValue(), + text, + `#qunit-fixture content should be: \`${text}\`` + ); } assertInnerHTML(html) { @@ -174,10 +176,17 @@ export default class AbstractTestCase { } assertHTML(html) { - equalTokens(this.element, html, `#qunit-fixture content should be: \`${html}\``); + equalTokens( + this.element, + html, + `#qunit-fixture content should be: \`${html}\`` + ); } - assertElement(node, { ElementType = HTMLElement, tagName, attrs = null, content = null }) { + assertElement( + node, + { ElementType = HTMLElement, tagName, attrs = null, content = null } + ) { if (!(node instanceof ElementType)) { throw new Error(`Expecting a ${ElementType.name}, but got ${node}`); } @@ -185,8 +194,15 @@ export default class AbstractTestCase { equalsElement(this.assert, node, tagName, attrs, content); } - assertComponentElement(node, { ElementType = HTMLElement, tagName = 'div', attrs = null, content = null }) { - attrs = assign({}, { id: regex(/^ember\d*$/), class: classes('ember-view') }, attrs || {}); + assertComponentElement( + node, + { ElementType = HTMLElement, tagName = 'div', attrs = null, content = null } + ) { + attrs = assign( + {}, + { id: regex(/^ember\d*$/), class: classes('ember-view') }, + attrs || {} + ); this.assertElement(node, { ElementType, tagName, attrs, content }); } @@ -198,7 +214,11 @@ export default class AbstractTestCase { oldSnapshot = oldSnapshot || this.snapshot; newSnapshot = newSnapshot || this.takeSnapshot(); - this.assert.strictEqual(newSnapshot.length, oldSnapshot.length, 'Same number of nodes'); + this.assert.strictEqual( + newSnapshot.length, + oldSnapshot.length, + 'Same number of nodes' + ); for (let i = 0; i < oldSnapshot.length; i++) { this.assertSameNode(newSnapshot[i], oldSnapshot[i]); diff --git a/packages/internal-test-helpers/lib/test-cases/application.js b/packages/internal-test-helpers/lib/test-cases/application.js index 1d8c0e599b1..c14a53c8676 100644 --- a/packages/internal-test-helpers/lib/test-cases/application.js +++ b/packages/internal-test-helpers/lib/test-cases/application.js @@ -8,7 +8,9 @@ export default class ApplicationTestCase extends TestResolverApplicationTestCase super(); let { applicationOptions } = this; - this.application = this.runTask(() => this.createApplication(applicationOptions)); + this.application = this.runTask(() => + this.createApplication(applicationOptions) + ); this.resolver = applicationOptions.Resolver.lastInstance; @@ -17,7 +19,7 @@ export default class ApplicationTestCase extends TestResolverApplicationTestCase } } - createApplication(myOptions={}, MyApplication=Application) { + createApplication(myOptions = {}, MyApplication = Application) { return MyApplication.create(myOptions); } @@ -32,9 +34,8 @@ export default class ApplicationTestCase extends TestResolverApplicationTestCase } transitionTo() { - return this.runTask(() =>{ + return this.runTask(() => { return this.appRouter.transitionTo(...arguments); }); } - } diff --git a/packages/internal-test-helpers/lib/test-cases/autoboot-application.js b/packages/internal-test-helpers/lib/test-cases/autoboot-application.js index be6ed3b9540..9ff71784a74 100644 --- a/packages/internal-test-helpers/lib/test-cases/autoboot-application.js +++ b/packages/internal-test-helpers/lib/test-cases/autoboot-application.js @@ -4,10 +4,9 @@ import { assign } from 'ember-utils'; import { Router } from 'ember-routing'; export default class AutobootApplicationTestCase extends TestResolverApplicationTestCase { - - createApplication(options, MyApplication=Application) { + createApplication(options, MyApplication = Application) { let myOptions = assign(this.applicationOptions, options); - let application = this.application = MyApplication.create(myOptions); + let application = (this.application = MyApplication.create(myOptions)); this.resolver = myOptions.Resolver.lastInstance; if (this.resolver) { @@ -18,10 +17,9 @@ export default class AutobootApplicationTestCase extends TestResolverApplication } visit(url) { - return this.application.boot() - .then(() => { - return this.applicationInstance.visit(url); - }); + return this.application.boot().then(() => { + return this.applicationInstance.visit(url); + }); } get applicationInstance() { @@ -33,5 +31,4 @@ export default class AutobootApplicationTestCase extends TestResolverApplication return application.__deprecatedInstance__; } - } diff --git a/packages/internal-test-helpers/lib/test-cases/default-resolver-application.js b/packages/internal-test-helpers/lib/test-cases/default-resolver-application.js index a447c674b16..53382558a04 100644 --- a/packages/internal-test-helpers/lib/test-cases/default-resolver-application.js +++ b/packages/internal-test-helpers/lib/test-cases/default-resolver-application.js @@ -1,17 +1,15 @@ import AbstractApplicationTestCase from './abstract-application'; import { Resolver as DefaultResolver } from 'ember-application'; import { Application } from 'ember-application'; -import { - setTemplates, - setTemplate -} from 'ember-glimmer'; +import { setTemplates, setTemplate } from 'ember-glimmer'; import { assign } from 'ember-utils'; import { Router } from 'ember-routing'; export default class ApplicationTestCase extends AbstractApplicationTestCase { - createApplication() { - let application = this.application = Application.create(this.applicationOptions); + let application = (this.application = Application.create( + this.applicationOptions + )); application.Router = Router.extend(this.routerOptions); return application; } @@ -33,7 +31,7 @@ export default class ApplicationTestCase extends AbstractApplicationTestCase { } transitionTo() { - return this.runTask(() =>{ + return this.runTask(() => { return this.appRouter.transitionTo(...arguments); }); } @@ -43,6 +41,4 @@ export default class ApplicationTestCase extends AbstractApplicationTestCase { setTemplate(name, compiled); return compiled; } - - } diff --git a/packages/internal-test-helpers/lib/test-cases/node-query.js b/packages/internal-test-helpers/lib/test-cases/node-query.js index 225e5eaf277..c54c2d6405f 100644 --- a/packages/internal-test-helpers/lib/test-cases/node-query.js +++ b/packages/internal-test-helpers/lib/test-cases/node-query.js @@ -5,7 +5,10 @@ import { fireEvent, focus, matches } from '../system/synthetic-events'; export default class NodeQuery { static query(selector, context = document) { - assert(`Invalid second parameter to NodeQuery.query`, context && context instanceof Node); + assert( + `Invalid second parameter to NodeQuery.query`, + context && context instanceof Node + ); return new NodeQuery(toArray(context.querySelectorAll(selector))); } @@ -14,10 +17,13 @@ export default class NodeQuery { } constructor(nodes) { - assert('NodeQuery must be initialized with a literal array', Array.isArray(nodes)); + assert( + 'NodeQuery must be initialized with a literal array', + Array.isArray(nodes) + ); this.nodes = nodes; - for (let i=0; i node[name] = value); + this.nodes.forEach(node => (node[name] = value)); return this; } @@ -103,14 +109,18 @@ export default class NodeQuery { function assertSingle(nodeQuery) { if (nodeQuery.length !== 1) { - throw new Error(`attr(name) called on a NodeQuery with ${this.nodes.length} elements. Expected one element.`); + throw new Error( + `attr(name) called on a NodeQuery with ${ + this.nodes.length + } elements. Expected one element.` + ); } } function toArray(nodes) { let out = []; - for (let i=0; iHello {{#if hasExistence}}{{location}}{{/if}}\
    {{component 'foo-bar'}}
    \ -"); +" + ); this.component('root-component', { - location: "World", + location: 'World', hasExistence: true }); - this.template('components/foo-bar', "\ + this.template( + 'components/foo-bar', + '\

    The files are *inside* the computer?!

    \ -"); +' + ); return this.renderToHTML('/').then(function(html) { - assertHTMLMatches(assert, html, '

    Hello World

    The files are *inside* the computer?!

    '); + assertHTMLMatches( + assert, + html, + '

    Hello World

    The files are *inside* the computer?!

    ' + ); }); }); -QUnit.test("{{link-to}}", function(assert) { - this.template('application', "

    {{#link-to 'photos'}}Go to photos{{/link-to}}

    "); +QUnit.test('{{link-to}}', function(assert) { + this.template( + 'application', + "

    {{#link-to 'photos'}}Go to photos{{/link-to}}

    " + ); this.routes(function() { this.route('photos'); }); return this.renderToHTML('/').then(function(html) { - assertHTMLMatches(assert, html, ''); + assertHTMLMatches( + assert, + html, + '' + ); }); }); -QUnit.test("non-escaped content", function(assert) { +QUnit.test('non-escaped content', function(assert) { this.routes(function() { this.route('photos'); }); - this.template('application', "

    {{{title}}}

    "); + this.template('application', '

    {{{title}}}

    '); this.controller('application', { - title: "Hello world" + title: 'Hello world' }); return this.renderToHTML('/').then(function(html) { - assertHTMLMatches(assert, html, '

    Hello world

    '); + assertHTMLMatches( + assert, + html, + '

    Hello world

    ' + ); }); }); -QUnit.test("outlets", function(assert) { +QUnit.test('outlets', function(assert) { this.routes(function() { this.route('photos'); }); - this.template('application', "

    {{outlet}}

    "); - this.template('index', "index"); - this.template('photos', "photos"); + this.template('application', '

    {{outlet}}

    '); + this.template('index', 'index'); + this.template('photos', 'photos'); var promises = []; - promises.push(this.renderToHTML('/').then(function(html) { - assertHTMLMatches(assert, html, '

    index

    '); - })); - - promises.push(this.renderToHTML('/photos').then(function(html) { - assertHTMLMatches(assert, html, '

    photos

    '); - })); + promises.push( + this.renderToHTML('/').then(function(html) { + assertHTMLMatches( + assert, + html, + '

    index

    ' + ); + }) + ); + + promises.push( + this.renderToHTML('/photos').then(function(html) { + assertHTMLMatches( + assert, + html, + '

    photos

    ' + ); + }) + ); return this.all(promises); }); -QUnit.test("lifecycle hooks disabled", function(assert) { +QUnit.test('lifecycle hooks disabled', function(assert) { assert.expect(1); this.template('application', "{{my-component foo='bar'}}{{outlet}}"); this.component('my-component', { didReceiveAttrs() { - assert.ok(true, "should trigger didReceiveAttrs hook"); + assert.ok(true, 'should trigger didReceiveAttrs hook'); }, willRender() { - assert.ok(false, "should not trigger willRender hook"); + assert.ok(false, 'should not trigger willRender hook'); }, didRender() { - assert.ok(false, "should not trigger didRender hook"); + assert.ok(false, 'should not trigger didRender hook'); }, willInsertElement() { - assert.ok(false, "should not trigger willInsertElement hook"); + assert.ok(false, 'should not trigger willInsertElement hook'); }, didInsertElement() { - assert.ok(false, "should not trigger didInsertElement hook"); + assert.ok(false, 'should not trigger didInsertElement hook'); } }); return this.renderToHTML('/'); }); -QUnit.test("Should not attempt to render element modifiers GH#14220", function(assert) { +QUnit.test('Should not attempt to render element modifiers GH#14220', function( + assert +) { assert.expect(1); this.template('application', "
    "); - return this.renderToHTML('/') - .then(function(html) { - assertHTMLMatches(assert, html, '
    '); - }); + return this.renderToHTML('/').then(function(html) { + assertHTMLMatches( + assert, + html, + '
    ' + ); + }); }); diff --git a/tests/node/component-rendering-test.js b/tests/node/component-rendering-test.js index b81f7b3a4bd..e67031972e3 100644 --- a/tests/node/component-rendering-test.js +++ b/tests/node/component-rendering-test.js @@ -2,13 +2,13 @@ var componentModule = require('./helpers/component-module'); componentModule('Components can be rendered without a DOM dependency'); -QUnit.test("Simple component", function(assert) { +QUnit.test('Simple component', function(assert) { var html = this.render('

    Hello

    '); assert.ok(html.match(/

    Hello<\/h1>/)); }); -QUnit.test("Component with dynamic value", function(assert) { +QUnit.test('Component with dynamic value', function(assert) { this.set('location', 'World'); var html = this.render('

    Hello {{location}}

    '); @@ -16,14 +16,20 @@ QUnit.test("Component with dynamic value", function(assert) { assert.ok(html.match(/

    Hello World<\/h1>/)); }); -QUnit.test("Ensure undefined attributes requiring protocol sanitization do not error", function(assert) { - this.owner.register('component:fake-link', this.Ember.Component.extend({ - tagName: 'link', - attributeBindings: ['href', 'rel'], - rel: 'canonical' - })); - - var html = this.render('{{fake-link}}'); - - assert.ok(html.match(/rel="canonical"/)); -}); +QUnit.test( + 'Ensure undefined attributes requiring protocol sanitization do not error', + function(assert) { + this.owner.register( + 'component:fake-link', + this.Ember.Component.extend({ + tagName: 'link', + attributeBindings: ['href', 'rel'], + rel: 'canonical' + }) + ); + + var html = this.render('{{fake-link}}'); + + assert.ok(html.match(/rel="canonical"/)); + } +); diff --git a/tests/node/helpers/app-module.js b/tests/node/helpers/app-module.js index ba0db4e21f9..3714180f91a 100644 --- a/tests/node/helpers/app-module.js +++ b/tests/node/helpers/app-module.js @@ -61,7 +61,7 @@ var SimpleDOM = require('simple-dom'); module.exports = function(moduleName) { QUnit.module(moduleName, { beforeEach: function() { - var Ember = this.Ember = require(emberPath); + var Ember = (this.Ember = require(emberPath)); Ember.testing = true; @@ -138,8 +138,7 @@ function visit(url) { isBrowser: false, document: dom, rootElement: dom.body - }) - .catch(function(error) { + }).catch(function(error) { console.error(error.stack); }); } diff --git a/tests/node/helpers/build-owner.js b/tests/node/helpers/build-owner.js index b6763aada22..ebebe592a25 100644 --- a/tests/node/helpers/build-owner.js +++ b/tests/node/helpers/build-owner.js @@ -1,8 +1,15 @@ module.exports = function buildOwner(Ember, resolver) { - var Owner = Ember.Object.extend(Ember._RegistryProxyMixin, Ember._ContainerProxyMixin); + var Owner = Ember.Object.extend( + Ember._RegistryProxyMixin, + Ember._ContainerProxyMixin + ); var namespace = Ember.Object.create({ - Resolver: { create: function() { return resolver; } } + Resolver: { + create: function() { + return resolver; + } + } }); var fallbackRegistry = Ember.Application.buildRegistry(namespace); diff --git a/tests/node/helpers/component-module.js b/tests/node/helpers/component-module.js index f1a15575cf0..e5f44f39fce 100644 --- a/tests/node/helpers/component-module.js +++ b/tests/node/helpers/component-module.js @@ -29,7 +29,7 @@ module.exports = function(moduleName) { return this.Ember.HTMLBars.template(template); }; - var Ember = this.Ember = require(emberPath); + var Ember = (this.Ember = require(emberPath)); Ember.testing = true; this.run = Ember.run; @@ -62,7 +62,9 @@ function setupComponentTest() { module.element = new SimpleDOM.Document(); module.owner = buildOwner(this.Ember, { resolve: function() {} }); - module.owner.register('service:-document', new SimpleDOM.Document(), { instantiate: false }); + module.owner.register('service:-document', new SimpleDOM.Document(), { + instantiate: false + }); this._hasRendered = false; let OutletView = module.owner.factoryFor('view:-outlet'); @@ -75,10 +77,10 @@ function setupComponentTest() { outlet: 'main', name: 'application', controller: module, - template: OutletTemplate, + template: OutletTemplate }, - outlets: { } + outlets: {} }; templateId = 0; @@ -100,7 +102,7 @@ function render(_template) { var module = this; var template = this.compile(_template); - var templateFullName = 'template:-undertest-' + (++templateId); + var templateFullName = 'template:-undertest-' + ++templateId; this.owner.register(templateFullName, template); var stateToRender = { owner: this.owner, @@ -108,7 +110,7 @@ function render(_template) { outlet: 'main', name: 'index', controller: this, - template: this.owner.lookup(templateFullName), + template: this.owner.lookup(templateFullName) }; stateToRender.name = 'index'; diff --git a/tests/node/template-compiler-test.js b/tests/node/template-compiler-test.js index 35a74effda4..5773a4bdb83 100644 --- a/tests/node/template-compiler-test.js +++ b/tests/node/template-compiler-test.js @@ -20,26 +20,54 @@ module('ember-template-compiler.js', { }); test('can be required', function(assert) { - assert.ok(typeof templateCompiler.precompile === 'function', 'precompile function is present'); - assert.ok(typeof templateCompiler.compile === 'function', 'compile function is present'); + assert.ok( + typeof templateCompiler.precompile === 'function', + 'precompile function is present' + ); + assert.ok( + typeof templateCompiler.compile === 'function', + 'compile function is present' + ); }); test('can access _Ember.ENV (private API used by ember-cli-htmlbars)', function(assert) { - assert.equal(typeof templateCompiler._Ember.ENV, 'object', '_Ember.ENV is present'); - assert.notEqual(typeof templateCompiler._Ember.ENV, null, '_Ember.ENV is not null'); + assert.equal( + typeof templateCompiler._Ember.ENV, + 'object', + '_Ember.ENV is present' + ); + assert.notEqual( + typeof templateCompiler._Ember.ENV, + null, + '_Ember.ENV is not null' + ); }); test('can access _Ember.FEATURES (private API used by ember-cli-htmlbars)', function(assert) { - assert.equal(typeof templateCompiler._Ember.FEATURES, 'object', '_Ember.FEATURES is present'); - assert.notEqual(typeof templateCompiler._Ember.FEATURES, null, '_Ember.FEATURES is not null'); + assert.equal( + typeof templateCompiler._Ember.FEATURES, + 'object', + '_Ember.FEATURES is present' + ); + assert.notEqual( + typeof templateCompiler._Ember.FEATURES, + null, + '_Ember.FEATURES is not null' + ); }); test('can access _Ember.VERSION (private API used by ember-cli-htmlbars)', function(assert) { - assert.equal(typeof templateCompiler._Ember.VERSION, 'string', '_Ember.VERSION is present'); + assert.equal( + typeof templateCompiler._Ember.VERSION, + 'string', + '_Ember.VERSION is present' + ); }); test('can generate a template with a server side generated `id`', function(assert) { - var TemplateJSON = JSON.parse(templateCompiler.precompile('
    simple text
    ')); + var TemplateJSON = JSON.parse( + templateCompiler.precompile('
    simple text
    ') + ); assert.ok(TemplateJSON.id, 'an `id` was generated'); }); diff --git a/tests/node/visit-test.js b/tests/node/visit-test.js index 69ce1e6fe47..1d271becb93 100644 --- a/tests/node/visit-test.js +++ b/tests/node/visit-test.js @@ -3,7 +3,10 @@ var SimpleDOM = require('simple-dom'); var appModule = require('./helpers/app-module'); function assertHTMLMatches(assert, actualHTML, expectedHTML) { - assert.ok(actualHTML.match(expectedHTML), actualHTML + " matches " + expectedHTML); + assert.ok( + actualHTML.match(expectedHTML), + actualHTML + ' matches ' + expectedHTML + ); } function handleError(assert) { @@ -40,7 +43,7 @@ function assertFastbootResult(assert, expected) { }; } -appModule("Ember.Application - visit() Integration Tests"); +appModule('Ember.Application - visit() Integration Tests'); QUnit.test('FastBoot: basic', function(assert) { this.routes(function() { @@ -73,20 +76,25 @@ QUnit.test('FastBoot: basic', function(assert) { fastbootVisit(App, '/a').then( assertFastbootResult(assert, { url: '/a', - body: '

    Hello world

    \n

    Welcome to Page A

    ' + body: + '

    Hello world

    \n

    Welcome to Page A

    ' }), handleError(assert) ), fastbootVisit(App, '/b').then( assertFastbootResult(assert, { url: '/b', - body: '

    Hello world

    \n

    Page B

    ' + body: + '

    Hello world

    \n

    Page B

    ' }), handleError ) ]).then(function() { assert.ok(initCalled, 'Component#init should be called'); - assert.ok(!didInsertElementCalled, 'Component#didInsertElement should not be called'); + assert.ok( + !didInsertElementCalled, + 'Component#didInsertElement should not be called' + ); }); }); @@ -117,11 +125,17 @@ QUnit.test('FastBoot: redirect', function(assert) { return RSVP.all([ fastbootVisit(App, '/a').then( - assertFastbootResult(assert, { url: '/c', body: '

    Hello from C

    ' }), + assertFastbootResult(assert, { + url: '/c', + body: '

    Hello from C

    ' + }), handleError(assert) ), fastbootVisit(App, '/b').then( - assertFastbootResult(assert, { url: '/c', body: '

    Hello from C

    ' }), + assertFastbootResult(assert, { + url: '/c', + body: '

    Hello from C

    ' + }), handleError(assert) ) ]); @@ -139,7 +153,10 @@ QUnit.test('FastBoot: attributes are sanitized', function(assert) { return RSVP.all([ fastbootVisit(App, '/').then( - assertFastbootResult(assert, { url: '/', body: '' }), + assertFastbootResult(assert, { + url: '/', + body: '' + }), handleError(assert) ) ]); @@ -169,25 +186,24 @@ QUnit.test('FastBoot: route error', function(assert) { var App = this.createApplication(); return RSVP.all([ - fastbootVisit(App, '/a') - .then( - function(instance) { - assert.ok(false, 'It should not render'); - instance.destroy(); - }, - function(error) { - assert.equal(error.message, 'Error from A'); - } - ), - fastbootVisit(App, '/b').then( - function(instance) { - assert.ok(false, 'It should not render'); - instance.destroy(); - }, - function(error) { - assert.equal(error.message, 'Error from B'); - } - ) + fastbootVisit(App, '/a').then( + function(instance) { + assert.ok(false, 'It should not render'); + instance.destroy(); + }, + function(error) { + assert.equal(error.message, 'Error from A'); + } + ), + fastbootVisit(App, '/b').then( + function(instance) { + assert.ok(false, 'It should not render'); + instance.destroy(); + }, + function(error) { + assert.equal(error.message, 'Error from B'); + } + ) ]); }); @@ -208,11 +224,13 @@ QUnit.test('FastBoot: route error template', function(assert) { var App = this.createApplication(); return RSVP.all([ - fastbootVisit(App, '/a') - .then( - assertFastbootResult(assert, { url: '/a', body: '

    Error template rendered!

    ' }), - handleError(assert) - ), + fastbootVisit(App, '/a').then( + assertFastbootResult(assert, { + url: '/a', + body: '

    Error template rendered!

    ' + }), + handleError(assert) + ) ]); }); @@ -299,7 +317,11 @@ QUnit.test('Resource-discovery setup', function(assert) { function(instance) { try { var viewRegistry = instance.lookup('-view-registry:main'); - assert.strictEqual(Object.keys(viewRegistry).length, 0, 'did not create any views'); + assert.strictEqual( + Object.keys(viewRegistry).length, + 0, + 'did not create any views' + ); var networkService = instance.lookup('service:network'); assert.deepEqual(networkService.get('requests'), resources); @@ -318,12 +340,19 @@ QUnit.test('Resource-discovery setup', function(assert) { assertResources('/d', ['/d', '/e']), assertResources('/e', ['/e']) ]).then(function() { - assert.strictEqual(xFooInstances, 0, 'it should not create any x-foo components'); + assert.strictEqual( + xFooInstances, + 0, + 'it should not create any x-foo components' + ); }); }); QUnit.test('FastBoot: tagless components can render', function(assert) { - this.template('application', "
    {{my-component}}
    "); + this.template( + 'application', + "
    {{my-component}}
    " + ); this.component('my-component', { tagName: '' }); this.template('components/my-component', '

    hello world

    '); @@ -331,7 +360,10 @@ QUnit.test('FastBoot: tagless components can render', function(assert) { return RSVP.all([ fastbootVisit(App, '/').then( - assertFastbootResult(assert, { url: '/', body: /

    hello world<\/h1><\/div>/ }), + assertFastbootResult(assert, { + url: '/', + body: /

    hello world<\/h1><\/div>/ + }), handleError(assert) ) ]); diff --git a/yarn.lock b/yarn.lock index 9da147cc5ab..f814816077f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2777,6 +2777,12 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.0, escape-string-regexp@^1 version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" +eslint-config-prettier@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-2.9.0.tgz#5ecd65174d486c22dff389fe036febf502d468a3" + dependencies: + get-stdin "^5.0.1" + eslint-plugin-ember-internal@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/eslint-plugin-ember-internal/-/eslint-plugin-ember-internal-1.1.1.tgz#5327f709799eac010bfcf0dd1be8d0acbc917d34" @@ -2793,6 +2799,13 @@ eslint-plugin-node@^6.0.1: resolve "^1.3.3" semver "^5.4.1" +eslint-plugin-prettier@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-2.6.0.tgz#33e4e228bdb06142d03c560ce04ec23f6c767dd7" + dependencies: + fast-diff "^1.1.1" + jest-docblock "^21.0.0" + eslint-scope@^3.7.1: version "3.7.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" @@ -3128,6 +3141,10 @@ fast-deep-equal@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" +fast-diff@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.1.2.tgz#4b62c42b8e03de3f848460b639079920695d0154" + fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" @@ -3474,6 +3491,10 @@ get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" +get-stdin@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" + get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" @@ -4272,6 +4293,10 @@ istextorbinary@2.1.0: editions "^1.1.1" textextensions "1 || 2" +jest-docblock@^21.0.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414" + jmespath@0.15.0: version "0.15.0" resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" @@ -5635,6 +5660,10 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" +prettier@1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.11.1.tgz#61e43fc4cd44e68f2b0dfc2c38cd4bb0fccdcc75" + pretty-ms@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-3.1.0.tgz#e9cac9c76bf6ee52fe942dd9c6c4213153b12881"