开玩笑:无法窥探该属性,因为它不是函数;给定的未定义
Posted
技术标签:
【中文标题】开玩笑:无法窥探该属性,因为它不是函数;给定的未定义【英文标题】:Jest: Cannot spy the property because it is not a function; undefined given instead 【发布时间】:2020-06-11 02:05:08 【问题描述】:我正在尝试为一个简单的 React 组件编写一个 Jest 测试,以确认在我模拟点击时调用了一个函数。
但是,当我使用 spyOn 方法时,我不断收到 TypeError: Cannot read property 'validateOnSave' of undefined. 我的代码如下所示:
OptionsView.js
class OptionsView extends React.Component
constructor(props)
super(props);
this.state =
reasonCode: null,
remarkCode: null,
otherCode: null,
codeSelectionIsInvalid: [false, false, false],
;
this.validateOnSave = this.validateOnSave.bind(this);
this.saveOptions = this.saveOptions.bind(this);
validateOnSave()
const copy = this.state.codeSelectionIsInvalid;
copy[0] = !this.state.reasonCode;
copy[1] = !this.state.remarkCode;
copy[2] = !this.state.otherCode;
this.setState( codeSelectionIsInvalid: copy );
if (!copy[0] && !copy[1] && !copy[2])
this.saveOptions();
saveOptions()
const saveCallback = this.props;
if (saveCallback !== undefined)
saveCallback( reasonCode: this.state.reasonCode, remarkCode: this.state.remarkCode, otherCode: this.state.otherCode,
);
render()
const cx = classNames.bind(styles);
const reasonCodes = this.props.reasonCodeset.map(reasonCode => (
<Select.Option
value=reasonCode.objectIdentifier
key=reasonCode.objectIdentifier
display=`$reasonCode.name`
/>
));
const remarkCodes = this.props.remarkCodeset.map(remarkCode => (
<Select.Option
value=remarkCode.objectIdentifier
key=remarkCode.objectIdentifier
display=`$remarkCode.name`
/>
));
const otherCodes = this.props.otherCodeset.map(otherCode => (
<Select.Option
value=otherCode.objectIdentifier
key=otherCode.objectIdentifier
display=`$otherCode.name`
/>
));
return (
<ContentContainer fill>
<Spacer marginTop="none" marginBottom="large+1" marginLeft="none" marginRight="none" paddingTop="large+2" paddingBottom="none" paddingLeft="large+2" paddingRight="large+2">
<Fieldset legend="Code sets">
<Grid>
<Grid.Row>
<Grid.Column tiny=3>
<SelectField selectId="reasons" required placeholder="Select" label="Reasons:" error="Required field is missing" value=this.state.reasonCode onChange=this.updateReasonCode isInvalid=this.state.codeSelectionIsInvalid[0]>
reasonCodes
</SelectField>
</Grid.Column>
</Grid.Row>
<Grid.Row>
<Grid.Column tiny=3>
<SelectField selectId="remarks" required placeholder="Select" label="Remarks:" error="Required field is missing" value=this.state.remarkCode onChange=this.updateRemarkCode isInvalid=this.state.codeSelectionIsInvalid[1]>
remarkCodes
</SelectField>
</Grid.Column>
</Grid.Row>
<Grid.Row>
<Grid.Column tiny=3>
<SelectField selectId="other-codes" required placeholder="Select" label="Other Codes:" error="Required field is missing" value=this.state.otherCode onChange=this.updateOtherCode isInvalid=this.state.codeSelectionIsInvalid[2]>
otherCodes
</SelectField>
</Grid.Column>
</Grid.Row>
</Grid>
</Fieldset>
</Spacer>
<ActionFooter
className=cx(['action-header-footer-color'])
end=(
<React.Fragment>
<Spacer isInlineBlock marginRight="medium">
<Button text="Save" onClick=this.validateOnSave />
</Spacer>
</React.Fragment>
)
/>
</ContentContainer>
);
OptionsView.propTypes = propTypes;
export default injectIntl(OptionsView);
OptionsView.test
describe('RemittanceOptions View', () =>
let defaultProps = ...defined...
beforeAll(() =>
Object.defineProperty(window, "matchMedia",
value: jest.fn(() =>
return
matches: true,
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
)
);
);
it('should validate remit codes on save', () =>
const wrapper = mountWithIntl(<OptionsView
...defaultProps
/>);
const instance = wrapper.instance();
const spy = jest.spyOn(instance, "validateOnSave");
wrapper.setState(
reasonCode: 84,
remarkCode: 10,
otherCode: null
);
console.log(wrapper.find('Button[text="Save"]').debug());
const button = wrapper.find('Button[text="Save"]').at(0);
expect(button.length).toBe(1);
button.simulate('click');
expect(spy).toHaveBeenCalled();
expect(wrapper.state('codeSelectionIsInvalid')).toEqual([false,false,true]);
);
);
最终目标是在点击保存时测试两种情况:
当 state.codeSelectionIsInvalid: [false,false,true]
当 state.codeSelectionIsInvalid: [false,false,false]
我哪里错了。任何帮助表示赞赏!
【问题讨论】:
【参考方案1】:经过几个小时的调试,发现实例没有绑定任何方法。由于是连接组件,使用shallowWithIntl()
和dive()
解决了错误。
it('should validate remit codes on save', () =>
const wrapper = shallowWithIntl(<RemitOptionsView
...testProps
/>);
const button = wrapper.dive().find('Button[text="Save"]'); //Not finding the button
const instance = wrapper.dive().instance();
const spy = jest.spyOn(instance, 'validateOnSave');
instance.validateOnSave();
);
【讨论】:
以上是关于开玩笑:无法窥探该属性,因为它不是函数;给定的未定义的主要内容,如果未能解决你的问题,请参考以下文章
Spring HATEOAS RepresentationModel,无法设置属性链接,因为没有设置器,没有枯萎,它不是持久性构造函数的一部分