Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

reorganize and refactor common triggerMethod, normalizeMethods, and m… #3549

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 24 additions & 13 deletions test/unit/common/merge-options.spec.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import View from '../../../src/view';

describe('mergeOptions', function() {
'use strict';
let MyView;
let MyUndefinedMergeOptionsView;

beforeEach(function() {
this.MyView = Marionette.View.extend({
MyView = View.extend({
myViewOptions: ['color', 'size'],

initialize: function(options) {
this.mergeOptions(options, this.myViewOptions);
}
});

this.MyUndefinedMergeOptionsView = Marionette.View.extend({
MyUndefinedMergeOptionsView = View.extend({
initialize: function(options) {
this.mergeOptions(undefined);
}
Expand All @@ -19,61 +23,68 @@ describe('mergeOptions', function() {

describe('when instantiating a view with no options', function() {
it('should not throw an Error', function() {
var suite = this;
expect(function() {
suite.myView = new suite.MyView();
new MyView();
}).to.not.throw();
});
});

describe('when calling mergeOptions with an undefined', function() {
let view;

it('should return instantly without merging anything', function() {
this.view = new this.MyUndefinedMergeOptionsView();
expect(this.view.options).to.deep.equal({});
view = new MyUndefinedMergeOptionsView();
expect(view.options).to.deep.equal({});
});
});

describe('when instantiating a view with options, none matching the keys', function() {
let myView;

beforeEach(function() {
this.myView = new this.MyView({
myView = new MyView({
hungry: true,
country: 'USA'
});
});

it('should not merge any of those options', function() {
expect(this.myView).to.not.contain.keys('hungry', 'country');
expect(myView).to.not.contain.keys('hungry', 'country');
});
});

describe('when instantiating a view with options, some matching the keys', function() {
let myView;

beforeEach(function() {
this.myView = new this.MyView({
myView = new MyView({
hungry: true,
country: 'USA',
color: 'blue'
});
});

it('should not merge the ones that do not match', function() {
expect(this.myView).to.not.contain.keys('hungry', 'country');
expect(myView).to.not.contain.keys('hungry', 'country');
});

it('should merge the ones that match', function() {
expect(this.myView).to.contain.keys('color');
expect(myView).to.contain.keys('color');
});
});

describe('when instantiating a view with options, all matching the keys', function() {
let myView;

beforeEach(function() {
this.myView = new this.MyView({
myView = new MyView({
size: 'large',
color: 'blue'
});
});

it('should merge all of the options', function() {
expect(this.myView).to.contain.keys('color', 'size');
expect(myView).to.contain.keys('color', 'size');
});
});
});
19 changes: 13 additions & 6 deletions test/unit/common/normalize-methods.spec.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,32 @@
import View from '../../../src/view';

describe('normalizeMethods', function() {
'use strict';

let MyView;
let view;
let hash;
let normalizedHash;

beforeEach(function() {
this.View = Backbone.Marionette.View.extend({
MyView = View.extend({
foo: this.sinon.stub()
});
this.view = new this.View();
this.hash = {
view = new MyView();
hash = {
'foo': 'foo',
'bar': 'bar'
};
this.normalizedHash = this.view.normalizeMethods(this.hash);
normalizedHash = view.normalizeMethods(hash);
});

describe('when normalizeMethods is called with a hash of functions and strings', function() {
it('should convert the strings that exist as functions to functions', function() {
expect(this.normalizedHash).to.have.property('foo');
expect(normalizedHash).to.have.property('foo');
});

it('should ignore strings that dont exist as functions on the context', function() {
expect(this.normalizedHash).not.to.have.property('bar');
expect(normalizedHash).not.to.have.property('bar');
});
});
});
141 changes: 87 additions & 54 deletions test/unit/common/trigger-method.spec.js
Original file line number Diff line number Diff line change
@@ -1,155 +1,188 @@
import _ from 'underscore';
import CollectionView from '../../../src/collection-view';
import View from '../../../src/view';


describe('trigger event and method name', function() {
'use strict';

let returnValue;
let argumentOne;
let argumentTwo;
let eventHandler;
let methodHandler;

beforeEach(function() {
this.returnValue = 'foo';
this.argumentOne = 'bar';
this.argumentTwo = 'baz';
returnValue = 'foo';
argumentOne = 'bar';
argumentTwo = 'baz';

this.eventHandler = this.sinon.stub();
this.methodHandler = this.sinon.stub().returns(this.returnValue);
eventHandler = this.sinon.stub();
methodHandler = this.sinon.stub().returns(returnValue);
});

describe('triggering an event when passed options', function() {
let view;

beforeEach(function() {
this.view = new Marionette.View({
onFoo: this.methodHandler
view = new View({
onFoo: methodHandler
});
this.view.triggerMethod('foo');
view.triggerMethod('foo');
});

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

describe('when triggering an event', function() {
let view;
let triggerMethodSpy;

beforeEach(function() {
this.view = new Marionette.View();
this.triggerMethodSpy = this.sinon.spy(this.view, 'triggerMethod');
view = new View();
triggerMethodSpy = this.sinon.spy(view, 'triggerMethod');

this.view.onFoo = this.methodHandler;
this.view.on('foo', this.eventHandler);
this.view.triggerMethod('foo');
view.onFoo = methodHandler;
view.on('foo', eventHandler);
view.triggerMethod('foo');
});

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

it('should call a method named on{Event}', function() {
expect(this.methodHandler).to.have.been.calledOnce;
expect(methodHandler).to.have.been.calledOnce;
});

it('returns the value returned by the on{Event} method', function() {
expect(this.triggerMethodSpy).to.have.been.calledOnce.and.returned(this.returnValue);
expect(triggerMethodSpy).to.have.been.calledOnce.and.returned(returnValue);
});

describe('when trigger does not exist', function() {
let triggerNonExistantEvent;

beforeEach(function() {
this.triggerNonExistantEvent = _.partial(this.view.triggerMethod, 'does:not:exist');
triggerNonExistantEvent = _.partial(view.triggerMethod, 'does:not:exist');
});

it('should do nothing', function() {
expect(this.triggerNonExistantEvent).not.to.throw;
expect(triggerNonExistantEvent).not.to.throw;
});
});
});

describe('when triggering an event with arguments', function() {
let view;

beforeEach(function() {
this.view = new Marionette.View();
this.view.onFoo = this.methodHandler;
this.view.on('foo', this.eventHandler);
this.view.triggerMethod('foo', this.argumentOne, this.argumentTwo);
view = new View();
view.onFoo = methodHandler;
view.on('foo', eventHandler);
view.triggerMethod('foo', argumentOne, argumentTwo);
});

it('should trigger the event with the args', function() {
expect(this.eventHandler).to.have.been.calledOnce.and.calledWith(this.argumentOne, this.argumentTwo);
expect(eventHandler).to.have.been.calledOnce.and.calledWith(argumentOne, argumentTwo);
});

it('should call a method named on{Event} with the args', function() {
expect(this.methodHandler).to.have.been.calledOnce.and.calledWith(this.argumentOne, this.argumentTwo);
expect(methodHandler).to.have.been.calledOnce.and.calledWith(argumentOne, argumentTwo);
});
});

describe('when triggering an event with : separated name', function() {
let view;

beforeEach(function() {
this.view = new Marionette.View();
this.view.onFooBar = this.methodHandler;
this.view.on('foo:bar', this.eventHandler);
this.view.triggerMethod('foo:bar', this.argumentOne, this.argumentTwo);
view = new View();
view.onFooBar = methodHandler;
view.on('foo:bar', eventHandler);
view.triggerMethod('foo:bar', argumentOne, argumentTwo);
});

it('should trigger the event with the args', function() {
expect(this.eventHandler).to.have.been.calledOnce.and.calledWith(this.argumentOne, this.argumentTwo);
expect(eventHandler).to.have.been.calledOnce.and.calledWith(argumentOne, argumentTwo);
});

it('should call a method named with each segment of the event name capitalized', function() {
expect(this.methodHandler).to.have.been.calledOnce.and.calledWith(this.argumentOne, this.argumentTwo);
expect(methodHandler).to.have.been.calledOnce.and.calledWith(argumentOne, argumentTwo);
});
});

describe('when triggering an event and no handler method exists', function() {
let view;

beforeEach(function() {
this.view = new Marionette.View();
this.view.on('foo:bar', this.eventHandler);
this.view.triggerMethod('foo:bar', this.argumentOne, this.argumentTwo);
view = new View();
view.on('foo:bar', eventHandler);
view.triggerMethod('foo:bar', argumentOne, argumentTwo);
});

it('should trigger the event with the args', function() {
expect(this.eventHandler).to.have.been.calledOnce.and.calledWith(this.argumentOne, this.argumentTwo);
expect(eventHandler).to.have.been.calledOnce.and.calledWith(argumentOne, argumentTwo);
});

it('should not call a method named with each segment of the event name capitalized', function() {
expect(this.methodHandler).not.to.have.been.calledOnce;
expect(methodHandler).not.to.have.been.calledOnce;
});
});

describe('when triggering an event and the attribute for that event is not a function', function() {
let view;

beforeEach(function() {
this.view = new Marionette.View();
this.view.onFooBar = 'baz';
this.view.on('foo:bar', this.eventHandler);
this.view.triggerMethod('foo:bar', this.argumentOne, this.argumentTwo);
view = new View();
view.onFooBar = 'baz';
view.on('foo:bar', eventHandler);
view.triggerMethod('foo:bar', argumentOne, argumentTwo);
});

it('should trigger the event with the args', function() {
expect(this.eventHandler).to.have.been.calledOnce.and.calledWith(this.argumentOne, this.argumentTwo);
expect(eventHandler).to.have.been.calledOnce.and.calledWith(argumentOne, argumentTwo);
});

it('should not call a method named with each segment of the event name capitalized', function() {
expect(this.methodHandler).not.to.have.been.calledOnce;
expect(methodHandler).not.to.have.been.calledOnce;
});
});

describe('triggering events through a child view', function() {
let onChildviewFooClickStub;
let MyView;
let MyCollectionView;
let collection;
let collectionView;
let childView;

beforeEach(function() {
this.onChildviewFooClickStub = this.sinon.stub();
onChildviewFooClickStub = this.sinon.stub();

this.View = Marionette.View.extend({
MyView = View.extend({
template: _.template('foo'),
triggers: {'click': 'foo:click'}
});

this.CollectionView = Marionette.CollectionView.extend({
childView: this.View,
MyCollectionView = CollectionView.extend({
childView: MyView,
childViewEventPrefix: 'childview',
onChildviewFooClick: this.onChildviewFooClickStub
onChildviewFooClick: onChildviewFooClickStub
});

this.collection = new Backbone.Collection([{foo: 'bar'}]);
this.collectionView = new this.CollectionView({
collection: this.collection
collection = new Backbone.Collection([{foo: 'bar'}]);
collectionView = new MyCollectionView({
collection: collection
});

this.collectionView.render();
this.childView = this.collectionView.children.findByModel(this.collection.at(0));
this.childView.$el.click();
collectionView.render();
childView = collectionView.children.findByModel(collection.at(0));
childView.$el.click();
});

it('should fire the event method once', function() {
expect(this.onChildviewFooClickStub).to.have.been.calledOnce;
expect(onChildviewFooClickStub).to.have.been.calledOnce;
});
});
});