OLD | NEW |
| (Empty) |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library XHRTaskTest; | |
6 | |
7 import 'dart:async'; | |
8 import 'dart:convert'; | |
9 import 'dart:html'; | |
10 import 'dart:typed_data'; | |
11 import 'package:unittest/html_individual_config.dart'; | |
12 import 'package:unittest/unittest.dart'; | |
13 | |
14 main() { | |
15 useHtmlIndividualConfiguration(); | |
16 | |
17 // Cache blocker is a workaround for: | |
18 // https://code.google.com/p/dart/issues/detail?id=11834 | |
19 var cacheBlocker = new DateTime.now().millisecondsSinceEpoch; | |
20 var url = '/root_dart/tests/html/xhr_cross_origin_data.txt?' | |
21 'cacheBlock=$cacheBlocker'; | |
22 | |
23 var urlExpando = new Expando(); | |
24 | |
25 Function buildCreateTaskHandler(List log, List tasks) { | |
26 Object createTaskHandler(Zone self, ZoneDelegate parent, Zone zone, | |
27 TaskCreate create, TaskSpecification spec) { | |
28 if (spec is HttpRequestTaskSpecification) { | |
29 var url = spec.url; | |
30 var method = spec.method; | |
31 var withCredentials = spec.withCredentials; | |
32 var responseType = spec.responseType; | |
33 var mimeType = spec.mimeType; | |
34 var data = spec.sendData; | |
35 | |
36 log.add("request $url"); | |
37 var dataLog = data is List<int> ? "binary ${data.length}" : "$data"; | |
38 log.add(" method: $method withCredentials: $withCredentials " | |
39 "responseType: $responseType mimeType: $mimeType data: $dataLog"); | |
40 var task = parent.createTask(zone, create, spec); | |
41 urlExpando[task] = url; | |
42 tasks.add(task); | |
43 return task; | |
44 } | |
45 if (spec is HttpRequestSendTaskSpecification) { | |
46 var data = spec.sendData; | |
47 var dataLog = data is List<int> ? "binary ${data.length}" : "$data"; | |
48 log.add("http-request (no info), data: $dataLog"); | |
49 var task = parent.createTask(zone, create, spec); | |
50 tasks.add(task); | |
51 urlExpando[task] = "unknown"; | |
52 return task; | |
53 } | |
54 if (spec is EventSubscriptionSpecification) { | |
55 EventSubscriptionSpecification eventSpec = spec; | |
56 if (eventSpec.target is HttpRequest) { | |
57 HttpRequest target = eventSpec.target; | |
58 log.add("event listener on http-request ${eventSpec.eventType}"); | |
59 if (eventSpec.eventType == "readystatechange") { | |
60 var oldOnData = eventSpec.onData; | |
61 spec = eventSpec.replace(onData: (event) { | |
62 oldOnData(event); | |
63 if (target.readyState == HttpRequest.DONE) { | |
64 log.add("unknown request done"); | |
65 } | |
66 }); | |
67 } | |
68 } | |
69 } | |
70 return parent.createTask(zone, create, spec); | |
71 } | |
72 | |
73 return createTaskHandler; | |
74 } | |
75 | |
76 Function buildRunTaskHandler(List log, List tasks) { | |
77 void runTaskHandler(Zone self, ZoneDelegate parent, Zone zone, | |
78 TaskRun run, Object task, Object arg) { | |
79 if (tasks.contains(task)) { | |
80 var url = urlExpando[task]; | |
81 if (arg is Error || arg is Exception) { | |
82 log.add("failed $url"); | |
83 } else { | |
84 if (arg is ProgressEvent) { | |
85 log.add("success $url with progress-event"); | |
86 } else if (arg is HttpRequest){ | |
87 log.add("success $url with http-request"); | |
88 } else { | |
89 log.add("success $url (unknown arg)"); | |
90 } | |
91 } | |
92 } | |
93 parent.runTask(zone, run, task, arg); | |
94 } | |
95 | |
96 return runTaskHandler; | |
97 } | |
98 | |
99 Future<List> runWithLogging(fun) async { | |
100 var log = []; | |
101 var tasks = []; | |
102 await runZoned(fun, zoneSpecification: new ZoneSpecification( | |
103 createTask: buildCreateTaskHandler(log, tasks), | |
104 runTask: buildRunTaskHandler(log, tasks))); | |
105 return log; | |
106 } | |
107 | |
108 void validate200Response(xhr) { | |
109 expect(xhr.status, equals(200)); | |
110 var data = JSON.decode(xhr.responseText); | |
111 expect(data, contains('feed')); | |
112 expect(data['feed'], contains('entry')); | |
113 expect(data, isMap); | |
114 } | |
115 | |
116 void validate404(xhr) { | |
117 expect(xhr.status, equals(404)); | |
118 // We cannot say much about xhr.responseText, most HTTP servers will | |
119 // include an HTML page explaining the error to a human. | |
120 String responseText = xhr.responseText; | |
121 expect(responseText, isNotNull); | |
122 } | |
123 | |
124 group('xhr', () { | |
125 test('XHR No file', () async { | |
126 var log = await runWithLogging(() { | |
127 var completer = new Completer(); | |
128 HttpRequest xhr = new HttpRequest(); | |
129 xhr.open("GET", "NonExistingFile", async: true); | |
130 xhr.onReadyStateChange.listen(expectAsyncUntil((event) { | |
131 if (xhr.readyState == HttpRequest.DONE) { | |
132 validate404(xhr); | |
133 completer.complete("done"); | |
134 } | |
135 }, () => xhr.readyState == HttpRequest.DONE)); | |
136 xhr.send(); | |
137 return completer.future; | |
138 }); | |
139 expect(log, equals([ | |
140 'event listener on http-request readystatechange', | |
141 'http-request (no info), data: null', | |
142 'unknown request done' | |
143 ])); | |
144 }); | |
145 | |
146 test('XHR_file', () async { | |
147 var log = await runWithLogging(() { | |
148 var completer = new Completer(); | |
149 var loadEndCalled = false; | |
150 | |
151 var xhr = new HttpRequest(); | |
152 xhr.open('GET', url, async: true); | |
153 xhr.onReadyStateChange.listen(expectAsyncUntil((e) { | |
154 if (xhr.readyState == HttpRequest.DONE) { | |
155 validate200Response(xhr); | |
156 | |
157 Timer.run(expectAsync(() { | |
158 expect(loadEndCalled, HttpRequest.supportsLoadEndEvent); | |
159 completer.complete("done"); | |
160 })); | |
161 } | |
162 }, () => xhr.readyState == HttpRequest.DONE)); | |
163 | |
164 xhr.onLoadEnd.listen((ProgressEvent e) { | |
165 loadEndCalled = true; | |
166 }); | |
167 xhr.send(); | |
168 return completer.future; | |
169 }); | |
170 expect(log, equals([ | |
171 'event listener on http-request readystatechange', | |
172 'event listener on http-request loadend', | |
173 'http-request (no info), data: null', | |
174 'unknown request done' | |
175 ])); | |
176 }); | |
177 | |
178 test('XHR.request No file', () async { | |
179 var log = await runWithLogging(() { | |
180 var completer = new Completer(); | |
181 HttpRequest.request('NonExistingFile').then( | |
182 (_) { fail('Request should not have succeeded.'); }, | |
183 onError: expectAsync((error) { | |
184 var xhr = error.target; | |
185 expect(xhr.readyState, equals(HttpRequest.DONE)); | |
186 validate404(xhr); | |
187 completer.complete('done'); | |
188 })); | |
189 return completer.future; | |
190 }); | |
191 expect(log, equals([ | |
192 'request NonExistingFile', | |
193 ' method: null withCredentials: null responseType: null ' | |
194 'mimeType: null data: null', | |
195 'event listener on http-request load', | |
196 'event listener on http-request error', | |
197 'success NonExistingFile with progress-event' | |
198 ])); | |
199 }); | |
200 | |
201 test('XHR.request file', () async { | |
202 var log = await runWithLogging(() { | |
203 var completer = new Completer(); | |
204 HttpRequest.request(url).then(expectAsync((xhr) { | |
205 expect(xhr.readyState, equals(HttpRequest.DONE)); | |
206 validate200Response(xhr); | |
207 completer.complete('done'); | |
208 })); | |
209 return completer.future; | |
210 }); | |
211 expect(log, equals([ | |
212 'request $url', | |
213 ' method: null withCredentials: null responseType: null ' | |
214 'mimeType: null data: null', | |
215 'event listener on http-request load', | |
216 'event listener on http-request error', | |
217 'success $url with http-request' | |
218 ])); | |
219 }); | |
220 | |
221 test('XHR.request onProgress', () async { | |
222 var log = await runWithLogging(() { | |
223 var completer = new Completer(); | |
224 var progressCalled = false; | |
225 HttpRequest.request(url, | |
226 onProgress: (_) { | |
227 progressCalled = true; | |
228 }).then(expectAsync( | |
229 (xhr) { | |
230 expect(xhr.readyState, equals(HttpRequest.DONE)); | |
231 expect(progressCalled, HttpRequest.supportsProgressEvent); | |
232 validate200Response(xhr); | |
233 completer.complete("done"); | |
234 })); | |
235 return completer.future; | |
236 }); | |
237 expect(log, equals([ | |
238 'request $url', | |
239 ' method: null withCredentials: null responseType: null ' | |
240 'mimeType: null data: null', | |
241 'event listener on http-request progress', | |
242 'event listener on http-request load', | |
243 'event listener on http-request error', | |
244 'success $url with http-request' | |
245 ])); | |
246 }); | |
247 | |
248 test('XHR.request withCredentials No file', () async { | |
249 var log = await runWithLogging(() { | |
250 var completer = new Completer(); | |
251 HttpRequest.request('NonExistingFile', withCredentials: true).then( | |
252 (_) { fail('Request should not have succeeded.'); }, | |
253 onError: expectAsync((error) { | |
254 var xhr = error.target; | |
255 expect(xhr.readyState, equals(HttpRequest.DONE)); | |
256 validate404(xhr); | |
257 completer.complete("done"); | |
258 })); | |
259 return completer.future; | |
260 }); | |
261 expect(log, equals([ | |
262 'request NonExistingFile', | |
263 ' method: null withCredentials: true responseType: null ' | |
264 'mimeType: null data: null', | |
265 'event listener on http-request load', | |
266 'event listener on http-request error', | |
267 'success NonExistingFile with progress-event' | |
268 ])); | |
269 }); | |
270 | |
271 | |
272 test('XHR.request withCredentials file', () async { | |
273 var log = await runWithLogging(() { | |
274 var completer = new Completer(); | |
275 HttpRequest.request(url, withCredentials: true).then(expectAsync((xhr) { | |
276 expect(xhr.readyState, equals(HttpRequest.DONE)); | |
277 validate200Response(xhr); | |
278 completer.complete("done"); | |
279 })); | |
280 return completer.future; | |
281 }); | |
282 expect(log, equals([ | |
283 'request $url', | |
284 ' method: null withCredentials: true responseType: null ' | |
285 'mimeType: null data: null', | |
286 'event listener on http-request load', | |
287 'event listener on http-request error', | |
288 'success $url with http-request' | |
289 ])); | |
290 }); | |
291 | |
292 test('XHR.getString file', () async { | |
293 var log = await runWithLogging(() { | |
294 return HttpRequest.getString(url).then(expectAsync((str) {})); | |
295 }); | |
296 expect(log, equals([ | |
297 'request $url', | |
298 ' method: null withCredentials: null responseType: null ' | |
299 'mimeType: null data: null', | |
300 'event listener on http-request load', | |
301 'event listener on http-request error', | |
302 'success $url with http-request' | |
303 ])); | |
304 }); | |
305 | |
306 test('XHR.getString No file', () async { | |
307 var log = await runWithLogging(() { | |
308 return HttpRequest.getString('NonExistingFile').then( | |
309 (_) { fail('Succeeded for non-existing file.'); }, | |
310 onError: expectAsync((error) { | |
311 validate404(error.target); | |
312 })); | |
313 }); | |
314 expect(log, equals([ | |
315 'request NonExistingFile', | |
316 ' method: null withCredentials: null responseType: null ' | |
317 'mimeType: null data: null', | |
318 'event listener on http-request load', | |
319 'event listener on http-request error', | |
320 'success NonExistingFile with progress-event' | |
321 ])); | |
322 }); | |
323 | |
324 test('XHR.request responseType arraybuffer', () async { | |
325 if (Platform.supportsTypedData) { | |
326 var log = await runWithLogging(() { | |
327 return HttpRequest.request(url, responseType: 'arraybuffer', | |
328 requestHeaders: {'Content-Type': 'text/xml'}).then( | |
329 expectAsync((xhr) { | |
330 expect(xhr.status, equals(200)); | |
331 var byteBuffer = xhr.response; | |
332 expect(byteBuffer, new isInstanceOf<ByteBuffer>()); | |
333 expect(byteBuffer, isNotNull); | |
334 })); | |
335 }); | |
336 expect(log, equals([ | |
337 'request $url', | |
338 ' method: null withCredentials: null responseType: arraybuffer ' | |
339 'mimeType: null data: null', | |
340 'event listener on http-request load', | |
341 'event listener on http-request error', | |
342 'success $url with http-request' | |
343 ])); | |
344 }; | |
345 }); | |
346 | |
347 test('overrideMimeType', () async { | |
348 var expectation = | |
349 HttpRequest.supportsOverrideMimeType ? returnsNormally : throws; | |
350 | |
351 var log = await runWithLogging(() { | |
352 var completer = new Completer(); | |
353 expect(() { | |
354 HttpRequest.request(url, mimeType: 'application/binary') | |
355 .whenComplete(completer.complete); | |
356 }, expectation); | |
357 return completer.future; | |
358 }); | |
359 expect(log, equals([ | |
360 'request $url', | |
361 ' method: null withCredentials: null responseType: null ' | |
362 'mimeType: application/binary data: null', | |
363 'event listener on http-request load', | |
364 'event listener on http-request error', | |
365 'success $url with http-request' | |
366 ])); | |
367 }); | |
368 | |
369 if (Platform.supportsTypedData) { | |
370 test('xhr upload', () async { | |
371 var log = await runWithLogging(() { | |
372 var xhr = new HttpRequest(); | |
373 var progressCalled = false; | |
374 xhr.upload.onProgress.listen((e) { | |
375 progressCalled = true; | |
376 }); | |
377 | |
378 xhr.open('POST', | |
379 '${window.location.protocol}//${window.location.host}/echo'); | |
380 | |
381 // 10MB of payload data w/ a bit of data to make sure it | |
382 // doesn't get compressed to nil. | |
383 var data = new Uint8List(1 * 1024 * 1024); | |
384 for (var i = 0; i < data.length; ++i) { | |
385 data[i] = i & 0xFF; | |
386 } | |
387 xhr.send(new Uint8List.view(data.buffer)); | |
388 | |
389 return xhr.onLoad.first.then((_) { | |
390 expect( | |
391 progressCalled, isTrue, reason: 'onProgress should be fired'); | |
392 }); | |
393 }); | |
394 expect(log, equals([ | |
395 'http-request (no info), data: binary 1048576', | |
396 'event listener on http-request load', | |
397 ])); | |
398 }); | |
399 } | |
400 | |
401 test('xhr postFormData', () async { | |
402 var url = '${window.location.protocol}//${window.location.host}/echo'; | |
403 var log = await runWithLogging(() { | |
404 var data = { 'name': 'John', 'time': '2 pm'}; | |
405 | |
406 var parts = []; | |
407 for (var key in data.keys) { | |
408 parts.add('${Uri.encodeQueryComponent(key)}=' | |
409 '${Uri.encodeQueryComponent(data[key])}'); | |
410 } | |
411 var encodedData = parts.join('&'); | |
412 | |
413 return HttpRequest.postFormData(url, data).then((xhr) { | |
414 expect(xhr.responseText, encodedData); | |
415 }); | |
416 }); | |
417 expect(log, equals([ | |
418 'request $url', | |
419 ' method: POST withCredentials: null responseType: null ' | |
420 'mimeType: null data: name=John&time=2+pm', | |
421 'event listener on http-request load', | |
422 'event listener on http-request error', | |
423 'success $url with http-request' | |
424 ])); | |
425 }); | |
426 }); | |
427 | |
428 group('xhr_requestBlob', () { | |
429 test('XHR.request responseType blob', () async { | |
430 if (Platform.supportsTypedData) { | |
431 var log = await runWithLogging(() { | |
432 return HttpRequest.request(url, responseType: 'blob').then( | |
433 (xhr) { | |
434 expect(xhr.status, equals(200)); | |
435 var blob = xhr.response; | |
436 expect(blob is Blob, isTrue); | |
437 expect(blob, isNotNull); | |
438 }); | |
439 }); | |
440 expect(log, equals([ | |
441 'request $url', | |
442 ' method: null withCredentials: null responseType: blob ' | |
443 'mimeType: null data: null', | |
444 'event listener on http-request load', | |
445 'event listener on http-request error', | |
446 'success $url with http-request' | |
447 ])); | |
448 } | |
449 }); | |
450 }); | |
451 | |
452 group('json', () { | |
453 test('xhr responseType json', () async { | |
454 var url = '${window.location.protocol}//${window.location.host}/echo'; | |
455 var log = await runWithLogging(() { | |
456 var completer = new Completer(); | |
457 var data = { | |
458 'key': 'value', | |
459 'a': 'b', | |
460 'one': 2, | |
461 }; | |
462 | |
463 HttpRequest.request(url, | |
464 method: 'POST', | |
465 sendData: JSON.encode(data), | |
466 responseType: 'json').then( | |
467 expectAsync((xhr) { | |
468 expect(xhr.status, equals(200)); | |
469 var json = xhr.response; | |
470 expect(json, equals(data)); | |
471 completer.complete("done"); | |
472 })); | |
473 return completer.future; | |
474 }); | |
475 expect(log, equals([ | |
476 'request $url', | |
477 ' method: POST withCredentials: null responseType: json mimeType: null' | |
478 ' data: {"key":"value","a":"b","one":2}', | |
479 'event listener on http-request load', | |
480 'event listener on http-request error', | |
481 'success $url with http-request' | |
482 ])); | |
483 }); | |
484 }); | |
485 | |
486 group('headers', () { | |
487 test('xhr responseHeaders', () async { | |
488 var log = await runWithLogging(() { | |
489 return HttpRequest.request(url).then( | |
490 (xhr) { | |
491 var contentTypeHeader = xhr.responseHeaders['content-type']; | |
492 expect(contentTypeHeader, isNotNull); | |
493 // Should be like: 'text/plain; charset=utf-8' | |
494 expect(contentTypeHeader.contains('text/plain'), isTrue); | |
495 expect(contentTypeHeader.contains('charset=utf-8'), isTrue); | |
496 }); | |
497 }); | |
498 expect(log, equals([ | |
499 'request $url', | |
500 ' method: null withCredentials: null responseType: null' | |
501 ' mimeType: null data: null', | |
502 'event listener on http-request load', | |
503 'event listener on http-request error', | |
504 'success $url with http-request' | |
505 ])); | |
506 }); | |
507 }); | |
508 } | |
OLD | NEW |