4

我正在尝试以去抖方法测试 axios 调用,但如果我添加假计时器, moxios.wait() 总是会超时。如果去抖时间设置得足够小(例如 10 毫秒),则测试可以在没有时钟的情况下进行,但这无助于测试正确的去抖。我已经尝试过使用 Vue.nextTick 以及对 it() 进行异步回调,但我似乎只是进一步深入杂草。这里的正确方法是什么?

这是一个组件和一个测试,它显示了问题:

import Vue from 'vue'
import { mount } from 'vue-test-utils'
import axios from 'axios'
import moxios from 'moxios'
import _ from 'lodash'
import expect from 'expect'
import sinon from 'sinon'

let Debounced = Vue.component('Debounced',
    {
        template: `<div><button @click.prevent="fetch"></button></div>`,
        data() {
            return {
                data: {}
            }
        },
        methods: {
            fetch: _.debounce(async () => {
                let data = await axios.post('/test', {param: 'example'})
                this.data = data
            }, 100)
        }
    }
)

describe.only ('Test axios in debounce()', () => {
    let wrapper, clock

    beforeEach(() => {
        clock = sinon.useFakeTimers()
        moxios.install()
        wrapper = mount(Debounced)
    })

    afterEach(() => {
        moxios.uninstall()
        clock.restore()
    })

    it ('should send off a request when clicked', (done) => {
        // Given we set up axios to return something
        moxios.stubRequest('/test', {
            status: 200,
            response: []
        })

        // When the button is clicked
        wrapper.find('button').trigger('click')
        clock.tick(100)

        moxios.wait(() => {
            // It should have called axios with the right params
            let request = moxios.requests.mostRecent()
            expect(JSON.parse(request.config.data)).toEqual({param: 'example'})

            done()
        })
    })
})
4

1 回答 1

2

关于测试超时异常: moxios.wait依赖于,setTimeout但我们setTimeout用自定义 js 实现替换了我们的,为了使moxios.wait工作我们应该clock.tick(1)在等待调用之后调用。

    moxios.wait(() => {
        // It should have called axios with the right params
        let request = moxios.requests.mostRecent()
        expect(JSON.parse(request.config.data)).toEqual({param: 'example'})

        done()
    });
    clock.tick(1);

这将允许测试进入回调主体......但它会再次失败,出现request未定义的异常。

主要问题:问题是假定时器同步调用所有回调(不使用宏任务事件循环),但承诺仍然使用事件循环。

所以你的代码在任何 Promise "then" 被执行之前就结束了。当然,您可以将测试代码作为微任务推送以访问请求和响应数据,例如(使用await或将其包装为 then" 回调):

    wrapper.find('button').trigger('click');

    // debounced function called
    clock.tick(100);
    // next lines will be executed after an axios "then" callback where a request will be created.
    await Promise.resolve();


    // axios promise created, a request is added to moxios requests
    // next "then" is added to microtask event loop
    console.log("First assert");
    let request = moxios.requests.mostRecent()
    expect(JSON.parse(request.config.data)).toEqual({ param: 'example' });

    // next lines will be executed after promise "then" from fetch method
    await Promise.resolve();

    console.log("Second assert");
    expect(wrapper.vm.data.data).toEqual([]);
    done();

我为数据添加了另一个断言,以表明您的代码应该“等待”两个“then”回调:axios 内部“then”与您的请求创建和您的“then”来自fetch方法。如您所见,我删除了wait调用,因为如果您想等待 Promises,它实际上什么都不做。

是的,这是一个肮脏的黑客,与 axios 实现本身密切相关,但我没有更好的建议,首先我只是试图解释这个问题。

于 2019-06-13T23:02:44.957 回答