summaryrefslogtreecommitdiffstats
path: root/browser/components/aboutlogins/tests/browser/browser_contextmenuFillLogins.js
blob: a10d92baac44df4332703b38cf33aa91d99edaf3 (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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */

add_setup(async function () {
  TEST_LOGIN1 = await addLogin(TEST_LOGIN1);
  await BrowserTestUtils.openNewForegroundTab({
    gBrowser,
    url: "about:logins",
  });
  registerCleanupFunction(() => {
    BrowserTestUtils.removeTab(gBrowser.selectedTab);
  });
});

const gTests = [
  {
    name: "test contextmenu on password field in create login view",
    async setup(browser) {
      // load up the create login view
      await SpecialPowers.spawn(browser, [], async () => {
        let loginList = Cu.waiveXrays(
          content.document.querySelector("login-list")
        );
        let createButton = loginList._createLoginButton;
        createButton.click();
      });
    },
  },
];

if (OSKeyStoreTestUtils.canTestOSKeyStoreLogin()) {
  gTests[gTests.length] = {
    name: "test contextmenu on password field in edit login view",
    async setup(browser) {
      let osAuthDialogShown = OSKeyStoreTestUtils.waitForOSKeyStoreLogin(true);

      // load up the edit login view
      await SpecialPowers.spawn(
        browser,
        [LoginHelper.loginToVanillaObject(TEST_LOGIN1)],
        async login => {
          let loginList = content.document.querySelector("login-list");
          let loginListItem = loginList.shadowRoot.querySelector(
            ".login-list-item[data-guid]:not([hidden])"
          );
          info("Clicking on the first login");

          loginListItem.click();
          let loginItem = Cu.waiveXrays(
            content.document.querySelector("login-item")
          );
          await ContentTaskUtils.waitForCondition(() => {
            return (
              loginItem._login.guid == loginListItem.dataset.guid &&
              loginItem._login.guid == login.guid
            );
          }, "Waiting for login item to get populated");
          let editButton = loginItem.shadowRoot.querySelector(".edit-button");
          editButton.click();
        }
      );
      await osAuthDialogShown;
      await SpecialPowers.spawn(browser, [], async () => {
        let loginItem = Cu.waiveXrays(
          content.document.querySelector("login-item")
        );
        await ContentTaskUtils.waitForCondition(
          () => loginItem.dataset.editing,
          "Waiting for login-item to be in editing state"
        );
      });
    },
  };
}

/**
 * Synthesize mouse clicks to open the password manager context menu popup
 * for a target input element.
 *
 */
async function openContextMenuForPasswordInput(browser) {
  const doc = browser.ownerDocument;
  const CONTEXT_MENU = doc.getElementById("contentAreaContextMenu");

  let contextMenuShownPromise = BrowserTestUtils.waitForEvent(
    CONTEXT_MENU,
    "popupshown"
  );

  let passwordInputCoords = await SpecialPowers.spawn(browser, [], async () => {
    let loginItem = Cu.waiveXrays(content.document.querySelector("login-item"));

    // The password display field is in the DOM when password input is unfocused.
    // To get the password input field, ensure it receives focus.
    let passwordInput = loginItem.shadowRoot.querySelector(
      "input[type='password']"
    );
    passwordInput.focus();
    passwordInput = loginItem.shadowRoot.querySelector(
      "input[name='password']"
    );

    passwordInput.focus();
    let passwordRect = passwordInput.getBoundingClientRect();

    // listen for the contextmenu event so we can assert on receiving it
    // and examine the target
    content.contextmenuPromise = new Promise(resolve => {
      content.document.body.addEventListener(
        "contextmenu",
        event => {
          info(
            `Received event on target: ${event.target.nodeName}, type: ${event.target.type}`
          );
          content.console.log("got contextmenu event: ", event);
          resolve(event);
        },
        { once: true }
      );
    });

    let coords = {
      x: passwordRect.x + passwordRect.width / 2,
      y: passwordRect.y + passwordRect.height / 2,
    };
    return coords;
  });

  // add the offsets of the <browser> in the chrome window
  let browserOffsets = browser.getBoundingClientRect();
  let offsetX = browserOffsets.x + passwordInputCoords.x;
  let offsetY = browserOffsets.y + passwordInputCoords.y;

  // Synthesize a right mouse click over the password input element, we have to trigger
  // both events because formfill code relies on this event happening before the contextmenu
  // (which it does for real user input) in order to not show the password autocomplete.
  let eventDetails = { type: "mousedown", button: 2 };
  await EventUtils.synthesizeMouseAtPoint(offsetX, offsetY, eventDetails);

  // Synthesize a contextmenu event to actually open the context menu.
  eventDetails = { type: "contextmenu", button: 2 };
  await EventUtils.synthesizeMouseAtPoint(offsetX, offsetY, eventDetails);

  await SpecialPowers.spawn(browser, [], async () => {
    let event = await content.contextmenuPromise;
    // XXX the event target here is the login-item element,
    //     not the input[type='password'] in its shadowRoot
    info("contextmenu event target: " + event.target.nodeName);
  });

  info("waiting for contextMenuShownPromise");
  await contextMenuShownPromise;
  return CONTEXT_MENU;
}

async function testContextMenuOnInputField(testData) {
  let browser = gBrowser.selectedBrowser;

  await SimpleTest.promiseFocus(browser.ownerGlobal);
  await testData.setup(browser);

  info("test setup completed");
  let contextMenu = await openContextMenuForPasswordInput(browser);
  let fillItem = contextMenu.querySelector("#fill-login");
  Assert.ok(fillItem, "fill menu item exists");
  Assert.ok(
    fillItem && EventUtils.isHidden(fillItem),
    "fill menu item is hidden"
  );

  let promiseHidden = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
  info("Calling hidePopup on contextMenu");
  contextMenu.hidePopup();
  info("waiting for promiseHidden");
  await promiseHidden;
}

for (let testData of gTests) {
  let tmp = {
    async [testData.name]() {
      await testContextMenuOnInputField(testData);
    },
  };
  add_task(tmp[testData.name]);
}