简体   繁体   English

在 React with Jest 中为 @material-ui withStyles 创建手动模拟

[英]Create manual mock for @material-ui withStyles in React with Jest

I am trying to create manual mocks for the @material-ui/core/styles module, which exports the HOC called withStyles .我正在尝试为@material-ui/core/styles模块创建手动模拟,该模块导出名为withStyles的 HOC。

Using the inline mock with jest.mock works perfectly, but when I try to move this logic into sharable __mocks__ folder, it does not work anymore.将内联模拟与jest.mock一起jest.mock效果很好,但是当我尝试将此逻辑移动到可共享的__mocks__文件夹时,它不再起作用。

I removed from the file being tested all the unecessary code, just keeping the two lines creating the issues:我从正在测试的文件中删除了所有不必要的代码,只保留造成问题的两行:

import { withStyles } from '@material-ui/core/styles';

console.log('loaded styles:', withStyles);

export default 'hello';

And the test simplified as well, just to see if the mock is working, is the following:并且测试也简化了,只是为了看看模拟是否有效,如下:

import test from '../test';
console.log(test);

What I have tried is to create a __mocks__ folder in the root of the project, where I have the node_modules folder.我尝试过的是在项目的根目录中创建一个__mocks__文件夹,在那里我有node_modules文件夹。

There I created a first folder called @material-ui and inside it another folder called core .在那里,我创建了一个名为@material-ui的第一个文件夹,并在其中创建了另一个名为core文件夹。 Inside this folder I have a file called styles.js with the following code:在此文件夹中,我有一个名为styles.js的文件, styles.js包含以下代码:

export const withStyles = 'hello world';

So the structure looks like:所以结构看起来像:

- __mocks__
  - @material-ui
    - core
      - styles.js
- node_modules

This is the code which works, with the mock defined inside the same testing file:这是有效的代码,在同一个测试文件中定义了模拟:

jest.mock('@material-ui/core/styles', () => ({
  withStyles: () => Component => props => (
    <Component
      classes=""
      {...props}
    />
  ),
}));

What is happening with the __mocks__ folder is that, if I do not call any __mocks__文件夹发生的情况是,如果我不调用任何

jest.mock('@material-ui/core/styles');

inside my test file, it uses the real withStyles , so the real module.在我的测试文件中,它使用真正的withStyles ,所以真正的模块。 No mock at all is being used.根本没有使用模拟。

If I use the:如果我使用:

jest.mock('@material-ui/core/styles');

It uses an automatic mock autogenerated by jest (or it looks so), skipping the one I define above.它使用由 jest 自动生成的自动模拟(或者看起来如此),跳过我在上面定义的那个。

Just a note about packages, I used CRA for bootstrapping the app and the jest version I currently have is the 20, with the react-scripts version 1.0.17只是关于包的说明,我使用CRA来引导应用程序,我目前拥有的jest版本是 20, react-scripts版本为 1.0.17

Thanks to you all for you the help!感谢大家的帮助!

Here is how you should use manual mocking in __mocks__/@material-ui/core/styles.js :以下是您应该如何在__mocks__/@material-ui/core/styles.js使用手动__mocks__/@material-ui/core/styles.js

// Grab the original exports
import * as Styles from '@material-ui/core/styles';

const mockWithStyles = () => {
  console.log('withStyles being mocked'); // this shows that it works
  /**
   * 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 () => {}; // your mock function (adjust as needed)
  // you can also return the same implementation on certain conditions
  // return Styles.makeStyles; 
};

module.exports = { ...Styles, withStyles: mockWithStyles };

Here is how I manual mock makeStyles :这是我手动模拟makeStyles

// 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';

const mockMakeStyles = 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
   * binding it with our custom theme
   */
  const theme = createMuiTheme(options);
  return Styles.makeStyles(func.bind(null, theme));
};

module.exports = { ...Styles, makeStyles: mockMakeStyles };

And makeStyles result uses React.useContext , so we have to avoid mocking useContext for makeStyles .makeStyles导致用途React.useContext ,所以我们要避免嘲讽useContextmakeStyles Either use mockImplementationOnce if you use React.useContext(...) first in you component, or just filter it out in your test code as:要么使用mockImplementationOnce如果使用React.useContext(...)在你第一个组件,或者只是过滤出来在你的测试代码如下:

jest.spyOn(React, 'useContext').mockImplementation(context => {
  console.log(context);
  // only stub the response if
  if (context.displayName === 'MyAppContext') {
    return {
      auth: {},
      lang: 'en',
      snackbar: () => {},
    };
  }

  const ActualReact = jest.requireActual('react');
  return ActualReact.useContext(context);
});

And on your createContext() call, probably in a store.js , add a displayName (standard), or any other custom property to Identify your context:在您的createContext()调用中,可能在store.js ,添加displayName (标准)或任何其他自定义属性来标识您的上下文:

const store = React.createContext(initialState);
store.displayName = 'MyAppContext';

The makeStyles context displayName will appear as StylesContext and ThemeContext and their implementation will remain untouched to avoid error. makeStyles上下文 displayName 将显示为StylesContextThemeContext并且它们的实现将保持不变以避免错误。

This fixed all kind of mocking problem with makeStyles .这解决了makeStyles所有嘲弄问题。 But I haven't use withStyles to know its structure deeply, but similar logic should be applicable.不过我没有用withStyles深入了解它的结构,不过类似的逻辑应该是适用的。

I created the file src/__mocks__/@material-ui/core/styles.jsx in my project and inside I put:我在我的项目中创建了文件src/__mocks__/@material-ui/core/styles.jsx并在里面放了:

import * as Styles from '@material-ui/core/styles';
import React from 'react';

const withStyles = () => Component => props => <Component classes={{}} {...props} />;

module.exports = { ...Styles, withStyles };

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM