content/base/test/test_xhr_progressevents.html

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:b5615c6d5608
1 <!DOCTYPE HTML>
2 <html>
3 <head>
4 <title>Test for XMLHttpRequest Progress Events</title>
5 <script type="text/javascript" src="/MochiKit/packed.js"></script>
6 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
7 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
8 </head>
9 <body onload="gen.next();">
10 <pre id=l></pre>
11 <script type="application/javascript;version=1.7">
12 SimpleTest.waitForExplicitFinish();
13
14 var gen = runTests();
15
16 function log(s) {
17 // Uncomment these to get debugging information
18 /*
19 document.getElementById("l").textContent += s + "\n";
20 dump(s + "\n");
21 */
22 }
23
24 function getEvent(e) {
25 log("got event: " + e.type + " (" + e.target.readyState + ")");
26 gen.send(e);
27 }
28
29 function startsWith(a, b) {
30 return a.substr(0, b.length) === b;
31 }
32
33 function updateProgress(e, data, testName) {
34 var test = " while running " + testName;
35 is(e.type, "progress", "event type" + test);
36
37 let response;
38 if (data.nodata) {
39 is(e.target.response, null, "response should be null" + test);
40 response = null;
41 }
42 else if (data.text) {
43 is(typeof e.target.response, "string", "response should be a string" + test);
44 response = e.target.response;
45 }
46 else if (data.blob) {
47 ok(e.target.response instanceof Blob, "response should be a Blob" + test);
48 response = e.target.response;
49 }
50 else {
51 ok(e.target.response instanceof ArrayBuffer, "response should be an ArrayBuffer" + test);
52 response = bufferToString(e.target.response);
53 }
54 is(e.target.response, e.target.response, "reflexivity should hold" + test);
55
56 if (!data.nodata && !data.encoded) {
57 if (data.blob) {
58 is(e.loaded, response.size, "event.loaded matches response size" + test);
59 }
60 else if (!data.chunked) {
61 is(e.loaded, response.length, "event.loaded matches response size" + test);
62 }
63 else {
64 is(e.loaded - data.receivedBytes, response.length,
65 "event.loaded grew by response size" + test);
66 }
67 }
68 ok(e.loaded > data.receivedBytes, "event.loaded increased" + test);
69 ok(e.loaded - data.receivedBytes <= data.pendingBytes,
70 "event.loaded didn't increase too much" + test);
71
72 if (!data.nodata && !data.blob) {
73 var newData;
74 ok(startsWith(response, data.receivedResult),
75 "response strictly grew" + test);
76 newData = response.substr(data.receivedResult.length);
77
78 if (!data.encoded) {
79 ok(newData.length > 0, "sanity check for progress" + test);
80 }
81 ok(startsWith(data.pendingResult, newData), "new data matches expected" + test);
82 }
83
84 is(e.lengthComputable, "total" in data, "lengthComputable" + test);
85 if ("total" in data) {
86 is(e.total, data.total, "total" + test);
87 }
88
89 if (!data.nodata && !data.blob) {
90 data.pendingResult = data.pendingResult.substr(newData.length);
91 }
92 data.pendingBytes -= e.loaded - data.receivedBytes;
93 data.receivedResult = response;
94 data.receivedBytes = e.loaded;
95 }
96
97 function sendData(s) {
98 var xhr = new XMLHttpRequest();
99 xhr.open("POST", "progressserver.sjs?send");
100 xhr.sendAsBinary(s);
101 }
102
103 function closeConn() {
104 log("in closeConn");
105 var xhr = new XMLHttpRequest();
106 xhr.open("POST", "progressserver.sjs?close");
107 xhr.send();
108 return xhr;
109 }
110
111 var longString = "long";
112 while(longString.length < 65536)
113 longString += longString;
114
115 function utf8encode(s) {
116 return unescape(encodeURIComponent(s));
117 }
118
119 function bufferToString(buffer) {
120 return String.fromCharCode.apply(String, new Uint8Array(buffer));
121 }
122
123 function runTests() {
124 var xhr = new XMLHttpRequest();
125 xhr.onprogress = xhr.onload = xhr.onerror = xhr.onreadystatechange = xhr.onloadend = getEvent;
126
127 var responseTypes = [{ type: "text", text: true },
128 { type: "arraybuffer", text: false, nodata: true },
129 { type: "blob", text: false, nodata: true, blob: true },
130 { type: "moz-blob", text: false, nodata: false, blob: true },
131 { type: "document", text: true, nodata: true },
132 { type: "json", text: true, nodata: true },
133 { type: "", text: true },
134 { type: "moz-chunked-text", text: true, chunked: true },
135 { type: "moz-chunked-arraybuffer", text: false, chunked: true },
136 ];
137 var responseType;
138 var fileExpectedResult = "";
139 for (var i = 0; i < 65536; i++) {
140 fileExpectedResult += String.fromCharCode(i & 255);
141 }
142 while (responseType = responseTypes.shift()) {
143 let tests = [{ open: "Content-Type=text/plain", name: "simple test" },
144 { data: "hello world" },
145 { data: "\u0000\u0001\u0002\u0003" },
146 { data: longString },
147 { data: "x" },
148 { close: true },
149 { open: "Content-Type=text/plain&Content-Length=20", name: "with length", total: 20 },
150 // 5 bytes from the "ready" in the open step
151 { data: "abcde" },
152 { data: "0123456789" },
153 { close: true },
154 { open: "Content-Type=application/xml", name: "without length, as xml" },
155 { data: "<out>" },
156 { data: "text" },
157 { data: "</foo>invalid" },
158 { close: true },
159 { open: "Content-Type=text/plain;charset%3dutf-8", name: "utf8 data", encoded: true },
160 { data: utf8encode("räksmörgås"), utf16: "räksmörgås" },
161 { data: utf8encode("Å").substr(0,1), utf16: "" },
162 { data: utf8encode("Å").substr(1), utf16: "Å" },
163 { data: utf8encode("aöb").substr(0,2), utf16: "a" },
164 { data: utf8encode("aöb").substr(2), utf16: "öb" },
165 { data: utf8encode("a\u867Eb").substr(0,3), utf16: "a" },
166 { data: utf8encode("a\u867Eb").substr(3,1), utf16: "\u867E" },
167 { data: utf8encode("a\u867Eb").substr(4), utf16: "b" },
168 { close: true },
169 ];
170 if (responseType.blob) {
171 tests.push({ file: "file_XHR_binary2.bin", name: "cacheable data", total: 65536 },
172 { close: true },
173 { file: "file_XHR_binary2.bin", name: "cached data", total: 65536 },
174 { close: true });
175 }
176 let testState = { index: 0 };
177
178 for (let i = 0; i < tests.length; ++i) {
179 let test = tests[i];
180 testState.index++;
181 if ("open" in test || "file" in test) {
182 log("opening " + testState.name);
183 testState = { name: test.name + " for " + responseType.type,
184 index: 0,
185 pendingResult: "ready",
186 pendingBytes: 5,
187 receivedResult: "",
188 receivedBytes: 0,
189 total: test.total,
190 encoded: test.encoded,
191 nodata: responseType.nodata,
192 chunked: responseType.chunked,
193 text: responseType.text,
194 blob: responseType.blob,
195 file: test.file };
196
197 xhr.onreadystatechange = null;
198 if (testState.file)
199 xhr.open("GET", test.file);
200 else
201 xhr.open("POST", "progressserver.sjs?open&" + test.open);
202 xhr.responseType = responseType.type;
203 xhr.send("ready");
204 xhr.onreadystatechange = getEvent;
205
206 let e = yield undefined;
207 is(e.type, "readystatechange", "should readystate to headers-received starting " + testState.name);
208 is(xhr.readyState, xhr.HEADERS_RECEIVED, "should be in state HEADERS_RECEIVED starting " + testState.name);
209
210 e = yield undefined;
211 is(e.type, "readystatechange", "should readystate to loading starting " + testState.name);
212 is(xhr.readyState, xhr.LOADING, "should be in state LOADING starting " + testState.name);
213 if (typeof testState.total == "undefined")
214 delete testState.total;
215 }
216 if ("file" in test) {
217 testState.pendingBytes = testState.total;
218 testState.pendingResult = fileExpectedResult;
219 }
220 if ("close" in test) {
221 log("closing");
222 let xhrClose;
223 if (!testState.file)
224 xhrClose = closeConn();
225
226 e = yield undefined;
227 is(e.type, "readystatechange", "should readystate to done closing " + testState.name);
228 is(xhr.readyState, xhr.DONE, "should be in state DONE closing " + testState.name);
229 log("readystate to 4");
230
231 if (responseType.chunked) {
232 xhr.responseType;
233 is(xhr.response, null, "chunked data has null response for " + testState.name);
234 }
235
236 e = yield undefined;
237 is(e.type, "load", "should fire load closing " + testState.name);
238 is(e.lengthComputable, true, "length should be computable during load closing " + testState.name);
239 log("got load");
240
241 if (responseType.chunked) {
242 is(xhr.response, null, "chunked data has null response for " + testState.name);
243 }
244
245 e = yield undefined;
246 is(e.type, "loadend", "should fire loadend closing " + testState.name);
247 is(e.lengthComputable, true, "length should be computable during loadend closing " + testState.name);
248 log("got loadend");
249
250 // if we closed the connection using an explicit request, make sure that goes through before
251 // running the next test in order to avoid reordered requests from closing the wrong
252 // connection.
253 if (xhrClose && xhrClose.readyState != xhrClose.DONE) {
254 log("wait for closeConn to finish");
255 xhrClose.onloadend = getEvent;
256 yield undefined;
257 is(xhrClose.readyState, xhrClose.DONE, "closeConn finished");
258 }
259
260 if (responseType.chunked) {
261 is(xhr.response, null, "chunked data has null response for " + testState.name);
262 }
263
264 if (!testState.nodata && !responseType.blob || responseType.chunked) {
265 // This branch intentionally left blank
266 // Under these conditions we check the response during updateProgress
267 }
268 else if (responseType.type === "arraybuffer") {
269 is(bufferToString(xhr.response), testState.pendingResult,
270 "full response for " + testState.name);
271 }
272 else if (responseType.blob) {
273 let reader = new FileReader;
274 reader.readAsBinaryString(xhr.response);
275 reader.onloadend = getEvent;
276 yield undefined;
277
278 is(reader.result, testState.pendingResult,
279 "full response in blob for " + testState.name);
280 }
281
282 testState.name = "";
283 }
284 if ("data" in test) {
285 log("sending");
286 if (responseType.text) {
287 testState.pendingResult += "utf16" in test ? test.utf16 : test.data;
288 }
289 else {
290 testState.pendingResult += test.data;
291 }
292 testState.pendingBytes = test.data.length;
293 sendData(test.data);
294 }
295
296 while(testState.pendingBytes) {
297 log("waiting for more bytes: " + testState.pendingBytes);
298 e = yield undefined;
299 // Readystate can fire several times between each progress event.
300 if (e.type === "readystatechange")
301 continue;
302
303 updateProgress(e, testState, "data for " + testState.name + "[" + testState.index + "]");
304 if (responseType.chunked) {
305 testState.receivedResult = "";
306 }
307 }
308
309 if (!testState.nodata && !testState.blob) {
310 is(testState.pendingResult, "",
311 "should have consumed the expected result");
312 }
313
314 log("done with this test");
315 }
316
317 is(testState.name, "", "forgot to close last test");
318 }
319
320 SimpleTest.finish();
321 yield undefined;
322 }
323
324 </script>
325
326 </body>
327 </html>

mercurial