-
Notifications
You must be signed in to change notification settings - Fork 143
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
Issue mocking exports via jest - inconsistency with Babel behaviour #715
Comments
Hi @jdb8 , thanks for the detailed report! Getting this sort of thing working is definitely in scope for Sucrase, even though, as you mention, some people might argue that you shouldn't be writing tests like this. At my company (where we use Sucrase for local dev and Babel/TypeScript in CI and production), we also have plenty of test code that directly patches module objects like you're describing. I think I have a pretty good handle on what's going wrong, at least for your first case, and I have some theories about the second case. Happy to explain what's going on. It's likely that there's a reasonable fix to make Sucrase work seamlessly here, though I'd need to think a little more about implementation details and backcompat concerns. To explain the issue, it's good to first understand how ES modules (
(There are other details with the spec like async loading and requiring file extensions, but those aren't relevant here.) That second bullet point means that your code would break when switching to true ES modules, since The first bullet point (live bindings) is the main challenge that Babel, TypeScript, and Sucrase need to deal with when converting For more complex scenarios like import-and-export, the tools diverge a bit more, but it's probably fair to say that Babel is more correct. Babel defines a computed getter that reads the latest value from the other module, while TypeScript and Sucrase just access the value at import time (i.e. it's not actually a live binding). It looks like TS behaves differently when re-exporting a default import vs re-exporting a named import, even though both should ideally have live bindings. Sucrase actually does do the right thing if you change the re-export to look like this: export {default as getValue} from './some-lib'; so you could try that as a workaround and see if that helps. The way to get your code working fully in Sucrase is for Sucrase to recognize that the export is from an import and write it to use a getter instead. This could possibly cause issues with tests assuming that the export is editable, so I'm a little hesitant about backcompat concerns, but I'd need to think about it; it might be fine. With your |
@alangpierce thank you for the very detailed explanation! I'll try out what you suggested. I was also able to make things work in the specific case I ran into by updating the code to import from the same place we were trying to mock, but I'm imagining that in some places that may not be easy or possible. Good point re:ESM, it's one of the potential future blockers to switching over so this may be a good forcing function to update some tests that are a little too reliant on transpiled behaviour. Definitely interested if there's something that can be done inside sucrase to make things magically work, though! But this stuff seems pretty complex so I understand if it's too risky :) |
Hi there, first off - thanks for making this library! I've been playing around on a large existing codebase comparing timings with Babel and it looks really promising.
I've run into something strange when comparing Babel and Sucrase for a few cases in Jest. I realise this may end up being a case of "don't do what you're doing in your test", but I think it's worth noting that Babel appears to be fine with the code.
It's kind of hard to give a full explanation given that I don't yet understand what's going on, so I've made a repro here which should demonstrate a minimal example of what I'm talking about: https://github.com/jdb8/sucrase-jest-export-repro.
The issue seems to be that Babel somehow transpiles module exports in a way that makes this kind of transitive mocking/spying work, while Sucrase does not. I don't know if that means Babel or Jest are actually doing something wrong rather than Sucrase, but it's unfortunate as it limits my ability to hotswap our existing Babel transforms for Sucrase ones in many cases.
A related but similar case which felt easier to fix in the test itself was one where we were mocking the imported function like this:
Something about the difference between Babel and Sucrase also broke this code in a way I didn't fully understand, but I switched over to using
jest.mock
since arguably assigning things to exports like this isn't the right way to do things.Overall, both of these cases make me think that the way these exports are transpiled differently somehow matters: under babel exports seem to produce something like this:
vs
exports.getValue = _somelib2.default;
Would be very curious to hear your thoughts, since I think I'm missing some of the nuances around how both Babel and Sucrase treat this code, and why they take different approaches (and why that seems to matter here!). Thanks in advance for taking a look!
The text was updated successfully, but these errors were encountered: