k.backbone.marionette
Version:
Make your Backbone.js apps dance!
370 lines (292 loc) • 12.4 kB
JavaScript
describe('item view', function() {
'use strict';
beforeEach(function() {
this.modelData = {foo: 'bar'};
this.collectionData = [{foo: 'bar'}, {foo: 'baz'}];
this.model = new Backbone.Model(this.modelData);
this.collection = new Backbone.Collection(this.collectionData);
this.template = 'foobar';
this.templateStub = this.sinon.stub().returns(this.template);
});
describe('when rendering without a valid template', function() {
beforeEach(function() {
this.view = new Marionette.ItemView();
});
it('should throw an exception because there was no valid template', function() {
expect(this.view.render).to.throw('Cannot render the template since it is null or undefined.');
});
});
describe('when rendering with a false template', function() {
beforeEach(function() {
this.onBeforeRenderStub = this.sinon.stub();
this.onRenderStub = this.sinon.stub();
this.View = Marionette.ItemView.extend({
template: false,
onBeforeRender: this.onBeforeRenderStub,
onRender: this.onRenderStub
});
this.view = new this.View();
this.marionetteRendererSpy = this.sinon.spy(Marionette.Renderer, 'render');
this.triggerSpy = this.sinon.spy(this.view, 'trigger');
this.serializeDataSpy = this.sinon.spy(this.view, 'serializeData');
this.mixinTemplateHelpersSpy = this.sinon.spy(this.view, 'mixinTemplateHelpers');
this.attachElContentSpy = this.sinon.spy(this.view, 'attachElContent');
this.view.render();
});
it('should not throw an exception for a false template', function() {
expect(this.view.render).to.not.throw('Cannot render the template since it is null or undefined.');
});
it('should call an "onBeforeRender" method on the view', function() {
expect(this.onBeforeRenderStub).to.have.been.calledOnce;
});
it('should call an "onRender" method on the view', function() {
expect(this.onRenderStub).to.have.been.calledOnce;
});
it('should trigger a before:render event', function() {
expect(this.triggerSpy).to.have.been.calledWith('before:render', this.view);
});
it('should trigger a rendered event', function() {
expect(this.triggerSpy).to.have.been.calledWith('render', this.view);
});
it('should not add in data or template helpers', function() {
expect(this.serializeDataSpy).to.not.have.been.called;
expect(this.mixinTemplateHelpersSpy).to.not.have.been.called;
});
it('should not render a template', function() {
expect(this.marionetteRendererSpy).to.not.have.been.called;
});
it('should not attach any html content', function() {
expect(this.attachElContentSpy).to.not.have.been.called;
});
});
describe('when rendering with a overridden attachElContent', function() {
beforeEach(function() {
this.attachElContentStub = this.sinon.stub();
this.ItemView = Marionette.ItemView.extend({
template : this.templateStub,
attachElContent : this.attachElContentStub
});
this.sinon.spy(Marionette.Renderer, 'render');
this.itemView = new this.ItemView();
this.itemView.render();
});
it('should render according to the custom attachElContent logic', function() {
expect(this.attachElContentStub).to.have.been.calledOnce.and.calledWith(this.template);
});
it("should pass template stub, data and view instance to `Marionette.Renderer.Render`", function(){
expect(Marionette.Renderer.render).to.have.been.calledWith(this.templateStub, {}, this.itemView);
});
});
describe('when rendering', function() {
beforeEach(function() {
this.onBeforeRenderStub = this.sinon.stub();
this.onRenderStub = this.sinon.stub();
this.View = Marionette.ItemView.extend({
template : this.templateStub,
onBeforeRender : this.onBeforeRenderStub,
onRender : this.onRenderStub
});
this.view = new this.View();
this.triggerSpy = this.sinon.spy(this.view, 'trigger');
this.view.render();
});
it('should call a "onBeforeRender" method on the view', function() {
expect(this.onBeforeRenderStub).to.have.been.calledOnce;
});
it('should call an "onRender" method on the view', function() {
expect(this.onRenderStub).to.have.been.calledOnce;
});
it('should trigger a before:render event', function() {
expect(this.triggerSpy).to.have.been.calledWith('before:render', this.view);
});
it('should trigger a rendered event', function() {
expect(this.triggerSpy).to.have.been.calledWith('render', this.view);
});
});
describe('when an item view has a model and is rendered', function() {
beforeEach(function() {
this.view = new Marionette.ItemView({
template : this.templateStub,
model : this.model
});
this.serializeDataSpy = this.sinon.spy(this.view, 'serializeData');
this.view.render();
});
it('should serialize the model', function() {
expect(this.serializeDataSpy).to.have.been.calledOnce;
});
it('should render the template with the serialized model', function() {
expect(this.templateStub).to.have.been.calledWith(this.modelData);
});
});
describe('when an item view has a collection and is rendered', function() {
beforeEach(function() {
this.view = new Marionette.ItemView({
template : this.templateStub,
collection : this.collection
});
this.serializeDataSpy = this.sinon.spy(this.view, 'serializeData');
this.view.render();
});
it('should serialize the collection', function() {
expect(this.serializeDataSpy).to.have.been.calledOnce;
});
it('should render the template with the serialized collection', function() {
expect(this.templateStub).to.have.been.calledWith({items: this.collectionData});
});
});
describe('when an item view has a model and collection, and is rendered', function() {
beforeEach(function() {
this.view = new Marionette.ItemView({
template : this.templateStub,
model : this.model,
collection : this.collection
});
this.serializeDataSpy = this.sinon.spy(this.view, 'serializeData');
this.view.render();
});
it('should serialize the model', function() {
expect(this.serializeDataSpy).to.have.been.calledOnce;
});
it('should render the template with the serialized model', function() {
expect(this.templateStub).to.have.been.calledWith(this.modelData);
});
});
describe('when destroying an item view', function() {
beforeEach(function() {
this.onBeforeDestroyStub = this.sinon.stub();
this.onDestroyStub = this.sinon.stub();
this.View = Marionette.ItemView.extend({
template : this.templateStub,
onBeforeDestroy : this.onBeforeDestroyStub,
onDestroy : this.onDestroyStub
});
this.view = new this.View();
this.view.render();
this.removeSpy = this.sinon.spy(this.view, 'remove');
this.stopListeningSpy = this.sinon.spy(this.view, 'stopListening');
this.triggerSpy = this.sinon.spy(this.view, 'trigger');
this.sinon.spy(this.view, 'destroy');
this.view.destroy();
});
it('should remove the views EL from the DOM', function() {
expect(this.removeSpy).to.have.been.calledOnce;
});
it('should unbind any listener to custom view events', function() {
expect(this.stopListeningSpy).to.have.been.calledOnce;
});
it('should trigger "before:destroy"', function(){
expect(this.triggerSpy).to.have.been.calledWith('before:destroy');
});
it('should trigger "destroy"', function(){
expect(this.triggerSpy).to.have.been.calledWith('destroy');
});
it('should call "onBeforeDestroy" if provided', function() {
expect(this.onBeforeDestroyStub).to.have.been.called;
});
it('should call "onDestroy" if provided', function() {
expect(this.onDestroyStub).to.have.been.called;
});
it('should return the view', function() {
expect(this.view.destroy).to.have.returned(this.view);
});
});
describe('when re-rendering an ItemView that is already shown', function() {
beforeEach(function() {
this.onDomRefreshStub = this.sinon.stub();
this.View = Marionette.ItemView.extend({
template : this.templateStub,
onDomRefresh : this.onDomRefreshStub
});
this.view = new this.View();
this.setFixtures(this.view.$el);
this.view.render();
this.view.triggerMethod('show');
this.view.render();
});
it('should trigger a dom:refresh event', function() {
expect(this.onDomRefreshStub).to.have.been.calledTwice;
});
});
describe('has a valid inheritance chain back to Marionette.View', function() {
beforeEach(function() {
this.constructorSpy = this.sinon.spy(Marionette, 'View');
this.itemView = new Marionette.ItemView();
});
it('calls the parent Marionette.Views constructor function on instantiation', function() {
expect(this.constructorSpy).to.have.been.called;
});
});
describe("when serializing view data", function(){
beforeEach(function(){
this.modelData = { foo: "bar" };
this.collectionData = [ { foo: "bar" }, { foo: "baz" } ];
this.itemView = new Marionette.ItemView();
this.sinon.spy(this.itemView, "serializeModel");
this.sinon.spy(this.itemView, "serializeCollection");
});
it("should return an empty object without data", function(){
expect(this.itemView.serializeData()).to.deep.equal({ });
});
describe('and the view has a model', function() {
beforeEach(function() {
this.itemView.model = new Backbone.Model(this.modelData);
this.itemView.serializeData();
});
it("should call serializeModel", function() {
expect(this.itemView.serializeModel).to.have.been.calledOnce;
});
it('should not call serializeCollection', function() {
expect(this.itemView.serializeCollection).to.not.have.been.called;
});
});
describe('and the view only has a collection', function() {
beforeEach(function() {
this.itemView.collection = new Backbone.Collection(this.collectionData);
this.itemView.serializeData();
});
it("should call serializeCollection", function(){
expect(this.itemView.serializeCollection).to.have.been.calledOnce;
});
it("should not call serializeModel", function() {
expect(this.itemView.serializeModel).to.not.have.been.called;
});
});
describe('and the view has a collection and a model', function() {
beforeEach(function() {
this.itemView.model = new Backbone.Model(this.modelData);
this.itemView.collection = new Backbone.Collection(this.collectionData);
this.itemView.serializeData();
});
it("should call serializeModel", function() {
expect(this.itemView.serializeModel).to.have.been.calledOnce;
});
it('should not call serializeCollection', function() {
expect(this.itemView.serializeCollection).to.not.have.been.called;
});
});
});
describe("when serializing a collection", function(){
beforeEach(function(){
this.collectionData = [ { foo: "bar" }, { foo: "baz" } ];
this.itemView = new Marionette.ItemView({
collection: new Backbone.Collection(this.collectionData)
});
});
it("should serialize to an items attribute", function(){
expect(this.itemView.serializeData().items).to.be.defined;
});
it("should serialize all models", function(){
expect(this.itemView.serializeData().items).to.deep.equal(this.collectionData);
});
});
describe("has a valid inheritance chain back to Marionette.View", function(){
beforeEach(function(){
this.constructor = this.sinon.spy(Marionette, "View");
this.collectionView = new Marionette.ItemView();
});
it("calls the parent Marionette.View's constructor function on instantiation", function(){
expect(this.constructor).to.have.been.calledOnce;
});
});
});