教程示例中的jest / react / typescript编译错误

时间:2016-12-15 17:19:43

标签: reactjs typescript intellij-idea webpack jestjs

我正在尝试使用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()

这种道具对象的类型{ [propName: string]: string }

是有道理的

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

3 个答案:

答案 0 :(得分:1)

我不确定为什么这对你有用 Link的道具没有onMouseEnter也没有onMouseLeave,而a的道具则来自Link.render

应该更像是:

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

...

tree._onMouseEnter();
...
tree._onMouseLeave();

答案 1 :(得分:0)

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

是的

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
            }
        );
    });
    // ...
});

答案 2 :(得分:0)

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