-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
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
Shallow testing (enzyme) component with custom theme and mui-styles' makeStyles hook #15404
Comments
Could you share your testing setup and the error you get? |
const useStyles = makeStyles((theme: any) => ({
button: {
// we've added this to the theme
color: theme.palette.red[500]
}
}));
const CustomComponent = ({ title }: { title: string}) => {
const classes = useStyles();
return (
<Typography className={classes.button} >
{title}
</Typography>
)
}
const title = 'some title';
const themeWrapper = shallow(
<ThemeProvider theme={theme}>
<CustomComponent title={title} />
</ThemeProvider>
);
// I have tried all of the following
const wrapper = themeWrapper;
const wrapper = themeWrapper.dive();
const wrapper = themeWrapper.childAt(0).dive();
const wrapper = themeWrapper.find(CustomComponent).dive();
test('displays typography with text', () => {
expect(wrapper.find('Typography').text()).toEqual(title);
}); This test fails each time with the error: First off am I doing this test correctly. Is there something I'm missing? If not, what is the correct solution to shallow render this example? I'm getting this to pass with mount, but mounting is really driving up our build times. |
@BenBrewerBowman I believe we already have a discussion for this problem: #11864. I would encourage you to use the mount API and to forget about the existence of the shallow one, or even to consider using react-testing-library.
I understand the concern. Did you benchmark it? We are migration the whole Material-UI test suite away from the shallow API. I personally think that the code refactoring flexibility the mount API provides worth a slower test suite. We haven't benchmarked any significant difference yet. The tests on the master branch take 32s, the tests on the next branch, where we started the mount migration take 42s (but we added many new tests). |
@BenBrewerBowman I was running into the same issues and I've found a way around using jest mocks. Here are the steps for my workaround:
// Grab the original exports
import * as Styles from "@material-ui/styles";
const makeStyles = () => {
return () => {
/**
* Note: if you want to mock this return value to be
* different within a test suite then use
* the pattern defined here:
* https://jestjs.io/docs/en/manual-mocks
**/
return {};
};
};
module.exports = { ...Styles, makeStyles }; You should now be able to use shallow rendering on all your tests. Just a couple of notes:
edit: updated mock to be much simpler (inspired by: #14357 (comment)) |
@mdvorscak Thanks for sharing, it looks similar to: #14357 (comment). |
@oliviertassinari You're welcome. |
Thanks @oliviertassinari. Maybe this method of mocking makeStyles could be documented somewhere? Note: I also cleaned up my mock code to be as minimal as possible |
@mdvorscak Well, we don't encourage shallow testings, it's not something we want people to rely on. It can be frustrating.
Your clean up mock wouldn't cut it for the snapshot use case. |
I have been using @mdvorscak implementation and placing the mock inside I solved that by moving the mock inside |
@mdvorscak thanks for putting me in the right path, now I think I've found the Perfect Solution for
So I managed to solved all of these problems at the end. Here is how I manual mock I mocked in the core path instead, but both should work: // Grab the original exports
// eslint-disable-next-line import/no-extraneous-dependencies
import * as Styles from '@material-ui/core/styles';
import createMuiTheme from '@material-ui/core/styles/createMuiTheme';
import options from '../../../src/themes/options'; // I put the theme options separately to be reusable
const makeStyles = func => {
/**
* Note: if you want to mock this return value to be
* different within a test suite then use
* the pattern defined here:
* https://jestjs.io/docs/en/manual-mocks
*/
/**
* Work around because Shallow rendering does not
* Hook context and some other hook features.
* `makeStyles` accept a function as argument (func)
* and that function accept a theme as argument
* so we can take that same function, passing it as
* parameter to the original makeStyles and
* bind it to our custom theme, created on the go
* so that createMuiTheme can be ready
*/
const theme = createMuiTheme(options);
return Styles.makeStyles(func.bind(null, theme));
};
module.exports = { ...Styles, makeStyles }; And makeStyles result uses jest.spyOn(React, 'useContext').mockImplementation(context => {
// only stub the response if it is one of your Context
if (context.displayName === 'MyAppContext') {
return {
auth: {},
lang: 'en',
snackbar: () => {},
};
}
// continue to use original useContext for the rest use cases
const ActualReact = jest.requireActual('react');
return ActualReact.useContext(context);
}); And on your const store = React.createContext(initialState);
store.displayName = 'MyAppContext'; The This fixed all kind of mocking problems related to |
And a version to mock it directly in test files instead of manual mock: jest.mock('@material-ui/core/styles', () => {
const Styles = jest.requireActual('@material-ui/core/styles');
const createMuiTheme = jest.requireActual(
'@material-ui/core/styles/createMuiTheme'
).default;
const options = jest.requireActual('../../../src/themes/options').default;
return {
...Styles,
makeStyles: func => {
const theme = createMuiTheme(options);
return Styles.makeStyles(func.bind(null, theme));
},
};
}); |
@oliviertassinari do you think that advance mockup might fit the snapshot use cases? I haven't try snapshot. |
@KeitelDOG I would stay on this #15404 (comment), replace enzyme with react-testing-library as soon as you can. |
@oliviertassinari I agree the react-testing-library is probably better to be used to avoid complications. And also I don't think others are asking to integrate the work around codes on material-ui. I do use mount for full rendering on some tests, but for most of them, we don't need to dive very deeply to render the same bottom level of components multiple times, especially when we're covering branch conditions. Using shallow to stay in a component is better when aiming at coverage. I personally will try react-testing-library in some times from now, I'll have to set it up to see if it fits better my need, if it's relatively fast compared to Shallow. But I already see that the package is adding some level of complexity in terms of setup and syntaxes. But I hope it does worth it to let Shallow go for it. |
So this how I got custom Themes to work with Material UI. I used an augmented version @mdvorscak . We have a custom Theme sheet that I don't want have to override in every instance of the snapshot tests:
Note: |
Can you add a way (or add documentation) to shallow test a component with a custom theme and using styling hooks?
Using unwrap worked with
withStyles
to shallow mount a component, but now with hook styling there is no longer a HOC styling wrapper. Dive is also not working as expected.ex.
I'm use shallow rendering (enzyme), and I wrap this component in the themeprovider from mui-styles. Diving into the themeprovider I get an error. Can you either add documentation surrounding this or add a clear way to test styling hooks?
The text was updated successfully, but these errors were encountered: