mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
Bug 1653083 - Add doorhanger telemetry for Credit Card A/B testing. r=abr
Differential Revision: https://phabricator.services.mozilla.com/D83723
This commit is contained in:
parent
ab461dd2a4
commit
48beff740e
@ -706,12 +706,29 @@ class FormAutofillParent extends JSWindowActorParent {
|
||||
creditCard.record["cc-number-decrypted"];
|
||||
let name = creditCard.record["cc-name"];
|
||||
const description = await CreditCard.getLabel({ name, number });
|
||||
|
||||
const telemetryObject = creditCard.guid
|
||||
? "update_doorhanger"
|
||||
: "capture_doorhanger";
|
||||
Services.telemetry.recordEvent(
|
||||
"creditcard",
|
||||
"show",
|
||||
telemetryObject,
|
||||
creditCard.flowId
|
||||
);
|
||||
|
||||
const state = await FormAutofillDoorhanger.show(
|
||||
browser,
|
||||
creditCard.guid ? "updateCreditCard" : "addCreditCard",
|
||||
description
|
||||
);
|
||||
if (state == "cancel") {
|
||||
Services.telemetry.recordEvent(
|
||||
"creditcard",
|
||||
"cancel",
|
||||
telemetryObject,
|
||||
creditCard.flowId
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -720,6 +737,12 @@ class FormAutofillParent extends JSWindowActorParent {
|
||||
"extensions.formautofill.creditCards.enabled",
|
||||
false
|
||||
);
|
||||
Services.telemetry.recordEvent(
|
||||
"creditcard",
|
||||
"disable",
|
||||
telemetryObject,
|
||||
creditCard.flowId
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -731,6 +754,12 @@ class FormAutofillParent extends JSWindowActorParent {
|
||||
let changedGUIDs = [];
|
||||
if (creditCard.guid) {
|
||||
if (state == "update") {
|
||||
Services.telemetry.recordEvent(
|
||||
"creditcard",
|
||||
"update",
|
||||
telemetryObject,
|
||||
creditCard.flowId
|
||||
);
|
||||
await gFormAutofillStorage.creditCards.update(
|
||||
creditCard.guid,
|
||||
creditCard.record,
|
||||
@ -738,6 +767,12 @@ class FormAutofillParent extends JSWindowActorParent {
|
||||
);
|
||||
changedGUIDs.push(creditCard.guid);
|
||||
} else if ("create") {
|
||||
Services.telemetry.recordEvent(
|
||||
"creditcard",
|
||||
"save",
|
||||
telemetryObject,
|
||||
creditCard.flowId
|
||||
);
|
||||
changedGUIDs.push(
|
||||
await gFormAutofillStorage.creditCards.add(creditCard.record)
|
||||
);
|
||||
@ -749,6 +784,12 @@ class FormAutofillParent extends JSWindowActorParent {
|
||||
))
|
||||
);
|
||||
if (!changedGUIDs.length) {
|
||||
Services.telemetry.recordEvent(
|
||||
"creditcard",
|
||||
"save",
|
||||
telemetryObject,
|
||||
creditCard.flowId
|
||||
);
|
||||
changedGUIDs.push(
|
||||
await gFormAutofillStorage.creditCards.add(creditCard.record)
|
||||
);
|
||||
|
@ -5,12 +5,12 @@ const { TelemetryTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/TelemetryTestUtils.jsm"
|
||||
);
|
||||
|
||||
async function assertTelemetry(expected_content = [], expected_parent = []) {
|
||||
async function assertTelemetry(expected_content, expected_parent) {
|
||||
let snapshots;
|
||||
|
||||
info(
|
||||
`Waiting for ${expected_content.length} content events and ` +
|
||||
`${expected_parent.length} parent events`
|
||||
`Waiting for ${expected_content?.length ?? 0} content events and ` +
|
||||
`${expected_parent?.length ?? 0} parent events`
|
||||
);
|
||||
|
||||
await TestUtils.waitForCondition(
|
||||
@ -20,8 +20,8 @@ async function assertTelemetry(expected_content = [], expected_parent = []) {
|
||||
false
|
||||
);
|
||||
return (
|
||||
(snapshots.parent?.length ?? 0) >= expected_parent.length &&
|
||||
(snapshots.content?.length ?? 0) >= expected_content.length
|
||||
(snapshots.parent?.length ?? 0) >= (expected_parent?.length ?? 0) &&
|
||||
(snapshots.content?.length ?? 0) >= (expected_content?.length ?? 0)
|
||||
);
|
||||
},
|
||||
"Wait for telemetry to be collected",
|
||||
@ -31,12 +31,12 @@ async function assertTelemetry(expected_content = [], expected_parent = []) {
|
||||
|
||||
info(JSON.stringify(snapshots, null, 2));
|
||||
|
||||
if (expected_content.length) {
|
||||
if (expected_content !== undefined) {
|
||||
expected_content = expected_content.map(([category, method, object]) => {
|
||||
return { category, method, object };
|
||||
});
|
||||
|
||||
let clear = !expected_parent.length;
|
||||
let clear = expected_parent === undefined;
|
||||
|
||||
TelemetryTestUtils.assertEvents(
|
||||
expected_content,
|
||||
@ -47,7 +47,7 @@ async function assertTelemetry(expected_content = [], expected_parent = []) {
|
||||
);
|
||||
}
|
||||
|
||||
if (expected_parent.length) {
|
||||
if (expected_parent !== undefined) {
|
||||
expected_parent = expected_parent.map(([category, method, object]) => {
|
||||
return { category, method, object };
|
||||
});
|
||||
@ -87,55 +87,216 @@ add_task(async function test_popup_opened() {
|
||||
]);
|
||||
});
|
||||
|
||||
add_task(async function test_submit_creditCard_saved() {
|
||||
add_task(async function test_submit_creditCard_new() {
|
||||
async function test_per_command(command, idx, expectChanged) {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [[CREDITCARDS_USED_STATUS_PREF, 0]],
|
||||
});
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: CREDITCARD_FORM_URL },
|
||||
async function(browser) {
|
||||
let promiseShown = BrowserTestUtils.waitForEvent(
|
||||
PopupNotifications.panel,
|
||||
"popupshown"
|
||||
);
|
||||
let onChanged = TestUtils.topicObserved("formautofill-storage-changed");
|
||||
|
||||
await SpecialPowers.spawn(browser, [], async function() {
|
||||
let form = content.document.getElementById("form");
|
||||
let name = form.querySelector("#cc-name");
|
||||
|
||||
name.focus();
|
||||
name.setUserInput("User 1");
|
||||
|
||||
form.querySelector("#cc-number").setUserInput("5038146897157463");
|
||||
form.querySelector("#cc-exp-month").setUserInput("12");
|
||||
form.querySelector("#cc-exp-year").setUserInput("2017");
|
||||
form.querySelector("#cc-type").value = "mastercard";
|
||||
|
||||
// Wait 1000ms before submission to make sure the input value applied
|
||||
await new Promise(resolve => content.setTimeout(resolve, 1000));
|
||||
form.querySelector("input[type=submit]").click();
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await clickDoorhangerButton(command, idx);
|
||||
if (expectChanged) {
|
||||
await onChanged;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
SpecialPowers.clearUserPref(CREDITCARDS_USED_STATUS_PREF);
|
||||
SpecialPowers.clearUserPref(ENABLED_AUTOFILL_CREDITCARDS_PREF);
|
||||
await removeAllRecords();
|
||||
}
|
||||
|
||||
Services.telemetry.clearEvents();
|
||||
Services.telemetry.setEventRecordingEnabled("creditcard", true);
|
||||
|
||||
let expected_content = [
|
||||
["creditcard", "detected", "cc_form"],
|
||||
["creditcard", "submitted", "cc_form"],
|
||||
];
|
||||
await test_per_command(MAIN_BUTTON, undefined, true);
|
||||
await assertTelemetry(expected_content, [
|
||||
["creditcard", "show", "capture_doorhanger"],
|
||||
["creditcard", "save", "capture_doorhanger"],
|
||||
]);
|
||||
|
||||
await test_per_command(SECONDARY_BUTTON, undefined, false);
|
||||
await assertTelemetry(expected_content, [
|
||||
["creditcard", "show", "capture_doorhanger"],
|
||||
["creditcard", "cancel", "capture_doorhanger"],
|
||||
]);
|
||||
|
||||
await test_per_command(MENU_BUTTON, 0, false);
|
||||
await assertTelemetry(expected_content, [
|
||||
["creditcard", "show", "capture_doorhanger"],
|
||||
["creditcard", "disable", "capture_doorhanger"],
|
||||
]);
|
||||
});
|
||||
|
||||
add_task(async function test_submit_creditCard_autofill() {
|
||||
if (!OSKeyStoreTestUtils.canTestOSKeyStoreLogin()) {
|
||||
todo(
|
||||
OSKeyStoreTestUtils.canTestOSKeyStoreLogin(),
|
||||
"Cannot test OS key store login on official builds."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
Services.telemetry.clearEvents();
|
||||
Services.telemetry.setEventRecordingEnabled("creditcard", true);
|
||||
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [[CREDITCARDS_USED_STATUS_PREF, 0]],
|
||||
});
|
||||
await saveCreditCard(TEST_CREDIT_CARD_1);
|
||||
let creditCards = await getCreditCards();
|
||||
is(creditCards.length, 1, "1 credit card in storage");
|
||||
|
||||
let osKeyStoreLoginShown = OSKeyStoreTestUtils.waitForOSKeyStoreLogin(true);
|
||||
let onUsed = TestUtils.topicObserved(
|
||||
"formautofill-storage-changed",
|
||||
(subject, data) => data == "notifyUsed"
|
||||
);
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: CREDITCARD_FORM_URL },
|
||||
async function(browser) {
|
||||
let promiseShown = BrowserTestUtils.waitForEvent(
|
||||
PopupNotifications.panel,
|
||||
"popupshown"
|
||||
);
|
||||
let onChanged = TestUtils.topicObserved("formautofill-storage-changed");
|
||||
|
||||
await openPopupOn(browser, "form #cc-name");
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, browser);
|
||||
await osKeyStoreLoginShown;
|
||||
await SpecialPowers.spawn(browser, [], async function() {
|
||||
await ContentTaskUtils.waitForCondition(() => {
|
||||
let form = content.document.getElementById("form");
|
||||
let name = form.querySelector("#cc-name");
|
||||
return name.value == "John Doe";
|
||||
}, "Credit card detail never fills");
|
||||
let form = content.document.getElementById("form");
|
||||
let name = form.querySelector("#cc-name");
|
||||
|
||||
name.focus();
|
||||
name.setUserInput("User 1");
|
||||
|
||||
form.querySelector("#cc-number").setUserInput("5038146897157463");
|
||||
form.querySelector("#cc-exp-month").setUserInput("12");
|
||||
form.querySelector("#cc-exp-year").setUserInput("2017");
|
||||
form.querySelector("#cc-type").value = "mastercard";
|
||||
|
||||
// Wait 1000ms before submission to make sure the input value applied
|
||||
await new Promise(resolve => content.setTimeout(resolve, 1000));
|
||||
form.querySelector("input[type=submit]").click();
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await clickDoorhangerButton(MAIN_BUTTON);
|
||||
await onChanged;
|
||||
await sleep(1000);
|
||||
is(PopupNotifications.panel.state, "closed", "Doorhanger is hidden");
|
||||
}
|
||||
);
|
||||
await onUsed;
|
||||
|
||||
is(
|
||||
SpecialPowers.getIntPref(CREDITCARDS_USED_STATUS_PREF),
|
||||
2,
|
||||
"User has seen the doorhanger"
|
||||
);
|
||||
SpecialPowers.clearUserPref(CREDITCARDS_USED_STATUS_PREF);
|
||||
await removeAllRecords();
|
||||
|
||||
await assertTelemetry([
|
||||
await assertTelemetry(
|
||||
[
|
||||
["creditcard", "detected", "cc_form"],
|
||||
["creditcard", "popup_shown", "cc_form"],
|
||||
["creditcard", "filled", "cc_form"],
|
||||
["creditcard", "submitted", "cc_form"],
|
||||
],
|
||||
[]
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_submit_creditCard_update() {
|
||||
if (!OSKeyStoreTestUtils.canTestOSKeyStoreLogin()) {
|
||||
todo(
|
||||
OSKeyStoreTestUtils.canTestOSKeyStoreLogin(),
|
||||
"Cannot test OS key store login on official builds."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
async function test_per_command(command, idx, expectChanged) {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [[CREDITCARDS_USED_STATUS_PREF, 0]],
|
||||
});
|
||||
await saveCreditCard(TEST_CREDIT_CARD_1);
|
||||
let creditCards = await getCreditCards();
|
||||
is(creditCards.length, 1, "1 credit card in storage");
|
||||
|
||||
let osKeyStoreLoginShown = OSKeyStoreTestUtils.waitForOSKeyStoreLogin(true);
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: CREDITCARD_FORM_URL },
|
||||
async function(browser) {
|
||||
let promiseShown = BrowserTestUtils.waitForEvent(
|
||||
PopupNotifications.panel,
|
||||
"popupshown"
|
||||
);
|
||||
let onChanged = TestUtils.topicObserved("formautofill-storage-changed");
|
||||
|
||||
await openPopupOn(browser, "form #cc-name");
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, browser);
|
||||
await osKeyStoreLoginShown;
|
||||
await SpecialPowers.spawn(browser, [], async function() {
|
||||
await ContentTaskUtils.waitForCondition(() => {
|
||||
let form = content.document.getElementById("form");
|
||||
let name = form.querySelector("#cc-name");
|
||||
return name.value == "John Doe";
|
||||
}, "Credit card detail never fills");
|
||||
let form = content.document.getElementById("form");
|
||||
let year = form.querySelector("#cc-exp-year");
|
||||
year.setUserInput("2019");
|
||||
|
||||
// Wait 1000ms before submission to make sure the input value applied
|
||||
await new Promise(resolve => content.setTimeout(resolve, 1000));
|
||||
form.querySelector("input[type=submit]").click();
|
||||
});
|
||||
await promiseShown;
|
||||
await clickDoorhangerButton(command, idx);
|
||||
if (expectChanged) {
|
||||
await onChanged;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
SpecialPowers.clearUserPref(CREDITCARDS_USED_STATUS_PREF);
|
||||
await removeAllRecords();
|
||||
}
|
||||
Services.telemetry.clearEvents();
|
||||
Services.telemetry.setEventRecordingEnabled("creditcard", true);
|
||||
|
||||
let expected_content = [
|
||||
["creditcard", "detected", "cc_form"],
|
||||
["creditcard", "popup_shown", "cc_form"],
|
||||
["creditcard", "filled", "cc_form"],
|
||||
["creditcard", "filled_modified", "cc_form"],
|
||||
["creditcard", "submitted", "cc_form"],
|
||||
];
|
||||
|
||||
await test_per_command(MAIN_BUTTON, undefined, true);
|
||||
await assertTelemetry(expected_content, [
|
||||
["creditcard", "show", "update_doorhanger"],
|
||||
["creditcard", "update", "update_doorhanger"],
|
||||
]);
|
||||
|
||||
await test_per_command(SECONDARY_BUTTON, undefined, true);
|
||||
await assertTelemetry(expected_content, [
|
||||
["creditcard", "show", "update_doorhanger"],
|
||||
["creditcard", "save", "update_doorhanger"],
|
||||
]);
|
||||
});
|
||||
|
@ -350,6 +350,25 @@ form_autocomplete:
|
||||
release_channel_collection: opt-out
|
||||
|
||||
creditcard:
|
||||
doorhanger:
|
||||
description: >-
|
||||
User interactions for the browser credit card autofill doorhanger.
|
||||
objects:
|
||||
- "capture_doorhanger"
|
||||
- "update_doorhanger"
|
||||
methods:
|
||||
- "show"
|
||||
- "save"
|
||||
- "update"
|
||||
- "cancel"
|
||||
- "disable"
|
||||
bug_numbers: [1653073, 1653083]
|
||||
notification_emails: ["jmathies@mozilla.com", "chsiang@mozilla.com"]
|
||||
expiry_version: "93"
|
||||
products:
|
||||
- "firefox"
|
||||
record_in_processes: ["main"]
|
||||
release_channel_collection: opt-out
|
||||
cc_form:
|
||||
description: >-
|
||||
User interactions for credit card autofill forms
|
||||
|
Loading…
Reference in New Issue
Block a user