Source code

Revision control

Other Tools

1
<!DOCTYPE HTML>
2
<html>
3
<head>
4
<title>Tabs executeScript runAt Test</title>
5
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
6
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
7
<script type="text/javascript" src="head.js"></script>
8
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
9
</head>
10
<body>
11
12
<script type="text/javascript">
13
"use strict";
14
15
/**
16
* These tests ensure that the runAt argument to tabs.executeScript delays
17
* script execution until the document has reached the correct state.
18
*
19
* Since tests of this nature are especially race-prone, it relies on a
20
* server-JS script to delay the completion of our test page's load cycle long
21
* enough for us to attempt to load our scripts in the earlies phase we support.
22
*
23
* And since we can't actually rely on that timing, it retries any attempts that
24
* fail to load as early as expected, but don't load at any illegal time.
25
*/
26
27
add_task(async function testExecuteScript() {
28
let win = window.open("about:blank");
29
30
async function background(DEBUG) {
31
let tab;
32
34
const URL = BASE + "file_slowed_document.sjs";
35
36
const MAX_TRIES = 30;
37
38
let onUpdatedPromise = (tabId, url, status) => {
39
return new Promise(resolve => {
40
browser.tabs.onUpdated.addListener(function listener(_, changed, tab) {
41
if (tabId == tab.id && changed.status == status && tab.url == url) {
42
browser.tabs.onUpdated.removeListener(listener);
43
resolve();
44
}
45
});
46
});
47
};
48
49
try {
50
[tab] = await browser.tabs.query({active: true, currentWindow: true});
51
// TODO bug 1565536: tab.active is broken in GeckoView.
52
browser.test.assertEq(undefined, tab, "currentWindow's tab is not active (bug 1565536)");
53
[tab] = await browser.tabs.query({currentWindow: true});
54
55
let success = false;
56
for (let tries = 0; !success && tries < MAX_TRIES; tries++) {
57
let url = `${URL}?with-iframe&r=${Math.random()}`;
58
59
let loadingPromise = onUpdatedPromise(tab.id, url, "loading");
60
let completePromise = onUpdatedPromise(tab.id, url, "complete");
61
62
// TODO: Test allFrames and frameId.
63
64
await browser.tabs.update({url});
65
await loadingPromise;
66
67
let states = await Promise.all([
68
// Send the executeScript requests in the reverse order that we expect
69
// them to execute in, to avoid them passing only because of timing
70
// races.
71
browser.tabs.executeScript({
72
code: "document.readyState",
73
runAt: "document_idle",
74
}),
75
browser.tabs.executeScript({
76
code: "document.readyState",
77
runAt: "document_end",
78
}),
79
browser.tabs.executeScript({
80
code: "document.readyState",
81
runAt: "document_start",
82
}),
83
].reverse());
84
85
browser.test.log(`Got states: ${states}`);
86
87
// Make sure that none of our scripts executed earlier than expected,
88
// regardless of retries.
89
browser.test.assertTrue(states[1] == "interactive" || states[1] == "complete",
90
`document_end state is valid: ${states[1]}`);
91
browser.test.assertTrue(states[2] == "interactive" || states[2] == "complete",
92
`document_idle state is valid: ${states[2]}`);
93
94
// If we have the earliest valid states for each script, we're done.
95
// Otherwise, try again.
96
success = ((states[0] == "loading" || DEBUG) &&
97
states[1] == "interactive" &&
98
(states[2] == "interactive" || states[2] == "complete"));
99
100
await completePromise;
101
}
102
103
browser.test.assertTrue(success, "Got the earliest expected states at least once");
104
105
browser.test.notifyPass("executeScript-runAt");
106
} catch (e) {
107
browser.test.fail(`Error: ${e} :: ${e.stack}`);
108
browser.test.notifyFail("executeScript-runAt");
109
}
110
}
111
112
let extension = ExtensionTestUtils.loadExtension({
113
manifest: {
114
"permissions": ["http://mochi.test/", "tabs"],
115
},
116
117
background: `(${background})(${AppConstants.DEBUG})`,
118
});
119
120
await extension.startup();
121
122
await extension.awaitFinish("executeScript-runAt");
123
124
await extension.unload();
125
126
win.close();
127
});
128
</script>
129
130
</body>
131
</html>