【问题标题】:jest/react/typescript compilation error in tutorial's example教程示例中的 jest/react/typescript 编译错误
【发布时间】:2017-05-01 09:26:51
【问题描述】:

我正在尝试使用 Jest、React 和 Typescript 从Jest Tutorial Page 启动基本示例

Link.tsx

import * as React from 'react';

const STATUS = {
    NORMAL: 'normal',
    HOVERED: 'hovered',
};

interface theProps {
    page:string
}

export default class Link extends React.Component<theProps,any> {

    constructor(props) {
        super(props);

        this._onMouseEnter = this._onMouseEnter.bind(this);
        this._onMouseLeave = this._onMouseLeave.bind(this);

        this.state = {
            class: STATUS.NORMAL,
        };
    }

    _onMouseEnter() {
        this.setState({class: STATUS.HOVERED});
    }

    _onMouseLeave() {
        this.setState({class: STATUS.NORMAL});
    }

    render() {
        return (
            <a
                className={this.state.class}
                href={this.props.page || '#'}
                onMouseEnter={this._onMouseEnter}
                onMouseLeave={this._onMouseLeave}>
                {this.props.children}
            </a>
        );
    }

}

test.tsx

import * as React from 'react';
import Link from '../app/Link';
import * as renderer from 'react-test-renderer';

it('Link changes the class when hovered', () => {
    const component = renderer.create(
        <Link page="http://www.facebook.com">Facebook</Link>
    );
    let tree = component.toJSON();
    expect(tree).toMatchSnapshot();

    // manually trigger the callback
    tree.props.onMouseEnter();
    // re-renderingf
    tree = component.toJSON();
    expect(tree).toMatchSnapshot();

    // manually trigger the callback
    tree.props.onMouseLeave();
    // re-rendering
    tree = component.toJSON();
    expect(tree).toMatchSnapshot();
});

但即使使用jest 的测试运行良好,Webpack 和 IntelliJ 都抱怨tree.props.onMouseEnter(); 行: Unresolved function or method onMouseLeave()

这是有道理的,因为 props 对象的类型为 { [propName: string]: string }

有什么可以包括跳过那些警告/错误消息的吗?

