我正在寫一個基於Promise的函數的測試。具體而言,它是一個React組件&我正在測試以確保onChange處理程序被正確調用。爲什麼我的Sinon間諜函數在promise條款中調用時不工作?
我的組件看起來是這樣的:
class TextInput extends React.Component {
constructor(props) {
super(props);
this.state = {
value: props.value || '',
};
this.onChange = this.onChange.bind(this);
}
updateState(values) {
return new Promise(
(resolve) => {
this.setState(values,() => { resolve(this.state); });
}
);
}
onChange(event) {
this.updateState({ value: event.target.value })
// then fire the onChange handler (if necessary)
//
.then((state) => {
if (this.props.onChange) {
// console.log(this.props.onChange) shows that this IS a
// Sinon spy function
this.props.onChange(state.value);
}
})
.catch((err) => { console.log('-----------', err); });
}
render() {
// render the component (omitted to keep this short)
}
}
我的測試是這樣的:在過去兩年expect
電話
import React from 'react';
import { mount } from 'enzyme';
import chai from 'chai';
import sinon from 'sinon';
import TextInput from '../../../../client/modules/components/TextInput';
const expect = chai.expect;
describe('TextInput component editing',() => {
it('calls the onChange handler',() => {
const onchange = sinon.spy();
const value = '';
const editedValue = 'something';
const component = mount(<TextInput value={value} onChange={onchange} />);
// change the value
//
component.find('input').simulate('change', {
target: { value: editedValue }
});
expect(component.find('input').prop('value')).to.equal(editedValue);
expect(onchange.calledOnce).to.equal(true);
expect(onchange.calledWith(editedValue)).to.equal(true);
});
});
測試失敗。
如果我用簡單的舊函數替換了sinon間諜,函數被調用。例如,
// instead of this...
// const onchange = sinon.spy();
// do this...
const onchange = (value) => { console.log(`VALUE = ${value}`); };
如果我直接使用setState
方法的回調,它的工作原理。例如,
// instead of...
// this.updateState(values).then(...)
// do this...
this.setState(values,() => {
// call the onChange handler...
});
我能做到這一點,但我想避免它,因爲我要更多的功能添加到這個組件,我不想被困在pyramid of doom。
起初我以爲它可能有一些在updateState
方法或該方法中的回調函數之一的範圍做一個問題this
,但加入console.log
陳述整個顯示,this
是指的一個實例TextInput
在所有適當的地方。
添加一條console.log
語句以便在它被觸發之前轉儲onChange
處理函數顯示this.props.onChange
實際上是一個Sinon間諜。
我看過其他套餐,如sinon-as-promised,但我不認爲這真的包解決什麼,我試圖做的 - 我只是想確保我的回調承諾then
子句中調用。 sinon-as-promised
是一個包裝整個承諾的軟件包。
我可能忽略了一件簡單的事情,但不管它是什麼,我都沒有看到它。
是不是絕對必要的'this.props.onChange '當狀態發生變化時(而不是當狀態正在被改變時)被調用?問題是你的狀態改變方法是異步的,但你的測試不是(我認爲沒有很乾淨解決方案) – robertklep
感謝@robertklep,你讓我對這個問題有了更多的瞭解,爲此,async並不是必須的,但我想在'setState'上使用回調函數來a)確保改變是在繼續(我承認可能會或可能不會有所作爲)和b)實現語義原因的承諾(多步驟過程中的鏈接步驟並避免厄運的金字塔)。 – Kryten