Skip to content
This repository has been archived by the owner on Aug 30, 2021. It is now read-only.

Commit

Permalink
fix(core): Remove trailing slash from routes
Browse files Browse the repository at this point in the history
Adds an angular $urlRouterProvider service Rule to the Core module
configuration, that removes any trailing slashes in the URL for all routes.

The Rule is defined in the core routes configuration. Thus, in order for
this to work on all routes in the application, we have to inject the Core
module into each client module, as a dependecy in the client.module
configuration. Otherwise, we'd have to define the Rule in each module's route
configuration individually.

Adds missing client-side route configuration tests.

Tests demonstrate that the various route configurations can handle a trailing
slash in the URL, and gets resolved to the correct client route.

Fixes #1075
  • Loading branch information
mleanos committed Mar 7, 2016
1 parent 8f00edc commit b004986
Show file tree
Hide file tree
Showing 7 changed files with 530 additions and 2 deletions.
2 changes: 1 addition & 1 deletion modules/articles/client/articles.client.module.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
(function (app) {
'use strict';

app.registerModule('articles');
app.registerModule('articles', ['core']);// The core module is required for special route handling; see /core/client/config/core.client.routes
app.registerModule('articles.services');
app.registerModule('articles.routes', ['ui.router', 'articles.services']);
})(ApplicationConfiguration);
34 changes: 34 additions & 0 deletions modules/articles/tests/client/articles.client.routes.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,25 @@
});
});

describe('List Route', function () {
var liststate;
beforeEach(inject(function ($state) {
liststate = $state.get('articles.list');
}));

it('Should have the correct URL', function () {
expect(liststate.url).toEqual('');
});

it('Should not be abstract', function () {
expect(liststate.abstract).toBe(undefined);
});

it('Should have template', function () {
expect(liststate.templateUrl).toBe('modules/articles/client/views/list-articles.client.view.html');
});
});

describe('View Route', function () {
var viewstate,
ArticlesController,
Expand Down Expand Up @@ -190,6 +209,21 @@
});
});

