Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests to ensure generator teardown in converted observables #47874

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 193 additions & 0 deletions dom/observable/tentative/observable-from.any.js
Original file line number Diff line number Diff line change
Expand Up @@ -352,3 +352,196 @@ test(() => {
assert_array_equals(results, ["from @@iterator", "complete"]);
}, "from(): Promise that implements @@iterator protocol gets converted as " +
"an iterable, not Promise");

test(() => {
const results = [];
let generatorFinalized = false;

const generator = function* () {
try {
for (let n = 0; n < 10; n++) {
yield n;
}
} catch {
assert_unreached("generator should not be aborted");
} finally {
generatorFinalized = true;
}
};

const observable = Observable.from(generator());

const abortController = new AbortController();

observable.subscribe((n) => {
results.push(n);
if (n === 3) {
abortController.abort();
}
}, { signal: abortController.signal });

assert_array_equals(results, [0, 1, 2, 3],
"from(): generator values are emitted until aborted");

assert_true(generatorFinalized, "from(): generator finalization should be called when the observable subscription is aborted");

}, "from(): generator finalization should be called when the observable subscription is aborted");

test(() => {
const results = [];
let generatorFinalized = false;

const generator = function* () {
try {
for (let n = 0; n < 10; n++) {
yield n;
}
} catch {
assert_unreached("generator should not be aborted");
} finally {
generatorFinalized = true;
}
};

const observable = Observable.from(generator());

observable.subscribe((n) => {
results.push(n);
});

assert_array_equals(results, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
"from(): generator values are emitted until the generator completes");

assert_true(generatorFinalized, "from(): generator finalization should be called when the observable completes");
}, "from(): generator finalization should be called when the observable completes");

test(() => {
const results = [];
let generatorFinalized = false;

const generator = function* () {
try {
for (let n = 0; n < 10; n++) {
yield n;
}
throw new Error('from the generator');
} finally {
generatorFinalized = true;
}
};

const observable = Observable.from(generator());

observable.subscribe({
next: (n) => results.push(n),
error: (e) => results.push(e.message)
});

assert_array_equals(results, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "from the generator"],
"from(): generator values are emitted until the generator errors");

assert_true(generatorFinalized, "from(): generator finalization should be called when the observable errors");
}, "from(): generator finalization should be called when the observable errors");


promise_test(async t => {
const results = [];
let generatorFinalized = false;

async function* asyncGenerator() {
try {
for (let n = 0; n < 10; n++) {
await Promise.resolve(); // some delay for "realism".
yield n;
}
} finally {
generatorFinalized = true;
}
}

const observable = Observable.from(asyncGenerator());

const abortController = new AbortController();

await new Promise((resolve) => {
observable.subscribe((n) => {
results.push(n);
if (n === 3) {
abortController.abort();
resolve();
}
}, { signal: abortController.signal });
});

assert_array_equals(results, [0, 1, 2, 3],
"from(): async generator values are emitted until aborted");

assert_true(generatorFinalized, "from(): async generator finalization should be called when the observable subscription is aborted");

}, "from(): async generator finalization should be called when the observable subscription is aborted");

promise_test(async t => {
const results = [];
let generatorFinalized = false;

async function* asyncGenerator() {
try {
for (let n = 0; n < 10; n++) {
await Promise.resolve(); // some delay for "realism".
yield n;
}
} finally {
generatorFinalized = true;
}
}

const observable = Observable.from(asyncGenerator());

await new Promise((resolve) => {
observable.subscribe((n) => {
results.push(n);
if (n === 3) {
resolve();
}
});
});

assert_array_equals(results, [0, 1, 2, 3],
"from(): async generator values are emitted until the generator completes");

assert_true(generatorFinalized, "from(): async generator finalization should be called when the observable completes");
}, "from(): async generator finalization should be called when the observable completes");

promise_test(async t => {
const results = [];
let generatorFinalized = false;

async function* asyncGenerator() {
try {
for (let n = 0; n < 10; n++) {
await Promise.resolve(); // some delay for "realism".
yield n;
}
throw new Error('from the async generator');
} finally {
generatorFinalized = true;
}
}

const observable = Observable.from(asyncGenerator());

await new Promise((resolve) => {
observable.subscribe({
next: (n) => results.push(n),
error: (e) => {
results.push(e.message);
resolve();
}
});
});

assert_array_equals(results, [0, 1, 2, 3, "from the async generator"],
"from(): async generator values are emitted until the generator errors");

assert_true(generatorFinalized, "from(): async generator finalization should be called when the observable errors");
}, "from(): async generator finalization should be called when the observable errors");