Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* 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 the `quickSuggestScoreMap` Nimbus variable that assigns scores to
// specified types of quick suggest suggestions. The scores in the map should
// override the scores in the individual suggestion objects so that experiments
// can fully control the relative ranking of suggestions.
"use strict";
ChromeUtils.defineESModuleGetters(this, {
});
AddonTestUtils.init(this, false);
AddonTestUtils.createAppInfo(
"xpcshell@tests.mozilla.org",
"XPCShell",
"42",
"42"
);
const { DEFAULT_SUGGESTION_SCORE } = UrlbarProviderQuickSuggest;
const REMOTE_SETTINGS_RECORDS = [
{
type: "data",
attachment: [
// sponsored without score
QuickSuggestTestUtils.ampRemoteSettings({
score: undefined,
keywords: [
"sponsored without score",
"sponsored without score, nonsponsored without score",
"sponsored without score, nonsponsored with score",
"sponsored without score, addon without score",
],
title: "Sponsored without score",
}),
// sponsored with score
QuickSuggestTestUtils.ampRemoteSettings({
score: 2 * DEFAULT_SUGGESTION_SCORE,
keywords: [
"sponsored with score",
"sponsored with score, nonsponsored without score",
"sponsored with score, nonsponsored with score",
"sponsored with score, addon with score",
],
title: "Sponsored with score",
}),
// nonsponsored without score
QuickSuggestTestUtils.wikipediaRemoteSettings({
score: undefined,
keywords: [
"nonsponsored without score",
"sponsored without score, nonsponsored without score",
"sponsored with score, nonsponsored without score",
],
title: "Nonsponsored without score",
}),
// nonsponsored with score
QuickSuggestTestUtils.wikipediaRemoteSettings({
score: 2 * DEFAULT_SUGGESTION_SCORE,
keywords: [
"nonsponsored with score",
"sponsored without score, nonsponsored with score",
"sponsored with score, nonsponsored with score",
],
title: "Nonsponsored with score",
}),
],
},
{
type: "amo-suggestions",
attachment: [
// addon with score
QuickSuggestTestUtils.amoRemoteSettings({
score: 2 * DEFAULT_SUGGESTION_SCORE,
keywords: [
"addon with score",
"sponsored with score, addon with score",
],
title: "Addon with score",
}),
],
},
];
const ADM_RECORD = REMOTE_SETTINGS_RECORDS[0];
const SPONSORED_WITHOUT_SCORE = ADM_RECORD.attachment[0];
const SPONSORED_WITH_SCORE = ADM_RECORD.attachment[1];
const NONSPONSORED_WITHOUT_SCORE = ADM_RECORD.attachment[2];
const NONSPONSORED_WITH_SCORE = ADM_RECORD.attachment[3];
const ADDON_RECORD = REMOTE_SETTINGS_RECORDS[1];
const ADDON_WITH_SCORE = ADDON_RECORD.attachment[0];
const MERINO_SPONSORED_SUGGESTION = {
provider: "adm",
score: DEFAULT_SUGGESTION_SCORE,
iab_category: "22 - Shopping",
is_sponsored: true,
keywords: ["test"],
full_keyword: "test",
block_id: 1,
title: "Merino sponsored",
impression_url: "https://example.com/impression",
advertiser: "TestAdvertiser",
icon: "1234",
};
const MERINO_ADDON_SUGGESTION = {
provider: "amo",
score: DEFAULT_SUGGESTION_SCORE,
keywords: ["test"],
title: "Merino addon",
description: "Merino addon",
custom_details: {
amo: {
guid: "merino-addon@example.com",
rating: "4.7",
number_of_ratings: "1256",
},
},
};
const MERINO_UNKNOWN_SUGGESTION = {
provider: "some_unknown_provider",
score: DEFAULT_SUGGESTION_SCORE,
keywords: ["test"],
title: "Merino unknown",
};
add_setup(async function init() {
await AddonTestUtils.promiseStartupManager();
await QuickSuggestTestUtils.ensureQuickSuggestInit({
remoteSettingsRecords: REMOTE_SETTINGS_RECORDS,
merinoSuggestions: [],
prefs: [
["suggest.quicksuggest.sponsored", true],
["suggest.quicksuggest.nonsponsored", true],
],
});
});
add_task(async function sponsoredWithout_nonsponsoredWithout_sponsoredWins() {
let keyword = "sponsored without score, nonsponsored without score";
let score = 10 * DEFAULT_SUGGESTION_SCORE;
await doTest({
keyword,
scoreMap: {
adm_sponsored: score,
},
expectedFeatureName: "AdmWikipedia",
expectedScore: score,
expectedResult: makeExpectedAmpResult({
keyword,
suggestion: SPONSORED_WITHOUT_SCORE,
}),
});
});
add_task(
async function sponsoredWithout_nonsponsoredWithout_nonsponsoredWins() {
let keyword = "sponsored without score, nonsponsored without score";
let score = 10 * DEFAULT_SUGGESTION_SCORE;
await doTest({
keyword,
scoreMap: {
adm_nonsponsored: score,
},
expectedFeatureName: "AdmWikipedia",
expectedScore: score,
expectedResult: makeExpectedWikipediaResult({
keyword,
suggestion: NONSPONSORED_WITHOUT_SCORE,
}),
});
}
);
add_task(
async function sponsoredWithout_nonsponsoredWithout_sponsoredWins_both() {
let keyword = "sponsored without score, nonsponsored without score";
let score = 10 * DEFAULT_SUGGESTION_SCORE;
await doTest({
keyword,
scoreMap: {
adm_sponsored: score,
adm_nonsponsored: score / 2,
},
expectedFeatureName: "AdmWikipedia",
expectedScore: score,
expectedResult: makeExpectedAmpResult({
keyword,
suggestion: SPONSORED_WITHOUT_SCORE,
}),
});
}
);
add_task(
async function sponsoredWithout_nonsponsoredWithout_nonsponsoredWins_both() {
let keyword = "sponsored without score, nonsponsored without score";
let score = 10 * DEFAULT_SUGGESTION_SCORE;
await doTest({
keyword,
scoreMap: {
adm_nonsponsored: score,
adm_sponsored: score / 2,
},
expectedFeatureName: "AdmWikipedia",
expectedScore: score,
expectedResult: makeExpectedWikipediaResult({
keyword,
suggestion: NONSPONSORED_WITHOUT_SCORE,
}),
});
}
);
add_task(async function sponsoredWith_nonsponsoredWith_sponsoredWins() {
let keyword = "sponsored with score, nonsponsored with score";
let score = 10 * DEFAULT_SUGGESTION_SCORE;
await doTest({
keyword,
scoreMap: {
adm_sponsored: score,
},
expectedFeatureName: "AdmWikipedia",
expectedScore: score,
expectedResult: makeExpectedAmpResult({
keyword,
suggestion: SPONSORED_WITH_SCORE,
}),
});
});
add_task(async function sponsoredWith_nonsponsoredWith_nonsponsoredWins() {
let keyword = "sponsored with score, nonsponsored with score";
let score = 10 * DEFAULT_SUGGESTION_SCORE;
await doTest({
keyword,
scoreMap: {
adm_nonsponsored: score,
},
expectedFeatureName: "AdmWikipedia",
expectedScore: score,
expectedResult: makeExpectedWikipediaResult({
keyword,
suggestion: NONSPONSORED_WITH_SCORE,
}),
});
});
add_task(async function sponsoredWith_nonsponsoredWith_sponsoredWins_both() {
let keyword = "sponsored with score, nonsponsored with score";
let score = 10 * DEFAULT_SUGGESTION_SCORE;
await doTest({
keyword,
scoreMap: {
adm_sponsored: score,
adm_nonsponsored: score / 2,
},
expectedFeatureName: "AdmWikipedia",
expectedScore: score,
expectedResult: makeExpectedAmpResult({
keyword,
suggestion: SPONSORED_WITH_SCORE,
}),
});
});
add_task(async function sponsoredWith_nonsponsoredWith_nonsponsoredWins_both() {
let keyword = "sponsored with score, nonsponsored with score";
let score = 10 * DEFAULT_SUGGESTION_SCORE;
await doTest({
keyword,
scoreMap: {
adm_nonsponsored: score,
adm_sponsored: score / 2,
},
expectedFeatureName: "AdmWikipedia",
expectedScore: score,
expectedResult: makeExpectedWikipediaResult({
keyword,
suggestion: NONSPONSORED_WITH_SCORE,
}),
});
});
add_task(async function sponsoredWithout_addonWithout_sponsoredWins() {
let keyword = "sponsored without score, addon without score";
let score = 10 * DEFAULT_SUGGESTION_SCORE;
await doTest({
keyword,
scoreMap: {
adm_sponsored: score,
},
expectedFeatureName: "AdmWikipedia",
expectedScore: score,
expectedResult: makeExpectedAmpResult({
keyword,
suggestion: SPONSORED_WITHOUT_SCORE,
}),
});
});
add_task(async function sponsoredWithout_addonWithout_sponsoredWins_both() {
let keyword = "sponsored without score, addon without score";
let score = 10 * DEFAULT_SUGGESTION_SCORE;
await doTest({
keyword,
scoreMap: {
adm_sponsored: score,
amo: score / 2,
},
expectedFeatureName: "AdmWikipedia",
expectedScore: score,
expectedResult: makeExpectedAmpResult({
keyword,
suggestion: SPONSORED_WITHOUT_SCORE,
}),
});
});
add_task(async function sponsoredWith_addonWith_sponsoredWins() {
let keyword = "sponsored with score, addon with score";
let score = 10 * DEFAULT_SUGGESTION_SCORE;
await doTest({
keyword,
scoreMap: {
adm_sponsored: score,
},
expectedFeatureName: "AdmWikipedia",
expectedScore: score,
expectedResult: makeExpectedAmpResult({
keyword,
suggestion: SPONSORED_WITH_SCORE,
}),
});
});
add_task(async function sponsoredWith_addonWith_addonWins() {
let keyword = "sponsored with score, addon with score";
let score = 10 * DEFAULT_SUGGESTION_SCORE;
await doTest({
keyword,
scoreMap: {
amo: score,
},
expectedFeatureName: "AddonSuggestions",
expectedScore: score,
expectedResult: makeExpectedAddonResult({
suggestion: ADDON_WITH_SCORE,
}),
});
});
add_task(async function sponsoredWith_addonWith_sponsoredWins_both() {
let keyword = "sponsored with score, addon with score";
let score = 10 * DEFAULT_SUGGESTION_SCORE;
await doTest({
keyword,
scoreMap: {
adm_sponsored: score,
amo: score / 2,
},
expectedFeatureName: "AdmWikipedia",
expectedScore: score,
expectedResult: makeExpectedAmpResult({
keyword,
suggestion: SPONSORED_WITH_SCORE,
}),
});
});
add_task(async function sponsoredWith_addonWith_addonWins_both() {
let keyword = "sponsored with score, addon with score";
let score = 10 * DEFAULT_SUGGESTION_SCORE;
await doTest({
keyword,
scoreMap: {
amo: score,
adm_sponsored: score / 2,
},
expectedFeatureName: "AddonSuggestions",
expectedScore: score,
expectedResult: makeExpectedAddonResult({
suggestion: ADDON_WITH_SCORE,
}),
});
});
add_task(async function merino_sponsored_addon_sponsoredWins() {
await QuickSuggestTestUtils.setRemoteSettingsRecords([]);
MerinoTestUtils.server.response.body.suggestions = [
MERINO_SPONSORED_SUGGESTION,
MERINO_ADDON_SUGGESTION,
];
let score = 10 * DEFAULT_SUGGESTION_SCORE;
await doTest({
keyword: "test",
scoreMap: {
adm_sponsored: score,
},
expectedFeatureName: "AdmWikipedia",
expectedScore: score,
expectedResult: makeExpectedAmpResult({
keyword: "test",
suggestion: MERINO_SPONSORED_SUGGESTION,
source: "merino",
provider: "adm",
requestId: MerinoTestUtils.server.response.body.request_id,
}),
});
await QuickSuggestTestUtils.setRemoteSettingsRecords(REMOTE_SETTINGS_RECORDS);
});
add_task(async function merino_sponsored_addon_addonWins() {
await QuickSuggestTestUtils.setRemoteSettingsRecords([]);
MerinoTestUtils.server.response.body.suggestions = [
MERINO_SPONSORED_SUGGESTION,
MERINO_ADDON_SUGGESTION,
];
let score = 10 * DEFAULT_SUGGESTION_SCORE;
await doTest({
keyword: "test",
scoreMap: {
amo: score,
},
expectedFeatureName: "AddonSuggestions",
expectedScore: score,
expectedResult: makeExpectedAddonResult({
suggestion: MERINO_ADDON_SUGGESTION,
source: "merino",
provider: "amo",
requestId: MerinoTestUtils.server.response.body.request_id,
}),
});
await QuickSuggestTestUtils.setRemoteSettingsRecords(REMOTE_SETTINGS_RECORDS);
});
add_task(async function merino_sponsored_unknown_sponsoredWins() {
await QuickSuggestTestUtils.setRemoteSettingsRecords([]);
MerinoTestUtils.server.response.body.suggestions = [
MERINO_SPONSORED_SUGGESTION,
MERINO_UNKNOWN_SUGGESTION,
];
let score = 10 * DEFAULT_SUGGESTION_SCORE;
await doTest({
keyword: "test",
scoreMap: {
adm_sponsored: score,
},
expectedFeatureName: "AdmWikipedia",
expectedScore: score,
expectedResult: makeExpectedAmpResult({
keyword: "test",
suggestion: MERINO_SPONSORED_SUGGESTION,
source: "merino",
provider: "adm",
requestId: MerinoTestUtils.server.response.body.request_id,
}),
});
await QuickSuggestTestUtils.setRemoteSettingsRecords(REMOTE_SETTINGS_RECORDS);
});
add_task(async function merino_sponsored_unknown_unknownWins() {
await QuickSuggestTestUtils.setRemoteSettingsRecords([]);
MerinoTestUtils.server.response.body.suggestions = [
MERINO_SPONSORED_SUGGESTION,
MERINO_UNKNOWN_SUGGESTION,
];
let score = 10 * DEFAULT_SUGGESTION_SCORE;
await doTest({
keyword: "test",
scoreMap: {
[MERINO_UNKNOWN_SUGGESTION.provider]: score,
},
expectedFeatureName: null,
expectedScore: score,
expectedResult: makeExpectedDefaultMerinoResult({
suggestion: MERINO_UNKNOWN_SUGGESTION,
}),
});
await QuickSuggestTestUtils.setRemoteSettingsRecords(REMOTE_SETTINGS_RECORDS);
});
add_task(async function stringValue() {
let keyword = "sponsored with score, nonsponsored with score";
await doTest({
keyword,
scoreMap: {
adm_sponsored: "123.456",
},
expectedFeatureName: "AdmWikipedia",
expectedScore: 123.456,
expectedResult: makeExpectedAmpResult({
keyword,
suggestion: SPONSORED_WITH_SCORE,
}),
});
});
/**
* Sets up Nimbus with a `quickSuggestScoreMap` variable value, does a search,
* and makes sure the expected result is shown and the expected score is set on
* the suggestion.
*
* @param {object} options
* Options object.
* @param {string} options.keyword
* The search string. This should be equal to a keyword from one or more
* suggestions.
* @param {object} options.scoreMap
* The value to set for the `quickSuggestScoreMap` variable.
* @param {string} options.expectedFeatureName
* The name of the `BaseFeature` instance that is expected to create the
* `UrlbarResult` that's shown. If the suggestion is intentionally from an
* unknown Merino provider and therefore the quick suggest provider is
* expected to create a default result for it, set this to null.
* @param {UrlbarResultstring} options.expectedResult
* The `UrlbarResult` that's expected to be shown.
* @param {number} options.expectedScore
* The final `score` value that's expected to be defined on the suggestion
* object.
*/
async function doTest({
keyword,
scoreMap,
expectedFeatureName,
expectedResult,
expectedScore,
}) {
let cleanUpNimbus = await UrlbarTestUtils.initNimbusFeature({
quickSuggestScoreMap: scoreMap,
});
// Stub the expected feature's `makeResult()` so we can see the value of the
// passed-in suggestion's score. If the suggestion's type is in the score map,
// the provider will set its score before calling `makeResult()`.
let actualScore;
let sandbox;
if (expectedFeatureName) {
sandbox = sinon.createSandbox();
let feature = QuickSuggest.getFeature(expectedFeatureName);
let stub = sandbox
.stub(feature, "makeResult")
.callsFake((queryContext, suggestion, searchString) => {
if (suggestion.url == expectedResult.payload.originalUrl) {
actualScore = suggestion.score;
}
return stub.wrappedMethod.call(
feature,
queryContext,
suggestion,
searchString
);
});
}
await check_results({
context: createContext(keyword, {
providers: [UrlbarProviderQuickSuggest.name],
isPrivate: false,
}),
matches: [expectedResult],
});
if (expectedFeatureName) {
Assert.equal(
actualScore,
expectedScore,
"Suggestion score should be set correctly"
);
sandbox.restore();
}
await cleanUpNimbus();
}
function makeExpectedAmpResult({
suggestion,
keyword,
source,
provider,
requestId,
}) {
return QuickSuggestTestUtils.ampResult({
keyword,
source,
provider,
requestId,
title: suggestion.title,
url: suggestion.url,
originalUrl: suggestion.url,
impressionUrl: suggestion.impression_url,
clickUrl: suggestion.click_url,
blockId: suggestion.id,
advertiser: suggestion.advertiser,
icon: suggestion.icon,
});
}
function makeExpectedWikipediaResult({ suggestion, keyword, source }) {
return QuickSuggestTestUtils.wikipediaResult({
keyword,
source,
title: suggestion.title,
url: suggestion.url,
originalUrl: suggestion.url,
impressionUrl: suggestion.impression_url,
clickUrl: suggestion.click_url,
blockId: suggestion.id,
});
}
function makeExpectedAddonResult({ suggestion, source, provider }) {
return QuickSuggestTestUtils.amoResult({
source,
provider,
title: suggestion.title,
description: suggestion.description,
url: suggestion.url,
originalUrl: suggestion.url,
icon: suggestion.icon,
});
}
function makeExpectedDefaultMerinoResult({ suggestion }) {
return {
type: UrlbarUtils.RESULT_TYPE.URL,
source: UrlbarUtils.RESULT_SOURCE.SEARCH,
heuristic: false,
payload: {
source: "merino",
provider: suggestion.provider,
telemetryType: suggestion.provider,
isSponsored: !!suggestion.is_sponsored,
title: suggestion.title,
url: suggestion.url,
displayUrl: suggestion.url.replace(/^https:\/\//, ""),
icon: suggestion.icon,
descriptionL10n: suggestion.is_sponsored
? { id: "urlbar-result-action-sponsored" }
: undefined,
shouldShowUrl: true,
isBlockable: true,
blockL10n: {
id: "urlbar-result-menu-dismiss-firefox-suggest",
},
isManageable: true,
},
};
}