test_geolocationUtils.js (9019B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 // Tests GeolocationUtils.sys.mjs. 6 7 "use strict"; 8 9 ChromeUtils.defineESModuleGetters(this, { 10 GeolocationUtils: 11 "moz-src:///browser/components/urlbar/private/GeolocationUtils.sys.mjs", 12 }); 13 14 add_setup(async () => { 15 // This test assume the mock geolocation is Kanagawa, Yokohama, Japan. 16 await MerinoTestUtils.initGeolocation(); 17 }); 18 19 const KAWASAKI = { 20 latitude: 35.516667, 21 longitude: 139.7, 22 country: "JP", 23 region: "14", 24 population: 1531646, 25 }; 26 27 // Made up city with the same location Kawasaki except it has a larger 28 // population. 29 const KAWASAKI_LARGER_POP = { 30 latitude: 35.516667, 31 longitude: 139.7, 32 country: "JP", 33 region: "14", 34 population: Infinity, 35 }; 36 37 const YOKOSUKA = { 38 latitude: 35.2815, 39 longitude: 139.672083, 40 country: "JP", 41 region: "14", 42 population: 388078, 43 }; 44 45 const OSAKA = { 46 latitude: 34.693889, 47 longitude: 135.502222, 48 country: "JP", 49 region: "27", 50 population: 2753862, 51 }; 52 53 const MITOYO = { 54 latitude: 34.1825, 55 longitude: 133.715, 56 country: "JP", 57 region: "37", 58 population: 59876, 59 }; 60 61 const NYC = { 62 latitude: 40.71427, 63 longitude: -74.00597, 64 country: "US", 65 region: "NY", 66 population: 8804190, 67 }; 68 69 // Tests items whose locations have latitude and longitude. 70 add_task(async function bestByDistance() { 71 // The made-up city with the same location as Kawasaki but with a larger 72 // population should be returned due to its larger population. 73 Assert.deepEqual( 74 await GeolocationUtils.best([ 75 MITOYO, 76 YOKOSUKA, 77 KAWASAKI, 78 KAWASAKI_LARGER_POP, 79 NYC, 80 ]), 81 KAWASAKI_LARGER_POP, 82 "Made-up Kawasaki-like city should be best when listed after Kawasaki" 83 ); 84 Assert.deepEqual( 85 await GeolocationUtils.best([ 86 MITOYO, 87 YOKOSUKA, 88 KAWASAKI_LARGER_POP, 89 KAWASAKI, 90 NYC, 91 ]), 92 KAWASAKI_LARGER_POP, 93 "Made-up Kawasaki-like city should be best when listed before Kawasaki" 94 ); 95 96 // Kawasaki is closest to Yokohama. 97 Assert.deepEqual( 98 await GeolocationUtils.best([MITOYO, YOKOSUKA, KAWASAKI, NYC]), 99 KAWASAKI, 100 "Kawasaki should be best" 101 ); 102 103 // Yokosuka is next closest when the Kawasaki location is messed up. 104 Assert.deepEqual( 105 await GeolocationUtils.best([ 106 MITOYO, 107 YOKOSUKA, 108 { ...KAWASAKI, latitude: null }, 109 NYC, 110 ]), 111 YOKOSUKA, 112 "Yokosuka should be best when Kawasaki location is missing latitude" 113 ); 114 Assert.deepEqual( 115 await GeolocationUtils.best([ 116 MITOYO, 117 YOKOSUKA, 118 { ...KAWASAKI, longitude: null }, 119 NYC, 120 ]), 121 YOKOSUKA, 122 "Yokosuka should be best when Kawasaki location is missing longitude" 123 ); 124 }); 125 126 // Tests items whose locations have region and country but no latitude or 127 // longitude. 128 add_task(async function bestByRegion() { 129 let kawasaki = { ...KAWASAKI, latitude: null, longitude: null }; 130 let yokosuka = { ...YOKOSUKA, latitude: null, longitude: null }; 131 let osaka = { ...OSAKA, latitude: null, longitude: null }; 132 let mitoyo = { ...MITOYO, latitude: null, longitude: null }; 133 let nyc = { ...NYC, latitude: null, longitude: null }; 134 135 // Kawasaki and Yokosuka are in the same region as Yokohama, and Kawasaki has 136 // a larger population, so it should be returned. 137 Assert.deepEqual( 138 await GeolocationUtils.best([mitoyo, yokosuka, kawasaki, nyc]), 139 kawasaki, 140 "Kawasaki should be best when listed after Yokosuka" 141 ); 142 Assert.deepEqual( 143 await GeolocationUtils.best([mitoyo, kawasaki, yokosuka, nyc]), 144 kawasaki, 145 "Kawasaki should be best when listed before Yokosuka" 146 ); 147 148 // Yokosuka is in the same region as Yokohama, so it should be returned. 149 Assert.deepEqual( 150 await GeolocationUtils.best([mitoyo, yokosuka, nyc]), 151 yokosuka, 152 "Yokosuka should be best" 153 ); 154 155 // Osaka is in a different region but the same country as the geolocation, and 156 // it has a larger population than Mitoyo, so it should be returned. 157 Assert.deepEqual( 158 await GeolocationUtils.best([mitoyo, osaka, nyc]), 159 osaka, 160 "Osaka should be best when listed after Mitoyo" 161 ); 162 Assert.deepEqual( 163 await GeolocationUtils.best([osaka, mitoyo, nyc]), 164 osaka, 165 "Osaka should be best when listed before Mitoyo" 166 ); 167 168 // Mitoyo is in a different region but the same country as the geolocation, so 169 // it should be returned. 170 Assert.deepEqual( 171 await GeolocationUtils.best([mitoyo, nyc]), 172 mitoyo, 173 "Mitoyo should be best when listed first" 174 ); 175 Assert.deepEqual( 176 await GeolocationUtils.best([nyc, mitoyo]), 177 mitoyo, 178 "Mitoyo should be best when listed last" 179 ); 180 }); 181 182 // Tests non-default values for the `locationFromItem` param. 183 add_task(async function locationFromItem() { 184 // Return an empty location for everything except NYC. Since NYC is the only 185 // location with latitude and longitude, `best()` should return it even though 186 // it's not actually the closest to Merino's mock geolocation. 187 Assert.deepEqual( 188 await GeolocationUtils.best([MITOYO, KAWASAKI, YOKOSUKA, NYC], item => 189 item == NYC ? NYC : {} 190 ), 191 NYC, 192 "NYC should be best" 193 ); 194 }); 195 196 // Tests unexpected Merino geolocation responses. 197 add_task(async function unexpectedMerinoGeolocation() { 198 // The first item should be returned in all these cases. 199 MerinoTestUtils.server.response = { status: 501 }; 200 Assert.deepEqual( 201 await GeolocationUtils.best([NYC, MITOYO, YOKOSUKA, KAWASAKI]), 202 NYC, 203 "NYC should be best when geolocation response is not a 200" 204 ); 205 206 await MerinoTestUtils.initGeolocation(); 207 MerinoTestUtils.server.response = { status: 200 }; 208 Assert.deepEqual( 209 await GeolocationUtils.best([NYC, MITOYO, YOKOSUKA, KAWASAKI]), 210 NYC, 211 "NYC should be best when geolocation response is empty" 212 ); 213 214 await MerinoTestUtils.initGeolocation(); 215 MerinoTestUtils.server.response.body.suggestions[0].custom_details = null; 216 Assert.deepEqual( 217 await GeolocationUtils.best([NYC, MITOYO, KAWASAKI, YOKOSUKA]), 218 NYC, 219 "NYC should be best when geolocation response is missing custom_details" 220 ); 221 222 await MerinoTestUtils.initGeolocation(); 223 MerinoTestUtils.server.response.body.suggestions[0].custom_details.geolocation = 224 null; 225 Assert.deepEqual( 226 await GeolocationUtils.best([NYC, MITOYO, KAWASAKI, YOKOSUKA]), 227 NYC, 228 "NYC should be best when geolocation response is missing geolocation" 229 ); 230 231 await MerinoTestUtils.initGeolocation(); 232 MerinoTestUtils.server.response.body.suggestions[0].custom_details.geolocation.region_code = 233 null; 234 MerinoTestUtils.server.response.body.suggestions[0].custom_details.geolocation.country_code = 235 null; 236 MerinoTestUtils.server.response.body.suggestions[0].custom_details.geolocation.location = 237 null; 238 Assert.deepEqual( 239 await GeolocationUtils.best([NYC, MITOYO, KAWASAKI, YOKOSUKA]), 240 NYC, 241 "NYC should be best when geolocation response is missing geolocation" 242 ); 243 244 // We should fall back to `#bestByRegion()` in these cases. 245 await MerinoTestUtils.initGeolocation(); 246 MerinoTestUtils.server.response.body.suggestions[0].custom_details.geolocation.location = 247 null; 248 Assert.deepEqual( 249 await GeolocationUtils.best([NYC, MITOYO, KAWASAKI, YOKOSUKA]), 250 KAWASAKI, 251 "Kawasaki should be best when geolocation response is missing location" 252 ); 253 254 await MerinoTestUtils.initGeolocation(); 255 MerinoTestUtils.server.response.body.suggestions[0].custom_details.geolocation.location.latitude = 256 null; 257 Assert.deepEqual( 258 await GeolocationUtils.best([NYC, MITOYO, KAWASAKI, YOKOSUKA]), 259 KAWASAKI, 260 "Kawasaki should be best when geolocation response is missing latitude" 261 ); 262 263 await MerinoTestUtils.initGeolocation(); 264 MerinoTestUtils.server.response.body.suggestions[0].custom_details.geolocation.location.longitude = 265 null; 266 Assert.deepEqual( 267 await GeolocationUtils.best([NYC, MITOYO, KAWASAKI, YOKOSUKA]), 268 KAWASAKI, 269 "Kawasaki should be best when geolocation response is missing longitude" 270 ); 271 272 // Here `region_code` and `location` are null but `country_code` is still 273 // correct, so the item with the same country should be returned. 274 await MerinoTestUtils.initGeolocation(); 275 MerinoTestUtils.server.response.body.suggestions[0].custom_details.geolocation.region_code = 276 null; 277 MerinoTestUtils.server.response.body.suggestions[0].custom_details.geolocation.location = 278 null; 279 Assert.deepEqual( 280 await GeolocationUtils.best([NYC, MITOYO]), 281 MITOYO, 282 "Mitoyo should be best when geolocation response is missing region_code and location and Mitoyo is listed after NYC" 283 ); 284 Assert.deepEqual( 285 await GeolocationUtils.best([MITOYO, NYC]), 286 MITOYO, 287 "Mitoyo should be best when geolocation response is missing region_code and location and Mitoyo is listed before NYC" 288 ); 289 290 // Reset for the next task. 291 await MerinoTestUtils.initGeolocation(); 292 });