Open jeengbe opened 1 month ago
☹️
yarn install v1.22.22
[1/4] Resolving packages...
[2/4] Fetching packages...
yarn run v1.22.22
$ eslint src spec
/bin/sh: 1: eslint: not found
error Command failed with exit code [12](https://github.com/ReactiveX/IxJS/actions/runs/10006204785/job/27677171680#step:7:13)7.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
Error: Process completed with exit code 127.
That's strange. Looking into it.
I don't know what's going on. It doesn't look like yarn is fetching eslint at all. It's possible something in the request chain is affected by the numerous outages today.
Tests passed, LGTM. @mattpodwysocki any thoughts?
Could you please take care of the change log and publish an update once this is merged? Thanks 🙂
Yes, changelog happens automatically when we publish. @mattpodwysocki requests a test to exercise the new behavior.
The tests are in the spec
dir, i.e. spec/iterable-operators/catcherror-spec.ts.
I think something like this should work for Iterable and can adapt for AsyncIterable:
test('Iterable#catchError calls return() on source iterator when no error', () => {
let done = false;
let returnCalled = false;
const xs = {
[Symbol.iterator]() { return xs; },
next: () => (done = !done) ? { value: 0 } : { done: true },
return: () => { returnCalled = true; }
};
const res = from(xs).pipe(catchError((_: Error) => of('foo')));
expect(sequenceEqual(res, range(0, 1))).toBeTruthy();
expect(returnCalled).toBeTruthy();
});
You can run the tests against the source via:
yarn test -t src --tests spec/iterable-operators/catcherror-spec.ts
Or to test against the compiled code:
# Compile all the output targets
yarn build
# Run the given test against each target
yarn test --tests spec/iterable-operators/catcherror-spec.ts
How do I debug tests? The tests fail for some reason, and I can't figure out how to attach a debugger, or even use console.log statements.
I tried console.log(CatchWithIterable.toString())
to check whether it's even executing the right code, but not even that log shows up in the console.
Also, if unrelated, I can't use jest in tests or I get ReferenceError: jest is not defined
.
You can debug the tests in VSCode via the "Debug Unit Tests" launch target.
augustocdias.tasks-shell-input
VSCode extensionI don't think we typically rely on the jasmine spy functions, but I do see one place we import and use them in aborting-spec.ts
.
We pass --reporters=jest-silent-reporter
to jest by default, unless you run the tests with --verbose
:
yarn test -t src --tests spec/iterable-operators/catcherror-spec.ts --verbose
I suspect this is why you weren't seeing your console.log()
statements.
I'm debugging the tests and it looks like we've stumbled across a closure compiler bug (wouldn't be the first time). I'll test if changing the implementation to not iterate manually fixes the issue.
Oh actually, I know the issue. Closure compiler's iterator rewriting replaces calls like it.return()
with returnIterator(it)
, meaning the jest.spyOn(xs, 'return')
never gets called (even though the iterators return()
logic does get executed). So we'll have to change the test to check a flag like in my example above.
Ah, I spoke too soon. It is indeed a closure compiler bug:
// test.js
function first(xs) {
for (let x of xs) {
return x;
}
}
let count = 0;
let returnCalled = false;
const xs = {
[Symbol.iterator]() { return xs; },
next() {
if (count < 3) {
return { value: count++, done: false };
}
return { done: true };
},
return() {
returnCalled = true;
return { done: true };
}
};
first(xs);
console.log('return called:', returnCalled);
$ npx google-closure-compiler --js test.js --js_output_file test.min.js --language_in ECMASCRIPT_NEXT --language_out ECMASCRIPT5 --assume_function_wrapper --compilation_level ADVANCED --third_party true
$ node test.js
> return called: true
$ node test.min.js
> return called: false
How do we proceed here? We could
a) quickfix the test by using a local implementation of first
that cc doesn't break
b) modify first()
to account for the same issue and go directly against https://github.com/ReactiveX/IxJS/pull/373#discussion_r1688486599
c) replace cc with tsc --downlevelIteration
? What's the reason cc is used in the first place, to reduce bundle size?
Your options A and B won't work, because the issue isn't with our code -- even if we implement a manual iterator, the issue is that closure compiler doesn't call the return()
function when it breaks or exits a for...of
loop. The only solution is option C, stop using closure-compiler.
The reason for closure-compiler is that historically, its (async)iterator and Promise polyfills have been both faster and smaller than alternatives, so we've tolerated its difficulties. That said, I haven't compared it to the downleveled iterators that use @swc/helpers
instead of tslib
, so maybe that's worth investigating again.
Why does Ix provide es5 code at all in the first place? for await...of
came with Node 10, which reached eol years ago. I assume browser bundlers do their own pass of converting to es5, so shipping es5 code is penalising performance for most users at the benefit of nothing?
catchError
currently swallows return signals. Instead of explicitly returning only if the source iterator is done or an error is thrown, always return it once done.I have briefly tried to add unit tests for this, but I couldn't find any other tests for similar behaviour and couldn't manage the juggle to spy on the return function.