Source code

Revision control

Other Tools

1
<!DOCTYPE HTML>
2
<html>
3
<head>
4
<title>PageAction Test</title>
7
<script type="text/javascript" src="head.js"></script>
8
<link rel="stylesheet" href="chrome://mochikit/contents/tests/SimpleTest/test.css"/>
9
</head>
10
<body>
11
12
<script type="text/javascript">
13
"use strict";
14
15
const {ContentTask} = ChromeUtils.import("resource://testing-common/ContentTask.jsm");
16
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
17
18
async function waitAboutAddonsRendered(addonId) {
19
await ContentTaskUtils.waitForCondition(() => {
20
return content.document.querySelector(`div.addon-item[addonID="${addonId}"]`);
21
}, `wait Addon Item for ${addonId} to be rendered`);
22
}
23
24
async function navigateToAddonDetails(addonId) {
25
const item = content.document.querySelector(`div.addon-item[addonID="${addonId}"]`);
26
let rect = item.getBoundingClientRect();
27
const x = rect.left + rect.width / 2;
28
const y = rect.top + rect.height / 2;
29
let domWinUtils = content.window.windowUtils;
30
31
domWinUtils.sendMouseEventToWindow("mousedown", x, y, 0, 1, 0);
32
domWinUtils.sendMouseEventToWindow("mouseup", x, y, 0, 1, 0);
33
}
34
35
async function waitAddonOptionsPage([addonId, expectedText]) {
36
await ContentTaskUtils.waitForCondition(() => {
37
const optionsIframe = content.document.querySelector(`#addon-options`);
38
return optionsIframe && optionsIframe.contentDocument.readyState === "complete" &&
39
optionsIframe.contentDocument.body.innerText.includes(expectedText);
40
}, `wait Addon Options ${expectedText} for ${addonId} to be loaded`);
41
42
const optionsIframe = content.document.querySelector(`#addon-options`);
43
44
return {
45
iframeHeight: optionsIframe.style.height,
46
documentHeight: optionsIframe.contentDocument.documentElement.scrollHeight,
47
bodyHeight: optionsIframe.contentDocument.body.scrollHeight,
48
};
49
}
50
51
async function clickOnLinkInOptionsPage(selector) {
52
const optionsIframe = content.document.querySelector(`#addon-options`);
53
optionsIframe.contentDocument.querySelector(selector).click();
54
}
55
56
async function clickAddonOptionButton() {
57
content.document.querySelector(`button#open-addon-options`).click();
58
}
59
60
async function navigateBack() {
61
content.window.history.back();
62
}
63
64
function waitDOMContentLoaded(checkUrlCb) {
65
const {BrowserApp} = Services.wm.getMostRecentWindow("navigator:browser");
66
67
return new Promise(resolve => {
68
let listener = (event) => {
69
if (checkUrlCb(event.target.defaultView.location.href)) {
70
BrowserApp.deck.removeEventListener("DOMContentLoaded", listener);
71
resolve();
72
}
73
};
74
75
BrowserApp.deck.addEventListener("DOMContentLoaded", listener);
76
});
77
}
78
79
function waitAboutAddonsLoaded() {
80
return waitDOMContentLoaded(url => url === "about:addons");
81
}
82
83
function clickAddonDisable() {
84
content.document.querySelector("#disable-btn").click();
85
}
86
87
function clickAddonEnable() {
88
content.document.querySelector("#enable-btn").click();
89
}
90
91
add_task(async function test_options_ui_iframe_height() {
92
let addonID = "test-options-ui@mozilla.org";
93
94
let extension = ExtensionTestUtils.loadExtension({
95
useAddonManager: "temporary",
96
manifest: {
97
applications: {
98
gecko: {id: addonID},
99
},
100
name: "Options UI Extension",
101
description: "Longer addon description",
102
options_ui: {
103
page: "options.html",
104
},
105
},
106
files: {
107
// An option page with the document element bigger than the body.
108
"options.html": `<!DOCTYPE html>
109
<html>
110
<head>
111
<meta charset="utf-8">
112
<style>
113
html { height: 500px; border: 1px solid black; }
114
body { height: 200px; }
115
</style>
116
</head>
117
<body>
118
<h1>Options page 1</h1>
119
<a href="options2.html">go to page 2</a>
120
</body>
121
</html>
122
`,
123
// A second option page with the body element bigger than the document.
124
"options2.html": `<!DOCTYPE html>
125
<html>
126
<head>
127
<meta charset="utf-8">
128
<style>
129
html { height: 200px; border: 1px solid black; }
130
body { height: 350px; }
131
</style>
132
</head>
133
<body>
134
<h1>Options page 2</h1>
135
</body>
136
</html>
137
`,
138
},
139
});
140
141
await extension.startup();
142
143
const {BrowserApp} = Services.wm.getMostRecentWindow("navigator:browser");
144
145
let onceAboutAddonsLoaded = waitAboutAddonsLoaded();
146
147
BrowserApp.addTab("about:addons", {
148
selected: true,
149
parentId: BrowserApp.selectedTab.id,
150
});
151
152
await onceAboutAddonsLoaded;
153
154
is(BrowserApp.selectedTab.currentURI.spec, "about:addons",
155
"about:addons is the currently selected tab");
156
157
await ContentTask.spawn(BrowserApp.selectedTab.browser, addonID, waitAboutAddonsRendered);
158
159
await ContentTask.spawn(BrowserApp.selectedTab.browser, addonID, navigateToAddonDetails);
160
161
const optionsSizes = await ContentTask.spawn(
162
BrowserApp.selectedTab.browser, [addonID, "Options page 1"], waitAddonOptionsPage
163
);
164
165
ok(parseInt(optionsSizes.iframeHeight, 10) >= 500,
166
"The addon options iframe is at least 500px");
167
168
is(optionsSizes.iframeHeight, optionsSizes.documentHeight + "px",
169
"The addon options iframe has the expected height");
170
171
await ContentTask.spawn(BrowserApp.selectedTab.browser, "a", clickOnLinkInOptionsPage);
172
173
const options2Sizes = await ContentTask.spawn(
174
BrowserApp.selectedTab.browser, [addonID, "Options page 2"], waitAddonOptionsPage
175
);
176
177
// The second option page has a body bigger than the document element
178
// and we expect the iframe to be bigger than that.
179
ok(parseInt(options2Sizes.iframeHeight, 10) > 200,
180
`The iframe is bigger then 200px (${options2Sizes.iframeHeight})`);
181
182
// The second option page has a body smaller than the document element of the first
183
// page and we expect the iframe to be smaller than for the previous options page.
184
ok(parseInt(options2Sizes.iframeHeight, 10) < 500,
185
`The iframe is smaller then 500px (${options2Sizes.iframeHeight})`);
186
187
is(options2Sizes.iframeHeight, options2Sizes.documentHeight + "px",
188
"The second addon options page has the expected height");
189
190
await ContentTask.spawn(BrowserApp.selectedTab.browser, null, navigateBack);
191
192
const backToOptionsSizes = await ContentTask.spawn(
193
BrowserApp.selectedTab.browser, [addonID, "Options page 1"], waitAddonOptionsPage
194
);
195
196
// After going back to the first options page,
197
// we expect the iframe to have the same size of the previous load.
198
is(backToOptionsSizes.iframeHeight, optionsSizes.iframeHeight,
199
`When navigating back, the old iframe size is restored (${backToOptionsSizes.iframeHeight})`);
200
201
BrowserApp.closeTab(BrowserApp.selectedTab);
202
203
await extension.unload();
204
});
205
206
add_task(async function test_options_ui_open_aboutaddons_details() {
207
let addonID = "test-options-ui-open-addon-details@mozilla.org";
208
209
function background() {
210
browser.test.onMessage.addListener(msg => {
211
if (msg !== "runtime.openOptionsPage") {
212
browser.test.fail(`Received unexpected test message: ${msg}`);
213
return;
214
}
215
216
browser.runtime.openOptionsPage();
217
});
218
}
219
220
function optionsScript() {
221
browser.test.sendMessage("options-page-loaded", window.location.href);
222
}
223
224
let extension = ExtensionTestUtils.loadExtension({
225
useAddonManager: "temporary",
226
background,
227
manifest: {
228
applications: {
229
gecko: {id: addonID},
230
},
231
name: "Options UI open addon details Extension",
232
description: "Longer addon description",
233
options_ui: {
234
page: "options.html",
235
},
236
},
237
files: {
238
"options.js": optionsScript,
239
"options.html": `<!DOCTYPE html>
240
<html>
241
<head>
242
<meta charset="utf-8">
243
</head>
244
<body>
245
<h1>Options page</h1>
246
<script src="options.js"><\/script>
247
</body>
248
</html>
249
`,
250
},
251
});
252
253
await extension.startup();
254
255
const {BrowserApp} = Services.wm.getMostRecentWindow("navigator:browser");
256
257
let onceAboutAddonsLoaded = waitAboutAddonsLoaded();
258
259
BrowserApp.addTab("about:addons", {
260
selected: true,
261
parentId: BrowserApp.selectedTab.id,
262
});
263
264
await onceAboutAddonsLoaded;
265
266
is(BrowserApp.selectedTab.currentURI.spec, "about:addons",
267
"about:addons is the currently selected tab");
268
269
info("Wait runtime.openOptionsPage to open the about:addond details in the existent tab");
270
extension.sendMessage("runtime.openOptionsPage");
271
await extension.awaitMessage("options-page-loaded");
272
273
is(BrowserApp.selectedTab.currentURI.spec, "about:addons",
274
"about:addons is still the currently selected tab once the options has been loaded");
275
276
BrowserApp.closeTab(BrowserApp.selectedTab);
277
278
await extension.unload();
279
});
280
281
add_task(async function test_options_ui_open_in_tab() {
282
let addonID = "test-options-ui@mozilla.org";
283
284
function background() {
285
browser.test.onMessage.addListener(msg => {
286
if (msg !== "runtime.openOptionsPage") {
287
browser.test.fail(`Received unexpected test message: ${msg}`);
288
return;
289
}
290
291
browser.runtime.openOptionsPage();
292
});
293
}
294
295
function optionsScript() {
296
browser.test.sendMessage("options-page-loaded", window.location.href);
297
}
298
299
let extension = ExtensionTestUtils.loadExtension({
300
useAddonManager: "temporary",
301
background,
302
manifest: {
303
applications: {
304
gecko: {id: addonID},
305
},
306
name: "Options UI open_in_tab Extension",
307
description: "Longer addon description",
308
options_ui: {
309
page: "options.html",
310
open_in_tab: true,
311
},
312
},
313
files: {
314
"options.js": optionsScript,
315
"options.html": `<!DOCTYPE html>
316
<html>
317
<head>
318
<meta charset="utf-8">
319
</head>
320
<body>
321
<h1>Options page</h1>
322
<script src="options.js"><\/script>
323
</body>
324
</html>
325
`,
326
},
327
});
328
329
await extension.startup();
330
331
const {BrowserApp} = Services.wm.getMostRecentWindow("navigator:browser");
332
333
let onceAboutAddonsLoaded = waitAboutAddonsLoaded();
334
335
BrowserApp.selectOrAddTab("about:addons", {
336
selected: true,
337
parentId: BrowserApp.selectedTab.id,
338
});
339
340
await onceAboutAddonsLoaded;
341
342
const aboutAddonsTab = BrowserApp.selectedTab;
343
344
is(aboutAddonsTab.currentURI.spec, "about:addons",
345
"about:addons is the currently selected tab");
346
347
await ContentTask.spawn(aboutAddonsTab.browser, addonID, waitAboutAddonsRendered);
348
await ContentTask.spawn(aboutAddonsTab.browser, addonID, navigateToAddonDetails);
349
350
let onceAddonOptionsLoaded = waitDOMContentLoaded(url => url.endsWith("options.html"));
351
352
info("Click the Options button in the addon details");
353
await ContentTask.spawn(aboutAddonsTab.browser, null, clickAddonOptionButton);
354
355
info("Waiting that the addon options are loaded in a new tab");
356
await onceAddonOptionsLoaded;
357
358
const addonOptionsTab = BrowserApp.selectedTab;
359
360
ok(aboutAddonsTab.id !== addonOptionsTab.id,
361
"The Addon Options page has been loaded in a new tab");
362
363
let optionsURL = await extension.awaitMessage("options-page-loaded");
364
365
is(addonOptionsTab.currentURI.spec, optionsURL,
366
"Got the expected extension url opened in the addon options tab");
367
368
const waitTabClosed = (nativeTab) => {
369
return new Promise(resolve => {
370
let {BrowserApp} = Services.wm.getMostRecentWindow("navigator:browser");
371
let expectedBrowser = nativeTab.browser;
372
373
let tabCloseListener = (event) => {
374
let browser = event.target;
375
if (browser !== expectedBrowser) {
376
return;
377
}
378
379
BrowserApp.deck.removeEventListener("TabClose", tabCloseListener);
380
resolve();
381
};
382
383
BrowserApp.deck.addEventListener("TabClose", tabCloseListener);
384
});
385
};
386
387
let onceOptionsTabClosed = waitTabClosed(addonOptionsTab);
388
let onceAboutAddonsClosed = waitTabClosed(aboutAddonsTab);
389
390
info("Close the opened about:addons and options tab");
391
BrowserApp.closeTab(addonOptionsTab);
392
BrowserApp.closeTab(aboutAddonsTab);
393
394
info("Wait the tabs to be closed");
395
await Promise.all([onceOptionsTabClosed, onceAboutAddonsClosed]);
396
397
const oldSelectedTab = BrowserApp.selectedTab;
398
info("Call runtime.openOptionsPage");
399
extension.sendMessage("runtime.openOptionsPage");
400
401
info("Wait runtime.openOptionsPage to open the options in a new tab");
402
optionsURL = await extension.awaitMessage("options-page-loaded");
403
is(BrowserApp.selectedTab.currentURI.spec, optionsURL,
404
"runtime.openOptionsPage has opened the expected extension page");
405
ok(BrowserApp.selectedTab !== oldSelectedTab,
406
"runtime.openOptionsPage has opened a new tab");
407
408
BrowserApp.closeTab(BrowserApp.selectedTab);
409
410
await extension.unload();
411
});
412
413
add_task(async function test_options_ui_on_disable_and_enable() {
414
// Temporarily disabled for races.
415
/* eslint-disable no-unreachable */
416
return;
417
418
let addonID = "test-options-ui-disable-enable@mozilla.org";
419
420
function optionsScript() {
421
browser.test.sendMessage("options-page-loaded", window.location.href);
422
}
423
424
let extension = ExtensionTestUtils.loadExtension({
425
useAddonManager: "temporary",
426
manifest: {
427
applications: {
428
gecko: {id: addonID},
429
},
430
name: "Options UI open addon details Extension",
431
description: "Longer addon description",
432
options_ui: {
433
page: "options.html",
434
},
435
},
436
files: {
437
"options.js": optionsScript,
438
"options.html": `<!DOCTYPE html>
439
<html>
440
<head>
441
<meta charset="utf-8">
442
</head>
443
<body>
444
<h1>Options page</h1>
445
<script src="options.js"><\/script>
446
</body>
447
</html>
448
`,
449
},
450
});
451
452
await extension.startup();
453
454
const {BrowserApp} = Services.wm.getMostRecentWindow("navigator:browser");
455
456
let onceAboutAddonsLoaded = waitAboutAddonsLoaded();
457
458
BrowserApp.addTab("about:addons", {
459
selected: true,
460
parentId: BrowserApp.selectedTab.id,
461
});
462
463
await onceAboutAddonsLoaded;
464
465
const aboutAddonsTab = BrowserApp.selectedTab;
466
467
is(aboutAddonsTab.currentURI.spec, "about:addons",
468
"about:addons is the currently selected tab");
469
470
info("Wait the addon details to have been loaded");
471
await ContentTask.spawn(aboutAddonsTab.browser, addonID, waitAboutAddonsRendered);
472
await ContentTask.spawn(aboutAddonsTab.browser, addonID, navigateToAddonDetails);
473
474
info("Wait the addon options page to have been loaded");
475
await extension.awaitMessage("options-page-loaded");
476
477
info("Click the addon disable button");
478
await ContentTask.spawn(aboutAddonsTab.browser, null, clickAddonDisable);
479
480
// NOTE: Currently after disabling the addon the extension.awaitMessage seems
481
// to fail be able to receive events coming from the browser.test.sendMessage API
482
// (nevertheless `await extension.unload()` seems to be able to remove the extension),
483
// falling back to wait for the options page to be loaded here.
484
const onceAddonOptionsLoaded = waitDOMContentLoaded(url => url.endsWith("options.html"));
485
486
info("Click the addon enable button");
487
await ContentTask.spawn(aboutAddonsTab.browser, null, clickAddonEnable);
488
489
info("Wait the addon options page to have been loaded after clicking the addon enable button");
490
await onceAddonOptionsLoaded;
491
492
BrowserApp.closeTab(BrowserApp.selectedTab);
493
494
await extension.unload();
495
});
496
497
</script>
498
499
</body>
500
</html>