nexus site path corrected
[portal.git] / ecomp-portal-FE / client / bower_components / lodash / vendor / backbone / test / router.js
1 (function() {
2
3   var router = null;
4   var location = null;
5   var lastRoute = null;
6   var lastArgs = [];
7
8   var onRoute = function(routerParam, route, args) {
9     lastRoute = route;
10     lastArgs = args;
11   };
12
13   var Location = function(href) {
14     this.replace(href);
15   };
16
17   _.extend(Location.prototype, {
18
19     parser: document.createElement('a'),
20
21     replace: function(href) {
22       this.parser.href = href;
23       _.extend(this, _.pick(this.parser,
24         'href',
25         'hash',
26         'host',
27         'search',
28         'fragment',
29         'pathname',
30         'protocol'
31       ));
32       // In IE, anchor.pathname does not contain a leading slash though
33       // window.location.pathname does.
34       if (!/^\//.test(this.pathname)) this.pathname = '/' + this.pathname;
35     },
36
37     toString: function() {
38       return this.href;
39     }
40
41   });
42
43   QUnit.module('Backbone.Router', {
44
45     setup: function() {
46       location = new Location('http://example.com');
47       Backbone.history = _.extend(new Backbone.History, {location: location});
48       router = new Router({testing: 101});
49       Backbone.history.interval = 9;
50       Backbone.history.start({pushState: false});
51       lastRoute = null;
52       lastArgs = [];
53       Backbone.history.on('route', onRoute);
54     },
55
56     teardown: function() {
57       Backbone.history.stop();
58       Backbone.history.off('route', onRoute);
59     }
60
61   });
62
63   var ExternalObject = {
64     value: 'unset',
65
66     routingFunction: function(value) {
67       this.value = value;
68     }
69   };
70   ExternalObject.routingFunction = _.bind(ExternalObject.routingFunction, ExternalObject);
71
72   var Router = Backbone.Router.extend({
73
74     count: 0,
75
76     routes: {
77       'noCallback': 'noCallback',
78       'counter': 'counter',
79       'search/:query': 'search',
80       'search/:query/p:page': 'search',
81       'charñ': 'charUTF',
82       'char%C3%B1': 'charEscaped',
83       'contacts': 'contacts',
84       'contacts/new': 'newContact',
85       'contacts/:id': 'loadContact',
86       'route-event/:arg': 'routeEvent',
87       'optional(/:item)': 'optionalItem',
88       'named/optional/(y:z)': 'namedOptional',
89       'splat/*args/end': 'splat',
90       ':repo/compare/*from...*to': 'github',
91       'decode/:named/*splat': 'decode',
92       '*first/complex-*part/*rest': 'complex',
93       'query/:entity': 'query',
94       'function/:value': ExternalObject.routingFunction,
95       '*anything': 'anything'
96     },
97
98     initialize: function(options) {
99       this.testing = options.testing;
100       this.route('implicit', 'implicit');
101     },
102
103     counter: function() {
104       this.count++;
105     },
106
107     implicit: function() {
108       this.count++;
109     },
110
111     search: function(query, page) {
112       this.query = query;
113       this.page = page;
114     },
115
116     charUTF: function() {
117       this.charType = 'UTF';
118     },
119
120     charEscaped: function() {
121       this.charType = 'escaped';
122     },
123
124     contacts: function(){
125       this.contact = 'index';
126     },
127
128     newContact: function(){
129       this.contact = 'new';
130     },
131
132     loadContact: function(){
133       this.contact = 'load';
134     },
135
136     optionalItem: function(arg){
137       this.arg = arg !== void 0 ? arg : null;
138     },
139
140     splat: function(args) {
141       this.args = args;
142     },
143
144     github: function(repo, from, to) {
145       this.repo = repo;
146       this.from = from;
147       this.to = to;
148     },
149
150     complex: function(first, part, rest) {
151       this.first = first;
152       this.part = part;
153       this.rest = rest;
154     },
155
156     query: function(entity, args) {
157       this.entity    = entity;
158       this.queryArgs = args;
159     },
160
161     anything: function(whatever) {
162       this.anything = whatever;
163     },
164
165     namedOptional: function(z) {
166       this.z = z;
167     },
168
169     decode: function(named, path) {
170       this.named = named;
171       this.path = path;
172     },
173
174     routeEvent: function(arg) {
175     }
176
177   });
178
179   QUnit.test('initialize', function(assert) {
180     assert.expect(1);
181     assert.equal(router.testing, 101);
182   });
183
184   QUnit.test('routes (simple)', function(assert) {
185     assert.expect(4);
186     location.replace('http://example.com#search/news');
187     Backbone.history.checkUrl();
188     assert.equal(router.query, 'news');
189     assert.equal(router.page, void 0);
190     assert.equal(lastRoute, 'search');
191     assert.equal(lastArgs[0], 'news');
192   });
193
194   QUnit.test('routes (simple, but unicode)', function(assert) {
195     assert.expect(4);
196     location.replace('http://example.com#search/тест');
197     Backbone.history.checkUrl();
198     assert.equal(router.query, 'тест');
199     assert.equal(router.page, void 0);
200     assert.equal(lastRoute, 'search');
201     assert.equal(lastArgs[0], 'тест');
202   });
203
204   QUnit.test('routes (two part)', function(assert) {
205     assert.expect(2);
206     location.replace('http://example.com#search/nyc/p10');
207     Backbone.history.checkUrl();
208     assert.equal(router.query, 'nyc');
209     assert.equal(router.page, '10');
210   });
211
212   QUnit.test('routes via navigate', function(assert) {
213     assert.expect(2);
214     Backbone.history.navigate('search/manhattan/p20', {trigger: true});
215     assert.equal(router.query, 'manhattan');
216     assert.equal(router.page, '20');
217   });
218
219   QUnit.test('routes via navigate with params', function(assert) {
220     assert.expect(1);
221     Backbone.history.navigate('query/test?a=b', {trigger: true});
222     assert.equal(router.queryArgs, 'a=b');
223   });
224
225   QUnit.test('routes via navigate for backwards-compatibility', function(assert) {
226     assert.expect(2);
227     Backbone.history.navigate('search/manhattan/p20', true);
228     assert.equal(router.query, 'manhattan');
229     assert.equal(router.page, '20');
230   });
231
232   QUnit.test('reports matched route via nagivate', function(assert) {
233     assert.expect(1);
234     assert.ok(Backbone.history.navigate('search/manhattan/p20', true));
235   });
236
237   QUnit.test('route precedence via navigate', function(assert){
238     assert.expect(6);
239     // check both 0.9.x and backwards-compatibility options
240     _.each([{trigger: true}, true], function( options ){
241       Backbone.history.navigate('contacts', options);
242       assert.equal(router.contact, 'index');
243       Backbone.history.navigate('contacts/new', options);
244       assert.equal(router.contact, 'new');
245       Backbone.history.navigate('contacts/foo', options);
246       assert.equal(router.contact, 'load');
247     });
248   });
249
250   QUnit.test('loadUrl is not called for identical routes.', function(assert) {
251     assert.expect(0);
252     Backbone.history.loadUrl = function(){ assert.ok(false); };
253     location.replace('http://example.com#route');
254     Backbone.history.navigate('route');
255     Backbone.history.navigate('/route');
256     Backbone.history.navigate('/route');
257   });
258
259   QUnit.test('use implicit callback if none provided', function(assert) {
260     assert.expect(1);
261     router.count = 0;
262     router.navigate('implicit', {trigger: true});
263     assert.equal(router.count, 1);
264   });
265
266   QUnit.test('routes via navigate with {replace: true}', function(assert) {
267     assert.expect(1);
268     location.replace('http://example.com#start_here');
269     Backbone.history.checkUrl();
270     location.replace = function(href) {
271       assert.strictEqual(href, new Location('http://example.com#end_here').href);
272     };
273     Backbone.history.navigate('end_here', {replace: true});
274   });
275
276   QUnit.test('routes (splats)', function(assert) {
277     assert.expect(1);
278     location.replace('http://example.com#splat/long-list/of/splatted_99args/end');
279     Backbone.history.checkUrl();
280     assert.equal(router.args, 'long-list/of/splatted_99args');
281   });
282
283   QUnit.test('routes (github)', function(assert) {
284     assert.expect(3);
285     location.replace('http://example.com#backbone/compare/1.0...braddunbar:with/slash');
286     Backbone.history.checkUrl();
287     assert.equal(router.repo, 'backbone');
288     assert.equal(router.from, '1.0');
289     assert.equal(router.to, 'braddunbar:with/slash');
290   });
291
292   QUnit.test('routes (optional)', function(assert) {
293     assert.expect(2);
294     location.replace('http://example.com#optional');
295     Backbone.history.checkUrl();
296     assert.ok(!router.arg);
297     location.replace('http://example.com#optional/thing');
298     Backbone.history.checkUrl();
299     assert.equal(router.arg, 'thing');
300   });
301
302   QUnit.test('routes (complex)', function(assert) {
303     assert.expect(3);
304     location.replace('http://example.com#one/two/three/complex-part/four/five/six/seven');
305     Backbone.history.checkUrl();
306     assert.equal(router.first, 'one/two/three');
307     assert.equal(router.part, 'part');
308     assert.equal(router.rest, 'four/five/six/seven');
309   });
310
311   QUnit.test('routes (query)', function(assert) {
312     assert.expect(5);
313     location.replace('http://example.com#query/mandel?a=b&c=d');
314     Backbone.history.checkUrl();
315     assert.equal(router.entity, 'mandel');
316     assert.equal(router.queryArgs, 'a=b&c=d');
317     assert.equal(lastRoute, 'query');
318     assert.equal(lastArgs[0], 'mandel');
319     assert.equal(lastArgs[1], 'a=b&c=d');
320   });
321
322   QUnit.test('routes (anything)', function(assert) {
323     assert.expect(1);
324     location.replace('http://example.com#doesnt-match-a-route');
325     Backbone.history.checkUrl();
326     assert.equal(router.anything, 'doesnt-match-a-route');
327   });
328
329   QUnit.test('routes (function)', function(assert) {
330     assert.expect(3);
331     router.on('route', function(name) {
332       assert.ok(name === '');
333     });
334     assert.equal(ExternalObject.value, 'unset');
335     location.replace('http://example.com#function/set');
336     Backbone.history.checkUrl();
337     assert.equal(ExternalObject.value, 'set');
338   });
339
340   QUnit.test('Decode named parameters, not splats.', function(assert) {
341     assert.expect(2);
342     location.replace('http://example.com#decode/a%2Fb/c%2Fd/e');
343     Backbone.history.checkUrl();
344     assert.strictEqual(router.named, 'a/b');
345     assert.strictEqual(router.path, 'c/d/e');
346   });
347
348   QUnit.test("fires event when router doesn't have callback on it", function(assert) {
349     assert.expect(1);
350     router.on('route:noCallback', function(){ assert.ok(true); });
351     location.replace('http://example.com#noCallback');
352     Backbone.history.checkUrl();
353   });
354
355   QUnit.test('No events are triggered if #execute returns false.', function(assert) {
356     assert.expect(1);
357     var MyRouter = Backbone.Router.extend({
358
359       routes: {
360         foo: function() {
361           assert.ok(true);
362         }
363       },
364
365       execute: function(callback, args) {
366         callback.apply(this, args);
367         return false;
368       }
369
370     });
371
372     var myRouter = new MyRouter;
373
374     myRouter.on('route route:foo', function() {
375       assert.ok(false);
376     });
377
378     Backbone.history.on('route', function() {
379       assert.ok(false);
380     });
381
382     location.replace('http://example.com#foo');
383     Backbone.history.checkUrl();
384   });
385
386   QUnit.test('#933, #908 - leading slash', function(assert) {
387     assert.expect(2);
388     location.replace('http://example.com/root/foo');
389
390     Backbone.history.stop();
391     Backbone.history = _.extend(new Backbone.History, {location: location});
392     Backbone.history.start({root: '/root', hashChange: false, silent: true});
393     assert.strictEqual(Backbone.history.getFragment(), 'foo');
394
395     Backbone.history.stop();
396     Backbone.history = _.extend(new Backbone.History, {location: location});
397     Backbone.history.start({root: '/root/', hashChange: false, silent: true});
398     assert.strictEqual(Backbone.history.getFragment(), 'foo');
399   });
400
401   QUnit.test('#967 - Route callback gets passed encoded values.', function(assert) {
402     assert.expect(3);
403     var route = 'has%2Fslash/complex-has%23hash/has%20space';
404     Backbone.history.navigate(route, {trigger: true});
405     assert.strictEqual(router.first, 'has/slash');
406     assert.strictEqual(router.part, 'has#hash');
407     assert.strictEqual(router.rest, 'has space');
408   });
409
410   QUnit.test('correctly handles URLs with % (#868)', function(assert) {
411     assert.expect(3);
412     location.replace('http://example.com#search/fat%3A1.5%25');
413     Backbone.history.checkUrl();
414     location.replace('http://example.com#search/fat');
415     Backbone.history.checkUrl();
416     assert.equal(router.query, 'fat');
417     assert.equal(router.page, void 0);
418     assert.equal(lastRoute, 'search');
419   });
420
421   QUnit.test('#2666 - Hashes with UTF8 in them.', function(assert) {
422     assert.expect(2);
423     Backbone.history.navigate('charñ', {trigger: true});
424     assert.equal(router.charType, 'UTF');
425     Backbone.history.navigate('char%C3%B1', {trigger: true});
426     assert.equal(router.charType, 'UTF');
427   });
428
429   QUnit.test('#1185 - Use pathname when hashChange is not wanted.', function(assert) {
430     assert.expect(1);
431     Backbone.history.stop();
432     location.replace('http://example.com/path/name#hash');
433     Backbone.history = _.extend(new Backbone.History, {location: location});
434     Backbone.history.start({hashChange: false});
435     var fragment = Backbone.history.getFragment();
436     assert.strictEqual(fragment, location.pathname.replace(/^\//, ''));
437   });
438
439   QUnit.test('#1206 - Strip leading slash before location.assign.', function(assert) {
440     assert.expect(1);
441     Backbone.history.stop();
442     location.replace('http://example.com/root/');
443     Backbone.history = _.extend(new Backbone.History, {location: location});
444     Backbone.history.start({hashChange: false, root: '/root/'});
445     location.assign = function(pathname) {
446       assert.strictEqual(pathname, '/root/fragment');
447     };
448     Backbone.history.navigate('/fragment');
449   });
450
451   QUnit.test('#1387 - Root fragment without trailing slash.', function(assert) {
452     assert.expect(1);
453     Backbone.history.stop();
454     location.replace('http://example.com/root');
455     Backbone.history = _.extend(new Backbone.History, {location: location});
456     Backbone.history.start({hashChange: false, root: '/root/', silent: true});
457     assert.strictEqual(Backbone.history.getFragment(), '');
458   });
459
460   QUnit.test('#1366 - History does not prepend root to fragment.', function(assert) {
461     assert.expect(2);
462     Backbone.history.stop();
463     location.replace('http://example.com/root/');
464     Backbone.history = _.extend(new Backbone.History, {
465       location: location,
466       history: {
467         pushState: function(state, title, url) {
468           assert.strictEqual(url, '/root/x');
469         }
470       }
471     });
472     Backbone.history.start({
473       root: '/root/',
474       pushState: true,
475       hashChange: false
476     });
477     Backbone.history.navigate('x');
478     assert.strictEqual(Backbone.history.fragment, 'x');
479   });
480
481   QUnit.test('Normalize root.', function(assert) {
482     assert.expect(1);
483     Backbone.history.stop();
484     location.replace('http://example.com/root');
485     Backbone.history = _.extend(new Backbone.History, {
486       location: location,
487       history: {
488         pushState: function(state, title, url) {
489           assert.strictEqual(url, '/root/fragment');
490         }
491       }
492     });
493     Backbone.history.start({
494       pushState: true,
495       root: '/root',
496       hashChange: false
497     });
498     Backbone.history.navigate('fragment');
499   });
500
501   QUnit.test('Normalize root.', function(assert) {
502     assert.expect(1);
503     Backbone.history.stop();
504     location.replace('http://example.com/root#fragment');
505     Backbone.history = _.extend(new Backbone.History, {
506       location: location,
507       history: {
508         pushState: function(state, title, url) {},
509         replaceState: function(state, title, url) {
510           assert.strictEqual(url, '/root/fragment');
511         }
512       }
513     });
514     Backbone.history.start({
515       pushState: true,
516       root: '/root'
517     });
518   });
519
520   QUnit.test('Normalize root.', function(assert) {
521     assert.expect(1);
522     Backbone.history.stop();
523     location.replace('http://example.com/root');
524     Backbone.history = _.extend(new Backbone.History, {location: location});
525     Backbone.history.loadUrl = function() { assert.ok(true); };
526     Backbone.history.start({
527       pushState: true,
528       root: '/root'
529     });
530   });
531
532   QUnit.test('Normalize root - leading slash.', function(assert) {
533     assert.expect(1);
534     Backbone.history.stop();
535     location.replace('http://example.com/root');
536     Backbone.history = _.extend(new Backbone.History, {
537       location: location,
538       history: {
539         pushState: function(){},
540         replaceState: function(){}
541       }
542     });
543     Backbone.history.start({root: 'root'});
544     assert.strictEqual(Backbone.history.root, '/root/');
545   });
546
547   QUnit.test('Transition from hashChange to pushState.', function(assert) {
548     assert.expect(1);
549     Backbone.history.stop();
550     location.replace('http://example.com/root#x/y');
551     Backbone.history = _.extend(new Backbone.History, {
552       location: location,
553       history: {
554         pushState: function(){},
555         replaceState: function(state, title, url){
556           assert.strictEqual(url, '/root/x/y');
557         }
558       }
559     });
560     Backbone.history.start({
561       root: 'root',
562       pushState: true
563     });
564   });
565
566   QUnit.test('#1619: Router: Normalize empty root', function(assert) {
567     assert.expect(1);
568     Backbone.history.stop();
569     location.replace('http://example.com/');
570     Backbone.history = _.extend(new Backbone.History, {
571       location: location,
572       history: {
573         pushState: function(){},
574         replaceState: function(){}
575       }
576     });
577     Backbone.history.start({root: ''});
578     assert.strictEqual(Backbone.history.root, '/');
579   });
580
581   QUnit.test('#1619: Router: nagivate with empty root', function(assert) {
582     assert.expect(1);
583     Backbone.history.stop();
584     location.replace('http://example.com/');
585     Backbone.history = _.extend(new Backbone.History, {
586       location: location,
587       history: {
588         pushState: function(state, title, url) {
589           assert.strictEqual(url, '/fragment');
590         }
591       }
592     });
593     Backbone.history.start({
594       pushState: true,
595       root: '',
596       hashChange: false
597     });
598     Backbone.history.navigate('fragment');
599   });
600
601   QUnit.test('Transition from pushState to hashChange.', function(assert) {
602     assert.expect(1);
603     Backbone.history.stop();
604     location.replace('http://example.com/root/x/y?a=b');
605     location.replace = function(url) {
606       assert.strictEqual(url, '/root#x/y?a=b');
607     };
608     Backbone.history = _.extend(new Backbone.History, {
609       location: location,
610       history: {
611         pushState: null,
612         replaceState: null
613       }
614     });
615     Backbone.history.start({
616       root: 'root',
617       pushState: true
618     });
619   });
620
621   QUnit.test('#1695 - hashChange to pushState with search.', function(assert) {
622     assert.expect(1);
623     Backbone.history.stop();
624     location.replace('http://example.com/root#x/y?a=b');
625     Backbone.history = _.extend(new Backbone.History, {
626       location: location,
627       history: {
628         pushState: function(){},
629         replaceState: function(state, title, url){
630           assert.strictEqual(url, '/root/x/y?a=b');
631         }
632       }
633     });
634     Backbone.history.start({
635       root: 'root',
636       pushState: true
637     });
638   });
639
640   QUnit.test('#1746 - Router allows empty route.', function(assert) {
641     assert.expect(1);
642     var MyRouter = Backbone.Router.extend({
643       routes: {'': 'empty'},
644       empty: function(){},
645       route: function(route){
646         assert.strictEqual(route, '');
647       }
648     });
649     new MyRouter;
650   });
651
652   QUnit.test('#1794 - Trailing space in fragments.', function(assert) {
653     assert.expect(1);
654     var history = new Backbone.History;
655     assert.strictEqual(history.getFragment('fragment   '), 'fragment');
656   });
657
658   QUnit.test('#1820 - Leading slash and trailing space.', 1, function(assert) {
659     var history = new Backbone.History;
660     assert.strictEqual(history.getFragment('/fragment '), 'fragment');
661   });
662
663   QUnit.test('#1980 - Optional parameters.', function(assert) {
664     assert.expect(2);
665     location.replace('http://example.com#named/optional/y');
666     Backbone.history.checkUrl();
667     assert.strictEqual(router.z, undefined);
668     location.replace('http://example.com#named/optional/y123');
669     Backbone.history.checkUrl();
670     assert.strictEqual(router.z, '123');
671   });
672
673   QUnit.test("#2062 - Trigger 'route' event on router instance.", function(assert) {
674     assert.expect(2);
675     router.on('route', function(name, args) {
676       assert.strictEqual(name, 'routeEvent');
677       assert.deepEqual(args, ['x', null]);
678     });
679     location.replace('http://example.com#route-event/x');
680     Backbone.history.checkUrl();
681   });
682
683   QUnit.test('#2255 - Extend routes by making routes a function.', function(assert) {
684     assert.expect(1);
685     var RouterBase = Backbone.Router.extend({
686       routes: function() {
687         return {
688           home: 'root',
689           index: 'index.html'
690         };
691       }
692     });
693
694     var RouterExtended = RouterBase.extend({
695       routes: function() {
696         var _super = RouterExtended.__super__.routes;
697         return _.extend(_super(), {show: 'show', search: 'search'});
698       }
699     });
700
701     var myRouter = new RouterExtended();
702     assert.deepEqual({home: 'root', index: 'index.html', show: 'show', search: 'search'}, myRouter.routes);
703   });
704
705   QUnit.test('#2538 - hashChange to pushState only if both requested.', function(assert) {
706     assert.expect(0);
707     Backbone.history.stop();
708     location.replace('http://example.com/root?a=b#x/y');
709     Backbone.history = _.extend(new Backbone.History, {
710       location: location,
711       history: {
712         pushState: function(){},
713         replaceState: function(){ assert.ok(false); }
714       }
715     });
716     Backbone.history.start({
717       root: 'root',
718       pushState: true,
719       hashChange: false
720     });
721   });
722
723   QUnit.test('No hash fallback.', function(assert) {
724     assert.expect(0);
725     Backbone.history.stop();
726     Backbone.history = _.extend(new Backbone.History, {
727       location: location,
728       history: {
729         pushState: function(){},
730         replaceState: function(){}
731       }
732     });
733
734     var MyRouter = Backbone.Router.extend({
735       routes: {
736         hash: function() { assert.ok(false); }
737       }
738     });
739     var myRouter = new MyRouter;
740
741     location.replace('http://example.com/');
742     Backbone.history.start({
743       pushState: true,
744       hashChange: false
745     });
746     location.replace('http://example.com/nomatch#hash');
747     Backbone.history.checkUrl();
748   });
749
750   QUnit.test('#2656 - No trailing slash on root.', function(assert) {
751     assert.expect(1);
752     Backbone.history.stop();
753     Backbone.history = _.extend(new Backbone.History, {
754       location: location,
755       history: {
756         pushState: function(state, title, url){
757           assert.strictEqual(url, '/root');
758         }
759       }
760     });
761     location.replace('http://example.com/root/path');
762     Backbone.history.start({pushState: true, hashChange: false, root: 'root'});
763     Backbone.history.navigate('');
764   });
765
766   QUnit.test('#2656 - No trailing slash on root.', function(assert) {
767     assert.expect(1);
768     Backbone.history.stop();
769     Backbone.history = _.extend(new Backbone.History, {
770       location: location,
771       history: {
772         pushState: function(state, title, url) {
773           assert.strictEqual(url, '/');
774         }
775       }
776     });
777     location.replace('http://example.com/path');
778     Backbone.history.start({pushState: true, hashChange: false});
779     Backbone.history.navigate('');
780   });
781
782   QUnit.test('#2656 - No trailing slash on root.', function(assert) {
783     assert.expect(1);
784     Backbone.history.stop();
785     Backbone.history = _.extend(new Backbone.History, {
786       location: location,
787       history: {
788         pushState: function(state, title, url){
789           assert.strictEqual(url, '/root?x=1');
790         }
791       }
792     });
793     location.replace('http://example.com/root/path');
794     Backbone.history.start({pushState: true, hashChange: false, root: 'root'});
795     Backbone.history.navigate('?x=1');
796   });
797
798   QUnit.test('#2765 - Fragment matching sans query/hash.', function(assert) {
799     assert.expect(2);
800     Backbone.history.stop();
801     Backbone.history = _.extend(new Backbone.History, {
802       location: location,
803       history: {
804         pushState: function(state, title, url) {
805           assert.strictEqual(url, '/path?query#hash');
806         }
807       }
808     });
809
810     var MyRouter = Backbone.Router.extend({
811       routes: {
812         path: function() { assert.ok(true); }
813       }
814     });
815     var myRouter = new MyRouter;
816
817     location.replace('http://example.com/');
818     Backbone.history.start({pushState: true, hashChange: false});
819     Backbone.history.navigate('path?query#hash', true);
820   });
821
822   QUnit.test('Do not decode the search params.', function(assert) {
823     assert.expect(1);
824     var MyRouter = Backbone.Router.extend({
825       routes: {
826         path: function(params){
827           assert.strictEqual(params, 'x=y%3Fz');
828         }
829       }
830     });
831     var myRouter = new MyRouter;
832     Backbone.history.navigate('path?x=y%3Fz', true);
833   });
834
835   QUnit.test('Navigate to a hash url.', function(assert) {
836     assert.expect(1);
837     Backbone.history.stop();
838     Backbone.history = _.extend(new Backbone.History, {location: location});
839     Backbone.history.start({pushState: true});
840     var MyRouter = Backbone.Router.extend({
841       routes: {
842         path: function(params) {
843           assert.strictEqual(params, 'x=y');
844         }
845       }
846     });
847     var myRouter = new MyRouter;
848     location.replace('http://example.com/path?x=y#hash');
849     Backbone.history.checkUrl();
850   });
851
852   QUnit.test('#navigate to a hash url.', function(assert) {
853     assert.expect(1);
854     Backbone.history.stop();
855     Backbone.history = _.extend(new Backbone.History, {location: location});
856     Backbone.history.start({pushState: true});
857     var MyRouter = Backbone.Router.extend({
858       routes: {
859         path: function(params) {
860           assert.strictEqual(params, 'x=y');
861         }
862       }
863     });
864     var myRouter = new MyRouter;
865     Backbone.history.navigate('path?x=y#hash', true);
866   });
867
868   QUnit.test('unicode pathname', function(assert) {
869     assert.expect(1);
870     location.replace('http://example.com/myyjä');
871     Backbone.history.stop();
872     Backbone.history = _.extend(new Backbone.History, {location: location});
873     var MyRouter = Backbone.Router.extend({
874       routes: {
875         myyjä: function() {
876           assert.ok(true);
877         }
878       }
879     });
880     new MyRouter;
881     Backbone.history.start({pushState: true});
882   });
883
884   QUnit.test('unicode pathname with % in a parameter', function(assert) {
885     assert.expect(1);
886     location.replace('http://example.com/myyjä/foo%20%25%3F%2f%40%25%20bar');
887     location.pathname = '/myyj%C3%A4/foo%20%25%3F%2f%40%25%20bar';
888     Backbone.history.stop();
889     Backbone.history = _.extend(new Backbone.History, {location: location});
890     var MyRouter = Backbone.Router.extend({
891       routes: {
892         'myyjä/:query': function(query) {
893           assert.strictEqual(query, 'foo %?/@% bar');
894         }
895       }
896     });
897     new MyRouter;
898     Backbone.history.start({pushState: true});
899   });
900
901   QUnit.test('newline in route', function(assert) {
902     assert.expect(1);
903     location.replace('http://example.com/stuff%0Anonsense?param=foo%0Abar');
904     Backbone.history.stop();
905     Backbone.history = _.extend(new Backbone.History, {location: location});
906     var MyRouter = Backbone.Router.extend({
907       routes: {
908         'stuff\nnonsense': function() {
909           assert.ok(true);
910         }
911       }
912     });
913     new MyRouter;
914     Backbone.history.start({pushState: true});
915   });
916
917   QUnit.test('Router#execute receives callback, args, name.', function(assert) {
918     assert.expect(3);
919     location.replace('http://example.com#foo/123/bar?x=y');
920     Backbone.history.stop();
921     Backbone.history = _.extend(new Backbone.History, {location: location});
922     var MyRouter = Backbone.Router.extend({
923       routes: {'foo/:id/bar': 'foo'},
924       foo: function(){},
925       execute: function(callback, args, name) {
926         assert.strictEqual(callback, this.foo);
927         assert.deepEqual(args, ['123', 'x=y']);
928         assert.strictEqual(name, 'foo');
929       }
930     });
931     var myRouter = new MyRouter;
932     Backbone.history.start();
933   });
934
935   QUnit.test('pushState to hashChange with only search params.', function(assert) {
936     assert.expect(1);
937     Backbone.history.stop();
938     location.replace('http://example.com?a=b');
939     location.replace = function(url) {
940       assert.strictEqual(url, '/#?a=b');
941     };
942     Backbone.history = _.extend(new Backbone.History, {
943       location: location,
944       history: null
945     });
946     Backbone.history.start({pushState: true});
947   });
948
949   QUnit.test('#3123 - History#navigate decodes before comparison.', function(assert) {
950     assert.expect(1);
951     Backbone.history.stop();
952     location.replace('http://example.com/shop/search?keyword=short%20dress');
953     Backbone.history = _.extend(new Backbone.History, {
954       location: location,
955       history: {
956         pushState: function(){ assert.ok(false); },
957         replaceState: function(){ assert.ok(false); }
958       }
959     });
960     Backbone.history.start({pushState: true});
961     Backbone.history.navigate('shop/search?keyword=short%20dress', true);
962     assert.strictEqual(Backbone.history.fragment, 'shop/search?keyword=short dress');
963   });
964
965   QUnit.test('#3175 - Urls in the params', function(assert) {
966     assert.expect(1);
967     Backbone.history.stop();
968     location.replace('http://example.com#login?a=value&backUrl=https%3A%2F%2Fwww.msn.com%2Fidp%2Fidpdemo%3Fspid%3Dspdemo%26target%3Db');
969     Backbone.history = _.extend(new Backbone.History, {location: location});
970     var myRouter = new Backbone.Router;
971     myRouter.route('login', function(params) {
972       assert.strictEqual(params, 'a=value&backUrl=https%3A%2F%2Fwww.msn.com%2Fidp%2Fidpdemo%3Fspid%3Dspdemo%26target%3Db');
973     });
974     Backbone.history.start();
975   });
976
977   QUnit.test('#3358 - pushState to hashChange transition with search params', function(assert) {
978     assert.expect(1);
979     Backbone.history.stop();
980     location.replace('http://example.com/root?foo=bar');
981     location.replace = function(url) {
982       assert.strictEqual(url, '/root#?foo=bar');
983     };
984     Backbone.history = _.extend(new Backbone.History, {
985       location: location,
986       history: {
987         pushState: undefined,
988         replaceState: undefined
989       }
990     });
991     Backbone.history.start({root: '/root', pushState: true});
992   });
993
994   QUnit.test("Paths that don't match the root should not match no root", function(assert) {
995     assert.expect(0);
996     location.replace('http://example.com/foo');
997     Backbone.history.stop();
998     Backbone.history = _.extend(new Backbone.History, {location: location});
999     var MyRouter = Backbone.Router.extend({
1000       routes: {
1001         foo: function(){
1002           assert.ok(false, 'should not match unless root matches');
1003         }
1004       }
1005     });
1006     var myRouter = new MyRouter;
1007     Backbone.history.start({root: 'root', pushState: true});
1008   });
1009
1010   QUnit.test("Paths that don't match the root should not match roots of the same length", function(assert) {
1011     assert.expect(0);
1012     location.replace('http://example.com/xxxx/foo');
1013     Backbone.history.stop();
1014     Backbone.history = _.extend(new Backbone.History, {location: location});
1015     var MyRouter = Backbone.Router.extend({
1016       routes: {
1017         foo: function(){
1018           assert.ok(false, 'should not match unless root matches');
1019         }
1020       }
1021     });
1022     var myRouter = new MyRouter;
1023     Backbone.history.start({root: 'root', pushState: true});
1024   });
1025
1026   QUnit.test('roots with regex characters', function(assert) {
1027     assert.expect(1);
1028     location.replace('http://example.com/x+y.z/foo');
1029     Backbone.history.stop();
1030     Backbone.history = _.extend(new Backbone.History, {location: location});
1031     var MyRouter = Backbone.Router.extend({
1032       routes: {foo: function(){ assert.ok(true); }}
1033     });
1034     var myRouter = new MyRouter;
1035     Backbone.history.start({root: 'x+y.z', pushState: true});
1036   });
1037
1038   QUnit.test('roots with unicode characters', function(assert) {
1039     assert.expect(1);
1040     location.replace('http://example.com/®ooτ/foo');
1041     Backbone.history.stop();
1042     Backbone.history = _.extend(new Backbone.History, {location: location});
1043     var MyRouter = Backbone.Router.extend({
1044       routes: {foo: function(){ assert.ok(true); }}
1045     });
1046     var myRouter = new MyRouter;
1047     Backbone.history.start({root: '®ooτ', pushState: true});
1048   });
1049
1050   QUnit.test('roots without slash', function(assert) {
1051     assert.expect(1);
1052     location.replace('http://example.com/®ooτ');
1053     Backbone.history.stop();
1054     Backbone.history = _.extend(new Backbone.History, {location: location});
1055     var MyRouter = Backbone.Router.extend({
1056       routes: {'': function(){ assert.ok(true); }}
1057     });
1058     var myRouter = new MyRouter;
1059     Backbone.history.start({root: '®ooτ', pushState: true});
1060   });
1061
1062 })();