describe('Handle Trailing Slash', function () {
beforeEach(inject(function ($state, $rootScope) {
$state.go('articles.list');
$rootScope.$digest();
}));

it('Should remove trailing slash', inject(function ($state, $location, $rootScope) {
$location.path('articles/');
$rootScope.$digest();

expect($location.path()).toBe('/articles');
expect($state.current.templateUrl).toBe('modules/articles/client/views/list-articles.client.view.html');
}));
});

});
});
})();
2 changes: 1 addition & 1 deletion modules/chat/client/chat.client.module.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
(function (app) {
'use strict';

app.registerModule('chat');
app.registerModule('chat', ['core']);
app.registerModule('chat.routes', ['ui.router']);
})(ApplicationConfiguration);
63 changes: 63 additions & 0 deletions modules/chat/tests/client/chat.client.routes.tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
(function () {
'use strict';

describe('Chat Route Tests', function () {
// Initialize global variables
var $scope,
Authentication;

//We can start by loading the main application module
beforeEach(module(ApplicationConfiguration.applicationModuleName));

// The injector ignores leading and trailing underscores here (i.e. _$httpBackend_).
// This allows us to inject a service but then attach it to a variable
// with the same name as the service.
beforeEach(inject(function ($rootScope, _Authentication_) {
// Set a new global scope
$scope = $rootScope.$new();
Authentication = _Authentication_;
}));

describe('Route Config', function () {
describe('Main Route', function () {
var mainstate;
beforeEach(inject(function ($state) {
mainstate = $state.get('chat');
}));

it('Should have the correct URL', function () {
expect(mainstate.url).toEqual('/chat');
});

it('Should not be abstract', function () {
expect(mainstate.abstract).toBe(undefined);
});

it('Should have templateUrl', function () {
expect(mainstate.templateUrl).toBe('modules/chat/client/views/chat.client.view.html');
});
});

describe('Handle Trailing Slash', function () {
beforeEach(inject(function ($state, $rootScope, _Authentication_) {
Authentication.user = {
name: 'user',
roles: ['user']
};

$state.go('chat');
$rootScope.$digest();
}));

it('Should remove trailing slash', inject(function ($state, $location, $rootScope) {
$location.path('chat/');
$rootScope.$digest();

expect($location.path()).toBe('/chat');
expect($state.current.templateUrl).toBe('modules/chat/client/views/chat.client.view.html');
}));
});

});
});
})();
11 changes: 11 additions & 0 deletions modules/core/client/config/core.client.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@
angular.module('core').config(['$stateProvider', '$urlRouterProvider',
function ($stateProvider, $urlRouterProvider) {

$urlRouterProvider.rule(function ($injector, $location) {
var path = $location.path();
var hasTrailingSlash = path.length > 1 && path[path.length - 1] === '/';

if (hasTrailingSlash) {
//if last character is a slash, return the same url without the slash
var newPath = path.substr(0, path.length - 1);
$location.replace().path(newPath);
}
});

// Redirect to 404 when route not found
$urlRouterProvider.otherwise(function ($injector, $location) {
$injector.get('$state').transitionTo('not-found', null, {
Expand Down
101 changes: 101 additions & 0 deletions modules/users/tests/client/users-admin.client.routes.tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
(function () {
'use strict';

describe('Users Admin Route Tests', function () {
// Initialize global variables
var $scope,
Authentication;

//We can start by loading the main application module
beforeEach(module(ApplicationConfiguration.applicationModuleName));

// The injector ignores leading and trailing underscores here (i.e. _$httpBackend_).
// This allows us to inject a service but then attach it to a variable
// with the same name as the service.
beforeEach(inject(function ($rootScope, _Authentication_) {
// Set a new global scope
$scope = $rootScope.$new();
Authentication = _Authentication_;
}));

describe('Route Config', function () {
describe('Main Route', function () {
var mainstate;
beforeEach(inject(function ($state) {
mainstate = $state.get('admin.users');
}));

it('Should have the correct URL', function () {
expect(mainstate.url).toEqual('/users');
});

it('Should not be abstract', function () {
expect(mainstate.abstract).toBe(undefined);
});

it('Should have templateUrl', function () {
expect(mainstate.templateUrl).toBe('modules/users/client/views/admin/list-users.client.view.html');
});
});

describe('View Route', function () {
var viewstate;
beforeEach(inject(function ($state) {
viewstate = $state.get('admin.user');
}));

it('Should have the correct URL', function () {
expect(viewstate.url).toEqual('/users/:userId');
});

it('Should not be abstract', function () {
expect(viewstate.abstract).toBe(undefined);
});

it('Should have templateUrl', function () {
expect(viewstate.templateUrl).toBe('modules/users/client/views/admin/view-user.client.view.html');
});
});

describe('Edit Route', function () {
var editstate;
beforeEach(inject(function ($state) {
editstate = $state.get('admin.user-edit');
}));

it('Should have the correct URL', function () {
expect(editstate.url).toEqual('/users/:userId/edit');
});

it('Should not be abstract', function () {
expect(editstate.abstract).toBe(undefined);
});

it('Should have templateUrl', function () {
expect(editstate.templateUrl).toBe('modules/users/client/views/admin/edit-user.client.view.html');
});
});

describe('Handle Trailing Slash', function () {
beforeEach(inject(function ($state, $rootScope, _Authentication_) {
Authentication.user = {
name: 'user',
roles: ['admin']
};

$state.go('admin.users');
$rootScope.$digest();
}));

it('Should remove trailing slash', inject(function ($state, $location, $rootScope) {
$location.path('admin/users/');
$rootScope.$digest();

expect($location.path()).toBe('/admin/users');
expect($state.current.templateUrl).toBe('modules/users/client/views/admin/list-users.client.view.html');
}));
});

});
});
})();
Loading

0 comments on commit b004986

Please sign in to comment.