Applies to Ember 1.9.1
Controller arrays will persist and accumulate data between tests because the reset function doesn't clear them out.
I declare a controller with a property fu that is an empty array, and then I programmatically assign the property bar as an empty array and use pushObject to add an object to both. App is my Ember application. I run App.reset(); and bar is destroyed but fu still contains the object I had pushed onto it.
Here is a JSFiddle demonstrating this
Here are some screenshots that capture it:


Yup, this is because the same array instance is currently shared between instances. I think this is maybe something we could warn against.
To work around this, you can return a computed property that gets you a new array instance and will be reset properly:
App.MyController = Ember.Controller.extend({
fu: Ember.computed(function(){
return [];
})
});
@fivetanley - Honestly, I'm not sure that this is an error condition. There are legitimate cases for wanting to use shared state amongst all instances (although I agree they are much rarer).
I may be thinking about this naively, but I am surprised by this behavior. The documentation indicates that Ember.Application.reset will
Deactivate existing routes
Destroy all objects in the container
Create a new application container
Re-route to the existing url
I would think that part of that process would be recreating my controller with the empty array, as defined in the controller definition. I think it is unexpected to need to manually clear properties, or be careful of how an array is defined so that a test doesn't start breaking because some previous test cause some objects to be stored in the array.
In my mind I just can't define controller properties as arrays now (that's what my boss is telling me anyway), at least without using a computed property. That would be helpful if it was in the docs because it causes tests to break in a way that is difficult to figure out.
I don't mean to be critical, in general I really like the way Ember is going and you guys are doing a great job. This is the first time I have reported an issue and I have been using Ember for 10 months now.
@RustyToms:
Storing mutable data in the prototype of any object will be shared with all instances. This is not an Ember.Object thing, but a normal Javascript thing.
function Person() { };
Person.prototype.listing = [];
var bob = new Person();
var alice = new Person();
bob.listing === alice.listing; // ==> true
Ember.Application.prototype.reset clears the container (which is where instantiated singleton controllers live), but there is no way for it to clear data that you have stored on the prototype of your controller (instead of the instance).
The solution is to set the array on the instance of your object (not on the prototype). In plain Javascript (with the example above) that would look like:
function Person() {
this.listing = [];
};
var bob = new Person();
var alice = new Person();
bob.listing === alice.listing; // ==> false
Now lets apply this standard JS knowledge to Ember.Object. The first example (storing mutable data on the prototype):
var Person = Ember.Object.extend({
listing: []
});
var bob = Person.create();
var alice = Person.create();
bob.listing === alice.listing; // ==> true
And without storing on the prototype:
var Person = Ember.Object.extend({
init: function() {
this.listing = [];
}
});
var bob = Person.create();
var alice = Person.create();
bob.listing === alice.listing; // ==> false
@rwjblue thank you for the detailed explanation. That is very helpful, I wasn't thinking about it that way but I understand it better now. Because they are singletons, I was just thinking about those properties as if they are on the instance instead of the prototype.
Most helpful comment
@RustyToms:
Storing mutable data in the prototype of any object will be shared with all instances. This is not an Ember.Object thing, but a normal Javascript thing.
Ember.Application.prototype.resetclears the container (which is where instantiated singleton controllers live), but there is no way for it to clear data that you have stored on the prototype of your controller (instead of the instance).The solution is to set the array on the instance of your object (not on the prototype). In plain Javascript (with the example above) that would look like:
Now lets apply this standard JS knowledge to
Ember.Object. The first example (storing mutable data on the prototype):And without storing on the prototype: