Để cấu hình test cho một app react thông thường sẽ không mấy khó khăn, nhưng để cấu hình cho một app sử dụng các kỹ thuật như redux, react-router đòi hỏi thêm một số cài đặt cần thiết khác.
Giả sử một ứng dụng react sử dụng redux và react-router của bạn có file App.js
như sau:
// App.js
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'react-router-redux';
import { createBrowserHistory } from 'history';
import createRoutes from '../routes/createRoutes'; // your routers
const store = initStore(); // your redux store
const history = createBrowserHistory({ basename: 'http://localhost:8080'});
class App extends Component {
render() {
return (
<Provider store={store}>
<ConnectedRouter history={history}>
{this.state.isReady ?
createRoutes(store, history)
:
<p style={{textAlign: 'center', paddingTop: 50}}>Loading...</p>
}
</ConnectedRouter>
</Provider>
);
}
}
export default App;
JavaScript
Bạn có một container của redux như sau:
// ../containers/TestContainer.js
import TestComponent from '../components/TestComponent.js';
const mapStateToProps = {...}
const mapDispatchToProps = {...}
export default connect(mapStateToProps, mapDispatchToProps)(TestComponent)
JavaScript
Bạn muốn viết test cho container trên như sau:
// TestContainer.spec.js
import React from 'react'
import { wait, fireEvent } from 'react-testing-library'
import { createMemoryHistory } from 'history';
import TestContainer from '../TestContainer';
import TestUtil from '../../../../tests/testUtil';
TestUtil.requireJquery()
const history = createMemoryHistory({ basename: 'http://localhost:8080'});
history.location.pathname = '/your/test/page/path'
const props = {
history,
match: {params: {id: null}}
}
const globalState = {
isLoading: true,
}
const userState = {...}
const pageState = {...}
const initialState = {
global: globalState,
user: userState,
data: pageState,
}
// mock function within testPage
const fetchMock = jest.spyOn(api, 'fetchMock')
const dumpData = {...} // your dump data for test
fetchMock.mockImplementation(() => Promise.resolve(dumpData))
let testPage = null
beforeAll(async () => {
testPage = TestUtil.renderWithRedux(<TestContainer {...props} />, {initialState})
// NOTE: wait to render done
await wait(() => surgeryPage.getByText(/render successfully/i))
})
it ('should match snapshot', () => {
expect(testPage).toMatchSnapshot()
})
it ('should active with jquery', async () => {
// fill 'ab-' to input element
const $ele = $qDiv.find('.textInputDiv input:eq(0)')
fireEvent.change($ele.get(0), { target: { value: 'ab-'}})
await wait(() => {
// because there has async method in pageTest, wait until errorText class appeared
const errText = $qDiv.find('.errorText').text()
expect(errText).toEqual('error')
})
})
JavaScript
Và mình cần viết một module TestUtil
như sau:
// testUtil.js
import React from 'react'
import { render } from 'react-testing-library'
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'react-router-redux';
import { MemoryRouter } from 'react-router-dom';
import { createMemoryHistory } from 'history';
const memoryHistory = createMemoryHistory({ basename: 'http://localhost:8080'});
export default class TestUtil {
static requireJquery() {
window.$ = require('./jquery.min.js')
}
/**
* This is a handy function that I normally make available for all my tests
* that deal with connected components.
* you can provide initialState or the entire store that the ui is rendered with
*/
static renderWithRedux = (
component,
{ initialState, store = initStore(initialState), history } = {}
) => {
return {
...render(
<Provider store={store}>
<ConnectedRouter history={history || memoryHistory}>
<MemoryRouter>
{component}
</MemoryRouter>
</ConnectedRouter>
</Provider>
),
// adding `store` to the returned utilities to allow us
// to reference it in our tests (just try to avoid using
// this to test implementation details).
store,
}
}
}
JavaScript