| promise_test(async (t) => { |
| const source = new Observable(subscriber => { |
| subscriber.next(1); |
| subscriber.next(2); |
| subscriber.next(3); |
| t.step_timeout(() => subscriber.complete(), 0); |
| }); |
| |
| const reducerArguments = []; |
| |
| const promiseToResult = source.reduce((acc, value, index) => { |
| reducerArguments.push([acc, value, index]); |
| return acc + value; |
| }, 0); |
| |
| // The reducer should be called immediately when the source emits a value. |
| assert_equals(reducerArguments.length, 3); |
| assert_array_equals(reducerArguments[0], [0, 1, 0]); |
| assert_array_equals(reducerArguments[1], [1, 2, 1]); |
| assert_array_equals(reducerArguments[2], [3, 3, 2]); |
| |
| const result = await promiseToResult; |
| assert_equals(result, 6); |
| }, "reduce(): Reduces the values of the Observable, starting with the " + |
| "initial seed value"); |
| |
| promise_test(async (t) => { |
| let error = new Error('from the source'); |
| const source = new Observable(subscriber => { |
| subscriber.next(1); |
| subscriber.error(error); |
| }); |
| |
| return promise_rejects_exactly(t, error, source.reduce((acc, value) => acc + value, 0)); |
| }, "reduce(): Rejects if the source observable emits an error"); |
| |
| promise_test(async (t) => { |
| const source = new Observable(subscriber => { |
| subscriber.next(1); |
| subscriber.next(2); |
| subscriber.next(3); |
| t.step_timeout(() => subscriber.complete(), 0); |
| }); |
| |
| const reducerArguments = []; |
| |
| const promiseToResult = source.reduce((acc, value, index) => { |
| reducerArguments.push([acc, value, index]); |
| return acc + value; |
| }); |
| |
| // The reducer should be called immediately when the source emits a value. |
| assert_equals(reducerArguments.length, 2); |
| assert_array_equals(reducerArguments[0], [1, 2, 1]); |
| assert_array_equals(reducerArguments[1], [3, 3, 2]); |
| |
| const result = await promiseToResult; |
| assert_equals(result, 6); |
| }, "reduce(): Seeds with the first value of the source, if no initial value " + |
| "is provided"); |
| |
| promise_test(async (t) => { |
| const logs = []; |
| |
| const source = new Observable(subscriber => { |
| subscriber.addTeardown(() => logs.push('teardown')); |
| logs.push('next 1'); |
| subscriber.next(1); |
| logs.push('next 2'); |
| subscriber.next(2); |
| logs.push('try to next 3'); |
| subscriber.next(3); |
| logs.push('try to complete'); |
| subscriber.complete(); |
| }); |
| |
| const error = new Error('from the reducer'); |
| |
| const promiseToResult = source.reduce((acc, value) => { |
| if (value === 2) { |
| logs.push('throw error'); |
| throw error; |
| } |
| return acc + value; |
| }, 0); |
| |
| await promise_rejects_exactly(t, error, promiseToResult); |
| |
| assert_array_equals(logs, [ |
| 'next 1', |
| 'next 2', |
| 'throw error', |
| 'teardown', |
| 'try to next 3', |
| 'try to complete', |
| ]); |
| }, "reduce(): Errors thrown in reducer reject the promise and abort the source"); |
| |
| promise_test(async () => { |
| const source = new Observable(subscriber => { |
| subscriber.complete(); |
| }); |
| |
| const result = await source.reduce(() => 'reduced', 'seed'); |
| |
| assert_equals(result, 'seed'); |
| }, "reduce(): When source is empty, promise resolves with initial value"); |
| |
| promise_test(async (t) => { |
| // This tests behavior that is analogous to `[].reduce(() => 'reduced')`, |
| // which throws a TypeError. |
| |
| const source = new Observable(subscriber => { |
| subscriber.complete(); |
| }); |
| |
| return promise_rejects_js(t, TypeError, source.reduce(() => 'reduced')); |
| }, "reduce(): When source is empty, AND no seed value is provided, the " + |
| "promise rejects with a TypeError"); |
| |
| promise_test(async (t) => { |
| let tornDown = false; |
| const source = new Observable((subscriber) => { |
| subscriber.addTeardown(() => { |
| tornDown = true; |
| }); |
| // Waits forever. |
| }); |
| |
| const abortController = new AbortController(); |
| |
| t.step_timeout(() => { |
| abortController.abort(); |
| assert_true(tornDown); |
| }, 0); |
| |
| return promise_rejects_dom(t, 'AbortError', source.reduce(() => 'reduced', 'seed', { signal: abortController.signal })); |
| }, "reduce(): Reject with an AbortError if the subscription is aborted " + |
| "before the source completes"); |
| |
| promise_test(async () => { |
| const source = new Observable(subscriber => { |
| subscriber.complete(); |
| }); |
| |
| const values = [{}, [], new Error("some error")]; |
| |
| for (let value of values) { |
| const result = await source.reduce(() => {}, value); |
| assert_equals(result, value); |
| } |
| }, "reduce(): Reduces the values for different objects"); |