| Index: tests/html/xhr_task_test.dart
|
| diff --git a/tests/html/xhr_task_test.dart b/tests/html/xhr_task_test.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c315ae6c9df8c9d09b644871e5ab25cc9e529f03
|
| --- /dev/null
|
| +++ b/tests/html/xhr_task_test.dart
|
| @@ -0,0 +1,508 @@
|
| +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +library XHRTaskTest;
|
| +
|
| +import 'dart:async';
|
| +import 'dart:convert';
|
| +import 'dart:html';
|
| +import 'dart:typed_data';
|
| +import 'package:unittest/html_individual_config.dart';
|
| +import 'package:unittest/unittest.dart';
|
| +
|
| +main() {
|
| + useHtmlIndividualConfiguration();
|
| +
|
| + // Cache blocker is a workaround for:
|
| + // https://code.google.com/p/dart/issues/detail?id=11834
|
| + var cacheBlocker = new DateTime.now().millisecondsSinceEpoch;
|
| + var url = '/root_dart/tests/html/xhr_cross_origin_data.txt?'
|
| + 'cacheBlock=$cacheBlocker';
|
| +
|
| + var urlExpando = new Expando();
|
| +
|
| + Function buildCreateTaskHandler(List log, List tasks) {
|
| + Object createTaskHandler(Zone self, ZoneDelegate parent, Zone zone,
|
| + TaskCreate create, TaskSpecification spec) {
|
| + if (spec is HttpRequestTaskSpecification) {
|
| + var url = spec.url;
|
| + var method = spec.method;
|
| + var withCredentials = spec.withCredentials;
|
| + var responseType = spec.responseType;
|
| + var mimeType = spec.mimeType;
|
| + var data = spec.sendData;
|
| +
|
| + log.add("request $url");
|
| + var dataLog = data is List<int> ? "binary ${data.length}" : "$data";
|
| + log.add(" method: $method withCredentials: $withCredentials "
|
| + "responseType: $responseType mimeType: $mimeType data: $dataLog");
|
| + var task = parent.createTask(zone, create, spec);
|
| + urlExpando[task] = url;
|
| + tasks.add(task);
|
| + return task;
|
| + }
|
| + if (spec is HttpRequestSendTaskSpecification) {
|
| + var data = spec.sendData;
|
| + var dataLog = data is List<int> ? "binary ${data.length}" : "$data";
|
| + log.add("http-request (no info), data: $dataLog");
|
| + var task = parent.createTask(zone, create, spec);
|
| + tasks.add(task);
|
| + urlExpando[task] = "unknown";
|
| + return task;
|
| + }
|
| + if (spec is EventSubscriptionSpecification) {
|
| + EventSubscriptionSpecification eventSpec = spec;
|
| + if (eventSpec.target is HttpRequest) {
|
| + HttpRequest target = eventSpec.target;
|
| + log.add("event listener on http-request ${eventSpec.eventType}");
|
| + if (eventSpec.eventType == "readystatechange") {
|
| + var oldOnData = eventSpec.onData;
|
| + spec = eventSpec.replace(onData: (event) {
|
| + oldOnData(event);
|
| + if (target.readyState == HttpRequest.DONE) {
|
| + log.add("unknown request done");
|
| + }
|
| + });
|
| + }
|
| + }
|
| + }
|
| + return parent.createTask(zone, create, spec);
|
| + }
|
| +
|
| + return createTaskHandler;
|
| + }
|
| +
|
| + Function buildRunTaskHandler(List log, List tasks) {
|
| + void runTaskHandler(Zone self, ZoneDelegate parent, Zone zone,
|
| + TaskRun run, Object task, Object arg) {
|
| + if (tasks.contains(task)) {
|
| + var url = urlExpando[task];
|
| + if (arg is Error || arg is Exception) {
|
| + log.add("failed $url");
|
| + } else {
|
| + if (arg is ProgressEvent) {
|
| + log.add("success $url with progress-event");
|
| + } else if (arg is HttpRequest){
|
| + log.add("success $url with http-request");
|
| + } else {
|
| + log.add("success $url (unknown arg)");
|
| + }
|
| + }
|
| + }
|
| + parent.runTask(zone, run, task, arg);
|
| + }
|
| +
|
| + return runTaskHandler;
|
| + }
|
| +
|
| + Future<List> runWithLogging(fun) async {
|
| + var log = [];
|
| + var tasks = [];
|
| + await runZoned(fun, zoneSpecification: new ZoneSpecification(
|
| + createTask: buildCreateTaskHandler(log, tasks),
|
| + runTask: buildRunTaskHandler(log, tasks)));
|
| + return log;
|
| + }
|
| +
|
| + void validate200Response(xhr) {
|
| + expect(xhr.status, equals(200));
|
| + var data = JSON.decode(xhr.responseText);
|
| + expect(data, contains('feed'));
|
| + expect(data['feed'], contains('entry'));
|
| + expect(data, isMap);
|
| + }
|
| +
|
| + void validate404(xhr) {
|
| + expect(xhr.status, equals(404));
|
| + // We cannot say much about xhr.responseText, most HTTP servers will
|
| + // include an HTML page explaining the error to a human.
|
| + String responseText = xhr.responseText;
|
| + expect(responseText, isNotNull);
|
| + }
|
| +
|
| + group('xhr', () {
|
| + test('XHR No file', () async {
|
| + var log = await runWithLogging(() {
|
| + var completer = new Completer();
|
| + HttpRequest xhr = new HttpRequest();
|
| + xhr.open("GET", "NonExistingFile", async: true);
|
| + xhr.onReadyStateChange.listen(expectAsyncUntil((event) {
|
| + if (xhr.readyState == HttpRequest.DONE) {
|
| + validate404(xhr);
|
| + completer.complete("done");
|
| + }
|
| + }, () => xhr.readyState == HttpRequest.DONE));
|
| + xhr.send();
|
| + return completer.future;
|
| + });
|
| + expect(log, equals([
|
| + 'event listener on http-request readystatechange',
|
| + 'http-request (no info), data: null',
|
| + 'unknown request done'
|
| + ]));
|
| + });
|
| +
|
| + test('XHR_file', () async {
|
| + var log = await runWithLogging(() {
|
| + var completer = new Completer();
|
| + var loadEndCalled = false;
|
| +
|
| + var xhr = new HttpRequest();
|
| + xhr.open('GET', url, async: true);
|
| + xhr.onReadyStateChange.listen(expectAsyncUntil((e) {
|
| + if (xhr.readyState == HttpRequest.DONE) {
|
| + validate200Response(xhr);
|
| +
|
| + Timer.run(expectAsync(() {
|
| + expect(loadEndCalled, HttpRequest.supportsLoadEndEvent);
|
| + completer.complete("done");
|
| + }));
|
| + }
|
| + }, () => xhr.readyState == HttpRequest.DONE));
|
| +
|
| + xhr.onLoadEnd.listen((ProgressEvent e) {
|
| + loadEndCalled = true;
|
| + });
|
| + xhr.send();
|
| + return completer.future;
|
| + });
|
| + expect(log, equals([
|
| + 'event listener on http-request readystatechange',
|
| + 'event listener on http-request loadend',
|
| + 'http-request (no info), data: null',
|
| + 'unknown request done'
|
| + ]));
|
| + });
|
| +
|
| + test('XHR.request No file', () async {
|
| + var log = await runWithLogging(() {
|
| + var completer = new Completer();
|
| + HttpRequest.request('NonExistingFile').then(
|
| + (_) { fail('Request should not have succeeded.'); },
|
| + onError: expectAsync((error) {
|
| + var xhr = error.target;
|
| + expect(xhr.readyState, equals(HttpRequest.DONE));
|
| + validate404(xhr);
|
| + completer.complete('done');
|
| + }));
|
| + return completer.future;
|
| + });
|
| + expect(log, equals([
|
| + 'request NonExistingFile',
|
| + ' method: null withCredentials: null responseType: null '
|
| + 'mimeType: null data: null',
|
| + 'event listener on http-request load',
|
| + 'event listener on http-request error',
|
| + 'success NonExistingFile with progress-event'
|
| + ]));
|
| + });
|
| +
|
| + test('XHR.request file', () async {
|
| + var log = await runWithLogging(() {
|
| + var completer = new Completer();
|
| + HttpRequest.request(url).then(expectAsync((xhr) {
|
| + expect(xhr.readyState, equals(HttpRequest.DONE));
|
| + validate200Response(xhr);
|
| + completer.complete('done');
|
| + }));
|
| + return completer.future;
|
| + });
|
| + expect(log, equals([
|
| + 'request $url',
|
| + ' method: null withCredentials: null responseType: null '
|
| + 'mimeType: null data: null',
|
| + 'event listener on http-request load',
|
| + 'event listener on http-request error',
|
| + 'success $url with http-request'
|
| + ]));
|
| + });
|
| +
|
| + test('XHR.request onProgress', () async {
|
| + var log = await runWithLogging(() {
|
| + var completer = new Completer();
|
| + var progressCalled = false;
|
| + HttpRequest.request(url,
|
| + onProgress: (_) {
|
| + progressCalled = true;
|
| + }).then(expectAsync(
|
| + (xhr) {
|
| + expect(xhr.readyState, equals(HttpRequest.DONE));
|
| + expect(progressCalled, HttpRequest.supportsProgressEvent);
|
| + validate200Response(xhr);
|
| + completer.complete("done");
|
| + }));
|
| + return completer.future;
|
| + });
|
| + expect(log, equals([
|
| + 'request $url',
|
| + ' method: null withCredentials: null responseType: null '
|
| + 'mimeType: null data: null',
|
| + 'event listener on http-request progress',
|
| + 'event listener on http-request load',
|
| + 'event listener on http-request error',
|
| + 'success $url with http-request'
|
| + ]));
|
| + });
|
| +
|
| + test('XHR.request withCredentials No file', () async {
|
| + var log = await runWithLogging(() {
|
| + var completer = new Completer();
|
| + HttpRequest.request('NonExistingFile', withCredentials: true).then(
|
| + (_) { fail('Request should not have succeeded.'); },
|
| + onError: expectAsync((error) {
|
| + var xhr = error.target;
|
| + expect(xhr.readyState, equals(HttpRequest.DONE));
|
| + validate404(xhr);
|
| + completer.complete("done");
|
| + }));
|
| + return completer.future;
|
| + });
|
| + expect(log, equals([
|
| + 'request NonExistingFile',
|
| + ' method: null withCredentials: true responseType: null '
|
| + 'mimeType: null data: null',
|
| + 'event listener on http-request load',
|
| + 'event listener on http-request error',
|
| + 'success NonExistingFile with progress-event'
|
| + ]));
|
| + });
|
| +
|
| +
|
| + test('XHR.request withCredentials file', () async {
|
| + var log = await runWithLogging(() {
|
| + var completer = new Completer();
|
| + HttpRequest.request(url, withCredentials: true).then(expectAsync((xhr) {
|
| + expect(xhr.readyState, equals(HttpRequest.DONE));
|
| + validate200Response(xhr);
|
| + completer.complete("done");
|
| + }));
|
| + return completer.future;
|
| + });
|
| + expect(log, equals([
|
| + 'request $url',
|
| + ' method: null withCredentials: true responseType: null '
|
| + 'mimeType: null data: null',
|
| + 'event listener on http-request load',
|
| + 'event listener on http-request error',
|
| + 'success $url with http-request'
|
| + ]));
|
| + });
|
| +
|
| + test('XHR.getString file', () async {
|
| + var log = await runWithLogging(() {
|
| + return HttpRequest.getString(url).then(expectAsync((str) {}));
|
| + });
|
| + expect(log, equals([
|
| + 'request $url',
|
| + ' method: null withCredentials: null responseType: null '
|
| + 'mimeType: null data: null',
|
| + 'event listener on http-request load',
|
| + 'event listener on http-request error',
|
| + 'success $url with http-request'
|
| + ]));
|
| + });
|
| +
|
| + test('XHR.getString No file', () async {
|
| + var log = await runWithLogging(() {
|
| + return HttpRequest.getString('NonExistingFile').then(
|
| + (_) { fail('Succeeded for non-existing file.'); },
|
| + onError: expectAsync((error) {
|
| + validate404(error.target);
|
| + }));
|
| + });
|
| + expect(log, equals([
|
| + 'request NonExistingFile',
|
| + ' method: null withCredentials: null responseType: null '
|
| + 'mimeType: null data: null',
|
| + 'event listener on http-request load',
|
| + 'event listener on http-request error',
|
| + 'success NonExistingFile with progress-event'
|
| + ]));
|
| + });
|
| +
|
| + test('XHR.request responseType arraybuffer', () async {
|
| + if (Platform.supportsTypedData) {
|
| + var log = await runWithLogging(() {
|
| + return HttpRequest.request(url, responseType: 'arraybuffer',
|
| + requestHeaders: {'Content-Type': 'text/xml'}).then(
|
| + expectAsync((xhr) {
|
| + expect(xhr.status, equals(200));
|
| + var byteBuffer = xhr.response;
|
| + expect(byteBuffer, new isInstanceOf<ByteBuffer>());
|
| + expect(byteBuffer, isNotNull);
|
| + }));
|
| + });
|
| + expect(log, equals([
|
| + 'request $url',
|
| + ' method: null withCredentials: null responseType: arraybuffer '
|
| + 'mimeType: null data: null',
|
| + 'event listener on http-request load',
|
| + 'event listener on http-request error',
|
| + 'success $url with http-request'
|
| + ]));
|
| + };
|
| + });
|
| +
|
| + test('overrideMimeType', () async {
|
| + var expectation =
|
| + HttpRequest.supportsOverrideMimeType ? returnsNormally : throws;
|
| +
|
| + var log = await runWithLogging(() {
|
| + var completer = new Completer();
|
| + expect(() {
|
| + HttpRequest.request(url, mimeType: 'application/binary')
|
| + .whenComplete(completer.complete);
|
| + }, expectation);
|
| + return completer.future;
|
| + });
|
| + expect(log, equals([
|
| + 'request $url',
|
| + ' method: null withCredentials: null responseType: null '
|
| + 'mimeType: application/binary data: null',
|
| + 'event listener on http-request load',
|
| + 'event listener on http-request error',
|
| + 'success $url with http-request'
|
| + ]));
|
| + });
|
| +
|
| + if (Platform.supportsTypedData) {
|
| + test('xhr upload', () async {
|
| + var log = await runWithLogging(() {
|
| + var xhr = new HttpRequest();
|
| + var progressCalled = false;
|
| + xhr.upload.onProgress.listen((e) {
|
| + progressCalled = true;
|
| + });
|
| +
|
| + xhr.open('POST',
|
| + '${window.location.protocol}//${window.location.host}/echo');
|
| +
|
| + // 10MB of payload data w/ a bit of data to make sure it
|
| + // doesn't get compressed to nil.
|
| + var data = new Uint8List(1 * 1024 * 1024);
|
| + for (var i = 0; i < data.length; ++i) {
|
| + data[i] = i & 0xFF;
|
| + }
|
| + xhr.send(new Uint8List.view(data.buffer));
|
| +
|
| + return xhr.onLoad.first.then((_) {
|
| + expect(
|
| + progressCalled, isTrue, reason: 'onProgress should be fired');
|
| + });
|
| + });
|
| + expect(log, equals([
|
| + 'http-request (no info), data: binary 1048576',
|
| + 'event listener on http-request load',
|
| + ]));
|
| + });
|
| + }
|
| +
|
| + test('xhr postFormData', () async {
|
| + var url = '${window.location.protocol}//${window.location.host}/echo';
|
| + var log = await runWithLogging(() {
|
| + var data = { 'name': 'John', 'time': '2 pm'};
|
| +
|
| + var parts = [];
|
| + for (var key in data.keys) {
|
| + parts.add('${Uri.encodeQueryComponent(key)}='
|
| + '${Uri.encodeQueryComponent(data[key])}');
|
| + }
|
| + var encodedData = parts.join('&');
|
| +
|
| + return HttpRequest.postFormData(url, data).then((xhr) {
|
| + expect(xhr.responseText, encodedData);
|
| + });
|
| + });
|
| + expect(log, equals([
|
| + 'request $url',
|
| + ' method: POST withCredentials: null responseType: null '
|
| + 'mimeType: null data: name=John&time=2+pm',
|
| + 'event listener on http-request load',
|
| + 'event listener on http-request error',
|
| + 'success $url with http-request'
|
| + ]));
|
| + });
|
| + });
|
| +
|
| + group('xhr_requestBlob', () {
|
| + test('XHR.request responseType blob', () async {
|
| + if (Platform.supportsTypedData) {
|
| + var log = await runWithLogging(() {
|
| + return HttpRequest.request(url, responseType: 'blob').then(
|
| + (xhr) {
|
| + expect(xhr.status, equals(200));
|
| + var blob = xhr.response;
|
| + expect(blob is Blob, isTrue);
|
| + expect(blob, isNotNull);
|
| + });
|
| + });
|
| + expect(log, equals([
|
| + 'request $url',
|
| + ' method: null withCredentials: null responseType: blob '
|
| + 'mimeType: null data: null',
|
| + 'event listener on http-request load',
|
| + 'event listener on http-request error',
|
| + 'success $url with http-request'
|
| + ]));
|
| + }
|
| + });
|
| + });
|
| +
|
| + group('json', () {
|
| + test('xhr responseType json', () async {
|
| + var url = '${window.location.protocol}//${window.location.host}/echo';
|
| + var log = await runWithLogging(() {
|
| + var completer = new Completer();
|
| + var data = {
|
| + 'key': 'value',
|
| + 'a': 'b',
|
| + 'one': 2,
|
| + };
|
| +
|
| + HttpRequest.request(url,
|
| + method: 'POST',
|
| + sendData: JSON.encode(data),
|
| + responseType: 'json').then(
|
| + expectAsync((xhr) {
|
| + expect(xhr.status, equals(200));
|
| + var json = xhr.response;
|
| + expect(json, equals(data));
|
| + completer.complete("done");
|
| + }));
|
| + return completer.future;
|
| + });
|
| + expect(log, equals([
|
| + 'request $url',
|
| + ' method: POST withCredentials: null responseType: json mimeType: null'
|
| + ' data: {"key":"value","a":"b","one":2}',
|
| + 'event listener on http-request load',
|
| + 'event listener on http-request error',
|
| + 'success $url with http-request'
|
| + ]));
|
| + });
|
| + });
|
| +
|
| + group('headers', () {
|
| + test('xhr responseHeaders', () async {
|
| + var log = await runWithLogging(() {
|
| + return HttpRequest.request(url).then(
|
| + (xhr) {
|
| + var contentTypeHeader = xhr.responseHeaders['content-type'];
|
| + expect(contentTypeHeader, isNotNull);
|
| + // Should be like: 'text/plain; charset=utf-8'
|
| + expect(contentTypeHeader.contains('text/plain'), isTrue);
|
| + expect(contentTypeHeader.contains('charset=utf-8'), isTrue);
|
| + });
|
| + });
|
| + expect(log, equals([
|
| + 'request $url',
|
| + ' method: null withCredentials: null responseType: null'
|
| + ' mimeType: null data: null',
|
| + 'event listener on http-request load',
|
| + 'event listener on http-request error',
|
| + 'success $url with http-request'
|
| + ]));
|
| + });
|
| + });
|
| +}
|
|
|