Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs 如何使用react redux钩子测试组件?_Reactjs_Testing_Redux_React Redux_Enzyme - Fatal编程技术网

Reactjs 如何使用react redux钩子测试组件?

Reactjs 如何使用react redux钩子测试组件?,reactjs,testing,redux,react-redux,enzyme,Reactjs,Testing,Redux,React Redux,Enzyme,我有一个简单的Todo组件,它利用react-redux钩子,我正在使用Ezyme测试它,但是我得到一个错误或者一个带有浅渲染的空对象,如下所述 使用react redux的钩子测试组件的正确方法是什么 Todos.js export const getIsSpinnerDisplayed = state => state.isSpinnerDisplayed; const Todos=()=>{ const{todos}=useSelector(state=>state); 返回(

我有一个简单的Todo组件,它利用react-redux钩子,我正在使用Ezyme测试它,但是我得到一个错误或者一个带有浅渲染的空对象,如下所述

使用react redux的钩子测试组件的正确方法是什么

Todos.js

export const getIsSpinnerDisplayed = state => state.isSpinnerDisplayed;
const Todos=()=>{
const{todos}=useSelector(state=>state);
返回(
    {todo.map(todo=>(
  • {todo.title}
  • ))}
); };
Todos.test.jsv1

。。。
它('渲染而不崩溃',()=>{
常量包装器=浅();
expect(wrapper.toMatchSnapshot();
});
它('应呈现ul',()=>{
常量包装器=浅();
expect(wrapper.find('ul').length).toBe(1);
});
v1错误:

...
Invariant Violation: could not find react-redux context value; 
please ensure the component is wrapped in a <Provider>
...
。。。
不变冲突:找不到react redux上下文值;
请确保组件包装在
...
Todos.test.jsv2

。。。
//从react redux导入的提供程序
它('渲染而不崩溃',()=>{
常数包装=浅(
,
);
expect(wrapper.toMatchSnapshot();
});
它('应呈现ul',()=>{
常量包装器=浅();
expect(wrapper.find('ul').length).toBe(1);
});
v2测试也会失败,因为
wrapper
,在
wrapper
上调用
dive()
将返回与v1相同的错误


提前感谢您的帮助

我可以使用酶安装工具测试使用redux钩子的组件,并向提供商提供模拟存储:

组件

import React from 'react';
import AppRouter from './Router'
import { useDispatch, useSelector } from 'react-redux'
import StartupActions from './Redux/Startup'
import Startup from './Components/Startup'
import './App.css';

// This is the main component, it includes the router which manages
// routing to different views.
// This is also the right place to declare components which should be
// displayed everywhere, i.e. sockets, services,...
function App () {
  const dispatch = useDispatch()
  const startupComplete = useSelector(state => state.startup.complete)

  if (!startupComplete) {
    setTimeout(() => dispatch(StartupActions.startup()), 1000)
  }

  return (
    <div className="app">
      {startupComplete ? <AppRouter /> : <Startup />}
    </div>
  );
}

export default App;
import React from 'react';
import {Provider} from 'react-redux'
import { mount, shallow } from 'enzyme'
import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk';
import App from '../App';

const mockStore = configureMockStore([thunk]);

describe('App', () => {
  it('should render a startup component if startup is not complete', () => {
    const store = mockStore({
      startup: { complete: false }
    });
    const wrapper = mount(
      <Provider store={store}>
        <App />
      </Provider>
    )
    expect(wrapper.find('Startup').length).toEqual(1)
  })
})
import * as React from 'react';
import { useSelector } from 'react-redux';
import Spinner from './Spinner';
import Button from './Button ';
import { getIsSpinnerDisplayed } from './selectors';

const Example = () => {
  const isSpinnerDisplayed = useSelector(getIsSpinnerDisplayed);

  return isSpinnerDisplayed ? <Spinner /> : <Button />;
};

export default Example;
import * as React from 'react';
import { shallow } from 'enzyme';
import Example from './Example';
import Button from './Button ';
import { getIsSpinnerDisplayed } from './selectors';

jest.mock('react-redux', () => ({
  useSelector: jest.fn(fn => fn()),
}));
jest.mock('./selectors');

describe('Example', () => {
  it('should render Button if getIsSpinnerDisplayed returns false', () => {
    getIsSpinnerDisplayed.mockReturnValue(false);

    const wrapper = shallow(<Example />);

    expect(wrapper.find(Button).exists()).toBe(true);
  });
});
从“React”导入React;
从“./路由器”导入AppRouter
从“react redux”导入{useDispatch,useSelector}
从“./Redux/Startup”导入StartupActions
从“./Components/Startup”导入启动
导入“/App.css”;
//这是主要组件,它包括管理的路由器
//路由到不同的视图。
//这也是声明组件的正确位置,应该
//到处显示,即插座、服务等,。。。
函数应用程序(){
const dispatch=usedpatch()
const startupComplete=useSelector(state=>state.startup.complete)
如果(!startupComplete){
setTimeout(()=>dispatch(StartupActions.startup()),1000)
}
返回(
{startupComplete?:}
);
}
导出默认应用程序;
测试

import React from 'react';
import AppRouter from './Router'
import { useDispatch, useSelector } from 'react-redux'
import StartupActions from './Redux/Startup'
import Startup from './Components/Startup'
import './App.css';

// This is the main component, it includes the router which manages
// routing to different views.
// This is also the right place to declare components which should be
// displayed everywhere, i.e. sockets, services,...
function App () {
  const dispatch = useDispatch()
  const startupComplete = useSelector(state => state.startup.complete)

  if (!startupComplete) {
    setTimeout(() => dispatch(StartupActions.startup()), 1000)
  }

  return (
    <div className="app">
      {startupComplete ? <AppRouter /> : <Startup />}
    </div>
  );
}

export default App;
import React from 'react';
import {Provider} from 'react-redux'
import { mount, shallow } from 'enzyme'
import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk';
import App from '../App';

const mockStore = configureMockStore([thunk]);

describe('App', () => {
  it('should render a startup component if startup is not complete', () => {
    const store = mockStore({
      startup: { complete: false }
    });
    const wrapper = mount(
      <Provider store={store}>
        <App />
      </Provider>
    )
    expect(wrapper.find('Startup').length).toEqual(1)
  })
})
import * as React from 'react';
import { useSelector } from 'react-redux';
import Spinner from './Spinner';
import Button from './Button ';
import { getIsSpinnerDisplayed } from './selectors';

const Example = () => {
  const isSpinnerDisplayed = useSelector(getIsSpinnerDisplayed);

  return isSpinnerDisplayed ? <Spinner /> : <Button />;
};

export default Example;
import * as React from 'react';
import { shallow } from 'enzyme';
import Example from './Example';
import Button from './Button ';
import { getIsSpinnerDisplayed } from './selectors';

jest.mock('react-redux', () => ({
  useSelector: jest.fn(fn => fn()),
}));
jest.mock('./selectors');

describe('Example', () => {
  it('should render Button if getIsSpinnerDisplayed returns false', () => {
    getIsSpinnerDisplayed.mockReturnValue(false);

    const wrapper = shallow(<Example />);

    expect(wrapper.find(Button).exists()).toBe(true);
  });
});
从“React”导入React;
从“react redux”导入{Provider}
从“酶”导入{mount,shallow}
从“redux模拟存储”导入configureMockStore
从“redux thunk”导入thunk;
从“../App”导入应用程序;
const mockStore=configureMockStore([thunk]);
描述('App',()=>{
它('如果启动未完成,则应呈现启动组件',()=>{
常量存储=模拟存储({
启动:{完成:错误}
});
常量包装器=装入(
)
expect(wrapper.find('Startup').length).toEqual(1)
})
})

如果您使用在另一个文件中定义的函数选择器,那么除了@abidibo之外还有另一种方法。您可以模拟
useSelector
和选择器函数,然后从以下位置使用
shallow

组件

import React from 'react';
import AppRouter from './Router'
import { useDispatch, useSelector } from 'react-redux'
import StartupActions from './Redux/Startup'
import Startup from './Components/Startup'
import './App.css';

// This is the main component, it includes the router which manages
// routing to different views.
// This is also the right place to declare components which should be
// displayed everywhere, i.e. sockets, services,...
function App () {
  const dispatch = useDispatch()
  const startupComplete = useSelector(state => state.startup.complete)

  if (!startupComplete) {
    setTimeout(() => dispatch(StartupActions.startup()), 1000)
  }

  return (
    <div className="app">
      {startupComplete ? <AppRouter /> : <Startup />}
    </div>
  );
}

export default App;
import React from 'react';
import {Provider} from 'react-redux'
import { mount, shallow } from 'enzyme'
import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk';
import App from '../App';

const mockStore = configureMockStore([thunk]);

describe('App', () => {
  it('should render a startup component if startup is not complete', () => {
    const store = mockStore({
      startup: { complete: false }
    });
    const wrapper = mount(
      <Provider store={store}>
        <App />
      </Provider>
    )
    expect(wrapper.find('Startup').length).toEqual(1)
  })
})
import * as React from 'react';
import { useSelector } from 'react-redux';
import Spinner from './Spinner';
import Button from './Button ';
import { getIsSpinnerDisplayed } from './selectors';

const Example = () => {
  const isSpinnerDisplayed = useSelector(getIsSpinnerDisplayed);

  return isSpinnerDisplayed ? <Spinner /> : <Button />;
};

export default Example;
import * as React from 'react';
import { shallow } from 'enzyme';
import Example from './Example';
import Button from './Button ';
import { getIsSpinnerDisplayed } from './selectors';

jest.mock('react-redux', () => ({
  useSelector: jest.fn(fn => fn()),
}));
jest.mock('./selectors');

describe('Example', () => {
  it('should render Button if getIsSpinnerDisplayed returns false', () => {
    getIsSpinnerDisplayed.mockReturnValue(false);

    const wrapper = shallow(<Example />);

    expect(wrapper.find(Button).exists()).toBe(true);
  });
});
测试

import React from 'react';
import AppRouter from './Router'
import { useDispatch, useSelector } from 'react-redux'
import StartupActions from './Redux/Startup'
import Startup from './Components/Startup'
import './App.css';

// This is the main component, it includes the router which manages
// routing to different views.
// This is also the right place to declare components which should be
// displayed everywhere, i.e. sockets, services,...
function App () {
  const dispatch = useDispatch()
  const startupComplete = useSelector(state => state.startup.complete)

  if (!startupComplete) {
    setTimeout(() => dispatch(StartupActions.startup()), 1000)
  }

  return (
    <div className="app">
      {startupComplete ? <AppRouter /> : <Startup />}
    </div>
  );
}

export default App;
import React from 'react';
import {Provider} from 'react-redux'
import { mount, shallow } from 'enzyme'
import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk';
import App from '../App';

const mockStore = configureMockStore([thunk]);

describe('App', () => {
  it('should render a startup component if startup is not complete', () => {
    const store = mockStore({
      startup: { complete: false }
    });
    const wrapper = mount(
      <Provider store={store}>
        <App />
      </Provider>
    )
    expect(wrapper.find('Startup').length).toEqual(1)
  })
})
import * as React from 'react';
import { useSelector } from 'react-redux';
import Spinner from './Spinner';
import Button from './Button ';
import { getIsSpinnerDisplayed } from './selectors';

const Example = () => {
  const isSpinnerDisplayed = useSelector(getIsSpinnerDisplayed);

  return isSpinnerDisplayed ? <Spinner /> : <Button />;
};

export default Example;
import * as React from 'react';
import { shallow } from 'enzyme';
import Example from './Example';
import Button from './Button ';
import { getIsSpinnerDisplayed } from './selectors';

jest.mock('react-redux', () => ({
  useSelector: jest.fn(fn => fn()),
}));
jest.mock('./selectors');

describe('Example', () => {
  it('should render Button if getIsSpinnerDisplayed returns false', () => {
    getIsSpinnerDisplayed.mockReturnValue(false);

    const wrapper = shallow(<Example />);

    expect(wrapper.find(Button).exists()).toBe(true);
  });
});
import*as React from'React';
从“酶”导入{shall};
从“./Example”导入示例;
从“./按钮”导入按钮;
从“/选择器”导入{getIsSpinnerDisplayed};
mock('react-redux',()=>({
useSelector:jest.fn(fn=>fn()),
}));
开玩笑的模仿(“/选择器”);
描述('示例',()=>{
它('如果getIsSpinnerDisplayed返回false,则应呈现按钮',()=>{
getIsSpinnerDisplayed.mockReturnValue(false);
常量包装器=浅();
expect(wrapper.find(Button.exists()).toBe(true);
});
});

它可能有点粗糙,但对我来说效果很好:)

这对我来说也很好:

import { shallow, mount } from "enzyme";
const store = mockStore({
  startup: { complete: false }
});

describe("==== Testing App ======", () => {
  const setUpFn = props => {
    return mount(
      <Provider store={store}>
        <App />
      </Provider>
    );
  };

  let wrapper;
  beforeEach(() => {
    wrapper = setUpFn();
  });
从“酶”导入{shall,mount};
常量存储=模拟存储({
启动:{完成:错误}
});
描述(“===测试应用程序===”,()=>{
常量设置fn=props=>{
回座(
);
};
让包装纸;
在每个之前(()=>{
包装器=setUpFn();
});

模拟使用选择器可以做到这一点

import * as redux from 'react-redux'

const spy = jest.spyOn(redux, 'useSelector')
spy.mockReturnValue({ username:'test' })

在寻找帮助后,我结合了我找到的一些方法来模拟useSelector

首先创建一个函数,在测试之前进行一些引导。 使用一些要覆盖的值设置存储,并模拟react redux的useSelector函数

我认为它对于创建多个测试用例非常有用,在这些测试用例中,您可以看到存储状态如何影响组件的行为

import configureMockStore from 'redux-mock-store';
import * as Redux from 'react-redux';
import MyComponent from './MyComponent';

const mockSelectors = (storeValues) => {
  const mockStore = configureMockStore()({
    mobile: {
      isUserConnected: false
      ...storeValues
    },
  });

  jest
    .spyOn(Redux, 'useSelector')
    .mockImplementation(state => state.dependencies[0](mockStore.getState()));
};

describe('isUserConnected: true', () => {
    beforeEach(() => {
      mockSelectors({ isUserConnected: true });
      component = shallow(<MyComponent />);

      test('should render a disconnect button', () => {
         expect(component).toBeDefined();
         expect(component.find('button')).toBeTruthy();
      });
    });
  });
从“redux mock store”导入configureMockStore;
从“react Redux”导入*作为Redux;
从“/MyComponent”导入MyComponent;
常量mockSelectors=(storeValues)=>{
const mockStore=configureMockStore()({
流动电话:{
isUserConnected:false
…存储值
},
});
开玩笑
.spyOn(Redux,“使用选择器”)
.mockImplementation(state=>state.dependencies[0](mockStore.getState());
};
描述('isUserConnected:true',()=>{
在每个之前(()=>{
mockselector({isUserConnected:true});
组件=浅();
测试('应呈现断开连接按钮',()=>{
expect(component.toBeDefined();
expect(component.find('button')).toBeTruthy();
});
});
});
和组件:

import React from 'react';
import { shallowEqual, useSelector } from 'react-redux';

const MyComponent = () => {    
  const isConnected = useSelector(selectIsConnected, shallowEqual);

  return (
    <>
      {
        showDisconnect ? (
          <button type="button" onClick={() => ()}>disconnect</button>
        ) : null
      }
    </>
  );
};

export default MyComponent;
从“React”导入React;
从'react redux'导入{shallowEqual,useSelector};
常量MyComponent=()=>{
const isConnected=使用选择器(选择isConnected,shallewequal);
返回(
{
显示断开连接(
()}>断开连接
):null
}
);
};
导出默认MyComponent;

下面的代码适合我

import { configure, shallow} from 'enzyme'; 
import Adapter from 'enzyme-adapter-react-16'; 
import ServiceListingScreen  from './ServiceListingScreen'; 
import renderer from 'react-test-renderer';
import { createStore } from 'redux';
import serviceReducer from './../store/reducers/services'; 
import { Provider } from 'react-redux'
 
const store = createStore(serviceReducer  ) ; 
configure({adapter: new Adapter()}); 


const ReduxProvider = ({ children, reduxStore }) => (
  <Provider store={reduxStore}>{children}</Provider>
)

describe('Screen/ServiceListingScreen', () => {
  it('renders correctly ', () => {
    const wrapper = shallow(<Provider store={store}><ServiceListingScreen  /></Provider>);
    const tree = renderer.create(wrapper).toJSON();
    expect(tree).toMatchSnapshot();
  });
   
});

从“酶”导入{configure,shallow};
从'enzyme-Adapter-react-16'导入适配器;
导入服务列表