我有一个丰富的文本编辑器输入字段,我想用一个已弹出的组件包装。已取消的输入组件如下所示:
import { useState, useCallback } from 'react';
import debounce from 'lodash.debounce';
const useDebounce = (callback, delay) => {
const debouncedFn = useCallback(
debounce((...args) => callback(...args), delay),
[delay] // will recreate if delay changes
);
return debouncedFn;
};
function DebouncedInput(props) {
const [value, setValue] = useState(props.value);
const debouncedSave = useDebounce((nextValue) => props.onChange(nextValue), props.delay);
const handleChange = (nextValue) => {
setValue(nextValue);
debouncedSave(nextValue);
};
return props.renderProps({ onChange: handleChange, value });
}
export default DebouncedInput;我使用DebouncedInput作为MediumEditor的包装组件。
<DebouncedInput
value={task.text}
onChange={(text) => onTextChange(text)}
delay={500}
renderProps={(props) => (
<MediumEditor
{...props}
id="task"
style={{ height: '100%' }}
placeholder="Task text…"
disabled={readOnly}
key={task.id}
/>
)}
/>;MediumEditor组件做了一些我想测试的卫生工作,例如剥离html标记:
class MediumEditor extends React.Component {
static props = {
id: PropTypes.string,
value: PropTypes.string,
onChange: PropTypes.func,
disabled: PropTypes.bool,
uniqueID: PropTypes.any,
placeholder: PropTypes.string,
style: PropTypes.object,
};
onChange(text) {
this.props.onChange(stripHtml(text) === '' ? '' : fixExcelPaste(text));
}
render() {
const {
id,
value,
onChange,
disabled,
placeholder,
style,
uniqueID,
...restProps
} = this.props;
return (
<div style={{ position: 'relative', height: '100%' }} {...restProps}>
{disabled && (
<div
style={{
position: 'absolute',
width: '100%',
height: '100%',
cursor: 'not-allowed',
zIndex: 1,
}}
/>
)}
<Editor
id={id}
data-testid="medium-editor"
options={{
toolbar: {
buttons: ['bold', 'italic', 'underline', 'subscript', 'superscript'],
},
spellcheck: false,
disableEditing: disabled,
placeholder: { text: placeholder || 'Skriv inn tekst...' },
}}
onChange={(text) => this.onChange(text)}
text={value}
style={{
...style,
background: disabled ? 'transparent' : 'white',
borderColor: disabled ? 'grey' : '#FF9600',
overflowY: 'auto',
color: '#444F55',
}}
/>
</div>
);
}
}
export default MediumEditor;我就是这样测试这个的:
it('not stripping html tags if there is text', async () => {
expect(editor.instance.state.text).toEqual('Lorem ipsum ...?');
const mediumEditor = editor.findByProps({ 'data-testid': 'medium-editor' });
const newText = '<p><b>New text, Flesk</b></p>';
mediumEditor.props.onChange(newText);
// jest.runAllTimers();
expect(editor.instance.state.text).toEqual(newText);
});当我运行这个测试时,我得到:
Error: expect(received).toEqual(expected) // deep equality
Expected: "<p><b>New text, Flesk</b></p>"
Received: "Lorem ipsum ...?"在检查结果之前,我还尝试过用jest.runAllTimers();运行测试,但之后我得到:
Error: Ran 100000 timers, and there are still more! Assuming we've hit an infinite recursion and bailing out...我也曾尝试过:
jest.advanceTimersByTime(500);但是考试总是失败,我得到了旧的文本状态。状态似乎不会因为某种原因而改变,这是很奇怪的,因为在我用DebounceInput组件包装组件之前,组件和测试都是绿色的。具有MediumEditor的父组件有一个应该从DebounceInput组件调用的方法onTextChange,因为它是作为onChange支柱传递给DebounceInput,的函数,但是在测试中,我可以看到这个方法是永远无法实现的。在浏览器中,一切都很好,所以我不知道它为什么不能在测试中工作?
onTextChange(text) {
console.log('text', text);
this.setState((state) => {
return {
task: { ...state.task, text },
isDirty: true,
};
});
}在进一步的检查中,我可以看到在测试中通过了正确的值,一直到handleChange in DebouncedInput.。因此,我怀疑,在这个测试中,lodash.debounce存在一些问题。我不确定我是应该嘲笑这个函数,还是嘲笑它?
const handleChange = (nextValue) => {
console.log(nextValue);
setValue(nextValue);
debouncedSave(nextValue);
};这就是我怀疑测试中的问题所在:
const useDebounce = (callback, delay) => {
const debouncedFn = useCallback(
debounce((...args) => callback(...args), delay),
[delay] // will recreate if delay changes
);
return debouncedFn;
};我试过像这样嘲弄别人:
import debounce from 'lodash.debounce'
jest.mock('lodash.debounce');
debounce.mockImplementation(() => jest.fn(fn => fn));这让我犯了错误:
TypeError:_lodash.default.mockImplementation不是一个函数
我该怎么解决这个问题?
发布于 2021-01-13 19:26:04
我猜你正在使用酶(从道具访问)。为了测试一些依赖于jest定时器的代码
请注意,当您从酶中更改状态时,需要使用jest.useFakeTimers()
componentWrapper.update()
jest.runOnlyPendingTimers()调用计时器。
这应该能行。
很少有关于测试反应组件的附带说明:
如果您想测试functionality
MediumEditor),测试整个包装组件以测试onChange
onChange道具(或任何其他道具)。它使您的测试更加了解实现(=与组件实现高度耦合),实际上它们没有检查您的组件是否正常工作,例如,考虑到由于某些原因您没有将onChange支柱传递给输入,您的测试就会通过(因为您的测试正在调用onChange支柱),但实际上它无法工作。组件测试的最佳方法是像用户将要做的那样模拟组件上的操作,例如,在输入组件中,模拟组件上的更改/输入事件(这是用户在实际应用程序中输入时所做的)。
https://stackoverflow.com/questions/65554104
复制相似问题