@ionic/core 7.5.6-dev.11700169088.140f3e6a → 7.5.6-dev.11700519388.1583475f

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/components/icon.js +15 -16
  2. package/components/index7.js +1 -1
  3. package/dist/cjs/{index-09471526.js → index-6b8be5a4.js} +1 -1
  4. package/dist/cjs/ion-accordion_2.cjs.entry.js +1 -1
  5. package/dist/cjs/ion-back-button.cjs.entry.js +1 -1
  6. package/dist/cjs/ion-breadcrumb_2.cjs.entry.js +1 -1
  7. package/dist/cjs/ion-button_2.cjs.entry.js +15 -16
  8. package/dist/cjs/ion-datetime_3.cjs.entry.js +1 -1
  9. package/dist/cjs/ion-fab_3.cjs.entry.js +1 -1
  10. package/dist/cjs/ion-input.cjs.entry.js +1 -1
  11. package/dist/cjs/ion-item_8.cjs.entry.js +1 -1
  12. package/dist/cjs/ion-menu_3.cjs.entry.js +1 -1
  13. package/dist/cjs/ion-refresher_2.cjs.entry.js +1 -1
  14. package/dist/cjs/ion-reorder_2.cjs.entry.js +1 -1
  15. package/dist/cjs/ion-searchbar.cjs.entry.js +1 -1
  16. package/dist/cjs/ion-select_3.cjs.entry.js +1 -1
  17. package/dist/cjs/ion-toggle.cjs.entry.js +1 -1
  18. package/dist/collection/collection-manifest.json +4 -4
  19. package/dist/collection/components/accordion/test/accordion.spec.js +195 -0
  20. package/dist/collection/components/action-sheet/test/action-sheet-id.spec.js +32 -0
  21. package/dist/collection/components/action-sheet/test/basic/action-sheet.spec.js +18 -0
  22. package/dist/collection/components/alert/test/alert-id.spec.js +32 -0
  23. package/dist/collection/components/alert/test/alert.spec.js +37 -0
  24. package/dist/collection/components/back-button/test/back-button.spec.js +86 -0
  25. package/dist/collection/components/breadcrumb/test/aria.spec.js +22 -0
  26. package/dist/collection/components/breadcrumbs/test/breadcrumbs.spec.js +58 -0
  27. package/dist/collection/components/button/test/form-reference/button.spec.js +26 -0
  28. package/dist/collection/components/card/test/aria.spec.js +16 -0
  29. package/dist/collection/components/checkbox/test/checkbox.spec.js +20 -0
  30. package/dist/collection/components/datetime/test/a11y/datetime.spec.js +43 -0
  31. package/dist/collection/components/datetime/test/comparison.spec.js +43 -0
  32. package/dist/collection/components/datetime/test/data.spec.js +456 -0
  33. package/dist/collection/components/datetime/test/format.spec.js +124 -0
  34. package/dist/collection/components/datetime/test/helpers.spec.js +72 -0
  35. package/dist/collection/components/datetime/test/manipulation.spec.js +433 -0
  36. package/dist/collection/components/datetime/test/parse.spec.js +222 -0
  37. package/dist/collection/components/datetime/test/state.spec.js +114 -0
  38. package/dist/collection/components/infinite-scroll-content/test/infinite-scroll-content.spec.js +37 -0
  39. package/dist/collection/components/input/test/input.spec.js +85 -0
  40. package/dist/collection/components/input/test/item/input.spec.js +24 -0
  41. package/dist/collection/components/item/test/a11y/item.spec.js +48 -0
  42. package/dist/collection/components/loading/test/basic/loading.spec.js +16 -0
  43. package/dist/collection/components/loading/test/loading-id.spec.js +32 -0
  44. package/dist/collection/components/loading/test/loading.spec.js +37 -0
  45. package/dist/collection/components/modal/test/a11y/modal.spec.js +22 -0
  46. package/dist/collection/components/modal/test/basic/modal.spec.js +16 -0
  47. package/dist/collection/components/modal/test/can-dismiss/modal.spec.js +191 -0
  48. package/dist/collection/components/modal/test/modal-id.spec.js +32 -0
  49. package/dist/collection/components/nav/test/nav-controller.spec.js +749 -0
  50. package/dist/collection/components/picker/test/picker-id.spec.js +32 -0
  51. package/dist/collection/components/picker-column/test/picker-column-aria.spec.js +35 -0
  52. package/dist/collection/components/picker-column/test/picker-column-dynamic.spec.js +29 -0
  53. package/dist/collection/components/picker-column/test/picker-column.spec.js +17 -0
  54. package/dist/collection/components/popover/test/basic/popover.spec.js +16 -0
  55. package/dist/collection/components/popover/test/popover-id.spec.js +32 -0
  56. package/dist/collection/components/popover/test/util.spec.js +53 -0
  57. package/dist/collection/components/radio/test/radio.spec.js +46 -0
  58. package/dist/collection/components/range/test/label/range.spec.js +23 -0
  59. package/dist/collection/components/range/test/range.spec.js +205 -0
  60. package/dist/collection/components/refresher-content/test/refresher-content.spec.js +46 -0
  61. package/dist/collection/components/router/test/matching.spec.js +250 -0
  62. package/dist/collection/components/router/test/parser.spec.js +133 -0
  63. package/dist/collection/components/router/test/path.spec.js +218 -0
  64. package/dist/collection/components/router/test/router.spec.js +55 -0
  65. package/dist/collection/components/searchbar/test/searchbar.spec.js +15 -0
  66. package/dist/collection/components/segment/test/segment.spec.js +37 -0
  67. package/dist/collection/components/select/test/select.spec.js +59 -0
  68. package/dist/collection/components/textarea/test/textarea.spec.js +59 -0
  69. package/dist/collection/components/toast/test/toast-id.spec.js +32 -0
  70. package/dist/collection/components/toast/test/toast.spec.js +120 -0
  71. package/dist/collection/components/toggle/test/toggle.spec.js +55 -0
  72. package/dist/collection/global/test/config-controller.spec.js +77 -0
  73. package/dist/collection/utils/animation/test/animation.spec.js +431 -0
  74. package/dist/collection/utils/keyboard/test/keyboard-controller.spec.js +21 -0
  75. package/dist/collection/utils/keyboard/test/keyboard.spec.js +214 -0
  76. package/dist/collection/utils/sanitization/test/sanitization.spec.js +43 -0
  77. package/dist/collection/utils/test/aria.spec.js +79 -0
  78. package/dist/collection/utils/test/attributes.spec.js +53 -0
  79. package/dist/collection/utils/test/hardware-back-button.spec.js +53 -0
  80. package/dist/collection/utils/test/overlays/overlays.spec.js +102 -0
  81. package/dist/collection/utils/test/platform.spec.js +132 -0
  82. package/dist/collection/utils/test/ready.spec.js +39 -0
  83. package/dist/collection/utils/test/theme.spec.js +56 -0
  84. package/dist/docs.json +21 -21
  85. package/dist/esm/{index-c132c5f1.js → index-5d8e6a4f.js} +1 -1
  86. package/dist/esm/ion-accordion_2.entry.js +1 -1
  87. package/dist/esm/ion-back-button.entry.js +1 -1
  88. package/dist/esm/ion-breadcrumb_2.entry.js +1 -1
  89. package/dist/esm/ion-button_2.entry.js +15 -16
  90. package/dist/esm/ion-datetime_3.entry.js +1 -1
  91. package/dist/esm/ion-fab_3.entry.js +1 -1
  92. package/dist/esm/ion-input.entry.js +1 -1
  93. package/dist/esm/ion-item_8.entry.js +1 -1
  94. package/dist/esm/ion-menu_3.entry.js +1 -1
  95. package/dist/esm/ion-refresher_2.entry.js +1 -1
  96. package/dist/esm/ion-reorder_2.entry.js +1 -1
  97. package/dist/esm/ion-searchbar.entry.js +1 -1
  98. package/dist/esm/ion-select_3.entry.js +1 -1
  99. package/dist/esm/ion-toggle.entry.js +1 -1
  100. package/dist/esm-es5/ion-accordion_2.entry.js +1 -1
  101. package/dist/esm-es5/ion-back-button.entry.js +1 -1
  102. package/dist/esm-es5/ion-breadcrumb_2.entry.js +1 -1
  103. package/dist/esm-es5/ion-button_2.entry.js +1 -1
  104. package/dist/esm-es5/ion-datetime_3.entry.js +1 -1
  105. package/dist/esm-es5/ion-fab_3.entry.js +1 -1
  106. package/dist/esm-es5/ion-input.entry.js +1 -1
  107. package/dist/esm-es5/ion-item_8.entry.js +1 -1
  108. package/dist/esm-es5/ion-menu_3.entry.js +1 -1
  109. package/dist/esm-es5/ion-refresher_2.entry.js +1 -1
  110. package/dist/esm-es5/ion-reorder_2.entry.js +1 -1
  111. package/dist/esm-es5/ion-searchbar.entry.js +1 -1
  112. package/dist/esm-es5/ion-select_3.entry.js +1 -1
  113. package/dist/esm-es5/ion-toggle.entry.js +1 -1
  114. package/dist/ionic/ionic.esm.js +1 -1
  115. package/dist/ionic/p-1070ed59.entry.js +4 -0
  116. package/dist/ionic/p-178fa84b.system.entry.js +4 -0
  117. package/dist/ionic/{p-bed722c4.system.entry.js → p-1f011033.system.entry.js} +1 -1
  118. package/dist/ionic/{p-b203659a.system.entry.js → p-1f21e106.system.entry.js} +1 -1
  119. package/dist/ionic/{p-1e86a71b.entry.js → p-3101643f.entry.js} +1 -1
  120. package/dist/ionic/{p-39044fe6.system.entry.js → p-324226bf.system.entry.js} +1 -1
  121. package/dist/ionic/{p-d91e93ac.system.entry.js → p-3cd4001e.system.entry.js} +1 -1
  122. package/dist/ionic/{p-d3952bd5.system.entry.js → p-3f4fdd67.system.entry.js} +1 -1
  123. package/dist/ionic/p-40903d34.system.js +1 -1
  124. package/dist/ionic/{p-a21b8d05.entry.js → p-413e5a56.entry.js} +1 -1
  125. package/dist/ionic/{p-73411c1b.entry.js → p-459dd2a9.entry.js} +1 -1
  126. package/dist/ionic/{p-a5c1e6ce.entry.js → p-52138a68.entry.js} +1 -1
  127. package/dist/ionic/{p-d21bfe66.system.entry.js → p-54aba2a6.system.entry.js} +1 -1
  128. package/dist/ionic/{p-34d2de14.system.entry.js → p-5b885cc5.system.entry.js} +1 -1
  129. package/dist/ionic/{p-abacb44b.system.entry.js → p-68d27845.system.entry.js} +1 -1
  130. package/dist/ionic/{p-b2a74a72.entry.js → p-73ab9076.entry.js} +1 -1
  131. package/dist/ionic/{p-ad61e508.entry.js → p-7821df39.entry.js} +1 -1
  132. package/dist/ionic/{p-a8e68fd9.entry.js → p-85f8bc31.entry.js} +1 -1
  133. package/dist/ionic/{p-14aca3fb.entry.js → p-8dc8c0b7.entry.js} +1 -1
  134. package/dist/ionic/{p-5da0eb3e.system.entry.js → p-9437dac6.system.entry.js} +1 -1
  135. package/dist/ionic/{p-f5a750e4.system.entry.js → p-a94bed6d.system.entry.js} +1 -1
  136. package/dist/ionic/{p-48d9faa7.entry.js → p-ace47557.entry.js} +1 -1
  137. package/dist/ionic/{p-b6f8ee31.entry.js → p-af83378e.entry.js} +1 -1
  138. package/dist/ionic/{p-3ce8c3e3.entry.js → p-bb20a3fb.entry.js} +1 -1
  139. package/dist/ionic/{p-07d9e9cd.system.entry.js → p-cb9c77e7.system.entry.js} +1 -1
  140. package/dist/ionic/{p-377c636c.system.entry.js → p-d4bd82e9.system.entry.js} +1 -1
  141. package/dist/ionic/{p-0dc0d9b5.entry.js → p-d50f9c4b.entry.js} +1 -1
  142. package/dist/ionic/{p-f4cc91f6.entry.js → p-dc527a33.entry.js} +1 -1
  143. package/dist/ionic/{p-664d2b07.system.entry.js → p-edeb2f05.system.entry.js} +1 -1
  144. package/hydrate/index.js +1 -13
  145. package/package.json +3 -2
  146. package/dist/ionic/p-1dc91702.entry.js +0 -4
  147. package/dist/ionic/p-3fb57e1b.system.entry.js +0 -4
  148. /package/dist/esm-es5/{index-c132c5f1.js → index-5d8e6a4f.js} +0 -0
  149. /package/dist/ionic/{p-ea96fa73.js → p-6856db55.js} +0 -0
  150. /package/dist/ionic/{p-8050b9b9.system.js → p-a2e89e43.system.js} +0 -0
