Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* Any copyright is dedicated to the Public Domain.
/**
* Browser test for clipboard suggestion.
*/
"use strict";
const { UrlbarProviderClipboard, CLIPBOARD_IMPRESSION_LIMIT } =
ChromeUtils.importESModule(
);
add_setup(async function () {
await SpecialPowers.pushPrefEnv({
set: [
["browser.urlbar.clipboard.featureGate", true],
["browser.urlbar.suggest.clipboard", true],
],
});
registerCleanupFunction(async () => {
SpecialPowers.clipboardCopyString("");
await PlacesUtils.history.clear();
});
});
async function searchEmptyStringAndGetFirstRow() {
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "",
});
Assert.ok(gURLBar.view.isOpen, "UrlbarView should be open.");
return UrlbarTestUtils.getRowAt(window, 0);
}
async function checkClipboardSuggestionAbsent(startIdx) {
for (let i = startIdx; i < UrlbarTestUtils.getResultCount(window); i++) {
const row = await UrlbarTestUtils.getRowAt(window, i);
Assert.notEqual(
row.result.providerName,
UrlbarProviderClipboard.name,
`Clipboard suggestion should be absent (checking index ${i})`
);
}
}
add_task(async function testFormattingOfClipboardSuggestion() {
let unicodeURL = "https://пример.com/";
let punycodeURL = "https://xn--e1afmkfd.com/";
SpecialPowers.clipboardCopyString(unicodeURL);
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "about:home" },
async () => {
let { result } = await searchEmptyStringAndGetFirstRow();
Assert.equal(
result.providerName,
UrlbarProviderClipboard.name,
"The first result is a clipboard valid url suggestion."
);
Assert.equal(
result.payload.url,
punycodeURL,
"The Clipboard suggestion URL should not be decoded."
);
Assert.equal(
result.payload.fallbackTitle,
unicodeURL,
"The Clipboard suggestion fallback title should be decoded."
);
}
);
});
// Verifies that a valid URL copied to the clipboard results in the
// display of a corresponding suggestion in the URL bar as the first
// suggestion with accurate URL and icon. Also ensures that engaging
// with a clipboard suggestion leads to navigation to the copied URL
// and subsequent absence of the suggestion upon refocusing the URL bar.
add_task(async function testUserEngagementWithClipboardSuggestion() {
const validURL = "https://example.com/";
SpecialPowers.clipboardCopyString(validURL);
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "about:home" },
async browser => {
let { result } = await searchEmptyStringAndGetFirstRow();
let onLoad = BrowserTestUtils.browserLoaded(browser, false);
Assert.equal(
result.providerName,
UrlbarProviderClipboard.name,
"The first result is a clipboard valid url suggestion."
);
Assert.equal(
result.payload.url,
validURL,
"The Clipboard suggestion URL and the valid URL should match."
);
Assert.equal(
result.icon,
"Clipboard suggestion icon"
);
await checkClipboardSuggestionAbsent(1);
// Focus and select the clipbaord result.
EventUtils.synthesizeKey("KEY_ArrowDown");
EventUtils.synthesizeKey("KEY_Enter");
await onLoad;
Assert.equal(
gBrowser.selectedBrowser.currentURI.spec,
validURL,
"Navigated to the validURL webpage after selecting the clipboard result."
);
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "",
});
await checkClipboardSuggestionAbsent(0);
}
);
await PlacesUtils.history.clear();
});
// This test confirms that dismissing the result from the result menu
// button after copying a valid URL dismisses the clipboard suggestion,
// and the suggestion does not reappear upon refocusing the URL bar.
add_task(async function testDismissClipboardSuggestion() {
SpecialPowers.clipboardCopyString("https://example.com/2");
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "about:home" },
async () => {
const resultIndex = 0;
const command = "dismiss";
let row = await searchEmptyStringAndGetFirstRow();
Assert.equal(
row.result.providerName,
UrlbarProviderClipboard.name,
"Clipboard suggestion should be present"
);
await checkClipboardSuggestionAbsent(1);
await UrlbarTestUtils.openResultMenuAndClickItem(window, command, {
resultIndex,
});
Assert.ok(
gURLBar.view.isOpen,
"The view should remain open after clicking the command"
);
Assert.ok(
!row.hasAttribute("feedback-acknowledgement"),
"Row should not have feedback acknowledgement after clicking command"
);
await UrlbarTestUtils.promisePopupClose(window, () => {
gURLBar.blur();
});
// Do the same search again. The suggestion should not appear.
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "",
});
await checkClipboardSuggestionAbsent(0);
}
);
});
// The test validates that the clipboard suggestion is displayed for
// the first two URL bar openings after copying a valid URL, but is
// suppressed on the third opening of URL bar.
add_task(async function testClipboardSuggestionLimit() {
SpecialPowers.clipboardCopyString("https://example.com/3");
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "about:home" },
async () => {
for (let i = 0; i < CLIPBOARD_IMPRESSION_LIMIT; i++) {
const { result } = await searchEmptyStringAndGetFirstRow();
Assert.equal(
result.providerName,
UrlbarProviderClipboard.name,
"Clipboard suggestion should be present as the first suggestion."
);
await checkClipboardSuggestionAbsent(1);
await UrlbarTestUtils.promisePopupClose(window, () => {
gURLBar.blur();
});
}
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "",
});
await checkClipboardSuggestionAbsent(0);
}
);
});
// This test ensures that copying non-URL content to the clipboard
// results in the absence of a clipboard suggestion when opening
// the URL bar.
add_task(async function testNonUrlClipboardSuggestion() {
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "about:home" },
async () => {
const malformedURLs = [
"plain text",
// Testing http because it is considered as a valid URL.
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
"http://",
"https://example.com some text",
"https://example.com/ some text",
];
for (let i = 0; i < malformedURLs.length; i++) {
SpecialPowers.clipboardCopyString(malformedURLs[i]);
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "",
});
Assert.ok(gURLBar.view.isOpen, "UrlbarView should be open.");
await checkClipboardSuggestionAbsent(0);
await UrlbarTestUtils.promisePopupClose(window, () => {
gURLBar.blur();
});
}
}
);
});
// This test verifies that clipboard suggestions are displayed
// based on the toggled state of the 'clipboard.featureGate' preference.
add_task(async function testClipboardFeatureGateToggle() {
await SpecialPowers.pushPrefEnv({
set: [
["browser.urlbar.clipboard.featureGate", false],
["browser.urlbar.suggest.clipboard", true],
],
});
SpecialPowers.clipboardCopyString("https://example.com/4");
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "about:home" },
async () => {
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "",
});
await checkClipboardSuggestionAbsent(0);
await UrlbarTestUtils.promisePopupClose(window, () => {
gURLBar.blur();
});
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.clipboard.featureGate", true]],
});
const { result } = await searchEmptyStringAndGetFirstRow();
Assert.equal(
result.providerName,
UrlbarProviderClipboard.name,
"Clipboard suggestion should be present as the first suggestion."
);
await checkClipboardSuggestionAbsent(1);
}
);
});
// This test confirms that clipboard suggestions are presented based on
// the state of the 'suggest.clipboard' preference toggle.
add_task(async function testClipboardSuggestToggle() {
await SpecialPowers.pushPrefEnv({
set: [
["browser.urlbar.clipboard.featureGate", true],
["browser.urlbar.suggest.clipboard", false],
],
});
SpecialPowers.clipboardCopyString("https://example.com/5");
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "about:home" },
async () => {
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "",
});
await checkClipboardSuggestionAbsent(0);
await UrlbarTestUtils.promisePopupClose(window, () => {
gURLBar.blur();
});
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.suggest.clipboard", true]],
});
const { result } = await searchEmptyStringAndGetFirstRow();
Assert.equal(
result.providerName,
UrlbarProviderClipboard.name,
"Clipboard suggestion should be present as the first suggestion."
);
await checkClipboardSuggestionAbsent(1);
}
);
});
add_task(async function testScalarAndStopWatchTelemetry() {
SpecialPowers.clipboardCopyString("https://example.com/6");
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "about:home" },
async () => {
Services.telemetry.clearScalars();
let histogram = Services.telemetry.getHistogramById(
"FX_URLBAR_PROVIDER_CLIPBOARD_READ_TIME_MS"
);
histogram.clear();
Assert.equal(
Object.values(histogram.snapshot().values).length,
0,
"histogram is empty before search"
);
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "",
waitForFocus,
fireInputEvent: true,
});
await UrlbarTestUtils.promisePopupClose(window, () => {
EventUtils.synthesizeKey("KEY_ArrowDown");
EventUtils.synthesizeKey("KEY_Enter");
});
const scalars = TelemetryTestUtils.getProcessScalars(
"parent",
true,
true
);
TelemetryTestUtils.assertKeyedScalar(
scalars,
`urlbar.picked.clipboard`,
0,
1
);
Assert.greater(
Object.values(histogram.snapshot().values).length,
0,
"histogram updated after search"
);
}
);
});
add_task(async function emptySearch_withClipboardEntry() {
SpecialPowers.clipboardCopyString("https://example.com/1");
const MAX_RESULTS = 3;
let expectedHistoryResults = [];
for (let i = 0; i < MAX_RESULTS; i++) {
await PlacesTestUtils.addVisits([`http://mochi.test/${i}`]);
expectedHistoryResults.push(`http://mochi.test/${i}`);
}
await BrowserTestUtils.withNewTab("about:robots", async function () {
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "",
});
await UrlbarTestUtils.enterSearchMode(window, {
source: UrlbarUtils.RESULT_SOURCE.HISTORY,
});
let urls = [];
for (let i = 0; i < UrlbarTestUtils.getResultCount(window); i++) {
let url = (await UrlbarTestUtils.getDetailsOfResultAt(window, i)).url;
urls.push(url);
}
urls.reverse();
Assert.deepEqual(expectedHistoryResults, urls);
await UrlbarTestUtils.exitSearchMode(window, { clickClose: true });
await UrlbarTestUtils.promisePopupClose(window);
});
await PlacesUtils.history.clear();
});