我正在尝试从基础测试开始学习测试,现在我想测试功能。但是,我遍历了整个互联网,无法测试onClick。也许我找不到东西。
我尝试使用sinon.spy,开玩笑的spyOn等,但是这些都没有解决。
测试,我正在尝试写。
import React from "react";
import {
shallow,
configure
} from "enzyme"
import Adapter from "enzyme-adapter-react-16";
import ConfirmDeleteButton from "../ConfirmDeleteButton"
import { Modal } from "react-bootstrap"
import sinon from "sinon"
import toJson from "enzyme-to-json";
configure({adapter: new Adapter()});
let wrapper;
const fnClick = sinon.spy();
// Assign component to wrapper variable, before all tests.
beforeEach(() => {
wrapper = shallow(<ConfirmDeleteButton onClick={fnClick} />)
});
describe("ConfirmDeleteButton component", () => {
it('should call mockfn onclick', () => {
//simulate onClick
wrapper
.find("Button").first()
.prop("onClick")()
expect(fnClick).toBeCalled();
})
})
我正在测试的组件:
import React, { useState } from 'react'
import PropTypes from 'prop-types'
import { Button, Spinner, Modal } from 'react-bootstrap'
import { Mutation } from 'react-apollo'
const ConfirmDeleteButton = props => {
const [confirmDelete, setConfirmDelete] = useState(false)
const [timeout, setTimeoutState] = useState()
const [show, setShow] = useState(false)
const confirmButtonRef = React.createRef()
const handleClose = () => setShow(false)
const handleShow = () => setShow(true)
return (
<React.Fragment>
<Button variant='outline-danger' onClick={handleShow} id='openModal'>
Delete
</Button>
<Modal show={show} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Confirmation dialog</Modal.Title>
</Modal.Header>
<Modal.Body>
Are you sure you want to delete this item?
This item will be gone permanently, and can cause cascade delete!
</Modal.Body>
<Modal.Footer>
<Button variant='outline-secondary' onClick={handleClose} id='closeModal'>
Close
</Button>
{confirmDelete ? (
<Mutation
mutation={props.deleteMutation}
// refetchQueries triggers parent component to be loaded with new data
refetchQueries={props.refetchQueries}
onCompleted={() => {
if (props.onCompleted) {
props.onCompleted()
}
setConfirmDelete(false)
}}
>
{(deleteFunction, { loading, error }) => (
<Button
variant='danger'
ref={confirmButtonRef}
onClick={() => {
let vars = {}
if (props.variables) {
for (let key in props.variables) {
vars[key] = props.variables[key]
}
} else {
vars['ID'] = props.id
}
deleteFunction({ variables: vars })
clearTimeout(timeout)
confirmButtonRef.current.blur()
handleClose()
}}
>
{loading ? <Spinner animation='border' as='span' size='sm' /> : 'Confirm'}
</Button>
)}
</Mutation>
) : (
<Button
variant='outline-success'
onClick={() => {
setConfirmDelete(true)
setTimeoutState(
setTimeout(function() {
setConfirmDelete(false)
}, 3000)
)
}}
>
Yes
</Button>
)}
</Modal.Footer>
</Modal>
</React.Fragment>
)
}
ConfirmDeleteButton.propTypes = {
onCompleted: PropTypes.func,
variables: PropTypes.object,
deleteMutation: PropTypes.object,
refetchQueries: PropTypes.array
}
export default ConfirmDeleteButton
最后,我想进行测试: *如果单击的按钮将调用handleShow
现在我开始了:
ConfirmDeleteButton component › should call mockfn onclick
expect(jest.fn())[.not].toBeCalled()
Matcher error: received value must be a mock or spy function
Received has type: function
Received has value: [Function anonymous]
我将添加package.json以防万一:
"devDependencies": {
"@babel/core": "^7.1.6",
"@babel/plugin-transform-runtime": "^7.5.0",
"@babel/preset-env": "^7.1.6",
"@babel/preset-es2015": "^7.0.0-beta.53",
"@babel/preset-react": "^7.0.0",
"@material-ui/core": "^4.2.0",
"apollo-boost": "^0.4.3",
"autoprefixer": "^9.6.1",
"babel-jest": "^24.8.0",
"babel-loader": "^8.0.6",
"babel-plugin-transform-export-extensions": "^6.22.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-stage-3": "^6.24.1",
"bootstrap": "^4.3.1",
"chai": "^4.2.0",
"chai-enzyme": "^1.0.0-beta.1",
"copy-webpack-plugin": "^5.0.3",
"css-loader": "^3.0.0",
"dotenv": "^8.0.0",
"dotenv-webpack": "^1.7.0",
"enzyme": "^3.10.0",
"enzyme-adapter-react-15": "^1.4.0",
"enzyme-adapter-react-16": "^1.14.0",
"enzyme-to-json": "^3.3.5",
"eslint": "^6.0.1",
"eslint-cli": "^1.1.1",
"eslint-config-airbnb": "^17.1.1",
"eslint-config-airbnb-base": "^13.2.0",
"eslint-config-prettier": "^6.0.0",
"eslint-loader": "^2.2.1",
"eslint-plugin-prettier": "^3.1.0",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^4.0.0",
"graphql": "^14.4.2",
"html-webpack-plugin": "^3.2.0",
"jest": "^24.8.0",
"mini-css-extract-plugin": "^0.7.0",
"node-sass": "^4.12.0",
"prettier": "^1.18.2",
"react": "^16.8.6",
"react-apollo": "^2.5.8",
"react-bootstrap": "^1.0.0-beta.9",
"react-dom": "^16.8.6",
"react-hot-loader": "^4.12.6",
"react-router-dom": "^5.0.1",
"react-scripts": "^3.0.1",
"react-test-renderer": "^16.8.6",
"sass-loader": "^7.1.0",
"sinon": "^7.3.2",
"sinon-chai": "^3.3.0",
"style-loader": "^0.23.1",
"ts-jest": "^24.0.2",
"uglifyjs-webpack-plugin": "^2.1.3",
"uuid": "^3.3.2",
"webpack": "^4.35.3",
"webpack-bundle-tracker": "^0.4.2-beta",
"webpack-cli": "^3.3.5",
"webpack-dev-server": "^3.7.2"
},
"dependencies": {
"@babel/core": "^7.5.4"
}
答案 0 :(得分:0)
请参见,您的组件不希望使用props.onClick
。通过查看propTypes
,然后在组件代码中进行验证,您可能会注意到这一点。由于未使用-永远不会调用它。
如果您正在寻找如何测试组件的方法,则可以在单击第一个按钮之后验证Modal是否已显示
it('displays modal after clicking Delete button", async () => {
const wrapper = shallow(...);
expect(wrapper.find(Modal).props().show).toBeFalsy();
wrapper.find("#openModal").props().onClick();
// here internal state is changed and to get component re-rendered we just skip await
await Promise.resolve(); // below code runs after re-render
expect(wrapper.find(Modal).props().show).toBeTruthy();
});
要使用jest.fn
进行验证,我们需要在组件内部调用的prop
。
在
ConfirmDeleteButton.propTypes = {
onCompleted: PropTypes.func,
variables: PropTypes.object,
deleteMutation: PropTypes.object,
refetchQueries: PropTypes.array
}
仅onCompleted
符合我们的需求。但是触发它会更困难:
it('delegates onCompleted to Mutation after user confirmed deletion', async () => {
const onCompletedMock = jest.fn();
const wrapper = shallow(<ConfirmDeleteButton onCompleted={onCompletedMock} />);
wrapper.find("#openModal").props().onClick();
// below code runs after modal is opened
await Promise.resolve();
/* confirmation button does not have any id
so we need to take second button in scope of Modal */
wrapper.find(Modal).find(Button).at(1).props().onClick();
await Promise.resolve();
// at this moment <Mutation> should be rendered
expect(onCompletedMock).not.toHaveBeenCalled(); // not yet called
/* <Mutation /> will not call `onCompleted` on its own because of shallow rendering
so we need to call it manually */
wrapper.find(Mutation).props().onCompleted();
expect(onCompletedMock).toHaveBeenCalled(); // should be already called
})
通常:
propTypes
以便更快地找到它)jest.fn
来监视功能道具find(Button).props().onClick
之类的嵌套元素上的道具来与组件进行通信expect(wrapper.find(SomeNewElementShouldAppear)).toHaveLength(1)
或expect(wrapper.find(Modal).props().show).toEqual(true)
之类的渲染中发生的更改