k.backbone.marionette
Version:
Make your Backbone.js apps dance!
254 lines (208 loc) • 8.21 kB
JavaScript
describe('app router', function() {
'use strict';
afterEach(function() {
window.location.hash = '';
});
describe('when a route is configured with a method that does not exist on the controller', function() {
beforeEach(function () {
var suite = this;
this.controller = {};
this.Router = Marionette.AppRouter.extend({
appRoutes: { 'foo-route': 'doesNotExist' }
});
this.run = function() {
suite.router = new suite.Router({controller: suite.controller});
};
});
it('should throw an error saying the method does not exist', function() {
expect(this.run).to.throw('Method "doesNotExist" was not found on the controller');
});
});
describe('when a controller is passed through the constructor and a route fires', function() {
beforeEach(function() {
this.controller = { foo: this.sinon.stub() };
this.Router = Marionette.AppRouter.extend({
appRoutes: { 'foo-route': 'foo' }
});
this.router = new this.Router({ controller: this.controller });
Backbone.history.start();
this.router.navigate('foo-route', true);
});
it('should call the configured method on the controller passed in the constructor', function() {
expect(this.controller.foo).to.have.been.calledOnce;
});
it('should execute the controller method with the context of the controller', function() {
expect(this.controller.foo).to.have.been.calledOnce.and.calledOn(this.controller);
});
});
describe('when a controller is provided in the router definition and a route fires', function() {
beforeEach(function() {
this.controller = { foo: this.sinon.stub() };
this.Router = Marionette.AppRouter.extend({
appRoutes: { 'foo-route': 'foo' },
controller: this.controller
});
this.router = new this.Router();
Backbone.history.start();
this.router.navigate('foo-route', true);
});
it('should execute the controller method with the context of the controller', function() {
expect(this.controller.foo).to.have.been.calledOnce.and.calledOn(this.controller);
});
});
describe('when a second route fires from a controller instance', function() {
beforeEach(function() {
this.controller = {
foo: this.sinon.stub(),
bar: this.sinon.stub()
};
this.Router = Marionette.AppRouter.extend({
appRoutes: {
'foo-route': 'foo',
'bar-route': 'bar'
}
});
this.router = new this.Router({ controller: this.controller });
Backbone.history.start();
this.router.navigate('foo-route', true);
this.router.navigate('bar-route', true);
});
it('should execute the controller method with the context of the controller', function() {
expect(this.controller.bar).to.have.been.calledOnce.and.calledOn(this.controller);
});
});
describe('when a route fires with parameters', function() {
beforeEach(function() {
this.fooParam = 'bar';
this.controller = { foo: this.sinon.stub() };
this.Router = Marionette.AppRouter.extend({
onRoute: this.sinon.stub(),
appRoutes: { 'foo-route/:id': 'foo' }
});
this.router = new this.Router({ controller: this.controller });
Backbone.history.start();
this.router.navigate('foo-route/' + this.fooParam, true);
});
it('should call the configured method with parameters', function() {
expect(this.controller.foo).to.have.always.been.calledWith(this.fooParam);
});
it('should call the onShow method for the route, passing the name of the route, the matched route, and the params', function() {
expect(this.router.onRoute).to.have.been.calledOnce;
expect(this.router.onRoute).to.have.been.calledWith('foo', 'foo-route/:id', [this.fooParam, null]);
});
});
describe('when a standard route is defined and fired', function() {
beforeEach(function() {
this.fooStub = this.sinon.stub();
this.Router = Marionette.AppRouter.extend({
routes: { 'foo-route': 'foo' },
foo: this.fooStub
});
this.router = new this.Router();
Backbone.history.start();
this.router.navigate('foo-route', true);
});
it('should fire the route callback', function() {
expect(this.fooStub).to.have.been.calledOnce;
});
});
describe('when router configured with ambiguous routes', function() {
beforeEach(function() {
this.controller = {
fooBar: this.sinon.stub(),
fooId: this.sinon.stub()
};
this.Router = Marionette.AppRouter.extend({
appRoutes: {
'foo/bar': 'fooBar',
'foo/:id': 'fooId'
}
});
Backbone.history.start();
this.router = new this.Router({ controller: this.controller });
this.router.navigate('foo/bar', true);
});
it('should take routes order into account', function() {
expect(this.controller.fooBar).to.have.been.calledOnce;
expect(this.controller.fooId).not.to.have.been.calledOnce;
});
});
describe('when routes are in the wrong order', function() {
beforeEach(function() {
this.controller = {
fooBar: this.sinon.stub(),
fooId: this.sinon.stub()
};
this.Router = Marionette.AppRouter.extend({
appRoutes: {
'foo/:id': 'fooId',
'foo/bar': 'fooBar'
}
});
Backbone.history.start();
this.router = new this.Router({ controller: this.controller });
this.router.navigate('foo/bar', true);
});
it('should fire the wrong route', function() {
expect(this.controller.fooBar).not.to.have.been.calledOnce;
expect(this.controller.fooId).to.have.been.calledOnce;
});
});
describe('when an app route is added manually', function() {
beforeEach(function() {
this.controller = { foo: this.sinon.stub() };
this.Router = Marionette.AppRouter.extend();
this.router = new this.Router({ controller: this.controller });
Backbone.history.start();
this.router.appRoute('foo-route', 'foo');
this.router.navigate('foo-route', true);
});
it('should fire the route', function() {
expect(this.controller.foo).to.have.been.calledOnce;
});
});
describe('when app routes are provided in the constructor', function() {
beforeEach(function() {
this.controller = {
foo: this.sinon.stub(),
bar: this.sinon.stub()
};
this.AppRouter = Marionette.AppRouter.extend({
appRoutes: { 'foo-route': 'foo' }
});
this.appRouter = new this.AppRouter({
controller: this.controller,
appRoutes: { 'bar-route': 'bar' }
});
Backbone.history.start();
this.appRouter.navigate('foo-route', true);
this.appRouter.navigate('bar-route', true);
});
it('should override the configured routes and use the constructor param', function() {
expect(this.controller.foo).not.to.have.been.calledOnce;
expect(this.controller.bar).to.have.been.calledOnce;
});
});
describe('when a route fires with parameters and app routes are provided exclusively in the constructor', function() {
beforeEach(function() {
this.fooParam = 'bar';
this.controller = { foo: this.sinon.stub() };
this.AppRouter = Marionette.AppRouter.extend({
onRoute: this.sinon.stub()
});
this.appRouter = new this.AppRouter({
controller: this.controller,
appRoutes: { 'foo-route/:id': 'foo' }
});
Backbone.history.start();
this.appRouter.navigate('foo-route/' + this.fooParam, true);
});
it('should call the configured method with parameters', function() {
expect(this.controller.foo).to.have.always.been.calledWith(this.fooParam);
});
it('should call the onRoute method for the route, passing the name of the route, the matched route, and the params', function() {
expect(this.appRouter.onRoute).to.have.been.calledOnce;
expect(this.appRouter.onRoute).to.have.been.calledWith('foo', 'foo-route/:id', [this.fooParam, null]);
});
});
});