diff --git a/packages/ember-routing/lib/services/router.js b/packages/ember-routing/lib/services/router.js index 4dddb018893..2c72d1de3ce 100644 --- a/packages/ember-routing/lib/services/router.js +++ b/packages/ember-routing/lib/services/router.js @@ -32,7 +32,7 @@ const RouterService = Service.extend({ @method transitionTo @category ember-routing-router-service - @param {String} name the name of the route or a URL + @param {String} routeNameOrUrl the name of the route or a URL @param {...Object} models the model(s) or identifier(s) to be used while transitioning to the route. @param {Object} [options] optional hash with a queryParams property @@ -41,7 +41,7 @@ const RouterService = Service.extend({ attempted transition @public */ - transitionTo() { + transitionTo(/* routeNameOrUrl, ...models, options */) { return this.router.transitionTo(...arguments); }, @@ -53,7 +53,7 @@ const RouterService = Service.extend({ @method replaceWith @category ember-routing-router-service - @param {String} name the name of the route or a URL + @param {String} routeNameOrUrl the name of the route or a URL @param {...Object} models the model(s) or identifier(s) to be used while transitioning to the route. @param {Object} [options] optional hash with a queryParams property @@ -62,8 +62,24 @@ const RouterService = Service.extend({ attempted transition @public */ - replaceWith() { + replaceWith(/* routeNameOrUrl, ...models, options */) { return this.router.replaceWith(...arguments); + }, + + /** + Generate a URL based on the supplied route name. + + @method urlFor + @param {String} routeName the name of the route + @param {...Object} models the model(s) or identifier(s) to be used while + transitioning to the route. + @param {Object} [options] optional hash with a queryParams property + containing a mapping of query parameters + @return {String} the string representing the generated URL + @public + */ + urlFor(/* routeName, ...models, options */) { + return this.router.generate(...arguments); } }); diff --git a/packages/ember/tests/routing/router_service_test/replaceWith_test.js b/packages/ember/tests/routing/router_service_test/replaceWith_test.js index 4f068793f32..179294d7fd9 100644 --- a/packages/ember/tests/routing/router_service_test/replaceWith_test.js +++ b/packages/ember/tests/routing/router_service_test/replaceWith_test.js @@ -67,6 +67,24 @@ if (isFeatureEnabled('ember-routing-router-service')) { }); } + ['@test RouterService#replaceWith with basic route using URLs replaces location'](assert) { + assert.expect(1); + + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('/child'); + }) + .then(() => { + return this.routerService.transitionTo('/sister'); + }) + .then(() => { + return this.routerService.replaceWith('/brother'); + }) + .then(() => { + assert.deepEqual(this.state, ['/', '/child', '/brother']); + }); + } + ['@test RouterService#replaceWith transitioning back to previously visited route replaces location'](assert) { assert.expect(1); diff --git a/packages/ember/tests/routing/router_service_test/transitionTo_test.js b/packages/ember/tests/routing/router_service_test/transitionTo_test.js index 9b510f94f7d..d1a2f8f30aa 100644 --- a/packages/ember/tests/routing/router_service_test/transitionTo_test.js +++ b/packages/ember/tests/routing/router_service_test/transitionTo_test.js @@ -127,6 +127,38 @@ if (isFeatureEnabled('ember-routing-router-service')) { }); } + ['@test RouterService#transitionTo with basic route using URL'](assert) { + assert.expect(1); + + let componentInstance; + + this.registerTemplate('parent.index', '{{foo-bar}}'); + + this.registerComponent('foo-bar', { + ComponentClass: Component.extend({ + routerService: inject.service('router'), + init() { + this._super(); + componentInstance = this; + }, + actions: { + transitionToSister() { + get(this, 'routerService').transitionTo('/sister'); + } + } + }), + template: `foo-bar` + }); + + return this.visit('/').then(() => { + run(function() { + componentInstance.send('transitionToSister'); + }); + + assert.equal(this.routerService.get('currentRouteName'), 'parent.sister'); + }); + } + ['@test RouterService#transitionTo with dynamic segment'](assert) { assert.expect(3); diff --git a/packages/ember/tests/routing/router_service_test/urlFor_test.js b/packages/ember/tests/routing/router_service_test/urlFor_test.js new file mode 100644 index 00000000000..54b83541357 --- /dev/null +++ b/packages/ember/tests/routing/router_service_test/urlFor_test.js @@ -0,0 +1,243 @@ +import { + Controller, + inject, + String +} from 'ember-runtime'; +import { Component } from 'ember-glimmer'; +import { Route, NoneLocation } from 'ember-routing'; +import { + get, + set +} from 'ember-metal'; +import { + RouterTestCase, + moduleFor +} from 'internal-test-helpers'; + +import { isFeatureEnabled } from 'ember-metal'; + +function setupController(app, name) { + let controllerName = `${String.capitalize(name)}Controller`; + + Object.defineProperty(app, controllerName, { + get() { + throw new Error(`Generating a URL should not require instantiation of a ${controllerName}.`); + } + }); +} + +function buildQueryParams(queryParams) { + return { + queryParams + }; +} + +if (isFeatureEnabled('ember-routing-router-service')) { + moduleFor('Router Service - urlFor', class extends RouterTestCase { + ['@test RouterService#urlFor returns URL for simple route'](assert) { + assert.expect(1); + + return this.visit('/').then(() => { + let expectedURL = this.routerService.urlFor('parent.child'); + + assert.equal('/child', expectedURL); + }); + } + + ['@test RouterService#urlFor returns URL for simple route with dynamic segments'](assert) { + assert.expect(1); + + setupController(this.application, 'dynamic'); + + let dynamicModel = { id: 1, contents: 'much dynamicism' }; + + return this.visit('/').then(() => { + let expectedURL = this.routerService.urlFor('dynamic', dynamicModel); + + assert.equal('/dynamic/1', expectedURL); + }); + } + + ['@test RouterService#urlFor returns URL for simple route with basic query params'](assert) { + assert.expect(1); + + let queryParams = buildQueryParams({ foo: 'bar' }); + + return this.visit('/').then(() => { + let expectedURL = this.routerService.urlFor('parent.child', queryParams); + + assert.equal('/child?foo=bar', expectedURL); + }); + } + + ['@test RouterService#urlFor returns URL for simple route with array as query params'](assert) { + assert.expect(1); + + let queryParams = buildQueryParams({ selectedItems: ['a', 'b', 'c'] }); + + return this.visit('/').then(() => { + let expectedURL = this.routerService.urlFor('parent.child', queryParams); + + assert.equal('/child?selectedItems[]=a&selectedItems[]=b&selectedItems[]=c', expectedURL); + }); + } + + ['@test RouterService#urlFor returns URL for simple route with null query params'](assert) { + assert.expect(1); + + let queryParams = buildQueryParams({ foo: null }); + + return this.visit('/').then(() => { + let expectedURL = this.routerService.urlFor('parent.child', queryParams); + + assert.equal('/child', expectedURL); + }); + } + + ['@test RouterService#urlFor returns URL for simple route with undefined query params'](assert) { + assert.expect(1); + + let queryParams = buildQueryParams({ foo: undefined }); + + return this.visit('/').then(() => { + let expectedURL = this.routerService.urlFor('parent.child', queryParams); + + assert.equal('/child', expectedURL); + }); + } + + ['@test RouterService#urlFor returns URL for simple route with dynamic segments and basic query params'](assert) { + assert.expect(1); + + let queryParams = buildQueryParams({ foo: 'bar' }); + + return this.visit('/').then(() => { + let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); + + assert.equal('/dynamic/1?foo=bar', expectedURL); + }); + } + + ['@test RouterService#urlFor returns URL for simple route with dynamic segments and array as query params'](assert) { + assert.expect(1); + + let queryParams = buildQueryParams({ selectedItems: ['a', 'b', 'c'] }); + + return this.visit('/').then(() => { + let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); + + assert.equal('/dynamic/1?selectedItems[]=a&selectedItems[]=b&selectedItems[]=c', expectedURL); + }); + } + + ['@test RouterService#urlFor returns URL for simple route with dynamic segments and null query params'](assert) { + assert.expect(1); + + let queryParams = buildQueryParams({ foo: null }); + + return this.visit('/').then(() => { + let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); + + assert.equal('/dynamic/1', expectedURL); + }); + } + + ['@test RouterService#urlFor returns URL for simple route with dynamic segments and undefined query params'](assert) { + assert.expect(1); + + let queryParams = buildQueryParams({ foo: undefined }); + + return this.visit('/').then(() => { + let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); + + assert.equal('/dynamic/1', expectedURL); + }); + } + + ['@test RouterService#urlFor correctly transitions to route via generated path'](assert) { + assert.expect(1); + + let expectedURL; + + return this.visit('/') + .then(() => { + expectedURL = this.routerService.urlFor('parent.child'); + + return this.routerService.transitionTo(expectedURL); + }) + .then(() => { + assert.equal(expectedURL, this.routerService.get('currentURL')); + }); + } + + ['@test RouterService#urlFor correctly transitions to route via generated path with dynamic segments'](assert) { + assert.expect(1); + + let expectedURL; + let dynamicModel = { id: 1 }; + + this.registerRoute('dynamic', Route.extend({ + model() { + return dynamicModel; + } + })); + + return this.visit('/') + .then(() => { + expectedURL = this.routerService.urlFor('dynamic', dynamicModel); + + return this.routerService.transitionTo(expectedURL); + }) + .then(() => { + assert.equal(expectedURL, this.routerService.get('currentURL')); + }); + } + + ['@test RouterService#urlFor correctly transitions to route via generated path with query params'](assert) { + assert.expect(1); + + let expectedURL; + let actualURL; + let queryParams = buildQueryParams({ foo: 'bar' }); + + return this.visit('/') + .then(() => { + expectedURL = this.routerService.urlFor('parent.child', queryParams); + + return this.routerService.transitionTo(expectedURL); + }) + .then(() => { + actualURL = `${this.routerService.get('currentURL')}?foo=bar`; + + assert.equal(expectedURL, actualURL); + }); + } + + ['@test RouterService#urlFor correctly transitions to route via generated path with dynamic segments and query params'](assert) { + assert.expect(1); + + let expectedURL; + let actualURL; + let queryParams = buildQueryParams({ foo: 'bar' }); + let dynamicModel = { id: 1 }; + + this.registerRoute('dynamic', Route.extend({ + model() { + return dynamicModel; + } + })); + + return this.visit('/') + .then(() => { + expectedURL = this.routerService.urlFor('dynamic', dynamicModel, queryParams); + + return this.routerService.transitionTo(expectedURL); + }) + .then(() => { + actualURL = `${this.routerService.get('currentURL')}?foo=bar`; + + assert.equal(expectedURL, actualURL); + }); + } + }); +} diff --git a/packages/internal-test-helpers/lib/test-cases/router.js b/packages/internal-test-helpers/lib/test-cases/router.js index 985d19ba8da..ab0636e2205 100644 --- a/packages/internal-test-helpers/lib/test-cases/router.js +++ b/packages/internal-test-helpers/lib/test-cases/router.js @@ -11,7 +11,7 @@ export default class RouterTestCase extends ApplicationTestCase { this.route('sister'); this.route('brother'); }); - this.route('dynamic', { path: '/dynamic/:post_id' }); + this.route('dynamic', { path: '/dynamic/:dynamic_id' }); }); }