我如何模拟两个提取或一个Promise和一个提取?

时间:2018-06-08 14:35:34

标签: javascript reactjs jestjs fetch-api

我正在尝试测试loadAllProjects函数。

测试在.then()失败并出现错误:TypeError:无法读取属性'然后'未定义的

我也尝试过模拟getHeadersWithToken()的响应但是无法让它工作。

对此问题嗤之以鼻,并感谢任何帮助。

试验:

    it('should create SET_ALL_PROJECTS action when fetching projects', () => {
        fetch
            .once(JSON.stringify([{ access_token: "12345" }]))
            .once(JSON.stringify({ name: "x" }))

        const expectedActions = [
            { type: "SET_ALL_PROJECTS", json: { name: "x" } },
        ]

        store.dispatch(actions.loadAllProjects.apply())
            .then(() => {     // FAILS HERE
                expect(store.getActions()).toEqual(expectedActions)
            })

    });

代码:

    export const getHeadersWithToken = () => {
        return fetch("/.auth/me", requestOptions)
            .then(parseResponseAndHandleErrors)
            .then(json => {
                const header = 'Bearer ' + json[0].access_token
                const applicationJsonHeaders = getJsonHeaders(header)
                return applicationJsonHeaders
            })
            .catch( error=> {
                console.error(error)
            })
    }

    export const loadAllProjects = () => {
        return (dispatch) => {
            getHeadersWithToken()
                .then(applicationJsonHeaders => {
                    const requestOptions = {
                        method: 'GET',
                        headers: applicationJsonHeaders,
                    };
                    return fetch(process.env.REACT_APP_PROJECTS_API_URL + "/projects", requestOptions)
                        .then(parseResponseAndHandleErrors)
                        .then(json => {
                            dispatch(setAllProjects(json))})
                        .catch(error => {
                            console.error(error)
                            dispatch(failedToLoadProjects(error))
                        });
                })
        }
    }

测试中使用的商店:

    const store = mockStore(Map(
        {
            allProjects: Map({
            }),
            currentProject: Map({

                authenticationData: Map({

                })
            })
        })

    );

2 个答案:

答案 0 :(得分:0)

您正在使用哪种Redux中间件来处理异步内容?在创建要测试的商店时,请确保您设置了中间件。

因为我没有看到上面代码中的任何地方,我都会假设我们在这里没有使用该中间件。

由于loadAllProjects是一个高阶函数,所以我会这样做:

it('should create SET_ALL_PROJECTS action when fetching projects', (done) => {
    fetch
        .once(JSON.stringify([{ access_token: "12345" }]))
        .once(JSON.stringify({ name: "x" }))

    const expectedActions = [
        { type: "SET_ALL_PROJECTS", json: { name: "x" } },
    ]

    // Higher order function that returns a new function.
    const loadAllProjectsAsync = actions.loadAllProjects();

    // The function returned expects a dispatch from Redux as an argument.
    // It will do async work and when its done, it will call the provided dispatch.
    loadAllProjectsAsync(store.dispatch).then(() => {
       expect(store.getActions()).toEqual(expectedActions);
       done();
    })

});

您还需要修改loadAllProjects的代码,以便内部函数返回promise:

export const loadAllProjects = () => {
return (dispatch) => {

    // You will need to return the promise in order for the test to be able to call .then() on it.
    return getHeadersWithToken()
        .then(applicationJsonHeaders => {
            const requestOptions = {
                method: 'GET',
                headers: applicationJsonHeaders,
            };
            return fetch(process.env.REACT_APP_PROJECTS_API_URL + "/projects", requestOptions)
                .then(parseResponseAndHandleErrors)
                .then(json => {
                    dispatch(setAllProjects(json))})
                .catch(error => {
                    console.error(error)
                    dispatch(failedToLoadProjects(error))
                });
        })
}}

此外,如前所述,如果您正在测试异步内容,则必须告诉玩笑何时完成测试。通过让您的it调用将done作为参数,并在.then()

中验证结果之后,将该函数作为函数进行调用来实现。

这只是我的快速解决方案。上面的代码中可能仍然缺少某些东西或一些错误,但是您明白了。

让我知道您是否有任何后续问题?

答案 1 :(得分:0)

万一这对任何人都有用,并且为了确认Septastium的回答,我最终将代码更改为:

async getHeadersWithToken(requestType) {
    if (process.env.REACT_APP_RUNNING_LOCALLY==="true") {
        return {
            'Accept': 'application/json, text/plain, */*',
            'Content-Type': 'application/json'
        };
    }
    let result = await fetch("/.auth/me", this.requestOptions)
    let headers = result.json()
        .then( json => {
            const header = 'Bearer ' + json[0].access_token
            const applicationJsonHeaders = this.getJsonHeaders(header, requestType)
            return applicationJsonHeaders
        })
        .catch(error => {
            console.error(error)
        })
    return headers
}

export const loadAllProjects = () => {
    return async dispatch => {
        const authenticator = new Authenticator()
        let applicationJsonHeaders = await authenticator.getHeadersWithToken(constants.GET)
        let loggedInUser = await authenticator.getLoggedInUser()
        const requestOptions = {
            method: 'GET',
            headers: applicationJsonHeaders,
        };
        return await fetch(process.env.REACT_APP_PROJECTS_API_URL + "/projects", requestOptions)
            .then(response => {
                return parseResponseAndHandleErrors(response)
            })
            .then(json => dispatch(setAllProjects(json)))
            .then(()=> dispatch(setAuthenticationData(loggedInUser)))
            .catch(error => {
                console.error(error)
                return dispatch(failedToLoadProjects(error))
            });
    }
} 

和测试:

const checkActionsWereDispatched = async (expectedActions, actionCreator) => {
    const store = mockStore(Map(
        {
        }),
    );
    store.dispatch(await actionCreator.apply()).then(() => {
        expect(store.getActions()).toEqual(expectedActions)
    })
}

it('should create SET_ALL_PROJECTS action when fetching projects', async () => {
    fetch
        .once(JSON.stringify([{ access_token: "12345" }]))
        .once(JSON.stringify({ name: "x" }))
    const expectedActions = [
        { type: "SET_ALL_PROJECTS", json: { name: "x" } },
    ]
    checkActionsWereDispatched(expectedActions, actions.loadAllProjects)
});

如上所述,我认为Spetastium的测试版本比我的更容易阅读,他的文章here很有帮助。