Branch data Line data Source code
1 [ + ]: 8 : import assert from 'node:assert';
2 : 8 :
3 : 8 : const recorded_xhr_events = [];
4 : 8 : const actual_xhr_events = [];
5 : 8 :
6 [ + ]: 8 : const record_xhr_event = (e) => {
7 [ + ][ + ]: 33 : const prefix = e.target.constructor.name === 'XMLHttpRequestUpload' ? 'upload.' : '';
8 [ + ]: 33 : const event = (prefix || '') + e.type + '(' + e.loaded + ',' + e.total + ',' + e.lengthComputable + ')';
9 : 33 :
10 : 33 : recorded_xhr_events.push(event);
11 : 33 : actual_xhr_events.push(event);
12 : 33 : }
13 : 8 :
14 [ + ][ + ]: 8 : const getNextEvent = (arr) => {
15 : 92 : let event = {
16 : 92 : str: arr.shift()
17 : 92 : };
18 : 92 :
19 : 92 : // we can only handle strings, numbers (readystates) and undefined
20 [ - ][ - ]: 92 : if(event.str === undefined){
21 : 0 : return event;
22 : 0 : }
23 : 92 :
24 [ + ][ + ]: 92 : if(typeof event.str !== 'string'){
25 : 30 :
26 : 30 : if(/^\d+$/.test(event.str)){
27 : 30 : event.state = event.str;
28 : 30 : event.str = `readystatechange(${event.str})`;
29 [ - ][ - ]: 30 : }
30 : 0 : else{
31 : 0 : throw `Test error: unexpected event type ${event.str}`;
32 : 0 : }
33 : 30 : }
34 : 92 :
35 : 92 : // parse out the general type, loaded and total values
36 : 92 : let type = event.type = event.str.split('(')[0].split('.').pop();
37 : 92 : let loadedAndTotal = event.str.match(/.*\((\d+),(\d+),(true|false)\)/);
38 : 92 :
39 [ + ][ + ]: 92 : if(loadedAndTotal){
40 : 62 : event.loaded = parseInt(loadedAndTotal[1]);
41 : 62 : event.total = parseInt(loadedAndTotal[2]);
42 : 62 : event.lengthComputable = loadedAndTotal[3] == 'true';
43 : 62 : }
44 : 92 :
45 : 92 : return event;
46 : 92 : }
47 : 8 :
48 [ + ][ + ]: 8 : export function prepare_xhr_for_event_order_test(xhr){
49 : 6 :
50 [ + ][ + ]: 6 : xhr.addEventListener('readystatechange', () => {
51 : 15 : recorded_xhr_events.push(xhr.readyState);
52 : 15 : actual_xhr_events.push(xhr.readyState);
53 : 6 : });
54 : 6 :
55 : 6 : const events = ['loadstart', 'progress', 'abort', 'timeout', 'error', 'load', 'loadend'];
56 : 6 :
57 [ + ][ + ]: 6 : for(let i = 0; i < events.length; ++i){
58 : 42 : xhr.addEventListener(events[i], record_xhr_event);
59 : 42 : }
60 : 6 :
61 : 6 : if('upload' in xhr){
62 [ + ][ + ]: 6 : for(let i = 0; i < events.length; ++i){
63 : 42 : xhr.upload.addEventListener(events[i], record_xhr_event);
64 : 42 : }
65 : 6 : }
66 : 6 : }
67 : 8 :
68 [ + ][ + ]: 8 : export function assert_xhr_event_order_matches(expected){
69 : 6 : let recorded = recorded_xhr_events;
70 : 6 : let lastRecordedLoaded = -1;
71 : 6 :
72 [ + ][ + ][ + ]: 6 : while(expected.length && recorded.length){
[ + ]
73 : 46 : let currentExpected = getNextEvent(expected);
74 : 46 : let currentRecorded = getNextEvent(recorded);
75 : 46 :
76 : 46 : // skip to the last progress event if we've hit one (note the next
77 : 46 : // event after a progress event should be a LOADING readystatechange,
78 : 46 : // if there are multiple progress events in a row).
79 : 46 :
80 [ + ][ + ][ + ]: 46 : while(recorded.length && currentRecorded.type == `progress` && parseInt(recorded) === 3){
[ + ][ - ]
81 : 0 :
82 : 0 : assert(typeof currentRecorded.loaded === 'number');
83 : 0 : assert(currentRecorded.loaded > lastRecordedLoaded, `progress event 'loaded' values must only increase`);
84 : 0 :
85 : 0 : lastRecordedLoaded = currentRecorded.loaded;
86 : 0 : }
87 : 46 :
88 [ + ][ + ]: 46 : if(currentRecorded.type == 'loadend'){
89 : 10 : let recordedProgressCount = 0;
90 : 10 : lastRecordedLoaded = -1;
91 : 10 : }
92 : 46 :
93 : 46 : assert(currentRecorded.str === currentExpected.str, `currentRecorded.str: ${currentRecorded.str} !== currentExpected.str: ${currentExpected.str}`);
94 : 46 : }
95 : 6 :
96 [ - ][ - ]: 6 : if(recorded.length){
97 : 0 : throw '\nUnexpected extra events: ' + recorded.join(', ');
98 : 0 : }
99 : 6 :
100 [ - ][ - ]: 6 : if(expected.length){
101 : 0 : throw '\nExpected more events: ' + expected.join(', ');
102 : 0 : }
103 : 6 : }
104 : 8 : /* node:coverage disable **
105 : 8 : export function show_xhr_events(){
106 : 8 : return actual_xhr_events;
107 : 8 : }
108 : 8 : node:coverage enable **/
109 : 8 :
110 : 8 : /*
111 : 8 : * xmlhttprequest-event-order.js
112 : 8 : *
113 : 8 :
114 : 8 : (function(global) {
115 : 8 : var recorded_xhr_events = [];
116 : 8 :
117 : 8 : function record_xhr_event(e) {
118 : 8 : var prefix = e.target instanceof XMLHttpRequestUpload ? "upload." : "";
119 : 8 : recorded_xhr_events.push((prefix || "") + e.type + "(" + e.loaded + "," + e.total + "," + e.lengthComputable + ")");
120 : 8 : }
121 : 8 :
122 : 8 : global.prepare_xhr_for_event_order_test = function(xhr) {
123 : 8 : xhr.addEventListener("readystatechange", function(e) {
124 : 8 : recorded_xhr_events.push(xhr.readyState);
125 : 8 : });
126 : 8 : var events = ["loadstart", "progress", "abort", "timeout", "error", "load", "loadend"];
127 : 8 : for(var i=0; i<events.length; ++i) {
128 : 8 : xhr.addEventListener(events[i], record_xhr_event);
129 : 8 : }
130 : 8 : if ("upload" in xhr) {
131 : 8 : for(var i=0; i<events.length; ++i) {
132 : 8 : xhr.upload.addEventListener(events[i], record_xhr_event);
133 : 8 : }
134 : 8 : }
135 : 8 : }
136 : 8 :
137 : 8 : function getNextEvent(arr) {
138 : 8 : var event = { str: arr.shift() };
139 : 8 :
140 : 8 : // we can only handle strings, numbers (readystates) and undefined
141 : 8 : if (event.str === undefined) {
142 : 8 : return event;
143 : 8 : }
144 : 8 :
145 : 8 : if (typeof event.str !== "string") {
146 : 8 : if (Number.isInteger(event.str)) {
147 : 8 : event.state = event.str;
148 : 8 : event.str = "readystatechange(" + event.str + ")";
149 : 8 : } else {
150 : 8 : throw "Test error: unexpected event type " + event.str;
151 : 8 : }
152 : 8 : }
153 : 8 :
154 : 8 : // parse out the general type, loaded and total values
155 : 8 : var type = event.type = event.str.split("(")[0].split(".").pop();
156 : 8 : var loadedAndTotal = event.str.match(/.*\((\d+),(\d+),(true|false)\)/);
157 : 8 : if (loadedAndTotal) {
158 : 8 : event.loaded = parseInt(loadedAndTotal[1]);
159 : 8 : event.total = parseInt(loadedAndTotal[2]);
160 : 8 : event.lengthComputable = loadedAndTotal[3] == "true";
161 : 8 : }
162 : 8 :
163 : 8 : return event;
164 : 8 : }
165 : 8 :
166 : 8 : global.assert_xhr_event_order_matches = function(expected) {
167 : 8 : var recorded = recorded_xhr_events;
168 : 8 : var lastRecordedLoaded = -1;
169 : 8 : while(expected.length && recorded.length) {
170 : 8 : var currentExpected = getNextEvent(expected),
171 : 8 : currentRecorded = getNextEvent(recorded);
172 : 8 :
173 : 8 : // skip to the last progress event if we've hit one (note the next
174 : 8 : // event after a progress event should be a LOADING readystatechange,
175 : 8 : // if there are multiple progress events in a row).
176 : 8 : while (recorded.length && currentRecorded.type == "progress" &&
177 : 8 : parseInt(recorded) === 3) {
178 : 8 : assert_greater_than(currentRecorded.loaded, lastRecordedLoaded,
179 : 8 : "progress event 'loaded' values must only increase");
180 : 8 : lastRecordedLoaded = currentRecorded.loaded;
181 : 8 : }
182 : 8 : if (currentRecorded.type == "loadend") {
183 : 8 : recordedProgressCount = 0;
184 : 8 : lastRecordedLoaded = -1;
185 : 8 : }
186 : 8 :
187 : 8 : assert_equals(currentRecorded.str, currentExpected.str);
188 : 8 : }
189 : 8 : if (recorded.length) {
190 : 8 : throw "\nUnexpected extra events: " + recorded.join(", ");
191 : 8 : }
192 : 8 : if (expected.length) {
193 : 8 : throw "\nExpected more events: " + expected.join(", ");
194 : 8 : }
195 : 8 : }
196 : 8 : }(this));
197 : 8 :
198 : 8 : *
199 : 8 : * xmlhttprequest-event-order.js
200 : 8 : */
|