解决 Enzyme 在 React v16.4 中的一些问题

阅读时长 10 分钟读完

前言

Enzyme 是 React 测试工具库中的重要成员,它具备了形如 jQuery 的 API,使得 React 组件的测试变得更加简单和可读性更高。但是,随着 React 不断更新迭代,Enzyme 也遇到了一些针对 React v16.4 的问题。

本篇文章主要介绍了通过一些基本的调整和技巧,解决 Enzyme 在 React v16.4 中出现的一些问题的方法。

##问题描述

React v16.4 以前的版本中,虚拟 DOM 的渲染是同步的,但是在 React v16.4 之后,渲染虚拟 DOM 变成了异步的。这使得 Enzyme 在渲染 React 组件时出现了一些问题。

具体来说,主要体现在 Enzyme 的渲染和断言过程中。

渲染问题

在 React v16.4 中,Enzyme 中的 shallow()mount() 函数中,虚拟 DOM 渲染变成了异步的。

这意味着,在 Enzyme 中,与 React 的生命周期函数一起工作的模拟时机就会发生变化。在这种情况下,这些模拟需要等待 React 执行完生命周期方法,才能在 Enzyme 中进行更进一步的断言。

例如,我们以一个简单的 React Axios 应用为例:

-- -------------------- ---- -------
------ ------ - --------- - ---- --------
------ ----- ---- --------

------ ----- -------- ------- --------- -
  ----------- ------- -
    -------------
    ---------- - -
      ----- ---
      -------- ----
    --
  -

  ----------------- -- -
    ---------------------------------------------------------
      --------- -- -
        ---------------
          ----- ---------
          -------- -----
        ---
      ---
  -

  ------ -- -
    ----- - -------- ---- - - -----------
    ------ -
      -----
        -------- - ------------ - --------------- -------------------- ----------------- ------------------------
      ------
    --
  -
-

我们可以使用 shallow() 把 AxiosGet 组件浅渲染一下,然后根据状态及加载情况来进行断言:

-- -------------------- ---- -------
------ ----- ---- --------
------ - ------- - ---- ---------
------ - -------- - ---- -------------

--------------- ---- ------- -- -- -
  ----------- ----- ------ -- -- -
    ----- ------- - ----------------- ----
    -----------------------------------------------

    ------------- -- -
      --------------------------------------- ------- ----------- --- ------ -------------
    -- ------
  ---
---

该测试不会通过,因为在 Enzyme 进行断言之前,由于虚拟 DOM 的异步渲染,Axios 请求还未完成,组件还在等待返回。

断言问题

在 React v16.4 中,Enzyme 中的 setState() 函数也变成了异步的。这意味着,在 setState() 之后进行的断言可能会出现一些问题,因为在最后更新之前,断言会在组件更新之前触发。

例如,我们以一个非常简单的 React 组件为例:

-- -------------------- ---- -------
------ ------ - --------- - ---- --------

----- ------- ------- --------- -
  ----------- ------- -
    -------------
    ---------- - - ------ - --
  -

  -------------- - -- -- -
    --------------- ------ ---------------- - - ---
  --

  ------ -- -
    ----- - ----- - - -----------
    ------ -
      ---- ------------------------------
        --- ----------------------------------------------
        ------- ---------------------------- ----------------------------------------
      ------
    --
  -
-

------ ------- --------

我们使用 mount() 将组件装载到虚拟 DOM 中,并对其进行交互和断言:

-- -------------------- ---- -------
------ ----- ---- --------
------ - ----- - ---- ---------
------ ------- ---- ------------

----------------- ---- ------- -- -- -
  --- --------
  ------------- -- -
    ------- - -------------- ----
  ---

  ------------ -- -
    ------------------
  ---

  ------------- ------ ------ ------- -------- -- -- -
    ----- ------- - ------------------------------------------------
    -------------------------------
  ---

  --------------- ------ ------ -------- --- --------- -- -- -
    ----- ------ - -----------------------------------------------
    ----- ------- - ----------------------------------------------
    ------------------------------------
    -------------------------
    ------------------------------------
  ---
---

我们会发现,这个测试不会通过,因为启动检查和 Enzyme 状态更新之间的时间差异。当我们模拟点击增量按钮时,执行了 setState(),而不是直接修改状态,所以断言错误地把旧状态与增量相加,而不是新状态。

解决方法

渲染问题

在工程项目中,我们可以尝试创建一个 async 函数。这个函数将会在传入了一个 React 组件的 Promise 上进行解析、解包和断言。将这个函数封装用到底层的 requestAnimationFrame 中,就可以使得每一次组件状态变化都能适当地等待。

-- -------------------- ---- -------
-- ------------

------ ----- -------- --- --------- -
  ----- ------------------
  -----------------
-

------ ----- -------- ------------------ --------- ------ -
  ----- -------------
  -- ------- -
    --------
  -
-

现在我们可以使用这个 testAsyncComponent 函数来解决异步渲染测试的问题:

-- -------------------- ---- -------
------ ----- ---- --------
------ - ------- - ---- ---------
------ - -------- - ---- -------------
------ - ------------------ - ---- --------------

--------------- ---- ------- -- -- -
  ----------- ----- ------ ----- -- -- -
    ----- ------- - ----- ----------------- ----
    -----------------------------------------------
    ----- -------------
    --------------------------------------- ------- ----------- --- ------ -------------
  ---
---

断言问题

在断言方案中,我们可以在组件 mount 后,通过组件实例对 setState() 进行修改。这将为 Enzyme 和 React 生命周期函数提供相同的上下文,使得它们同步化,从而解决了我们遇到的问题。

-- -------------------- ---- -------
------ ----- ---- --------
------ - ----- - ---- ---------
------ ------- ---- ------------

----------------- ---- ------- -- -- -
  --- --------
  ------------- -- -
    ------- - -------------- ----
  ---

  ------------ -- -
    ------------------
  ---

  ------------- ------ ------ ------- -------- -- -- -
    ----- ------- - ------------------------------------------------
    -------------------------------
  ---

  --------------- ------ ------ -------- --- --------- -- -- -
    ----- ------ - -----------------------------------------------
    ---------------------------------------
    -------------------------
    ---------------------------------------
  ---
---

在这个示例中,我们使用了 mount(),因为它与 React 生命周期进行更紧密的集成。

结论

通过尝试针对 Enzyme 和 React v16.4 的不同工作方式进行微调或使用特殊技巧,可以解决许多 Enzyme 在渲染和断言时出现的问题。

使用 async 和 Enzyme 的 update() 函数结合使用,我们可以解决 Enzyme 中异步渲染的测试问题。同时,在断言状态更新方面,可以尝试直接修改实例的 state 状态,避免 Enzyme 状态更新之间的时间差异。

这些方法对 Enzyme 或 React 的工作方式不是理解,而是一个真正的经验问题。使用上述方法可以帮助开发者在 Enzyme 和 React v16.4 的情况下高效地构建和测试组件。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67186a8ead1e889fe22ae99a

纠错
反馈