-
Notifications
You must be signed in to change notification settings - Fork 69
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
test: add initial watch mode test suite #386
Conversation
Failing Windows tests seem to be due to #385 , not the tests here |
|
|
|
Tracing instrumentation is good, maybe add a new verbosity level if you plan to add massive amounts of output |
- test starting watch mode, changing a file, and adding a semantic error - put this in a separate file as it has its own complexity to deal with (see below) - initially put it inside `no-errors`, but it got pretty confusing; this structure is a good bit simpler - refactored this a couple times actually - add two watch mode helpers - `watchBundle` is very similar to `genBundle` but with some watch mode nuances (like returning a watcher) - `watchEnd` is a bit complicated async wrapper around a listener interface to make imperative testing simpler - refactor: abstract out `createInput` and `createOutput` to be used in both `genBundle` and `watchBundle` - refactor: make sure `dist` output gets put into a temp test dir - the previous config made it output into rpt2's `dist` dir, since `cwd` is project root (when running tests from project root) - the Rollup API's `watch` func always writes out; can't just test in-memory like with `bundle.generate` - so the `dist` dir becomes relevant as such - refactor: pass in a temp `testDir` instead of the `cacheRoot` - we can derive the `cacheRoot` and the `dist` output from `testDir` - also improve test clean-up by removing `testDir` at the end, not just the `cacheRoot` dir inside it - `testDir` is the same var used in the unit tests to define a temp dir for testing - change the `no-errors` fixture a tiny bit so that changing the import causes it to change too - this ended up being fairly complex due to having to handle lots of async and parallelism - parallel testing means fixtures have to be immutable, but watch mode needs to modify files - ended up copying fixtures to a temp dir where I could modify them - async events are all over here - had to convert a callback listener interface to async too, which was pretty confusing - and make sure the listener and bundles got properly closed too so no leaky tests - apparently `expect.rejects.toThrow` can return a Promise too, so missed this error for a while - refactor: make sure the error spec awaits too (though I think the errors _happen_ to throw synchronously there) - and also found a number of bugs while attempting to test cache invalidation within watch mode - thought it was a natural place to test since watch mode testing needs to modify files anyway - had to trace a bunch to figure out why some code paths weren't being covered; will discuss this separately from this commit - testing Rollup watch within Jest watch also causes Jest to re-run a few times - I imagine double, overlapping watchers are confusing each other - might need to disable these tests when using Jest watch - high complexity async + parallel flows makes it pretty confusing to debug, so this code needs to be "handled with care" - also this high complexity was even harder to debug when I'm having migraines (which is most of the time, unfortunately) - hence why it took me a bit to finally make a PR for this small amount of code; the code was ok, the debugging was not too fun
dae4143
to
37f4247
Compare
Rebased with |
Yea, so I think the problem is that Since #345 implemented the I suppose we could create another var, The Aside: did also look around and only found two Acorn plugins for TS; giving Rollup better knowledge of the TS AST could potentially simplify the integration, particularly when it comes to module graph issues like this, but there's some hurdles to that approach too 😕 .
Yea I thought about using it when reading #177, then I realized it's already in the codebase so was like "nvm".
Was gonna add a |
@ezolenko not sure if changing your GitHub notification settings may have broke something, so figured I'd send a friendly ping as I've got this PR and a dozen+ others waiting now (and then another handful built on top of those, left as "Drafts" currently 😅 ). No worries if you just haven't had time to review these! Just thought it might be due to the notification settings changes (as that was recent) instead of time, so sending a ping just in case. |
@agilgur5 it was both, I killed all emails and was offline for 2 weeks :) I'll review the PRs in the next few days... |
@ezolenko have you had any time for reviews recently? There's still a dozen+ PRs in the queue and I have more on top of those as well (built on top of some of the current drafts etc) 😕 A patch release has also been needed for a bit now as some fixes have been sitting unreleased for ~2 months now and we've had at least two users request one. I was planning to PR a |
Summary
Creates a test harness/structure for watch mode tests and adds an initial test suite to it
Details
test starting watch mode, changing a file, and adding a semantic error
no-errors
, but it got pretty confusing; this structure is a good bit simpleradd two watch mode helpers
watchBundle
is very similar togenBundle
but with some watch mode nuances (like returning a watcher)watchEnd
is a bit complicated async wrapper around a listener interface to make imperative testing simplercreateInput
andcreateOutput
to be used in bothgenBundle
andwatchBundle
dist
output gets put into a temp test dirdist
dir, sincecwd
is project root (when running tests from project root)watch
func always writes out; can't just test in-memory like withbundle.generate
dist
dir becomes relevant as suchtestDir
instead of thecacheRoot
cacheRoot
and thedist
output fromtestDir
testDir
at the end, not just thecacheRoot
dir inside ittestDir
is the same var used in the unit tests to define a temp dir for testingchange the
no-errors
fixture a tiny bit so that changing the import causes it to change toothis ended up being fairly complex due to having to handle lots of async and parallelism
expect.rejects.toThrow
can return a Promise too, so missed this error for a whileFound several bugs
Per above, in the process of writing this, I discovered lots of bugs with watch mode itself as well as cache invalidation during watch mode. This took some tracing to figure out, so see this annotated trace log I manually created:
Trace log:
Per the annotations, there are a few bugs:
walkTree
seems entirely unnecessary: it duplicates the existing type-checkswalkTree
usesRollupContext
instead ofConsoleContext
we get duplicate warnings in the tests when usingabortOnError: false
.tscache
constructor is only called once since it's created on plugin init and not in theoptions
hookcloseWatcher
hook to roll caches in watch mode instead of duringbuildEnd
may be a workaround for thisinit
wasprivate
before andclean
was only called whenpluginOptions.clean
options
hook in watch mode nor during thewatchChange
hookDocumentRegistry
between watch cycles instead of resetting it in theoptions
hooknoErrors
not being reset, but that's only used when not in watch mode, so maybe there aren't as many issues?checkImports
, the coverage report shows that the imports are never checked in watch mode (at least)dirty
. Since, in the current buggy watch mode, these are never reset (per above), they will always bedirty
if starting from an empty / clean cache.noCache
mode, with I/O / FS being a general bottleneck to watch out for).Related: Since I manually wrote debug log traces to track these down, it might be good to straight up add tracing / output a trace in debug verbosity, whether via library, runtime-native, or other. This could potentially obviate the need for debug logging as well and be a very powerful debugging / telemetry tool.