javascript – 如何在redux操作(或操作中分配的其他回调)的上下文中使用jest测试`image.onload`

我的问题是我正在尝试对函数进行单元测试,但无法弄清楚如何测试它的一部分.

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

1)使用图像URL检索json数据

2)将图像加载到Image实例并将其大小调度到reducer(使用Image.onload加载图像时异步)

3)将完成提取的调度发送给reducer

图像onload是异步发生的,所以当我尝试对它进行单元测试时,就不会调用它.而且,我不能只是嘲笑事物,因为图像实例是在函数内创建的……

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

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,
            });
        };
    };
}

请注意,最后一个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,
        );
    });

此测试虽然会失败,因为测试在调用image.onload回调之前完成.

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

解决方法:

经过一番调查,我找到了一个非常有趣的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 onl oad 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,
        );
    });

我在这里做的是使用define属性覆盖任何Image实例的setter. setter将继续像正常一样获取或设置,但也会保存设置为单元测试范围内的变量的值(在本例中为函数).之后,您可以在测试的验证步骤之前运行您捕获的功能.

陷阱
– 可配置需要设置
– 请注意,defineProperty是一个与defineProperties不同的函数
– 这在实际代码中是不好的做法.
– 记得使用原型

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

上一篇:javascript – Travis CI Jest Preset react-native not found


下一篇:javascript – 如何修复TypeError不是一个函数(使用Jest测试promise)