forked from nodejs/undici
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathreftest-wait.js
More file actions
178 lines (161 loc) · 5.49 KB
/
Copy pathreftest-wait.js
File metadata and controls
178 lines (161 loc) · 5.49 KB
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
/**
* Remove the `reftest-wait` class on the document element.
* The reftest runner will wait with taking a screenshot while
* this class is present.
*
* See https://web-platform-tests.org/writing-tests/reftests.html#controlling-when-comparison-occurs
*/
function takeScreenshot() {
document.documentElement.classList.remove("reftest-wait");
}
/**
* Call `takeScreenshot()` after a delay of at least |timeout| milliseconds.
* @param {number} timeout - milliseconds
*/
function takeScreenshotDelayed(timeout) {
setTimeout(function() {
takeScreenshot();
}, timeout);
}
/**
* Ensure that a precondition is met before waiting for a screenshot.
* @param {bool} condition - Fail the test if this evaluates to false
* @param {string} msg - Error message to write to the screenshot
* @returns {bool} True if the condition passed, false if it failed
*/
function failIfNot(condition, msg) {
const fail = () => {
(document.body || document.documentElement).textContent = `Precondition Failed: ${msg}`;
takeScreenshot();
};
if (!condition) {
if (document.readyState == "interactive") {
fail();
} else {
document.addEventListener("DOMContentLoaded", fail, false);
}
return false;
}
return true;
}
/**
* Display the failure reason and stop waiting for a screenshot.
*
* Does nothing for a mismatch-only reftest (no `match` reference is also
* present), since an error page necessarily differs from the reference and
* would spuriously pass instead of correctly timing out.
* @param {Error|ErrorEvent|PromiseRejectionEvent|*} error - The error that caused the failure.
*/
function failOnError(error) {
// Only <link>s explicitly in the XHTML namespace count as match/mismatch
// links, matching the manifest's own namespace-qualified lookup.
const links = document.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", "link");
let hasMatch = false;
let hasMismatch = false;
for (const link of links) {
const rel = link.getAttribute("rel");
if (rel === "match") {
hasMatch = true;
} else if (rel === "mismatch") {
hasMismatch = true;
}
}
if (hasMismatch && !hasMatch) {
return;
}
let message;
if (typeof PromiseRejectionEvent !== "undefined" && error instanceof PromiseRejectionEvent) {
if (error.reason && error.reason.message) {
message = "Unhandled rejection: " + error.reason.message;
} else {
message = "Unhandled rejection";
}
} else {
if (error.message) {
message = "Uncaught exception: " + error.message;
} else {
message = "Uncaught exception";
}
}
const node = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
node.textContent = message;
if (document.body) {
document.body.insertBefore(node, document.body.firstChild);
} else {
const root = document.documentElement;
const is_html = (root &&
root.namespaceURI === "http://www.w3.org/1999/xhtml" &&
root.localName === "html");
const is_svg = ("SVGSVGElement" in self && root instanceof SVGSVGElement);
if (is_svg) {
const foreignObject = document.createElementNS("http://www.w3.org/2000/svg", "foreignObject");
foreignObject.setAttribute("width", "100%");
foreignObject.setAttribute("height", "100%");
root.insertBefore(foreignObject, root.firstChild);
foreignObject.appendChild(node);
} else if (is_html) {
root.appendChild(document.createElementNS("http://www.w3.org/1999/xhtml", "body"))
.appendChild(node);
} else {
root.insertBefore(node, root.firstChild);
}
}
takeScreenshot();
}
/**
* Wrap `func` so a synchronous exception it throws is reported via
* failOnError() instead of propagating as an uncaught error. For use
* wrapping a callback, e.g. an event listener.
* @param {Function} func - Callback to wrap.
* @returns {Function} The wrapped callback.
*/
function reftestStep(func) {
return function(...args) {
try {
return func.apply(this, args);
} catch (e) {
failOnError(e);
}
};
}
/**
* Call `func` immediately, reporting via failOnError() either a
* synchronous exception it throws or an asynchronous rejection of the
* promise it returns.
* @param {Function} func - Function to call, typically async.
*/
function reftestPromise(func) {
const result = reftestStep(func)();
Promise.resolve(result).catch(failOnError);
}
/**
* Once a text track cue becomes active, pause the video, wait
* for layout to update, then call takeScreenshot().
*/
function waitForActiveCueAndTakeScreenshot() {
var videoElement = document.querySelector("video");
var trackElement = document.querySelector("track");
if (!failIfNot(videoElement, "Video element not found"))
return;
if (!failIfNot(trackElement, "Track element not found"))
return;
var textTrack = trackElement.track;
function pauseVideoAndTakeScreenshot() {
if (videoElement.paused)
requestAnimationFrame(() => takeScreenshot());
else {
videoElement.addEventListener("pause", function() {
requestAnimationFrame(() => takeScreenshot());
});
videoElement.pause();
}
}
textTrack.oncuechange = function() {
if (textTrack.activeCues && textTrack.activeCues.length) {
textTrack.oncuechange = null;
pauseVideoAndTakeScreenshot();
}
};
if (textTrack.activeCues && textTrack.activeCues.length)
pauseVideoAndTakeScreenshot();
}