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