Skip to content

Instantly share code, notes, and snippets.

@noelrappin
Last active December 14, 2015 04:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save noelrappin/5030407 to your computer and use it in GitHub Desktop.
Save noelrappin/5030407 to your computer and use it in GitHub Desktop.
Problem I'm having with Ember and Jasmine

I'm trying to run an Ember controller in a Jasmine test, and it's giving me some trouble.

This spec works, in that it renders the controller, and most of the controller is rendered accurately and can be tested.

However, there is clearly a difference between how I'm setting up these objects in the test, and how Ember sets them up at run time, because parts of the controller are not working in the test...

Details:

  • The itemController is not accessed at all, which means that the reference to "startDateDisplay" (which is defined in the item controller) comes up empty.

  • In a probably related story, the action referenced in the template can not be triggered in the test with a $(".trip").click() jQuery event.

I tried a few workarounds -- I tried changing the {{each}} in the template to:

{{#each trip in controller}}

Which gives me the error 

Error: assertion failed: an Ember.CollectionView's content must implement Ember.Array. You passed <TimeTravel.IndexTripController:ember258>

Which I take to mean that whatever magic causes looping over a controller to refer to its content is not being invoked when rendered in the test.

I also tried the more explicit 

{{#each trip in controller.content itemController="IndexTrip"}}

Which fails with

TypeError: Cannot call method 'child' of null 
at Ember.ArrayController.Ember.ArrayProxy.extend.controllerAt (http://js_travel.dev/assets/ember.js?body=1:12492:53)
at Ember.ArrayController.Ember.ArrayProxy.extend.objectAtContent (http://js_travel.dev/assets/ember.js?body=1:12445:21)

Which I don't get at all, but has something to do with containers.

{{! This is part of the template I'm trying to render -- the relevant part is the each, which triggers the use of
the itemController}
<div class="admin_trips span-12">
{{#each trip in controller}}
<div class="trip">
<div class="header" {{action selectTrip trip}}>
{{trip.name}}
{{trip.totalRevenueDisplay}}
</div>
{{log trip.startDateDisplay}}
<div class="dates">{{trip.startDateDisplay}} - {{trip.endDateDisplay}}</div>
<div class="price">{{trip.priceDisplay}}</div>
</div>
{{/each}}
</div>
// This is the controller -- it has other details, but those aren't important right now
TimeTravel.IndexController = Ember.ArrayController.extend({
itemController: "indexTrip",
})
// Here's the spec -- it creates a controller, a dummy view, and renders the view.
describe("with an index controller", function() {
beforeEach(function() {
Ember.testing = true;
Ember.run(function() {
trip = TimeTravel.Trip.createRecord({
name: "Mayflower",
startDate: "1620-09-06",
endDate: "1620-11-21"
});
controller = TimeTravel.IndexController.create();
controller.set('content', [trip]);
view = Ember.View.create({
controller: controller,
templateName: 'index'
});
view.append();
});
});
afterEach(function() {
Ember.run(function() {
view.remove();
});
});
describe("basic stuff", function() {
it("displays trips", function() {
Ember.run(function() {
expect($(".admin_trips").length).toEqual(1)
expect($(".trip").length).toEqual(1)
expect($(".trip .dates").text()).toEqual("Sep 6, 1620 - Nov 21, 1620")
});
});
it("manages clicks", function() {
Ember.run(function() {
$(".trip .header").first().click();
});
expect($(".selected_name").text()).toEqual("Mayflower");
});
});
});
@wagenet
Copy link

wagenet commented Feb 25, 2013

controller = TimeTravel.IndexTripController.create();
controller.set('content', [trip]);

The above seems wrong since you've said that IndexTripController is an ObjectController. Am I mistaken?

@noelrappin
Copy link
Author

No, you are right, but if I change that, then I get the same error that I do when I explicitly set the itemController in the template, namely:

TypeError: Cannot call method 'child' of null
at Ember.ArrayController.Ember.ArrayProxy.extend.controllerAt (http://js_travel.dev/assets/ember.js?body=1:12492:53)
at Ember.ArrayController.Ember.ArrayProxy.extend.objectAtContent (http://js_travel.dev/assets/ember.js?body=1:12445:21)
at superWrapper as objectAtContent
at Ember.ArrayProxy.Ember.Object.extend.objectAt (http://js_travel.dev/assets/ember.js?body=1:11365:41)
at superWrapper as objectAt
at Ember.Array.Ember.Mixin.create.arrayContentDidChange (http://js_travel.dev/assets/ember.js?body=1:8487:14)
at Ember.ArrayController.Ember.ArrayProxy.extend.arrayContentDidChange (http://js_travel.dev/assets/ember.js?body=1:12476:10)
at superWrapper as arrayContentDidChange
at Ember.ArrayProxy.Ember.Object.extend.arrangedContentArrayDidChange (http://js_travel.dev/assets/ember.js?body=1:11385:10)
at Ember.ArrayProxy.Ember.Object.extend._arrangedContentDidChange (http://js_travel.dev/assets/ember.js?body=1:11336:10)

@wagenet
Copy link

wagenet commented Feb 25, 2013

It's really hard for me to know what's going on beyond this without being able to interact with the code.

@noelrappin
Copy link
Author

That said, it's clearly a change that needs to be made in the spec. I wandered through the error, and it seems to have to do with containers or subcontainers not being created properly.

So, is this a reasonable way to test Ember, or should I be trying to go through the router?

@wagenet
Copy link

wagenet commented Feb 25, 2013

It definitely seems possible that containers are an issue here. The general line of thought recently has been that most Ember app testing should be integration tests and not unit tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment