@@ -11,8 +11,9 @@ function MockWindow(options) {
11
11
}
12
12
var events = { } ;
13
13
var timeouts = this . timeouts = [ ] ;
14
- var locationHref = 'http://server/' ;
15
- var committedHref = 'http://server/' ;
14
+ var locationHref = window . document . createElement ( 'a' ) ;
15
+ var committedHref = window . document . createElement ( 'a' ) ;
16
+ locationHref . href = committedHref . href = 'http://server/' ;
16
17
var mockWindow = this ;
17
18
var msie = options . msie ;
18
19
var ieState ;
@@ -60,28 +61,28 @@ function MockWindow(options) {
60
61
61
62
this . location = {
62
63
get href ( ) {
63
- return committedHref ;
64
+ return committedHref . href ;
64
65
} ,
65
66
set href ( value ) {
66
- locationHref = value ;
67
+ locationHref . href = value ;
67
68
mockWindow . history . state = null ;
68
69
historyEntriesLength ++ ;
69
70
if ( ! options . updateAsync ) this . flushHref ( ) ;
70
71
} ,
71
72
get hash ( ) {
72
- return getHash ( committedHref ) ;
73
+ return getHash ( committedHref . href ) ;
73
74
} ,
74
75
set hash ( value ) {
75
- locationHref = replaceHash ( locationHref , value ) ;
76
+ locationHref . href = replaceHash ( locationHref . href , value ) ;
76
77
if ( ! options . updateAsync ) this . flushHref ( ) ;
77
78
} ,
78
79
replace : function ( url ) {
79
- locationHref = url ;
80
+ locationHref . href = url ;
80
81
mockWindow . history . state = null ;
81
82
if ( ! options . updateAsync ) this . flushHref ( ) ;
82
83
} ,
83
84
flushHref : function ( ) {
84
- committedHref = locationHref ;
85
+ committedHref . href = locationHref . href ;
85
86
}
86
87
} ;
87
88
@@ -91,13 +92,13 @@ function MockWindow(options) {
91
92
historyEntriesLength ++ ;
92
93
} ,
93
94
replaceState : function ( state , title , url ) {
94
- locationHref = url ;
95
- if ( ! options . updateAsync ) committedHref = locationHref ;
95
+ locationHref . href = url ;
96
+ if ( ! options . updateAsync ) committedHref . href = locationHref . href ;
96
97
mockWindow . history . state = copy ( state ) ;
97
98
if ( ! options . updateAsync ) this . flushHref ( ) ;
98
99
} ,
99
100
flushHref : function ( ) {
100
- committedHref = locationHref ;
101
+ committedHref . href = locationHref . href ;
101
102
}
102
103
} ;
103
104
// IE 10-11 deserialize history.state on each read making subsequent reads
@@ -398,26 +399,26 @@ describe('browser', function() {
398
399
399
400
it ( 'should return current location.href' , function ( ) {
400
401
fakeWindow . location . href = 'http://test.com' ;
401
- expect ( browser . url ( ) ) . toEqual ( 'http://test.com' ) ;
402
+ expect ( browser . url ( ) ) . toEqual ( 'http://test.com/ ' ) ;
402
403
403
404
fakeWindow . location . href = 'https://another.com' ;
404
- expect ( browser . url ( ) ) . toEqual ( 'https://another.com' ) ;
405
+ expect ( browser . url ( ) ) . toEqual ( 'https://another.com/ ' ) ;
405
406
} ) ;
406
407
407
408
it ( 'should strip an empty hash fragment' , function ( ) {
408
- fakeWindow . location . href = 'http://test.com#' ;
409
- expect ( browser . url ( ) ) . toEqual ( 'http://test.com' ) ;
409
+ fakeWindow . location . href = 'http://test.com/ #' ;
410
+ expect ( browser . url ( ) ) . toEqual ( 'http://test.com/ ' ) ;
410
411
411
- fakeWindow . location . href = 'https://another.com#foo' ;
412
- expect ( browser . url ( ) ) . toEqual ( 'https://another.com#foo' ) ;
412
+ fakeWindow . location . href = 'https://another.com/ #foo' ;
413
+ expect ( browser . url ( ) ) . toEqual ( 'https://another.com/ #foo' ) ;
413
414
} ) ;
414
415
415
416
it ( 'should use history.pushState when available' , function ( ) {
416
417
sniffer . history = true ;
417
418
browser . url ( 'http://new.org' ) ;
418
419
419
420
expect ( pushState ) . toHaveBeenCalledOnce ( ) ;
420
- expect ( pushState . calls . argsFor ( 0 ) [ 2 ] ) . toEqual ( 'http://new.org' ) ;
421
+ expect ( pushState . calls . argsFor ( 0 ) [ 2 ] ) . toEqual ( 'http://new.org/ ' ) ;
421
422
422
423
expect ( replaceState ) . not . toHaveBeenCalled ( ) ;
423
424
expect ( locationReplace ) . not . toHaveBeenCalled ( ) ;
@@ -429,7 +430,7 @@ describe('browser', function() {
429
430
browser . url ( 'http://new.org' , true ) ;
430
431
431
432
expect ( replaceState ) . toHaveBeenCalledOnce ( ) ;
432
- expect ( replaceState . calls . argsFor ( 0 ) [ 2 ] ) . toEqual ( 'http://new.org' ) ;
433
+ expect ( replaceState . calls . argsFor ( 0 ) [ 2 ] ) . toEqual ( 'http://new.org/ ' ) ;
433
434
434
435
expect ( pushState ) . not . toHaveBeenCalled ( ) ;
435
436
expect ( locationReplace ) . not . toHaveBeenCalled ( ) ;
@@ -440,7 +441,7 @@ describe('browser', function() {
440
441
sniffer . history = false ;
441
442
browser . url ( 'http://new.org' ) ;
442
443
443
- expect ( fakeWindow . location . href ) . toEqual ( 'http://new.org' ) ;
444
+ expect ( fakeWindow . location . href ) . toEqual ( 'http://new.org/ ' ) ;
444
445
445
446
expect ( pushState ) . not . toHaveBeenCalled ( ) ;
446
447
expect ( replaceState ) . not . toHaveBeenCalled ( ) ;
@@ -473,7 +474,7 @@ describe('browser', function() {
473
474
sniffer . history = false ;
474
475
browser . url ( 'http://new.org' , true ) ;
475
476
476
- expect ( locationReplace ) . toHaveBeenCalledWith ( 'http://new.org' ) ;
477
+ expect ( locationReplace ) . toHaveBeenCalledWith ( 'http://new.org/ ' ) ;
477
478
478
479
expect ( pushState ) . not . toHaveBeenCalled ( ) ;
479
480
expect ( replaceState ) . not . toHaveBeenCalled ( ) ;
@@ -507,9 +508,9 @@ describe('browser', function() {
507
508
it ( 'should not set URL when the URL is already set' , function ( ) {
508
509
var current = fakeWindow . location . href ;
509
510
sniffer . history = false ;
510
- fakeWindow . location . href = 'dontchange' ;
511
+ fakeWindow . location . href = 'http:// dontchange/ ' ;
511
512
browser . url ( current ) ;
512
- expect ( fakeWindow . location . href ) . toBe ( 'dontchange' ) ;
513
+ expect ( fakeWindow . location . href ) . toBe ( 'http:// dontchange/ ' ) ;
513
514
} ) ;
514
515
515
516
it ( 'should not read out location.href if a reload was triggered but still allow to change the url' , function ( ) {
@@ -688,6 +689,73 @@ describe('browser', function() {
688
689
expect ( replaceState ) . not . toHaveBeenCalled ( ) ;
689
690
expect ( locationReplace ) . not . toHaveBeenCalled ( ) ;
690
691
} ) ;
692
+
693
+ it ( 'should not do pushState with a URL using relative protocol' , function ( ) {
694
+ browser . url ( 'http://server/' ) ;
695
+
696
+ pushState . calls . reset ( ) ;
697
+ replaceState . calls . reset ( ) ;
698
+ locationReplace . calls . reset ( ) ;
699
+
700
+ browser . url ( '//server' ) ;
701
+ expect ( pushState ) . not . toHaveBeenCalled ( ) ;
702
+ expect ( replaceState ) . not . toHaveBeenCalled ( ) ;
703
+ expect ( locationReplace ) . not . toHaveBeenCalled ( ) ;
704
+ } ) ;
705
+
706
+ it ( 'should not do pushState with a URL only adding a trailing slash after domain' , function ( ) {
707
+ // A domain without a trailing /
708
+ browser . url ( 'http://server' ) ;
709
+
710
+ pushState . calls . reset ( ) ;
711
+ replaceState . calls . reset ( ) ;
712
+ locationReplace . calls . reset ( ) ;
713
+
714
+ // A domain from something such as window.location.href with a trailing slash
715
+ browser . url ( 'http://server/' ) ;
716
+ expect ( pushState ) . not . toHaveBeenCalled ( ) ;
717
+ expect ( replaceState ) . not . toHaveBeenCalled ( ) ;
718
+ expect ( locationReplace ) . not . toHaveBeenCalled ( ) ;
719
+ } ) ;
720
+
721
+ it ( 'should not do pushState with a URL only removing a trailing slash after domain' , function ( ) {
722
+ // A domain from something such as window.location.href with a trailing slash
723
+ browser . url ( 'http://server/' ) ;
724
+
725
+ pushState . calls . reset ( ) ;
726
+ replaceState . calls . reset ( ) ;
727
+ locationReplace . calls . reset ( ) ;
728
+
729
+ // A domain without a trailing /
730
+ browser . url ( 'http://server' ) ;
731
+ expect ( pushState ) . not . toHaveBeenCalled ( ) ;
732
+ expect ( replaceState ) . not . toHaveBeenCalled ( ) ;
733
+ expect ( locationReplace ) . not . toHaveBeenCalled ( ) ;
734
+ } ) ;
735
+
736
+ it ( 'should do pushState with a URL only adding a trailing slash after the path' , function ( ) {
737
+ browser . url ( 'http://server/foo' ) ;
738
+
739
+ pushState . calls . reset ( ) ;
740
+ replaceState . calls . reset ( ) ;
741
+ locationReplace . calls . reset ( ) ;
742
+
743
+ browser . url ( 'http://server/foo/' ) ;
744
+ expect ( pushState ) . toHaveBeenCalledOnce ( ) ;
745
+ expect ( fakeWindow . location . href ) . toEqual ( 'http://server/foo/' ) ;
746
+ } ) ;
747
+
748
+ it ( 'should do pushState with a URL only removing a trailing slash after the path' , function ( ) {
749
+ browser . url ( 'http://server/foo/' ) ;
750
+
751
+ pushState . calls . reset ( ) ;
752
+ replaceState . calls . reset ( ) ;
753
+ locationReplace . calls . reset ( ) ;
754
+
755
+ browser . url ( 'http://server/foo' ) ;
756
+ expect ( pushState ) . toHaveBeenCalledOnce ( ) ;
757
+ expect ( fakeWindow . location . href ) . toEqual ( 'http://server/foo' ) ;
758
+ } ) ;
691
759
} ;
692
760
}
693
761
} ) ;
@@ -812,7 +880,7 @@ describe('browser', function() {
812
880
it ( 'should not fire urlChange if changed by browser.url method' , function ( ) {
813
881
sniffer . history = false ;
814
882
browser . onUrlChange ( callback ) ;
815
- browser . url ( 'http://new.com' ) ;
883
+ browser . url ( 'http://new.com/ ' ) ;
816
884
817
885
fakeWindow . fire ( 'hashchange' ) ;
818
886
expect ( callback ) . not . toHaveBeenCalled ( ) ;
@@ -1092,7 +1160,7 @@ describe('browser', function() {
1092
1160
it ( 'should not interfere with legacy browser url replace behavior' , function ( ) {
1093
1161
inject ( function ( $rootScope ) {
1094
1162
var current = fakeWindow . location . href ;
1095
- var newUrl = 'notyet' ;
1163
+ var newUrl = 'http:// notyet/ ' ;
1096
1164
sniffer . history = false ;
1097
1165
expect ( historyEntriesLength ) . toBe ( 1 ) ;
1098
1166
browser . url ( newUrl , true ) ;
0 commit comments