summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/extensions/test/xpinstall/browser_required_useractivation.js
blob: 6c8894699dc66b14ba88ca5257ed78971d0b3946 (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
/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/
 */

"use strict";

const { AddonTestUtils } = ChromeUtils.importESModule(
  "resource://testing-common/AddonTestUtils.sys.mjs"
);

AddonTestUtils.initMochitest(this);

const XPI_URL = `${TESTROOT}amosigned.xpi`;

async function runTestCase(spawnArgs, spawnFn, { expectInstall, clickLink }) {
  await SpecialPowers.pushPrefEnv({
    set: [
      // Make use the user activation requirements is enabled while running this test.
      ["xpinstall.userActivation.required", true],
    ],
  });
  await BrowserTestUtils.withNewTab(TESTROOT, async browser => {
    const expectedError = `${XPI_URL} install cancelled because of missing user gesture activation`;

    let promiseDone;

    if (expectInstall) {
      promiseDone = TestUtils.topicObserved("addon-install-blocked").then(
        ([subject]) => {
          // Cancel the pending installation flow.
          subject.wrappedJSObject.cancel();
        }
      );
    } else {
      promiseDone = new Promise(resolve => {
        function messageHandler(msgObj) {
          if (
            msgObj instanceof Ci.nsIScriptError &&
            msgObj.message.includes(expectedError)
          ) {
            ok(
              true,
              "Expect error on triggering navigation to xpi without user gesture activation"
            );
            cleanupListener();
            resolve();
          }
        }
        let listenerCleared = false;
        function cleanupListener() {
          if (!listenerCleared) {
            Services.console.unregisterListener(messageHandler);
          }
          listenerCleared = true;
        }
        Services.console.registerListener(messageHandler);
        registerCleanupFunction(cleanupListener);
      });
    }

    await SpecialPowers.spawn(browser, spawnArgs, spawnFn);

    if (clickLink) {
      info("Click link element");
      // Wait for the install to trigger the third party website doorhanger.
      // Trigger the link by simulating a mouse click, and expect it to trigger the
      // install flow instead (the window is still navigated to the xpi url from the
      // webpage JS code, but doing it while handling a DOM event does make it pass
      // the user activation check).
      await BrowserTestUtils.synthesizeMouseAtCenter(
        "#link-to-xpi-file",
        {},
        browser
      );
    }

    info("Wait test case to be completed");
    await promiseDone;
    ok(true, "Test case run completed");
  });
}

add_task(async function testSuccessOnUserActivatedLink() {
  await runTestCase(
    [XPI_URL],
    xpiURL => {
      const { document } = this.content;
      const link = document.createElement("a");
      link.id = "link-to-xpi-file";
      link.setAttribute("href", xpiURL);
      link.textContent = "Link to XPI File";

      // Empty the test case and add the link, if the link is not visible
      // without scrolling, BrowserTestUtils.synthesizeMouseAtCenter may
      // fail to trigger the mouse event.
      document.body.innerHTML = "";
      document.body.appendChild(link);
    },
    { expectInstall: true, clickLink: true }
  );
});

add_task(async function testSuccessOnJSWithUserActivation() {
  await runTestCase(
    [XPI_URL],
    xpiURL => {
      const { document } = this.content;
      const link = document.createElement("a");
      link.id = "link-to-xpi-file";
      link.setAttribute("href", "#");
      link.textContent = "Link to XPI File";

      // Empty the test case and add the link, if the link is not visible
      // without scrolling, BrowserTestUtils.synthesizeMouseAtCenter may
      // fail to trigger the mouse event.
      document.body.innerHTML = "";
      document.body.appendChild(link);

      this.content.eval(`
        const linkEl = document.querySelector("#link-to-xpi-file");
        linkEl.onclick = () => {
          // This is expected to trigger the install flow successfully if handling
          // a user gesture DOM event, but to fail when triggered outside of it (as
          // done a few line below).
          window.location = "${xpiURL}";
        };
      `);
    },
    { expectInstall: true, clickLink: true }
  );
});

add_task(async function testFailureOnJSWithoutUserActivation() {
  await runTestCase(
    [XPI_URL],
    xpiURL => {
      this.content.eval(`window.location = "${xpiURL}";`);
    },
    { expectInstall: false }
  );
});

add_task(async function testFailureOnJSWithoutUserActivation() {
  await runTestCase(
    [XPI_URL],
    xpiURL => {
      this.content.eval(`
        const frame = document.createElement("iframe");
        frame.src = "${xpiURL}";
        document.body.innerHTML = "";
        document.body.appendChild(frame);
      `);
    },
    { expectInstall: false }
  );
});