Cod*_*gle 7 unit-testing reactjs jestjs redux react-testing-library
我正在尝试了解 React 和 Redux 测试的过程,我正在使用测试库来使用dom 节点查询来测试我的项目,但我仍然对在 React 项目中测试 Redux 实现的方式感到困惑:
我创建了一个自定义渲染函数,而不是反应测试库中的普通渲染方法
import React from 'react'
import { render as rtlRender } from '@testing-library/react'
import { Provider } from 'react-redux'
import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk'
const middlewares = [thunk]
const mockStore = configureMockStore(middlewares);
//test-utils.js
//creating a custom render function so we can wrap our App with
//react-redux provider
const render = (ui, initialState) => {
const store = mockStore(initialState);
//App wrapper and mocked store passed to it
const Wrapper = ({ children }) => {
return <Provider store={store}>{children}</Provider>
}
return rtlRender(ui, { wrapper: Wrapper })
}
// re-export everything
export * from '@testing-library/react'
// override render method
export { render }
Run Code Online (Sandbox Code Playgroud)
在App.test.js中,我手动操作 initialState 。这是令人困惑的一部分,我不知道我是否在这里做:
describe('App', () => {
const { getByText, getByTestId, findByText, queryByText } = screen;
let initialState = {
data: {
books: [],
error: '',
loading: false
},
//rest of the state
}
it('should render App correctly with given redux state', () => {
const { container } = render(<App />, initialState);
expect(container.firstChild).toMatchSnapshot();
expect(getByTestId(/header/)).toHaveTextContent('React Testing')
});
it('displays loading message before data get fetched', () => {
initialState = {
...initialState,
data: {
...initialState.data,
loading: true
}
}
render(<App />, initialState);
expect(getByText(/...loading books/)).toBeInTheDocument();
});
it('display an error message if any thing wrong happened while fetching data', () => {
initialState = {
...initialState,
data: {
...initialState.data,
error: 'something went wrong'
}
}
render(<App />, initialState);
expect(getByText(/something went wrong/)).toBeInTheDocument();
})
})
Run Code Online (Sandbox Code Playgroud)
例如,这是我在应用程序组件中调用的操作创建者
export const fetchData = () => dispatch => {
dispatch({ type: SET_LOADING }); // this set loading to true
return axios.get("https://api.jsonbin.io/b/57d5760ea")
.then(res => {
dispatch({
type: FETCH_DATA, // this set data
payload: res.data.books
});
dispatch({ type: STOP_LOADING })
})
.catch(err => {
dispatch({
type: SET_ERROR, // this set errors
payload: 'Something went wrong'
})
})
}
Run Code Online (Sandbox Code Playgroud)
这是App.js 组件:
function App({ fetchData, data: { loading, error, books } }) {
useEffect(() => {
fetchData()
}, []);
return (
<div className="App">
<header data-testid="header">
<h2>React Testing</h2>
<Bag />
</header>
{
error ? error :
!loading ? <Bookstore books={books} /> : <span data-testid='loading-message'>...loading books</span>
}
</div>
);
}
const mapStateToProps = state => ({
data: state.data,
});
Run Code Online (Sandbox Code Playgroud)
我不确定像这样使用initialState是否是正确的方法,因为我没有找到任何其他方法来在我的测试用例中实现,并且当我尝试测试加载消息是否会消失后,我遇到了问题使用获取的数据waitForElementToBeRemoved,因为我总是收到超时错误,表明loading永远不会像实际应用程序中那样出现错误!
像这样使用initialState是对还是错,或者可以以其他方式使用是正确的?
App.js如果您想要根据结果测试 is的行为fetch,那么我会采用不同的方法。
import { fetchData } from './fetchDataLocation';
jest.mock('./fetchDataLocation', () => ({
fetchData: jest.fn()
}))
jest.mock('./Error', () => jest.fn(() => 'Error'));
jest.mock('./Loading', () => jest.fn(() => 'Loading'));
jest.mock('./Bookstore', () => jest.fn(() => 'Bookstore'));
describe('App', () => {
describe('with error', () => {
beforeEach(() => {
Error.mockClear();
Loading.mockClear();
fetchData.mockImplementation(() => Promise.reject('Error'));
})
test('renders loading component', () => {
const { container } = render(<App />);
expect(Loading).toBeCalled(); // or toBeCalledTimes(1) or lastCalledWith(XYZ) if you want to test the props
})
test('renders error component', () => {
const { container } = render(<App />);
expect(Error).toBeCalled();
})
})
describe('with data', () => {
beforeEach(() => {
Loading.mockClear();
Bookstore.mockClear();
fetchData.mockImplementation(() => Promise.resolve([{ id: 2 }]));
})
test('renders loading component', () => {
const { container } = render(<App />);
expect(Loading).toBeCalled(); // or toBeCalledTimes(1) or lastCalledWith(XYZ) if you want to test the props
})
test('renders bookstore component', () => {
const { container } = render(<App />);
expect(Bookstore).lastCalledWith({ books: [{ id: 2 }]})
})
})
});
Run Code Online (Sandbox Code Playgroud)
保持关注点分离很重要,Foo组件只需要关心它根据道具的行为方式。如果组件有像 a 这样的副作用,fetch则模拟fetch返回不同的场景并相应地测试它们。
| 归档时间: |
|
| 查看次数: |
2976 次 |
| 最近记录: |