summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/extensions/test/browser/browser_addon_list_reordering.js
blob: 3fd419032b8ef561c321f41956f1d08f595a98e2 (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
186
187
188
189
190
191
192
193
194
195
196
197
/* 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);

function assertInSection(card, sectionName, msg) {
  let section = card.closest("section");
  let heading = section.querySelector(".list-section-heading");
  is(
    card.ownerDocument.l10n.getAttributes(heading).id,
    `extension-${sectionName}-heading`,
    msg
  );
}

function waitForAnimationFrame(win) {
  return new Promise(resolve => win.requestAnimationFrame(resolve));
}

async function clickEnableToggle(card) {
  let isDisabled = card.addon.userDisabled;
  let addonEvent = isDisabled ? "onEnabled" : "onDisabled";
  let addonStateChanged = AddonTestUtils.promiseAddonEvent(addonEvent);
  let win = card.ownerGlobal;
  let button = card.querySelector(".extension-enable-button");

  // Centre the button since "start" could be behind the sticky header.
  button.scrollIntoView({ block: "center" });
  EventUtils.synthesizeMouseAtCenter(button, { type: "mousemove" }, win);
  EventUtils.synthesizeMouseAtCenter(button, {}, win);

  await addonStateChanged;
  await waitForAnimationFrame(win);
}

function mouseOver(el) {
  let win = el.ownerGlobal;
  el.scrollIntoView({ block: "center" });
  EventUtils.synthesizeMouseAtCenter(el, { type: "mousemove" }, win);
  return waitForAnimationFrame(win);
}

function mouseOutOfList(win) {
  return mouseOver(win.document.querySelector(".header-name"));
}

function pressKey(win, key) {
  EventUtils.synthesizeKey(key, {}, win);
  return waitForAnimationFrame(win);
}

function waitForTransitionEnd(...els) {
  return Promise.all(
    els.map(el =>
      BrowserTestUtils.waitForEvent(el, "transitionend", false, e => {
        let cardEl = el.firstElementChild;
        return e.target == cardEl && e.propertyName == "transform";
      })
    )
  );
}

add_setup(async function () {
  // Ensure prefers-reduced-motion isn't set. Some linux environments will have
  // this enabled by default.
  await SpecialPowers.pushPrefEnv({
    set: [["ui.prefersReducedMotion", 0]],
  });
});

add_task(async function testReordering() {
  let addonIds = [
    "one@mochi.test",
    "two@mochi.test",
    "three@mochi.test",
    "four@mochi.test",
    "five@mochi.test",
  ];
  let extensions = addonIds.map(id =>
    ExtensionTestUtils.loadExtension({
      manifest: {
        name: id,
        browser_specific_settings: { gecko: { id } },
      },
      useAddonManager: "temporary",
    })
  );

  await Promise.all(extensions.map(ext => ext.startup()));

  let win = await loadInitialView("extension", { withAnimations: true });

  let cardOne = getAddonCard(win, "one@mochi.test");
  ok(!cardOne.addon.userDisabled, "extension one is enabled");
  assertInSection(cardOne, "enabled", "cardOne is initially in Enabled");

  await clickEnableToggle(cardOne);

  ok(cardOne.addon.userDisabled, "extension one is now disabled");
  assertInSection(cardOne, "enabled", "cardOne is still in Enabled");

  let cardThree = getAddonCard(win, "three@mochi.test");
  ok(!cardThree.addon.userDisabled, "extension three is enabled");
  assertInSection(cardThree, "enabled", "cardThree is initially in Enabled");

  await clickEnableToggle(cardThree);

  ok(cardThree.addon.userDisabled, "extension three is now disabled");
  assertInSection(cardThree, "enabled", "cardThree is still in Enabled");

  let transitionsEnded = waitForTransitionEnd(cardOne, cardThree);
  await mouseOutOfList(win);
  await transitionsEnded;

  assertInSection(cardOne, "disabled", "cardOne has moved to disabled");
  assertInSection(cardThree, "disabled", "cardThree has moved to disabled");

  await clickEnableToggle(cardThree);
  await clickEnableToggle(cardOne);

  assertInSection(cardOne, "disabled", "cardOne is still in disabled");
  assertInSection(cardThree, "disabled", "cardThree is still in disabled");

  info("Opening a more options menu");
  let panel = cardThree.querySelector("panel-list");
  EventUtils.synthesizeMouseAtCenter(
    cardThree.querySelector('[action="more-options"]'),
    {},
    win
  );

  await BrowserTestUtils.waitForEvent(panel, "shown");
  await mouseOutOfList(win);

  assertInSection(cardOne, "disabled", "cardOne stays in disabled, menu open");
  assertInSection(cardThree, "disabled", "cardThree stays in disabled");

  transitionsEnded = waitForTransitionEnd(cardOne, cardThree);
  EventUtils.synthesizeMouseAtCenter(
    win.document.querySelector(".header-name"),
    {},
    win
  );
  await transitionsEnded;

  assertInSection(cardOne, "enabled", "cardOne is now in enabled");
  assertInSection(cardThree, "enabled", "cardThree is now in enabled");

  let cardOneToggle = cardOne.querySelector(".extension-enable-button");
  cardOneToggle.scrollIntoView({ block: "center" });
  cardOneToggle.focus();
  await pressKey(win, " ");
  await waitForAnimationFrame(win);

  let cardThreeToggle = cardThree.querySelector(".extension-enable-button");
  let addonList = win.document.querySelector("addon-list");
  // Tab down to cardThreeToggle.
  while (
    addonList.contains(win.document.activeElement) &&
    win.document.activeElement !== cardThreeToggle
  ) {
    await pressKey(win, "VK_TAB");
  }
  await pressKey(win, " ");

  assertInSection(cardOne, "enabled", "cardOne is still in enabled");
  assertInSection(cardThree, "enabled", "cardThree is still in enabled");

  transitionsEnded = waitForTransitionEnd(cardOne, cardThree);
  win.document.querySelector('[action="page-options"]').focus();
  await transitionsEnded;
  assertInSection(
    cardOne,
    "disabled",
    "cardOne is now in the disabled section"
  );
  assertInSection(
    cardThree,
    "disabled",
    "cardThree is now in the disabled section"
  );

  // Ensure an uninstalled extension is removed right away.
  // Hover a card in the middle of the list.
  await mouseOver(getAddonCard(win, "two@mochi.test"));
  await cardOne.addon.uninstall(true);
  ok(!cardOne.parentNode, "cardOne has been removed from the document");

  await closeView(win);
  await Promise.all(extensions.map(ext => ext.unload()));
});