Skip to content

Commit

Permalink
refactor and reorganize view trigger and entity events unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
wesmangum committed Nov 16, 2017
1 parent 91ab7ea commit 24eeb7e
Show file tree
Hide file tree
Showing 2 changed files with 248 additions and 170 deletions.
229 changes: 133 additions & 96 deletions test/unit/view.entity-events.spec.js
Original file line number Diff line number Diff line change
@@ -1,237 +1,274 @@
import _ from 'underscore';
import Backbone from 'backbone';
import View from '../../src/view';

describe('view entity events', function() {
'use strict';

let model;
let collection;
let fooStub;
let barStub;
let modelEventsStub
let collectionEventsStub;

beforeEach(function() {
this.model = new Backbone.Model();
this.collection = new Backbone.Collection();
model = new Backbone.Model();
collection = new Backbone.Collection();

this.fooStub = this.sinon.stub();
this.barStub = this.sinon.stub();
fooStub = this.sinon.stub();
barStub = this.sinon.stub();

this.modelEventsStub = this.sinon.stub().returns({'foo': this.fooStub});
this.collectionEventsStub = this.sinon.stub().returns({'bar': this.barStub});
modelEventsStub = this.sinon.stub().returns({'foo': fooStub});
collectionEventsStub = this.sinon.stub().returns({'bar': barStub});
});

describe('when a view has string-based model and collection event configuration', function() {
let fooOneStub;
let fooTwoStub;
let barOneStub;
let barTwoStub;
let TestView;

beforeEach(function() {
this.fooOneStub = this.sinon.stub();
this.fooTwoStub = this.sinon.stub();
this.barOneStub = this.sinon.stub();
this.barTwoStub = this.sinon.stub();
fooOneStub = this.sinon.stub();
fooTwoStub = this.sinon.stub();
barOneStub = this.sinon.stub();
barTwoStub = this.sinon.stub();

this.View = Marionette.View.extend({
TestView = View.extend({
modelEvents: {'foo': 'fooOne fooTwo'},
collectionEvents: {'bar': 'barOne barTwo'},
fooOne: this.fooOneStub,
fooTwo: this.fooTwoStub,
barOne: this.barOneStub,
barTwo: this.barTwoStub
fooOne: fooOneStub,
fooTwo: fooTwoStub,
barOne: barOneStub,
barTwo: barTwoStub
});

this.view = new this.View({
model: this.model,
collection: this.collection
new TestView({
model: model,
collection: collection
});
});

it('should wire up model events', function() {
this.model.trigger('foo');
expect(this.fooOneStub).to.have.been.calledOnce;
expect(this.fooTwoStub).to.have.been.calledOnce;
model.trigger('foo');
expect(fooOneStub).to.have.been.calledOnce;
expect(fooTwoStub).to.have.been.calledOnce;
});

it('should wire up collection events', function() {
this.collection.trigger('bar');
expect(this.barOneStub).to.have.been.calledOnce;
expect(this.barTwoStub).to.have.been.calledOnce;
collection.trigger('bar');
expect(barOneStub).to.have.been.calledOnce;
expect(barTwoStub).to.have.been.calledOnce;
});
});

describe('when a view has function-based model and collection event configuration', function() {
let TestView;

beforeEach(function() {
this.View = Marionette.View.extend({
modelEvents: {'foo': this.fooStub},
collectionEvents: {'bar': this.barStub}
TestView = View.extend({
modelEvents: {'foo': fooStub},
collectionEvents: {'bar': barStub}
});

this.view = new this.View({
model: this.model,
collection: this.collection
new TestView({
model: model,
collection: collection
});
});

it('should wire up model events', function() {
this.model.trigger('foo');
expect(this.fooStub).to.have.been.calledOnce;
model.trigger('foo');
expect(fooStub).to.have.been.calledOnce;
});

it('should wire up collection events', function() {
this.collection.trigger('bar');
expect(this.barStub).to.have.been.calledOnce;
collection.trigger('bar');
expect(barStub).to.have.been.calledOnce;
});
});

describe('when a view has model event config with a specified handler method that doesnt exist', function() {
beforeEach(function() {
var suite = this;
let MyView;
let getBadViewInstance;

this.View = Marionette.View.extend({
beforeEach(function() {
MyView = View.extend({
modelEvents: {foo: 'doesNotExist'},
model: this.model
model: model
});

this.getBadViewInstance = function() {
return new suite.View();
getBadViewInstance = function() {
return new MyView();
};
});

it('should error when method doesnt exist', function() {
var errorMessage = 'Method "doesNotExist" was configured as an event handler, but does not exist.';
expect(this.getBadViewInstance).to.throw(errorMessage);
const errorMessage = 'Method "doesNotExist" was configured as an event handler, but does not exist.';
expect(getBadViewInstance).to.throw(errorMessage);
});
});

describe('when configuring entity events with a function', function() {
let TestView;
let view;

beforeEach(function() {
this.View = Marionette.View.extend({
modelEvents: this.modelEventsStub,
collectionEvents: this.collectionEventsStub
TestView = View.extend({
modelEvents: modelEventsStub,
collectionEvents: collectionEventsStub
});

this.view = new this.View({
model: this.model,
collection: this.collection
view = new TestView({
model: model,
collection: collection
});
});

it('should trigger the model event', function() {
this.view.model.trigger('foo');
expect(this.fooStub).to.have.been.calledOnce;
view.model.trigger('foo');
expect(fooStub).to.have.been.calledOnce;
});

it('should trigger the collection event', function() {
this.view.collection.trigger('bar');
expect(this.barStub).to.have.been.calledOnce;
view.collection.trigger('bar');
expect(barStub).to.have.been.calledOnce;
});
});

describe('when undelegating entity events on a view', function() {
let TestView;
let view;

beforeEach(function() {
this.View = Marionette.View.extend({
TestView = View.extend({
modelEvents: {'foo': 'foo'},
collectionEvents: {'bar': 'bar'},
foo: this.fooStub,
bar: this.barStub
foo: fooStub,
bar: barStub
});

this.view = new this.View({
model: this.model,
collection: this.collection
view = new TestView({
model: model,
collection: collection
});

this.sinon.spy(this.view, 'undelegateEntityEvents');
this.view.undelegateEntityEvents();
this.sinon.spy(view, 'undelegateEntityEvents');
view.undelegateEntityEvents();

this.model.trigger('foo');
this.collection.trigger('bar');
model.trigger('foo');
collection.trigger('bar');
});

it('should undelegate the model events', function() {
expect(this.fooStub).not.to.have.been.calledOnce;
expect(fooStub).not.to.have.been.calledOnce;
});

it('should undelegate the collection events', function() {
expect(this.barStub).not.to.have.been.calledOnce;
expect(barStub).not.to.have.been.calledOnce;
});

it('should return the view', function() {
expect(this.view.undelegateEntityEvents).to.have.returned(this.view);
expect(view.undelegateEntityEvents).to.have.returned(view);
});
});

describe('when undelegating events on a view, delegating them again, and then triggering a model event', function() {
let TestView;
let view;

beforeEach(function() {
this.View = Marionette.View.extend({
TestView = View.extend({
modelEvents: {'foo': 'foo'},
collectionEvents: {'bar': 'bar'},
foo: this.fooStub,
bar: this.barStub
foo: fooStub,
bar: barStub
});

this.view = new this.View({
model: this.model,
collection: this.collection
view = new TestView({
model: model,
collection: collection
});

this.view.undelegateEntityEvents();
this.sinon.spy(this.view, 'delegateEntityEvents');
this.view.delegateEntityEvents();
view.undelegateEntityEvents();
this.sinon.spy(view, 'delegateEntityEvents');
view.delegateEntityEvents();
});

it('should fire the model event once', function() {
this.model.trigger('foo');
expect(this.fooStub).to.have.been.calledOnce;
model.trigger('foo');
expect(fooStub).to.have.been.calledOnce;
});

it('should fire the collection event once', function() {
this.collection.trigger('bar');
expect(this.barStub).to.have.been.calledOnce;
collection.trigger('bar');
expect(barStub).to.have.been.calledOnce;
});

it('should return the view from delegateEntityEvents', function() {
expect(this.view.delegateEntityEvents).to.have.returned(this.view);
expect(view.delegateEntityEvents).to.have.returned(view);
});
});

describe('when View bound to modelEvent replaces region with new view', function() {
let Layout;
let TestView;
let layoutView;
let itemViewOne;
let itemViewTwo;

beforeEach(function() {
this.Layout = Marionette.View.extend({
Layout = View.extend({
template: _.template('<div id="child"></div>'),
regions: {child: '#child'},
modelEvents: {'baz': 'foo'},
foo: this.fooStub
foo: fooStub
});

this.View = Marionette.View.extend({
TestView = View.extend({
template: _.template('bar'),
modelEvents: {'baz': 'bar'},
bar: this.barStub
bar: barStub
});

this.layoutView = new this.Layout({model: this.model});
this.itemViewOne = new this.View({model: this.model});
this.itemViewTwo = new this.View({model: this.model});
layoutView = new Layout({model: model});
itemViewOne = new TestView({model: model});
itemViewTwo = new TestView({model: model});

this.layoutView.render();
this.layoutView.getRegion('child').show(this.itemViewOne);
this.layoutView.getRegion('child').show(this.itemViewTwo);
layoutView.render();
layoutView.getRegion('child').show(itemViewOne);
layoutView.getRegion('child').show(itemViewTwo);

this.model.trigger('baz');
model.trigger('baz');
});

it('should leave the layoutView\'s modelEvent binded', function() {
expect(this.fooStub).to.have.been.calledOnce;
expect(fooStub).to.have.been.calledOnce;
});

it('should unbind the previous child view\'s modelEvents', function() {
expect(this.barStub).to.have.been.calledOnce;
expect(barStub).to.have.been.calledOnce;
});
});

// Fixes https://github.com/marionettejs/backbone.marionette/issues/3527
describe('when entity events are added in initialize', function() {
let view;

it('should not undelegate them', function() {
const View = Marionette.View.extend({
let TestView = View.extend({
template: false,
initialize() {
this.listenTo(this.model, 'foo', this.onFoo);
this.listenTo(model, 'foo', this.onFoo);
},
onFoo: this.sinon.stub()
});

const model = new Backbone.Model();
model = new Backbone.Model();

const view = new View({ model });
view = new TestView({ model });

model.trigger('foo');

Expand Down
Loading

0 comments on commit 24eeb7e

Please sign in to comment.