observable-inspect.any.js (11471B)
1 // Because we test that the global error handler is called at various times. 2 setup({ allow_uncaught_exception: true }); 3 4 test(() => { 5 const results = []; 6 let sourceSubscriptionCall = 0; 7 const source = new Observable(subscriber => { 8 sourceSubscriptionCall++; 9 results.push(`source subscribe ${sourceSubscriptionCall}`); 10 subscriber.next(1); 11 subscriber.next(2); 12 subscriber.next(3); 13 subscriber.complete(); 14 }); 15 16 let inspectSubscribeCall = 0; 17 const result = source.inspect({ 18 subscribe: () => { 19 inspectSubscribeCall++; 20 results.push(`inspect() subscribe ${inspectSubscribeCall}`); 21 }, 22 next: (value) => results.push(`inspect() next ${value}`), 23 error: () => results.push('inspect() error'), 24 complete: () => results.push('inspect() complete'), 25 }); 26 27 result.subscribe({ 28 next: (value) => results.push(`result next ${value}`), 29 error: () => results.push('result error'), 30 complete: () => results.push('result complete'), 31 }); 32 33 result.subscribe({ 34 next: (value) => results.push(`result next ${value}`), 35 error: () => results.push('result error'), 36 complete: () => results.push('result complete'), 37 }); 38 39 assert_array_equals(results, 40 [ 41 "inspect() subscribe 1", 42 "source subscribe 1", 43 "inspect() next 1", 44 "result next 1", 45 "inspect() next 2", 46 "result next 2", 47 "inspect() next 3", 48 "result next 3", 49 "inspect() complete", 50 "result complete", 51 "inspect() subscribe 2", 52 "source subscribe 2", 53 "inspect() next 1", 54 "result next 1", 55 "inspect() next 2", 56 "result next 2", 57 "inspect() next 3", 58 "result next 3", 59 "inspect() complete", 60 "result complete", 61 ]); 62 }, "inspect(): Provides a pre-subscription subscribe callback"); 63 64 test(() => { 65 const source = new Observable(subscriber => { 66 subscriber.next(1); 67 subscriber.next(2); 68 subscriber.next(3); 69 subscriber.complete(); 70 }); 71 72 const results = []; 73 74 const result = source.inspect({ 75 next: value => results.push(value), 76 error: e => results.push(e), 77 complete: () => results.push("complete"), 78 }); 79 80 result.subscribe(); 81 result.subscribe(); 82 83 assert_array_equals(results, [1, 2, 3, "complete", 1, 2, 3, "complete"]); 84 }, "inspect(): Provides a way to tap into the values and completions of the " + 85 "source observable using an observer"); 86 87 test(() => { 88 const error = new Error("error from source"); 89 const source = new Observable(subscriber => subscriber.error(error)); 90 91 const results = []; 92 93 const result = source.inspect({ 94 next: value => results.push(value), 95 error: e => results.push(e), 96 complete: () => results.push("complete"), 97 }); 98 99 let errorReported = null; 100 self.addEventListener('error', e => errorReported = e.error, {once: true}); 101 result.subscribe(); 102 103 assert_array_equals(results, [error]); 104 assert_equals(errorReported, error, 105 "errorReported to global matches error from source Observable"); 106 }, "inspect(): Error handler does not stop error from being reported to the " + 107 "global, when subscriber does not pass error handler"); 108 109 test(() => { 110 const error = new Error("error from source"); 111 const source = new Observable(subscriber => { 112 subscriber.next(1); 113 subscriber.next(2); 114 subscriber.next(3); 115 subscriber.error(error); 116 }); 117 118 const results = []; 119 120 const result = source.inspect({ 121 next: value => results.push(value), 122 error: e => results.push(e), 123 complete: () => results.push("complete"), 124 }); 125 126 const observer = { 127 error: e => results.push(e), 128 }; 129 result.subscribe(observer); 130 result.subscribe(observer); 131 132 assert_array_equals(results, [1, 2, 3, error, error, 1, 2, 3, error, error]); 133 }, "inspect(): Provides a way to tap into the values and errors of the " + 134 "source observable using an observer. Errors are passed through"); 135 136 test(() => { 137 const source = new Observable(subscriber => { 138 subscriber.next(1); 139 subscriber.next(2); 140 subscriber.next(3); 141 subscriber.complete(); 142 }); 143 144 const results = []; 145 146 const result = source.inspect(value => results.push(value)); 147 148 result.subscribe(); 149 result.subscribe(); 150 151 assert_array_equals(results, [1, 2, 3, 1, 2, 3]); 152 }, "inspect(): ObserverCallback passed in"); 153 154 test(() => { 155 const source = new Observable(subscriber => { 156 subscriber.next(1); 157 subscriber.next(2); 158 subscriber.next(3); 159 }); 160 161 const error = new Error("error from inspect() next handler"); 162 const result = source.inspect({ 163 next: (value) => { 164 if (value === 2) { 165 throw error; 166 } 167 }, 168 }); 169 170 const results1 = []; 171 result.subscribe({ 172 next: (value) => results1.push(value), 173 error: (e) => results1.push(e), 174 complete: () => results1.push("complete"), 175 }); 176 177 const results2 = []; 178 result.subscribe({ 179 next: (value) => results2.push(value), 180 error: (e) => results2.push(e), 181 complete: () => results2.push("complete"), 182 }); 183 184 assert_array_equals(results1, [1, error]); 185 assert_array_equals(results2, [1, error]); 186 }, "inspect(): Throwing an error in the observer next handler is caught and " + 187 "sent to the error callback of the result observable"); 188 189 test(() => { 190 const sourceError = new Error("error from source"); 191 const inspectError = new Error("error from inspect() error handler"); 192 193 const source = new Observable(subscriber => { 194 subscriber.error(sourceError); 195 }); 196 197 const result = source.inspect({ 198 error: () => { 199 throw inspectError; 200 }, 201 }); 202 203 const results = []; 204 result.subscribe({ 205 next: () => results.push("next"), 206 error: (e) => results.push(e), 207 complete: () => results.push("complete"), 208 }); 209 210 assert_array_equals(results, [inspectError]); 211 }, "inspect(): Throwing an error in the observer error handler in " + 212 "inspect() is caught and sent to the error callback of the result " + 213 "observable"); 214 215 test(() => { 216 const source = new Observable(subscriber => { 217 subscriber.next(1); 218 subscriber.next(2); 219 subscriber.next(3); 220 subscriber.complete(); 221 }); 222 223 const error = new Error("error from inspect() complete handler"); 224 const result = source.inspect({ 225 complete: () => { 226 throw error; 227 }, 228 }); 229 230 const results = []; 231 result.subscribe({ 232 next: (value) => results.push(value), 233 error: (e) => results.push(e), 234 complete: () => results.push("complete"), 235 }); 236 237 assert_array_equals(results, [1, 2, 3, error]); 238 }, "inspect(): Throwing an error in the observer complete handler is caught " + 239 "and sent to the error callback of the result observable"); 240 241 test(() => { 242 const source = new Observable(subscriber => { 243 subscriber.next(1); 244 subscriber.next(2); 245 subscriber.next(3); 246 }); 247 248 const error = new Error("error from inspect() next handler"); 249 const result = source.inspect({ 250 next: (value) => { 251 if (value === 2) { 252 throw error; 253 } 254 }, 255 }); 256 257 const results = []; 258 result.subscribe({ 259 next: (value) => results.push(value), 260 error: (e) => results.push(e), 261 complete: () => results.push("complete"), 262 }); 263 264 assert_array_equals(results, [1, error]); 265 }, "inspect(): Throwing an error in the next handler function in do should " + 266 "be caught and sent to the error callback of the result observable"); 267 268 test(() => { 269 const source = new Observable(subscriber => {}); 270 const error = new Error("error from do subscribe handler"); 271 272 const result = source.inspect({ 273 subscribe: () => { 274 throw error; 275 }, 276 }); 277 278 const results = []; 279 result.subscribe({ 280 next: () => results.push("next"), 281 error: (e) => results.push(e), 282 complete: () => results.push("complete"), 283 }); 284 285 assert_array_equals(results, [error]); 286 }, "inspect(): Errors thrown in subscribe() Inspector handler subscribe " + 287 "handler are caught and sent to error callback"); 288 289 test(() => { 290 const results = []; 291 let sourceTeardownCall = 0; 292 const source = new Observable(subscriber => { 293 subscriber.addTeardown(() => { 294 sourceTeardownCall++; 295 results.push(`source teardown ${sourceTeardownCall}`); 296 }); 297 subscriber.next(1); 298 subscriber.next(2); 299 subscriber.next(3); 300 subscriber.complete(); 301 }); 302 303 let doUnsubscribeCall = 0; 304 const result = source.inspect({ 305 abort: (reason) => { 306 doUnsubscribeCall++; 307 results.push(`inspect() abort ${doUnsubscribeCall} ${reason}`); 308 }, 309 next: (value) => results.push(`inspect() next ${value}`), 310 error: () => results.push('inspect() error'), 311 complete: () => results.push(`inspect() complete`), 312 }); 313 314 const controller = new AbortController(); 315 result.subscribe({ 316 next: (value) => { 317 results.push(`result next ${value}`); 318 if (value === 2) { 319 controller.abort("abort reason"); 320 } 321 }, 322 error: () => results.push('result error'), 323 complete: () => results.push(`result complete`), 324 }, { signal: controller.signal }); 325 326 assert_array_equals(results, [ 327 "inspect() next 1", 328 "result next 1", 329 "inspect() next 2", 330 "result next 2", 331 "inspect() abort 1 abort reason", 332 "source teardown 1", 333 ]); 334 }, "inspect(): Provides a way to tap into the moment a source observable is unsubscribed from"); 335 336 test(() => { 337 const results = []; 338 let sourceTeardownCall = 0; 339 const source = new Observable(subscriber => { 340 subscriber.addTeardown(() => { 341 sourceTeardownCall++; 342 results.push(`source teardown ${sourceTeardownCall}`); 343 }); 344 subscriber.next(1); 345 subscriber.next(2); 346 subscriber.next(3); 347 subscriber.complete(); 348 }); 349 350 let inspectUnsubscribeCall = 0; 351 const result = source.inspect({ 352 next: (value) => results.push(`inspect() next ${value}`), 353 complete: () => results.push(`inspect() complete`), 354 abort: (reason) => { 355 inspectUnsubscribeCall++; 356 results.push(`inspect() abort ${inspectUnsubscribeCall} ${reason}`); 357 }, 358 }); 359 360 result.subscribe({ 361 next: (value) => results.push(`result next ${value}`), 362 complete: () => results.push(`result complete`), 363 }); 364 365 assert_array_equals(results, [ 366 "inspect() next 1", 367 "result next 1", 368 "inspect() next 2", 369 "result next 2", 370 "inspect() next 3", 371 "result next 3", 372 "source teardown 1", 373 "inspect() complete", 374 "result complete", 375 ]); 376 }, "inspect(): Inspector abort() handler is not called if the source " + 377 "completes before the result is unsubscribed from"); 378 379 test(() => { 380 const source = new Observable(subscriber => { 381 subscriber.next(1); 382 }); 383 384 const results = []; 385 const error = new Error("error from inspect() subscribe handler"); 386 387 const result = source.inspect({ 388 abort: () => { 389 results.push("abort() handler run"); 390 throw error; 391 }, 392 }); 393 394 const controller = new AbortController(); 395 396 self.when("error").take(1).subscribe((e) => { 397 results.push("from report exception"); 398 results.push(e.error); 399 }); 400 401 result.subscribe({ 402 next: (value) => { 403 results.push(value); 404 controller.abort(); 405 }, 406 error: () => { 407 assert_unreached("This should not be invoked at all!!"); 408 }, 409 complete: () => results.push("complete"), 410 }, { signal: controller.signal }); 411 412 assert_array_equals(results, [ 413 1, 414 "abort() handler run", 415 "from report exception", 416 error, 417 ]); 418 }, "inspect(): Errors thrown from inspect()'s abort() handler are caught " + 419 "and reported to the global, because the subscription is already closed " + 420 "by the time the handler runs");