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

[BUGFIX beta] Ensure substates properly work with resetNamespace #14054

Merged
merged 1 commit into from
Aug 12, 2016
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
4 changes: 2 additions & 2 deletions packages/ember-routing/lib/system/dsl.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ DSL.prototype = {

if (this.enableLoadingSubstates) {
createRoute(this, `${name}_loading`, { resetNamespace: options.resetNamespace });
createRoute(this, `${name}_error`, { path: dummyErrorRoute });
createRoute(this, `${name}_error`, { resetNamespace: options.resetNamespace, path: dummyErrorRoute });
}

if (callback) {
Expand Down Expand Up @@ -193,7 +193,7 @@ if (isEnabled('ember-application-engines')) {
if (this.enableLoadingSubstates) {
let dummyErrorRoute = `/_unused_dummy_error_path_route_${name}/:error`;
createRoute(this, `${name}_loading`, { resetNamespace: options.resetNamespace });
createRoute(this, `${name}_error`, { path: dummyErrorRoute });
createRoute(this, `${name}_error`, { resetNamespace: options.resetNamespace, path: dummyErrorRoute });
}

let localFullName = 'application';
Expand Down
20 changes: 14 additions & 6 deletions packages/ember-routing/lib/system/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -1014,16 +1014,24 @@ function findChildRouteName(parentRoute, originatingChildRoute, name) {
}
}

let targetChildRouteName = originatingChildRouteName.split('.').pop();
let namespace = parentRoute.routeName === 'application' ? '' : parentRoute.routeName + '.';

// First, try a named loading state, e.g. 'foo_loading'
childName = namespace + targetChildRouteName + '_' + name;
// First, try a named loading state of the route, e.g. 'foo_loading'
childName = originatingChildRouteName + '_' + name;
if (routeHasBeenDefined(router, childName)) {
return childName;
}

// Second, try general loading state, e.g. 'loading'
// Second, try general loading state of the parent, e.g. 'loading'
let originatingChildRouteParts = originatingChildRouteName.split('.').slice(0, -1);
let namespace;

// If there is a namespace on the route, then we use that, otherwise we use
// the parent route as the namespace.
if (originatingChildRouteParts.length) {
namespace = originatingChildRouteParts.join('.') + '.';
} else {
namespace = parentRoute.routeName === 'application' ? '' : parentRoute.routeName + '.';
}

childName = namespace + name;
if (routeHasBeenDefined(router, childName)) {
return childName;
Expand Down
58 changes: 58 additions & 0 deletions packages/ember-routing/tests/system/dsl_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,33 @@ QUnit.test('should not add loading and error routes if _isRouterMapResult is fal
ok(!router.router.recognizer.names['blork_error'], 'error route was not added');
});

QUnit.test('should reset namespace of loading and error routes for routes with resetNamespace', function() {
Router.map(function() {
this.route('blork', function() {
this.route('blorp');
this.route('bleep', { resetNamespace: true });
});
});

let router = Router.create({
_hasModuleBasedResolver() { return true; }
});

router._initRouterJs();

ok(router.router.recognizer.names['blork.blorp'], 'nested route was created');
ok(router.router.recognizer.names['blork.blorp_loading'], 'nested loading route was added');
ok(router.router.recognizer.names['blork.blorp_error'], 'nested error route was added');

ok(router.router.recognizer.names['bleep'], 'reset route was created');
ok(router.router.recognizer.names['bleep_loading'], 'reset loading route was added');
ok(router.router.recognizer.names['bleep_error'], 'reset error route was added');

ok(!router.router.recognizer.names['blork.bleep'], 'nested reset route was not created');
ok(!router.router.recognizer.names['blork.bleep_loading'], 'nested reset loading route was not added');
ok(!router.router.recognizer.names['blork.bleep_error'], 'nested reset error route was not added');
});

if (isEnabled('ember-application-engines')) {
QUnit.test('should throw an error when defining a route serializer outside an engine', function() {
Router.map(function() {
Expand Down Expand Up @@ -267,4 +294,35 @@ if (isEnabled('ember-application-engines')) {
ok(!router.router.recognizer.names['chat_loading'], 'loading route was not added');
ok(!router.router.recognizer.names['chat_error'], 'error route was not added');
});

QUnit.test('should reset namespace of loading and error routes for mounts with resetNamespace', function() {
Router.map(function() {
this.route('news', function() {
this.mount('chat');
this.mount('blog', { resetNamespace: true });
});
});

let engineInstance = buildOwner({
routable: true
});

let router = Router.create({
_hasModuleBasedResolver() { return true; }
});
setOwner(router, engineInstance);
router._initRouterJs();

ok(router.router.recognizer.names['news.chat'], 'nested route was created');
ok(router.router.recognizer.names['news.chat_loading'], 'nested loading route was added');
ok(router.router.recognizer.names['news.chat_error'], 'nested error route was added');

ok(router.router.recognizer.names['blog'], 'reset route was created');
ok(router.router.recognizer.names['blog_loading'], 'reset loading route was added');
ok(router.router.recognizer.names['blog_error'], 'reset error route was added');

ok(!router.router.recognizer.names['news.blog'], 'nested reset route was not created');
ok(!router.router.recognizer.names['news.blog_loading'], 'nested reset loading route was not added');
ok(!router.router.recognizer.names['news.blog_error'], 'nested reset error route was not added');
});
}
71 changes: 69 additions & 2 deletions packages/ember/tests/routing/substates_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -794,7 +794,7 @@ QUnit.test('Default error event moves into nested route, prioritizing more speci

templates['grandma'] = 'GRANDMA {{outlet}}';
templates['grandma/error'] = 'ERROR: {{model.msg}}';
templates['grandma/mom_error'] = 'MOM ERROR: {{model.msg}}';
templates['mom_error'] = 'MOM ERROR: {{model.msg}}';

Router.map(function() {
this.route('grandma', function() {
Expand Down Expand Up @@ -842,7 +842,7 @@ QUnit.test('Prioritized substate entry works with preserved-namespace nested rou

Router.map(function() {
this.route('foo', function() {
this.route('foo.bar', { path: '/bar', resetNamespace: true }, function() {
this.route('bar', { path: '/bar' }, function() {
});
});
});
Expand All @@ -865,6 +865,37 @@ QUnit.test('Prioritized substate entry works with preserved-namespace nested rou
equal(jQuery('#app', '#qunit-fixture').text(), 'YAY');
});

QUnit.test('Prioritized substate entry works with reset-namespace nested routes', function() {
expect(2);

templates['bar_loading'] = 'BAR LOADING';
templates['bar/index'] = 'YAY';

Router.map(function() {
this.route('foo', function() {
this.route('bar', { path: '/bar', resetNamespace: true }, function() {
});
});
});

App.ApplicationController = Controller.extend();

let deferred = RSVP.defer();
App.BarRoute = Route.extend({
model() {
return deferred.promise;
}
});

bootApplication('/foo/bar');

equal(jQuery('#app', '#qunit-fixture').text(), 'BAR LOADING', 'foo.bar_loading was entered (as opposed to something like foo/foo/bar_loading)');

run(deferred, 'resolve');

equal(jQuery('#app', '#qunit-fixture').text(), 'YAY');
});

QUnit.test('Prioritized loading substate entry works with preserved-namespace nested routes', function() {
expect(2);

Expand Down Expand Up @@ -1090,4 +1121,40 @@ if (isEnabled('ember-application-engines')) {

equal(jQuery('#app', '#qunit-fixture').text(), 'BLOG ERROR', 'news/blog_loading was entered');
});

QUnit.test('Slow Promise from an Engine application route enters the mounts loading state with resetNamespace', function() {
expect(1);

templates['blog_loading'] = 'BLOG LOADING';

// Register engine
let BlogEngine = Engine.extend();
registry.register('engine:blog', BlogEngine);

// Register engine route map
let BlogMap = function() {};
registry.register('route-map:blog', BlogMap);

Router.map(function() {
this.route('news', function() {
this.mount('blog', { resetNamespace: true });
});
});

let deferred = RSVP.defer();
let BlogRoute = Route.extend({
model() {
return deferred.promise;
}
});

var blog = container.lookup('engine:blog');
blog.register('route:application', BlogRoute);

bootApplication('/news/blog');

equal(jQuery('#app', '#qunit-fixture').text(), 'BLOG LOADING', 'news/blog_loading was entered');

run(deferred, 'resolve');
});
}