-
Notifications
You must be signed in to change notification settings - Fork 16
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
fix(transfer): fix transfer undefined imports when testing #1137
base: master
Are you sure you want to change the base?
Conversation
🚀 Deployed on https://pr-1137--dhis2-ui.netlify.app |
Test summaryRun details
View run in Cypress Dashboard ➡️ This comment has been generated by cypress-bot as a result of this project's GitHub integration settings. You can manage this integration in this project's settings in the Cypress Dashboard |
Thanks for looking into this @ismay your analysis and explanation make a lot of sense. There is one thing I still don't fully understand, and it is relates to this:
I've copied your entire point and highlighted the part I find a bit confusing. You are suggesting that using Enzyme's But, thinking about the
Then I think things would still break. And you'd need to mock the UI component instead... Having said that, I guess there is not much we can do about this type of behaviour. Unless we fundamentally revisit our tooling and/or publishing setup.... |
Yeah the wording is a bit confusing maybe. What I meant is that you can assume that the component from @dhis2/ui is doing what it should. Since that's already tested in ui. The enzyme docs phrase it well:
So any child components are stubbed and don't factor into the test. Which seems like a sound solution to me as we use jest for unit tests. As to why it didn't work in the scheduler, I'm not sure. We should take a look at that.
The docs for mount state a couple usecases:
So yeah there might be a couple scenarios in which you'd want to use mount. We'd have to work around those. I don't think that's too bad. We always have cypress, and these scenarios don't necessarily have to overlap with components that use ui components. Plus if they do the ui components can be mocked, then you should still be able to use mount. That would be like a kind of manual shallow rendering. |
I'm wondering if a third potential solution would be to mock styled-jsx/style in such a way that it wouldn't crash where it's currently failing. That might be possible as well. I'd have to look into that. |
Thanks for looking at this @ismay. It sounds like we might run into this problem in a few other places at some point too given its a problem with I think from memory that LeftSide and RightSide were basically sharing some values via a local module - most of which were constants so I don't think i would object to solution 2. I think only one value might be duplicated but I think as a couple of developers have run in to problems testing this component having the component in a better state for testing would be beneficial. When I ran in to the problem I was working in the Schedule App and was create a custom form field that I was looking to test. Although the field was pulling in data from the server it felt like jest was a good fit for it as it seemed like a relatively small piece of code. I generally find jest tests quicker to write and I like that they tend to be quick in giving feedback - saying that I haven't really spun up the Cypress tests locally yet so I should probably look at doing that too (my bad) I think there might be some merit to what you say about a potential third solution but I don't really know how complex mocking styled-jsx/style for the tests would be - maybe we would need a spike around it. I guess another short term solution might be that if we come across this again in using the UI lib components we could mock out that component specifically. Its not something I would like to do a lot of but if we don't care about the specific implementation of that component in our test It think that would be fine - in some way it might actually give use some understanding of how often we come around this problem in future too. |
I've tried, but I'm not able to make this work. It seems like the error isn't occuring in styled-jsx but in react.createElement, which is evaluating the expression without having the necessary values in scope. So 3 doesn't seem viable. |
My pleasure 👍️. Yeah I agree, it's likely that this'll happen with other components as well.
Yeah that's right, it's the imported values that the transfer is using that are the problem. Outside of not using styled-jsx I think our most viable solution is to not mount ui components in jest tests outside of the ui lib (so solution 1). It's safe to assume that ui components are doing what they should for your jest tests. So feel free to mock them for your jest tests if they're causing issues. And if you want to write an integration test cypress is more realistic and works with our ui components. So outside of any changes in our preferences for the framework to use for integration tests i think that would be my recommended way forward. Not ideal, but it seems the most practical to me. We can of course still look into 2., but in terms of a testing strategy I'd go with 1. |
Thanks for looking into this Ismay. From what you say there it does look like 1 is the best option |
Anytime 👍️. Yeah it's not ideal and maybe there's a better workaround, but I couldn't find anything that worked. |
@ismay
I agree we shouldn't test any UI components in our apps. But there are quite a few valid scenarios where we do have mount (or shallow-mount) these components. Some basic examples that come to mind:
Mocking UI components all the time seem rather inconvenient. Not quite sure what we want to do with this PR BTW. Having this test for 1 single component doesn't seem to make sense. Having it for all components seems a bit odd too. Perhaps we can simply close it? |
Yeah no the tests were just a demonstration. In the end what we're running into here is a technical limitation of styled-jsx it seems. It seems you can't use the components that were compiled for production in jest, in certain conditions. I've not had the time to get completely to the bottom of this, because it concerns both bundling and babel, which gets very complex. I think the most practical way forward for now is to fix the import style of the transfer, as it seems that that's somehow causing this issue (still not sure how). Most of our other components are fine in jest. Also, I still think devs shouldn't be testing internals of our ui components in any way, that's our job. They'll need them to run properly in integration tests of course (and they do), but they shouldn't be asserting anything that's our responsibility, that'll just couple their tests unnecessarily to our implementation. So I'd say this is a low priority bug for that reason, if a very annoying one. |
See https://dhis2.atlassian.net/browse/LIBS-342.
I've added two tests. One that uses the untranspiled code and succeeds, and one that uses the transpiled code and fails. I've narrowed it down to an issue with styled-jsx. It seems the cause of the problem is linked to this:
https://github.com/dhis2/app-platform/blob/ede728c7a1e8ca84940b580917b80cfd2eaf5b33/cli/config/makeBabelConfig.js#L56-L70
If you look at our babel config there, you'll see that styled-jsx is not compiling styles for test environments, as recommended in their docs: https://github.com/vercel/styled-jsx#rendering-in-tests. That's the right approach to prevent any errors in jest, see this issue for example: vercel/styled-jsx#516 (there are a lot of others like it), and vercel/styled-jsx#469 (comment).
So the above babel config fixes any issues with jest when you allow jest to transpile the code with the correct babel config. However, if you aren't testing a local module, but a module imported from node_modules, you're getting a module that has been transpiled for production and so that seems to fail with jest again. So that seems to be where it's going wrong.
To be more precise. It seems that the styled-jsx transform will flag expressions it can't evaluate at build time as dynamic: vercel/styled-jsx#595 (comment). So these imports in the transfer are one such case for example. Part of the transfer transpiles down to this:
and as you can see, backgroundColor is referred to but not defined in this module (see the part under
dynamic
). I didn't look into it any further than that. So why exactly styled-jsx isn't failing in the browser and only in jest I'm not sure. The code is not necessarily invalid, i.e. this is valid:so assuming that styled-jsx uses something like a tagged template to evaluate this, it's probably that that's going wrong in jest somehow, maybe it's due to jsdom.
Anyway, it seems that this is just a downside of using styled-jsx the way we use it. Apparently baking styled-jsx into our published modules also bakes in the jest incompatibility. Let me know if I've overlooked/misinterpreted anything!