From 8dd16259287f58f9273002717ec4d27e97127719 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 12 Jun 2024 07:43:14 +0200 Subject: Merging upstream version 127.0. Signed-off-by: Daniel Baumann --- .../observable/tentative/observable-every.any.js | 250 +++++++++++++ .../observable/tentative/observable-filter.any.js | 12 + .../observable/tentative/observable-find.any.js | 85 +++++ .../observable/tentative/observable-inspect.any.js | 412 +++++++++++++++++++++ .../observable/tentative/observable-some.any.js | 96 +++++ 5 files changed, 855 insertions(+) create mode 100644 testing/web-platform/tests/dom/observable/tentative/observable-every.any.js create mode 100644 testing/web-platform/tests/dom/observable/tentative/observable-find.any.js create mode 100644 testing/web-platform/tests/dom/observable/tentative/observable-inspect.any.js create mode 100644 testing/web-platform/tests/dom/observable/tentative/observable-some.any.js (limited to 'testing/web-platform/tests/dom/observable/tentative') diff --git a/testing/web-platform/tests/dom/observable/tentative/observable-every.any.js b/testing/web-platform/tests/dom/observable/tentative/observable-every.any.js new file mode 100644 index 0000000000..74a344b8f7 --- /dev/null +++ b/testing/web-platform/tests/dom/observable/tentative/observable-every.any.js @@ -0,0 +1,250 @@ +promise_test(async () => { + const source = new Observable(subscriber => { + subscriber.next("good"); + subscriber.next("good"); + subscriber.next("good"); + subscriber.complete(); + }); + + const result = await source.every((value) => value === "good"); + + assert_true(result, "Promise resolves with true if all values pass the predicate"); +}, "every(): Promise resolves to true if all values pass the predicate"); + +promise_test(async () => { + const source = new Observable(subscriber => { + subscriber.next("good"); + subscriber.next("good"); + subscriber.next("bad"); + subscriber.complete(); + }); + + const result = await source.every((value) => value === "good"); + + assert_false(result, "Promise resolves with false if any value fails the predicate"); +}, "every(): Promise resolves to false if any value fails the predicate"); + +promise_test(async () => { + let tornDown = false; + let subscriberActiveAfterFailingPredicate = true; + const source = new Observable(subscriber => { + subscriber.addTeardown(() => tornDown = true); + subscriber.next("good"); + subscriber.next("good"); + subscriber.next("bad"); + subscriberActiveAfterFailingPredicate = subscriber.active; + subscriber.next("good"); + subscriber.complete(); + }); + + const result = await source.every((value) => value === "good"); + + assert_false(result, "Promise resolves with false if any value fails the predicate"); + assert_false(subscriberActiveAfterFailingPredicate, + "Subscriber becomes inactive because every() unsubscribed"); +}, "every(): Abort the subscription to the source if the predicate does not pass"); + +promise_test(async () => { + const logs = []; + + const source = createTestSubject({ + onSubscribe: () => logs.push("subscribed to source"), + onTeardown: () => logs.push("teardown"), + }); + + const resultPromise = source.every((value, index) => { + logs.push(`Predicate called with ${value}, ${index}`); + return true; + }); + + let promiseResolved = false; + + resultPromise.then(() => promiseResolved = true); + + assert_array_equals(logs, ["subscribed to source"], + "calling every() subscribes to the source immediately"); + + source.next("a"); + assert_array_equals(logs, [ + "subscribed to source", + "Predicate called with a, 0" + ], "Predicate called with the value and the index"); + + source.next("b"); + assert_array_equals(logs, [ + "subscribed to source", + "Predicate called with a, 0", + "Predicate called with b, 1", + ], "Predicate called with the value and the index"); + + // wait a tick, just to prove that you have to wait for complete to be called. + await Promise.resolve(); + + assert_false(promiseResolved, + "Promise should not resolve until after the source completes"); + + source.complete(); + assert_array_equals(logs, [ + "subscribed to source", + "Predicate called with a, 0", + "Predicate called with b, 1", + "teardown", + ], "Teardown function called immediately after the source completes"); + + const result = await resultPromise; + + assert_true(result, + "Promise resolves with true if all values pass the predicate"); +}, "every(): Lifecycle checks when all values pass the predicate"); + +promise_test(async () => { + const logs = []; + + const source = createTestSubject({ + onSubscribe: () => logs.push("subscribed to source"), + onTeardown: () => logs.push("teardown"), + }); + + const resultPromise = source.every((value, index) => { + logs.push(`Predicate called with ${value}, ${index}`); + return value === "good"; + }); + + let promiseResolved = false; + + resultPromise.then(() => promiseResolved = true); + + assert_array_equals(logs, ["subscribed to source"], + "calling every() subscribes to the source immediately"); + + source.next("good"); + source.next("good"); + assert_array_equals(logs, [ + "subscribed to source", + "Predicate called with good, 0", + "Predicate called with good, 1", + ], "Predicate called with the value and the index"); + + assert_false(promiseResolved, "Promise should not resolve until after the predicate fails"); + + source.next("bad"); + assert_array_equals(logs, [ + "subscribed to source", + "Predicate called with good, 0", + "Predicate called with good, 1", + "Predicate called with bad, 2", + "teardown", + ], "Predicate called with the value and the index, failing predicate immediately aborts subscription to source"); + + const result = await resultPromise; + + assert_false(result, "Promise resolves with false if any value fails the predicate"); +}, "every(): Lifecycle checks when any value fails the predicate"); + +promise_test(async () => { + const source = new Observable(subscriber => { + subscriber.complete(); + }); + + const result = await source.every(() => true); + + assert_true(result, + "Promise resolves with true if the observable completes without " + + "emitting a value"); +}, "every(): Resolves with true if the observable completes without " + + "emitting a value"); + +promise_test(async t => { + const error = new Error("error from source"); + const source = new Observable(subscriber => { + subscriber.error(error); + }); + + promise_rejects_exactly(t, error, source.every(() => true), + "Promise rejects with the error emitted from the source observable"); +}, "every(): Rejects with any error emitted from the source observable"); + +promise_test(async t => { + const source = new Observable(subscriber => { + subscriber.next(1); + subscriber.next(2); + subscriber.next(3); + subscriber.complete(); + }); + + const error = new Error("bad value"); + const promise = source.every(value => { + if (value <= 2) return true; + throw error; + }); + + promise_rejects_exactly(t, error, promise, "Promise rejects with the " + + "error thrown from the predicate"); +}, "every(): Rejects with any error thrown from the predicate"); + +promise_test(async () => { + const indices = []; + + const source = new Observable(subscriber => { + subscriber.next("a"); + subscriber.next("b"); + subscriber.next("c"); + subscriber.complete(); + }); + + const value = await source.every((value, index) => { + indices.push(index); + return true; + }); + + assert_array_equals(indices, [0, 1, 2]); + + assert_true(value, + "Promise resolves with true if all values pass the predicate"); +}, "every(): Index is passed into the predicate"); + +promise_test(async t => { + const source = new Observable(subscriber => {}); + + const controller = new AbortController(); + const promise = source.every(() => true, { signal: controller.signal }); + controller.abort(); + + promise_rejects_dom(t, 'AbortError', promise, "Promise rejects with a " + + "DOMException if the source Observable is aborted"); +}, "every(): Rejects with a DOMException if the source Observable is aborted"); + +function createTestSubject(options) { + const onTeardown = options?.onTeardown; + + const subscribers = new Set(); + const subject = new Observable(subscriber => { + options?.onSubscribe?.(); + subscribers.add(subscriber); + subscriber.addTeardown(() => subscribers.delete(subscriber)); + if (onTeardown) { + subscriber.addTeardown(onTeardown); + } + }); + + subject.next = (value) => { + for (const subscriber of Array.from(subscribers)) { + subscriber.next(value); + } + }; + subject.error = (error) => { + for (const subscriber of Array.from(subscribers)) { + subscriber.error(error); + } + }; + subject.complete = () => { + for (const subscriber of Array.from(subscribers)) { + subscriber.complete(); + } + }; + subject.subscriberCount = () => { + return subscribers.size; + }; + + return subject; +} diff --git a/testing/web-platform/tests/dom/observable/tentative/observable-filter.any.js b/testing/web-platform/tests/dom/observable/tentative/observable-filter.any.js index 8a49bcf467..3c1a7d7824 100644 --- a/testing/web-platform/tests/dom/observable/tentative/observable-filter.any.js +++ b/testing/web-platform/tests/dom/observable/tentative/observable-filter.any.js @@ -103,3 +103,15 @@ test(() => { ['source teardown', 'source abort event', 'filter observable complete']); }, "filter(): Upon source completion, source Observable teardown sequence " + "happens after downstream filter complete() is called"); + +test(() => { + const source = new Observable(subscriber => { + subscriber.next('value1'); + subscriber.next('value2'); + subscriber.next('value3'); + }); + + const indices = []; + source.filter((value, index) => indices.push(index)).subscribe(); + assert_array_equals(indices, [0, 1, 2]); +}, "filter(): Index is passed correctly to predicate"); diff --git a/testing/web-platform/tests/dom/observable/tentative/observable-find.any.js b/testing/web-platform/tests/dom/observable/tentative/observable-find.any.js new file mode 100644 index 0000000000..0e09060fc5 --- /dev/null +++ b/testing/web-platform/tests/dom/observable/tentative/observable-find.any.js @@ -0,0 +1,85 @@ +promise_test(async () => { + let inactiveAfterB = false; + const source = new Observable(subscriber => { + subscriber.next("a"); + subscriber.next("b"); + inactiveAfterB = !subscriber.active; + subscriber.next("c"); + subscriber.complete(); + }); + + const value = await source.find((value) => value === "b"); + + assert_equals(value, "b", "Promise resolves with the first value that passes the predicate"); + + assert_true(inactiveAfterB, "subscriber is inactive after the first value that passes the predicate"); +}, "find(): Promise resolves with the first value that passes the predicate"); + +promise_test(async () => { + const source = new Observable(subscriber => { + subscriber.next("a"); + subscriber.next("b"); + subscriber.next("c"); + subscriber.complete(); + }); + + const value = await source.find(() => false); + + assert_equals(value, undefined, "Promise resolves with undefined if no value passes the predicate"); +}, "find(): Promise resolves with undefined if no value passes the predicate"); + +promise_test(async t => { + const error = new Error("error from source"); + const source = new Observable(subscriber => { + subscriber.error(error); + }); + + promise_rejects_exactly(t, error, source.find(() => true), "Promise " + + "rejects with the error emitted from the source Observable"); +}, "find(): Promise rejects with the error emitted from the source Observable"); + +promise_test(async t => { + const source = new Observable(subscriber => { + subscriber.next("ignored"); + }); + + const error = new Error("thrown from predicate"); + promise_rejects_exactly(t, error, source.find(() => {throw error}), + "Promise rejects with any error thrown from the predicate"); +}, "find(): Promise rejects with any error thrown from the predicate"); + +promise_test(async () => { + let indices = []; + + const source = new Observable(subscriber => { + subscriber.next("a"); + subscriber.next("b"); + subscriber.next("c"); + subscriber.complete(); + }); + + const value = await source.find((value, index) => { + indices.push(index); + return false; + }); + + assert_equals(value, undefined, "Promise resolves with undefined if no value passes the predicate"); + + assert_array_equals(indices, [0, 1, 2], "find(): Passes the index of the value to the predicate"); +}, "find(): Passes the index of the value to the predicate"); + +promise_test(async t => { + const controller = new AbortController(); + const source = new Observable(subscriber => { + subscriber.next("a"); + subscriber.next("b"); + subscriber.next("c"); + subscriber.complete(); + }); + + controller.abort(); + const promise = source.find(() => true, { signal: controller.signal }); + + promise_rejects_dom(t, 'AbortError', promise, "Promise rejects with " + + "DOMException when the signal is aborted"); +}, "find(): Rejects with AbortError when the signal is aborted"); diff --git a/testing/web-platform/tests/dom/observable/tentative/observable-inspect.any.js b/testing/web-platform/tests/dom/observable/tentative/observable-inspect.any.js new file mode 100644 index 0000000000..8aff741d26 --- /dev/null +++ b/testing/web-platform/tests/dom/observable/tentative/observable-inspect.any.js @@ -0,0 +1,412 @@ +// Because we test that the global error handler is called at various times. +setup({ allow_uncaught_exception: true }); + +test(() => { + const results = []; + let sourceSubscriptionCall = 0; + const source = new Observable(subscriber => { + sourceSubscriptionCall++; + results.push(`source subscribe ${sourceSubscriptionCall}`); + subscriber.next(1); + subscriber.next(2); + subscriber.next(3); + subscriber.complete(); + }); + + let inspectSubscribeCall = 0; + const result = source.inspect({ + subscribe: () => { + inspectSubscribeCall++; + results.push(`inspect() subscribe ${inspectSubscribeCall}`); + }, + next: (value) => results.push(`inspect() next ${value}`), + error: (e) => results.push(`inspect() error ${e.message}`), + complete: () => results.push(`inspect() complete`), + }); + + result.subscribe({ + next: (value) => results.push(`result next ${value}`), + error: (e) => results.push(`result error ${e.message}`), + complete: () => results.push(`result complete`), + }); + + result.subscribe({ + next: (value) => results.push(`result next ${value}`), + error: (e) => results.push(`result error ${e.message}`), + complete: () => results.push(`result complete`), + }); + + assert_array_equals(results, + [ + "inspect() subscribe 1", + "source subscribe 1", + "inspect() next 1", + "result next 1", + "inspect() next 2", + "result next 2", + "inspect() next 3", + "result next 3", + "inspect() complete", + "result complete", + "inspect() subscribe 2", + "source subscribe 2", + "inspect() next 1", + "result next 1", + "inspect() next 2", + "result next 2", + "inspect() next 3", + "result next 3", + "inspect() complete", + "result complete", + ]); +}, "inspect(): Provides a pre-subscription subscribe callback"); + +test(() => { + const source = new Observable(subscriber => { + subscriber.next(1); + subscriber.next(2); + subscriber.next(3); + subscriber.complete(); + }); + + const results = []; + + const result = source.inspect({ + next: value => results.push(value), + error: e => results.push(e), + complete: () => results.push("complete"), + }); + + result.subscribe(); + result.subscribe(); + + assert_array_equals(results, [1, 2, 3, "complete", 1, 2, 3, "complete"]); +}, "inspect(): Provides a way to tap into the values and completions of the " + + "source observable using an observer"); + +test(() => { + const error = new Error("error from source"); + const source = new Observable(subscriber => subscriber.error(error)); + + const results = []; + + const result = source.inspect({ + next: value => results.push(value), + error: e => results.push(e), + complete: () => results.push("complete"), + }); + + let errorReported = null; + self.addEventListener('error', e => errorReported = e.error, {once: true}); + result.subscribe(); + + assert_array_equals(results, [error]); + assert_equals(errorReported, error, + "errorReported to global matches error from source Observable"); +}, "inspect(): Error handler does not stop error from being reported to the " + + "global, when subscriber does not pass error handler"); + +test(() => { + const error = new Error("error from source"); + const source = new Observable(subscriber => { + subscriber.next(1); + subscriber.next(2); + subscriber.next(3); + subscriber.error(error); + }); + + const results = []; + + const result = source.inspect({ + next: value => results.push(value), + error: e => results.push(e), + complete: () => results.push("complete"), + }); + + const observer = { + error: e => results.push(e), + }; + result.subscribe(observer); + result.subscribe(observer); + + assert_array_equals(results, [1, 2, 3, error, error, 1, 2, 3, error, error]); +}, "inspect(): Provides a way to tap into the values and errors of the " + + "source observable using an observer. Errors are passed through"); + +test(() => { + const source = new Observable(subscriber => { + subscriber.next(1); + subscriber.next(2); + subscriber.next(3); + subscriber.complete(); + }); + + const results = []; + + const result = source.inspect(value => results.push(value)); + + result.subscribe(); + result.subscribe(); + + assert_array_equals(results, [1, 2, 3, 1, 2, 3]); +}, "inspect(): ObserverCallback passed in"); + +test(() => { + const source = new Observable(subscriber => { + subscriber.next(1); + subscriber.next(2); + subscriber.next(3); + }); + + const error = new Error("error from inspect() next handler"); + const result = source.inspect({ + next: (value) => { + if (value === 2) { + throw error; + } + }, + }); + + const results1 = []; + result.subscribe({ + next: (value) => results1.push(value), + error: (e) => results1.push(e), + complete: () => results1.push("complete"), + }); + + const results2 = []; + result.subscribe({ + next: (value) => results2.push(value), + error: (e) => results2.push(e), + complete: () => results2.push("complete"), + }); + + assert_array_equals(results1, [1, error]); + assert_array_equals(results2, [1, error]); +}, "inspect(): Throwing an error in the observer next handler is caught and " + + "sent to the error callback of the result observable"); + +test(() => { + const sourceError = new Error("error from source"); + const inspectError = new Error("error from inspect() error handler"); + + const source = new Observable(subscriber => { + subscriber.error(sourceError); + }); + + const result = source.inspect({ + error: () => { + throw inspectError; + }, + }); + + const results = []; + result.subscribe({ + next: () => results.push("next"), + error: (e) => results.push(e), + complete: () => results.push("complete"), + }); + + assert_array_equals(results, [inspectError]); +}, "inspect(): Throwing an error in the observer error handler in " + + "inspect() is caught and sent to the error callback of the result " + + "observable"); + +test(() => { + const source = new Observable(subscriber => { + subscriber.next(1); + subscriber.next(2); + subscriber.next(3); + subscriber.complete(); + }); + + const error = new Error("error from inspect() complete handler"); + const result = source.inspect({ + complete: () => { + throw error; + }, + }); + + const results = []; + result.subscribe({ + next: (value) => results.push(value), + error: (e) => results.push(e), + complete: () => results.push("complete"), + }); + + assert_array_equals(results, [1, 2, 3, error]); +}, "inspect(): Throwing an error in the observer complete handler is caught " + + "and sent to the error callback of the result observable"); + +test(() => { + const source = new Observable(subscriber => { + subscriber.next(1); + subscriber.next(2); + subscriber.next(3); + }); + + const error = new Error("error from inspect() next handler"); + const result = source.inspect({ + next: (value) => { + if (value === 2) { + throw error; + } + }, + }); + + const results = []; + result.subscribe({ + next: (value) => results.push(value), + error: (e) => results.push(e), + complete: () => results.push("complete"), + }); + + assert_array_equals(results, [1, error]); +}, "inspect(): Throwing an error in the next handler function in do should " + + "be caught and sent to the error callback of the result observable"); + +test(() => { + const source = new Observable(subscriber => {}); + + const result = source.inspect({ + subscribe: () => { + throw new Error("error from do subscribe handler"); + }, + }); + + const results = []; + result.subscribe({ + next: () => results.push("next"), + error: (e) => results.push(e.message), + complete: () => results.push("complete"), + }); + + assert_array_equals(results, ["error from do subscribe handler"]); +}, "inspect(): Errors thrown in subscribe() Inspector handler subscribe " + + "handler are caught and sent to error callback"); + +test(() => { + const results = []; + let sourceTeardownCall = 0; + const source = new Observable(subscriber => { + subscriber.addTeardown(() => { + sourceTeardownCall++; + results.push(`source teardown ${sourceTeardownCall}`); + }); + subscriber.next(1); + subscriber.next(2); + subscriber.next(3); + subscriber.complete(); + }); + + let doUnsubscribeCall = 0; + const result = source.inspect({ + abort: (reason) => { + doUnsubscribeCall++; + results.push(`inspect() abort ${doUnsubscribeCall} ${reason}`); + }, + next: (value) => results.push(`inspect() next ${value}`), + error: (e) => results.push(`inspect() error ${e.message}`), + complete: () => results.push(`inspect() complete`), + }); + + const controller = new AbortController(); + result.subscribe({ + next: (value) => { + results.push(`result next ${value}`); + if (value === 2) { + controller.abort("abort reason"); + } + }, + error: (e) => results.push(`result error ${e.message}`), + complete: () => results.push(`result complete`), + }, { signal: controller.signal }); + + assert_array_equals(results, [ + "inspect() next 1", + "result next 1", + "inspect() next 2", + "result next 2", + "inspect() abort 1 abort reason", + "source teardown 1", + ]); +}, "inspect(): Provides a way to tap into the moment a source observable is unsubscribed from"); + +test(() => { + const results = []; + let sourceTeardownCall = 0; + const source = new Observable(subscriber => { + subscriber.addTeardown(() => { + sourceTeardownCall++; + results.push(`source teardown ${sourceTeardownCall}`); + }); + subscriber.next(1); + subscriber.next(2); + subscriber.next(3); + subscriber.complete(); + }); + + let inspectUnsubscribeCall = 0; + const result = source.inspect({ + next: (value) => results.push(`inspect() next ${value}`), + complete: () => results.push(`inspect() complete`), + abort: (reason) => { + inspectUnsubscribeCall++; + results.push(`inspect() abort ${inspectUnsubscribeCall} ${reason}`); + }, + }); + + result.subscribe({ + next: (value) => results.push(`result next ${value}`), + complete: () => results.push(`result complete`), + }); + + assert_array_equals(results, [ + "inspect() next 1", + "result next 1", + "inspect() next 2", + "result next 2", + "inspect() next 3", + "result next 3", + "source teardown 1", + "inspect() complete", + "result complete", + ]); +}, "inspect(): Inspector abort() handler is not called if the source " + + "completes before the result is unsubscribed from"); + +test(() => { + const source = new Observable(subscriber => { + subscriber.next(1); + }); + + const results = []; + + const result = source.inspect({ + abort: () => { + results.push('abort() handler run'); + throw new Error("error from inspect() subscribe handler"); + }, + }); + + const controller = new AbortController(); + + self.on('error').take(1).subscribe(e => + results.push(e.message + ', from report exception')); + + result.subscribe({ + next: (value) => { + results.push(value); + controller.abort(); + }, + // This should not be invoked at all!! + error: (e) => results.push(e.message + ', from Observer#error()'), + complete: () => results.push("complete"), + }, {signal: controller.signal}); + + assert_array_equals(results, [1, "abort() handler run", + "Uncaught Error: error from inspect() subscribe handler, from report " + + "exception"]); +}, "inspect(): Errors thrown from inspect()'s abort() handler are caught " + + "and reported to the global, because the subscription is already closed " + + "by the time the handler runs"); diff --git a/testing/web-platform/tests/dom/observable/tentative/observable-some.any.js b/testing/web-platform/tests/dom/observable/tentative/observable-some.any.js new file mode 100644 index 0000000000..b692610df3 --- /dev/null +++ b/testing/web-platform/tests/dom/observable/tentative/observable-some.any.js @@ -0,0 +1,96 @@ +promise_test(async () => { + let inactiveAfterFirstGood = true; + + const source = new Observable(subscriber => { + subscriber.next("good"); + inactiveAfterFirstGood = !subscriber.active; + subscriber.next("good"); + subscriber.next("good"); + subscriber.complete(); + }); + + const result = await source.some((value) => value === "good"); + + assert_true(result, "Promise resolves with true if any value passes the predicate"); + + assert_true(inactiveAfterFirstGood, + "subscriber is inactive after the first value that passes the " + + "predicate, because the source was unsubscribed from"); +}, "some(): subscriber is inactive after the first value that passes the predicate, because the source was unsubscribed from"); + +promise_test(async () => { + const source = new Observable(subscriber => { + subscriber.next("bad"); + subscriber.next("bad"); + subscriber.next("bad"); + subscriber.complete(); + }); + + const result = await source.some((value) => value === "good"); + + assert_false(result, "some(): Promise resolves with false if no value passes the predicate"); +}); + +promise_test(async () => { + const source = new Observable(subscriber => { + subscriber.next("bad"); + subscriber.next("bad"); + subscriber.next("good"); + subscriber.complete(); + }); + + const result = await source.some((value) => value === "good"); + + assert_true(result, "some(): Promise resolves with true if any value passes the predicate"); +}); + +promise_test(async t => { + const source = new Observable(subscriber => { + subscriber.next("not used"); + }); + + const error = new Error("thrown from predicate"); + promise_rejects_exactly(t, error, source.some(() => {throw error}), + "The returned promise rejects with an error if the predicate errors"); +}, "some(): The returned promise rejects with an error if the predicate errors"); + +promise_test(async t => { + const error = new Error("error from source"); + const source = new Observable(subscriber => { + subscriber.error(error); + }); + + promise_rejects_exactly(t, error, source.some(() => true), + "The returned promise rejects with an error if the source observable errors"); +}, "some(): The returned promise rejects with an error if the source observable errors"); + +promise_test(async () => { + const source = new Observable(subscriber => { + subscriber.complete(); + }); + + const result = await source.some(() => true); + + assert_false(result, + "The returned promise resolves as false if the source observable " + + "completes without emitting a value"); +}, "some(): The returned promise resolves as false if the source observable " + + "completes without emitting a value"); + +promise_test(async t => { + let teardownCalled = false; + const source = new Observable(subscriber => { + subscriber.addTeardown(() => { + teardownCalled = true; + }); + }); + + const controller = new AbortController(); + const promise = source.some(() => true, { signal: controller.signal }); + + controller.abort(); + + promise_rejects_dom(t, 'AbortError', promise); + assert_true(teardownCalled, + "The teardown function is called when the signal is aborted"); +}, "some(): The return promise rejects with a DOMException if the signal is aborted"); -- cgit v1.2.3