<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Test capturing of fields outside of a form</title>
  <script src="/tests/SimpleTest/SimpleTest.js"></script>
  <script src="pwmgr_common.js"></script>
  <link rel="stylesheet" href="/tests/SimpleTest/test.css" />
</head>
<body>
<script type="application/javascript">
const { LoginFormFactory } = SpecialPowers.ChromeUtils.import(
  "resource://gre/modules/LoginFormFactory.jsm"
);
const { LoginManagerChild } = SpecialPowers.ChromeUtils.import(
  "resource://gre/modules/LoginManagerChild.jsm"
);

function loadFrame() {
  return new Promise(resolve => {
    document.getElementById("loginFrame").addEventListener("load", (evt) => {
      if (evt.target.contentWindow.location.href.includes("blank.html")) {
        resolve();
      }
    });
  });
}

let loadPromise = new Promise(resolve => {
  document.addEventListener("DOMContentLoaded", () => {
    resolve(loadFrame());
  });
});

add_setup(async () => {
  info("Waiting for page and frame loads");
  await loadPromise;

  await loadRecipes({
    siteRecipes: [{
      hosts: ["mochi.test:8888"],
      usernameSelector: "input[name='recipeuname']",
      passwordSelector: "input[name='recipepword']",
    }],
  });
});

const DEFAULT_ORIGIN = "http://mochi.test:8888";
const TESTCASES = [
  {
    // Inputs
    document: `<input type=password value="">`,
    selectorValues: {
      "[type=password]": "pass1",
    },
    inputIndexForFormLike: 0,
    expectedFormsCount: 1,

    // Expected outputs similar to PasswordManager:onFormSubmit
    origin: DEFAULT_ORIGIN,
    formActionOrigin: DEFAULT_ORIGIN,
    usernameFieldValue: null,
    newPasswordFieldValue: "pass1",
    oldPasswordFieldValue: null,
  },
  {
    document: `<input id="u1" value="">
      <input type=password value="">`,
    selectorValues: {
      "#u1": "user1",
      "[type=password]": "pass1",
    },
    inputIndexForFormLike: 0,
    expectedFormsCount: 1,
    origin: DEFAULT_ORIGIN,
    formActionOrigin: DEFAULT_ORIGIN,
    usernameFieldValue: "user1",
    newPasswordFieldValue: "pass1",
    oldPasswordFieldValue: null,
  },
  {
    document: `<input id="u1" value="">
      <input type=password value="">`,
    selectorValues: {
      "#u1": "user1",
      "[type=password]": "pass1",
    },
    inputIndexForFormLike: 1,
    expectedFormsCount: 1,
    origin: DEFAULT_ORIGIN,
    formActionOrigin: DEFAULT_ORIGIN,
    usernameFieldValue: "user1",
    newPasswordFieldValue: "pass1",
    oldPasswordFieldValue: null,
  },
  {
    document: `<input id="u1" value="">
      <input id="p1" type=password value="">
      <input id="p2" type=password value="">`,
    selectorValues: {
      "#u1": "user1",
      "#p1": "pass1",
      "#p2": "pass2",
    },
    inputIndexForFormLike: 2,
    expectedFormsCount: 1,
    origin: DEFAULT_ORIGIN,
    formActionOrigin: DEFAULT_ORIGIN,
    usernameFieldValue: "user1",
    newPasswordFieldValue: "pass2",
    oldPasswordFieldValue: "pass1",
  },
  {
    document: `<input id="u1" value="">
      <input id="p1" type=password value="">
      <input id="p2" type=password value="">
      <input id="p3" type=password value="">`,
    selectorValues: {
      "#u1": "user1",
      "#p1": "pass1",
      "#p2": "pass2",
      "#p3": "pass2",
    },
    inputIndexForFormLike: 3,
    expectedFormsCount: 1,
    origin: DEFAULT_ORIGIN,
    formActionOrigin: DEFAULT_ORIGIN,
    usernameFieldValue: "user1",
    newPasswordFieldValue: "pass2",
    oldPasswordFieldValue: "pass1",
  },
  {
    document: `<input id="u1" value="">
      <input id="p1" type=password value="" form="form1">
      <input id="p2" type=password value="">
      <form id="form1">
        <input id="u2" value="">
        <input id="p3" type=password value="">
      </form>`,
    selectorValues: {
      "#u1": "user1",
      "#p1": "user2",
      "#p2": "pass1",
      "#u2": "user3",
      "#p3": "pass2",
    },
    inputIndexForFormLike: 2,
    expectedFormsCount: 2,
    origin: DEFAULT_ORIGIN,
    formActionOrigin: DEFAULT_ORIGIN,
    usernameFieldValue: "user1",
    newPasswordFieldValue: "pass1",
    oldPasswordFieldValue: null,
  },
  {
    document: `<!-- recipe field override -->
      <input name="recipeuname" value="">
      <input id="u1" value="">
      <input id="p1" type=password value="">
      <input name="recipepword" type=password value="">`,
    selectorValues: {
      "[name='recipeuname']": "username from recipe",
      "#u1": "default field username",
      "#p1": "pass1",
      "[name='recipepword']": "pass2",
    },
    inputIndexForFormLike: 2,
    expectedFormsCount: 1,
    origin: DEFAULT_ORIGIN,
    formActionOrigin: DEFAULT_ORIGIN,
    usernameFieldValue: "username from recipe",
    newPasswordFieldValue: "pass2",
    oldPasswordFieldValue: null,
  },
];

