summaryrefslogtreecommitdiffstats
path: root/toolkit/components/satchel/test/test_password_autocomplete.html
blob: c6830071938dc0c2d614b90b40dd034e952cf9a9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
<!DOCTYPE HTML>
<html>
<head>
  <title>Test for form history on type=password</title>
  <script src="/tests/SimpleTest/SimpleTest.js"></script>
  <script src="/tests/SimpleTest/EventUtils.js"></script>
  <script type="text/javascript" src="satchel_common.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
  Test for form history on type=password
  (based on test_bug_511615.html)
<p id="display"></p>

<!-- we presumably can't hide the content for this test. -->
<div id="content">
  <datalist id="datalist1">
    <option>value10</option>
    <option>value11</option>
    <option>value12</option>
  </datalist>
  <form id="form1" onsubmit="return false;">
    <!-- Don't set the type to password until rememberSignons is false since we
         want to test when rememberSignons is false. -->
    <input  type="to-be-password" name="field1" list="datalist1">
    <button type="submit">Submit</button>
  </form>
  <!-- Same as form1 but with an insecure HTTP action -->
  <form id="form2" onsubmit="return false;" action="http://mochi.test/">
    <input  type="to-be-password" name="field1" list="datalist1">
    <button type="submit">Submit</button>
  </form>
</div>

<pre id="test">
<script class="testbody" type="text/javascript">
var resolvePopupShownListener;
registerPopupShownListener(() => resolvePopupShownListener());

function waitForNextPopup() {
  return new Promise(resolve => { resolvePopupShownListener = resolve; });
}

/**
 * Indicates the time to wait before checking that the state of the autocomplete
 * popup, including whether it is open, has not changed in response to events.
 *
 * Manual testing on a fast machine revealed that 80ms was still unreliable,
 * while 100ms detected a simulated failure reliably. Unfortunately, this means
 * that to take into account slower machines we should use a larger value.
 *
 * Note that if a machine takes more than this time to show the popup, this
 * would not cause a failure, conversely the machine would not be able to detect
 * whether the test should have failed. In other words, this use of timeouts is
 * never expected to cause intermittent failures with test automation.
 */
const POPUP_RESPONSE_WAIT_TIME_MS = 200;

SimpleTest.requestFlakyTimeout("Must ensure that an event does not happen.");

/**
 * Checks that the popup does not open in response to the given function.
 *
 * @param {Function} triggerFn - function that triggers an event
 * @returns {Promise}
 */
function expectPopupDoesNotOpen(triggerFn) {
  let popupShown = waitForNextPopup();
  triggerFn();
  return Promise.race([
    popupShown.then(() => Promise.reject("Popup opened unexpectedly.")),
    new Promise(resolve => setTimeout(resolve, POPUP_RESPONSE_WAIT_TIME_MS)),
  ]);
}

add_task(async function test_initialize() {
  await SpecialPowers.pushPrefEnv({set: [["signon.rememberSignons", false]]});

  is(window.location.protocol, "https:", "This test must run on HTTPS");

  // Now that rememberSignons is false, create the password fields.
  $_(1, "field1").type = "password";
  $_(2, "field1").type = "password";

  await new Promise(resolve => updateFormHistory([
    { op: "remove" },
    { op: "add", fieldname: "field1", value: "value1" },
    { op: "add", fieldname: "field1", value: "value2" },
    { op: "add", fieldname: "field1", value: "value3" },
    { op: "add", fieldname: "field1", value: "value4" },
    { op: "add", fieldname: "field1", value: "value5" },
    { op: "add", fieldname: "field1", value: "value6" },
    { op: "add", fieldname: "field1", value: "value7" },
    { op: "add", fieldname: "field1", value: "value8" },
    { op: "add", fieldname: "field1", value: "value9" },
  ], resolve));
});

add_task(async function test_secure_noFormHistoryOrWarning() {
  let input = $_(1, "field1");

  // The autocomplete popup should not open under any circumstances on
  // type=password with password manager disabled.
  for (let triggerFn of [
    () => input.focus(),
    () => input.click(),
    () => synthesizeKey("KEY_ArrowDown"),
    () => synthesizeKey("KEY_PageDown"),
    () => synthesizeKey("KEY_Enter"),
    () => sendString("v "),
    () => synthesizeKey("KEY_Backspace"),
  ]) {
    ok(true, "Testing: " + triggerFn.toString());
    // We must wait for the entire timeout for each individual test, because the
    // next event in the list might prevent the popup from opening.
    await expectPopupDoesNotOpen(triggerFn);
  }

  // Close the popup.
  input.blur();
});

add_task(async function test_insecure_focusWarning() {
  // Form 2 has an insecure action so should show the warning even if password manager is disabled.
  let input = $_(2, "field1");
  let shownPromise = waitForNextPopup();
  input.focus();
  await shownPromise;

  ok(getMenuEntries()[0].includes("Logins entered here could be compromised"),
     "Check warning is first");

  // Close the popup
  input.blur();
});
</script>
</pre>
</body>
</html>