【问题讨论】:

    标签: reactjs typescript intellij-idea webpack jestjs


    【解决方案1】:

    我不确定为什么这对你有用。
    Link 的 props 没有 onMouseEnter 也没有 onMouseLeave,是从 Link.render 返回的 a 有它。

    应该更像:

    const component = renderer.create(
        <Link page="http://www.facebook.com">Facebook</Link>
    ) as Link;
    
    ...
    
    tree._onMouseEnter();
    ...
    tree._onMouseLeave();
    

    【讨论】:

    • 使用此解决方案,测试不再编译。使用 'link._onMouseEnter();',IntelliJ 很高兴,但测试仍然无法编译。我也认为它首先起作用很奇怪......
    • TypeError: tree._onMouseEnter 不是函数
    【解决方案2】:

    “有什么可以包括跳过那些警告/错误消息的吗?”

    是的

    let tree: any = component.toJSON();
    

    let tree = Component.toJSON();
    let props = tree.props as any;
    

    或者这可能足够接近吗? ...

    import * as React from "react";
    import * as renderer from "react-test-renderer";
    import * as TestUtil from "react-addons-test-utils";
    
    interface HTMLProps extends React.HTMLProps<any> {
        [key: string]: any;
    }
    
    interface ITree /* reimplements ReactTestRendererJSON */ {
        type: string;
        // I'm not sure about this but ... is it close enought ? 
        props: HTMLProps;
        children: null | Array<string | ITree>;
        $$typeof?: any;
    }
    
    function isTree(x: string | ITree): x is ITree {
        return x && (typeof x !== "string")
            && x.type !== "undefined"
            && typeof x.children !== "undefined" // .. or  === ("string" || "array"
            && typeof x.props !== "undefined"; // === "object"
    }
    
    function isString(x: any): x is string {
        return typeof x === "string";
    }
    
    describe("react-test-renderer", () => {
    
        it("Should/Could be typed?", () => {
    
            let All = (props: any) =>
                (<div {...props.divProps}>
                    Hello1
                    <span {...props.spanProps}>
                        Hello2
                        <a {...props.aProps}>
                            Hello3
                        </a>
                    </span>
                </div>);
    
            const X3 = (props?: any) => {
                return <All {...props}></All>;
            }
    
            const X2 = (props?: any) => {
                return <X3 {...props} />;
            };
    
            const X1 = (props?: any) => {
                return <X2 {...props} />;
            };
    
            let result = {
                onDrag: false,
                onDrop: false,
                onMouseEnter: false
            };
    
            let onDrag = () => result.onDrag = true;
            let onDrop = () => result.onDrop = true;
            let onMouseEnter = () => result.onMouseEnter = true;
    
            let _render /*: ReactTestInstance*/ = renderer.create(X1({
                divProps: {
                    onDrag
                },
                spanProps: {
                    onDrop
                },
                aProps: {
                    onMouseEnter
                }
            }));
    
            // 1st Rendered component its a Div
            let divTree = _render.toJSON() as ITree;
    
            // is Not an Element
            expect(TestUtil.isDOMComponent(divTree as any))
                .toBeFalsy();
            // is Not a Component
            expect(TestUtil.isCompositeComponent(divTree as any))
                .toBeFalsy();
            // is a Tree 
            expect(isTree(divTree))
                .toBeTruthy();
    
            // tree.props = 1st rendered DOMElement props , in this case a <div/>
            expect(divTree.type).toEqual("div");
            // not created 
            expect(divTree.props.accept).toBeUndefined();
            // should be there, beacuse of divProps
            expect(typeof divTree.props.onDrag).toEqual("function");
    
            //  TODO: ReactTestRenderer.js => Symbol['for']('react.test.json')
            // expect(tree.$$typeof).toBe("?");
    
            // trigger !
            divTree.props.onDrag(null);
    
            // Children ... 
            expect(divTree.children.length).toEqual(2);
    
            // String children 
            {
                let text = divTree.children.filter(isString)[0];
                if (!isString(text)) { throw "Never"; }
                expect(text).toEqual("Hello1");
            }
    
            // For <Span/>
            let spanTree = divTree.children.filter(isTree)[0];
    
            if (!isTree(spanTree)) {
                // make peace with the compiler ... 
                throw "never";
            }
    
            expect(isTree(spanTree)).toBeTruthy();
            expect(spanTree.type).toEqual("span");
            // String children 
            {
                let text = spanTree.children.filter(isString)[0];
                if (!isString(text)) { throw "Never"; }
                expect(text).toEqual("Hello2");
            }
    
            // trigger, [div][span onDrop]
            spanTree.props.onDrop(null);
    
            // For <A/>
            let aTree = spanTree.children.filter(isTree)[0];
            expect(isTree(aTree)).toBeTruthy();
            if (!isTree(aTree)) {
                // make peace with the compiler 
                // ...Its a ITree 
                throw "never";
            }
    
            expect(aTree.type).toEqual("a");
            aTree.props.onMouseEnter(null);
            let text = aTree.children.filter(isString)[0];
            if (!isString(text)) { throw "Never"; }
            expect(text).toEqual("Hello3");
    
    
            expect(result).toEqual(
                {
                    onDrag: true,
                    onDrop: true,
                    onMouseEnter: true
                }
            );
        });
        // ...
    });
    

    【讨论】:

    • 输入“任何”使其工作。感觉很脏,我仍然对那个“tree.props.onMouseEnter”感到困惑......
    • 是的,并且我对 tree.props 的 React.HTMLProps 接口的使用非常笨拙且具有误导性,但它正是我期望找到/发现的那种;我从练习中学到的是,当调用/创建组件/元素时,道具将被“实现”的道具填充,这样你就可以测试它的存在,触发它的处理程序,树/树项目也将只填充 DOM 元素,或字符串......它的孩子“内部元素”应该在“treeItem”孩子上找到,所以可以“查询?”结果。
    • 如果(存在这样的功能)我们可以在伪 sqlx 中查询它:“from tree.children select item where item.type == 'a' and item.props.href == '#HOME '" 或者 injsLike: expect( tree.children .ofType() .find(x=> x.type === 'a' && x.props.href == '#HOME') ).toBeSomething( );
    【解决方案3】:

    2019.09.15

    依赖关系:

    "react": "^16.9.0",
    "react-dom": "^16.9.0",
    "react-test-renderer": "^16.9.0",
    "jest": "^24.8.0",
    "ts-jest": "^24.0.2",
    "tslint": "^5.18.0",
    "typescript": "^3.5.3"
    

    下面的例子对我有用。

    import React from 'react';
    
    enum STATUS {
      HOVERED = 'hovered',
      NORMAL = 'normal'
    }
    
    interface ILinkState {
      class: STATUS;
    }
    
    export default class Link extends React.Component<any, ILinkState> {
      constructor(props) {
        super(props);
    
        this._onMouseEnter = this._onMouseEnter.bind(this);
        this._onMouseLeave = this._onMouseLeave.bind(this);
    
        this.state = {
          class: STATUS.NORMAL
        };
      }
    
      public render() {
        return (
          <a
            className={this.state.class}
            href={this.props.page || '#'}
            onMouseEnter={this._onMouseEnter}
            onMouseLeave={this._onMouseLeave}>
            {this.props.children}
          </a>
        );
      }
      private _onMouseEnter() {
        this.setState({ class: STATUS.HOVERED });
      }
    
      private _onMouseLeave() {
        this.setState({ class: STATUS.NORMAL });
      }
    }
    
    

    快照测试:

    import React from 'react';
    import Link from './';
    import renderer, { ReactTestRendererJSON } from 'react-test-renderer';
    
    test('Link changes the class when hovered', () => {
      const component = renderer.create(<Link page="http://www.facebook.com">Facebook</Link>);
      let tree: ReactTestRendererJSON | null = component.toJSON();
      expect(tree).toMatchSnapshot();
    
      if (tree) {
        // manually trigger the callback
        tree.props.onMouseEnter();
      }
      // re-rendering
      tree = component.toJSON();
      expect(tree).toMatchSnapshot();
    
      if (tree) {
        // manually trigger the callback
        tree.props.onMouseLeave();
      }
      // re-rendering
      tree = component.toJSON();
      expect(tree).toMatchSnapshot();
    });
    
    

    使用覆盖率报告进行快照测试:

     PASS  src/react-test-renderer-examples/01-quick-start/index.spec.tsx
      ✓ Link changes the class when hovered (32ms)
    
    -----------|----------|----------|----------|----------|-------------------|
    File       |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
    -----------|----------|----------|----------|----------|-------------------|
    All files  |      100 |    83.33 |      100 |      100 |                   |
     index.tsx |      100 |    83.33 |      100 |      100 |                28 |
    -----------|----------|----------|----------|----------|-------------------|
    Test Suites: 1 passed, 1 total
    Tests:       1 passed, 1 total
    Snapshots:   3 passed, 3 total
    Time:        3.614s, estimated 5s
    

    【讨论】:

      猜你喜欢
      • 2018-09-19
      • 1970-01-01
      • 2020-02-10
      • 2023-03-06
      • 2013-08-03
      • 1970-01-01
      • 1970-01-01
      • 2019-10-14
      • 1970-01-01
      相关资源
      最近更新 更多