diff --git a/.jshintrc b/.jshintrc
index b4f3c6f42..6c4721ea2 100644
--- a/.jshintrc
+++ b/.jshintrc
@@ -11,6 +11,7 @@
     "I18n",
     "bootbox",
     "module",
+    "moduleFor",
     "integration",
     "test",
     "ok",
diff --git a/test/javascripts/admin/controllers/admin_badges_controller_test.js b/test/javascripts/admin/controllers/admin_badges_controller_test.js
index ddfb02b71..16a126deb 100644
--- a/test/javascripts/admin/controllers/admin_badges_controller_test.js
+++ b/test/javascripts/admin/controllers/admin_badges_controller_test.js
@@ -1,29 +1,26 @@
-module("controller:admin-badges");
+moduleFor("controller:admin-badges", "controller:admin-badges", {
+  needs: ['controller:modal', 'controller:admin-badge']
+});
 
 test("canEditDescription", function() {
-  var badge, controller;
-
-  badge = Discourse.Badge.create({id: 101, name: "Test Badge"});
-  controller = testController("admin-badges", [badge]);
+  var badge = Discourse.Badge.create({id: 101, name: "Test Badge"});
+  var controller = this.subject({ model: [badge] });
   controller.send('selectBadge', badge);
   ok(controller.get('canEditDescription'), "allows editing description when a translation exists for the badge name");
 
-  this.stub(I18n, "t").returns("translated string");
-  badge = Discourse.Badge.create({id: 102, name: "Test Badge"});
-  controller = testController("admin-badges", [badge]);
-  controller.send('selectBadge', badge);
-  ok(!controller.get('canEditDescription'), "shows the displayName when it is different from the name");
+  badge.set('translatedDescription', 'translated');
+  ok(!controller.get('canEditDescription'), "can't edit the description when it's got a translation");
 });
 
 test("createNewBadge", function() {
-  var controller = testController("admin-badges", []);
+  var controller = this.subject();
   controller.send('createNewBadge');
   equal(controller.get('model.length'), 1, "adds a new badge to the list of badges");
 });
 
 test("selectBadge", function() {
   var badge = Discourse.Badge.create({id: 101, name: "Test Badge"}),
-      controller = testController("admin-badges", [badge]);
+      controller = this.subject({ model: [badge] });
 
   controller.send('selectBadge', badge);
   equal(controller.get('selectedItem'), badge, "the badge is selected");
@@ -32,10 +29,10 @@ test("selectBadge", function() {
 test("save", function() {
   var badge = Discourse.Badge.create({id: 101, name: "Test Badge"}),
       otherBadge = Discourse.Badge.create({id: 102, name: "Other Badge"}),
-      controller = testController("admin-badges", [badge, otherBadge]);
+      controller = this.subject({ model: [badge, otherBadge] });
 
   controller.send('selectBadge', badge);
-  this.stub(badge, "save").returns(Ember.RSVP.resolve({}));
+  sinon.stub(badge, "save").returns(Ember.RSVP.resolve({}));
   controller.send("save");
   ok(badge.save.calledOnce, "called save on the badge");
 });
@@ -43,9 +40,9 @@ test("save", function() {
 test("destroy", function() {
   var badge = Discourse.Badge.create({id: 101, name: "Test Badge"}),
       otherBadge = Discourse.Badge.create({id: 102, name: "Other Badge"}),
-      controller = testController("admin-badges", [badge, otherBadge]);
+      controller = this.subject({model: [badge, otherBadge]});
 
-  this.stub(badge, 'destroy').returns(Ember.RSVP.resolve({}));
+  sinon.stub(badge, 'destroy').returns(Ember.RSVP.resolve({}));
 
   bootbox.confirm = function(text, yes, no, func) {
     func(false);
diff --git a/test/javascripts/admin/controllers/admin_email_index_controller_test.js b/test/javascripts/admin/controllers/admin_email_index_controller_test.js
index d5d780e1d..0456c5e50 100644
--- a/test/javascripts/admin/controllers/admin_email_index_controller_test.js
+++ b/test/javascripts/admin/controllers/admin_email_index_controller_test.js
@@ -1,5 +1,5 @@
-module("controller:admin-email-index");
+moduleFor("controller:admin-email-index");
 
 test("mixes in Discourse.Presence", function() {
-  ok(Discourse.Presence.detect(controllerFor("admin-email-index")));
+  ok(Discourse.Presence.detect(this.subject()));
 });
diff --git a/test/javascripts/admin/controllers/admin_email_preview_digest_controller_test.js b/test/javascripts/admin/controllers/admin_email_preview_digest_controller_test.js
index f42dbc178..e6aa17bfd 100644
--- a/test/javascripts/admin/controllers/admin_email_preview_digest_controller_test.js
+++ b/test/javascripts/admin/controllers/admin_email_preview_digest_controller_test.js
@@ -1,5 +1,5 @@
-module("controller:admin-email-preview-digest");
+moduleFor("controller:admin-email-preview-digest");
 
 test("mixes in Discourse.Presence", function() {
-  ok(Discourse.Presence.detect(controllerFor("admin-email-preview-digest")));
+  ok(Discourse.Presence.detect(this.subject()));
 });
diff --git a/test/javascripts/admin/controllers/admin_site_settings_controller_test.js b/test/javascripts/admin/controllers/admin_site_settings_controller_test.js
index 69472b294..a454bfa99 100644
--- a/test/javascripts/admin/controllers/admin_site_settings_controller_test.js
+++ b/test/javascripts/admin/controllers/admin_site_settings_controller_test.js
@@ -1,27 +1,20 @@
-module("controller:admin-site-settings", {
-  setup: function() {
-    sinon.stub(Ember.run, "debounce").callsArg(1);
-  },
-
-  teardown: function() {
-    Ember.run.debounce.restore();
-  }
-});
+moduleFor("controller:admin-site-settings");
 
 test("filter", function() {
-  var allSettings = Em.A([Ember.Object.create({
+  var allSettings = [Ember.Object.create({
     nameKey: 'users', name: 'users',
     siteSettings: [Discourse.SiteSetting.create({"setting":"username_change_period","description":"x","default":3,"type":"fixnum","value":"3","category":"users"})]
   }), Ember.Object.create({
     nameKey: 'posting', name: 'posting',
     siteSettings: [Discourse.SiteSetting.create({"setting":"display_name_on_posts","description":"x","default":false,"type":"bool","value":"true","category":"posting"})]
-  })]);
-  var adminSiteSettingsController = testController("admin-site-settings", allSettings);
+  })];
+  var adminSiteSettingsController = this.subject({ model: allSettings });
   adminSiteSettingsController.set('allSiteSettings', allSettings);
 
   equal(adminSiteSettingsController.get('content')[0].nameKey, 'users', "Can get first site setting category's name key.");
 
   adminSiteSettingsController.set('filter', 'username_change');
+
   equal(adminSiteSettingsController.get('content').length, 2, "a. Filter with one match for username_change");
   equal(adminSiteSettingsController.get('content')[0].nameKey, "all_results", "b. First element is all the results that match");
   equal(adminSiteSettingsController.get('content')[1].nameKey, "users", "c. Filter with one match for username_change");
diff --git a/test/javascripts/controllers/avatar_selector_controller_test.js b/test/javascripts/controllers/avatar_selector_controller_test.js
index e306752ea..8d7441d6e 100644
--- a/test/javascripts/controllers/avatar_selector_controller_test.js
+++ b/test/javascripts/controllers/avatar_selector_controller_test.js
@@ -1,7 +1,9 @@
-module("controller:avatar-selector");
+moduleFor("controller:avatar-selector", "controller:avatar-selector", {
+  needs: ['controller:modal']
+});
 
 test("avatarTemplate", function() {
-  var avatarSelectorController = controllerFor('avatar-selector');
+  var avatarSelectorController = this.subject();
   avatarSelectorController.setProperties({
     selected: "system",
     system_avatar_upload_id:1,
diff --git a/test/javascripts/controllers/create_account_controller_test.js b/test/javascripts/controllers/create_account_controller_test.js
index 8bdd59f70..3cb737c1b 100644
--- a/test/javascripts/controllers/create_account_controller_test.js
+++ b/test/javascripts/controllers/create_account_controller_test.js
@@ -1,8 +1,12 @@
-module("controller:create-account");
+moduleFor("controller:create-account", "controller:create-account", {
+  needs: ['controller:modal']
+});
 
 test('basicUsernameValidation', function() {
+  var subject = this.subject;
+
   var testInvalidUsername = function(username, expectedReason) {
-    var controller = controllerFor('create-account');
+    var controller = subject();
     controller.set('accountUsername', username);
     equal(controller.get('basicUsernameValidation.failed'), true, 'username should be invalid: ' + username);
     equal(controller.get('basicUsernameValidation.reason'), expectedReason, 'username validation reason: ' + username + ', ' + expectedReason);
@@ -12,7 +16,7 @@ test('basicUsernameValidation', function() {
   testInvalidUsername('x', I18n.t('user.username.too_short'));
   testInvalidUsername('123456789012345678901', I18n.t('user.username.too_long'));
 
-  var controller = controllerFor('create-account');
+  var controller = subject();
   controller.set('accountUsername',   'porkchops');
   controller.set('prefilledUsername', 'porkchops');
   equal(controller.get('basicUsernameValidation.ok'), true, 'Prefilled username is valid');
diff --git a/test/javascripts/controllers/flag_controller_test.js b/test/javascripts/controllers/flag_controller_test.js
index 505e812df..bea4949fe 100644
--- a/test/javascripts/controllers/flag_controller_test.js
+++ b/test/javascripts/controllers/flag_controller_test.js
@@ -13,7 +13,7 @@ var buildAdminUser = function(args) {
   }, args || {}));
 };
 
-module("controller:flag canDeleteSpammer");
+moduleFor("controller:flag");
 
 test("canDeleteSpammer not staff", function(){
   var flagController = controllerFor('flag', buildPost()); 
diff --git a/test/javascripts/controllers/notification_controller_test.js b/test/javascripts/controllers/notification_controller_test.js
index a1f4757fd..1481593ee 100644
--- a/test/javascripts/controllers/notification_controller_test.js
+++ b/test/javascripts/controllers/notification_controller_test.js
@@ -1,4 +1,3 @@
-var controller;
 var notificationFixture = {
   notification_type: 1, //mentioned
   post_number: 1,
@@ -10,36 +9,26 @@ var notificationFixture = {
   }
 };
 
-module("controller:notification", {
-  setup: function() {
-    controller = testController('notification', notificationFixture);
-  },
-
-  teardown: function() {
-    controller.set('model', null);
-  }
-});
+moduleFor("controller:notification");
 
 test("scope property is correct", function() {
+  var controller = this.subject(notificationFixture);
   equal(controller.get("scope"), "notifications.mentioned");
 });
 
 test("username property is correct", function() {
+  var controller = this.subject(notificationFixture);
   equal(controller.get("username"), "velesin");
 });
 
 test("link property returns empty string when there is no topic title", function() {
   var fixtureWithEmptyTopicTitle = _.extend({}, notificationFixture, {data: {topic_title: ""}});
-  Ember.run(function() {
-    controller.set("content", fixtureWithEmptyTopicTitle);
-  });
-
+  var controller = this.subject(fixtureWithEmptyTopicTitle);
   equal(controller.get("link"), "");
 });
 
 test("link property returns correctly built link when there is a topic title", function() {
-  var $link = $(controller.get("link"));
-
-  equal($link.attr("href"), "/t/a-slug/1234", "generated link points to a correct URL");
-  equal($link.text(), "some title", "generated link has correct text");
+  var controller = this.subject(notificationFixture);
+  ok(controller.get("link").indexOf('/t/a-slug/1234') !== -1, 'has the correct URL');
+  ok(controller.get("link").indexOf('some title') !== -1, 'has the correct title');
 });
diff --git a/test/javascripts/controllers/notifications_controller_test.js b/test/javascripts/controllers/notifications_controller_test.js
index 4f7fe77e9..f30af6f0a 100644
--- a/test/javascripts/controllers/notifications_controller_test.js
+++ b/test/javascripts/controllers/notifications_controller_test.js
@@ -1,83 +1,11 @@
-var controller, view;
-
-var appendView = function() {
-  Ember.run(function() {
-    view.appendTo(fixture());
-  });
-};
-
-var noItemsMessageSelector = "div.none";
-var itemListSelector = "ul";
-var itemSelector = "li";
-
-module("controller:notifications", {
-  setup: function() {
-    sinon.stub(I18n, "t", function (scope, options) {
-      options = options || {};
-      return [scope, options.username, options.link].join(" ").trim();
-    });
-
-    controller = testController('notifications');
-
-    view = Ember.View.create({
-      container: Discourse.__container__,
-      controller: controller,
-      templateName: "notifications"
-    });
-  },
-
-  teardown: function() {
-    I18n.t.restore();
-  }
+moduleFor('controller:notifications', 'controller:notifications', {
+  needs: ['controller:header']
 });
 
 test("mixes in HasCurrentUser", function() {
-  ok(Discourse.HasCurrentUser.detect(controller));
+  ok(Discourse.HasCurrentUser.detect(this.subject()));
 });
 
 test("by default uses NotificationController as its item controller", function() {
-  equal(controller.get("itemController"), "notification");
-});
-
-test("shows proper info when there are no notifications", function() {
-  controller.set("content", null);
-
-  appendView();
-
-  ok(exists(fixture(noItemsMessageSelector)), "special 'no notifications' message is displayed");
-  equal(fixture(noItemsMessageSelector).text(), "notifications.none", "'no notifications' message contains proper internationalized text");
-  equal(count(fixture(itemListSelector)), 0, "a list of notifications is not displayed");
-});
-
-test("displays a list of notifications and a 'more' link when there are notifications", function() {
-  controller.set("itemController", null);
-  controller.set("content", [
-    {
-      read: false,
-      scope: "scope_1",
-      username: "username_1",
-      link: "link_1"
-    },
-    {
-      read: true,
-      scope: "scope_2",
-      username: "username_2",
-      link: "link_2"
-    }
-  ]);
-
-  appendView();
-
-  var items = fixture(itemSelector);
-  equal(count(items), 3, "number of list items is correct");
-
-  equal(items.eq(0).attr("class"), "ember-view", "first (unread) item has proper class");
-  equal(items.eq(0).text().trim(), "scope_1 username_1 link_1", "first item has correct content");
-
-  equal(items.eq(1).attr("class"), "ember-view read", "second (read) item has proper class");
-  equal(items.eq(1).text().trim(), "scope_2 username_2 link_2", "second item has correct content");
-
-  var moreLink = items.eq(2).find("> a");
-  equal(moreLink.attr("href"), Discourse.User.current().get("path"), "'more' link points to a correct URL");
-  equal(moreLink.text(), "notifications.more …", "'more' link has correct text");
+  equal(this.subject().get("itemController"), "notification");
 });
diff --git a/test/javascripts/controllers/topic_controller_test.js b/test/javascripts/controllers/topic_controller_test.js
index c99a84dc3..6cae2006a 100644
--- a/test/javascripts/controllers/topic_controller_test.js
+++ b/test/javascripts/controllers/topic_controller_test.js
@@ -1,4 +1,7 @@
-module("Discourse.TopicController");
+moduleFor('controller:topic', 'controller:topic', {
+  needs: ['controller:header', 'controller:modal', 'controller:composer', 'controller:quote-button',
+          'controller:search', 'controller:topic-progress']
+});
 
 var buildTopic = function() {
   return Discourse.Topic.create({
@@ -11,9 +14,10 @@ var buildTopic = function() {
   });
 };
 
+
 test("editingMode", function() {
   var topic = buildTopic(),
-      topicController = testController(Discourse.TopicController, topic);
+      topicController = this.subject({model: topic});
 
   ok(!topicController.get('editingTopic'), "we are not editing by default");
 
@@ -32,7 +36,7 @@ test("editingMode", function() {
 });
 
 test("toggledSelectedPost", function() {
-  var tc = testController(Discourse.TopicController, buildTopic()),
+  var tc = this.subject({ model: buildTopic() }),
       post = Discourse.Post.create({id: 123, post_number: 2}),
       postStream = tc.get('postStream');
 
@@ -54,7 +58,7 @@ test("toggledSelectedPost", function() {
 });
 
 test("selectAll", function() {
-  var tc = testController(Discourse.TopicController, buildTopic()),
+  var tc = this.subject({model: buildTopic()}),
       post = Discourse.Post.create({id: 123, post_number: 2}),
       postStream = tc.get('postStream');
 
@@ -72,7 +76,7 @@ test("selectAll", function() {
 
 test("Automating setting of allPostsSelected", function() {
   var topic = buildTopic(),
-      tc = testController(Discourse.TopicController, topic),
+      tc = this.subject({model: topic}),
       post = Discourse.Post.create({id: 123, post_number: 2}),
       postStream = tc.get('postStream');
 
@@ -89,7 +93,7 @@ test("Automating setting of allPostsSelected", function() {
 
 test("Select Replies when present", function() {
   var topic = buildTopic(),
-      tc = testController(Discourse.TopicController, topic),
+      tc = this.subject({ model: topic }),
       p1 = Discourse.Post.create({id: 1, post_number: 1, reply_count: 1}),
       p2 = Discourse.Post.create({id: 2, post_number: 2}),
       p3 = Discourse.Post.create({id: 2, post_number: 3, reply_to_post_number: 1});
diff --git a/test/javascripts/helpers/init-ember-qunit.js b/test/javascripts/helpers/init-ember-qunit.js
new file mode 100644
index 000000000..abd0e9160
--- /dev/null
+++ b/test/javascripts/helpers/init-ember-qunit.js
@@ -0,0 +1,4 @@
+/* global emq */
+
+emq.globalize();
+emq.setResolver(Discourse.Resolver.create({ namespace: Discourse }));
diff --git a/test/javascripts/helpers/qunit_helpers.js b/test/javascripts/helpers/qunit_helpers.js
index 8b938827e..55bbef322 100644
--- a/test/javascripts/helpers/qunit_helpers.js
+++ b/test/javascripts/helpers/qunit_helpers.js
@@ -26,29 +26,6 @@ function integration(name, lifecycle) {
   });
 }
 
-function testController(klass, model) {
-  // HAX until we get ES6 everywhere:
-  if (typeof klass === "string") {
-    var base = "discourse",
-        moduleName,
-        module;
-
-    // maybe a bit too hacky? (all of the "admin-*" controllers are in the "admin" directory)
-    if (klass.indexOf("admin") === 0) {
-      base = "admin";
-    }
-
-    moduleName = base + '/controllers/' + klass;
-    module = requirejs.entries[moduleName];
-
-    if (module) {
-      klass = require(moduleName, null, null, true).default;
-    }
-  }
-
-  return klass.create({model: model, container: Discourse.__container__});
-}
-
 function controllerFor(controller, model) {
   controller = Discourse.__container__.lookup('controller:' + controller);
   if (model) { controller.set('model', model ); }
diff --git a/test/javascripts/test_helper.js b/test/javascripts/test_helper.js
index 8cf40d993..adc8ca682 100644
--- a/test/javascripts/test_helper.js
+++ b/test/javascripts/test_helper.js
@@ -14,6 +14,7 @@
 //= require handlebars.js
 //= require development/ember.js
 //= require message-bus.js
+//= require ember-qunit.js
 
 //= require ../../app/assets/javascripts/locales/i18n
 //= require ../../app/assets/javascripts/discourse/helpers/i18n_helpers
@@ -41,6 +42,7 @@
 //= require helpers/qunit_helpers
 //= require helpers/assertions
 
+//= require helpers/init-ember-qunit
 //= require_tree ./fixtures
 //= require_tree ./lib
 //= require_tree .
@@ -95,5 +97,11 @@ QUnit.testStart(function() {
   Discourse.SiteSettings = jQuery.extend(true, {}, Discourse.SiteSettingsOriginal);
   Discourse.BaseUri = "/";
   Discourse.BaseUrl = "";
+
+  // Never debounce in test, just makes testing harder
+  sinon.stub(Ember.run, "debounce").callsArg(1)
 });
 
+QUnit.testDone(function() {
+  Ember.run.debounce.restore();
+});
diff --git a/vendor/assets/javascripts/ember-qunit.js b/vendor/assets/javascripts/ember-qunit.js
new file mode 100644
index 000000000..3bb231499
--- /dev/null
+++ b/vendor/assets/javascripts/ember-qunit.js
@@ -0,0 +1,282 @@
+!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<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
+"use strict";
+var testResolver = _dereq_("./test-resolver")["default"] || _dereq_("./test-resolver");
+var Ember = window.Ember["default"] || window.Ember;
+
+exports["default"] = function isolatedContainer(fullNames) {
+  var resolver = testResolver.get();
+  var container = new Ember.Container();
+  container.optionsForType('component', { singleton: false });
+  container.optionsForType('view', { singleton: false });
+  container.optionsForType('template', { instantiate: false });
+  container.optionsForType('helper', { instantiate: false });
+  container.register('component-lookup:main', Ember.ComponentLookup);
+  for (var i = fullNames.length; i > 0; i--) {
+    var fullName = fullNames[i - 1];
+    container.register(fullName, resolver.resolve(fullName));
+  }
+  return container;
+}
+},{"./test-resolver":7}],2:[function(_dereq_,module,exports){
+"use strict";
+var Ember = window.Ember["default"] || window.Ember;
+var isolatedContainer = _dereq_("./isolated-container")["default"] || _dereq_("./isolated-container");
+var moduleFor = _dereq_("./module-for")["default"] || _dereq_("./module-for");
+var moduleForComponent = _dereq_("./module-for-component")["default"] || _dereq_("./module-for-component");
+var moduleForModel = _dereq_("./module-for-model")["default"] || _dereq_("./module-for-model");
+var test = _dereq_("./test")["default"] || _dereq_("./test");
+var testResolver = _dereq_("./test-resolver")["default"] || _dereq_("./test-resolver");
+
+Ember.testing = true;
+
+function setResolver(resolver) {
+  testResolver.set(resolver);
+}
+
+function globalize() {
+  window.moduleFor = moduleFor;
+  window.moduleForComponent = moduleForComponent;
+  window.moduleForModel = moduleForModel;
+  window.test = test;
+  window.setResolver = setResolver;
+}
+
+exports.globalize = globalize;
+exports.moduleFor = moduleFor;
+exports.moduleForComponent = moduleForComponent;
+exports.moduleForModel = moduleForModel;
+exports.test = test;
+exports.setResolver = setResolver;
+},{"./isolated-container":1,"./module-for":5,"./module-for-component":3,"./module-for-model":4,"./test":8,"./test-resolver":7}],3:[function(_dereq_,module,exports){
+"use strict";
+var testResolver = _dereq_("./test-resolver")["default"] || _dereq_("./test-resolver");
+var moduleFor = _dereq_("./module-for")["default"] || _dereq_("./module-for");
+var Ember = window.Ember["default"] || window.Ember;
+
+exports["default"] = function moduleForComponent(name, description, callbacks) {
+  var resolver = testResolver.get();
+
+  moduleFor('component:' + name, description, callbacks, function(container, context, defaultSubject) {
+    var layoutName = 'template:components/' + name;
+
+    var layout = resolver.resolve(layoutName);
+
+    if (layout) {
+      container.register(layoutName, layout);
+      container.injection('component:' + name, 'layout', layoutName);
+    }
+
+    context.dispatcher = Ember.EventDispatcher.create();
+    context.dispatcher.setup({}, '#ember-testing');
+
+    context.__setup_properties__.render = function() {
+      var containerView = Ember.ContainerView.create({container: container});
+      var view = Ember.run(function(){
+        var subject = context.subject();
+        containerView.pushObject(subject);
+        // TODO: destory this somewhere
+        containerView.appendTo('#ember-testing');
+        return subject;
+      });
+
+      return view.$();
+    };
+
+    context.__setup_properties__.append = function(){
+      Ember.deprecate('this.append() is deprecated. Please use this.render() instead.');
+      return this.render();
+    };
+
+    context.$ = function(){
+      var $view = this.render(), subject = this.subject();
+
+      if(arguments.length){
+        return subject.$.apply(subject, arguments);
+      }else{
+        return $view;
+      }
+    };
+  });
+}
+},{"./module-for":5,"./test-resolver":7}],4:[function(_dereq_,module,exports){
+"use strict";
+var moduleFor = _dereq_("./module-for")["default"] || _dereq_("./module-for");
+var Ember = window.Ember["default"] || window.Ember;
+
+exports["default"] = function moduleForModel(name, description, callbacks) {
+  if (!DS) throw new Error('You must have Ember Data installed to use `moduleForModel`.');
+
+  moduleFor('model:' + name, description, callbacks, function(container, context, defaultSubject) {
+    if (DS._setupContainer) {
+      DS._setupContainer(container);
+    } else {
+      container.register('store:main', DS.Store);
+    }
+
+    var adapterFactory = container.lookupFactory('adapter:application');
+    if (!adapterFactory) {
+      container.register('adapter:application', DS.FixtureAdapter);
+    }
+
+    context.__setup_properties__.store = function(){
+      return container.lookup('store:main');
+    };
+
+    if (context.__setup_properties__.subject === defaultSubject) {
+      context.__setup_properties__.subject = function(options) {
+        return Ember.run(function() {
+          return container.lookup('store:main').createRecord(name, options);
+        });
+      };
+    }
+  });
+}
+},{"./module-for":5}],5:[function(_dereq_,module,exports){
+"use strict";
+var Ember = window.Ember["default"] || window.Ember;
+//import QUnit from 'qunit'; // Assumed global in runner
+var testContext = _dereq_("./test-context")["default"] || _dereq_("./test-context");
+var isolatedContainer = _dereq_("./isolated-container")["default"] || _dereq_("./isolated-container");
+
+exports["default"] = function moduleFor(fullName, description, callbacks, delegate) {
+  var container;
+  var context;
+  
+  var _callbacks = {
+    setup: function(){
+      callbacks = callbacks || { };
+
+      var needs = [fullName].concat(callbacks.needs || []);
+      container = isolatedContainer(needs);
+
+      callbacks.subject   = callbacks.subject || defaultSubject;
+
+      callbacks.setup     = callbacks.setup    || function() { };
+      callbacks.teardown  = callbacks.teardown || function() { };
+      
+      function factory() {
+        return container.lookupFactory(fullName);
+      }
+      
+      testContext.set({
+        container:            container,
+        factory:              factory,
+        dispatcher:           null,
+        __setup_properties__: callbacks
+      });
+      
+      context = testContext.get();
+
+      if (delegate) {
+        delegate(container, context, defaultSubject);
+      }
+      
+      if (Ember.$('#ember-testing').length === 0) {
+        Ember.$('<div id="ember-testing"/>').appendTo(document.body);
+      }
+      
+      buildContextVariables(context);
+      callbacks.setup.call(context, container);
+    },
+
+    teardown: function(){
+      Ember.run(function(){
+        container.destroy();
+        
+        if (context.dispatcher) {
+          context.dispatcher.destroy();
+        }
+      });
+      
+      callbacks.teardown(container);
+      Ember.$('#ember-testing').empty();
+    }
+  };
+
+  QUnit.module(description || fullName, _callbacks);
+}
+
+function defaultSubject(options, factory) {
+  return factory.create(options);
+}
+
+// allow arbitrary named factories, like rspec let
+function buildContextVariables(context) {
+  var cache     = { };
+  var callbacks = context.__setup_properties__;
+  var container = context.container;
+  var factory   = context.factory;
+    
+  Ember.keys(callbacks).filter(function(key){
+    // ignore the default setup/teardown keys
+    return key !== 'setup' && key !== 'teardown';
+  }).forEach(function(key){
+    context[key] = function(options) {
+      if (cache[key]) { return cache[key]; }
+
+      var result = callbacks[key](options, factory(), container);
+      cache[key] = result;
+      return result;
+    };
+  });
+}
+},{"./isolated-container":1,"./test-context":6}],6:[function(_dereq_,module,exports){
+"use strict";
+var __test_context__;
+
+function set(context) {
+  __test_context__ = context;
+}
+
+exports.set = set;function get() {
+  return __test_context__;
+}
+
+exports.get = get;
+},{}],7:[function(_dereq_,module,exports){
+"use strict";
+var __resolver__;
+
+function set(resolver) {
+  __resolver__ = resolver;
+}
+
+exports.set = set;function get() {
+  if (__resolver__ == null) throw new Error('you must set a resolver with `testResolver.set(resolver)`');
+  return __resolver__;
+}
+
+exports.get = get;
+},{}],8:[function(_dereq_,module,exports){
+"use strict";
+var Ember = window.Ember["default"] || window.Ember;
+//import QUnit from 'qunit'; // Assumed global in runner
+var testContext = _dereq_("./test-context")["default"] || _dereq_("./test-context");
+
+function resetViews() {
+  Ember.View.views = {};
+}
+
+exports["default"] = function test(testName, callback) {
+
+  function wrapper() {
+    var context = testContext.get();
+    
+    resetViews();
+    var result = callback.call(context);
+
+    function failTestOnPromiseRejection(reason) {
+      ok(false, reason);
+    }
+
+    Ember.run(function(){
+      stop();
+      Ember.RSVP.Promise.cast(result)['catch'](failTestOnPromiseRejection)['finally'](start);
+    });
+  }
+
+  QUnit.test(testName, wrapper);
+}
+},{"./test-context":6}]},{},[2])
+(2)
+});
\ No newline at end of file