Javascript 数组在使用酶渲染的组件中未定义?
我有一个简单的组件,它使用useSelector和useDispatch钩子从我的redux存储中分派和获取当前状态,并映射它们以返回一个子组件 我不熟悉使用钩子进行测试,在阅读了一些文章之后,我用jest mock模拟了两个redux钩子,以查看它们在装载时是否被调用,但是,在运行测试时,我的状态数组返回为未定义,因此测试失败。有人知道为什么会这样吗 COMPONENT.tsxJavascript 数组在使用酶渲染的组件中未定义?,javascript,reactjs,jestjs,react-hooks,enzyme,Javascript,Reactjs,Jestjs,React Hooks,Enzyme,我有一个简单的组件,它使用useSelector和useDispatch钩子从我的redux存储中分派和获取当前状态,并映射它们以返回一个子组件 我不熟悉使用钩子进行测试,在阅读了一些文章之后,我用jest mock模拟了两个redux钩子,以查看它们在装载时是否被调用,但是,在运行测试时,我的状态数组返回为未定义,因此测试失败。有人知道为什么会这样吗 COMPONENT.tsx import React, { useEffect, useState } from 'react'; import
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getData } from '../actions/index';
import { AppState } from '../store/store';
import GridItem from '../component/GridItem';
function GridContainer () {
const dispatch = useDispatch();
const books = useSelector((state: AppState) => state);
useEffect(() => {
dispatch(getData());
}, [dispatch]);
const bookList = (list: AppState) => {
return list.map((book) => (
<GridItem key={book.id} data={ book } />
))
};
return (
<div className="book-container">
{ bookList(books) }
</div>
)
}
export default GridContainer;
import React,{useffect,useState}来自“React”;
从'react redux'导入{useDispatch,useSelector};
从“../actions/index”导入{getData};
从“../store/store”导入{AppState};
从“../component/GridItem”导入GridItem;
函数GridContainer(){
const dispatch=usedpatch();
const books=useSelector((状态:AppState)=>state);
useffect(()=>{
调度(getData());
},[发送];
常量bookList=(列表:AppState)=>{
返回列表。地图((书本)=>(
))
};
返回(
{图书目录(图书)}
)
}
导出默认网格容器;
COMPONENT.test.tsx
import React from 'react';
import { shallow, mount } from 'enzyme';
import GridContainer from './GridContainer';
const mockDispatch = jest.fn();
jest.mock("react-redux", () => ({
useSelector: jest.fn(fn => fn()),
useDispatch: () => mockDispatch
}));
it('renders container', () => {
const wrapper = shallow(<GridContainer />);
const component = wrapper.find('.book-container');
expect(component.length).toBe(1);
});
describe('react hooks', () => {
afterEach(() => {
jest.clearAllMocks();
});
it('runs dispatch on mount', () => {
const wrapper = mount(<GridContainer />);
expect(mockDispatch).toHaveBeenCalledTimes(1);
});
});
从“React”导入React;
从“酶”导入{shall,mount};
从“./GridContainer”导入GridContainer;
const mockDispatch=jest.fn();
mock(“react redux”,()=>({
useSelector:jest.fn(fn=>fn()),
useDispatch:()=>mockDispatch
}));
它('呈现容器',()=>{
常量包装器=浅();
const component=wrapper.find('.book container');
expect(组件长度).toBe(1);
});
描述('react hooks',()=>{
之后(()=>{
开玩笑。clearAllMocks();
});
它('在装载时运行分派',()=>{
const wrapper=mount();
预计(模拟调度)。已催收时间(1);
});
});
错误消息
TypeError: Cannot read property 'map' of undefined
25 | //function to print list of books component
26 | const bookList = (list: AppState) => {
> 27 | return list.map((book) => (
| ^
28 | <GridItem key={book.id} data={ book } />
29 | ))
30 | };
TypeError:无法读取未定义的属性“map”
25 |//打印图书列表组件的函数
26 | const bookList=(列表:AppState)=>{
>27 |返回列表。地图((书)=>(
| ^
28 |
29 | ))
30 | };
问题在于模仿useSelector
。函数本身将AppState
传递给回调,但模拟函数不知道AppState
。这样,您的模拟将返回未定义。这样书籍
(列表)将未定义
您需要指定模拟将返回的内容,在本例中是一个数组。您可以调用mockReturnValue
传递booksMock(数组)来实现:
jest.mock("react-redux", () => ({
useSelector: jest.fn().mockReturnValue(booksMock),
useDispatch: () => mockDispatch
}));
问题在于模拟
useSelector
。函数本身将AppState
传递给回调,但模拟函数不知道AppState
。这样,您的模拟将返回未定义。这样书籍
(列表)将未定义
您需要指定模拟将返回的内容,在本例中是一个数组。您可以调用mockReturnValue
传递booksMock(数组)来实现:
jest.mock("react-redux", () => ({
useSelector: jest.fn().mockReturnValue(booksMock),
useDispatch: () => mockDispatch
}));
您应该模拟
useSelector
hook的返回值
例如
GridContainer.tsx
:
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getData } from './actions/index';
import { AppState } from './store/store';
import GridItem from './component/GridItem';
function GridContainer() {
const dispatch = useDispatch();
const books = useSelector((state: AppState) => state);
console.log('books:', books);
useEffect(() => {
dispatch(getData());
}, [dispatch]);
const bookList = (list: AppState) => {
return list.map((book) => <GridItem key={book.id} data={book} />);
};
return <div className="book-container">{bookList(books)}</div>;
}
export default GridContainer;
import React from 'react';
export default function GridItem({ data }) {
return <div>{data.name}</div>;
}
import React from 'react';
import { shallow, mount } from 'enzyme';
import GridContainer from './GridContainer';
import { useDispatch, useSelector } from 'react-redux';
const mockDispatch = jest.fn();
const booksMock = [
{ id: 1, name: 'golang' },
{ id: 2, name: 'TypeScript' },
];
jest.mock('react-redux', () => {
return {
useSelector: jest.fn(() => booksMock),
useDispatch: jest.fn(() => mockDispatch),
};
});
describe('react hooks', () => {
afterEach(() => {
jest.clearAllMocks();
});
it('renders container', () => {
const wrapper = shallow(<GridContainer />);
const component = wrapper.find('.book-container');
expect(component.length).toBe(1);
});
it('runs dispatch on mount', () => {
const wrapper = mount(<GridContainer />);
expect(useDispatch).toBeCalledTimes(1);
expect(useSelector).toBeCalledWith(expect.any(Function));
expect(mockDispatch).toBeCalledWith({ type: 'GET_DATA' });
expect(wrapper.find('.book-container').children()).toHaveLength(2);
});
});
/store/store.ts
:
export type AppState = any[];
export function getData() {
return { type: 'GET_DATA' };
}
/actions/index.ts
:
export type AppState = any[];
export function getData() {
return { type: 'GET_DATA' };
}
GridContainer.test.tsx
:
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getData } from './actions/index';
import { AppState } from './store/store';
import GridItem from './component/GridItem';
function GridContainer() {
const dispatch = useDispatch();
const books = useSelector((state: AppState) => state);
console.log('books:', books);
useEffect(() => {
dispatch(getData());
}, [dispatch]);
const bookList = (list: AppState) => {
return list.map((book) => <GridItem key={book.id} data={book} />);
};
return <div className="book-container">{bookList(books)}</div>;
}
export default GridContainer;
import React from 'react';
export default function GridItem({ data }) {
return <div>{data.name}</div>;
}
import React from 'react';
import { shallow, mount } from 'enzyme';
import GridContainer from './GridContainer';
import { useDispatch, useSelector } from 'react-redux';
const mockDispatch = jest.fn();
const booksMock = [
{ id: 1, name: 'golang' },
{ id: 2, name: 'TypeScript' },
];
jest.mock('react-redux', () => {
return {
useSelector: jest.fn(() => booksMock),
useDispatch: jest.fn(() => mockDispatch),
};
});
describe('react hooks', () => {
afterEach(() => {
jest.clearAllMocks();
});
it('renders container', () => {
const wrapper = shallow(<GridContainer />);
const component = wrapper.find('.book-container');
expect(component.length).toBe(1);
});
it('runs dispatch on mount', () => {
const wrapper = mount(<GridContainer />);
expect(useDispatch).toBeCalledTimes(1);
expect(useSelector).toBeCalledWith(expect.any(Function));
expect(mockDispatch).toBeCalledWith({ type: 'GET_DATA' });
expect(wrapper.find('.book-container').children()).toHaveLength(2);
});
});
源代码:您应该模拟
useSelector
hook的返回值
例如
GridContainer.tsx
:
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getData } from './actions/index';
import { AppState } from './store/store';
import GridItem from './component/GridItem';
function GridContainer() {
const dispatch = useDispatch();
const books = useSelector((state: AppState) => state);
console.log('books:', books);
useEffect(() => {
dispatch(getData());
}, [dispatch]);
const bookList = (list: AppState) => {
return list.map((book) => <GridItem key={book.id} data={book} />);
};
return <div className="book-container">{bookList(books)}</div>;
}
export default GridContainer;
import React from 'react';
export default function GridItem({ data }) {
return <div>{data.name}</div>;
}
import React from 'react';
import { shallow, mount } from 'enzyme';
import GridContainer from './GridContainer';
import { useDispatch, useSelector } from 'react-redux';
const mockDispatch = jest.fn();
const booksMock = [
{ id: 1, name: 'golang' },
{ id: 2, name: 'TypeScript' },
];
jest.mock('react-redux', () => {
return {
useSelector: jest.fn(() => booksMock),
useDispatch: jest.fn(() => mockDispatch),
};
});
describe('react hooks', () => {
afterEach(() => {
jest.clearAllMocks();
});
it('renders container', () => {
const wrapper = shallow(<GridContainer />);
const component = wrapper.find('.book-container');
expect(component.length).toBe(1);
});
it('runs dispatch on mount', () => {
const wrapper = mount(<GridContainer />);
expect(useDispatch).toBeCalledTimes(1);
expect(useSelector).toBeCalledWith(expect.any(Function));
expect(mockDispatch).toBeCalledWith({ type: 'GET_DATA' });
expect(wrapper.find('.book-container').children()).toHaveLength(2);
});
});
/store/store.ts
:
export type AppState = any[];
export function getData() {
return { type: 'GET_DATA' };
}
/actions/index.ts
:
export type AppState = any[];
export function getData() {
return { type: 'GET_DATA' };
}
GridContainer.test.tsx
:
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getData } from './actions/index';
import { AppState } from './store/store';
import GridItem from './component/GridItem';
function GridContainer() {
const dispatch = useDispatch();
const books = useSelector((state: AppState) => state);
console.log('books:', books);
useEffect(() => {
dispatch(getData());
}, [dispatch]);
const bookList = (list: AppState) => {
return list.map((book) => <GridItem key={book.id} data={book} />);
};
return <div className="book-container">{bookList(books)}</div>;
}
export default GridContainer;
import React from 'react';
export default function GridItem({ data }) {
return <div>{data.name}</div>;
}
import React from 'react';
import { shallow, mount } from 'enzyme';
import GridContainer from './GridContainer';
import { useDispatch, useSelector } from 'react-redux';
const mockDispatch = jest.fn();
const booksMock = [
{ id: 1, name: 'golang' },
{ id: 2, name: 'TypeScript' },
];
jest.mock('react-redux', () => {
return {
useSelector: jest.fn(() => booksMock),
useDispatch: jest.fn(() => mockDispatch),
};
});
describe('react hooks', () => {
afterEach(() => {
jest.clearAllMocks();
});
it('renders container', () => {
const wrapper = shallow(<GridContainer />);
const component = wrapper.find('.book-container');
expect(component.length).toBe(1);
});
it('runs dispatch on mount', () => {
const wrapper = mount(<GridContainer />);
expect(useDispatch).toBeCalledTimes(1);
expect(useSelector).toBeCalledWith(expect.any(Function));
expect(mockDispatch).toBeCalledWith({ type: 'GET_DATA' });
expect(wrapper.find('.book-container').children()).toHaveLength(2);
});
});
源代码:Hi,感谢您回来,我尝试了您的解决方案,但是错误是一样的,再看一看,似乎由于某种原因Ezyme没有检测到我的redux状态Hi,感谢您回来,我尝试了您的解决方案,但是错误是一样的,在看了多一点之后,似乎是因为某种原因,酶没有恢复我的redux状态