为React模块编写单元测试时,如何模拟“ this”?

时间:2020-03-05 09:53:20

标签: javascript reactjs unit-testing mocking

我正在编写一个React应用,其中App.js里面有很多逻辑,将其余组件捆绑在一起并保持一致状态。我已经将一些App.js中的原始代码移至helpermodule.js并绑定了导入的函数,以便它们可以操纵App组件的状态。

这是我的设置:

App.js

import helperFunction from './helpermodule'

class App extends Component {
  constructor(props) {
    super(props)

    this.state = { foo: 'bar' }
    this.helperFunction = helperFunction.bind(this)
  }
}

helpermodule.js

function helperFunction() {
  this.setState({
    bar: 'calculated' + this.state.foo,
  })
}

export { helperFunction }

我想为helpermodule中的函数编写一个单元测试。在涉及此内容的酶或Jest文档中找不到相关的部分。目的是查看helperFunction对App状态有什么影响。

我已经尝试过类似的事情

test('helperFunction', () => {
  let state = { foo: 'bar' }
  let setState = (obj) => { this.state = obj }

  return expect(helperFunction().bind(this))
    .toBe({
      ...newShift,
      id: 0,
    })
}

但这只会返回一个错误; TypeError: Cannot read property 'state' of undefined。也许我的整个方法是错误的,所以可以解决该问题,但我不确定。

2 个答案:

答案 0 :(得分:0)

请勿在外部函数中使用this.setState

helpermodule.js

function helperFunction(stateFoo) {
  return {bar: 'calculated' + stateFoo};
}

export { helperFunction }

然后使用结果在组件中设置状态。也不要在构造函数中使用setState。

import helperFunction from './helpermodule'

class App extends Component {
  constructor(props) {
    super(props)

    this.state = { foo: 'bar', ...helperFunction('bar') }
  }
}

这将使测试更容易,并且总体上来说是更好的结构。

答案 1 :(得分:0)

不知道您为什么要采用这种方法,但是这种奇怪且难以遵循和维护的方法,只是出于您的观点。问题是您正在将this传递给绑定,而this没有statesetState的属性,因此您应该传递模拟的this。 / p>

这是怎么回事

describe('helperFunction', () => {
    function helperFunction() {
        // @ts-ignore
        this.setState({
            // @ts-ignore
            bar: 'calculated' + this.state.foo,
        })
    }

    it('updates the provided stateHolder', () => {
        const stateHolder = {
            state: { foo: 'bar' },
            // don't use arrow function otherwise it won't react the state via this
            setState(obj: any) {
                this.state = obj;
            },
        };

        const importedHelperFunction = helperFunction.bind(stateHolder);
        importedHelperFunction();

        expect(stateHolder.state.foo).toBe('calculatedbar');
    });
});