<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <title>Test behavior of unmasking in LMC._passwordEditedOrGenerated</title>
  <script src="/tests/SimpleTest/SimpleTest.js"></script>
  <script src="/tests/SimpleTest/EventUtils.js"></script>
  <script type="text/javascript" src="../../../satchel/test/satchel_common.js"></script>
  <script src="pwmgr_common.js"></script>
  <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content"></div>
<pre id="test"></pre>
<script>
const { LoginManagerChild } = SpecialPowers.ChromeUtils.import(
  "resource://gre/modules/LoginManagerChild.jsm"
);

function preventDefaultAndStopProgagation(event) {
  event.preventDefault();
  event.stopImmediatePropagation();
}

add_setup(async () => {
  await SpecialPowers.pushPrefEnv({"set": [
    ["signon.generation.available", true],
    ["signon.generation.enabled", true],
  ]});
  await setStoredLoginsAsync(
    [location.origin, "https://autofill", null, "user1", "pass1"],
    [location.origin, "https://autofill", null, "user2", "pass2"]
  );
});

add_task(async function prevent_default_and_stop_propagation() {
  const form = createLoginForm({
    action: "https://autofill"
  });
  await promiseFormsProcessedInSameProcess();
  form.pword.focus();

  form.pword.addEventListener("focus", preventDefaultAndStopProgagation);
  form.pword.addEventListener("focus", preventDefaultAndStopProgagation, true);
  form.pword.addEventListener("blur", preventDefaultAndStopProgagation);
  form.pword.addEventListener("blur", preventDefaultAndStopProgagation, true);

  SpecialPowers.wrap(form.pword).setUserInput("generatedpass");
  LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, true, "Before first fill");
  LoginManagerChild.forWindow(window)._passwordEditedOrGenerated(form.pword, { triggeredByFillingGenerated: true });
  LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, false, "After first fill");
  synthesizeKey("KEY_Tab"); // blur
  LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, true, "After blur");
  synthesizeKey("KEY_Tab", { shiftKey: true }); // focus again
  LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, false, "After shift-tab to focus again");
});

add_task(async function fields_masked_after_saved_login_fill() {
  const form = createLoginForm({
    action: "https://autofill"
  });
  await promiseFormsProcessedInSameProcess();
  form.pword.focus();

  SpecialPowers.wrap(form.pword).setUserInput("generatedpass");
  LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, true, "Before first fill");
  LoginManagerChild.forWindow(window)._passwordEditedOrGenerated(form.pword, { triggeredByFillingGenerated: true });
  LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, false, "After first fill");
  synthesizeKey("KEY_Tab", { shiftKey: true }); // blur pw, focus un
  LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, true, "After blur");

  info("Filling username matching saved login");
  sendString("user1");

  let processedPromise = promiseFormsProcessedInSameProcess();
  synthesizeKey("KEY_Tab"); // focus again and trigger a fill of the matching password
  await processedPromise;
  is(form.pword.value, "pass1", "Saved password was filled")
  LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, true, "After filling a saved login");
});

add_task(async function fields_masked_after_replacing_whole_value() {
  const form = createLoginForm({
    action: "https://autofill"
  });
  await promiseFormsProcessedInSameProcess();
  form.pword.focus();

  SpecialPowers.wrap(form.pword).setUserInput("generatedpass");
  LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, true, "Before first fill");
  LoginManagerChild.forWindow(window)._passwordEditedOrGenerated(form.pword, { triggeredByFillingGenerated: true });
  LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, false, "After first fill");
  synthesizeKey("KEY_Tab", { shiftKey: true }); // blur pw, focus un
  LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, true, "After blur");

  synthesizeKey("KEY_Tab"); // focus again and replace the whole password value
  info("Replacing password field value with arbitrary string");
  sendString("some_other_password");
  is(form.pword.value, "some_other_password", "Whole password replaced")
  LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, true, "Replaced password value");

  synthesizeKey("KEY_Tab"); // blur pw
  LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, true, "After blur");
  synthesizeKey("KEY_Tab", { shiftKey: true }); // focus pw again
  LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, true, "After focus again");
});

add_task(async function fields_unmasked_after_adding_character() {
  const form = createLoginForm({
    action: "https://autofill"
  });
  await promiseFormsProcessedInSameProcess();
  form.pword.focus();

  SpecialPowers.wrap(form.pword).setUserInput("generatedpass");
  LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, true, "Before first fill");
  LoginManagerChild.forWindow(window)._passwordEditedOrGenerated(form.pword, { triggeredByFillingGenerated: true });
  LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, false, "After first fill");
  synthesizeKey("KEY_Tab", { shiftKey: true }); // blur pw, focus un
  LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, true, "After blur");

  synthesizeKey("KEY_Tab"); // focus again
  synthesizeKey("KEY_ArrowRight"); // Remove the selection
  info("Adding a character to the end of the password");
  sendString("@");
  is(form.pword.value, "generatedpass@", "Character was added to the value")
  LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, false, "Added @");

  synthesizeKey("KEY_Tab"); // blur pw
  LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, true, "After blur after @");
  synthesizeKey("KEY_Tab", { shiftKey: true }); // focus pw again
  LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, false, "After focus after @");
});

add_task(async function type_not_password() {
  const form = createLoginForm({
    action: "https://autofill"
  });
  await promiseFormsProcessedInSameProcess();
  form.pword.focus();

  LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, true, "Before first fill");
  SpecialPowers.wrap(form.pword).setUserInput("generatedpass");
  LoginManagerChild.forWindow(window)._passwordEditedOrGenerated(form.pword, { triggeredByFillingGenerated: true });
  LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, false, "After first fill");

  // Simulate a website doing their own unmasking and re-masking
  form.pword.type = "text";
  await new Promise(resolve => SimpleTest.executeSoon(resolve));
  form.pword.type = "password";

  synthesizeKey("KEY_Tab"); // blur
  LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, true, "After blur");
  synthesizeKey("KEY_Tab", { shiftKey: true }); // focus again
  LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, false, "After shift-tab to focus again");
});
</script>
</body>
</html>
