如何在Redux动作(或该动作中分配的其他回调)的上下文中使用Jest测试`image.onload`

Thi*_*obo 4 javascript unit-testing jest react-redux

我的问题是我试图对某个功能进行单元测试,但无法弄清楚如何测试其中的一部分。

这是一个react / redux操作,它执行以下操作:

1)使用图像网址检索json数据

2)将图像加载到Image实例中,并将其大小分派给reducer(使用Image.onload加载图像时异步)

3)派遣完成到减速机的提取

图片加载是异步发生的,因此当我尝试进行单元测试时,它不会被调用。而且,我不能只是模拟一下,因为图像实例是在函数内创建的。

这是我要测试的代码(删除了一些检查,分支逻辑和内容):

export function fetchInsuranceCardPhoto() {
    return dispatch => {
        dispatch(requestingInsuranceCardPhoto());
        return fetch(`${api}`,
            {
                headers: {},
                credentials: 'same-origin',
                method: 'GET',
            })
            .then(response => {
                switch (response.status) {
                    case 200:
                        return response.json()
                            .then(json => {
                                dispatch(receivedInsuranceCardPhoto(json));
                            })
                }
            });
    };
}

function receivedInsuranceCardPhoto(json) {
    return dispatch => {
        const insuranceCardFrontImg = json.insuranceCardData.url_front;
        const insuranceCardBackImg = json.insuranceCardData.url_back;

        if (insuranceCardFrontImg) {
            dispatch(storeImageSize(insuranceCardFrontImg, 'insuranceCardFront'));
        }

        return dispatch(receivedInsuranceCardPhotoSuccess(json));
    };
}

function receivedInsuranceCardPhotoSuccess(json) {
    const insuranceCardFrontImg = json.insuranceCardData.url_front;
    const insuranceCardBackImg = json.insuranceCardData.url_back;
    const insuranceCardId = json.insuranceCardData.id;

    return {
        type: RECEIVED_INSURANCE_CARD_PHOTO,
        insuranceCardFrontImg,
        insuranceCardBackImg,
        insuranceCardId,
    };
}

function storeImageSize(imgSrc, side) {
    return dispatch => {
        const img = new Image();
        img.src = imgSrc;
        img.onload = () => {
            return dispatch({
                type: STORE_CARD_IMAGE_SIZE,
                side,
                width: img.naturalWidth,
                height: img.naturalHeight,
            });
        };
    };
}
Run Code Online (Sandbox Code Playgroud)

注意在最后一个storeImageSize私有函数中,如何创建Image实例和分配给函数的image.onload。

现在这是我的测试:

it('triggers RECEIVED_INSURANCE_CARD_PHOTO when 200 returned without data', async () => {
        givenAPICallSucceedsWithData();

        await store.dispatch(fetchInsuranceCardPhoto());

        expectActionsToHaveBeenTriggered(
            REQUESTING_INSURANCE_CARD_PHOTO,
            RECEIVED_INSURANCE_CARD_PHOTO,
            STORE_CARD_IMAGE_SIZE,
        );
    });
Run Code Online (Sandbox Code Playgroud)

但是此测试将失败,因为该测试在image.onload调用回调之前完成。

如何强制image.onload调用回调,以便测试是否可以广播`STORE_CARD_IMAGE_SIZE操作?

Thi*_*obo 7

经过一番调查,我发现了一个非常有趣的javascript函数,可以解决我的问题。

它是这样的:https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

这是我过去Object.defineProperty(...)解决问题的方式:

describe('fetchInsuranceCardPhoto', () => {
    let imageOnload = null;


    /** Override Image global to save onload setting here so that I can trigger it manually in my test */
    function trackImageOnload() {
        Object.defineProperty(Image.prototype, 'onload', {
            get: function () {
                return this._onload;
            },
            set: function (fn) {
                imageOnload = fn;
                this._onload = fn;
            },
        });
    }

    it('triggers RECEIVED_INSURANCE_CARD_PHOTO when 200 returned with data', async () => {
        trackImageOnload();
        givenAPICallSucceedsWithData();

        await store.dispatch(fetchInsuranceCardPhoto());
        imageOnload();

        expectActionsToHaveBeenTriggered(
            REQUESTING_INSURANCE_CARD_PHOTO,
            RECEIVED_INSURANCE_CARD_PHOTO,
            STORE_CARD_IMAGE_SIZE,
        );
    });
Run Code Online (Sandbox Code Playgroud)

我在这里所做的是使用define属性覆盖的任何实例的setter Image。设置器将继续正常进行获取或设置,但还将保存在单元测试范围内设置为变量的值(在这种情况下为函数)。之后,您可以运行在测试的验证步骤之前捕获的功能。

陷阱 -需要设置可配置-注意defineProperty与以下功能不同defineProperties -这在实际代码中是不好的做法。-记得使用原型

希望这篇文章可以帮助有需要的开发者!

  • 我修改了您的解决方案,以模拟src的设置程序,该设置对于测试错误和负载条件都非常有效。我的解决方案(在其他人的问题中)可以在这里找到:/sf/answers/3444303551/ (3认同)