OLD | NEW |
| (Empty) |
1 library zone_spec; | |
2 | |
3 import '../_specs.dart'; | |
4 | |
5 import 'dart:async'; | |
6 | |
7 main() => describe('zone', () { | |
8 var zone; | |
9 var exceptionHandler; | |
10 beforeEach(module((Module module) { | |
11 exceptionHandler = new LoggingExceptionHandler(); | |
12 module.value(ExceptionHandler, exceptionHandler); | |
13 })); | |
14 | |
15 beforeEach(inject((Logger log, ExceptionHandler eh) { | |
16 zone = new NgZone(); | |
17 zone.onTurnDone = () { | |
18 log('onTurnDone'); | |
19 }; | |
20 zone.onError = (e, s, ls) => eh(e, s); | |
21 })); | |
22 | |
23 | |
24 describe('exceptions', () { | |
25 it('should rethrow exceptions from the body and call onError', () { | |
26 var error; | |
27 zone.onError = (e, s, l) => error = e; | |
28 expect(() { | |
29 zone.run(() { | |
30 throw ['hello']; | |
31 }); | |
32 }).toThrow('hello'); | |
33 expect(error).toEqual(['hello']); | |
34 }); | |
35 | |
36 | |
37 it('should call onError for errors from scheduleMicrotask', async(inject(()
{ | |
38 zone.run(() { | |
39 scheduleMicrotask(() { | |
40 throw ["async exception"]; | |
41 }); | |
42 }); | |
43 | |
44 expect(exceptionHandler.errors.length).toEqual(1); | |
45 expect(exceptionHandler.errors[0].error).toEqual(["async exception"]); | |
46 }))); | |
47 | |
48 | |
49 it('should allow executing code outside the zone', inject(() { | |
50 var zone = new NgZone(); | |
51 var outerZone = Zone.current; | |
52 var ngZone; | |
53 var outsideZone; | |
54 zone.run(() { | |
55 ngZone = Zone.current; | |
56 zone.runOutsideAngular(() { | |
57 outsideZone = Zone.current; | |
58 }); | |
59 }); | |
60 | |
61 expect(outsideZone).toEqual(outerZone); | |
62 expect(ngZone.parent).toEqual((outerZone)); | |
63 })); | |
64 | |
65 | |
66 it('should rethrow exceptions from the onTurnDone and call onError when the
zone is sync', () { | |
67 zone.onTurnDone = () { | |
68 throw ["fromOnTurnDone"]; | |
69 }; | |
70 | |
71 expect(() { | |
72 zone.run(() { }); | |
73 }).toThrow('fromOnTurnDone'); | |
74 | |
75 expect(exceptionHandler.errors.length).toEqual(1); | |
76 expect(exceptionHandler.errors[0].error).toEqual(["fromOnTurnDone"]); | |
77 }); | |
78 | |
79 | |
80 it('should rethrow exceptions from the onTurnDone and call onError when the
zone is async', () { | |
81 var asyncRan = false; | |
82 | |
83 zone.onTurnDone = () { | |
84 throw ["fromOnTurnDone"]; | |
85 }; | |
86 | |
87 expect(() { | |
88 zone.run(() { | |
89 scheduleMicrotask(() { | |
90 asyncRan = true; | |
91 }); | |
92 }); | |
93 }).toThrow('fromOnTurnDone'); | |
94 | |
95 expect(asyncRan).toBeTruthy(); | |
96 expect(exceptionHandler.errors.length).toEqual(1); | |
97 expect(exceptionHandler.errors[0].error).toEqual(["fromOnTurnDone"]); | |
98 }); | |
99 }); | |
100 | |
101 xdescribe('long stack traces', () { | |
102 it('should have nice error when crossing scheduleMicrotask boundries', async
(inject(() { | |
103 var error; | |
104 var stack; | |
105 var longStacktrace; | |
106 | |
107 zone.onError = (e, s, f) { | |
108 error = e; | |
109 stack = s; | |
110 longStacktrace = f; | |
111 }; | |
112 var FRAME = new RegExp(r'.*\(.*\:(\d+):\d+\)'); | |
113 | |
114 var line = ((){ try {throw [];} catch(e, s) { return int.parse(FRAME.first
Match('$s')[1]);}})(); | |
115 var throwFn = () { throw ['double zonned']; }; | |
116 var inner = () => zone.run(throwFn); | |
117 var middle = () => scheduleMicrotask(inner); | |
118 var outer = () => scheduleMicrotask(middle); | |
119 zone.run(outer); | |
120 | |
121 microLeap(); | |
122 expect(error).toEqual(['double zonned']); | |
123 | |
124 // Not in dart2js.. | |
125 if ('$stack'.contains('.dart.js')) { | |
126 return; | |
127 } | |
128 | |
129 expect('$stack').toContain('zone_spec.dart:${line+1}'); | |
130 expect('$stack').toContain('zone_spec.dart:${line+2}'); | |
131 expect('$longStacktrace').toContain('zone_spec.dart:${line+3}'); | |
132 expect('$longStacktrace').toContain('zone_spec.dart:${line+4}'); | |
133 expect('$longStacktrace').toContain('zone_spec.dart:${line+5}'); | |
134 }))); | |
135 }); | |
136 | |
137 it('should call onTurnDone after a synchronous block', inject((Logger log) { | |
138 zone.run(() { | |
139 log('run'); | |
140 }); | |
141 expect(log.result()).toEqual('run; onTurnDone'); | |
142 })); | |
143 | |
144 | |
145 it('should return the body return value from run', () { | |
146 expect(zone.run(() { return 6; })).toEqual(6); | |
147 }); | |
148 | |
149 | |
150 it('should call onTurnDone for a scheduleMicrotask in onTurnDone', async(injec
t((Logger log) { | |
151 var ran = false; | |
152 zone.onTurnDone = () { | |
153 if (!ran) { | |
154 scheduleMicrotask(() { ran = true; log('onTurnAsync'); }); | |
155 } | |
156 log('onTurnDone'); | |
157 }; | |
158 zone.run(() { | |
159 log('run'); | |
160 }); | |
161 microLeap(); | |
162 | |
163 expect(log.result()).toEqual('run; onTurnDone; onTurnAsync; onTurnDone'); | |
164 }))); | |
165 | |
166 | |
167 it('should call onTurnDone for a scheduleMicrotask in onTurnDone triggered by
a scheduleMicrotask in run', async(inject((Logger log) { | |
168 var ran = false; | |
169 zone.onTurnDone = () { | |
170 if (!ran) { | |
171 scheduleMicrotask(() { ran = true; log('onTurnAsync'); }); | |
172 } | |
173 log('onTurnDone'); | |
174 }; | |
175 zone.run(() { | |
176 scheduleMicrotask(() { log('scheduleMicrotask'); }); | |
177 log('run'); | |
178 }); | |
179 microLeap(); | |
180 | |
181 expect(log.result()).toEqual('run; scheduleMicrotask; onTurnDone; onTurnAsyn
c; onTurnDone'); | |
182 }))); | |
183 | |
184 | |
185 | |
186 it('should call onTurnDone once after a turn', async(inject((Logger log) { | |
187 zone.run(() { | |
188 log('run start'); | |
189 scheduleMicrotask(() { | |
190 log('async'); | |
191 }); | |
192 log('run end'); | |
193 }); | |
194 microLeap(); | |
195 | |
196 expect(log.result()).toEqual('run start; run end; async; onTurnDone'); | |
197 }))); | |
198 | |
199 | |
200 it('should work for Future.value as well', async(inject((Logger log) { | |
201 var futureRan = false; | |
202 zone.onTurnDone = () { | |
203 if (!futureRan) { | |
204 new Future.value(null).then((_) { log('onTurn future'); }); | |
205 futureRan = true; | |
206 } | |
207 log('onTurnDone'); | |
208 }; | |
209 | |
210 zone.run(() { | |
211 log('run start'); | |
212 new Future.value(null) | |
213 .then((_) { | |
214 log('future then'); | |
215 new Future.value(null) | |
216 .then((_) { log('future ?'); }); | |
217 return new Future.value(null); | |
218 }) | |
219 .then((_) { | |
220 log('future ?'); | |
221 }); | |
222 log('run end'); | |
223 }); | |
224 microLeap(); | |
225 | |
226 expect(log.result()).toEqual('run start; run end; future then; future ?; fut
ure ?; onTurnDone; onTurn future; onTurnDone'); | |
227 }))); | |
228 | |
229 | |
230 it('should call onTurnDone after each turn', async(inject((Logger log) { | |
231 Completer a, b; | |
232 zone.run(() { | |
233 a = new Completer(); | |
234 b = new Completer(); | |
235 a.future.then((_) => log('a then')); | |
236 b.future.then((_) => log('b then')); | |
237 log('run start'); | |
238 }); | |
239 microLeap(); | |
240 zone.run(() { | |
241 a.complete(null); | |
242 }); | |
243 microLeap(); | |
244 zone.run(() { | |
245 b.complete(null); | |
246 }); | |
247 microLeap(); | |
248 | |
249 expect(log.result()).toEqual('run start; onTurnDone; a then; onTurnDone; b t
hen; onTurnDone'); | |
250 }))); | |
251 | |
252 | |
253 it('should call onTurnDone after each turn in a chain', async(inject((Logger l
og) { | |
254 zone.run(() { | |
255 log('run start'); | |
256 scheduleMicrotask(() { | |
257 log('async1'); | |
258 scheduleMicrotask(() { | |
259 log('async2'); | |
260 }); | |
261 }); | |
262 log('run end'); | |
263 }); | |
264 microLeap(); | |
265 | |
266 expect(log.result()).toEqual('run start; run end; async1; async2; onTurnDone
'); | |
267 }))); | |
268 | |
269 it('should call onTurnDone for futures created outside of run body', async(inj
ect((Logger log) { | |
270 var future = new Future.value(4).then((x) => new Future.value(x)); | |
271 zone.run(() { | |
272 future.then((_) => log('future then')); | |
273 log('zone run'); | |
274 }); | |
275 microLeap(); | |
276 | |
277 expect(log.result()).toEqual('zone run; onTurnDone; future then; onTurnDone'
); | |
278 }))); | |
279 | |
280 | |
281 it('should call onTurnDone even if there was an exception in body', async(inje
ct((Logger log) { | |
282 zone.onError = (e, s, l) => log('onError'); | |
283 expect(() => zone.run(() { | |
284 log('zone run'); | |
285 throw 'zoneError'; | |
286 })).toThrow('zoneError'); | |
287 expect(() => zone.assertInTurn()).toThrow(); | |
288 expect(log.result()).toEqual('zone run; onError; onTurnDone'); | |
289 }))); | |
290 | |
291 | |
292 it('should call onTurnDone even if there was an exception in scheduleMicrotask
', async(inject((Logger log) { | |
293 zone.onError = (e, s, l) => log('onError'); | |
294 zone.run(() { | |
295 log('zone run'); | |
296 scheduleMicrotask(() { | |
297 log('scheduleMicrotask'); | |
298 throw new Error(); | |
299 }); | |
300 }); | |
301 | |
302 microLeap(); | |
303 | |
304 expect(() => zone.assertInTurn()).toThrow(); | |
305 expect(log.result()).toEqual('zone run; scheduleMicrotask; onError; onTurnDo
ne'); | |
306 }))); | |
307 | |
308 it('should support assertInZone', async(() { | |
309 var calls = ''; | |
310 zone.onTurnDone = () { | |
311 zone.assertInZone(); | |
312 calls += 'done;'; | |
313 }; | |
314 zone.run(() { | |
315 zone.assertInZone(); | |
316 calls += 'sync;'; | |
317 scheduleMicrotask(() { | |
318 zone.assertInZone(); | |
319 calls += 'async;'; | |
320 }); | |
321 }); | |
322 | |
323 microLeap(); | |
324 expect(calls).toEqual('sync;async;done;'); | |
325 })); | |
326 | |
327 it('should throw outside of the zone', () { | |
328 expect(async(() { | |
329 zone.assertInZone(); | |
330 microLeap(); | |
331 })).toThrow(); | |
332 }); | |
333 | |
334 | |
335 it('should support assertInTurn', async(() { | |
336 var calls = ''; | |
337 zone.onTurnDone = () { | |
338 calls += 'done;'; | |
339 zone.assertInTurn(); | |
340 }; | |
341 zone.run(() { | |
342 calls += 'sync;'; | |
343 zone.assertInTurn(); | |
344 scheduleMicrotask(() { | |
345 calls += 'async;'; | |
346 zone.assertInTurn(); | |
347 }); | |
348 }); | |
349 | |
350 microLeap(); | |
351 expect(calls).toEqual('sync;async;done;'); | |
352 })); | |
353 | |
354 | |
355 it('should assertInTurn outside of the zone', () { | |
356 expect(async(() { | |
357 zone.assertInTurn(); | |
358 microLeap(); | |
359 })).toThrow('ssertion'); // Support both dart2js and the VM with half a wor
d. | |
360 }); | |
361 }); | |
OLD | NEW |