diff options
Diffstat (limited to 'toolkit/components/passwordmgr/test/browser/browser_doorhanger_submit_telemetry.js')
-rw-r--r-- | toolkit/components/passwordmgr/test/browser/browser_doorhanger_submit_telemetry.js | 387 |
1 files changed, 387 insertions, 0 deletions
diff --git a/toolkit/components/passwordmgr/test/browser/browser_doorhanger_submit_telemetry.js b/toolkit/components/passwordmgr/test/browser/browser_doorhanger_submit_telemetry.js new file mode 100644 index 0000000000..97353007ac --- /dev/null +++ b/toolkit/components/passwordmgr/test/browser/browser_doorhanger_submit_telemetry.js @@ -0,0 +1,387 @@ +/** + * Test that doorhanger submit telemetry is sent when the user saves/updates. + */ + +add_setup(function () { + // This test used to rely on the initial timer of + // TestUtils.waitForCondition. See bug 1695395. + // The test is perma-fail on Linux asan opt without this. + let originalWaitForCondition = TestUtils.waitForCondition; + TestUtils.waitForCondition = async function ( + condition, + msg, + interval = 100, + maxTries = 50 + ) { + // eslint-disable-next-line mozilla/no-arbitrary-setTimeout + await new Promise(resolve => setTimeout(resolve, 100)); + + return originalWaitForCondition(condition, msg, interval, maxTries); + }; + registerCleanupFunction(function () { + TestUtils.waitForCondition = originalWaitForCondition; + }); +}); + +const PAGE_USERNAME_SELECTOR = "#form-basic-username"; +const PAGE_PASSWORD_SELECTOR = "#form-basic-password"; + +const TEST_CASES = [ + { + description: + "Saving a new login from page values without modification sends a 'no modification' event", + savedLogin: undefined, + userActions: [ + { + pageChanges: { + username: "pageUn", + password: "pagePw", + }, + doorhangerChanges: [], + }, + ], + expectedEvents: [ + { + type: "save", + ping: { + did_edit_un: "false", + did_select_un: "false", + did_edit_pw: "false", + did_select_pw: "false", + }, + }, + ], + }, + ///////////////// + { + description: "Saving two logins sends two events", + userActions: [ + { + pageChanges: { password: "pagePw" }, + doorhangerChanges: [ + { + typedUsername: "doorhangerUn", + }, + ], + }, + { + pageChanges: { password: "pagePw2" }, + doorhangerChanges: [ + { + typedPassword: "doorhangerPw", + }, + ], + }, + ], + expectedEvents: [ + { + type: "save", + ping: { + did_edit_un: "true", + did_select_un: "false", + did_edit_pw: "false", + did_select_pw: "false", + }, + }, + { + type: "update", + ping: { + did_edit_un: "false", + did_select_un: "false", + did_edit_pw: "true", + did_select_pw: "false", + }, + }, + ], + }, + ///////////////// + { + description: "Updating a doorhanger password sends a 'pw updated' event", + savedLogin: { + username: "savedUn", + password: "savedPw", + }, + userActions: [ + { + pageChanges: { password: "pagePw" }, + doorhangerChanges: [ + { + typedPassword: "doorhangerPw", + }, + ], + }, + ], + expectedEvents: [ + { + type: "update", + ping: { + did_edit_un: "false", + did_select_un: "false", + did_edit_pw: "true", + did_select_pw: "false", + }, + }, + ], + }, + ///////////////// + { + description: + "Saving a new username with an existing password sends a 'un updated' event", + savedLogin: { + username: "savedUn", + password: "savedPw", + }, + userActions: [ + { + pageChanges: { password: "pagePw" }, + doorhangerChanges: [ + { + typedUsername: "doorhangerUn", + }, + ], + }, + ], + expectedEvents: [ + { + type: "update", + ping: { + did_edit_un: "true", + did_select_un: "false", + did_edit_pw: "false", + did_select_pw: "false", + }, + }, + ], + }, + /////////////// + { + description: "selecting a saved username sends a 'not edited' event", + savedLogin: { + username: "savedUn", + password: "savedPw", + }, + userActions: [ + { + pageChanges: { password: "pagePw" }, + doorhangerChanges: [ + { + selectUsername: "savedUn", + }, + ], + }, + ], + expectedEvents: [ + { + type: "update", + ping: { + did_edit_un: "false", + did_select_un: "true", + did_edit_pw: "false", + did_select_pw: "false", + }, + }, + ], + }, + ///////////////// + { + description: + "typing a new username then selecting a saved username sends a 'not edited' event", + savedLogin: { + username: "savedUn", + password: "savedPw", + }, + userActions: [ + { + pageChanges: { password: "pagePw" }, + doorhangerChanges: [ + { + typedUsername: "doorhangerTypedUn", + }, + { + selectUsername: "savedUn", + }, + ], + }, + ], + expectedEvents: [ + { + type: "update", + ping: { + did_edit_un: "false", + did_select_un: "true", + did_edit_pw: "false", + did_select_pw: "false", + }, + }, + ], + }, + ///////////////// + { + description: + "selecting a saved username then typing a new username sends an 'edited' event", + savedLogin: { + username: "savedUn", + password: "savedPw", + }, + userActions: [ + { + pageChanges: { password: "pagePw" }, + doorhangerChanges: [ + { + selectUsername: "savedUn", + }, + { + typedUsername: "doorhangerTypedUn", + }, + ], + }, + ], + expectedEvents: [ + { + type: "update", + ping: { + did_edit_un: "true", + did_select_un: "false", + did_edit_pw: "false", + did_select_pw: "false", + }, + }, + ], + }, + ///////////////// +]; + +for (let testData of TEST_CASES) { + let tmp = { + async [testData.description]() { + info("testing with: " + JSON.stringify(testData)); + await test_submit_telemetry(testData); + }, + }; + add_task(tmp[testData.description]); +} + +function _validateTestCase(tc) { + for (let event of tc.expectedEvents) { + Assert.ok( + !(event.ping.did_edit_un && event.ping.did_select_un), + "'did_edit_un' and 'did_select_un' can never be true at the same time" + ); + Assert.ok( + !(event.ping.did_edit_pw && event.ping.did_select_pw), + "'did_edit_pw' and 'did_select_pw' can never be true at the same time" + ); + } +} + +async function test_submit_telemetry(tc) { + if (tc.savedLogin) { + await Services.logins.addLoginAsync( + LoginTestUtils.testData.formLogin({ + origin: "https://example.com", + formActionOrigin: "https://example.com", + username: tc.savedLogin.username, + password: tc.savedLogin.password, + }) + ); + } + + let notif; + for (let userAction of tc.userActions) { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: + "https://example.com/browser/toolkit/components/" + + "passwordmgr/test/browser/form_basic.html", + }, + async function (browser) { + await SimpleTest.promiseFocus(browser.ownerGlobal); + + if (userAction.pageChanges) { + info( + `Update form with changes: ${JSON.stringify( + userAction.pageChanges + )}` + ); + let changeTo = {}; + if (userAction.pageChanges.username) { + changeTo[PAGE_USERNAME_SELECTOR] = userAction.pageChanges.username; + } + if (userAction.pageChanges.password) { + changeTo[PAGE_PASSWORD_SELECTOR] = userAction.pageChanges.password; + } + + await changeContentFormValues(browser, changeTo); + } + + info("Submitting form"); + let formSubmittedPromise = listenForTestNotification("ShowDoorhanger"); + await SpecialPowers.spawn(browser, [], async function () { + let doc = this.content.document; + doc.getElementById("form-basic").submit(); + }); + await formSubmittedPromise; + + let saveDoorhanger = waitForDoorhanger(browser, "password-save"); + let updateDoorhanger = waitForDoorhanger(browser, "password-change"); + notif = await Promise.race([saveDoorhanger, updateDoorhanger]); + + if (PopupNotifications.panel.state !== "open") { + await BrowserTestUtils.waitForEvent( + PopupNotifications.panel, + "popupshown" + ); + } + + if (userAction.doorhangerChanges) { + for (let doorhangerChange of userAction.doorhangerChanges) { + if ( + doorhangerChange.typedUsername || + doorhangerChange.typedPassword + ) { + await updateDoorhangerInputValues({ + username: doorhangerChange.typedUsername, + password: doorhangerChange.typedPassword, + }); + } + + if (doorhangerChange.selectUsername) { + await selectDoorhangerUsername(doorhangerChange.selectUsername); + } + if (doorhangerChange.selectPassword) { + await selectDoorhangerPassword(doorhangerChange.selectPassword); + } + } + } + + info("Waiting for doorhanger"); + await clickDoorhangerButton(notif, REMEMBER_BUTTON); + } + ); + } + + let expectedEvents = tc.expectedEvents.map(expectedEvent => [ + "pwmgr", + "doorhanger_submitted", + expectedEvent.type, + null, + expectedEvent.ping, + ]); + + await LoginTestUtils.telemetry.waitForEventCount( + expectedEvents.length, + "parent", + "pwmgr", + "doorhanger_submitted" + ); + TelemetryTestUtils.assertEvents( + expectedEvents, + { category: "pwmgr", method: "doorhanger_submitted" }, + { clear: true } + ); + + // Clean up the database before the next test case is executed. + await cleanupDoorhanger(notif); + Services.logins.removeAllUserFacingLogins(); +} |