Skip to content

Commit

Permalink
DOM: Implement the last() Observable operator
Browse files Browse the repository at this point in the history
See WICG/observable#133. This CL implements the
`last()` operator which returns a Promise that resolves to the last
item that the source Observable emits, and rejects with a RangeError
if the Observable completes prematurely.

For WPTs:
Co-authored-by: [email protected]

[email protected]

Bug: 40282760
Change-Id: Id1ec2af152c288ae81dfe383dfa9a7f166cfb375
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5417373
Reviewed-by: Di Zhang <[email protected]>
Commit-Queue: Dominic Farolino <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1282037}
  • Loading branch information
domfarolino authored and chromium-wpt-export-bot committed Apr 3, 2024
1 parent 6673c54 commit 4f97207
Showing 1 changed file with 113 additions and 0 deletions.
113 changes: 113 additions & 0 deletions dom/observable/tentative/observable-last.any.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
promise_test(async () => {
const source = new Observable(subscriber => {
// Never exposed to the `last()` promise.
subscriber.next(1);

subscriber.next(2);
subscriber.complete();
});

const value = await source.last();

assert_equals(value, 2);
}, "last(): Promise resolves to last value");

promise_test(async () => {
const error = new Error("error from source");
const source = new Observable(subscriber => {
subscriber.error(error);
});

let rejection = null;
try {
await source.last();
} catch (e) {
rejection = e;
}

assert_equals(rejection, error);
}, "last(): Promise rejects with emitted error");

promise_test(async () => {
const source = new Observable(subscriber => {
subscriber.complete();
});

let rejection = null;
try {
await source.last();
} catch (e) {
rejection = e;
}

assert_true(rejection instanceof RangeError,
"Promise rejects with RangeError");
assert_equals(rejection.message, "No values in Observable");
}, "last(): Promise rejects with RangeError when source Observable " +
"completes without emitting any values");

promise_test(async () => {
const source = new Observable(subscriber => {});

const controller = new AbortController();
const promise = source.last({ signal: controller.signal });

controller.abort();

let rejection = null;
try {
await promise;
} catch (e) {
rejection = e;
}

assert_true(rejection instanceof DOMException,
"Promise rejects with a DOMException for abortion");
assert_equals(rejection.name, "AbortError",
"Rejected with 'AbortError' DOMException");
assert_equals(rejection.message, "signal is aborted without reason");
}, "last(): Aborting a signal rejects the Promise with an AbortError DOMException");

promise_test(async () => {
const results = [];
const source = new Observable(subscriber => {
results.push("source subscribe");
subscriber.addTeardown(() => results.push("source teardown"));
subscriber.signal.addEventListener("abort", () => results.push("source abort"));
results.push("before source next 1");
subscriber.next(1);
results.push("after source next 1");
results.push("before source complete");
subscriber.complete();
results.push("after source complete");
});

results.push("calling last");
const promise = source.last();

assert_array_equals(results, [
"calling last",
"source subscribe",
"before source next 1",
"after source next 1",
"before source complete",
"source teardown",
"source abort",
"after source complete",
], "Array values after last() is called");

const lastValue = await promise;
results.push(`last resolved with: ${lastValue}`);

assert_array_equals(results, [
"calling last",
"source subscribe",
"before source next 1",
"after source next 1",
"before source complete",
"source teardown",
"source abort",
"after source complete",
"last resolved with: 1",
], "Array values after Promise is awaited");
}, "last(): Lifecycle");

0 comments on commit 4f97207

Please sign in to comment.