@@ -0,0 +1,250 @@
1
+ /*!
2
+ * (C) Ionic http://ionicframework.com - MIT License
3
+ */
4
+ import { RouterSegments, matchesIDs, matchesSegments, matchesRedirect, mergeParams, findChainForSegments, } from "../utils/matching";
5
+ import { parsePath } from "../utils/path";
6
+ const CHAIN_1 = [
7
+ { id: '2', segments: ['to'], params: undefined },
8
+ { id: '1', segments: ['path'], params: undefined },
9
+ { id: '3', segments: ['segment'], params: undefined },
10
+ { id: '4', segments: [''], params: undefined },
11
+ ];
12
+ const CHAIN_2 = [
13
+ { id: '2', segments: [''], params: undefined },
14
+ { id: '1', segments: [''], params: undefined },
15
+ { id: '3', segments: ['segment', 'to'], params: undefined },
16
+ { id: '4', segments: [''], params: undefined },
17
+ { id: '5', segments: ['hola'], params: undefined },
18
+ { id: '6', segments: [''], params: undefined },
19
+ { id: '7', segments: [''], params: undefined },
20
+ { id: '8', segments: ['adios', 'que', 'tal'], params: undefined },
21
+ ];
22
+ const CHAIN_3 = [
23
+ { id: '2', segments: ['this', 'to'], params: undefined },
24
+ { id: '1', segments: ['path'], params: undefined },
25
+ { id: '3', segments: ['segment', 'to', 'element'], params: undefined },
26
+ { id: '4', segments: [''], params: undefined },
27
+ ];
28
+ describe('matchesIDs', () => {
29
+ it('should match simple set of ids', () => {
30
+ const chain = CHAIN_1;
31
+ expect(matchesIDs([{ id: '2' }], chain)).toBe(1);
32
+ expect(matchesIDs([{ id: '2' }, { id: '1' }], chain)).toBe(2);
33
+ expect(matchesIDs([{ id: '2' }, { id: '1' }, { id: '3' }], chain)).toBe(3);
34
+ expect(matchesIDs([{ id: '2' }, { id: '1' }, { id: '3' }, { id: '4' }], chain)).toBe(4);
35
+ expect(matchesIDs([{ id: '2' }, { id: '1' }, { id: '3' }, { id: '4' }, { id: '5' }], chain)).toBe(4);
36
+ expect(matchesIDs([], chain)).toBe(0);
37
+ expect(matchesIDs([{ id: '1' }], chain)).toBe(0);
38
+ });
39
+ it('should match path with params', () => {
40
+ const ids = [{ id: 'my-page', params: { s1: 'a', s2: 'b' } }];
41
+ expect(matchesIDs(ids, [{ id: 'my-page', segments: [''], params: {} }])).toBe(1);
42
+ expect(matchesIDs(ids, [{ id: 'my-page', segments: [':s1'], params: {} }])).toBe(1);
43
+ expect(matchesIDs(ids, [{ id: 'my-page', segments: [':s1', ':s2'], params: {} }])).toBe(3);
44
+ expect(matchesIDs(ids, [{ id: 'my-page', segments: [':s1', ':s2', ':s3'], params: {} }])).toBe(1);
45
+ });
46
+ });
47
+ describe('matchesSegments', () => {
48
+ it('should match simple path', () => {
49
+ const chain = CHAIN_3;
50
+ expect(matchesSegments(['this'], chain)).toEqual(null);
51
+ expect(matchesSegments(['this', 'to'], chain)).toEqual(null);
52
+ expect(matchesSegments(['this', 'to', 'path'], chain)).toEqual(null);
53
+ expect(matchesSegments(['this', 'to', 'path', 'segment'], chain)).toEqual(null);
54
+ expect(matchesSegments(['this', 'to', 'path', 'segment', 'to'], chain)).toEqual(null);
55
+ expect(matchesSegments(['this', 'to', 'path', 'segment', 'to', 'element'], chain)).toEqual(chain);
56
+ expect(matchesSegments(['this', 'to', 'path', 'segment', 'to', 'element', 'more'], chain)).toEqual(null);
57
+ expect(matchesSegments([], chain)).toEqual(null);
58
+ expect(matchesSegments([''], chain)).toEqual(null);
59
+ expect(matchesSegments(['path'], chain)).toEqual(null);
60
+ });
61
+ it('should match simple default route', () => {
62
+ const chain = CHAIN_2;
63
+ expect(matchesSegments([''], chain)).toEqual(null);
64
+ expect(matchesSegments(['segment'], chain)).toEqual(null);
65
+ expect(matchesSegments(['segment', 'to'], chain)).toEqual(null);
66
+ expect(matchesSegments(['segment', 'to', 'hola'], chain)).toEqual(null);
67
+ expect(matchesSegments(['segment', 'to', 'hola', 'adios'], chain)).toEqual(null);
68
+ expect(matchesSegments(['segment', 'to', 'hola', 'adios', 'que'], chain)).toEqual(null);
69
+ expect(matchesSegments(['segment', 'to', 'hola', 'adios', 'que', 'tal'], chain)).toEqual(chain);
70
+ expect(matchesSegments(['segment', 'to', 'hola', 'adios', 'que', 'tal', 'more'], chain)).toEqual(chain);
71
+ expect(matchesSegments(['to'], chain)).toEqual(null);
72
+ expect(matchesSegments(['path', 'to'], chain)).toEqual(null);
73
+ });
74
+ it('should match simple route 2', () => {
75
+ const chain = [{ id: '5', segments: ['hola'], params: undefined }];
76
+ expect(matchesSegments([''], chain)).toEqual(null);
77
+ expect(matchesSegments(['hola'], chain)).toEqual(chain);
78
+ expect(matchesSegments(['hola', 'hola'], chain)).toEqual(chain);
79
+ expect(matchesSegments(['hola', 'adios'], chain)).toEqual(chain);
80
+ });
81
+ it('should match simple route 3', () => {
82
+ const chain = [{ id: '5', segments: ['hola', 'adios'], params: undefined }];
83
+ expect(matchesSegments([''], chain)).toEqual(null);
84
+ expect(matchesSegments(['hola'], chain)).toEqual(null);
85
+ expect(matchesSegments(['hola', 'hola'], chain)).toEqual(null);
86
+ expect(matchesSegments(['hola', 'adios'], chain)).toEqual(chain);
87
+ expect(matchesSegments(['hola', 'adios', 'bye'], chain)).toEqual(chain);
88
+ });
89
+ it('should match simple route 4', () => {
90
+ const chain = [
91
+ { id: '5', segments: ['hola'], params: undefined },
92
+ { id: '5', segments: ['adios'], params: undefined },
93
+ ];
94
+ expect(matchesSegments([''], chain)).toEqual(null);
95
+ expect(matchesSegments(['hola'], chain)).toEqual(null);
96
+ expect(matchesSegments(['hola', 'hola'], chain)).toEqual(null);
97
+ expect(matchesSegments(['hola', 'adios'], chain)).toEqual(chain);
98
+ });
99
+ it('should match with parameters', () => {
100
+ const chain = [
101
+ { id: '5', segments: ['profile', ':name'], params: undefined },
102
+ { id: '5', segments: [''], params: undefined },
103
+ { id: '5', segments: ['image'], params: { size: 'lg' } },
104
+ { id: '5', segments: ['image', ':size', ':type'], params: { size: 'mg' } },
105
+ ];
106
+ const matched = matchesSegments(parsePath('/profile/manu/image/image/large/retina').segments, chain);
107
+ expect(matched).toEqual([
108
+ { id: '5', segments: ['profile', ':name'], params: { name: 'manu' } },
109
+ { id: '5', segments: [''], params: undefined },
110
+ { id: '5', segments: ['image'], params: { size: 'lg' } },
111
+ { id: '5', segments: ['image', ':size', ':type'], params: { size: 'large', type: 'retina' } },
112
+ ]);
113
+ });
114
+ });
115
+ describe('findChainForSegments', () => {
116
+ it('should match the route with higher priority', () => {
117
+ const chain3 = [{ id: '5', segments: ['hola'], params: undefined }];
118
+ const chain4 = [
119
+ { id: '5', segments: ['hola'], params: undefined },
120
+ { id: '5', segments: ['adios'], params: undefined },
121
+ ];
122
+ const routes = [CHAIN_1, CHAIN_2, chain3, chain4];
123
+ expect(findChainForSegments(['to'], routes)).toEqual(null);
124
+ expect(findChainForSegments([''], routes)).toEqual(null);
125
+ expect(findChainForSegments(['segment', 'to'], routes)).toEqual(null);
126
+ expect(findChainForSegments(['hola'], routes)).toEqual(chain3);
127
+ expect(findChainForSegments(['hola', 'hola'], routes)).toEqual(chain3);
128
+ expect(findChainForSegments(['hola', 'adios'], routes)).toEqual(chain4);
129
+ });
130
+ it('should match the route with higher priority 2', () => {
131
+ const chain1 = [{ id: '1', segments: ['categories', ':category_slug'], params: undefined }];
132
+ const chain2 = [{ id: '2', segments: ['workouts', ':workout_slug'], params: undefined }];
133
+ const chain3 = [{ id: '3', segments: ['workouts', ':workout_slug', 'time-select'], params: undefined }];
134
+ const chain4 = [{ id: '4', segments: ['workouts', ':workout_slug', 'end-workout'], params: undefined }];
135
+ const chain5 = [{ id: '5', segments: ['plans'], params: undefined }];
136
+ const chain6 = [{ id: '6', segments: ['custom'], params: undefined }];
137
+ const chain7 = [{ id: '7', segments: ['workouts', 'list'], params: undefined }];
138
+ const routes = [chain1, chain2, chain3, chain4, chain5, chain6, chain7];
139
+ // no match
140
+ expect(findChainForSegments(['categories'], routes)).toEqual(null);
141
+ expect(findChainForSegments(['workouts'], routes)).toEqual(null);
142
+ expect(findChainForSegments(['plans'], routes)).toEqual(chain5);
143
+ expect(findChainForSegments(['custom'], routes)).toEqual(chain6);
144
+ expect(findChainForSegments(['workouts', 'list'], routes)).toEqual(chain7);
145
+ expect(findChainForSegments(['workouts', 'hola'], routes)).toEqual([
146
+ { id: '2', segments: ['workouts', ':workout_slug'], params: { workout_slug: 'hola' } },
147
+ ]);
148
+ expect(findChainForSegments(['workouts', 'hello', 'time-select'], routes)).toEqual([
149
+ { id: '3', segments: ['workouts', ':workout_slug', 'time-select'], params: { workout_slug: 'hello' } },
150
+ ]);
151
+ expect(findChainForSegments(['workouts', 'hello2', 'end-workout'], routes)).toEqual([
152
+ { id: '4', segments: ['workouts', ':workout_slug', 'end-workout'], params: { workout_slug: 'hello2' } },
153
+ ]);
154
+ });
155
+ it('should match the default route', () => {
156
+ const chain1 = [
157
+ { id: 'tabs', segments: [''], params: undefined },
158
+ { id: 'tab1', segments: [''], params: undefined },
159
+ { id: 'schedule', segments: [''], params: undefined },
160
+ ];
161
+ const chain2 = [
162
+ { id: 'tabs', segments: [''], params: undefined },
163
+ { id: 'tab2', segments: ['tab2'], params: undefined },
164
+ { id: 'page2', segments: [''], params: undefined },
165
+ ];
166
+ expect(findChainForSegments([''], [chain1])).toEqual(chain1);
167
+ expect(findChainForSegments(['tab2'], [chain1])).toEqual(null);
168
+ expect(findChainForSegments([''], [chain2])).toEqual(null);
169
+ expect(findChainForSegments(['tab2'], [chain2])).toEqual(chain2);
170
+ });
171
+ });
172
+ describe('mergeParams', () => {
173
+ it('should merge undefined', () => {
174
+ expect(mergeParams(undefined, undefined)).toBeUndefined();
175
+ expect(mergeParams(null, undefined)).toBeUndefined();
176
+ expect(mergeParams(undefined, null)).toBeUndefined();
177
+ expect(mergeParams(null, null)).toBeUndefined();
178
+ });
179
+ it('should merge undefined with params', () => {
180
+ const params = { data: '1' };
181
+ expect(mergeParams(undefined, params)).toEqual(params);
182
+ expect(mergeParams(null, params)).toEqual(params);
183
+ expect(mergeParams(params, undefined)).toEqual(params);
184
+ expect(mergeParams(params, null)).toEqual(params);
185
+ });
186
+ it('should merge params with params', () => {
187
+ const params1 = { data: '1', data3: 'hello' };
188
+ const params2 = { data: '2', data2: 'hola' };
189
+ expect(mergeParams(params1, params2)).toEqual({
190
+ data: '2',
191
+ data2: 'hola',
192
+ data3: 'hello',
193
+ });
194
+ expect(params1).toEqual({ data: '1', data3: 'hello' });
195
+ expect(params2).toEqual({ data: '2', data2: 'hola' });
196
+ });
197
+ });
198
+ describe('RouterSegments', () => {
199
+ it('should initialize with empty array', () => {
200
+ const s = new RouterSegments([]);
201
+ expect(s.next()).toEqual('');
202
+ expect(s.next()).toEqual('');
203
+ expect(s.next()).toEqual('');
204
+ expect(s.next()).toEqual('');
205
+ expect(s.next()).toEqual('');
206
+ });
207
+ it('should initialize with array', () => {
208
+ const s = new RouterSegments(['', 'path', 'to', 'destination']);
209
+ expect(s.next()).toEqual('');
210
+ expect(s.next()).toEqual('path');
211
+ expect(s.next()).toEqual('to');
212
+ expect(s.next()).toEqual('destination');
213
+ expect(s.next()).toEqual('');
214
+ expect(s.next()).toEqual('');
215
+ });
216
+ });
217
+ describe('matchesRedirect', () => {
218
+ it('should match empty redirect', () => {
219
+ expect(matchesRedirect([''], { from: [''], to: { segments: [''] } })).toBeTruthy();
220
+ expect(matchesRedirect([''], { from: ['*'], to: { segments: [''] } })).toBeTruthy();
221
+ expect(matchesRedirect([''], { from: ['hola'], to: { segments: [] } })).toBeFalsy();
222
+ expect(matchesRedirect([''], { from: ['hola', '*'], to: { segments: [''] } })).toBeFalsy();
223
+ });
224
+ it('should match simple segment redirect', () => {
225
+ expect(matchesRedirect(['workouts'], { from: ['workouts'], to: { segments: [''] } })).toBeTruthy();
226
+ expect(matchesRedirect(['workouts'], { from: ['*'], to: { segments: [''] } })).toBeTruthy();
227
+ expect(matchesRedirect(['workouts', 'hola'], { from: ['workouts', '*'], to: { segments: [''] } })).toBeTruthy();
228
+ expect(matchesRedirect(['workouts', 'hola'], { from: ['workouts', 'hola'], to: { segments: [''] } })).toBeTruthy();
229
+ expect(matchesRedirect(['workouts'], { from: ['workouts', '*'], to: { segments: [''] } })).toBeFalsy();
230
+ expect(matchesRedirect(['workouts', 'hola'], { from: ['workouts'], to: { segments: [''] } })).toBeFalsy();
231
+ expect(matchesRedirect(['workouts', 'hola'], { from: ['workouts', 'adios'], to: { segments: [''] } })).toBeFalsy();
232
+ });
233
+ it('should match long route', () => {
234
+ expect(matchesRedirect(['workouts', 'path', 'to'], { from: ['*'], to: { segments: [''] } })).toBeTruthy();
235
+ expect(matchesRedirect(['workouts', 'path', 'to'], { from: ['workouts', '*'], to: { segments: [''] } })).toBeTruthy();
236
+ expect(matchesRedirect(['workouts', 'path', 'to'], { from: ['workouts', 'path', '*'], to: { segments: [''] } })).toBeTruthy();
237
+ expect(matchesRedirect(['workouts', 'path', 'to'], { from: ['workouts', 'path', 'to'], to: { segments: [''] } })).toBeTruthy();
238
+ expect(matchesRedirect(['workouts', 'path', 'to'], { from: ['login'], to: { segments: [''] } })).toBeFalsy();
239
+ expect(matchesRedirect(['workouts', 'path', 'to'], { from: ['login', '*'], to: { segments: [''] } })).toBeFalsy();
240
+ expect(matchesRedirect(['workouts', 'path', 'to'], { from: ['workouts'], to: { segments: [''] } })).toBeFalsy();
241
+ expect(matchesRedirect(['workouts', 'path', 'to'], { from: ['workouts', 'path'], to: { segments: [''] } })).toBeFalsy();
242
+ expect(matchesRedirect(['workouts', 'path', 'to'], { from: ['workouts', 'path', 'to', '*'], to: { segments: [''] } })).toBeFalsy();
243
+ });
244
+ it('should not match undefined "to"', () => {
245
+ expect(matchesRedirect(['workouts', 'path', 'to'], { from: ['*'], to: undefined })).toBeFalsy();
246
+ expect(matchesRedirect(['workouts', 'path', 'to'], { from: ['workouts', '*'], to: undefined })).toBeFalsy();
247
+ expect(matchesRedirect(['workouts', 'path', 'to'], { from: ['workouts', 'path', '*'], to: undefined })).toBeFalsy();
248
+ expect(matchesRedirect(['workouts', 'path', 'to'], { from: ['workouts', 'path', 'to'], to: undefined })).toBeFalsy();
249
+ });
250
+ });
@@ -0,0 +1,133 @@
1
+ /*!
2
+ * (C) Ionic http://ionicframework.com - MIT License
3
+ */
4
+ import { mockWindow } from "@stencil/core/testing";
5
+ import { flattenRouterTree, readRedirects, readRouteNodes } from "../utils/parser";
6
+ describe('parser', () => {
7
+ describe('readRoutes', () => {
8
+ it('should read URL', () => {
9
+ const root = win.document.createElement('div');
10
+ const r1 = mockRouteElement(win, '/', 'MAIN-PAGE');
11
+ const r2 = mockRouteElement(win, '/one-page', 'one-page');
12
+ const r3 = mockRouteElement(win, 'secondpage', 'second-page');
13
+ const r4 = mockRouteElement(win, '/5/hola', '4');
14
+ const r5 = mockRouteElement(win, '/path/to/five', '5');
15
+ const r6 = mockRouteElement(win, '/path/to/five2', '6');
16
+ const r7 = mockRouteElement(win, '/path?flag=true', '6');
17
+ root.appendChild(r1);
18
+ root.appendChild(r2);
19
+ root.appendChild(r3);
20
+ root.appendChild(r7);
21
+ r3.appendChild(r4);
22
+ r4.appendChild(r5);
23
+ r4.appendChild(r6);
24
+ const expected = [
25
+ { segments: [''], id: 'main-page', children: [], params: undefined },
26
+ { segments: ['one-page'], id: 'one-page', children: [], params: undefined },
27
+ {
28
+ segments: ['secondpage'],
29
+ id: 'second-page',
30
+ params: undefined,
31
+ children: [
32
+ {
33
+ segments: ['5', 'hola'],
34
+ id: '4',
35
+ params: undefined,
36
+ children: [
37
+ { segments: ['path', 'to', 'five'], id: '5', children: [], params: undefined },
38
+ { segments: ['path', 'to', 'five2'], id: '6', children: [], params: undefined },
39
+ ],
40
+ },
41
+ ],
42
+ },
43
+ { segments: ['path'], id: '6', children: [], params: undefined },
44
+ ];
45
+ expect(readRouteNodes(root)).toEqual(expected);
46
+ });
47
+ });
48
+ describe('readRedirects', () => {
49
+ it('should read redirects', () => {
50
+ const root = win.document.createElement('div');
51
+ const r1 = mockRedirectElement(win, '/', undefined);
52
+ const r2 = mockRedirectElement(win, undefined, '/workout');
53
+ const r3 = mockRedirectElement(win, '*', null);
54
+ const r4 = mockRedirectElement(win, '/workout/*', '');
55
+ const r5 = mockRedirectElement(win, 'path/hey', '/path/to//login');
56
+ const r6 = mockRedirectElement(win, 'path/qs', '/path?qs=true');
57
+ root.appendChild(r1);
58
+ root.appendChild(r2);
59
+ root.appendChild(r3);
60
+ root.appendChild(r4);
61
+ root.appendChild(r5);
62
+ root.appendChild(r6);
63
+ const expected = [
64
+ { from: [''], to: undefined },
65
+ { from: [''], to: { segments: ['workout'] } },
66
+ { from: ['*'], to: undefined },
67
+ { from: ['workout', '*'], to: { segments: [''] } },
68
+ { from: ['path', 'hey'], to: { segments: ['path', 'to', 'login'] } },
69
+ { from: ['path', 'qs'], to: { segments: ['path'], queryString: 'qs=true' } },
70
+ ];
71
+ expect(readRedirects(root)).toEqual(expected);
72
+ });
73
+ });
74
+ describe('flattenRouterTree', () => {
75
+ it('should process routes', () => {
76
+ const entries = [
77
+ { segments: [''], id: 'hola', children: [], params: undefined },
78
+ { segments: ['one-page'], id: 'one-page', children: [], params: undefined },
79
+ {
80
+ segments: ['secondpage'],
81
+ id: 'second-page',
82
+ params: undefined,
83
+ children: [
84
+ {
85
+ segments: ['5', 'hola'],
86
+ id: '4',
87
+ params: undefined,
88
+ children: [
89
+ { segments: ['path', 'to', 'five'], id: '5', children: [], params: undefined },
90
+ { segments: ['path', 'to', 'five2'], id: '6', children: [], params: undefined },
91
+ ],
92
+ },
93
+ ],
94
+ },
95
+ ];
96
+ const routes = flattenRouterTree(entries);
97
+ expect(routes).toEqual([
98
+ [{ segments: [''], id: 'hola' }],
99
+ [{ segments: ['one-page'], id: 'one-page' }],
100
+ [
101
+ { segments: ['secondpage'], id: 'second-page' },
102
+ { segments: ['5', 'hola'], id: '4' },
103
+ { segments: ['path', 'to', 'five'], id: '5' },
104
+ ],
105
+ [
106
+ { segments: ['secondpage'], id: 'second-page' },
107
+ { segments: ['5', 'hola'], id: '4' },
108
+ { segments: ['path', 'to', 'five2'], id: '6' },
109
+ ],
110
+ ]);
111
+ });
112
+ });
113
+ let win;
114
+ beforeEach(() => {
115
+ win = mockWindow();
116
+ });
117
+ });
118
+ export function mockRouteElement(win, path, component) {
119
+ const el = win.document.createElement('ion-route');
120
+ el.setAttribute('url', path);
121
+ el.component = component;
122
+ return el;
123
+ }
124
+ function mockRedirectElement(win, from, to) {
125
+ const el = win.document.createElement('ion-route-redirect');
126
+ if (from != null) {
127
+ el.setAttribute('from', from);
128
+ }
129
+ if (to != null) {
130
+ el.setAttribute('to', to);
131
+ }
132
+ return el;
133
+ }
@@ -0,0 +1,218 @@
1
+ /*!
2
+ * (C) Ionic http://ionicframework.com - MIT License
3
+ */
4
+ import { ROUTER_INTENT_FORWARD } from "../utils/constants";
5
+ import { chainToSegments, generatePath, parsePath, readSegments, writeSegments } from "../utils/path";
6
+ describe('parsePath', () => {
7
+ it('should parse empty path', () => {
8
+ expect(parsePath('').segments).toEqual(['']);
9
+ });
10
+ it('should parse slash path', () => {
11
+ expect(parsePath('/').segments).toEqual(['']);
12
+ expect(parsePath(' / ').segments).toEqual(['']);
13
+ });
14
+ it('should parse empty path (2)', () => {
15
+ expect(parsePath(' ').segments).toEqual(['']);
16
+ });
17
+ it('should parse null path', () => {
18
+ expect(parsePath(null).segments).toEqual(['']);
19
+ });
20
+ it('should parse undefined path', () => {
21
+ expect(parsePath(undefined).segments).toEqual(['']);
22
+ });
23
+ it('should parse single segment', () => {
24
+ expect(parsePath('path').segments).toEqual(['path']);
25
+ expect(parsePath('path/').segments).toEqual(['path']);
26
+ expect(parsePath('/path/').segments).toEqual(['path']);
27
+ expect(parsePath('/path').segments).toEqual(['path']);
28
+ });
29
+ it('should parse relative path', () => {
30
+ expect(parsePath('path/to/file.js').segments).toEqual(['path', 'to', 'file.js']);
31
+ });
32
+ it('should parse absolute path', () => {
33
+ expect(parsePath('/path/to/file.js').segments).toEqual(['path', 'to', 'file.js']);
34
+ });
35
+ it('should parse absolute path with multiple slashes', () => {
36
+ expect(parsePath('/PATH///to//file.js//').segments).toEqual(['PATH', 'to', 'file.js']);
37
+ });
38
+ it('should parse query string', () => {
39
+ expect(parsePath(null).queryString).toBe(undefined);
40
+ expect(parsePath('path/to/file.js').queryString).toBe(undefined);
41
+ expect(parsePath('path/to/file.js?').queryString).toEqual('');
42
+ expect(parsePath('path/to/file.js?a=b').queryString).toEqual('a=b');
43
+ });
44
+ });
45
+ describe('generatePath', () => {
46
+ it('should generate an empty URL', () => {
47
+ expect(generatePath([])).toEqual('/');
48
+ expect(generatePath([{ segments: '' }])).toEqual('/');
49
+ expect(generatePath([{ segments: '/' }])).toEqual('/');
50
+ expect(generatePath([{ segments: '//' }])).toEqual('/');
51
+ expect(generatePath([{ segments: ' ' }])).toEqual('/');
52
+ });
53
+ it('should genenerate a basic url', () => {
54
+ const stack = ['', '', '', 'path/to', 'page', 'number-TWO', ''];
55
+ expect(generatePath(stack)).toEqual('/path/to/page/number-TWO');
56
+ });
57
+ });
58
+ describe('chainToSegments', () => {
59
+ it('should generate a simple URL', () => {
60
+ const chain = [
61
+ { id: '2', segments: [''], params: undefined },
62
+ { id: '1', segments: [''], params: undefined },
63
+ { id: '3', segments: ['segment', 'to'], params: undefined },
64
+ { id: '4', segments: [''], params: undefined },
65
+ { id: '5', segments: ['hola', '', 'hey'], params: undefined },
66
+ { id: '6', segments: [''], params: undefined },
67
+ { id: '7', segments: [':param'], params: { param: 'name' } },
68
+ { id: '8', segments: ['adios', ':name', ':id'], params: { name: 'manu', id: '123' } },
69
+ ];
70
+ expect(chainToSegments(chain)).toEqual(['segment', 'to', 'hola', 'hey', 'name', 'adios', 'manu', '123']);
71
+ });
72
+ it('should return null on missing parameters', () => {
73
+ const chain = [
74
+ { id: '3', segments: ['segment'], params: undefined },
75
+ { id: '8', segments: [':name'], params: undefined },
76
+ ];
77
+ expect(chainToSegments(chain)).toBeNull();
78
+ });
79
+ it('should return null on missing parameters 2', () => {
80
+ const chain = [
81
+ { id: '3', segments: ['segment'], params: undefined },
82
+ { id: '8', segments: [':name', ':id'], params: { name: 'hey' } },
83
+ ];
84
+ expect(chainToSegments(chain)).toBeNull();
85
+ });
86
+ });
87
+ describe('readSegments', () => {
88
+ it('should read the URL from root (no hash)', () => {
89
+ const loc = mockLocation('/', '');
90
+ expect(readSegments(loc, '', false)).toEqual(['']);
91
+ expect(readSegments(loc, '/', false)).toEqual(['']);
92
+ expect(readSegments(loc, ' / ', false)).toEqual(['']);
93
+ expect(readSegments(loc, '', true)).toEqual(['']);
94
+ expect(readSegments(loc, '/', true)).toEqual(['']);
95
+ expect(readSegments(loc, ' / ', true)).toEqual(['']);
96
+ });
97
+ it('should read the URL from root (hash)', () => {
98
+ const loc = mockLocation('/', '#');
99
+ expect(readSegments(loc, '', true)).toEqual(['']);
100
+ expect(readSegments(loc, '/', true)).toEqual(['']);
101
+ expect(readSegments(loc, ' / ', true)).toEqual(['']);
102
+ const loc2 = mockLocation('/', '#/');
103
+ expect(readSegments(loc2, '', true)).toEqual(['']);
104
+ expect(readSegments(loc2, '/', true)).toEqual(['']);
105
+ expect(readSegments(loc2, ' / ', true)).toEqual(['']);
106
+ });
107
+ it('should not read the URL from root', () => {
108
+ const loc = mockLocation('/', '');
109
+ expect(readSegments(loc, '/hola', false)).toBeNull();
110
+ expect(readSegments(loc, 'hola', false)).toBeNull();
111
+ expect(readSegments(loc, '/hola', true)).toBeNull();
112
+ expect(readSegments(loc, 'hola', true)).toBeNull();
113
+ });
114
+ it('should read the URL from non root (no hash)', () => {
115
+ const loc = mockLocation('/path/to/component', '#hello');
116
+ expect(readSegments(loc, '', false)).toEqual(['path', 'to', 'component']);
117
+ expect(readSegments(loc, '/', false)).toEqual(['path', 'to', 'component']);
118
+ expect(readSegments(loc, 'path', false)).toEqual(['to', 'component']);
119
+ expect(readSegments(loc, '/path', false)).toEqual(['to', 'component']);
120
+ expect(readSegments(loc, '/path/', false)).toEqual(['to', 'component']);
121
+ expect(readSegments(loc, '/path/to', false)).toEqual(['component']);
122
+ expect(readSegments(loc, '/path/to/component', false)).toEqual(['']);
123
+ expect(readSegments(loc, '/path/to/component/', false)).toEqual(['']);
124
+ expect(readSegments(loc, '/path/to/component/path', false)).toBeNull();
125
+ });
126
+ it('should read the URL from non root (hash)', () => {
127
+ const loc = mockLocation('/index.html', '#path/to/component');
128
+ expect(readSegments(loc, '', true)).toEqual(['path', 'to', 'component']);
129
+ expect(readSegments(loc, '/', true)).toEqual(['path', 'to', 'component']);
130
+ expect(readSegments(loc, 'path', true)).toEqual(['to', 'component']);
131
+ expect(readSegments(loc, '/path', true)).toEqual(['to', 'component']);
132
+ expect(readSegments(loc, '/path/', true)).toEqual(['to', 'component']);
133
+ expect(readSegments(loc, '/path/to', true)).toEqual(['component']);
134
+ expect(readSegments(loc, '/path/to/component', true)).toEqual(['']);
135
+ expect(readSegments(loc, '/path/to/component/', true)).toEqual(['']);
136
+ expect(readSegments(loc, '/path/to/component/path', true)).toBeNull();
137
+ expect(readSegments(loc, '/path/to/component2', true)).toBeNull();
138
+ });
139
+ it('should read the URL from non root (hash) 2', () => {
140
+ const loc = mockLocation('/index.html', '#/path/to/component');
141
+ expect(readSegments(loc, '', true)).toEqual(['path', 'to', 'component']);
142
+ expect(readSegments(loc, '/', true)).toEqual(['path', 'to', 'component']);
143
+ expect(readSegments(loc, 'path', true)).toEqual(['to', 'component']);
144
+ expect(readSegments(loc, '/path', true)).toEqual(['to', 'component']);
145
+ expect(readSegments(loc, '/path/', true)).toEqual(['to', 'component']);
146
+ expect(readSegments(loc, '/path/to', true)).toEqual(['component']);
147
+ expect(readSegments(loc, '/path/to/component', true)).toEqual(['']);
148
+ expect(readSegments(loc, '/path/to/component/', true)).toEqual(['']);
149
+ expect(readSegments(loc, '/path/to/component/path', true)).toBeNull();
150
+ });
151
+ });
152
+ describe('writeSegments', () => {
153
+ it('should write root path (no hash)', () => {
154
+ const history = mockHistory();
155
+ writeSegments(history, '', false, [''], ROUTER_INTENT_FORWARD, 123);
156
+ expect(history.pushState).toHaveBeenCalledWith(123, '', '/');
157
+ writeSegments(history, '', false, ['schedule'], ROUTER_INTENT_FORWARD, 123);
158
+ expect(history.pushState).toHaveBeenCalledWith(123, '', '/schedule');
159
+ writeSegments(history, '/', false, [''], ROUTER_INTENT_FORWARD, 123);
160
+ expect(history.pushState).toHaveBeenCalledWith(123, '', '/');
161
+ writeSegments(history, '/', false, ['to', 'schedule'], ROUTER_INTENT_FORWARD, 123);
162
+ expect(history.pushState).toHaveBeenCalledWith(123, '', '/to/schedule');
163
+ writeSegments(history, '/', false, ['to', 'schedule'], ROUTER_INTENT_FORWARD, 123, 'flag=true');
164
+ expect(history.pushState).toHaveBeenCalledWith(123, '', '/to/schedule?flag=true');
165
+ });
166
+ it('should write non root path (no hash)', () => {
167
+ const history = mockHistory();
168
+ writeSegments(history, '/path', false, [''], ROUTER_INTENT_FORWARD, 2);
169
+ expect(history.pushState).toHaveBeenCalledWith(2, '', '/path');
170
+ writeSegments(history, '/path', false, ['to', 'page'], ROUTER_INTENT_FORWARD, 2);
171
+ expect(history.pushState).toHaveBeenCalledWith(2, '', '/path/to/page');
172
+ writeSegments(history, 'path/to', false, ['second', 'page'], ROUTER_INTENT_FORWARD, 2);
173
+ expect(history.pushState).toHaveBeenCalledWith(2, '', '/path/to/second/page');
174
+ writeSegments(history, '/path/to/', false, ['second', 'page'], ROUTER_INTENT_FORWARD, 2);
175
+ expect(history.pushState).toHaveBeenCalledWith(2, '', '/path/to/second/page');
176
+ writeSegments(history, '/path/to/', false, ['second', 'page'], ROUTER_INTENT_FORWARD, 2, 'flag=true');
177
+ expect(history.pushState).toHaveBeenCalledWith(2, '', '/path/to/second/page?flag=true');
178
+ });
179
+ it('should write root path (no hash)', () => {
180
+ const history = mockHistory();
181
+ writeSegments(history, '', true, [''], ROUTER_INTENT_FORWARD, 123);
182
+ expect(history.pushState).toHaveBeenCalledWith(123, '', '#/');
183
+ writeSegments(history, '', true, ['schedule'], ROUTER_INTENT_FORWARD, 123);
184
+ expect(history.pushState).toHaveBeenCalledWith(123, '', '#/schedule');
185
+ writeSegments(history, '/', true, [''], ROUTER_INTENT_FORWARD, 123);
186
+ expect(history.pushState).toHaveBeenCalledWith(123, '', '#/');
187
+ writeSegments(history, '/', true, ['to', 'schedule'], ROUTER_INTENT_FORWARD, 123);
188
+ expect(history.pushState).toHaveBeenCalledWith(123, '', '#/to/schedule');
189
+ writeSegments(history, '/', true, ['to', 'schedule'], ROUTER_INTENT_FORWARD, 123, 'flag=true');
190
+ expect(history.pushState).toHaveBeenCalledWith(123, '', '#/to/schedule?flag=true');
191
+ });
192
+ it('should write non root path (no hash)', () => {
193
+ const history = mockHistory();
194
+ writeSegments(history, '/path', true, [''], ROUTER_INTENT_FORWARD, 123);
195
+ expect(history.pushState).toHaveBeenCalledWith(123, '', '#/path');
196
+ writeSegments(history, '/path', true, ['to', 'page'], ROUTER_INTENT_FORWARD, 123);
197
+ expect(history.pushState).toHaveBeenCalledWith(123, '', '#/path/to/page');
198
+ writeSegments(history, 'path/to', true, ['second', 'page'], ROUTER_INTENT_FORWARD, 123);
199
+ expect(history.pushState).toHaveBeenCalledWith(123, '', '#/path/to/second/page');
200
+ writeSegments(history, '/path/to/', true, ['second', 'page'], ROUTER_INTENT_FORWARD, 123);
201
+ expect(history.pushState).toHaveBeenCalledWith(123, '', '#/path/to/second/page');
202
+ writeSegments(history, '/path/to/', true, ['second', 'page'], ROUTER_INTENT_FORWARD, 123, 'flag=true');
203
+ expect(history.pushState).toHaveBeenCalledWith(123, '', '#/path/to/second/page?flag=true');
204
+ });
205
+ });
206
+ function mockHistory() {
207
+ return {
208
+ replaceState: jest.fn(),
209
+ pushState: jest.fn(),
210
+ length: 0,
211
+ };
212
+ }
213
+ function mockLocation(pathname, hash) {
214
+ return {
215
+ pathname,
216
+ hash,
217
+ };
218
+ }