├── .gitignore ├── .travis.yml ├── .npmignore ├── lib ├── test-context.js ├── test-resolver.js ├── test.js ├── isolated-container.js ├── main.js ├── module-for-model.js ├── module-for-component.js └── module-for.js ├── dist ├── cjs │ ├── test-context.js │ ├── test-resolver.js │ ├── test.js │ ├── isolated-container.js │ ├── module-for-model.js │ ├── main.js │ ├── module-for-component.js │ └── module-for.js ├── amd │ ├── test-context.js │ ├── test-resolver.js │ ├── isolated-container.js │ ├── test.js │ ├── module-for-model.js │ ├── main.js │ ├── module-for-component.js │ └── module-for.js ├── globals │ └── main.js └── named-amd │ └── main.js ├── test ├── support │ └── setup.js └── main.spec.js ├── Brocfile.js ├── bower.json ├── karma.conf.js ├── package.json ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | tmp 2 | node_modules 3 | bower_components 4 | 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.11" 4 | - "0.10" 5 | before_script: 6 | - export DISPLAY=:99.0 7 | - sh -e /etc/init.d/xvfb start 8 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | bower_components 2 | dist/amd 3 | dist/named-amd 4 | dist/globals 5 | lib 6 | test 7 | .travis.yml 8 | bower.json 9 | Brocfile.js 10 | karma.conf.js 11 | tmp 12 | -------------------------------------------------------------------------------- /lib/test-context.js: -------------------------------------------------------------------------------- 1 | var __test_context__; 2 | 3 | export function set(context) { 4 | __test_context__ = context; 5 | } 6 | 7 | export function get() { 8 | return __test_context__; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /dist/cjs/test-context.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __test_context__; 3 | 4 | function set(context) { 5 | __test_context__ = context; 6 | } 7 | 8 | exports.set = set;function get() { 9 | return __test_context__; 10 | } 11 | 12 | exports.get = get; -------------------------------------------------------------------------------- /test/support/setup.js: -------------------------------------------------------------------------------- 1 | String.prototype.compile = function() { 2 | return Ember.Handlebars.compile(this); 3 | }; 4 | 5 | Array.prototype.compile = function() { 6 | return Ember.Handlebars.compile(this.join('\n')); 7 | }; 8 | 9 | document.write('
'); 10 | -------------------------------------------------------------------------------- /lib/test-resolver.js: -------------------------------------------------------------------------------- 1 | var __resolver__; 2 | 3 | export function set(resolver) { 4 | __resolver__ = resolver; 5 | } 6 | 7 | export function get() { 8 | if (__resolver__ == null) throw new Error('you must set a resolver with `testResolver.set(resolver)`'); 9 | return __resolver__; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /Brocfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(broccoli) { 2 | return require('broccoli-dist-es6-module')(broccoli.makeTree('lib'), { 3 | global: 'emq', 4 | packageName: 'ember-qunit', 5 | main: 'main', 6 | shim: { 7 | 'ember': 'Ember', 8 | 'qunit': 'QUnit' 9 | } 10 | }); 11 | }; 12 | 13 | -------------------------------------------------------------------------------- /dist/cjs/test-resolver.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __resolver__; 3 | 4 | function set(resolver) { 5 | __resolver__ = resolver; 6 | } 7 | 8 | exports.set = set;function get() { 9 | if (__resolver__ == null) throw new Error('you must set a resolver with `testResolver.set(resolver)`'); 10 | return __resolver__; 11 | } 12 | 13 | exports.get = get; -------------------------------------------------------------------------------- /dist/amd/test-context.js: -------------------------------------------------------------------------------- 1 | define( 2 | ["exports"], 3 | function(__exports__) { 4 | "use strict"; 5 | var __test_context__; 6 | 7 | function set(context) { 8 | __test_context__ = context; 9 | } 10 | 11 | __exports__.set = set;function get() { 12 | return __test_context__; 13 | } 14 | 15 | __exports__.get = get; 16 | }); -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ember-qunit", 3 | "version": "0.1.6", 4 | "authors": [ 5 | "Stefan Penner", 6 | "Ryan Florence" 7 | ], 8 | "license": "MIT", 9 | "ignore": [ 10 | "**/.*", 11 | "node_modules", 12 | "bower_components", 13 | "test" 14 | ], 15 | "dependencies": { 16 | "ember": "^1.3.0", 17 | "ember-data": "~1.0.0-beta.7" 18 | } 19 | } -------------------------------------------------------------------------------- /dist/amd/test-resolver.js: -------------------------------------------------------------------------------- 1 | define( 2 | ["exports"], 3 | function(__exports__) { 4 | "use strict"; 5 | var __resolver__; 6 | 7 | function set(resolver) { 8 | __resolver__ = resolver; 9 | } 10 | 11 | __exports__.set = set;function get() { 12 | if (__resolver__ == null) throw new Error('you must set a resolver with `testResolver.set(resolver)`'); 13 | return __resolver__; 14 | } 15 | 16 | __exports__.get = get; 17 | }); -------------------------------------------------------------------------------- /lib/test.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import QUnit from 'qunit'; 3 | import testContext from './test-context'; 4 | 5 | function resetViews() { 6 | Ember.View.views = {}; 7 | } 8 | 9 | export default function test(testName, callback) { 10 | 11 | function wrapper() { 12 | var context = testContext.get(); 13 | 14 | resetViews(); 15 | var result = callback.call(context); 16 | 17 | function failTestOnPromiseRejection(reason) { 18 | ok(false, reason); 19 | } 20 | 21 | Ember.run(function(){ 22 | stop(); 23 | Ember.RSVP.Promise.cast(result)['catch'](failTestOnPromiseRejection)['finally'](start); 24 | }); 25 | } 26 | 27 | QUnit.test(testName, wrapper); 28 | } 29 | 30 | -------------------------------------------------------------------------------- /lib/isolated-container.js: -------------------------------------------------------------------------------- 1 | import testResolver from './test-resolver'; 2 | import Ember from 'ember'; 3 | 4 | export default function isolatedContainer(fullNames) { 5 | var resolver = testResolver.get(); 6 | var container = new Ember.Container(); 7 | container.optionsForType('component', { singleton: false }); 8 | container.optionsForType('view', { singleton: false }); 9 | container.optionsForType('template', { instantiate: false }); 10 | container.optionsForType('helper', { instantiate: false }); 11 | container.register('component-lookup:main', Ember.ComponentLookup); 12 | for (var i = fullNames.length; i > 0; i--) { 13 | var fullName = fullNames[i - 1]; 14 | container.register(fullName, resolver.resolve(fullName)); 15 | } 16 | return container; 17 | } 18 | -------------------------------------------------------------------------------- /dist/cjs/test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var Ember = require("ember")["default"] || require("ember"); 3 | var QUnit = require("qunit")["default"] || require("qunit"); 4 | var testContext = require("./test-context")["default"] || require("./test-context"); 5 | 6 | function resetViews() { 7 | Ember.View.views = {}; 8 | } 9 | 10 | exports["default"] = function test(testName, callback) { 11 | 12 | function wrapper() { 13 | var context = testContext.get(); 14 | 15 | resetViews(); 16 | var result = callback.call(context); 17 | 18 | function failTestOnPromiseRejection(reason) { 19 | ok(false, reason); 20 | } 21 | 22 | Ember.run(function(){ 23 | stop(); 24 | Ember.RSVP.Promise.cast(result)['catch'](failTestOnPromiseRejection)['finally'](start); 25 | }); 26 | } 27 | 28 | QUnit.test(testName, wrapper); 29 | } -------------------------------------------------------------------------------- /dist/cjs/isolated-container.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var testResolver = require("./test-resolver")["default"] || require("./test-resolver"); 3 | var Ember = require("ember")["default"] || require("ember"); 4 | 5 | exports["default"] = function isolatedContainer(fullNames) { 6 | var resolver = testResolver.get(); 7 | var container = new Ember.Container(); 8 | container.optionsForType('component', { singleton: false }); 9 | container.optionsForType('view', { singleton: false }); 10 | container.optionsForType('template', { instantiate: false }); 11 | container.optionsForType('helper', { instantiate: false }); 12 | container.register('component-lookup:main', Ember.ComponentLookup); 13 | for (var i = fullNames.length; i > 0; i--) { 14 | var fullName = fullNames[i - 1]; 15 | container.register(fullName, resolver.resolve(fullName)); 16 | } 17 | return container; 18 | } -------------------------------------------------------------------------------- /lib/main.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import isolatedContainer from './isolated-container'; 3 | import moduleFor from './module-for'; 4 | import moduleForComponent from './module-for-component'; 5 | import moduleForModel from './module-for-model'; 6 | import test from './test'; 7 | import testResolver from './test-resolver'; 8 | 9 | Ember.testing = true; 10 | 11 | function setResolver(resolver) { 12 | testResolver.set(resolver); 13 | } 14 | 15 | function globalize() { 16 | window.moduleFor = moduleFor; 17 | window.moduleForComponent = moduleForComponent; 18 | window.moduleForModel = moduleForModel; 19 | window.test = test; 20 | window.setResolver = setResolver; 21 | } 22 | 23 | export { 24 | globalize, 25 | moduleFor, 26 | moduleForComponent, 27 | moduleForModel, 28 | test, 29 | setResolver 30 | }; 31 | 32 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config) { 2 | config.set({ 3 | 4 | frameworks: ['qunit'], 5 | 6 | files: [ 7 | 'bower_components/jquery/dist/jquery.js', 8 | 'bower_components/handlebars/handlebars.js', 9 | 'bower_components/ember/ember.js', 10 | 'bower_components/ember-data/ember-data.js', 11 | 'dist/globals/main.js', 12 | // when running broccoli serve, we use this instead 13 | 'http://localhost:4200/globals/main.js', 14 | 'test/support/setup.js', 15 | 'test/**/*.spec.js' 16 | ], 17 | 18 | basePath: '', 19 | 20 | reporters: ['progress'], 21 | 22 | port: 9876, 23 | 24 | colors: true, 25 | 26 | logLevel: config.LOG_INFO, 27 | 28 | autoWatch: true, 29 | 30 | browsers: ['Chrome'], 31 | 32 | captureTimeout: 60000, 33 | 34 | singleRun: false 35 | 36 | }); 37 | }; 38 | 39 | -------------------------------------------------------------------------------- /lib/module-for-model.js: -------------------------------------------------------------------------------- 1 | import moduleFor from './module-for'; 2 | import Ember from 'ember'; 3 | 4 | export default function moduleForModel(name, description, callbacks) { 5 | moduleFor('model:' + name, description, callbacks, function(container, context, defaultSubject) { 6 | // custom model specific awesomeness 7 | container.register('store:main', DS.Store); 8 | container.register('adapter:application', DS.FixtureAdapter); 9 | 10 | context.__setup_properties__.store = function(){ 11 | return container.lookup('store:main'); 12 | }; 13 | 14 | if (context.__setup_properties__.subject === defaultSubject) { 15 | context.__setup_properties__.subject = function(options) { 16 | return Ember.run(function() { 17 | return container.lookup('store:main').createRecord(name, options); 18 | }); 19 | }; 20 | } 21 | }); 22 | } 23 | 24 | -------------------------------------------------------------------------------- /dist/cjs/module-for-model.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var moduleFor = require("./module-for")["default"] || require("./module-for"); 3 | var Ember = require("ember")["default"] || require("ember"); 4 | 5 | exports["default"] = function moduleForModel(name, description, callbacks) { 6 | moduleFor('model:' + name, description, callbacks, function(container, context, defaultSubject) { 7 | // custom model specific awesomeness 8 | container.register('store:main', DS.Store); 9 | container.register('adapter:application', DS.FixtureAdapter); 10 | 11 | context.__setup_properties__.store = function(){ 12 | return container.lookup('store:main'); 13 | }; 14 | 15 | if (context.__setup_properties__.subject === defaultSubject) { 16 | context.__setup_properties__.subject = function(options) { 17 | return Ember.run(function() { 18 | return container.lookup('store:main').createRecord(name, options); 19 | }); 20 | }; 21 | } 22 | }); 23 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ember-qunit", 3 | "version": "0.1.6", 4 | "description": "unit test helpers for ember", 5 | "main": "dist/cjs/main.js", 6 | "scripts": { 7 | "test": "bower install && rm -rf dist && broccoli build dist && karma start --browsers Firefox --single-run" 8 | }, 9 | "authors": [ 10 | "Stefan Penner", 11 | "Ryan Florence" 12 | ], 13 | "license": "MIT", 14 | "devDependencies": { 15 | "broccoli": "~0.2.0", 16 | "broccoli-dist-es6-module": "^0.1.8", 17 | "karma-script-launcher": "~0.1.0", 18 | "karma-chrome-launcher": "~0.1.2", 19 | "karma-firefox-launcher": "~0.1.3", 20 | "karma-html2js-preprocessor": "~0.1.0", 21 | "karma-jasmine": "~0.1.5", 22 | "karma-coffee-preprocessor": "~0.1.3", 23 | "requirejs": "~2.1.11", 24 | "karma-requirejs": "~0.2.1", 25 | "karma-phantomjs-launcher": "~0.1.2", 26 | "karma": "~0.10.9", 27 | "qunitjs": "~1.12.0", 28 | "karma-qunit": "~0.1.1", 29 | "bower": "^1.2.8", 30 | "broccoli-cli": "0.0.1" 31 | } 32 | } -------------------------------------------------------------------------------- /dist/amd/isolated-container.js: -------------------------------------------------------------------------------- 1 | define( 2 | ["./test-resolver","ember","exports"], 3 | function(__dependency1__, __dependency2__, __exports__) { 4 | "use strict"; 5 | var testResolver = __dependency1__["default"] || __dependency1__; 6 | var Ember = __dependency2__["default"] || __dependency2__; 7 | 8 | __exports__["default"] = function isolatedContainer(fullNames) { 9 | var resolver = testResolver.get(); 10 | var container = new Ember.Container(); 11 | container.optionsForType('component', { singleton: false }); 12 | container.optionsForType('view', { singleton: false }); 13 | container.optionsForType('template', { instantiate: false }); 14 | container.optionsForType('helper', { instantiate: false }); 15 | container.register('component-lookup:main', Ember.ComponentLookup); 16 | for (var i = fullNames.length; i > 0; i--) { 17 | var fullName = fullNames[i - 1]; 18 | container.register(fullName, resolver.resolve(fullName)); 19 | } 20 | return container; 21 | } 22 | }); -------------------------------------------------------------------------------- /dist/amd/test.js: -------------------------------------------------------------------------------- 1 | define( 2 | ["ember","qunit","./test-context","exports"], 3 | function(__dependency1__, __dependency2__, __dependency3__, __exports__) { 4 | "use strict"; 5 | var Ember = __dependency1__["default"] || __dependency1__; 6 | var QUnit = __dependency2__["default"] || __dependency2__; 7 | var testContext = __dependency3__["default"] || __dependency3__; 8 | 9 | function resetViews() { 10 | Ember.View.views = {}; 11 | } 12 | 13 | __exports__["default"] = function test(testName, callback) { 14 | 15 | function wrapper() { 16 | var context = testContext.get(); 17 | 18 | resetViews(); 19 | var result = callback.call(context); 20 | 21 | function failTestOnPromiseRejection(reason) { 22 | ok(false, reason); 23 | } 24 | 25 | Ember.run(function(){ 26 | stop(); 27 | Ember.RSVP.Promise.cast(result)['catch'](failTestOnPromiseRejection)['finally'](start); 28 | }); 29 | } 30 | 31 | QUnit.test(testName, wrapper); 32 | } 33 | }); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Ryan Florence 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /dist/amd/module-for-model.js: -------------------------------------------------------------------------------- 1 | define( 2 | ["./module-for","ember","exports"], 3 | function(__dependency1__, __dependency2__, __exports__) { 4 | "use strict"; 5 | var moduleFor = __dependency1__["default"] || __dependency1__; 6 | var Ember = __dependency2__["default"] || __dependency2__; 7 | 8 | __exports__["default"] = function moduleForModel(name, description, callbacks) { 9 | moduleFor('model:' + name, description, callbacks, function(container, context, defaultSubject) { 10 | // custom model specific awesomeness 11 | container.register('store:main', DS.Store); 12 | container.register('adapter:application', DS.FixtureAdapter); 13 | 14 | context.__setup_properties__.store = function(){ 15 | return container.lookup('store:main'); 16 | }; 17 | 18 | if (context.__setup_properties__.subject === defaultSubject) { 19 | context.__setup_properties__.subject = function(options) { 20 | return Ember.run(function() { 21 | return container.lookup('store:main').createRecord(name, options); 22 | }); 23 | }; 24 | } 25 | }); 26 | } 27 | }); -------------------------------------------------------------------------------- /dist/cjs/main.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var Ember = require("ember")["default"] || require("ember"); 3 | var isolatedContainer = require("./isolated-container")["default"] || require("./isolated-container"); 4 | var moduleFor = require("./module-for")["default"] || require("./module-for"); 5 | var moduleForComponent = require("./module-for-component")["default"] || require("./module-for-component"); 6 | var moduleForModel = require("./module-for-model")["default"] || require("./module-for-model"); 7 | var test = require("./test")["default"] || require("./test"); 8 | var testResolver = require("./test-resolver")["default"] || require("./test-resolver"); 9 | 10 | Ember.testing = true; 11 | 12 | function setResolver(resolver) { 13 | testResolver.set(resolver); 14 | } 15 | 16 | function globalize() { 17 | window.moduleFor = moduleFor; 18 | window.moduleForComponent = moduleForComponent; 19 | window.moduleForModel = moduleForModel; 20 | window.test = test; 21 | window.setResolver = setResolver; 22 | } 23 | 24 | exports.globalize = globalize; 25 | exports.moduleFor = moduleFor; 26 | exports.moduleForComponent = moduleForComponent; 27 | exports.moduleForModel = moduleForModel; 28 | exports.test = test; 29 | exports.setResolver = setResolver; -------------------------------------------------------------------------------- /lib/module-for-component.js: -------------------------------------------------------------------------------- 1 | import testResolver from './test-resolver'; 2 | import moduleFor from './module-for'; 3 | import Ember from 'ember'; 4 | 5 | export default function moduleForComponent(name, description, callbacks) { 6 | var resolver = testResolver.get(); 7 | 8 | moduleFor('component:' + name, description, callbacks, function(container, context, defaultSubject) { 9 | var templateName = 'template:components/' + name; 10 | 11 | var template = resolver.resolve(templateName); 12 | 13 | if (template) { 14 | container.register(templateName, template); 15 | container.injection('component:' + name, 'template', templateName); 16 | } 17 | 18 | context.dispatcher = Ember.EventDispatcher.create(); 19 | context.dispatcher.setup({}, '#ember-testing'); 20 | 21 | context.__setup_properties__.append = function(selector) { 22 | var containerView = Ember.ContainerView.create({container: container}); 23 | var view = Ember.run(function(){ 24 | var subject = context.subject(); 25 | containerView.pushObject(subject); 26 | // TODO: destory this somewhere 27 | containerView.appendTo('#ember-testing'); 28 | return subject; 29 | }); 30 | 31 | return view.$(); 32 | }; 33 | context.__setup_properties__.$ = context.__setup_properties__.append; 34 | }); 35 | } 36 | -------------------------------------------------------------------------------- /dist/cjs/module-for-component.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var testResolver = require("./test-resolver")["default"] || require("./test-resolver"); 3 | var moduleFor = require("./module-for")["default"] || require("./module-for"); 4 | var Ember = require("ember")["default"] || require("ember"); 5 | 6 | exports["default"] = function moduleForComponent(name, description, callbacks) { 7 | var resolver = testResolver.get(); 8 | 9 | moduleFor('component:' + name, description, callbacks, function(container, context, defaultSubject) { 10 | var templateName = 'template:components/' + name; 11 | 12 | var template = resolver.resolve(templateName); 13 | 14 | if (template) { 15 | container.register(templateName, template); 16 | container.injection('component:' + name, 'template', templateName); 17 | } 18 | 19 | context.dispatcher = Ember.EventDispatcher.create(); 20 | context.dispatcher.setup({}, '#ember-testing'); 21 | 22 | context.__setup_properties__.append = function(selector) { 23 | var containerView = Ember.ContainerView.create({container: container}); 24 | var view = Ember.run(function(){ 25 | var subject = context.subject(); 26 | containerView.pushObject(subject); 27 | // TODO: destory this somewhere 28 | containerView.appendTo('#ember-testing'); 29 | return subject; 30 | }); 31 | 32 | return view.$(); 33 | }; 34 | context.__setup_properties__.$ = context.__setup_properties__.append; 35 | }); 36 | } -------------------------------------------------------------------------------- /dist/amd/main.js: -------------------------------------------------------------------------------- 1 | define( 2 | ["ember","./isolated-container","./module-for","./module-for-component","./module-for-model","./test","./test-resolver","exports"], 3 | function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { 4 | "use strict"; 5 | var Ember = __dependency1__["default"] || __dependency1__; 6 | var isolatedContainer = __dependency2__["default"] || __dependency2__; 7 | var moduleFor = __dependency3__["default"] || __dependency3__; 8 | var moduleForComponent = __dependency4__["default"] || __dependency4__; 9 | var moduleForModel = __dependency5__["default"] || __dependency5__; 10 | var test = __dependency6__["default"] || __dependency6__; 11 | var testResolver = __dependency7__["default"] || __dependency7__; 12 | 13 | Ember.testing = true; 14 | 15 | function setResolver(resolver) { 16 | testResolver.set(resolver); 17 | } 18 | 19 | function globalize() { 20 | window.moduleFor = moduleFor; 21 | window.moduleForComponent = moduleForComponent; 22 | window.moduleForModel = moduleForModel; 23 | window.test = test; 24 | window.setResolver = setResolver; 25 | } 26 | 27 | __exports__.globalize = globalize; 28 | __exports__.moduleFor = moduleFor; 29 | __exports__.moduleForComponent = moduleForComponent; 30 | __exports__.moduleForModel = moduleForModel; 31 | __exports__.test = test; 32 | __exports__.setResolver = setResolver; 33 | }); -------------------------------------------------------------------------------- /dist/amd/module-for-component.js: -------------------------------------------------------------------------------- 1 | define( 2 | ["./test-resolver","./module-for","ember","exports"], 3 | function(__dependency1__, __dependency2__, __dependency3__, __exports__) { 4 | "use strict"; 5 | var testResolver = __dependency1__["default"] || __dependency1__; 6 | var moduleFor = __dependency2__["default"] || __dependency2__; 7 | var Ember = __dependency3__["default"] || __dependency3__; 8 | 9 | __exports__["default"] = function moduleForComponent(name, description, callbacks) { 10 | var resolver = testResolver.get(); 11 | 12 | moduleFor('component:' + name, description, callbacks, function(container, context, defaultSubject) { 13 | var templateName = 'template:components/' + name; 14 | 15 | var template = resolver.resolve(templateName); 16 | 17 | if (template) { 18 | container.register(templateName, template); 19 | container.injection('component:' + name, 'template', templateName); 20 | } 21 | 22 | context.dispatcher = Ember.EventDispatcher.create(); 23 | context.dispatcher.setup({}, '#ember-testing'); 24 | 25 | context.__setup_properties__.append = function(selector) { 26 | var containerView = Ember.ContainerView.create({container: container}); 27 | var view = Ember.run(function(){ 28 | var subject = context.subject(); 29 | containerView.pushObject(subject); 30 | // TODO: destory this somewhere 31 | containerView.appendTo('#ember-testing'); 32 | return subject; 33 | }); 34 | 35 | return view.$(); 36 | }; 37 | context.__setup_properties__.$ = context.__setup_properties__.append; 38 | }); 39 | } 40 | }); -------------------------------------------------------------------------------- /lib/module-for.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import QUnit from 'qunit'; 3 | import testContext from './test-context'; 4 | import isolatedContainer from './isolated-container'; 5 | 6 | export default function moduleFor(fullName, description, callbacks, delegate) { 7 | var container; 8 | var context; 9 | 10 | var _callbacks = { 11 | setup: function(){ 12 | callbacks = callbacks || { }; 13 | 14 | var needs = [fullName].concat(callbacks.needs || []); 15 | container = isolatedContainer(needs); 16 | 17 | callbacks.subject = callbacks.subject || defaultSubject; 18 | 19 | callbacks.setup = callbacks.setup || function() { }; 20 | callbacks.teardown = callbacks.teardown || function() { }; 21 | 22 | function factory() { 23 | return container.lookupFactory(fullName); 24 | } 25 | 26 | testContext.set({ 27 | container: container, 28 | factory: factory, 29 | dispatcher: null, 30 | __setup_properties__: callbacks 31 | }); 32 | 33 | context = testContext.get(); 34 | 35 | if (delegate) { 36 | delegate(container, context, defaultSubject); 37 | } 38 | 39 | if (Ember.$('#ember-testing').length === 0) { 40 | Ember.$('').appendTo(document.body); 41 | } 42 | 43 | buildContextVariables(context); 44 | callbacks.setup.call(context, container); 45 | }, 46 | 47 | teardown: function(){ 48 | Ember.run(function(){ 49 | container.destroy(); 50 | 51 | if (context.dispatcher) { 52 | context.dispatcher.destroy(); 53 | } 54 | }); 55 | 56 | callbacks.teardown(container); 57 | Ember.$('#ember-testing').empty(); 58 | } 59 | }; 60 | 61 | QUnit.module(description || fullName, _callbacks); 62 | } 63 | 64 | function defaultSubject(options, factory) { 65 | return factory.create(options); 66 | } 67 | 68 | // allow arbitrary named factories, like rspec let 69 | function buildContextVariables(context) { 70 | var cache = { }; 71 | var callbacks = context.__setup_properties__; 72 | var container = context.container; 73 | var factory = context.factory; 74 | 75 | Ember.keys(callbacks).filter(function(key){ 76 | // ignore the default setup/teardown keys 77 | return key !== 'setup' && key !== 'teardown'; 78 | }).forEach(function(key){ 79 | context[key] = function(options) { 80 | if (cache[key]) { return cache[key]; } 81 | 82 | var result = callbacks[key](options, factory(), container); 83 | cache[key] = result; 84 | return result; 85 | }; 86 | }); 87 | } 88 | -------------------------------------------------------------------------------- /dist/cjs/module-for.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var Ember = require("ember")["default"] || require("ember"); 3 | var QUnit = require("qunit")["default"] || require("qunit"); 4 | var testContext = require("./test-context")["default"] || require("./test-context"); 5 | var isolatedContainer = require("./isolated-container")["default"] || require("./isolated-container"); 6 | 7 | exports["default"] = function moduleFor(fullName, description, callbacks, delegate) { 8 | var container; 9 | var context; 10 | 11 | var _callbacks = { 12 | setup: function(){ 13 | callbacks = callbacks || { }; 14 | 15 | var needs = [fullName].concat(callbacks.needs || []); 16 | container = isolatedContainer(needs); 17 | 18 | callbacks.subject = callbacks.subject || defaultSubject; 19 | 20 | callbacks.setup = callbacks.setup || function() { }; 21 | callbacks.teardown = callbacks.teardown || function() { }; 22 | 23 | function factory() { 24 | return container.lookupFactory(fullName); 25 | } 26 | 27 | testContext.set({ 28 | container: container, 29 | factory: factory, 30 | dispatcher: null, 31 | __setup_properties__: callbacks 32 | }); 33 | 34 | context = testContext.get(); 35 | 36 | if (delegate) { 37 | delegate(container, context, defaultSubject); 38 | } 39 | 40 | if (Ember.$('#ember-testing').length === 0) { 41 | Ember.$('').appendTo(document.body); 42 | } 43 | 44 | buildContextVariables(context); 45 | callbacks.setup.call(context, container); 46 | }, 47 | 48 | teardown: function(){ 49 | Ember.run(function(){ 50 | container.destroy(); 51 | 52 | if (context.dispatcher) { 53 | context.dispatcher.destroy(); 54 | } 55 | }); 56 | 57 | callbacks.teardown(container); 58 | Ember.$('#ember-testing').empty(); 59 | } 60 | }; 61 | 62 | QUnit.module(description || fullName, _callbacks); 63 | } 64 | 65 | function defaultSubject(options, factory) { 66 | return factory.create(options); 67 | } 68 | 69 | // allow arbitrary named factories, like rspec let 70 | function buildContextVariables(context) { 71 | var cache = { }; 72 | var callbacks = context.__setup_properties__; 73 | var container = context.container; 74 | var factory = context.factory; 75 | 76 | Ember.keys(callbacks).filter(function(key){ 77 | // ignore the default setup/teardown keys 78 | return key !== 'setup' && key !== 'teardown'; 79 | }).forEach(function(key){ 80 | context[key] = function(options) { 81 | if (cache[key]) { return cache[key]; } 82 | 83 | var result = callbacks[key](options, factory(), container); 84 | cache[key] = result; 85 | return result; 86 | }; 87 | }); 88 | } -------------------------------------------------------------------------------- /dist/amd/module-for.js: -------------------------------------------------------------------------------- 1 | define( 2 | ["ember","qunit","./test-context","./isolated-container","exports"], 3 | function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { 4 | "use strict"; 5 | var Ember = __dependency1__["default"] || __dependency1__; 6 | var QUnit = __dependency2__["default"] || __dependency2__; 7 | var testContext = __dependency3__["default"] || __dependency3__; 8 | var isolatedContainer = __dependency4__["default"] || __dependency4__; 9 | 10 | __exports__["default"] = function moduleFor(fullName, description, callbacks, delegate) { 11 | var container; 12 | var context; 13 | 14 | var _callbacks = { 15 | setup: function(){ 16 | callbacks = callbacks || { }; 17 | 18 | var needs = [fullName].concat(callbacks.needs || []); 19 | container = isolatedContainer(needs); 20 | 21 | callbacks.subject = callbacks.subject || defaultSubject; 22 | 23 | callbacks.setup = callbacks.setup || function() { }; 24 | callbacks.teardown = callbacks.teardown || function() { }; 25 | 26 | function factory() { 27 | return container.lookupFactory(fullName); 28 | } 29 | 30 | testContext.set({ 31 | container: container, 32 | factory: factory, 33 | dispatcher: null, 34 | __setup_properties__: callbacks 35 | }); 36 | 37 | context = testContext.get(); 38 | 39 | if (delegate) { 40 | delegate(container, context, defaultSubject); 41 | } 42 | 43 | if (Ember.$('#ember-testing').length === 0) { 44 | Ember.$('').appendTo(document.body); 45 | } 46 | 47 | buildContextVariables(context); 48 | callbacks.setup.call(context, container); 49 | }, 50 | 51 | teardown: function(){ 52 | Ember.run(function(){ 53 | container.destroy(); 54 | 55 | if (context.dispatcher) { 56 | context.dispatcher.destroy(); 57 | } 58 | }); 59 | 60 | callbacks.teardown(container); 61 | Ember.$('#ember-testing').empty(); 62 | } 63 | }; 64 | 65 | QUnit.module(description || fullName, _callbacks); 66 | } 67 | 68 | function defaultSubject(options, factory) { 69 | return factory.create(options); 70 | } 71 | 72 | // allow arbitrary named factories, like rspec let 73 | function buildContextVariables(context) { 74 | var cache = { }; 75 | var callbacks = context.__setup_properties__; 76 | var container = context.container; 77 | var factory = context.factory; 78 | 79 | Ember.keys(callbacks).filter(function(key){ 80 | // ignore the default setup/teardown keys 81 | return key !== 'setup' && key !== 'teardown'; 82 | }).forEach(function(key){ 83 | context[key] = function(options) { 84 | if (cache[key]) { return cache[key]; } 85 | 86 | var result = callbacks[key](options, factory(), container); 87 | cache[key] = result; 88 | return result; 89 | }; 90 | }); 91 | } 92 | }); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Ember QUnit 2 | =========== 3 | 4 | [](https://travis-ci.org/rpflorence/ember-qunit) 5 | 6 | [WIP] Unit test helpers for Ember. 7 | 8 | About 9 | ----- 10 | 11 | Ember QUnit uses your application's resolver to find and automatically 12 | create test subjects for you with the `moduleFor` and `test` helpers. 13 | 14 | *This is a work in progress* but its also quite handy already. Feedback 15 | is highly encouraged. 16 | 17 | Module Formats 18 | -------------- 19 | 20 | You will find all the popular formats in `dist/`. If using globals, all 21 | methods are found on `window.emq`. 22 | 23 | Examples 24 | -------- 25 | 26 | ### Global build setup: 27 | 28 | ```js 29 | // inject test helpers onto window 30 | emq.globalize(); 31 | ``` 32 | 33 | ### Setting the resolver 34 | 35 | ```js 36 | // if you don't have a custom resolver, do it like this: 37 | setResolver(Ember.DefaultResolver.create({namespace: App})); 38 | 39 | // otherwise something like: 40 | import Resolver from './path/to/resolver'; 41 | import {setResolver} from 'ember-qunit'; 42 | setResolver(Resolver.create()); 43 | ``` 44 | 45 | ### Simple example: 46 | 47 | ```js 48 | // tell ember qunit what you are testing, it will find it from the 49 | // resolver 50 | moduleForComponent('x-foo', 'XFooComponent'); 51 | 52 | // run a test 53 | test('it renders', function() { 54 | expect(2); 55 | 56 | // creates the component instance 57 | var component = this.subject(); 58 | equal(component.state, 'preRender'); 59 | 60 | // appends the component to the page 61 | this.append(); 62 | equal(component.state, 'inDOM'); 63 | }); 64 | ``` 65 | 66 | ### Complex example 67 | 68 | ```js 69 | // a more complex example taken from ic-tabs 70 | moduleForComponent('ic-tabs', 'TabsComponent', { 71 | 72 | // specify the other units that are required for this test 73 | needs: [ 74 | 'component:ic-tab', 75 | 'component:ic-tab-panel', 76 | 'component:ic-tab-list' 77 | ] 78 | }); 79 | 80 | test('selects first tab and shows the panel', function() { 81 | expect(3); 82 | var component = test.subject({ 83 | 84 | // can provide properties for the subject, like the yielded template 85 | // of a component (not the layout, in this case) 86 | template: Ember.Handlebars.compile(''+ 87 | '{{#ic-tab-list}}'+ 88 | '{{#ic-tab id="tab1"}}tab1{{/ic-tab}}'+ 89 | '{{#ic-tab id="tab2"}}tab2{{/ic-tab}}'+ 90 | '{{#ic-tab id="tab3"}}tab3{{/ic-tab}}'+ 91 | '{{/ic-tab-list}}'+ 92 | '{{#ic-tab-panel id="panel1"}}one{{/ic-tab-panel}}'+ 93 | '{{#ic-tab-panel id="panel2"}}two{{/ic-tab-panel}}'+ 94 | '{{#ic-tab-panel id="panel3"}}three{{/ic-tab-panel}}' 95 | }) 96 | }); 97 | this.append(); 98 | var tab1 = Ember.View.views['tab1']; 99 | var panel1 = Ember.View.views['panel1']; 100 | ok(component.get('activeTab') === tab1); 101 | ok(tab1.get('active')); 102 | var el = tab1.$(); 103 | ok(panel1.$().is(':visible')); 104 | }); 105 | ``` 106 | 107 | Helpers 108 | ------- 109 | 110 | ### `moduleFor(fullName [, description [, callbacks]])` 111 | 112 | - `fullName`: (String) - The full name of the unit, ie 113 | `controller:application`, `route:index`. 114 | 115 | - `description`: (String) optional - The description of the module 116 | 117 | - `callbacks`: (Object) optional - Normal QUnit callbacks (setup and 118 | teardown), with addition to `needs`, which allows you specify the 119 | other units the tests will need. 120 | 121 | ### `moduleForComponent(name, [description, callbacks])` 122 | 123 | - `name`: (String) - the short name of the component that you'd use in a 124 | template, ie `x-foo`, `ic-tabs`, etc. 125 | 126 | ### `moduleForModel(name, [description, callbacks])` 127 | 128 | - `name`: (String) - the short name of the model you'd use in `store` 129 | operations ie `user`, `assignmentGroup`, etc. 130 | 131 | Contributing 132 | ------------ 133 | 134 | ```sh 135 | $ npm install 136 | $ bower install 137 | $ broccoli serve 138 | # new tab 139 | $ karma start 140 | ``` 141 | 142 | -------------------------------------------------------------------------------- /test/main.spec.js: -------------------------------------------------------------------------------- 1 | emq.globalize(); 2 | 3 | var Post = DS.Model.extend({ 4 | title: DS.attr(), 5 | user: DS.attr(), 6 | comments: DS.hasMany('comment') 7 | }); 8 | var Comment = DS.Model.extend({ 9 | post: DS.belongsTo('post') 10 | }); 11 | 12 | var PrettyColor = Ember.Component.extend({ 13 | classNames: ['pretty-color'], 14 | attributeBindings: ['style'], 15 | style: function(){ 16 | return 'color: ' + this.get('name') + ';'; 17 | }.property('name') 18 | }); 19 | 20 | var registry = { 21 | 'component:x-foo': Ember.Component.extend(), 22 | 'component:pretty-color': PrettyColor, 23 | 'template:components/pretty-color': "Pretty Color: {{name}}".compile(), 24 | 'route:foo': Ember.Route.extend(), 25 | 'controller:foos': Ember.ArrayController.extend(), 26 | 'controller:bar': Ember.Controller.extend({ 27 | needs: ['foos'] 28 | }), 29 | 'model:post': Post, 30 | 'model:comment': Comment 31 | }; 32 | 33 | var Resolver = Ember.DefaultResolver.extend({ 34 | resolve: function(fullName) { 35 | return registry[fullName] || this._super.apply(this, arguments); 36 | } 37 | }); 38 | 39 | setResolver(Resolver.create()); 40 | 41 | 42 | 43 | //moduleForRoute('foo', 'FooRoute'); 44 | 45 | //test('creates route instance', function() { 46 | //expect(1); 47 | //var route = this.subject(); 48 | //ok(route instanceof registry['route:foo']); 49 | //}); 50 | 51 | 52 | 53 | //moduleForController('bar', 'BarController'); 54 | 55 | //test('creates controller instance', function() { 56 | //expect(1); 57 | //var controller = this.subject(); 58 | //ok(controller instanceof registry['controller:bar']); 59 | //}); 60 | 61 | moduleFor('controller:bar', 'moduleFor with bar controller', { 62 | needs: ['controller:foos'] 63 | }); 64 | 65 | test('exists', function() { 66 | var bar = this.subject(); 67 | 68 | foos = bar.get('controllers.foos'); 69 | 70 | ok(bar); 71 | ok(bar instanceof Ember.Controller); 72 | ok(foos instanceof Ember.ArrayController); 73 | }); 74 | 75 | test('exists again', function() { 76 | var bar = this.subject(); 77 | 78 | foos = bar.get('controllers.foos'); 79 | 80 | ok(bar); 81 | ok(bar instanceof Ember.Controller); 82 | ok(foos instanceof Ember.ArrayController); 83 | }); 84 | 85 | moduleForModel('post', 'moduleForModel with post', { 86 | needs: ['model:comment'] 87 | }); 88 | 89 | test('exists', function() { 90 | var post = this.subject({title: 'A title for a post', user: 'bob'}); 91 | 92 | ok(post); 93 | ok(post instanceof DS.Model); 94 | ok(post instanceof Post); 95 | }); 96 | 97 | 98 | moduleForComponent('x-foo', 'moduleForComponent with x-foo'); 99 | 100 | test('renders', function() { 101 | expect(2); 102 | var component = this.subject(); 103 | equal(component.state, 'preRender'); 104 | this.append(); 105 | equal(component.state, 'inDOM'); 106 | }); 107 | 108 | test('yields', function() { 109 | expect(2); 110 | var component = this.subject({ 111 | template: "yield me".compile() 112 | }); 113 | equal(component.state, 'preRender'); 114 | this.append(); 115 | equal(component.state, 'inDOM'); 116 | }); 117 | 118 | test('can lookup components in its template', function() { 119 | expect(1); 120 | var component = this.subject({ 121 | template: "{{x-foo id='yodawg-i-heard-you-liked-x-foo-in-ur-x-foo'}}".compile() 122 | }); 123 | this.append(); 124 | equal(component.state, 'inDOM'); 125 | }); 126 | 127 | test('clears out views from test to test', function() { 128 | expect(1); 129 | var component = this.subject({ 130 | template: "{{x-foo id='yodawg-i-heard-you-liked-x-foo-in-ur-x-foo'}}".compile() 131 | }); 132 | this.append(); 133 | ok(true, 'rendered without id already being used from another test'); 134 | }); 135 | 136 | moduleForComponent('pretty-color', 'moduleForComponent with pretty-color'); 137 | 138 | test("className", function(){ 139 | // first call to this.$() renders the component. 140 | ok(this.$().is('.pretty-color')); 141 | }); 142 | 143 | test("template", function(){ 144 | var component = this.subject(); 145 | 146 | equal($.trim(this.$().text()), 'Pretty Color:'); 147 | 148 | Ember.run(function(){ 149 | component.set('name', 'green'); 150 | }); 151 | 152 | equal($.trim(this.$().text()), 'Pretty Color: green'); 153 | }); -------------------------------------------------------------------------------- /dist/globals/main.js: -------------------------------------------------------------------------------- 1 | !function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.emq=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o