我正在尝试使用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 }
有什么我可以包含跳过那些警告/错误消息吗?
答案 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