【问题标题】:Unit testing Vue composition functions单元测试 Vue 组合功能
【发布时间】:2022-02-05 00:45:50
【问题描述】:

我正在尝试编写一个获取数据的“钩子”(不完全清楚 Vue 中的这个词是什么,而是一个不呈现模板的状态函数)。 Hook 将异步数据解析器作为参数。 hook 本身非常简单,它只是将加载状态添加到返回 promise 的函数中。

import { ref, watch } from "vue";

export function useDataFetcher<T>(
  resolver: () => Promise<T>,
) {
  const isLoading = ref(false);
  const data = ref<T>();
  watch(resolver, () => {
    isLoading.value = true;
    resolver(...parameters)
      .then((fetchedData) => {
        data.value = fetchedData;
      })
      .finally(() => {
        isLoading.value = false;
      });
  });
  return {
    isLoading: isLoading.value,
    data,
    parameters,
  };
}

我正在尝试针对此函数编写测试,以确保 isLoading 方法正确更新:

import { useDataFetcher } from "./useDataFetcher";
test("While the fetcher is loading data, isLoading should be true", async () => {
  const promise = new Promise<void>((resolver) =>
    setTimeout(() => resolver(), 2000)
  );
  const { isLoading } = useDataFetcher(() => promise);
  expect(isLoading).toBeTruthy();
  await promise;

  expect(isLoading).toBeFalsy();
});

正如所写,此测试不起作用。我没有在互联网上看到很多关于在 Vue 中测试这些状态函数的信息。 有两个似乎相关的堆栈溢出问题: Is it possible to test a Vue 3 Composition library which uses inject without a wrapping component?

How to unit test standalone Vue composition

但这些似乎都不能完全解决我在这里的痒。

在 React 中,您可以使用 @testing-library/react-hooks 库来管理这些测试,这使得它变得非常简单。在我看来,我错过了await Vue.nextTick() 的效果。

那么,最后的问题是:测试这些不呈现模板的 Vue 钩子的最佳方法到底是什么?

【问题讨论】:

    标签: vue.js jestjs vuejs3 vue-composition-api


    【解决方案1】:

    所以,我最终为我的问题制定了一个解决方案并为它发布了一个 npm 模块:https://www.npmjs.com/package/vue-composable-function-tester。我希望得到有关解决方案的反馈。

    下面是一个例子:

    测试:

    it("Reacts to a resolving promise", async () => {
      const resolvedData = {
        hello: "world",
      };
      const promise = Promise.resolve(resolvedData);
      const composable = mountComposableFunction(() =>
        useAsynchronousLoader(() => promise)
      );
      await composable.nextTick();
      expect(composable.data.isLoading.value).toBe(true);
      await promise;
      await composable.nextTick();
      expect(composable.data.data.value).toStrictEqual(resolvedData);
      await composable.nextTick();
      expect(composable.data.isLoading.value).toBe(false);
    });
    

    实施:

    export function useAsynchronousLoader<T>(promiseCreator: () => Promise<T>) {
      const isLoading = ref(false);
      const data = ref<T>();
      const error = ref<object>();
      isLoading.value = true;
      promiseCreator()
        .then((newData) => {
          data.value = newData;
        })
        .catch((e) => {
          error.value = e;
        })
        .finally(() => {
          isLoading.value = false;
        });
      return {
        isLoading,
        data,
        error,
      };
    }
    

    编辑:改进的代码示例。

    【讨论】:

      【解决方案2】:

      您需要返回加载引用以保持反应性。

        return {
          isLoading,
          data,
          parameters,
        };
      

      通过 isLoading.value 你只传递当时的值并失去反应性

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-08-18
        • 2019-03-20
        • 2019-04-18
        • 2017-03-05
        • 2021-09-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多