Bug 1833658 - Add Telemetry for Recent Browsing r=fxview-reviewers,jsudiaman,sclements

Differential Revision: https://phabricator.services.mozilla.com/D187676
This commit is contained in:
Kelly Cochrane
2023-09-13 13:06:50 +00:00
parent 897e271a27
commit 439792e3b2
12 changed files with 426 additions and 116 deletions

View File

@@ -61,11 +61,11 @@ class CardContainer extends MozLitElement {
if (this.preserveCollapseState) {
Services.prefs.setBoolPref(this.openStatePref, this.isExpanded);
}
if (!this.isExpanded && this.shortPageName) {
// Record telemetry
// Record telemetry
if (this.shortPageName) {
Services.telemetry.recordEvent(
"firefoxview_next",
"card_collapsed",
this.isExpanded ? "card_expanded" : "card_collapsed",
"card_container",
null,
{
@@ -75,6 +75,15 @@ class CardContainer extends MozLitElement {
}
}
viewAllClicked() {
this.dispatchEvent(
new CustomEvent("card-container-view-all", {
bubbles: true,
composed: true,
})
);
}
render() {
return html`
<link
@@ -111,6 +120,7 @@ class CardContainer extends MozLitElement {
</summary>
<a
href="about:firefoxview-next#${this.shortPageName}"
@click=${this.viewAllClicked}
class="view-all-link"
data-l10n-id="firefoxview-view-all-link"
?hidden=${!this.showViewAll}

View File

@@ -22,7 +22,15 @@ function changePage(page) {
);
(currentCategoryButton || navigation.categoryButtons[0]).focus();
}
}
function recordTelemetry(source, eventTarget) {
let page = "recentbrowsing";
if (source === "category-navigation") {
page = eventTarget.parentNode.currentCategory;
} else if (source === "view-all") {
page = eventTarget.shortPageName;
}
// Record telemetry
Services.telemetry.recordEvent(
"firefoxview_next",
@@ -30,7 +38,8 @@ function changePage(page) {
"navigation",
null,
{
page: navigation.currentCategory,
page,
source,
}
);
}
@@ -44,6 +53,10 @@ window.addEventListener("DOMContentLoaded", async () => {
window.addEventListener("hashchange", onHashChange);
window.addEventListener("change-category", function (event) {
location.hash = event.target.getAttribute("name");
recordTelemetry("category-navigation", event.target);
});
window.addEventListener("card-container-view-all", function (event) {
recordTelemetry("view-all", event.originalTarget);
});
if (document.location.hash) {
changePage(document.location.hash.substring(1));

View File

@@ -105,6 +105,7 @@ class HistoryInView extends ViewPage {
migrationWizardDialog: "#migrationWizardDialog",
emptyState: "fxview-empty-state",
lists: { all: "fxview-tab-list" },
panelList: "panel-list",
};
static properties = {
@@ -210,6 +211,7 @@ class HistoryInView extends ViewPage {
deleteFromHistory(e) {
lazy.PlacesUtils.history.remove(this.triggerNode.url);
this.recordContextMenuTelemetry("delete-from-history", e);
}
async onChangeSortOption(e) {
@@ -268,7 +270,7 @@ class HistoryInView extends ViewPage {
panelListTemplate() {
return html`
<panel-list slot="menu">
<panel-list slot="menu" data-tab-type="history">
<panel-item
@click=${this.deleteFromHistory}
data-l10n-id="firefoxview-history-context-delete"

View File

@@ -257,18 +257,21 @@ class OpenTabsInViewCard extends ViewPage {
}
static queries = {
cardEl: "card-container",
panelList: "panel-list",
tabList: "fxview-tab-list",
};
closeTab() {
closeTab(e) {
const tab = this.triggerNode.tabElement;
const browserWindow = tab.ownerGlobal;
browserWindow.gBrowser.removeTab(tab, { animate: true });
this.recordContextMenuTelemetry("close-tab", e);
}
panelListTemplate() {
return html`
<panel-list slot="menu">
<panel-list slot="menu" data-tab-type="opentabs">
<panel-item
data-l10n-id="fxviewtabrow-close-tab"
data-l10n-attrs="accesskey"

View File

@@ -269,7 +269,7 @@ class SyncedTabsInView extends ViewPage {
panelListTemplate() {
return html`
<panel-list slot="menu">
<panel-list slot="menu" data-tab-type="syncedtabs">
<panel-item
@click=${this.openInNewWindow}
data-l10n-id="fxviewtabrow-open-in-window"

View File

@@ -2,6 +2,7 @@
support-files = ../head.js
[browser_firefoxview_next.js]
[browser_firefoxview_next_general_telemetry.js]
[browser_history_firefoxview_next.js]
[browser_recentlyclosed_firefoxview_next.js]
[browser_syncedtabs_errors_firefoxview_next.js]

View File

@@ -0,0 +1,334 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from ../head.js */
const FXVIEW_NEXT_ENABLED_PREF = "browser.tabs.firefox-view-next";
const CARD_COLLAPSED_EVENT = [
["firefoxview_next", "card_collapsed", "card_container", undefined],
];
const CARD_EXPANDED_EVENT = [
["firefoxview_next", "card_expanded", "card_container", undefined],
];
async function cardCollapsedTelemetry() {
await TestUtils.waitForCondition(
() => {
let events = Services.telemetry.snapshotEvents(
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
false
).parent;
return events && events.length >= 1;
},
"Waiting for card_collapsed firefoxview_next telemetry event.",
200,
100
);
TelemetryTestUtils.assertEvents(
CARD_COLLAPSED_EVENT,
{ category: "firefoxview_next" },
{ clear: true, process: "parent" }
);
}
async function cardExpandedTelemetry() {
await TestUtils.waitForCondition(
() => {
let events = Services.telemetry.snapshotEvents(
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
false
).parent;
return events && events.length >= 1;
},
"Waiting for card_expanded firefoxview_next telemetry event.",
200,
100
);
TelemetryTestUtils.assertEvents(
CARD_EXPANDED_EVENT,
{ category: "firefoxview_next" },
{ clear: true, process: "parent" }
);
}
async function navigationTelemetry(changePageEvent) {
await TestUtils.waitForCondition(
() => {
let events = Services.telemetry.snapshotEvents(
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
false
).parent;
return events && events.length >= 1;
},
"Waiting for change_page firefoxview_next telemetry event.",
200,
100
);
TelemetryTestUtils.assertEvents(
changePageEvent,
{ category: "firefoxview_next" },
{ clear: true, process: "parent" }
);
}
async function contextMenuTelemetry(contextMenuEvent) {
await TestUtils.waitForCondition(
() => {
let events = Services.telemetry.snapshotEvents(
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
false
).parent;
return events && events.length >= 1;
},
"Waiting for context_menu firefoxview_next telemetry event.",
200,
100
);
TelemetryTestUtils.assertEvents(
contextMenuEvent,
{ category: "firefoxview_next" },
{ clear: true, process: "parent" }
);
}
add_setup(async () => {
await SpecialPowers.pushPrefEnv({ set: [[FXVIEW_NEXT_ENABLED_PREF, true]] });
registerCleanupFunction(async () => {
await SpecialPowers.popPrefEnv();
clearHistory();
});
});
add_task(async function test_collapse_and_expand_card() {
await withFirefoxView({}, async browser => {
const { document } = browser.contentWindow;
is(document.location.href, "about:firefoxview-next");
// Test using Recently Closed card on Recent Browsing page
let recentlyClosedComponent = document.querySelector(
"view-recentlyclosed[slot=recentlyclosed]"
);
let cardContainer = recentlyClosedComponent.cardEl;
is(
cardContainer.isExpanded,
true,
"The card-container is expanded initially"
);
await clearAllParentTelemetryEvents();
// Click the summary to collapse the details disclosure
await EventUtils.synthesizeMouseAtCenter(
cardContainer.summaryEl,
{},
content
);
is(
cardContainer.detailsEl.hasAttribute("open"),
false,
"The card-container is collapsed"
);
await cardCollapsedTelemetry();
// Click the summary again to expand the details disclosure
await EventUtils.synthesizeMouseAtCenter(
cardContainer.summaryEl,
{},
content
);
is(
cardContainer.detailsEl.hasAttribute("open"),
true,
"The card-container is expanded"
);
await cardExpandedTelemetry();
});
});
add_task(async function test_change_page_telemetry() {
await withFirefoxView({}, async browser => {
const { document } = browser.contentWindow;
is(document.location.href, "about:firefoxview-next");
let changePageEvent = [
[
"firefoxview_next",
"change_page",
"navigation",
undefined,
{ page: "recentlyclosed", source: "category-navigation" },
],
];
await clearAllParentTelemetryEvents();
navigateToCategory(document, "recentlyclosed");
await navigationTelemetry(changePageEvent);
navigateToCategory(document, "recentbrowsing");
let openTabsComponent = document.querySelector(
"view-opentabs[slot=opentabs]"
);
let cardContainer =
openTabsComponent.shadowRoot.querySelector("view-opentabs-card").cardEl;
let viewAllLink = cardContainer.viewAllLink;
changePageEvent = [
[
"firefoxview_next",
"change_page",
"navigation",
undefined,
{ page: "opentabs", source: "view-all" },
],
];
await clearAllParentTelemetryEvents();
await EventUtils.synthesizeMouseAtCenter(viewAllLink, {}, content);
await navigationTelemetry(changePageEvent);
});
});
add_task(async function test_context_menu_telemetry() {
await PlacesUtils.history.insert({
url: URLs[0],
title: "Example Domain 1",
visits: [{ date: new Date() }],
});
await withFirefoxView({}, async browser => {
const { document } = browser.contentWindow;
is(document.location.href, "about:firefoxview-next");
// Test open tabs telemetry
let openTabsComponent = document.querySelector(
"view-opentabs[slot=opentabs]"
);
let tabList =
openTabsComponent.shadowRoot.querySelector("view-opentabs-card").tabList;
let firstItem = tabList.rowEls[0];
let panelList =
openTabsComponent.shadowRoot.querySelector(
"view-opentabs-card"
).panelList;
await EventUtils.synthesizeMouseAtCenter(firstItem.buttonEl, {}, content);
await BrowserTestUtils.waitForEvent(panelList, "shown");
await clearAllParentTelemetryEvents();
let copyLinkOption = panelList.children[1];
let contextMenuEvent = [
[
"firefoxview_next",
"context_menu",
"tabs",
undefined,
{ menu_action: "copy-link", data_type: "opentabs" },
],
];
await EventUtils.synthesizeMouseAtCenter(copyLinkOption, {}, content);
await contextMenuTelemetry(contextMenuEvent);
// Open new tab to test 'Close tab' menu option
window.openTrustedLinkIn("about:robots", "tab");
await switchToFxViewTab(browser.ownerGlobal);
firstItem = tabList.rowEls[0];
await EventUtils.synthesizeMouseAtCenter(firstItem.buttonEl, {}, content);
await BrowserTestUtils.waitForEvent(panelList, "shown");
await clearAllParentTelemetryEvents();
let closeTabOption = panelList.children[0];
contextMenuEvent = [
[
"firefoxview_next",
"context_menu",
"tabs",
undefined,
{ menu_action: "close-tab", data_type: "opentabs" },
],
];
await EventUtils.synthesizeMouseAtCenter(closeTabOption, {}, content);
await contextMenuTelemetry(contextMenuEvent);
// Test history context menu options
navigateToCategory(document, "history");
let historyComponent = document.querySelector("view-history");
await TestUtils.waitForCondition(() => historyComponent.fullyUpdated);
let firstTabList = historyComponent.lists[0];
firstItem = firstTabList.rowEls[0];
panelList = historyComponent.panelList;
await EventUtils.synthesizeMouseAtCenter(firstItem.buttonEl, {}, content);
await BrowserTestUtils.waitForEvent(panelList, "shown");
await clearAllParentTelemetryEvents();
let panelItems = Array.from(panelList.children).filter(
panelItem => panelItem.nodeName === "PANEL-ITEM"
);
let openInNewWindowOption = panelItems[1];
contextMenuEvent = [
[
"firefoxview_next",
"context_menu",
"tabs",
undefined,
{ menu_action: "open-in-new-window", data_type: "history" },
],
];
let newWindowPromise = BrowserTestUtils.waitForNewWindow({
url: URLs[0],
});
await EventUtils.synthesizeMouseAtCenter(
openInNewWindowOption,
{},
content
);
let win = await newWindowPromise;
await contextMenuTelemetry(contextMenuEvent);
await BrowserTestUtils.closeWindow(win);
await EventUtils.synthesizeMouseAtCenter(firstItem.buttonEl, {}, content);
await BrowserTestUtils.waitForEvent(panelList, "shown");
await clearAllParentTelemetryEvents();
let openInPrivateWindowOption = panelItems[2];
contextMenuEvent = [
[
"firefoxview_next",
"context_menu",
"tabs",
undefined,
{ menu_action: "open-in-private-window", data_type: "history" },
],
];
newWindowPromise = BrowserTestUtils.waitForNewWindow({
url: URLs[0],
});
await EventUtils.synthesizeMouseAtCenter(
openInPrivateWindowOption,
{},
content
);
win = await newWindowPromise;
await contextMenuTelemetry(contextMenuEvent);
ok(
PrivateBrowsingUtils.isWindowPrivate(win),
"Should have opened a private window."
);
await BrowserTestUtils.closeWindow(win);
await EventUtils.synthesizeMouseAtCenter(firstItem.buttonEl, {}, content);
await BrowserTestUtils.waitForEvent(panelList, "shown");
await clearAllParentTelemetryEvents();
let deleteFromHistoryOption = panelItems[0];
contextMenuEvent = [
[
"firefoxview_next",
"context_menu",
"tabs",
undefined,
{ menu_action: "delete-from-history", data_type: "history" },
],
];
await EventUtils.synthesizeMouseAtCenter(
deleteFromHistoryOption,
{},
content
);
await contextMenuTelemetry(contextMenuEvent);
// clean up extra tabs
while (gBrowser.tabs.length > 1) {
BrowserTestUtils.removeTab(gBrowser.tabs.at(-1));
}
});
});

View File

@@ -47,17 +47,6 @@ async function openFirefoxView(win) {
);
}
function navigateToHistory(document) {
// Navigate to Recently closed tabs page/view
const navigation = document.querySelector("fxview-category-navigation");
let historyNavButton = Array.from(navigation.categoryButtons).find(
categoryButton => {
return categoryButton.name === "history";
}
);
historyNavButton.buttonEl.click();
}
async function addHistoryItems(dateAdded) {
await PlacesUtils.history.insert({
url: URLs[0],
@@ -101,7 +90,7 @@ add_task(async function test_list_ordering() {
const { document } = browser.contentWindow;
is(document.location.href, "about:firefoxview-next");
navigateToHistory(document);
navigateToCategory(document, "history");
let historyComponent = document.querySelector("view-history");
historyComponent.profileAge = 8;
@@ -158,7 +147,7 @@ add_task(async function test_empty_states() {
const { document } = browser.contentWindow;
is(document.location.href, "about:firefoxview-next");
navigateToHistory(document);
navigateToCategory(document, "history");
let historyComponent = document.querySelector("view-history");
historyComponent.profileAge = 8;
@@ -246,7 +235,7 @@ add_task(async function test_observers_removed_when_view_is_hidden() {
);
await withFirefoxView({}, async browser => {
const { document } = browser.contentWindow;
navigateToHistory(document);
navigateToCategory(document, "history");
const historyComponent = document.querySelector("view-history");
historyComponent.profileAge = 8;
const visitList = await TestUtils.waitForCondition(() =>

View File

@@ -15,12 +15,6 @@ const RECENTLY_CLOSED_EVENT = [
const DISMISS_CLOSED_TAB_EVENT = [
["firefoxview_next", "dismiss_closed_tab", "tabs", undefined],
];
const CHANGE_PAGE_EVENT = [
["firefoxview_next", "change_page", "navigation", undefined],
];
const CARD_COLLAPSED_EVENT = [
["firefoxview_next", "card_collapsed", "card_container", undefined],
];
const initialTab = gBrowser.selectedTab;
function isElInViewport(element) {
@@ -248,48 +242,6 @@ async function recentlyClosedDismissTelemetry() {
);
}
async function navigationTelemetry() {
await TestUtils.waitForCondition(
() => {
let events = Services.telemetry.snapshotEvents(
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
false
).parent;
return events && events.length >= 1;
},
"Waiting for change_page firefoxview_next telemetry event.",
200,
100
);
TelemetryTestUtils.assertEvents(
CHANGE_PAGE_EVENT,
{ category: "firefoxview_next" },
{ clear: true, process: "parent" }
);
}
async function cardCollapsedTelemetry() {
await TestUtils.waitForCondition(
() => {
let events = Services.telemetry.snapshotEvents(
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
false
).parent;
return events && events.length >= 1;
},
"Waiting for card_collapsed firefoxview_next telemetry event.",
200,
100
);
TelemetryTestUtils.assertEvents(
CARD_COLLAPSED_EVENT,
{ category: "firefoxview_next" },
{ clear: true, process: "parent" }
);
}
add_setup(async () => {
await SpecialPowers.pushPrefEnv({ set: [[FXVIEW_NEXT_ENABLED_PREF, true]] });
registerCleanupFunction(async () => {
@@ -309,7 +261,6 @@ add_task(async function test_list_ordering() {
is(document.location.href, "about:firefoxview-next");
await clearAllParentTelemetryEvents();
navigateToCategory(document, "recentlyclosed");
await navigationTelemetry();
let [cardMainSlotNode, listItems] = await waitForRecentlyClosedTabsList(
document
);
@@ -329,49 +280,6 @@ add_task(async function test_list_ordering() {
await cleanup();
});
add_task(async function test_collapse_card() {
const { cleanup } = await prepareSingleClosedTab();
await withFirefoxView({}, async browser => {
const { document } = browser.contentWindow;
is(document.location.href, "about:firefoxview-next");
let recentlyClosedComponent = document.querySelector(
"view-recentlyclosed[slot=recentlyclosed]"
);
let cardContainer = recentlyClosedComponent.cardEl;
is(
cardContainer.isExpanded,
true,
"The card-container is expanded initially"
);
await clearAllParentTelemetryEvents();
// Click the summary to collapse the details disclosure
await EventUtils.synthesizeMouseAtCenter(
cardContainer.summaryEl,
{},
content
);
is(
cardContainer.detailsEl.hasAttribute("open"),
false,
"The card-container is collapsed"
);
await cardCollapsedTelemetry();
// Click the summary again to expand the details disclosure
await EventUtils.synthesizeMouseAtCenter(
cardContainer.summaryEl,
{},
content
);
is(
cardContainer.detailsEl.hasAttribute("open"),
true,
"The card-container is expanded"
);
});
await cleanup();
});
/**
* Asserts that an out-of-band update to recently-closed tabs results in the correct update to the tab list
*/

View File

@@ -35,7 +35,7 @@
}
function getRowsForCard(card) {
return card.shadowRoot.querySelector("fxview-tab-list").rowEls;
return card.tabList.rowEls;
}
add_setup(async function () {

View File

@@ -121,17 +121,33 @@ export class ViewPage extends MozLitElement {
null,
Ci.nsIClipboard.kGlobalClipboard
);
this.recordContextMenuTelemetry("copy-link", e);
}
openInNewWindow(e) {
this.getWindow().openTrustedLinkIn(this.triggerNode.url, "window", {
private: false,
});
this.recordContextMenuTelemetry("open-in-new-window", e);
}
openInNewPrivateWindow(e) {
this.getWindow().openTrustedLinkIn(this.triggerNode.url, "window", {
private: true,
});
this.recordContextMenuTelemetry("open-in-private-window", e);
}
recordContextMenuTelemetry(menuAction, event) {
Services.telemetry.recordEvent(
"firefoxview_next",
"context_menu",
"tabs",
null,
{
menu_action: menuAction,
data_type: event.target.panel.dataset.tabType,
}
);
}
}