diff --git a/app/assets/javascripts/discourse/components/create-topics-notice.js.es6 b/app/assets/javascripts/discourse/components/create-topics-notice.js.es6
index 9f502ec7c..9481bfbd4 100644
--- a/app/assets/javascripts/discourse/components/create-topics-notice.js.es6
+++ b/app/assets/javascripts/discourse/components/create-topics-notice.js.es6
@@ -54,23 +54,17 @@ export default Ember.Component.extend({
     }));
   },
 
-  @computed()
-  topicTrackingState() {
-    return Discourse.TopicTrackingState.current();
-  },
-
   @observes('topicTrackingState.incomingCount')
   fetchLiveStats() {
     if (!this.get('enabled')) { return; }
 
-    var self = this;
-    LivePostCounts.find().then(function(stats) {
+    LivePostCounts.find().then((stats) => {
       if(stats) {
-        self.set('publicTopicCount', stats.get('public_topic_count'));
-        self.set('publicPostCount', stats.get('public_post_count'));
-        if (self.get('publicTopicCount') >= self.get('requiredTopics')
-            && self.get('publicPostCount') >= self.get('requiredPosts')) {
-          self.set('enabled', false); // No more checks
+        this.set('publicTopicCount', stats.get('public_topic_count'));
+        this.set('publicPostCount', stats.get('public_post_count'));
+        if (this.get('publicTopicCount') >= this.get('requiredTopics')
+            && this.get('publicPostCount') >= this.get('requiredPosts')) {
+          this.set('enabled', false); // No more checks
         }
       }
     });
diff --git a/app/assets/javascripts/discourse/components/edit-category-general.js.es6 b/app/assets/javascripts/discourse/components/edit-category-general.js.es6
index 5d323ce06..e26c24a21 100644
--- a/app/assets/javascripts/discourse/components/edit-category-general.js.es6
+++ b/app/assets/javascripts/discourse/components/edit-category-general.js.es6
@@ -1,6 +1,7 @@
 import DiscourseURL from 'discourse/lib/url';
 import { buildCategoryPanel } from 'discourse/components/edit-category-panel';
 import { categoryBadgeHTML } from 'discourse/helpers/category-link';
+import Category from 'discourse/models/category';
 
 export default buildCategoryPanel('general', {
   foregroundColors: ['FFFFFF', '000000'],
@@ -31,7 +32,7 @@ export default buildCategoryPanel('general', {
 
   categoryBadgePreview: function() {
     const category = this.get('category');
-    const c = Discourse.Category.create({
+    const c = Category.create({
       name: category.get('categoryName'),
       color: category.get('color'),
       text_color: category.get('text_color'),
@@ -45,7 +46,7 @@ export default buildCategoryPanel('general', {
   // We can change the parent if there are no children
   subCategories: function() {
     if (Ember.isEmpty(this.get('category.id'))) { return null; }
-    return Discourse.Category.list().filterBy('parent_category_id', this.get('category.id'));
+    return Category.list().filterBy('parent_category_id', this.get('category.id'));
   }.property('category.id'),
 
   showDescription: function() {
diff --git a/app/assets/javascripts/discourse/components/hamburger-menu.js.es6 b/app/assets/javascripts/discourse/components/hamburger-menu.js.es6
index d3b5cc57a..a3c077748 100644
--- a/app/assets/javascripts/discourse/components/hamburger-menu.js.es6
+++ b/app/assets/javascripts/discourse/components/hamburger-menu.js.es6
@@ -22,11 +22,6 @@ export default Ember.Component.extend({
     return this.siteSettings.faq_url ? this.siteSettings.faq_url : Discourse.getURL('/faq');
   },
 
-  @computed()
-  topicTrackingState() {
-    return Discourse.TopicTrackingState.current();
-  },
-
   _lookupCount(type) {
     const state = this.get('topicTrackingState');
     return state ? state.lookupCount(type) : 0;
diff --git a/app/assets/javascripts/discourse/controllers/discovery/categories.js.es6 b/app/assets/javascripts/discourse/controllers/discovery/categories.js.es6
index ebda2c04a..ba9877d48 100644
--- a/app/assets/javascripts/discourse/controllers/discovery/categories.js.es6
+++ b/app/assets/javascripts/discourse/controllers/discovery/categories.js.es6
@@ -19,8 +19,8 @@ export default DiscoveryController.extend({
       this.set('controllers.discovery.loading', true);
 
       const parentCategory = this.get('model.parentCategory');
-      const promise = parentCategory ? Discourse.CategoryList.listForParent(parentCategory) :
-                                       Discourse.CategoryList.list();
+      const promise = parentCategory ? Discourse.CategoryList.listForParent(this.store, parentCategory) :
+                                       Discourse.CategoryList.list(this.store);
 
       const self = this;
       promise.then(function(list) {
diff --git a/app/assets/javascripts/discourse/controllers/discovery/topics.js.es6 b/app/assets/javascripts/discourse/controllers/discovery/topics.js.es6
index 772c8e4c5..45716ae2e 100644
--- a/app/assets/javascripts/discourse/controllers/discovery/topics.js.es6
+++ b/app/assets/javascripts/discourse/controllers/discovery/topics.js.es6
@@ -29,8 +29,8 @@ const controllerOpts = {
     },
 
     // Show newly inserted topics
-    showInserted: function() {
-      const tracker = Discourse.TopicTrackingState.current();
+    showInserted() {
+      const tracker = this.topicTrackingState;
 
       // Move inserted into topics
       this.get('content').loadBefore(tracker.get('newIncoming'));
@@ -38,9 +38,8 @@ const controllerOpts = {
       return false;
     },
 
-    refresh: function() {
-      const filter = this.get('model.filter'),
-          self = this;
+    refresh() {
+      const filter = this.get('model.filter');
 
       this.setProperties({ order: 'default', ascending: false });
 
@@ -52,36 +51,27 @@ const controllerOpts = {
       // Lesson learned: Don't call `loading` yourself.
       this.set('controllers.discovery.loading', true);
 
-      this.store.findFiltered('topicList', {filter}).then(function(list) {
-        Discourse.TopicList.hideUniformCategory(list, self.get('category'));
+      this.store.findFiltered('topicList', {filter}).then((list) => {
+        Discourse.TopicList.hideUniformCategory(list, this.get('category'));
 
-        self.setProperties({ model: list });
-        self.resetSelected();
+        this.setProperties({ model: list });
+        this.resetSelected();
 
-        const tracking = Discourse.TopicTrackingState.current();
-        if (tracking) {
-          tracking.sync(list, filter);
+        if (this.topicTrackingState) {
+          this.topicTrackingState.sync(list, filter);
         }
 
-        self.send('loadingComplete');
+        this.send('loadingComplete');
       });
     },
 
 
-    resetNew: function() {
-      const self = this;
-
-      Discourse.TopicTrackingState.current().resetNew();
-      Discourse.Topic.resetNew().then(function() {
-        self.send('refresh');
-      });
+    resetNew() {
+      this.topicTrackingState.resetNew();
+      Discourse.Topic.resetNew().then(() => this.send('refresh'));
     }
   },
 
-  topicTrackingState: function() {
-    return Discourse.TopicTrackingState.current();
-  }.property(),
-
   isFilterPage: function(filter, filterType) {
     if (!filter) { return false; }
     return filter.match(new RegExp(filterType + '$', 'gi')) ? true : false;
@@ -96,7 +86,7 @@ const controllerOpts = {
   }.property('model.filter', 'model.topics.length'),
 
   tooManyTracked: function(){
-      return Discourse.TopicTrackingState.current().tooManyTracked();
+    return this.topicTrackingState.tooManyTracked();
   }.property(),
 
   showDismissAtTop: function() {
diff --git a/app/assets/javascripts/discourse/lib/screen-track.js.es6 b/app/assets/javascripts/discourse/lib/screen-track.js.es6
index 3d55418cf..4bac0e521 100644
--- a/app/assets/javascripts/discourse/lib/screen-track.js.es6
+++ b/app/assets/javascripts/discourse/lib/screen-track.js.es6
@@ -9,6 +9,9 @@ const ScreenTrack = Ember.Object.extend({
 
   init() {
     this.reset();
+
+    // TODO: Move `ScreenTrack` to injection and remove this
+    this.set('topicTrackingState', Discourse.__container__.lookup('topic-tracking-state:main'));
   },
 
   start(topicId, topicController) {
@@ -112,7 +115,7 @@ const ScreenTrack = Ember.Object.extend({
       highestSeenByTopic[topicId] = highestSeen;
     }
 
-    Discourse.TopicTrackingState.current().updateSeen(topicId, highestSeen);
+    this.topicTrackingState.updateSeen(topicId, highestSeen);
 
     if (!$.isEmptyObject(newTimings)) {
       Discourse.ajax('/topics/timings', {
diff --git a/app/assets/javascripts/discourse/mixins/bulk-topic-selection.js.es6 b/app/assets/javascripts/discourse/mixins/bulk-topic-selection.js.es6
index a30cba1f9..c0e7650d8 100644
--- a/app/assets/javascripts/discourse/mixins/bulk-topic-selection.js.es6
+++ b/app/assets/javascripts/discourse/mixins/bulk-topic-selection.js.es6
@@ -36,7 +36,7 @@ export default Ember.Mixin.create({
       }
       promise.then(function(result) {
         if (result && result.topic_ids) {
-          const tracker = Discourse.TopicTrackingState.current();
+          const tracker = self.topicTrackingState;
           result.topic_ids.forEach(function(t) {
             tracker.removeTopic(t);
           });
diff --git a/app/assets/javascripts/discourse/models/category-list.js.es6 b/app/assets/javascripts/discourse/models/category-list.js.es6
new file mode 100644
index 000000000..fcbe90bd0
--- /dev/null
+++ b/app/assets/javascripts/discourse/models/category-list.js.es6
@@ -0,0 +1,60 @@
+const CategoryList = Ember.ArrayProxy.extend({
+  init() {
+    this.set('content', []);
+    this._super();
+  }
+});
+
+CategoryList.reopenClass({
+  categoriesFrom(store, result) {
+    const categories = Discourse.CategoryList.create();
+    const users = Discourse.Model.extractByKey(result.featured_users, Discourse.User);
+    const list = Discourse.Category.list();
+
+    result.category_list.categories.forEach(function(c) {
+      if (c.parent_category_id) {
+        c.parentCategory = list.findBy('id', c.parent_category_id);
+      }
+
+      if (c.subcategory_ids) {
+        c.subcategories = c.subcategory_ids.map(scid => list.findBy('id', parseInt(scid, 10)));
+      }
+
+      if (c.featured_user_ids) {
+        c.featured_users = c.featured_user_ids.map(u => users[u]);
+      }
+
+      if (c.topics) {
+        c.topics = c.topics.map(t => Discourse.Topic.create(t));
+      }
+
+      categories.pushObject(store.createRecord('category', c));
+    });
+    return categories;
+  },
+
+  listForParent(store, category) {
+    return Discourse.ajax('/categories.json?parent_category_id=' + category.get('id')).then((result) => {
+      return Discourse.CategoryList.create({
+        categories: this.categoriesFrom(store, result),
+        parentCategory: category
+      });
+    });
+  },
+
+  list(store) {
+    const getCategories = () => Discourse.ajax("/categories.json");
+    return PreloadStore.getAndRemove("categories_list", getCategories).then((result) => {
+      return Discourse.CategoryList.create({
+        categories: this.categoriesFrom(store, result),
+        can_create_category: result.category_list.can_create_category,
+        can_create_topic: result.category_list.can_create_topic,
+        draft_key: result.category_list.draft_key,
+        draft: result.category_list.draft,
+        draft_sequence: result.category_list.draft_sequence
+      });
+    });
+  }
+});
+
+export default CategoryList;
diff --git a/app/assets/javascripts/discourse/models/category.js b/app/assets/javascripts/discourse/models/category.js.es6
similarity index 85%
rename from app/assets/javascripts/discourse/models/category.js
rename to app/assets/javascripts/discourse/models/category.js.es6
index 33b57894a..fd99d494b 100644
--- a/app/assets/javascripts/discourse/models/category.js
+++ b/app/assets/javascripts/discourse/models/category.js.es6
@@ -1,4 +1,6 @@
-Discourse.Category = Discourse.Model.extend({
+import RestModel from 'discourse/models/rest';
+
+const Category = RestModel.extend({
 
   init: function() {
     this._super();
@@ -26,7 +28,7 @@ Discourse.Category = Discourse.Model.extend({
   }.property('id'),
 
   url: function() {
-    return Discourse.getURL("/c/") + Discourse.Category.slugFor(this);
+    return Discourse.getURL("/c/") + Category.slugFor(this);
   }.property('name'),
 
   fullSlug: function() {
@@ -129,16 +131,12 @@ Discourse.Category = Discourse.Model.extend({
     }
   }.property('topics'),
 
-  topicTrackingState: function(){
-    return Discourse.TopicTrackingState.current();
-  }.property(),
-
-  unreadTopics: function(){
-    return this.get('topicTrackingState').countUnread(this.get('id'));
+  unreadTopics: function() {
+    return this.topicTrackingState.countUnread(this.get('id'));
   }.property('topicTrackingState.messageCount'),
 
-  newTopics: function(){
-    return this.get('topicTrackingState').countNew(this.get('id'));
+  newTopics: function() {
+    return this.topicTrackingState.countNew(this.get('id'));
   }.property('topicTrackingState.messageCount'),
 
   topicStatsTitle: function() {
@@ -193,10 +191,10 @@ Discourse.Category = Discourse.Model.extend({
 
 var _uncategorized;
 
-Discourse.Category.reopenClass({
+Category.reopenClass({
 
   findUncategorized: function() {
-    _uncategorized = _uncategorized || Discourse.Category.list().findBy('id', Discourse.Site.currentProp('uncategorized_category_id'));
+    _uncategorized = _uncategorized || Category.list().findBy('id', Discourse.Site.currentProp('uncategorized_category_id'));
     return _uncategorized;
   },
 
@@ -207,7 +205,7 @@ Discourse.Category.reopenClass({
         result = "";
 
     if (parentCategory) {
-      result = Discourse.Category.slugFor(parentCategory) + "/";
+      result = Category.slugFor(parentCategory) + "/";
     }
 
     var id = Em.get(category, 'id'),
@@ -234,20 +232,20 @@ Discourse.Category.reopenClass({
   },
 
   findSingleBySlug: function(slug) {
-    return Discourse.Category.list().find(function(c) {
-      return Discourse.Category.slugFor(c) === slug;
+    return Category.list().find(function(c) {
+      return Category.slugFor(c) === slug;
     });
   },
 
   findById: function(id) {
     if (!id) { return; }
-    return Discourse.Category.idMap()[id];
+    return Category.idMap()[id];
   },
 
   findByIds: function(ids){
     var categories = [];
     _.each(ids, function(id){
-      var found = Discourse.Category.findById(id);
+      var found = Category.findById(id);
       if(found){
         categories.push(found);
       }
@@ -256,20 +254,20 @@ Discourse.Category.reopenClass({
   },
 
   findBySlug: function(slug, parentSlug) {
-    var categories = Discourse.Category.list(),
+    var categories = Category.list(),
         category;
 
     if (parentSlug) {
-      var parentCategory = Discourse.Category.findSingleBySlug(parentSlug);
+      var parentCategory = Category.findSingleBySlug(parentSlug);
       if (parentCategory) {
         if (slug === 'none') { return parentCategory; }
 
         category = categories.find(function(item) {
-          return item && item.get('parentCategory') === parentCategory && Discourse.Category.slugFor(item) === (parentSlug + "/" + slug);
+          return item && item.get('parentCategory') === parentCategory && Category.slugFor(item) === (parentSlug + "/" + slug);
         });
       }
     } else {
-      category = Discourse.Category.findSingleBySlug(slug);
+      category = Category.findSingleBySlug(slug);
 
       // If we have a parent category, we need to enforce it
       if (category && category.get('parentCategory')) return;
@@ -283,9 +281,9 @@ Discourse.Category.reopenClass({
     return category;
   },
 
-  reloadById: function(id) {
-    return Discourse.ajax("/c/" + id + "/show.json").then(function (result) {
-      return Discourse.Category.create(result.category);
-    });
+  reloadById(id) {
+    return Discourse.ajax("/c/" + id + "/show.json");
   }
 });
+
+export default Category;
diff --git a/app/assets/javascripts/discourse/models/category_list.js b/app/assets/javascripts/discourse/models/category_list.js
deleted file mode 100644
index bd1e1711f..000000000
--- a/app/assets/javascripts/discourse/models/category_list.js
+++ /dev/null
@@ -1,68 +0,0 @@
-Discourse.CategoryList = Ember.ArrayProxy.extend({
-  init: function() {
-    this.set('content', []);
-    this._super();
-  }
-});
-
-Discourse.CategoryList.reopenClass({
-  categoriesFrom: function(result) {
-    var categories = Discourse.CategoryList.create(),
-        users = Discourse.Model.extractByKey(result.featured_users, Discourse.User),
-        list = Discourse.Category.list();
-
-    result.category_list.categories.forEach(function(c) {
-
-      if (c.parent_category_id) {
-        c.parentCategory = list.findBy('id', c.parent_category_id);
-      }
-
-      if (c.subcategory_ids) {
-        c.subcategories = c.subcategory_ids.map(function(scid) { return list.findBy('id', parseInt(scid, 10)); });
-      }
-
-      if (c.featured_user_ids) {
-        c.featured_users = c.featured_user_ids.map(function(u) {
-          return users[u];
-        });
-      }
-      if (c.topics) {
-        c.topics = c.topics.map(function(t) {
-          return Discourse.Topic.create(t);
-        });
-      }
-
-      categories.pushObject(Discourse.Category.create(c));
-
-    });
-    return categories;
-  },
-
-  listForParent: function(category) {
-    var self = this;
-    return Discourse.ajax('/categories.json?parent_category_id=' + category.get('id')).then(function(result) {
-      return Discourse.CategoryList.create({
-        categories: self.categoriesFrom(result),
-        parentCategory: category
-      });
-    });
-  },
-
-  list: function() {
-    var self = this;
-
-    return PreloadStore.getAndRemove("categories_list", function() {
-      return Discourse.ajax("/categories.json");
-    }).then(function(result) {
-      return Discourse.CategoryList.create({
-        categories: self.categoriesFrom(result),
-        can_create_category: result.category_list.can_create_category,
-        can_create_topic: result.category_list.can_create_topic,
-        draft_key: result.category_list.draft_key,
-        draft: result.category_list.draft,
-        draft_sequence: result.category_list.draft_sequence
-      });
-    });
-  }
-
-});
diff --git a/app/assets/javascripts/discourse/models/composer.js.es6 b/app/assets/javascripts/discourse/models/composer.js.es6
index ad4115c8b..a59a2f8f0 100644
--- a/app/assets/javascripts/discourse/models/composer.js.es6
+++ b/app/assets/javascripts/discourse/models/composer.js.es6
@@ -689,13 +689,6 @@ const Composer = RestModel.extend({
 });
 
 Composer.reopenClass({
-
-  open(opts) {
-    const composer = Composer.create();
-    composer.open(opts);
-    return composer;
-  },
-
   loadDraft(opts) {
     opts = opts || {};
 
diff --git a/app/assets/javascripts/discourse/models/nav-item.js.es6 b/app/assets/javascripts/discourse/models/nav-item.js.es6
index d4e5ef228..2a424c64f 100644
--- a/app/assets/javascripts/discourse/models/nav-item.js.es6
+++ b/app/assets/javascripts/discourse/models/nav-item.js.es6
@@ -20,10 +20,6 @@ const NavItem = Discourse.Model.extend({
     return I18n.t("filters." + name.replace("/", ".") + ".title", extra);
   }.property('categoryName', 'name', 'count'),
 
-  topicTrackingState: function() {
-    return Discourse.TopicTrackingState.current();
-  }.property(),
-
   categoryName: function() {
     var split = this.get('name').split('/');
     return split[0] === 'category' ? split[1] : null;
@@ -100,7 +96,9 @@ NavItem.reopenClass({
       extra = cb.call(self, text, opts);
       _.merge(args, extra);
     });
-    return Discourse.NavItem.create(args);
+
+    const store = Discourse.__container__.lookup('store:main');
+    return store.createRecord('nav-item', args);
   },
 
   buildList(category, args) {
diff --git a/app/assets/javascripts/discourse/models/rest.js.es6 b/app/assets/javascripts/discourse/models/rest.js.es6
index 60d011bfc..0c595bb73 100644
--- a/app/assets/javascripts/discourse/models/rest.js.es6
+++ b/app/assets/javascripts/discourse/models/rest.js.es6
@@ -78,13 +78,10 @@ RestModel.reopenClass({
 
   create(args) {
     args = args || {};
-    if (!args.store || !args.keyValueStore) {
+    if (!args.store) {
       const container = Discourse.__container__;
       // Ember.warn('Use `store.createRecord` to create records instead of `.create()`');
       args.store = container.lookup('store:main');
-
-      // TODO: Remove this when composer is using the store fully
-      args.keyValueStore = container.lookup('key-value-store:main');
     }
 
     args.__munge = this.munge;
diff --git a/app/assets/javascripts/discourse/models/site.js.es6 b/app/assets/javascripts/discourse/models/site.js.es6
index 226e1ed81..deddc23d3 100644
--- a/app/assets/javascripts/discourse/models/site.js.es6
+++ b/app/assets/javascripts/discourse/models/site.js.es6
@@ -1,8 +1,9 @@
 import Archetype from 'discourse/models/archetype';
 import PostActionType from 'discourse/models/post-action-type';
 import Singleton from 'discourse/mixins/singleton';
+import RestModel from 'discourse/models/rest';
 
-const Site = Discourse.Model.extend({
+const Site = RestModel.extend({
 
   isReadOnly: Em.computed.alias('is_readonly'),
 
@@ -80,7 +81,7 @@ const Site = Discourse.Model.extend({
       existingCategory.setProperties(newCategory);
     } else {
       // TODO insert in right order?
-      newCategory = Discourse.Category.create(newCategory);
+      newCategory = this.store.createRecord('category', newCategory);
       categories.pushObject(newCategory);
       this.get('categoriesById')[categoryId] = newCategory;
     }
@@ -91,16 +92,18 @@ Site.reopenClass(Singleton, {
 
   // The current singleton will retrieve its attributes from the `PreloadStore`.
   createCurrent() {
-    return Site.create(PreloadStore.get('site'));
+    const store = Discourse.__container__.lookup('store:main');
+    return store.createRecord('site', PreloadStore.get('site'));
   },
 
   create() {
     const result = this._super.apply(this, arguments);
 
+    const store = result.store;
     if (result.categories) {
       result.categoriesById = {};
       result.categories = _.map(result.categories, function(c) {
-        return result.categoriesById[c.id] = Discourse.Category.create(c);
+        return result.categoriesById[c.id] = store.createRecord('category', c);
       });
 
       // Associate the categories with their parents
diff --git a/app/assets/javascripts/discourse/models/store.js.es6 b/app/assets/javascripts/discourse/models/store.js.es6
index dec3fcec7..57d60b0bb 100644
--- a/app/assets/javascripts/discourse/models/store.js.es6
+++ b/app/assets/javascripts/discourse/models/store.js.es6
@@ -157,6 +157,10 @@ export default Ember.Object.extend({
     obj.__type = type;
     obj.__state = obj.id ? "created" : "new";
 
+    // TODO: Have injections be automatic
+    obj.topicTrackingState = this.container.lookup('topic-tracking-state:main');
+    obj.keyValueStore = this.container.lookup('key-value-store:main');
+
     const klass = this.container.lookupFactory('model:' + type) || RestModel;
     const model = klass.create(obj);
 
diff --git a/app/assets/javascripts/discourse/models/topic-list.js.es6 b/app/assets/javascripts/discourse/models/topic-list.js.es6
index 742abdac4..a600221e6 100644
--- a/app/assets/javascripts/discourse/models/topic-list.js.es6
+++ b/app/assets/javascripts/discourse/models/topic-list.js.es6
@@ -147,9 +147,6 @@ TopicList.reopenClass({
     json.per_page = json.topic_list.per_page;
     json.topics = topicsFrom(json, store);
 
-    if (json.topic_list.filtered_category) {
-      json.category = Discourse.Category.create(json.topic_list.filtered_category);
-    }
     return json;
   },
 
diff --git a/app/assets/javascripts/discourse/models/topic-tracking-state.js.es6 b/app/assets/javascripts/discourse/models/topic-tracking-state.js.es6
index 9a4e9d374..0005b6e60 100644
--- a/app/assets/javascripts/discourse/models/topic-tracking-state.js.es6
+++ b/app/assets/javascripts/discourse/models/topic-tracking-state.js.es6
@@ -312,7 +312,7 @@ TopicTrackingState.reopenClass({
     const container = Discourse.__container__,
           messageBus = container.lookup('message-bus:main'),
           currentUser = container.lookup('current-user:main'),
-          instance = Discourse.TopicTrackingState.create({ messageBus, currentUser });
+          instance = TopicTrackingState.create({ messageBus, currentUser });
 
     instance.loadStates(data);
     instance.initialStatesLength = data && data.length;
diff --git a/app/assets/javascripts/discourse/pre-initializers/dynamic-route-builders.js.es6 b/app/assets/javascripts/discourse/pre-initializers/dynamic-route-builders.js.es6
index a01c73def..812e2aed9 100644
--- a/app/assets/javascripts/discourse/pre-initializers/dynamic-route-builders.js.es6
+++ b/app/assets/javascripts/discourse/pre-initializers/dynamic-route-builders.js.es6
@@ -3,6 +3,7 @@ import buildTopicRoute from 'discourse/routes/build-topic-route';
 import DiscoverySortableController from 'discourse/controllers/discovery-sortable';
 
 export default {
+  after: 'inject-discourse-objects',
   name: 'dynamic-route-builders',
 
   initialize(container, app) {
diff --git a/app/assets/javascripts/discourse/pre-initializers/inject-discourse-objects.js.es6 b/app/assets/javascripts/discourse/pre-initializers/inject-discourse-objects.js.es6
index 59e7202b3..ed2577e23 100644
--- a/app/assets/javascripts/discourse/pre-initializers/inject-discourse-objects.js.es6
+++ b/app/assets/javascripts/discourse/pre-initializers/inject-discourse-objects.js.es6
@@ -5,6 +5,7 @@ import Store from 'discourse/models/store';
 import DiscourseURL from 'discourse/lib/url';
 import DiscourseLocation from 'discourse/lib/discourse-location';
 import SearchService from 'discourse/services/search';
+import TopicTrackingState from 'discourse/models/topic-tracking-state';
 
 function inject() {
   const app = arguments[0],
@@ -30,6 +31,12 @@ export default {
     app.register('store:main', Store);
     inject(app, 'store', 'route', 'controller');
 
+    app.register('message-bus:main', window.MessageBus, { instantiate: false });
+    injectAll(app, 'messageBus');
+
+    app.register('topic-tracking-state:main', TopicTrackingState.current(), { instantiate: false });
+    injectAll(app, 'topicTrackingState');
+
     const site = Discourse.Site.current();
     app.register('site:main', site, { instantiate: false });
     injectAll(app, 'site');
@@ -46,9 +53,6 @@ export default {
     app.register('current-user:main', Discourse.User.current(), { instantiate: false });
     inject(app, 'currentUser', 'component', 'route', 'controller');
 
-    app.register('message-bus:main', window.MessageBus, { instantiate: false });
-    injectAll(app, 'messageBus');
-
     app.register('location:discourse-location', DiscourseLocation);
 
     const keyValueStore = new KeyValueStore("discourse_");
diff --git a/app/assets/javascripts/discourse/routes/application.js.es6 b/app/assets/javascripts/discourse/routes/application.js.es6
index 5944ccbd2..b8654da91 100644
--- a/app/assets/javascripts/discourse/routes/application.js.es6
+++ b/app/assets/javascripts/discourse/routes/application.js.es6
@@ -2,6 +2,7 @@ import { setting } from 'discourse/lib/computed';
 import logout from 'discourse/lib/logout';
 import showModal from 'discourse/lib/show-modal';
 import OpenComposer from "discourse/mixins/open-composer";
+import Category from 'discourse/models/category';
 
 function unlessReadOnly(method) {
   return function() {
@@ -126,11 +127,11 @@ const ApplicationRoute = Discourse.Route.extend(OpenComposer, {
     },
 
     editCategory(category) {
-      const self = this;
-      Discourse.Category.reloadById(category.get('id')).then(function (model) {
-        self.site.updateCategory(model);
+      Category.reloadById(category.get('id')).then((atts) => {
+        const model = this.store.createRecord('category', atts.category);
+        this.site.updateCategory(model);
         showModal('editCategory', { model });
-        self.controllerFor('editCategory').set('selectedTab', 'general');
+        this.controllerFor('editCategory').set('selectedTab', 'general');
       });
     },
 
diff --git a/app/assets/javascripts/discourse/routes/build-category-route.js.es6 b/app/assets/javascripts/discourse/routes/build-category-route.js.es6
index eaf26cc18..192155285 100644
--- a/app/assets/javascripts/discourse/routes/build-category-route.js.es6
+++ b/app/assets/javascripts/discourse/routes/build-category-route.js.es6
@@ -36,7 +36,7 @@ export default function(filter, params) {
       this._categoryList = null;
       if (Em.isNone(model.get('parentCategory')) && Discourse.SiteSettings.show_subcategory_list) {
         var self = this;
-        return Discourse.CategoryList.listForParent(model).then(function(list) {
+        return Discourse.CategoryList.listForParent(this.store, model).then(function(list) {
           self._categoryList = list;
         });
       }
@@ -52,7 +52,7 @@ export default function(filter, params) {
       var findOpts = filterQueryParams(transition.queryParams, params),
           extras = { cached: this.isPoppedState(transition) };
 
-      return findTopicList(this.store, listFilter, findOpts, extras).then(function(list) {
+      return findTopicList(this.store, this.topicTrackingState, listFilter, findOpts, extras).then(function(list) {
         Discourse.TopicList.hideUniformCategory(list, model);
         self.set('topics', list);
       });
diff --git a/app/assets/javascripts/discourse/routes/build-topic-route.js.es6 b/app/assets/javascripts/discourse/routes/build-topic-route.js.es6
index 0011b0305..36d54fd84 100644
--- a/app/assets/javascripts/discourse/routes/build-topic-route.js.es6
+++ b/app/assets/javascripts/discourse/routes/build-topic-route.js.es6
@@ -12,9 +12,7 @@ function filterQueryParams(params, defaultParams) {
   return findOpts;
 }
 
-function findTopicList(store, filter, filterParams, extras) {
-  const tracking = Discourse.TopicTrackingState.current();
-
+function findTopicList(store, tracking, filter, filterParams, extras) {
   extras = extras || {};
   return new Ember.RSVP.Promise(function(resolve) {
 
@@ -77,7 +75,7 @@ export default function(filter, extras) {
       const findOpts = filterQueryParams(transition.queryParams),
             findExtras = { cached: this.isPoppedState(transition) };
 
-      return findTopicList(this.store, filter, findOpts, findExtras);
+      return findTopicList(this.store, this.topicTrackingState, filter, findOpts, findExtras);
     },
 
     titleToken() {
diff --git a/app/assets/javascripts/discourse/routes/discovery-categories.js.es6 b/app/assets/javascripts/discourse/routes/discovery-categories.js.es6
index 85bbab29f..d8a34f062 100644
--- a/app/assets/javascripts/discourse/routes/discovery-categories.js.es6
+++ b/app/assets/javascripts/discourse/routes/discovery-categories.js.es6
@@ -16,8 +16,8 @@ const DiscoveryCategoriesRoute = Discourse.Route.extend(OpenComposer, {
     // if default page is categories
     PreloadStore.remove("topic_list");
 
-    return Discourse.CategoryList.list("categories").then(function(list) {
-      const tracking = Discourse.TopicTrackingState.current();
+    return Discourse.CategoryList.list(this.store, 'categories').then((list) => {
+      const tracking = this.topicTrackingState;
       if (tracking) {
         tracking.sync(list, "categories");
         tracking.trackIncoming("categories");
@@ -46,7 +46,7 @@ const DiscoveryCategoriesRoute = Discourse.Route.extend(OpenComposer, {
       const groups = this.site.groups,
             everyoneName = groups.findBy("id", 0).name;
 
-      const model = Discourse.Category.create({
+      const model = this.store.createRecord('category', {
         color: "AB9364", text_color: "FFFFFF", group_permissions: [{group_name: everyoneName, permission_type: 1}],
         available_groups: groups.map(g => g.name),
         allow_badges: true
diff --git a/app/assets/javascripts/discourse/routes/topic.js.es6 b/app/assets/javascripts/discourse/routes/topic.js.es6
index 5c9a97733..1f0b8098d 100644
--- a/app/assets/javascripts/discourse/routes/topic.js.es6
+++ b/app/assets/javascripts/discourse/routes/topic.js.es6
@@ -216,7 +216,7 @@ const TopicRoute = Discourse.Route.extend({
     this.controllerFor('topic-admin-menu').set('model', model);
 
     this.controllerFor('composer').set('topic', model);
-    Discourse.TopicTrackingState.current().trackIncoming('all');
+    this.topicTrackingState.trackIncoming('all');
     controller.subscribe();
 
     this.controllerFor('topic-progress').set('model', model);
diff --git a/app/assets/javascripts/discourse/views/topic.js.es6 b/app/assets/javascripts/discourse/views/topic.js.es6
index bd6265ace..8a1828236 100644
--- a/app/assets/javascripts/discourse/views/topic.js.es6
+++ b/app/assets/javascripts/discourse/views/topic.js.es6
@@ -121,10 +121,6 @@ const TopicView = Ember.View.extend(AddCategoryClass, AddArchetypeClass, Scrolli
     this.appEvents.trigger('topic:scrolled', offset);
   },
 
-  topicTrackingState: function() {
-    return Discourse.TopicTrackingState.current();
-  }.property(),
-
   browseMoreMessage: function() {
     var opts = { latestLink: "<a href=\"" + Discourse.getURL("/latest") + "\">" + I18n.t("topic.view_latest_topics") + "</a>" },
         category = this.get('controller.content.category');
diff --git a/app/assets/javascripts/main_include.js b/app/assets/javascripts/main_include.js
index 1181452b4..0ff243058 100644
--- a/app/assets/javascripts/main_include.js
+++ b/app/assets/javascripts/main_include.js
@@ -31,6 +31,7 @@
 //= require ./discourse/models/rest
 //= require ./discourse/models/badge-grouping
 //= require ./discourse/models/badge
+//= require ./discourse/models/category
 //= require_tree ./discourse/mixins
 //= require ./discourse/lib/ajax-error
 //= require ./discourse/lib/markdown
diff --git a/test/javascripts/helpers/create-store.js.es6 b/test/javascripts/helpers/create-store.js.es6
index 4be1b8feb..9bfa00be4 100644
--- a/test/javascripts/helpers/create-store.js.es6
+++ b/test/javascripts/helpers/create-store.js.es6
@@ -1,16 +1,29 @@
 import Store from "discourse/models/store";
 import RestAdapter from 'discourse/adapters/rest';
+import KeyValueStore from 'discourse/lib/key-value-store';
+import TopicTrackingState from 'discourse/models/topic-tracking-state';
 import Resolver from 'discourse/ember/resolver';
 
-let _restAdapter;
 export default function() {
   const resolver = Resolver.create();
   return Store.create({
     container: {
       lookup(type) {
         if (type === "adapter:rest") {
-          _restAdapter = _restAdapter || RestAdapter.create({ container: this });
-          return (_restAdapter);
+          this._restAdapter = this._restAdapter || RestAdapter.create({ container: this });
+          return (this._restAdapter);
+        }
+        if (type === "key-value-store:main") {
+          this._kvs = this._kvs || new KeyValueStore();
+          return (this._kvs);
+        }
+        if (type === "topic-tracking-state:main") {
+          this._tracker = this._tracker || TopicTrackingState.current();
+          return (this._tracker);
+        }
+        if (type === "site-settings:main") {
+          this._settings = this._settings || Discourse.SiteSettings.current();
+          return (this._settings);
         }
       },
 
diff --git a/test/javascripts/helpers/qunit-helpers.js.es6 b/test/javascripts/helpers/qunit-helpers.js.es6
index 4b0207e54..44812f7ec 100644
--- a/test/javascripts/helpers/qunit-helpers.js.es6
+++ b/test/javascripts/helpers/qunit-helpers.js.es6
@@ -71,7 +71,7 @@ function acceptance(name, options) {
         options.teardown.call(this);
       }
       Discourse.User.resetCurrent();
-      Discourse.Site.resetCurrent(Discourse.Site.create(fixtures['site.json'].site));
+      Discourse.Site.resetCurrent(Discourse.Site.create(jQuery.extend(true, {}, fixtures['site.json'].site)));
 
       Discourse.Utilities.avatarImg = oldAvatar;
       Discourse.reset();
diff --git a/test/javascripts/lib/category-badge-test.js.es6 b/test/javascripts/lib/category-badge-test.js.es6
index 55e2da586..385d478c6 100644
--- a/test/javascripts/lib/category-badge-test.js.es6
+++ b/test/javascripts/lib/category-badge-test.js.es6
@@ -1,3 +1,4 @@
+import createStore from 'helpers/create-store';
 import { blank, present } from 'helpers/qunit-helpers';
 
 module("lib:category-link");
@@ -10,33 +11,36 @@ test("categoryBadge without a category", function() {
 });
 
 test("Regular categoryBadge", function() {
-  var category = Discourse.Category.create({
-        name: 'hello',
-        id: 123,
-        description_text: 'cool description',
-        color: 'ff0',
-        text_color: 'f00'
-      }),
-      tag = parseHTML(categoryBadgeHTML(category))[0];
+  const store = createStore();
+  const category = store.createRecord('category', {
+          name: 'hello',
+          id: 123,
+          description_text: 'cool description',
+          color: 'ff0',
+          text_color: 'f00'
+        });
+  const tag = parseHTML(categoryBadgeHTML(category))[0];
 
   equal(tag.name, 'a', 'it creates a `a` wrapper tag');
   equal(tag.attributes['class'].trim(), 'badge-wrapper', 'it has the correct class');
 
-  var label = tag.children[1];
+  const label = tag.children[1];
   equal(label.attributes.title, 'cool description', 'it has the correct title');
 
   equal(label.children[0].data, 'hello', 'it has the category name');
 });
 
 test("undefined color", function() {
-  var noColor = Discourse.Category.create({ name: 'hello', id: 123 }),
-      tag = parseHTML(categoryBadgeHTML(noColor))[0];
+  const store = createStore();
+  const noColor = store.createRecord('category', { name: 'hello', id: 123 });
+  const tag = parseHTML(categoryBadgeHTML(noColor))[0];
 
   blank(tag.attributes.style, "it has no color style because there are no colors");
 });
 
 test("allowUncategorized", function() {
-  var uncategorized = Discourse.Category.create({name: 'uncategorized', id: 345});
+  const store = createStore();
+  const uncategorized = store.createRecord('category', {name: 'uncategorized', id: 345});
   sandbox.stub(Discourse.Site, 'currentProp').withArgs('uncategorized_category_id').returns(345);
 
   blank(categoryBadgeHTML(uncategorized), "it doesn't return HTML for uncategorized by default");
diff --git a/test/javascripts/models/category-test.js.es6 b/test/javascripts/models/category-test.js.es6
index b005ec116..48735f88e 100644
--- a/test/javascripts/models/category-test.js.es6
+++ b/test/javascripts/models/category-test.js.es6
@@ -1,27 +1,30 @@
-module("Discourse.Category");
+import createStore from 'helpers/create-store';
+
+module("model:category");
 
 test('slugFor', function(){
+  const store = createStore();
 
-  var slugFor = function(cat, val, text) {
+  const slugFor = function(cat, val, text) {
     equal(Discourse.Category.slugFor(cat), val, text);
   };
 
-  slugFor(Discourse.Category.create({slug: 'hello'}), "hello", "It calculates the proper slug for hello");
-  slugFor(Discourse.Category.create({id: 123, slug: ''}), "123-category", "It returns id-category for empty strings");
-  slugFor(Discourse.Category.create({id: 456}), "456-category", "It returns id-category for undefined slugs");
-  slugFor(Discourse.Category.create({slug: '熱帶風暴畫眉'}), "熱帶風暴畫眉", "It can be non english characters");
+  slugFor(store.createRecord('category', {slug: 'hello'}), "hello", "It calculates the proper slug for hello");
+  slugFor(store.createRecord('category', {id: 123, slug: ''}), "123-category", "It returns id-category for empty strings");
+  slugFor(store.createRecord('category', {id: 456}), "456-category", "It returns id-category for undefined slugs");
+  slugFor(store.createRecord('category', {slug: '熱帶風暴畫眉'}), "熱帶風暴畫眉", "It can be non english characters");
 
-  var parentCategory = Discourse.Category.create({id: 345, slug: 'darth'});
-  slugFor(Discourse.Category.create({slug: 'luke', parentCategory: parentCategory}),
+  const parentCategory = store.createRecord('category', {id: 345, slug: 'darth'});
+  slugFor(store.createRecord('category', {slug: 'luke', parentCategory: parentCategory}),
           "darth/luke",
           "it uses the parent slug before the child");
 
-  slugFor(Discourse.Category.create({id: 555, parentCategory: parentCategory}),
+  slugFor(store.createRecord('category', {id: 555, parentCategory: parentCategory}),
           "darth/555-category",
           "it uses the parent slug before the child and then uses id");
 
   parentCategory.set('slug', null);
-  slugFor(Discourse.Category.create({id: 555, parentCategory: parentCategory}),
+  slugFor(store.createRecord('category', {id: 555, parentCategory: parentCategory}),
         "345-category/555-category",
         "it uses the parent before the child and uses ids for both");
 });
@@ -30,12 +33,13 @@ test('slugFor', function(){
 test('findBySlug', function() {
   expect(6);
 
-  var darth = Discourse.Category.create({id: 1, slug: 'darth'}),
-    luke = Discourse.Category.create({id: 2, slug: 'luke', parentCategory: darth}),
-    hurricane = Discourse.Category.create({id: 3, slug: '熱帶風暴畫眉'}),
-    newsFeed = Discourse.Category.create({id: 4, slug: '뉴스피드', parentCategory: hurricane}),
-    time = Discourse.Category.create({id: 5, slug: '时间', parentCategory: darth}),
-    bah = Discourse.Category.create({id: 6, slug: 'bah', parentCategory: hurricane}),
+  const store = createStore();
+  const darth = store.createRecord('category', {id: 1, slug: 'darth'}),
+    luke = store.createRecord('category', {id: 2, slug: 'luke', parentCategory: darth}),
+    hurricane = store.createRecord('category', {id: 3, slug: '熱帶風暴畫眉'}),
+    newsFeed = store.createRecord('category', {id: 4, slug: '뉴스피드', parentCategory: hurricane}),
+    time = store.createRecord('category', {id: 5, slug: '时间', parentCategory: darth}),
+    bah = store.createRecord('category', {id: 6, slug: 'bah', parentCategory: hurricane}),
     categoryList = [darth, luke, hurricane, newsFeed, time, bah];
 
   sandbox.stub(Discourse.Category, 'list').returns(categoryList);
@@ -51,12 +55,13 @@ test('findBySlug', function() {
 test('findSingleBySlug', function() {
   expect(6);
 
-  var darth = Discourse.Category.create({id: 1, slug: 'darth'}),
-    luke = Discourse.Category.create({id: 2, slug: 'luke', parentCategory: darth}),
-    hurricane = Discourse.Category.create({id: 3, slug: '熱帶風暴畫眉'}),
-    newsFeed = Discourse.Category.create({id: 4, slug: '뉴스피드', parentCategory: hurricane}),
-    time = Discourse.Category.create({id: 5, slug: '时间', parentCategory: darth}),
-    bah = Discourse.Category.create({id: 6, slug: 'bah', parentCategory: hurricane}),
+  const store = createStore();
+  const darth = store.createRecord('category', {id: 1, slug: 'darth'}),
+    luke = store.createRecord('category', {id: 2, slug: 'luke', parentCategory: darth}),
+    hurricane = store.createRecord('category', {id: 3, slug: '熱帶風暴畫眉'}),
+    newsFeed = store.createRecord('category', {id: 4, slug: '뉴스피드', parentCategory: hurricane}),
+    time = store.createRecord('category', {id: 5, slug: '时间', parentCategory: darth}),
+    bah = store.createRecord('category', {id: 6, slug: 'bah', parentCategory: hurricane}),
     categoryList = [darth, luke, hurricane, newsFeed, time, bah];
 
   sandbox.stub(Discourse.Category, 'list').returns(categoryList);
@@ -70,9 +75,10 @@ test('findSingleBySlug', function() {
 });
 
 test('findByIds', function() {
-  var categories =  {
-    1: Discourse.Category.create({id: 1}),
-    2: Discourse.Category.create({id: 2})
+  const store = createStore();
+  const categories =  {
+    1: store.createRecord('category', {id: 1}),
+    2: store.createRecord('category', {id: 2})
   };
 
   sandbox.stub(Discourse.Category, 'idMap').returns(categories);
@@ -80,13 +86,14 @@ test('findByIds', function() {
 });
 
 test('postCountStats', function() {
-  var category1 = Discourse.Category.create({id: 1, slug: 'unloved', posts_year: 2, posts_month: 0, posts_week: 0, posts_day: 0}),
-      category2 = Discourse.Category.create({id: 2, slug: 'hasbeen', posts_year: 50, posts_month: 4, posts_week: 0, posts_day: 0}),
-      category3 = Discourse.Category.create({id: 3, slug: 'solastweek', posts_year: 250, posts_month: 200, posts_week: 50, posts_day: 0}),
-      category4 = Discourse.Category.create({id: 4, slug: 'hotstuff', posts_year: 500, posts_month: 280, posts_week: 100, posts_day: 22}),
-      category5 = Discourse.Category.create({id: 6, slug: 'empty', posts_year: 0, posts_month: 0, posts_week: 0, posts_day: 0});
+  const store = createStore();
+  const category1 = store.createRecord('category', {id: 1, slug: 'unloved', posts_year: 2, posts_month: 0, posts_week: 0, posts_day: 0}),
+      category2 = store.createRecord('category', {id: 2, slug: 'hasbeen', posts_year: 50, posts_month: 4, posts_week: 0, posts_day: 0}),
+      category3 = store.createRecord('category', {id: 3, slug: 'solastweek', posts_year: 250, posts_month: 200, posts_week: 50, posts_day: 0}),
+      category4 = store.createRecord('category', {id: 4, slug: 'hotstuff', posts_year: 500, posts_month: 280, posts_week: 100, posts_day: 22}),
+      category5 = store.createRecord('category', {id: 6, slug: 'empty', posts_year: 0, posts_month: 0, posts_week: 0, posts_day: 0});
 
-  var result = category1.get('postCountStats');
+  let result = category1.get('postCountStats');
   equal(result.length, 1, "should only show year");
   equal(result[0].value, 2);
   equal(result[0].unit, 'year');
diff --git a/test/javascripts/models/composer-test.js.es6 b/test/javascripts/models/composer-test.js.es6
index 08559b8bc..c9c2e1dc8 100644
--- a/test/javascripts/models/composer-test.js.es6
+++ b/test/javascripts/models/composer-test.js.es6
@@ -1,6 +1,8 @@
 import { blank } from 'helpers/qunit-helpers';
 import { currentUser } from 'helpers/qunit-helpers';
 import KeyValueStore from 'discourse/lib/key-value-store';
+import Composer from 'discourse/models/composer';
+import createStore from 'helpers/create-store';
 
 module("model:composer");
 
@@ -9,10 +11,13 @@ const keyValueStore = new KeyValueStore("_test_composer");
 function createComposer(opts) {
   opts = opts || {};
   opts.user = opts.user || currentUser();
-  opts.site = Discourse.Site.current();
-  opts.siteSettings = Discourse.SiteSettings;
-  opts.keyValueStore = keyValueStore;
-; return Discourse.Composer.create(opts);
+  return createStore().createRecord('composer', opts);
+}
+
+function openComposer(opts) {
+  const composer = createComposer(opts);
+  composer.open(opts);
+  return composer;
 }
 
 test('replyLength', function() {
@@ -111,7 +116,7 @@ test("Title length for regular topics", function() {
 test("Title length for private messages", function() {
   Discourse.SiteSettings.min_private_message_title_length = 5;
   Discourse.SiteSettings.max_topic_title_length = 10;
-  const composer = createComposer({action: Discourse.Composer.PRIVATE_MESSAGE});
+  const composer = createComposer({action: Composer.PRIVATE_MESSAGE});
 
   composer.set('title', 'asdf');
   ok(!composer.get('titleLengthValid'), "short titles are not valid");
@@ -126,7 +131,7 @@ test("Title length for private messages", function() {
 test("Title length for private messages", function() {
   Discourse.SiteSettings.min_private_message_title_length = 5;
   Discourse.SiteSettings.max_topic_title_length = 10;
-  const composer = createComposer({action: Discourse.Composer.PRIVATE_MESSAGE});
+  const composer = createComposer({action: Composer.PRIVATE_MESSAGE});
 
   composer.set('title', 'asdf');
   ok(!composer.get('titleLengthValid'), "short titles are not valid");
@@ -143,7 +148,7 @@ test('editingFirstPost', function() {
   ok(!composer.get('editingFirstPost'), "it's false by default");
 
   const post = Discourse.Post.create({id: 123, post_number: 2});
-  composer.setProperties({post: post, action: Discourse.Composer.EDIT });
+  composer.setProperties({post: post, action: Composer.EDIT });
   ok(!composer.get('editingFirstPost'), "it's false when not editing the first post");
 
   post.set('post_number', 1);
@@ -170,19 +175,19 @@ test('clearState', function() {
 
 test('initial category when uncategorized is allowed', function() {
   Discourse.SiteSettings.allow_uncategorized_topics = true;
-  const composer = Discourse.Composer.open({action: 'createTopic', draftKey: 'asfd', draftSequence: 1});
+  const composer = openComposer({action: 'createTopic', draftKey: 'asfd', draftSequence: 1});
   equal(composer.get('categoryId'),undefined,"Uncategorized by default");
 });
 
 test('initial category when uncategorized is not allowed', function() {
   Discourse.SiteSettings.allow_uncategorized_topics = false;
-  const composer = Discourse.Composer.open({action: 'createTopic', draftKey: 'asfd', draftSequence: 1});
+  const composer = openComposer({action: 'createTopic', draftKey: 'asfd', draftSequence: 1});
   ok(composer.get('categoryId') === undefined, "Uncategorized by default. Must choose a category.");
 });
 
 test('showPreview', function() {
   const newComposer = function() {
-    return Discourse.Composer.open({action: 'createTopic', draftKey: 'asfd', draftSequence: 1});
+    return openComposer({action: 'createTopic', draftKey: 'asfd', draftSequence: 1});
   };
 
   Discourse.Mobile.mobileView = true;
@@ -199,7 +204,7 @@ test('showPreview', function() {
 test('open with a quote', function() {
   const quote = '[quote="neil, post:5, topic:413"]\nSimmer down you two.\n[/quote]';
   const newComposer = function() {
-    return Discourse.Composer.open({action: Discourse.Composer.REPLY, draftKey: 'asfd', draftSequence: 1, quote: quote});
+    return openComposer({action: Discourse.Composer.REPLY, draftKey: 'asfd', draftSequence: 1, quote: quote});
   };
 
   equal(newComposer().get('originalText'), quote, "originalText is the quote" );
@@ -212,7 +217,7 @@ test("Title length for static page topics as admin", function() {
   const composer = createComposer();
 
   const post = Discourse.Post.create({id: 123, post_number: 2, static_doc: true});
-  composer.setProperties({post: post, action: Discourse.Composer.EDIT });
+  composer.setProperties({post: post, action: Composer.EDIT });
 
   composer.set('title', 'asdf');
   ok(composer.get('titleLengthValid'), "admins can use short titles");
diff --git a/test/javascripts/models/site-test.js.es6 b/test/javascripts/models/site-test.js.es6
index 65804504d..bc1c3c0ac 100644
--- a/test/javascripts/models/site-test.js.es6
+++ b/test/javascripts/models/site-test.js.es6
@@ -1,14 +1,14 @@
+import createStore from 'helpers/create-store';
 import { blank, present } from 'helpers/qunit-helpers';
 
-module("Discourse.Site");
+module("model:site");
 
 test('create', function() {
   ok(Discourse.Site.create(), 'it can create with no parameters');
 });
 
 test('instance', function() {
-
-  var site = Discourse.Site.current();
+  const site = Discourse.Site.current();
 
   present(site, "We have a current site singleton");
   present(site.get('categories'), "The instance has a list of categories");
@@ -18,24 +18,24 @@ test('instance', function() {
 });
 
 test('create categories', function() {
-
-  var site = Discourse.Site.create({
+  const store = createStore();
+  const site = store.createRecord('site', {
     categories: [{ id: 1234, name: 'Test'},
                  { id: 3456, name: 'Test Subcategory', parent_category_id: 1234},
-                 { id: 3456, name: 'Invalid Subcategory', parent_category_id: 6666}]
+                 { id: 3458, name: 'Invalid Subcategory', parent_category_id: 6666}]
   });
 
-  var categories = site.get('categories');
+  const categories = site.get('categories');
   site.get('sortedCategories');
 
   present(categories, "The categories are present");
   equal(categories.length, 3, "it loaded all three categories");
 
-  var parent = categories.findBy('id', 1234);
+  const parent = categories.findBy('id', 1234);
   present(parent, "it loaded the parent category");
   blank(parent.get('parentCategory'), 'it has no parent category');
 
-  var subcategory = categories.findBy('id', 3456);
+  const subcategory = categories.findBy('id', 3456);
   present(subcategory, "it loaded the subcategory");
   equal(subcategory.get('parentCategory'), parent, "it has associated the child with the parent");
 
diff --git a/test/javascripts/models/topic-tracking-state-test.js.es6 b/test/javascripts/models/topic-tracking-state-test.js.es6
index 305fc1d17..f135584ee 100644
--- a/test/javascripts/models/topic-tracking-state-test.js.es6
+++ b/test/javascripts/models/topic-tracking-state-test.js.es6
@@ -1,21 +1,19 @@
-module("Discourse.TopicTrackingState");
+import TopicTrackingState from 'discourse/models/topic-tracking-state';
 
-test("sync", function () {
+module("model:topic-tracking-state");
 
-  var state = Discourse.TopicTrackingState.create();
-  // fake track it
+test("sync", function (assert) {
+  const state = TopicTrackingState.create();
   state.states["t111"] = {last_read_post_number: null};
 
   state.updateSeen(111, 7);
-  var list = {topics: [{
+  const list = {topics: [{
     highest_post_number: null,
     id: 111,
     unread: 10,
     new_posts: 10
-    }]};
+  }]};
 
   state.sync(list, "new");
-
-  equal(list.topics.length, 0, "expect new topic to be removed as it was seen");
-
+  assert.equal(list.topics.length, 0, "expect new topic to be removed as it was seen");
 });