Branch data Line data Source code
1 [ + ]: 17 : import assert from 'node:assert';
2 : 17 :
3 : 17 : const recorded_xhr_events = [];
4 : 17 : const actual_xhr_events = [];
5 : 17 :
6 [ + ]: 17 : 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 : 17 :
14 [ + ][ + ]: 17 : 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 : 17 :
48 [ + ][ + ]: 17 : 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 : 17 :
68 [ + ][ + ]: 17 : 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 : 17 :
105 : 17 : export function show_xhr_events(){
106 : 0 : return actual_xhr_events;
107 : 0 : }
108 : 17 :
109 : 17 : /*
110 : 17 : * xmlhttprequest-event-order.js
111 : 17 : *
112 : 17 :
113 : 17 : (function(global) {
114 : 17 : var recorded_xhr_events = [];
115 : 17 :
116 : 17 : function record_xhr_event(e) {
117 : 17 : var prefix = e.target instanceof XMLHttpRequestUpload ? "upload." : "";
118 : 17 : recorded_xhr_events.push((prefix || "") + e.type + "(" + e.loaded + "," + e.total + "," + e.lengthComputable + ")");
119 : 17 : }
120 : 17 :
121 : 17 : global.prepare_xhr_for_event_order_test = function(xhr) {
122 : 17 : xhr.addEventListener("readystatechange", function(e) {
123 : 17 : recorded_xhr_events.push(xhr.readyState);
124 : 17 : });
125 : 17 : var events = ["loadstart", "progress", "abort", "timeout", "error", "load", "loadend"];
126 : 17 : for(var i=0; i<events.length; ++i) {
127 : 17 : xhr.addEventListener(events[i], record_xhr_event);
128 : 17 : }
129 : 17 : if ("upload" in xhr) {
130 : 17 : for(var i=0; i<events.length; ++i) {
131 : 17 : xhr.upload.addEventListener(events[i], record_xhr_event);
132 : 17 : }
133 : 17 : }
134 : 17 : }
135 : 17 :
136 : 17 : function getNextEvent(arr) {
137 : 17 : var event = { str: arr.shift() };
138 : 17 :
139 : 17 : // we can only handle strings, numbers (readystates) and undefined
140 : 17 : if (event.str === undefined) {
141 : 17 : return event;
142 : 17 : }
143 : 17 :
144 : 17 : if (typeof event.str !== "string") {
145 : 17 : if (Number.isInteger(event.str)) {
146 : 17 : event.state = event.str;
147 : 17 : event.str = "readystatechange(" + event.str + ")";
148 : 17 : } else {
149 : 17 : throw "Test error: unexpected event type " + event.str;
150 : 17 : }
151 : 17 : }
152 : 17 :
153 : 17 : // parse out the general type, loaded and total values
154 : 17 : var type = event.type = event.str.split("(")[0].split(".").pop();
155 : 17 : var loadedAndTotal = event.str.match(/.*\((\d+),(\d+),(true|false)\)/);
156 : 17 : if (loadedAndTotal) {
157 : 17 : event.loaded = parseInt(loadedAndTotal[1]);
158 : 17 : event.total = parseInt(loadedAndTotal[2]);
159 : 17 : event.lengthComputable = loadedAndTotal[3] == "true";
160 : 17 : }
161 : 17 :
162 : 17 : return event;
163 : 17 : }
164 : 17 :
165 : 17 : global.assert_xhr_event_order_matches = function(expected) {
166 : 17 : var recorded = recorded_xhr_events;
167 : 17 : var lastRecordedLoaded = -1;
168 : 17 : while(expected.length && recorded.length) {
169 : 17 : var currentExpected = getNextEvent(expected),
170 : 17 : currentRecorded = getNextEvent(recorded);
171 : 17 :
172 : 17 : // skip to the last progress event if we've hit one (note the next
173 : 17 : // event after a progress event should be a LOADING readystatechange,
174 : 17 : // if there are multiple progress events in a row).
175 : 17 : while (recorded.length && currentRecorded.type == "progress" &&
176 : 17 : parseInt(recorded) === 3) {
177 : 17 : assert_greater_than(currentRecorded.loaded, lastRecordedLoaded,
178 : 17 : "progress event 'loaded' values must only increase");
179 : 17 : lastRecordedLoaded = currentRecorded.loaded;
180 : 17 : }
181 : 17 : if (currentRecorded.type == "loadend") {
182 : 17 : recordedProgressCount = 0;
183 : 17 : lastRecordedLoaded = -1;
184 : 17 : }
185 : 17 :
186 : 17 : assert_equals(currentRecorded.str, currentExpected.str);
187 : 17 : }
188 : 17 : if (recorded.length) {
189 : 17 : throw "\nUnexpected extra events: " + recorded.join(", ");
190 : 17 : }
191 : 17 : if (expected.length) {
192 : 17 : throw "\nExpected more events: " + expected.join(", ");
193 : 17 : }
194 : 17 : }
195 : 17 : }(this));
196 : 17 :
197 : 17 : *
198 : 17 : * xmlhttprequest-event-order.js
199 : 17 : */
|