Reactjs 使用React钩子客户端测试Apollo查询
我正在尝试使用jest为这个组件编写测试Reactjs 使用React钩子客户端测试Apollo查询,reactjs,jestjs,react-hooks,react-apollo,Reactjs,Jestjs,React Hooks,React Apollo,我正在尝试使用jest为这个组件编写测试 import { useState, useRef } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { Query } from 'react-apollo'; import { updateYourDetails } from 'universal/domain/health/yourDetails/yo
import { useState, useRef } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Query } from 'react-apollo';
import { updateYourDetails } from 'universal/domain/health/yourDetails/yourDetailsActions';
import Input from 'universal/components/input/input';
import InputNumber from 'universal/components/input/inputNumber/inputNumber';
import AsyncButton from 'universal/components/asyncButton/asyncButton';
import ErrorMessage from 'universal/components/errorMessage/errorMessage';
import Link from 'universal/components/link/link';
import analytics from 'universal/utils/analytics/analytics';
import { isChatAvailable } from 'universal/logic/chatLogic';
import { validators } from 'universal/utils/validation';
import { localTimezone, getWeekdays } from 'universal/utils/date';
import {
CALL_ME_BACK_LOADING_MSG,
CALL_ME_BACK_LABELS_SCHEDULE_TIME,
CALL_ME_BACK_LABELS_SELECTED_DATE,
CALL_ME_BACK_ERROR_MSG,
CALL_ME_BACK_TEST_PARENT_WEEKDAY,
CALL_ME_BACK_TEST_CHILD_WEEKDAY,
} from 'universal/constants/callMeBack';
import CallCenterAvailibility from './CallCenterAvailibility';
import SelectWrapper from './SelectWrapper';
import SelectOption from './SelectOption';
import styles from './callMeBackLightBox.css';
import { CALL_ME_BACK_QUERY } from './callMeBackQuery';
import postData from './postData';
export const CallMeForm = props => {
const initSelectedDate = getWeekdays()
.splice(0, 1)
.reduce(acc => ({ ...acc }));
const { onSubmissionComplete, className, variant } = props;
const [hasSuccessfullySubmitted, setHasSuccessfullySubmitted] = useState(false);
const [apiStatus, setApiStatus] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [cellNumber, setCallNumber] = useState(props.cellNumber || '');
const [customerFirstName, setCustomerFirstName] = useState(props.customerFirstName || '');
const [number, setNumber] = useState(props.Number || '');
const [selectedDate, setSelectedDate] = useState(initSelectedDate || '');
const [scheduledTime, setScheduledTime] = useState('');
const weekdays = getWeekdays() || [];
const timezone = localTimezone || '';
const requestReceived = apiStatus === 'CALLBACK_ALREADY_EXIST';
const cellNumberInput = useRef(null);
const customerFirstNameInput = useRef(null);
const getQuery = () => (
<Query query={CALL_ME_BACK_QUERY} variables={{ weekday: selectedDate.weekday }}>
{({ data, error, loading }) => {
if (loading)
return (
<SelectWrapper disabled labelTitle={CALL_ME_BACK_LABELS_SCHEDULE_TIME} name="scheduledTime">
<SelectOption label={CALL_ME_BACK_LOADING_MSG} />
</SelectWrapper>
);
if (error) return <ErrorMessage hasError errorMessage={<p>{CALL_ME_BACK_ERROR_MSG}</p>} />;
return (
<CallCenterAvailibility
selectedDate={selectedDate}
callCenterBusinessHour={data.callCenterBusinessHour}
onChange={val => setScheduledTime(val)}
/>
);
}}
</Query>
);
const getPostSubmitMessage = (firstName: string, type: string) => {
const messages = {
callCentreClosed: `a`,
requestReceived: `b`,
default: `c`,
};
return `Thanks ${firstName}, ${messages[type] || messages.default}`;
};
const validate = () => {
const inputs = [customerFirstNameInput, cellNumberInput];
const firstInvalidIndex = inputs.map(input => input.current.validate()).indexOf(false);
const isValid = firstInvalidIndex === -1;
return isValid;
};
const onSubmitForm = event => {
event.preventDefault();
onSubmit();
};
const onSubmit = async () => {
if (variant === '0' && !validate()) {
return;
}
analytics.track(analytics.events.callMeBack.callMeBackSubmit, {
trackingSource: 'Call Me Form',
});
setIsLoading(true);
const srDescription = '';
const response = await postData({
cellNumber,
customerFirstName,
number,
scheduledTime,
timezone,
srDescription,
});
const { status } = response;
const updatedSubmissionFlag = status === 'CALLBACK_ALREADY_EXIST' || status === 'CALLBACK_ADDED_SUCCESSFULLY';
// NOTE: add a slight delay for better UX
setTimeout(() => {
setApiStatus(apiStatus);
setIsLoading(false);
setHasSuccessfullySubmitted(updatedSubmissionFlag);
}, 400);
// Update Redux store
updateYourDetails({
mobile: cellNumber,
firstName: customerFirstName,
});
if (onSubmissionComplete) {
onSubmissionComplete();
}
};
if (hasSuccessfullySubmitted) {
return (
<p aria-live="polite" role="status">
{getPostSubmitMessage(
customerFirstName,
(!requestReceived && !isChatAvailable() && 'callCentreClosed') || (requestReceived && 'requestReceived')
)}
</p>
);
}
return (
<form onSubmit={onSubmitForm} className={className}>
{variant !== '1' && (
<>
<label htmlFor="customerFirstName" className={styles.inputLabel}>
First name
</label>
<Input
className={styles.input}
initialValue={customerFirstName}
isMandatory
maxLength={20}
name="customerFirstName"
onChange={val => setCustomerFirstName(val)}
ref={customerFirstNameInput}
value={customerFirstName}
{...validators.plainCharacters}
/>
</>
)}
{variant !== '1' && (
<>
<label htmlFor="cellNumber" className={styles.inputLabel}>
Mobile number
</label>
<Input
className={styles.input}
initialValue={cellNumber}
isMandatory
maxLength={10}
name="cellNumber"
onChange={val => setCallNumber(val)}
ref={cellNumberInput}
type="tel"
value={cellNumber}
{...validators.tel}
/>
</>
)}
{variant !== '1' && (
<>
{' '}
<label htmlFor="number" className={styles.inputLabel}>
Qantas Frequent Flyer number (optional)
</label>
<InputNumber
className={styles.input}
disabled={Boolean(props.number)}
initialValue={number}
name="number"
onChange={val => setNumber(val)}
value={number}
/>
</>
)}
{weekdays && (
<>
<SelectWrapper
testId={`${CALL_ME_BACK_TEST_PARENT_WEEKDAY}`}
labelTitle={CALL_ME_BACK_LABELS_SELECTED_DATE}
name="selectedDate"
onChange={val =>
setSelectedDate({
...weekdays.filter(({ value }) => value === val).reduce(acc => ({ ...acc })),
})
}
tabIndex={0}
>
{weekdays.map(({ value, label }, i) => (
<SelectOption
testId={`${CALL_ME_BACK_TEST_CHILD_WEEKDAY}-${i}`}
key={value}
label={label}
value={value}
/>
))}
</SelectWrapper>
{getQuery()}
</>
)}
<AsyncButton className={styles.submitButton} onClick={onSubmit} isLoading={isLoading}>
Call me
</AsyncButton>
<ErrorMessage
hasError={(apiStatus >= 400 && apiStatus < 600) || apiStatus === 'Failed to fetch'}
errorMessage={
<p>
There was an error submitting your request to call you back. Please try again or call us at{' '}
<Link href="tel:134960">13 49 60</Link>.
</p>
}
/>
</form>
);
};
CallMeForm.propTypes = {
cellNumber: PropTypes.string,
customerFirstName: PropTypes.string,
number: PropTypes.string,
onSubmissionComplete: PropTypes.func,
className: PropTypes.string,
variant: PropTypes.string,
};
const mapStateToProps = state => {
const { frequentFlyer, yourDetails } = state;
return {
cellNumber: yourDetails.mobile,
customerFirstName: yourDetails.firstName,
number: frequentFlyer.memberNumber,
};
};
export default connect(mapStateToProps)(CallMeForm);
从'react'导入{useState,useRef};
从“道具类型”导入道具类型;
从'react redux'导入{connect};
从'react apollo'导入{Query};
从“universal/domain/health/yourDetails/yourDetailsActions”导入{updateYourDetails};
从“通用/组件/输入/输入”导入输入;
从“universal/components/input/InputNumber/InputNumber”导入InputNumber;
从“universal/components/AsyncButton/AsyncButton”导入AsyncButton;
从“universal/components/ErrorMessage/ErrorMessage”导入ErrorMessage;
从“通用/组件/链接/链接”导入链接;
从“universal/utils/analytics/analytics”导入分析;
从“universal/logic/chatLogic”导入{isChatAvailable};
从“universal/utils/validation”导入{validators};
从“universal/utils/date”导入{localTimezone,getWeekdays};
进口{
给我回电话,装邮件,
给我回个电话给我安排时间,
回拨\u我\u标签\u选定日期,
给我回电话错误消息,
在工作日给我回电话,考试,家长,
在工作日给我回电话,考试,孩子,
}来自“universal/constants/callMeBack”;
从“/CallCenterAvailability”导入CallCenterAvailability;
从“/SelectWrapper”导入SelectWrapper;
从“/SelectOption”导入SelectOption;
从“./callmebackgroundbox.css”导入样式;
从“./callMeBackQuery”导入{CALL_ME_BACK_QUERY};
从“/postData”导入postData;
导出常量CallMeForm=props=>{
const initSelectedDate=getWeekdays()
.拼接(0,1)
.reduce(acc=>({…acc}));
const{onSubmissionComplete,className,variant}=props;
const[HassSuccessfullySubmitted,SetHassSuccessfullySubmitted]=useState(false);
const[apiStatus,setApiStatus]=useState(“”);
const[isLoading,setIsLoading]=useState(false);
const[cellNumber,setCallNumber]=useState(props.cellNumber | |“”);
const[customerFirstName,setCustomerFirstName]=useState(props.customerFirstName | |“”);
const[number,setNumber]=useState(props.number | |“”);
const[selectedDate,setSelectedDate]=useState(initSelectedDate | |“”);
const[scheduledTime,setScheduledTime]=useState(“”);
const weekdays=getWeekdays()| 124;[];
常量时区=本地时区| |'';
const requestReceived=apiStatus==“回调已存在”;
const cellNumberInput=useRef(null);
const customerFirstNameInput=useRef(null);
常量getQuery=()=>(
{({数据,错误,加载})=>{
如果(装载)
返回(
);
如果(错误)返回;
返回(
setScheduledTime(val)}
/>
);
}}
);
const getPostSubmitMessage=(名字:string,类型:string)=>{
常量消息={
callCentreClosed:`a`,
requestReceived:`b`,
默认值:`c`,
};
返回`谢谢${firstName},${messages[type]| | messages.default}`;
};
常量验证=()=>{
常量输入=[customerFirstNameInput,cellNumberInput];
const firstInvalidIndex=inputs.map(input=>input.current.validate()).indexOf(false);
常量isValid=firstInvalidIndex==-1;
返回有效;
};
const onSubmitForm=事件=>{
event.preventDefault();
onSubmit();
};
const onSubmit=async()=>{
如果(变量=='0'&&!validate()){
返回;
}
analytics.track(analytics.events.callMeBack.callMeBackSubmit{
trackingSource:“呼叫我表单”,
});
设置加载(真);
常量srDescription='';
const response=等待postData({
手机号码,
customerFirstName,
数字,
预定时间,
时区,
描述,
});
const{status}=响应;
const updatedSubmissionFlag=状态=='CALLBACK_已经存在'| |状态=='CALLBACK_添加成功';
//注意:增加一点延迟以获得更好的用户体验
设置超时(()=>{
setApiStatus(apiStatus);
设置加载(假);
SetHassSuccessfullySubmited(更新的SubmissionFlag);
}, 400);
//更新Redux存储
更新您的详细信息({
手机号码:,
名字:customerFirstName,
});
如果(任务完成时){
onSubmissionComplete();
}
};
如果(已成功提交){
返回(
{getPostSubmitMessage(
customerFirstName,
(!requestReceived&&!isChatAvailable()&&“callCentreClosed”)| |(requestReceived&&“requestReceived”)
)}
);
}
返回(
{variant!='1'&&(
名字
setCustomerFirstName(val)}
ref={customerFirstNameInput}
值={customerFirstName}
{…验证程序.纯字符}
/>
)}
{variant!='1'&&(
手机号码
setCallNumber(val)}
ref={cellNumberInput}
type=“电话”
值={cellNumber}
{…validators.tel}
/>
)}
{variant!='1'&&(
{' '}
澳航常客号码(可选)
setNumber(val)}
值={number}
/>
)}
{工作日&&(
选定日期({
…weekdays.filter(({value})=>value==val.reduce(acc=>({…acc})),
})
}
tabIndex={0}
>
{weekdays.map({value,label},i)=>(
))}
{getQuery()}
)}
打电话给我
=400&&apiStatus<600)| | apiStatus==='无法获取'}
错误信息={
提交您的回拨请求时出错。请重试或致电{'}
13 49 60.
import { render, cleanup } from '@testing-library/react';
import { MockedProvider } from 'react-apollo/test-utils';
import { shallow } from 'enzyme';
import MockDate from 'mockdate';
import { isChatAvailable } from 'universal/logic/chatLogic';
import { CALL_ME_BACK_QUERY } from './callMeBackQuery';
import { CallMeForm } from './CallMeForm';
import postData from './postData';
jest.mock('universal/components/input/input', () => 'Input');
jest.mock('universal/components/asyncButton/asyncButton', () => 'AsyncButton');
jest.mock('universal/components/errorMessage/errorMessage', () => 'ErrorMessage');
jest.mock('universal/logic/chatLogic');
jest.mock('./postData');
describe('CallMeForm', () => {
let output;
beforeEach(() => {
jest.resetModules();
jest.resetAllMocks();
const mockQueryData = [
{
client:{},
request: {
query: CALL_ME_BACK_QUERY,
variables: { weekday: '' },
},
result: {
data: {
callCenterBusinessHour: {
timeStartHour: 9,
timeStartMinute: 0,
timeEndHour: 5,
timeEndMinute: 0,
closed: false,
},
},
},
},
];
const { container } = render(<MockedProvider mocks={mockQueryData} addTypename={false}><CallMeForm /></MockedProvider>);
output = container;
});
afterEach(cleanup);
it('renders correctly', () => {
expect(output).toMatchSnapshot();
});
});
<MockedProvider {...props}>
<ApolloConsumer>
{client => {
client.stop = jest.fn();
return <MyComponent />;
}}
</ApolloConsumer>
</MockedProvider>