jest.mock不变变量访问:__extends

时间:2018-08-29 19:14:32

标签: reactjs typescript jestjs

我正在将React组件库从JS转换为TS,并且jest.mock()遇到问题。

之前:

"react": "^15.6.1"
"jest": "20.0.4"
"enzyme": "^2.9.1"

CustomDate.js

...
import DatePicker from 'react-datepicker';
...
export default class CustomDate extends React.Component {
...
    render() {
        return (
            <div onChange={this.handleDivChange}>
                <DatePicker
...
                />
            </div>
        );
    }
}

CustomDate.test.js

...
import CustomDate from '../component/CustomDate';
import DatePicker from 'react-datepicker';

jest.mock('react-datepicker', () => {
    let React = require('react');
    return class DatePicker extends React.Component {
        render() {
            return (
                <div id='DatePicker'></div>
            );
        }
    };
});
...
    beforeEach(function () {
        customDate = mount(<CustomDate {...testProps}/>);
    });
...
    it('renders a DatePicker component', () => {
        console.log(customDate.find('div').at(0).html());   -> outputs <div><div id='DatePicker'></div></div>, not the react datepicker
        console.log(customDate.find('div').at(1).html());   -> outputs <div id='DatePicker'></div>, not the react datepicker
        expect(customDate.find(DatePicker).length).toBe(1);
    });

之后:

"react": "^16.4.2"
"typescript": "^2.9.2"
"jest": "^23.5.0"
"ts-jest": "^23.1.4"
"enzyme": "^3.5.0"
"enzyme-adapter-react-16": "^1.3.0"

CustomDate.tsx

...
import DatePicker from 'react-datepicker';
...
export default class CustomDate extends Component<CustomDateProps, CustomDateState> {
...
    render() {
        return (
            <div onChange={this.handleDivChange}>
                <DatePicker
...
                />
            </div>
        );
    }
}

CustomDate.test.tsx

...
import CustomDate from '../component/CustomDate';
import DatePicker from 'react-datepicker';

jest.mock('react-datepicker', () => {
    let React = require('react');
    return class DatePicker extends React.Component {
        render() {
            return (
                <div id='DatePicker'></div>
            );
        }
    };
});
...
    beforeEach(function () {
        customDate = mount(<CustomDate {...testProps}/>);
    });
...
    it('renders a DatePicker component', () => {
        expect(customDate.find(DatePicker).length).toBe(1);
    });

运行测试时,我收到以下消息:

 CustomDate.test.tsx: babel-plugin-jest-hoist: The module factory of `jest.mock()` is not allowed to reference any out-of-scope variable
s.
    Invalid variable access: __extends
...
    Note: This is a precaution to guard against uninitialized mock variables. If it is ensured that the mock is required lazily, variable names prefixed with `mock` are permitted.

我花了一天时间尝试不同的事情。有些人摆脱了错误,但并没有真正嘲笑DatePicker。我要放松一下。

任何帮助将不胜感激。

更新

已编译的测试文件:

"use strict";
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    }
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
exports.__esModule = true;
var React = require("react");
var mockDatePicker = /** @class */ (function (_super) {
    __extends(mockDatePicker, _super);
    function mockDatePicker() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    mockDatePicker.prototype.render = function () {
        return React.createElement("div", { id: "DatePicker1" });
    };
    return mockDatePicker;
}(React.Component));
jest.mock('react-datepicker', function () { return mockDatePicker; });

2 个答案:

答案 0 :(得分:0)

当您使用带有某些代码的转译器(例如TypeScript)时,通常能够查看实际生成的代码,以更好地理解为什么会看到此类错误。例如,如果我使用您的存根DatePicker类并用tsc进行编译,则会得到以下内容:

"use strict";
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var React = require("react");
var DatePicker = /** @class */ (function (_super) {
    __extends(DatePicker, _super);
    function DatePicker() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    DatePicker.prototype.render = function () {
        return (React.createElement("div", { id: 'DatePicker' }));
    };
    return DatePicker;
}(React.Component));

在这里,您可以看到__extends是TypeScript定义的函数,并放置在“ __extends”变量中。这已经超出了范围(请参阅您所发布的错误),因为jest将所有对jest.mock的调用移至文件顶部(在babel的帮助下)。

一种解决方案是在要设置模拟的闭包之外定义模拟类。例如:

import * as React from "react";
class MockDatePicker extends React.Component {
   // ...
}

jest.mock("react-datepicker", () => MockDatePicker);

答案 1 :(得分:0)

我发现了另一种模拟react-datepicker的方法:

CustomDate.test.tsx

jest.mock('react-datepicker', 
    () => require.requireActual('../test/mocks/DatePickerMock').default());

DatePickerMock.tsx

import * as React from 'react';

export class DatePicker extends React.Component {
    render() {
        return <div id="DatePicker"/>;
    }
}

export default DatePicker;