From c7cdf0aebe2b012da40941515860ff4e1ddb512b Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Tue, 7 Apr 2015 17:22:06 -0400 Subject: [PATCH] support integration-mode component tests --- lib/ember-test-helpers.js | 4 +- lib/ember-test-helpers/isolated-container.js | 14 ++- .../test-module-for-component.js | 112 +++++++++++++++++- .../test-module-for-integration.js | 89 -------------- lib/ember-test-helpers/test-module.js | 7 +- tests/test-module-for-component-test.js | 3 + tests/test-module-for-integration-test.js | 25 +++- 7 files changed, 150 insertions(+), 104 deletions(-) delete mode 100644 lib/ember-test-helpers/test-module-for-integration.js diff --git a/lib/ember-test-helpers.js b/lib/ember-test-helpers.js index 8f8409f9d..d172b7d5c 100644 --- a/lib/ember-test-helpers.js +++ b/lib/ember-test-helpers.js @@ -1,9 +1,8 @@ import Ember from 'ember'; -import isolatedContainer from 'ember-test-helpers/isolated-container'; +import { isolatedContainer } from 'ember-test-helpers/isolated-container'; import TestModule from 'ember-test-helpers/test-module'; import TestModuleForComponent from 'ember-test-helpers/test-module-for-component'; import TestModuleForModel from 'ember-test-helpers/test-module-for-model'; -import TestModuleForIntegration from 'ember-test-helpers/test-module-for-integration'; import { getContext, setContext } from 'ember-test-helpers/test-context'; import { setResolver } from 'ember-test-helpers/test-resolver'; @@ -14,7 +13,6 @@ export { TestModule, TestModuleForComponent, TestModuleForModel, - TestModuleForIntegration, getContext, setContext, setResolver diff --git a/lib/ember-test-helpers/isolated-container.js b/lib/ember-test-helpers/isolated-container.js index 2effd510d..8cf2f177f 100644 --- a/lib/ember-test-helpers/isolated-container.js +++ b/lib/ember-test-helpers/isolated-container.js @@ -27,16 +27,17 @@ function exposeRegistryMethodsWithoutDeprecations(container) { } } -export default function isolatedContainer(fullNames) { +export function isolatedRegistry(fullNames) { var resolver = getResolver(); var container; + var registry; var normalize = function(fullName) { return resolver.normalize(fullName); }; if (Ember.Registry) { - var registry = new Ember.Registry(); + registry = new Ember.Registry(); registry.normalizeFullName = normalize; container = registry.container(); @@ -83,5 +84,12 @@ export default function isolatedContainer(fullNames) { var normalizedFullName = resolver.normalize(fullName); container.register(fullName, resolver.resolve(normalizedFullName)); } - return container; + return { + container: container, + registry: registry + }; +} + +export function isolatedContainer(fullNames) { + return isolatedRegistry(fullNames).container; } diff --git a/lib/ember-test-helpers/test-module-for-component.js b/lib/ember-test-helpers/test-module-for-component.js index 9b102fa96..21156b18d 100644 --- a/lib/ember-test-helpers/test-module-for-component.js +++ b/lib/ember-test-helpers/test-module-for-component.js @@ -4,14 +4,45 @@ import { getResolver } from './test-resolver'; export default TestModule.extend({ init: function(componentName, description, callbacks) { + // Allow `description` to be omitted + if (!callbacks && typeof description === 'object') { + callbacks = description || {}; + description = null; + } + this.componentName = componentName; - this._super.call(this, 'component:' + componentName, description, callbacks); + if (callbacks.needs || callbacks.unit || callbacks.integration === false) { + this.isUnitTest = true; + } else if (callbacks.integration) { + this.isUnitTest = false; + } else { + Ember.deprecate("the component:" + componentName + " test module is implicitly running in unit test mode, which will change to integration test mode by default in an upcoming version of ember-test-helpers. Add `unit: true` or a `needs:[]` list to explicitly opt in to unit test mode."); + this.isUnitTest = true; + } + + if (!this.isUnitTest) { + callbacks.integration = true; + } - this.setupSteps.push(this.setupComponent); + if (description) { + this._super.call(this, 'component:' + componentName, description, callbacks); + } else { + this._super.call(this, 'component:' + componentName, callbacks); + } + + if (this.isUnitTest) { + this.setupSteps.push(this.setupComponentUnitTest); + } else { + this.callbacks.subject = function() { + throw new Error("component integration tests do not support `subject()`."); + }; + this.setupSteps.push(this.setupComponentIntegrationTest); + this.teardownSteps.push(this.teardownComponent); + } }, - setupComponent: function() { + setupComponentUnitTest: function() { var _this = this; var resolver = getResolver(); var container = this.container; @@ -55,5 +86,80 @@ export default TestModule.extend({ return subject.$.apply(subject, arguments); }; + }, + + setupComponentIntegrationTest: function() { + var self = this; + var context = this.context; + context.dispatcher = Ember.EventDispatcher.create(); + context.dispatcher.setup({}, '#ember-testing'); + this.actionHooks = {}; + + context.render = function(template) { + if (!template) { + throw new Error("in a component integration test you must pass a template to `render()`"); + } + if (Ember.isArray(template)) { + template = template.join(''); + } + if (typeof template === 'string') { + template = Ember.Handlebars.compile(template); + } + self.component = Ember.View.create({ + context: context, + controller: self, + template: template, + container: self.container + }); + Ember.run(function() { + self.component.appendTo('#ember-testing'); + }); + }; + + context.$ = function() { + return self.component.$.apply(self.component, arguments); + }; + + context.set = function(key, value) { + Ember.run(function() { + Ember.set(context, key, value); + }); + }; + + context.get = function(key) { + return Ember.get(context, key); + }; + + context.on = function(actionName, handler) { + self.actionHooks[actionName] = handler; + }; + + }, + + setupContext: function() { + this._super.call(this); + if (!this.isUnitTest) { + this.context.factory = function() {}; + } + }, + + + send: function(actionName) { + var hook = this.actionHooks[actionName]; + if (!hook) { + throw new Error("integration testing template received unexpected action " + actionName); + } + hook.apply(this, Array.prototype.slice.call(arguments, 1)); + }, + + teardownComponent: function() { + var component = this.component; + if (component) { + Ember.run(function() { + component.destroy(); + }); + } } + + }); diff --git a/lib/ember-test-helpers/test-module-for-integration.js b/lib/ember-test-helpers/test-module-for-integration.js deleted file mode 100644 index 153752484..000000000 --- a/lib/ember-test-helpers/test-module-for-integration.js +++ /dev/null @@ -1,89 +0,0 @@ -import Ember from 'ember'; -import TestModule from './test-module'; -import { getResolver } from './test-resolver'; -import { getContext, setContext } from './test-context'; - -export default TestModule.extend({ - - isIntegration: true, - - init: function(name, description, callbacks) { - this._super.call(this, name, description, callbacks); - this.setupSteps.push(this.setupIntegrationHelpers); - this.teardownSteps.push(this.teardownView); - }, - - setupIntegrationHelpers: function() { - var self = this; - var context = this.context; - context.dispatcher = Ember.EventDispatcher.create(); - context.dispatcher.setup({}, '#ember-testing'); - this.actionHooks = {}; - - context.render = function(template) { - if (Ember.isArray(template)) { - template = template.join(''); - } - if (typeof template === 'string') { - template = Ember.Handlebars.compile(template); - } - self.view = Ember.View.create({ - context: context, - controller: self, - template: template, - container: self.container - }); - Ember.run(function() { - self.view.appendTo('#ember-testing'); - }); - }; - - context.$ = function() { - return self.view.$.apply(self.view, arguments); - }; - - context.set = function(key, value) { - Ember.run(function() { - Ember.set(context, key, value); - }); - }; - - context.get = function(key) { - return Ember.get(context, key); - }; - - context.on = function(actionName, handler) { - self.actionHooks[actionName] = handler; - }; - - }, - - setupContext: function() { - - setContext({ - container: this.container, - factory: function() {}, - dispatcher: null - }); - - this.context = getContext(); - }, - - send: function(actionName) { - var hook = this.actionHooks[actionName]; - if (!hook) { - throw new Error("integration testing template received unexpected action " + actionName); - } - hook.apply(this, Array.prototype.slice.call(arguments, 1)); - }, - - teardownView: function() { - var view = this.view; - if (view) { - Ember.run(function() { - view.destroy(); - }); - } - } - -}); diff --git a/lib/ember-test-helpers/test-module.js b/lib/ember-test-helpers/test-module.js index e42210150..eb957de33 100644 --- a/lib/ember-test-helpers/test-module.js +++ b/lib/ember-test-helpers/test-module.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import isolatedContainer from './isolated-container'; +import { isolatedRegistry } from './isolated-container'; import { getContext, setContext } from './test-context'; import { Klass } from 'klassy'; import { getResolver } from './test-resolver'; @@ -133,6 +133,7 @@ export default Klass.extend({ setContext({ container: this.container, + registry: this.registry, factory: factory, dispatcher: null }); @@ -213,7 +214,9 @@ export default Klass.extend({ _setupIsolatedContainer: function() { - this.container = isolatedContainer(this.needs); + var isolated = isolatedRegistry(this.needs); + this.container = isolated.container; + this.registry = isolated.registry; }, _setupIntegratedContainer: function() { diff --git a/tests/test-module-for-component-test.js b/tests/test-module-for-component-test.js index dc0d4d93e..7bc8f4894 100644 --- a/tests/test-module-for-component-test.js +++ b/tests/test-module-for-component-test.js @@ -186,6 +186,7 @@ test('clears out views from test to test', function() { /////////////////////////////////////////////////////////////////////////////// moduleForComponent('pretty-color', { + unit: true, beforeSetup: function() { setupRegistry(); } @@ -215,6 +216,7 @@ test("$", function(){ }); moduleForComponent('pretty-color', 'component:pretty-color -- this.render in setup', { + unit: true, beforeSetup: function() { setupRegistry(); }, @@ -236,6 +238,7 @@ test("className", function(){ }); moduleForComponent('boring-color', 'component:boring-color -- still in DOM in willDestroyElement', { + unit: true, beforeSetup: function() { setupRegistry(); }, diff --git a/tests/test-module-for-integration-test.js b/tests/test-module-for-integration-test.js index 25a0d2f5e..17e192528 100644 --- a/tests/test-module-for-integration-test.js +++ b/tests/test-module-for-integration-test.js @@ -1,15 +1,17 @@ import Ember from 'ember'; -import { TestModuleForIntegration } from 'ember-test-helpers'; +import { TestModuleForComponent } from 'ember-test-helpers'; import test from 'tests/test-support/qunit-test'; import qunitModuleFor from 'tests/test-support/qunit-module-for'; import { setResolverRegistry } from 'tests/test-support/resolver'; -function moduleForIntegration(name, description, callbacks) { - var module = new TestModuleForIntegration(name, description, callbacks); +function moduleForComponent(name, description, callbacks) { + var module = new TestModuleForComponent(name, description, callbacks); qunitModuleFor(module); } -moduleForIntegration('Better Integration Tests', { + +moduleForComponent('Component Integration Tests', { + integration: true, beforeSetup: function() { setResolverRegistry({ 'template:components/my-component': Ember.Handlebars.compile( @@ -24,6 +26,21 @@ test('it can render a template', function() { equal(this.$('span').text(), 'Hello'); }); +test('it complains if you try to use bare render', function() { + var self = this; + throws(function() { + self.render(); + }, /in a component integration test you must pass a template to `render\(\)`/); +}); + +test('it complains if you try to use subject()', function() { + var self = this; + throws(function() { + self.subject(); + }, /component integration tests do not support `subject\(\)`\./); +}); + + test('it can access the full container', function() { this.set('myColor', 'red'); this.render('{{my-component name=myColor}}');