let count = 0;
async function testFormlessSubmit(tc) {
  let loginFrame = document.getElementById("loginFrame");

  let frameDoc = SpecialPowers.wrap(loginFrame.contentWindow).document;
  info("Starting testcase: " + JSON.stringify(tc));

  let formsProcessed = promiseFormsProcessedInSameProcess(tc.expectedFormsCount);
  // eslint-disable-next-line no-unsanitized/property
  frameDoc.documentElement.innerHTML = tc.document;
  await formsProcessed;
  // We eliminate no user input as a reason for not capturing by modifying the value
  setUserInputValues(frameDoc.documentElement, tc.selectorValues);

  let inputForFormLike = frameDoc.querySelectorAll("input")[tc.inputIndexForFormLike];

  let formLike = LoginFormFactory.createFromField(inputForFormLike);

  info("Calling _onFormSubmit with FormLike");
  let submitProcessed = getSubmitMessage();
  LoginManagerChild.forWindow(frameDoc.defaultView)._onFormSubmit(formLike);

  let { origin, data } = await submitProcessed;

  // Check data sent via PasswordManager:onFormSubmit
  is(origin, tc.origin, "Check origin");
  is(data.formActionOrigin, tc.formActionOrigin, "Check formActionOrigin");

  if (tc.usernameFieldValue === null) {
    is(data.usernameField, tc.usernameFieldValue, "Check usernameField");
  } else {
    is(data.usernameField.value, tc.usernameFieldValue, "Check usernameField");
  }

  is(data.newPasswordField.value, tc.newPasswordFieldValue, "Check newPasswordFieldValue");

  if (tc.oldPasswordFieldValue === null) {
    is(data.oldPasswordField, tc.oldPasswordFieldValue, "Check oldPasswordFieldValue");
  } else {
    is(data.oldPasswordField.value, tc.oldPasswordFieldValue, "Check oldPasswordFieldValue");
  }

  loadPromise = loadFrame();
  loginFrame.contentWindow.location =
    "http://mochi.test:8888/tests/toolkit/components/passwordmgr/test/mochitest/blank.html?" + count++;
  await loadPromise;
}

for (let tc of TESTCASES) {
  let taskName = "testcase-" + count++;
  let tmp = {
    async [taskName]() {
      await testFormlessSubmit(tc);
    },
  };
  add_task(tmp[taskName]);
}
</script>

<p id="display"></p>

<div id="content">
  <iframe id="loginFrame" src="http://mochi.test:8888/tests/toolkit/components/passwordmgr/test/mochitest/blank.html"></iframe>
</div>
<pre id="test"></pre>
</body>
</html>
