observable-reduce.any.js (4454B)
1 promise_test(async (t) => { 2 const source = new Observable(subscriber => { 3 subscriber.next(1); 4 subscriber.next(2); 5 subscriber.next(3); 6 t.step_timeout(() => subscriber.complete(), 0); 7 }); 8 9 const reducerArguments = []; 10 11 const promiseToResult = source.reduce((acc, value, index) => { 12 reducerArguments.push([acc, value, index]); 13 return acc + value; 14 }, 0); 15 16 // The reducer should be called immediately when the source emits a value. 17 assert_equals(reducerArguments.length, 3); 18 assert_array_equals(reducerArguments[0], [0, 1, 0]); 19 assert_array_equals(reducerArguments[1], [1, 2, 1]); 20 assert_array_equals(reducerArguments[2], [3, 3, 2]); 21 22 const result = await promiseToResult; 23 assert_equals(result, 6); 24 }, "reduce(): Reduces the values of the Observable, starting with the " + 25 "initial seed value"); 26 27 promise_test(async (t) => { 28 let error = new Error('from the source'); 29 const source = new Observable(subscriber => { 30 subscriber.next(1); 31 subscriber.error(error); 32 }); 33 34 return promise_rejects_exactly(t, error, source.reduce((acc, value) => acc + value, 0)); 35 }, "reduce(): Rejects if the source observable emits an error"); 36 37 promise_test(async (t) => { 38 const source = new Observable(subscriber => { 39 subscriber.next(1); 40 subscriber.next(2); 41 subscriber.next(3); 42 t.step_timeout(() => subscriber.complete(), 0); 43 }); 44 45 const reducerArguments = []; 46 47 const promiseToResult = source.reduce((acc, value, index) => { 48 reducerArguments.push([acc, value, index]); 49 return acc + value; 50 }); 51 52 // The reducer should be called immediately when the source emits a value. 53 assert_equals(reducerArguments.length, 2); 54 assert_array_equals(reducerArguments[0], [1, 2, 1]); 55 assert_array_equals(reducerArguments[1], [3, 3, 2]); 56 57 const result = await promiseToResult; 58 assert_equals(result, 6); 59 }, "reduce(): Seeds with the first value of the source, if no initial value " + 60 "is provided"); 61 62 promise_test(async (t) => { 63 const logs = []; 64 65 const source = new Observable(subscriber => { 66 subscriber.addTeardown(() => logs.push('teardown')); 67 logs.push('next 1'); 68 subscriber.next(1); 69 logs.push('next 2'); 70 subscriber.next(2); 71 logs.push('try to next 3'); 72 subscriber.next(3); 73 logs.push('try to complete'); 74 subscriber.complete(); 75 }); 76 77 const error = new Error('from the reducer'); 78 79 const promiseToResult = source.reduce((acc, value) => { 80 if (value === 2) { 81 logs.push('throw error'); 82 throw error; 83 } 84 return acc + value; 85 }, 0); 86 87 await promise_rejects_exactly(t, error, promiseToResult); 88 89 assert_array_equals(logs, [ 90 'next 1', 91 'next 2', 92 'throw error', 93 'teardown', 94 'try to next 3', 95 'try to complete', 96 ]); 97 }, "reduce(): Errors thrown in reducer reject the promise and abort the source"); 98 99 promise_test(async () => { 100 const source = new Observable(subscriber => { 101 subscriber.complete(); 102 }); 103 104 const result = await source.reduce(() => 'reduced', 'seed'); 105 106 assert_equals(result, 'seed'); 107 }, "reduce(): When source is empty, promise resolves with initial value"); 108 109 promise_test(async (t) => { 110 // This tests behavior that is analogous to `[].reduce(() => 'reduced')`, 111 // which throws a TypeError. 112 113 const source = new Observable(subscriber => { 114 subscriber.complete(); 115 }); 116 117 return promise_rejects_js(t, TypeError, source.reduce(() => 'reduced')); 118 }, "reduce(): When source is empty, AND no seed value is provided, the " + 119 "promise rejects with a TypeError"); 120 121 promise_test(async (t) => { 122 let tornDown = false; 123 const source = new Observable((subscriber) => { 124 subscriber.addTeardown(() => { 125 tornDown = true; 126 }); 127 // Waits forever. 128 }); 129 130 const abortController = new AbortController(); 131 132 t.step_timeout(() => { 133 abortController.abort(); 134 assert_true(tornDown); 135 }, 0); 136 137 return promise_rejects_dom(t, 'AbortError', source.reduce(() => 'reduced', 'seed', { signal: abortController.signal })); 138 }, "reduce(): Reject with an AbortError if the subscription is aborted " + 139 "before the source completes"); 140 141 promise_test(async () => { 142 const source = new Observable(subscriber => { 143 subscriber.complete(); 144 }); 145 146 const values = [{}, [], new Error("some error")]; 147 148 for (let value of values) { 149 const result = await source.reduce(() => {}, value); 150 assert_equals(result, value); 151 } 152 }, "reduce(): Reduces the values for different objects");