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 XHRTask2Test; | |
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 class MockProgressEvent implements ProgressEvent { | |
15 final target; | |
16 MockProgressEvent(this.target); | |
17 | |
18 noSuchMethod(Invocation invocation) { | |
19 throw "missing function in MockProgressEvent"; | |
20 } | |
21 } | |
22 | |
23 class MockHttpRequestTask implements Future<HttpRequest> { | |
24 final Completer completer = new Completer<HttpRequest>(); | |
25 final HttpRequestTaskSpecification spec; | |
26 final Zone zone; | |
27 | |
28 MockHttpRequestTask(this.spec, this.zone); | |
29 | |
30 void trigger(response) { | |
31 var xhr = new MockHttpRequest(spec, response); | |
32 var arg; | |
33 if (spec.url == "NonExistingFile") { | |
34 arg = new MockProgressEvent(xhr); | |
35 } else { | |
36 arg = xhr; | |
37 } | |
38 zone.runTask(run, this, arg); | |
39 } | |
40 | |
41 then(onData, {onError}) => completer.future.then(onData, onError: onError); | |
42 catchError(f, {test}) => completer.future.catchError(f, test: test); | |
43 whenComplete(f) => completer.future.whenComplete(f); | |
44 asStream() => completer.future.asStream(); | |
45 timeout(timeLimit, {onTimeout}) => | |
46 completer.future.timeout(timeLimit, onTimeout: onTimeout); | |
47 | |
48 static create(HttpRequestTaskSpecification spec, Zone zone) { | |
49 return new MockHttpRequestTask(spec, zone); | |
50 } | |
51 | |
52 static run(MockHttpRequestTask task, value) { | |
53 if (value is HttpRequest) { | |
54 task.completer.complete(value); | |
55 } else { | |
56 task.completer.completeError(value); | |
57 } | |
58 } | |
59 } | |
60 | |
61 class MockHttpRequest implements HttpRequest { | |
62 final HttpRequestTaskSpecification spec; | |
63 final response; | |
64 | |
65 MockHttpRequest(this.spec, this.response); | |
66 | |
67 noSuchMethod(Invocation invocation) { | |
68 print("isGetter: ${invocation.isGetter}"); | |
69 print("isMethod: ${invocation.isMethod}"); | |
70 print("memberName: ${invocation.memberName}"); | |
71 } | |
72 | |
73 int get status => spec.url == "NonExistingFile" ? 404 : 200; | |
74 | |
75 get readyState => HttpRequest.DONE; | |
76 get responseText => "$response"; | |
77 | |
78 Map get responseHeaders => {'content-type': 'text/plain; charset=utf-8',}; | |
79 } | |
80 | |
81 main() { | |
82 useHtmlIndividualConfiguration(); | |
83 unittestConfiguration.timeout = const Duration(milliseconds: 800); | |
84 | |
85 var urlExpando = new Expando(); | |
86 | |
87 var url = 'some/url.html'; | |
88 | |
89 Function buildCreateTaskHandler(List log, List tasks) { | |
90 Object createTaskHandler(Zone self, ZoneDelegate parent, Zone zone, | |
91 TaskCreate create, TaskSpecification spec) { | |
92 if (spec is HttpRequestTaskSpecification) { | |
93 var url = spec.url; | |
94 var method = spec.method; | |
95 var withCredentials = spec.withCredentials; | |
96 var responseType = spec.responseType; | |
97 var mimeType = spec.mimeType; | |
98 var data = spec.sendData; | |
99 | |
100 log.add("request $url"); | |
101 var dataLog = data is List<int> ? "binary ${data.length}" : "$data"; | |
102 log.add(" method: $method withCredentials: $withCredentials " | |
103 "responseType: $responseType mimeType: $mimeType data: $dataLog"); | |
104 var task = parent.createTask(zone, MockHttpRequestTask.create, spec); | |
105 urlExpando[task] = url; | |
106 tasks.add(task); | |
107 return task; | |
108 } | |
109 if (spec is EventSubscriptionSpecification) { | |
110 EventSubscriptionSpecification eventSpec = spec; | |
111 if (eventSpec.target is HttpRequest) { | |
112 HttpRequest target = eventSpec.target; | |
113 log.add("event listener on http-request ${eventSpec.eventType}"); | |
114 if (eventSpec.eventType == "readystatechange") { | |
115 var oldOnData = eventSpec.onData; | |
116 spec = eventSpec.replace(onData: (event) { | |
117 oldOnData(event); | |
118 if (target.readyState == HttpRequest.DONE) { | |
119 log.add("unknown request done"); | |
120 } | |
121 }); | |
122 } | |
123 } | |
124 } | |
125 return parent.createTask(zone, create, spec); | |
126 } | |
127 | |
128 return createTaskHandler; | |
129 } | |
130 | |
131 Function buildRunTaskHandler(List log, List tasks) { | |
132 void runTaskHandler(Zone self, ZoneDelegate parent, Zone zone, TaskRun run, | |
133 Object task, Object arg) { | |
134 if (tasks.contains(task)) { | |
135 var url = urlExpando[task]; | |
136 if (arg is Error || arg is Exception) { | |
137 log.add("failed $url"); | |
138 } else { | |
139 if (arg is ProgressEvent) { | |
140 log.add("success $url with progress-event"); | |
141 } else if (arg is HttpRequest) { | |
142 log.add("success $url with http-request"); | |
143 } else { | |
144 log.add("success $url (unknown arg)"); | |
145 } | |
146 } | |
147 } | |
148 parent.runTask(zone, run, task, arg); | |
149 } | |
150 | |
151 return runTaskHandler; | |
152 } | |
153 | |
154 Future<List> runMocked(response, fun) async { | |
155 var log = []; | |
156 var tasks = []; | |
157 var future = runZoned(fun, | |
158 zoneSpecification: new ZoneSpecification( | |
159 createTask: buildCreateTaskHandler(log, tasks), | |
160 runTask: buildRunTaskHandler(log, tasks))); | |
161 // Wait a full cycle to make sure things settle. | |
162 await new Future(() {}); | |
163 var beforeTriggerLog = log.toList(); | |
164 log.clear(); | |
165 expect(tasks.length, 1); | |
166 tasks.single.trigger(response); | |
167 await future; | |
168 return [beforeTriggerLog, log]; | |
169 } | |
170 | |
171 void validate200Response(xhr) { | |
172 expect(xhr.status, equals(200)); | |
173 var data = JSON.decode(xhr.responseText); | |
174 expect(data, contains('feed')); | |
175 expect(data['feed'], contains('entry')); | |
176 expect(data, isMap); | |
177 } | |
178 | |
179 void validate404(xhr) { | |
180 expect(xhr.status, equals(404)); | |
181 // We cannot say much about xhr.responseText, most HTTP servers will | |
182 // include an HTML page explaining the error to a human. | |
183 String responseText = xhr.responseText; | |
184 expect(responseText, isNotNull); | |
185 } | |
186 | |
187 group('xhr', () { | |
188 test('XHR.request No file', () async { | |
189 var log = await runMocked("404", () { | |
190 var completer = new Completer(); | |
191 HttpRequest.request('NonExistingFile').then((_) { | |
192 fail('Request should not have succeeded.'); | |
193 }, onError: expectAsync((error) { | |
194 var xhr = error.target; | |
195 expect(xhr.readyState, equals(HttpRequest.DONE)); | |
196 validate404(xhr); | |
197 completer.complete('done'); | |
198 })); | |
199 return completer.future; | |
200 }); | |
201 expect( | |
202 log, | |
203 equals([ | |
204 [ | |
205 'request NonExistingFile', | |
206 ' method: null withCredentials: null responseType: null ' | |
207 'mimeType: null data: null', | |
208 ], | |
209 ['success NonExistingFile with progress-event'] | |
210 ])); | |
211 }); | |
212 | |
213 test('XHR.request file', () async { | |
214 var log = await runMocked('{"feed": {"entry": 499}}', () { | |
215 var completer = new Completer(); | |
216 HttpRequest.request(url).then(expectAsync((xhr) { | |
217 expect(xhr.readyState, equals(HttpRequest.DONE)); | |
218 validate200Response(xhr); | |
219 completer.complete('done'); | |
220 })); | |
221 return completer.future; | |
222 }); | |
223 expect( | |
224 log, | |
225 equals([ | |
226 [ | |
227 'request $url', | |
228 ' method: null withCredentials: null responseType: null ' | |
229 'mimeType: null data: null' | |
230 ], | |
231 ['success $url with http-request'] | |
232 ])); | |
233 }); | |
234 | |
235 test('XHR.getString file', () async { | |
236 var log = await runMocked("foo", () { | |
237 return HttpRequest.getString(url).then(expectAsync((str) {})); | |
238 }); | |
239 expect( | |
240 log, | |
241 equals([ | |
242 [ | |
243 'request $url', | |
244 ' method: null withCredentials: null responseType: null ' | |
245 'mimeType: null data: null' | |
246 ], | |
247 ['success $url with http-request'] | |
248 ])); | |
249 }); | |
250 | |
251 test('XHR.request responseType arraybuffer', () async { | |
252 if (Platform.supportsTypedData) { | |
253 var data = new Uint8List(128); | |
254 var log = await runMocked(data.buffer, () { | |
255 return HttpRequest.request(url, | |
256 responseType: 'arraybuffer', | |
257 requestHeaders: { | |
258 'Content-Type': 'text/xml' | |
259 }).then(expectAsync((xhr) { | |
260 expect(xhr.status, equals(200)); | |
261 var byteBuffer = xhr.response; | |
262 expect(byteBuffer, new isInstanceOf<ByteBuffer>()); | |
263 expect(byteBuffer, isNotNull); | |
264 })); | |
265 }); | |
266 expect( | |
267 log, | |
268 equals([ | |
269 [ | |
270 'request $url', | |
271 ' method: null withCredentials: null responseType: arraybuffer' | |
272 ' mimeType: null data: null' | |
273 ], | |
274 ['success $url with http-request'] | |
275 ])); | |
276 } | |
277 ; | |
278 }); | |
279 }); | |
280 } | |
OLD | NEW |