Commit 8e029641 authored by jneuberger's avatar jneuberger
Browse files

Bug 1815449 - Adding telemetry for signup scenario detection using Fathom...

Bug 1815449 - Adding telemetry for signup scenario detection using Fathom r=credential-management-reviewers,dimi

Differential Revision: https://phabricator.services.mozilla.com/D175130
parent ede5a763
Loading
Loading
Loading
Loading
+12 −4
Original line number Diff line number Diff line
@@ -598,16 +598,24 @@ export class LoginFormState {
   */
  isProbablyASignUpForm(formElement) {
    if (!HTMLFormElement.isInstance(formElement)) {
      return 0;
      return false;
    }
    const threshold = lazy.LoginHelper.signupDetectionConfidenceThreshold;
    let score = this.#cachedSignUpFormScore.get(formElement);
    if (score) {
      return score >= threshold;
    }
    TelemetryStopwatch.start("PWMGR_SIGNUP_FORM_DETECTION_MS");
    try {
      const { rules, type } = lazy.SignUpFormRuleset;
      const results = rules.against(formElement);
      score = results.get(formElement).scoreFor(type);
      TelemetryStopwatch.finish("PWMGR_SIGNUP_FORM_DETECTION_MS");
    } finally {
      if (TelemetryStopwatch.running("PWMGR_SIGNUP_FORM_DETECTION_MS")) {
        TelemetryStopwatch.cancel("PWMGR_SIGNUP_FORM_DETECTION_MS");
      }
    }
    this.#cachedSignUpFormScore.set(formElement, score);
    return score > threshold;
  }
+46 −7
Original line number Diff line number Diff line
"use strict";

const SIGNUP_DETECTION_HISTOGRAM = "PWMGR_SIGNUP_FORM_DETECTION_MS";
const TEST_URL = `https://example.com${DIRECTORY_PATH}form_signup_detection.html`;

/**
 * Test cases for LoginFormState.isProbablyASignUpForm (uses SignUpFormRuleSet fathom model)
 * 1. An obvious sign up form that meets many of the positively weighted rules and leads to score > threshold (default signon.signupDetection.confidenceThreshold)
 * 2. An obvious non sign up form (such as a login form) that meets most of the negatively weighted rules
 * 3. Fathom not running on <input> HTML elements
 *
 * @param {Object} histogramData The histogram data to examine
 * @returns The amount of entries found in the histogram data
 */
function countEntries(histogramData) {
  info(typeof histogramData);
  return histogramData
    ? Object.values(histogramData.values).reduce((a, b) => a + b, 0)
    : null;
}

"use strict";
const TEST_URL = `https://example.com${DIRECTORY_PATH}form_signup_detection.html`;
/**
 * @param {String} id The histogram to examine
 * @param {Number} expected The expected amount of entries for a histogram
 */
async function countEntriesOfChildHistogram(id, expected) {
  let histogram;
  await TestUtils.waitForCondition(() => {
    let histograms = Services.telemetry.getSnapshotForHistograms("main", false)
      .content;

    histogram = histograms[id];

    return !!histogram && countEntries(histogram) == expected;
  }, `The histogram ${id} was expected to have ${expected} entries.`);
  Assert.equal(countEntries(histogram), expected);
}

add_setup(async () => {
  Services.telemetry.getSnapshotForHistograms("main", true);
});

add_task(async () => {
  info("Test case: Obvious non signup form is detected as non sign up form");
  await BrowserTestUtils.withNewTab(
    {
      gBrowser,
@@ -25,18 +52,30 @@ add_task(async () => {
        const docState = loginManagerChild.stateForDocument(doc);
        let isSignUpForm;

        info("Test case: Obvious signup form is detected as sign up form");
        const signUpForm = doc.getElementById("obvious-signup-form");
        isSignUpForm = docState.isProbablyASignUpForm(signUpForm);
        Assert.equal(isSignUpForm, true);

        info(
          "Test case: Obvious non signup form is detected as non sign up form"
        );
        const loginForm = doc.getElementById("obvious-login-form");
        isSignUpForm = docState.isProbablyASignUpForm(loginForm);
        Assert.equal(isSignUpForm, false);

        info(
          "Test case: An <input> HTML element is detected as non sign up form"
        );
        const inputField = doc.getElementById("obvious-signup-username");
        isSignUpForm = docState.isProbablyASignUpForm(inputField);
        Assert.equal(isSignUpForm, false);
      });
    }
  );

  info(
    "Test case: After running isProbablyASignUpForm against two <form> HTML elements, the histogram PWMGR_SIGNUP_FORM_DETECTION_MS should have two entries."
  );
  await countEntriesOfChildHistogram(SIGNUP_DETECTION_HISTOGRAM, 2);
});
+12 −0
Original line number Diff line number Diff line
@@ -14185,6 +14185,18 @@
    "alert_emails": ["passwords-dev@mozilla.org"],
    "releaseChannelCollection": "opt-out"
  },
  "PWMGR_SIGNUP_FORM_DETECTION_MS": {
    "record_in_processes": ["content"],
    "products": ["firefox"],
    "expires_in_version": "never",
    "kind": "exponential",
    "high":10000,
    "n_buckets": 70,
    "bug_numbers": [1815449],
    "alert_emails": ["passwords-dev@mozilla.org"],
    "releaseChannelCollection": "opt-out",
    "description": "Elapsed time to detect whether a <form> element is a signup form."
  },
  "PWMGR_USERNAME_PRESENT": {
    "record_in_processes": ["main"],
    "products": ["firefox", "fennec", "thunderbird"],