【问题标题】:Mocking moment.js react props with jest and enzymeMocking moment.js 用 jest 和酶反应道具
【发布时间】:2020-01-18 14:20:11
【问题描述】:

假设我有一个子组件,它需要两个矩对象作为道具,例如:

import React from 'react';
import PropTypes from 'prop-types';
import moment from 'moment';

class ChildComponent extends React.Component {
    constructor(props) {
        super(props);
    }

    startAndEndDateOnSameDay() {
        return this.props.startDate.isSame(this.props.endDate, 'date')
    }

    render() {
        let formattedDate;
        if(this.startAndEndDateOnSameDay()) {
            formattedDate = this.props.startDate.format();
        }
        else {
            formattedDate = this.props.endDate.fromNow();
        }

        return (
            <div>{formattedDate}</div>
        );
    }
}

ChildComponent.propTypes = {
    startDate: PropTypes.instanceOf(moment).isRequired,
    endDate: PropTypes.instanceOf(moment).isRequired
}

export default ChildComponent;

还有一个父组件将两个矩对象传递给子组件,例如:

import React from 'react';
import PropTypes from 'prop-types';
import moment from 'moment';
import ChildComponent from './ChildComponent';

class ParentComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            startDate: moment(),
            endDate: moment()
        };
    }

    render() {
        return (
            <ChildComponent startDate={this.state.startDate} endDate={this.state.endDate}/>
        );
    }
}

export default ParentComponent;

我正在尝试用 jest 和酶来测试这些组件:

import React from 'react';
import { shallow } from 'enzyme';
import ParentComponent from '../components/ParentComponent';

describe('<ParentComponent />', () => {
    let wrapper;

    beforeAll(() => {
        wrapper = shallow(<ParentComponent/>);
    });

    it('should render the component correctly', () => {
        expect(wrapper).toMatchSnapshot();
    });
});

import React from 'react';
import { shallow } from 'enzyme';
import ChildComponent from '../components/ChildComponent';
import moment from 'moment';

describe('<ChildComponent />', () => {
    let wrapper;

    beforeAll(() => {
        wrapper = shallow(<ChildComponent startDate={moment()} endDate={moment()}/>);
    });

    it('should render the component correctly', () => {
        expect(wrapper).toMatchSnapshot();
    });

    describe('when the the start date and end date are on the same day', () => {
        it('should print a the formatted start date', () => {
            expect(wrapper.text()).toEqual('mock format here');
        });
    });

    describe('when the start and end date are not on the same day', () => {
        it('should print the the end date from now', () => {
            expect(wrapper.text()).toEqual('mock from now here');
        });
    });
});

如何模拟 moment.js 库函数以使我的测试正常工作?

我正在尝试在 __mocks__ 文件夹中创建一个手动模拟文件,该文件将模拟两个测试套件的时刻库函数。我目前遇到的问题:

  1. 如何从模拟文件中模拟 moment() 构造函数以始终返回相同的日期,这样我的快照测试将始终通过?
  2. 如何模拟 .isSame().format().fromNow() 函数以始终返回相同的值,而不管当前时间如何?

到目前为止,我的以下测试文件破坏了我的所有测试。我正在关注文档here

const moment = require('moment');

function isSame() {
  return true;
}

function fromNow() {
  return 'Tomorrow at 12:00 pm'
}

function format() {
  return 'Sept 16th 19';
}

exports.isSame = isSame;
exports.fromNow = fromNow;
exports.format = format;

当我使用此文件时,我的组件中出现错误,提示 startDate 和 endDate 未定义。

【问题讨论】:

    标签: reactjs mocking jestjs enzyme


    【解决方案1】:

    我最终通过在 mocks 文件夹中创建手动模拟来解决此问题。关键是那一刻用moment.fn导出它的原型。

    import fixtures from '../__fixtures__/moment';
    
    const moment = require.requireActual('moment');
    
    // By default, the isSame function will always return true
    let isSame = true;
    
    moment.fn.isSame = () => isSame;
    moment.fn.calendar = () => fixtures.CALENDAR;
    moment.fn.fromNow = () => fixtures.FROM_NOW;
    
    // Since format is often called with a variety of format strings, we need to
    // differentiate how we are calling the function
    moment.fn.format = (format) => {
        switch (format) {
        case 'MMM Do YY':
            return fixtures.DATE;
        case 'H:mm a':
            return fixtures.TIME;
        case 'MMM Do YY H:mm a':
            return fixtures.DATETIME;
        default:
            return Error('Unsupported format in moment mock. Add case to __mocks__/moment.js');
        }
    };
    moment.duration.fn.humanize = () => fixtures.DURATION;
    
    // This function is added to moment's prototype in order for our tests to
    // change moment's isSame behaviour
    moment.fn.__isSame = (value) => { isSame = value; };
    
    // This resets the isSame behaviour back to default
    moment.fn.__reset = () => {
        moment.fn.isSame = () => true;
    };
    
    export default moment;
    

    Jest 在运行测试时自动加载此文件,然后我可以测试我的组件,例如:

    it('renders a moment duration', () => {
        expect(wrapper.text()).toEqual(fixtures.DURATION);
    });
    

    如果我需要改变 .isSame 函数的行为,我可以修改它:

    import moment from 'moment';
    
    beforeAll(() => {
        moment.fn.__isSame(false);
    });
    

    【讨论】:

      【解决方案2】:

      如果你使用 JEST 测试,我可以推荐你https://github.com/hustcc/jest-date-mock 然后你可以使用模拟当前日期

      advanceTo(new Date(2018, 5, 27, 0, 0, 0));
      

      测试的最佳实践是模拟固定日期并与结果进行比较

      【讨论】:

        猜你喜欢
        • 2020-08-22
        • 1970-01-01
        • 2021-04-18
        • 2018-09-12
        • 2016-04-28
        • 2020-03-23
        • 2019-01-30
        • 2021-11-26
        • 2018-02-13
        相关资源
        最近更新 更多