Bug 1899757 - Allow targeting the trigger tab for feature callouts. r=hanna_a,omc-reviewers

Also add a global `browserIsSelected` context property for all triggers,
so you can entirely avoid showing a message if the triggering browser
was in the background. You can use the selector and the context property
together or separately.

Context targeting:
`browserIsSelected`

Background tab selector:
`#tabbrowser-tabs:not([overflow]):not([haspinnedtabs]) %triggerTab%`

Current tab selector:
`#tabbrowser-tabs:not([overflow]):not([haspinnedtabs]) %triggerTab%[visuallyselected]`

Child of tab selector:
`#tabbrowser-tabs:not([overflow]):not([haspinnedtabs]) %triggerTab% .tab-icon-image`

Differential Revision: https://phabricator.services.mozilla.com/D212494
This commit is contained in:
Shane Hughes
2024-06-16 23:05:10 +00:00
parent e20222c8c4
commit 039ba4cf7a
7 changed files with 108 additions and 8 deletions

View File

@@ -1120,3 +1120,36 @@ add_task(async function first_anchor_selected_is_invalid() {
await BrowserTestUtils.closeWindow(win);
sandbox.restore();
});
add_task(async function test_triggerTab_selector() {
const win = await BrowserTestUtils.openNewBrowserWindow();
const config = {
win,
location: "chrome",
context: "chrome",
browser: win.gBrowser.selectedBrowser,
theme: { preset: "chrome" },
};
const message = JSON.parse(JSON.stringify(testMessage.message));
message.content.screens[0].anchors[0].selector =
"#tabbrowser-tabs %triggerTab%[visuallyselected]";
const sandbox = sinon.createSandbox();
const doc = win.document;
const featureCallout = new FeatureCallout(config);
const getAnchorSpy = sandbox.spy(featureCallout, "_getAnchor");
featureCallout.showFeatureCallout(message);
await waitForCalloutScreen(doc, message.content.screens[0].id);
ok(
getAnchorSpy.alwaysReturned(
sandbox.match(message.content.screens[0].anchors[0])
),
"The first anchor is selected"
);
win.document.querySelector(calloutCTASelector).click();
await waitForCalloutRemoved(win.document);
await BrowserTestUtils.closeWindow(win);
sandbox.restore();
});

View File

@@ -50,6 +50,7 @@ describe("ASRouter", () => {
let FakeToolbarBadgeHub;
let FakeMomentsPageHub;
let ASRouterTargeting;
let gBrowser;
let screenImpressions;
function setMessageProviderPref(value) {
@@ -171,6 +172,14 @@ describe("ASRouter", () => {
userId: "adsf",
},
};
gBrowser = {
selectedBrowser: {
constructor: { name: "MozBrowser" },
get ownerGlobal() {
return { gBrowser };
},
},
};
ASRouterPreferences.specialConditions = {
someCondition: true,
@@ -236,7 +245,7 @@ describe("ASRouter", () => {
ASRouterTargeting,
ASRouterTriggerListeners,
QueryCache,
gBrowser: { selectedBrowser: {} },
gBrowser,
gURLBar: {},
isSeparateAboutWelcome: true,
AttributionCode: fakeAttributionCode,
@@ -1591,7 +1600,7 @@ describe("ASRouter", () => {
await Router.sendTriggerMessage({
tabId: 0,
browser: {},
browser: gBrowser.selectedBrowser,
id: "firstRun",
});
@@ -1601,7 +1610,7 @@ describe("ASRouter", () => {
{
id: "firstRun",
param: undefined,
context: undefined,
context: { browserIsSelected: true },
}
);
});

View File

@@ -70,7 +70,11 @@ describe("ASRTargeting docs", () => {
// "allow" includes targeting attributes that are not implemented by
// ASRTargetingAttributes. For example trigger context passed to the evaluation
// context in when a trigger runs or ASRouter state used in the evaluation.
const allow = ["messageImpressions", "screenImpressions"];
const allow = [
"messageImpressions",
"screenImpressions",
"browserIsSelected",
];
for (const targetingParam of DOCS_TARGETING_HEADINGS.filter(
doc => !allow.includes(doc)
)) {