/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // Tests GeolocationUtils.sys.mjs. "use strict"; ChromeUtils.defineESModuleGetters(this, { GeolocationUtils: "resource:///modules/urlbar/private/GeolocationUtils.sys.mjs", }); add_setup(async () => { // This test assume the mock geolocation is Kanagawa, Yokohama, Japan. await MerinoTestUtils.initGeolocation(); }); const KAWASAKI = { latitude: 35.516667, longitude: 139.7, country: "JP", region: "14", population: 1531646, }; // Made up city with the same location Kawasaki except it has a larger // population. const KAWASAKI_LARGER_POP = { latitude: 35.516667, longitude: 139.7, country: "JP", region: "14", population: Infinity, }; const YOKOSUKA = { latitude: 35.2815, longitude: 139.672083, country: "JP", region: "14", population: 388078, }; const OSAKA = { latitude: 34.693889, longitude: 135.502222, country: "JP", region: "27", population: 2753862, }; const MITOYO = { latitude: 34.1825, longitude: 133.715, country: "JP", region: "37", population: 59876, }; const NYC = { latitude: 40.71427, longitude: -74.00597, country: "US", region: "NY", population: 8804190, }; // Tests items whose locations have latitude and longitude. add_task(async function bestByDistance() { // The made-up city with the same location as Kawasaki but with a larger // population should be returned due to its larger population. Assert.deepEqual( await GeolocationUtils.best([ MITOYO, YOKOSUKA, KAWASAKI, KAWASAKI_LARGER_POP, NYC, ]), KAWASAKI_LARGER_POP, "Made-up Kawasaki-like city should be best when listed after Kawasaki" ); Assert.deepEqual( await GeolocationUtils.best([ MITOYO, YOKOSUKA, KAWASAKI_LARGER_POP, KAWASAKI, NYC, ]), KAWASAKI_LARGER_POP, "Made-up Kawasaki-like city should be best when listed before Kawasaki" ); // Kawasaki is closest to Yokohama. Assert.deepEqual( await GeolocationUtils.best([MITOYO, YOKOSUKA, KAWASAKI, NYC]), KAWASAKI, "Kawasaki should be best" ); // Yokosuka is next closest when the Kawasaki location is messed up. Assert.deepEqual( await GeolocationUtils.best([ MITOYO, YOKOSUKA, { ...KAWASAKI, latitude: null }, NYC, ]), YOKOSUKA, "Yokosuka should be best when Kawasaki location is missing latitude" ); Assert.deepEqual( await GeolocationUtils.best([ MITOYO, YOKOSUKA, { ...KAWASAKI, longitude: null }, NYC, ]), YOKOSUKA, "Yokosuka should be best when Kawasaki location is missing longitude" ); }); // Tests items whose locations have region and country but no latitude or // longitude. add_task(async function bestByRegion() { let kawasaki = { ...KAWASAKI, latitude: null, longitude: null }; let yokosuka = { ...YOKOSUKA, latitude: null, longitude: null }; let osaka = { ...OSAKA, latitude: null, longitude: null }; let mitoyo = { ...MITOYO, latitude: null, longitude: null }; let nyc = { ...NYC, latitude: null, longitude: null }; // Kawasaki and Yokosuka are in the same region as Yokohama, and Kawasaki has // a larger population, so it should be returned. Assert.deepEqual( await GeolocationUtils.best([mitoyo, yokosuka, kawasaki, nyc]), kawasaki, "Kawasaki should be best when listed after Yokosuka" ); Assert.deepEqual( await GeolocationUtils.best([mitoyo, kawasaki, yokosuka, nyc]), kawasaki, "Kawasaki should be best when listed before Yokosuka" ); // Yokosuka is in the same region as Yokohama, so it should be returned. Assert.deepEqual( await GeolocationUtils.best([mitoyo, yokosuka, nyc]), yokosuka, "Yokosuka should be best" ); // Osaka is in a different region but the same country as the geolocation, and // it has a larger population than Mitoyo, so it should be returned. Assert.deepEqual( await GeolocationUtils.best([mitoyo, osaka, nyc]), osaka, "Osaka should be best when listed after Mitoyo" ); Assert.deepEqual( await GeolocationUtils.best([osaka, mitoyo, nyc]), osaka, "Osaka should be best when listed before Mitoyo" ); // Mitoyo is in a different region but the same country as the geolocation, so // it should be returned. Assert.deepEqual( await GeolocationUtils.best([mitoyo, nyc]), mitoyo, "Mitoyo should be best when listed first" ); Assert.deepEqual( await GeolocationUtils.best([nyc, mitoyo]), mitoyo, "Mitoyo should be best when listed last" ); }); // Tests non-default values for the `locationFromItem` param. add_task(async function locationFromItem() { // Return an empty location for everything except NYC. Since NYC is the only // location with latitude and longitude, `best()` should return it even though // it's not actually the closest to Merino's mock geolocation. Assert.deepEqual( await GeolocationUtils.best([MITOYO, KAWASAKI, YOKOSUKA, NYC], item => item == NYC ? NYC : {} ), NYC, "NYC should be best" ); }); // Tests unexpected Merino geolocation responses. add_task(async function unexpectedMerinoGeolocation() { // The first item should be returned in all these cases. MerinoTestUtils.server.response = { status: 501 }; Assert.deepEqual( await GeolocationUtils.best([NYC, MITOYO, YOKOSUKA, KAWASAKI]), NYC, "NYC should be best when geolocation response is not a 200" ); await MerinoTestUtils.initGeolocation(); MerinoTestUtils.server.response = { status: 200 }; Assert.deepEqual( await GeolocationUtils.best([NYC, MITOYO, YOKOSUKA, KAWASAKI]), NYC, "NYC should be best when geolocation response is empty" ); await MerinoTestUtils.initGeolocation(); MerinoTestUtils.server.response.body.suggestions[0].custom_details = null; Assert.deepEqual( await GeolocationUtils.best([NYC, MITOYO, KAWASAKI, YOKOSUKA]), NYC, "NYC should be best when geolocation response is missing custom_details" ); await MerinoTestUtils.initGeolocation(); MerinoTestUtils.server.response.body.suggestions[0].custom_details.geolocation = null; Assert.deepEqual( await GeolocationUtils.best([NYC, MITOYO, KAWASAKI, YOKOSUKA]), NYC, "NYC should be best when geolocation response is missing geolocation" ); await MerinoTestUtils.initGeolocation(); MerinoTestUtils.server.response.body.suggestions[0].custom_details.geolocation.region_code = null; MerinoTestUtils.server.response.body.suggestions[0].custom_details.geolocation.country_code = null; MerinoTestUtils.server.response.body.suggestions[0].custom_details.geolocation.location = null; Assert.deepEqual( await GeolocationUtils.best([NYC, MITOYO, KAWASAKI, YOKOSUKA]), NYC, "NYC should be best when geolocation response is missing geolocation" ); // We should fall back to `#bestByRegion()` in these cases. await MerinoTestUtils.initGeolocation(); MerinoTestUtils.server.response.body.suggestions[0].custom_details.geolocation.location = null; Assert.deepEqual( await GeolocationUtils.best([NYC, MITOYO, KAWASAKI, YOKOSUKA]), KAWASAKI, "Kawasaki should be best when geolocation response is missing location" ); await MerinoTestUtils.initGeolocation(); MerinoTestUtils.server.response.body.suggestions[0].custom_details.geolocation.location.latitude = null; Assert.deepEqual( await GeolocationUtils.best([NYC, MITOYO, KAWASAKI, YOKOSUKA]), KAWASAKI, "Kawasaki should be best when geolocation response is missing latitude" ); await MerinoTestUtils.initGeolocation(); MerinoTestUtils.server.response.body.suggestions[0].custom_details.geolocation.location.longitude = null; Assert.deepEqual( await GeolocationUtils.best([NYC, MITOYO, KAWASAKI, YOKOSUKA]), KAWASAKI, "Kawasaki should be best when geolocation response is missing longitude" ); // Here `region_code` and `location` are null but `country_code` is still // correct, so the item with the same country should be returned. await MerinoTestUtils.initGeolocation(); MerinoTestUtils.server.response.body.suggestions[0].custom_details.geolocation.region_code = null; MerinoTestUtils.server.response.body.suggestions[0].custom_details.geolocation.location = null; Assert.deepEqual( await GeolocationUtils.best([NYC, MITOYO]), MITOYO, "Mitoyo should be best when geolocation response is missing region_code and location and Mitoyo is listed after NYC" ); Assert.deepEqual( await GeolocationUtils.best([MITOYO, NYC]), MITOYO, "Mitoyo should be best when geolocation response is missing region_code and location and Mitoyo is listed before NYC" ); // Reset for the next task. await MerinoTestUtils.initGeolocation(); });