Skip to content

Instantly share code, notes, and snippets.

@biscuitvile
Forked from emk/ember-test.html
Created September 4, 2013 02:15
Show Gist options
  • Save biscuitvile/6432061 to your computer and use it in GitHub Desktop.
Save biscuitvile/6432061 to your computer and use it in GitHub Desktop.
<!-- Mocha test output goes here. -->
<div id="mocha"></div>
<!-- Handlebars templates for our application. -->
<script type="text/x-handlebars">
<h1>Testing Ember.js with Mocha</h1>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="index">
<p>{{#linkTo 'employees'}}Show employees{{/linkTo}}</p>
</script>
<script type="text/x-handlebars" data-template-name="employees">
<h2>Employees</h2>
<ul>
{{#each employee in controller}}
<li>{{#linkTo 'employee' employee}}{{employee.name}}{{/linkTo}}</li>
{{/each}}
</ul>
</script>
<script type="text/x-handlebars" data-template-name="employee">
<h2>{{name}}</h2>
<p>Salary: <span class="salary">${{salary}}</span></p>
<button {{action 'giveRaise'}}>Give Raise</button>
{{#if managedBy}}
<p class="managed-by">
Managed by: {{#linkTo 'employee' managedBy}}{{managedBy.name}}{{/linkTo}}
</p>
{{/if}}
{{#if manages}}
<h3>Manages</h3>
<ul class="manages">
{{#each employee in manages}}
<li>{{#linkTo 'employee' employee}}{{employee.name}}{{/linkTo}}</li>
{{/each}}
</ul>
{{/if}}
<p>{{#linkTo 'employees'}}All employees{{/linkTo}}</p>
</script>
//================================================================================
// Application Code
window.App = Ember.Application.create();
// Our normal data store, which we be overridden when testing.
App.Store = DS.Store.extend({
revision: 12,
adapter: DS.RESTAdapter.create()
});
App.Employee = DS.Model.extend({
name: DS.attr("string"),
salary: DS.attr("number"),
managedBy: DS.belongsTo("App.Employee"),
manages: DS.hasMany("App.Employee")
});
App.Router.map(function () {
this.route("index", { path: "/" });
this.route("employees", { path: "/employees" });
this.route("employee", { path: "/employee/:employee_id" });
});
App.EmployeesRoute = Ember.Route.extend({
model: function (params) {
return App.Employee.find();
}
});
App.EmployeeRoute = Ember.Route.extend({
model: function (params) {
return App.Employee.find(params.employee_id);
}
});
App.EmployeesController = Ember.ArrayController.extend();
App.EmployeeController = Ember.ObjectController.extend({
giveRaise: function () {
this.set("salary", this.get("salary") * 1.10);
}
});
// Declare this explicitly so we can test it.
App.EmployeeView = Ember.View.extend({
// Only needed so we can be called outside of a route by our unit tests.
templateName: 'employee'
});
//================================================================================
// Test Code
// Configure Mocha, telling both it and chai to use BDD-style tests.
mocha.setup("bdd");
chai.should();
// Replace our fixture-based store with a REST-based store for testing, so we
// don't need a server. We disable simulateRemoteResponse so that objects will
// appear to load at the end of every Ember.run block instead of waiting for a
// timer to fire.
App.Store = DS.Store.extend({
revision: 12,
adapter: DS.FixtureAdapter.create({ simulateRemoteResponse: false })
});
// Declare some fixture objects to use in our test application. There's
// nothing like factory_girl or machinist yet.
App.Employee.FIXTURES = [{
id: 1,
name: "Jane Q. Public",
salary: 80000,
managedBy: null,
manages: [2]
}, {
id: 2,
name: "John Q. Public",
salary: 60000,
managedBy: 1,
manages: []
}];
mocha.setup('bdd');
// Run before each test case.
beforeEach(function () {
// Put the application into a known state, and destroy the defaultStore.
// Be careful about DS.Model instances stored in App; they'll be invalid
// after this.
// Currently broken, see: https://github.com/emberjs/data/issues/847
//App.reset();
// Display an error if asynchronous operations are queued outside of
// Ember.run. You need this if you want to stay sane.
Ember.testing = true;
});
// Run after each test case.
afterEach(function () {
Ember.testing = false;
});
// Load associations immediately, instead of waiting for FixtureAdapter's
// asynchronous loads. Basically, all we need to do is access each object
// from inside Ember.run.
// TODO: We can't test this or insert where needed until App.reset() works.
// TODO: Handle hasMany.
function loadAssociations(object /*, paths... */) {
var paths = Array.prototype.slice.call(arguments, 1);
for (var i = 0; i < paths.length; i++) {
var components = paths[i].split(".");
for (var j = 0; j < components.length; j++) {
Ember.run(function () {
var path = components.slice(0, j+1).join(".");
object.get(path);
});
}
}
}
// Sample model test.
describe("App.Employee", function () {
it("has a name", function () {
var jane;
Ember.run(function () {
// Won't actually load until the end of the run-block.
jane = App.Employee.find(1);
});
jane.get("name").should.equal("Jane Q. Public");
});
});
// Sample controller test.
describe("App.EmployeeController", function () {
var model, controller;
beforeEach(function () {
Ember.run(function () {
model = App.Employee.createRecord({ salary: 100000 });
controller = App.EmployeeController.create({ content: model });
});
});
it("can give the employee a raise", function () {
var oldSalary = model.get("salary");
Ember.run(function () {
controller.giveRaise();
});
model.get("salary").should.be(oldSalary * 1.1);
});
});
// Sample view test.
describe("App.EmployeeView", function () {
var controller, view;
beforeEach(function () {
Ember.run(function () {
var model = App.Employee.find(1);
controller = App.EmployeeController.create({
// We need a container to test views with linkTo.
container: App.__container__,
content: model
});
// If for some reason we want to isolate this, we can use
// a sinon stub to intercept certain calls.
sinon.stub(controller, "giveRaise");
view = App.EmployeeView.create({
controller: controller,
context: controller
});
view.append(); // Hook up to our document.
});
});
afterEach(function () {
Ember.run(function () {
view.remove(); // Unhook from our document.
});
});
it("shows the employee's name", function () {
// This uses a chai-jquery assertion.
view.$("h2").should.have.text("Jane Q. Public");
view.$(".manages li").text().should.match(/John/);
});
it("has a button which gives the employee a raise", function () {
view.$("button").click();
// We use a sinon-chai method here.
controller.giveRaise.should.have.been.calledOnce;
});
});
// Sample acceptance test.
describe("Employee features", function () {
it("give John's boss a raise", function () {
$("a:contains('Show employees')").click();
$("a:contains('John')").click();
$(".managed-by a").click();
$(".salary").should.have.text("$80000");
$("button:contains('Give Raise')").click();
$(".salary").should.have.text("$88000");
});
});
// Run all our test suites. Only necessary in the browser.
mocha.run();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment