Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/414.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何测试未安装的React组件';依赖于setState的方法是什么?_Javascript_Reactjs_Testing_Jestjs - Fatal编程技术网

Javascript 如何测试未安装的React组件';依赖于setState的方法是什么?

Javascript 如何测试未安装的React组件';依赖于setState的方法是什么?,javascript,reactjs,testing,jestjs,Javascript,Reactjs,Testing,Jestjs,我已经实现了一个组件(用于打字培训应用程序),它可以在全局范围内跟踪按键,如下所示: class TrainerApp extends React.Component { constructor() { // ... this.handlePress = this.handlePress.bind(this); } handlePress(event) { const pressedKey = event.key;

我已经实现了一个组件(用于打字培训应用程序),它可以在全局范围内跟踪按键,如下所示:

class TrainerApp extends React.Component {
    constructor() {
        // ...
        this.handlePress = this.handlePress.bind(this);
    }
    handlePress(event) {
        const pressedKey = event.key;
        const task = this.state.task;
        const expectedKey = task.line[task.position];

        const pressedCorrectly = pressedKey == expectedKey;
        this.setState(prevState => {
            const newPosition = prevState.task.position +
                (pressedCorrectly ? 1 : 0);
            return {
                // ...prevState, not needed: https://reactjs.org/docs/state-and-lifecycle.html#state-updates-are-merged
                task: {
                    ...prevState.task,
                    position: newPosition,
                    mistakeAtCurrentPosition: !pressedCorrectly
                }
            }
        })
    }
    componentDidMount() {
        document.addEventListener(this.keyEventTypeToHandle,this.handlePress);
    }
    componentWillUnmount () {
        document.removeEventListener(this.keyEventTypeToHandle,this.handlePress);
    }
    ...
}
test('move to the next char on correct press',() => {

    const app = new TrainerApp();
    app.setState = jest.fn(function(handler) {
        this.state = handler(this.state);
    });
    app.state.task.line = 'abc';
    app.state.task.position = 0;
    const fakeEvent = { key: 'a' };

    app.handlePress(fakeEvent);

    expect(app.state.task.position).toBe(1);
});
class ExplorableTrainerApp extends TrainerApp {
    setState(handler) {
        this.state = handler(this.state);
    }
}
test('move to the next char on correct press',() => {

    const app = new ExplorableTrainerApp();
    app.state.task.line = 'abc';
    app.state.task.position = 0;
    const fakeEvent = { key: 'a' };

    app.handlePress(fakeEvent);

    expect(app.state.task.position).toBe(1);
});
我想用Jest编写一些单元测试。我最初的想法是:

describe('TrainerApp.handlePress should',() => {
    test('move to the next char on correct press',() => {

        const app = new TrainerApp();
        app.state.task.line = 'abc';
        app.state.task.position = 0;
        const fakeEvent = { key: 'a' };

        app.handlePress(fakeEvent);

        expect(app.state.task.position).toBe(1);
    });
    ...
});
但问题是
app.handlePress
依赖于
this.setState
的使用,该设置状态在组件尚未安装时未定义。当然,我可以这样修改
应用程序

class TrainerApp extends React.Component {
    constructor() {
        // ...
        this.handlePress = this.handlePress.bind(this);
    }
    handlePress(event) {
        const pressedKey = event.key;
        const task = this.state.task;
        const expectedKey = task.line[task.position];

        const pressedCorrectly = pressedKey == expectedKey;
        this.setState(prevState => {
            const newPosition = prevState.task.position +
                (pressedCorrectly ? 1 : 0);
            return {
                // ...prevState, not needed: https://reactjs.org/docs/state-and-lifecycle.html#state-updates-are-merged
                task: {
                    ...prevState.task,
                    position: newPosition,
                    mistakeAtCurrentPosition: !pressedCorrectly
                }
            }
        })
    }
    componentDidMount() {
        document.addEventListener(this.keyEventTypeToHandle,this.handlePress);
    }
    componentWillUnmount () {
        document.removeEventListener(this.keyEventTypeToHandle,this.handlePress);
    }
    ...
}
test('move to the next char on correct press',() => {

    const app = new TrainerApp();
    app.setState = jest.fn(function(handler) {
        this.state = handler(this.state);
    });
    app.state.task.line = 'abc';
    app.state.task.position = 0;
    const fakeEvent = { key: 'a' };

    app.handlePress(fakeEvent);

    expect(app.state.task.position).toBe(1);
});
class ExplorableTrainerApp extends TrainerApp {
    setState(handler) {
        this.state = handler(this.state);
    }
}
test('move to the next char on correct press',() => {

    const app = new ExplorableTrainerApp();
    app.state.task.line = 'abc';
    app.state.task.position = 0;
    const fakeEvent = { key: 'a' };

    app.handlePress(fakeEvent);

    expect(app.state.task.position).toBe(1);
});
甚至像这样:

class TrainerApp extends React.Component {
    constructor() {
        // ...
        this.handlePress = this.handlePress.bind(this);
    }
    handlePress(event) {
        const pressedKey = event.key;
        const task = this.state.task;
        const expectedKey = task.line[task.position];

        const pressedCorrectly = pressedKey == expectedKey;
        this.setState(prevState => {
            const newPosition = prevState.task.position +
                (pressedCorrectly ? 1 : 0);
            return {
                // ...prevState, not needed: https://reactjs.org/docs/state-and-lifecycle.html#state-updates-are-merged
                task: {
                    ...prevState.task,
                    position: newPosition,
                    mistakeAtCurrentPosition: !pressedCorrectly
                }
            }
        })
    }
    componentDidMount() {
        document.addEventListener(this.keyEventTypeToHandle,this.handlePress);
    }
    componentWillUnmount () {
        document.removeEventListener(this.keyEventTypeToHandle,this.handlePress);
    }
    ...
}
test('move to the next char on correct press',() => {

    const app = new TrainerApp();
    app.setState = jest.fn(function(handler) {
        this.state = handler(this.state);
    });
    app.state.task.line = 'abc';
    app.state.task.position = 0;
    const fakeEvent = { key: 'a' };

    app.handlePress(fakeEvent);

    expect(app.state.task.position).toBe(1);
});
class ExplorableTrainerApp extends TrainerApp {
    setState(handler) {
        this.state = handler(this.state);
    }
}
test('move to the next char on correct press',() => {

    const app = new ExplorableTrainerApp();
    app.state.task.line = 'abc';
    app.state.task.position = 0;
    const fakeEvent = { key: 'a' };

    app.handlePress(fakeEvent);

    expect(app.state.task.position).toBe(1);
});

但这似乎是一种非常脆弱的方法(这里我依赖于这样一个事实,即
.setState
是用函数参数调用的,而它可以用
newState
参数调用,因此我正在测试实现细节,而不仅仅是行为。有没有更可靠的方法来测试这一点?

有一些框架用于测试React组件,它们都是受欢迎且支持良好。

您需要实际安装组件才能访问这些方法。airbnb的“酶”与React配合得很好,因此基本上我们需要使用工具来安装组件以使
设置状态
正常工作;React不提供仅用于测试的简便方法,因此最好使用tes测试框架,对吗?您可以只在DOM中装载组件:
const-app=ReactDOM.render(,document.querySelector('.main');
,但是测试框架提供了一些方法,允许您方便地在树的深处查找组件。