如何使用Jest Mocks防止非确定性或其他变化的组件持续导致快照差异的发生

155 阅读2分钟

image.png

快照测试是很好的。我经常使用React,并经常使用Storybook来对我的组件进行视觉和快照测试。它可以帮助快速识别任何回归和不希望的行为,指出你的组件在渲染时与你上次运行测试套件时的不同。

非决定性或其他变化的组件的问题

快照差异有时是没有意义的。例如,如果你快照测试一个包含随机数生成器的组件,你会不断得到快照差异,而实际上没有任何变化。这些差异本质上是一种困扰--我们不希望一次又一次地批准它们。

一个具体的例子:当前的时间戳

比方说,我们的应用程序有一个告诉用户当前时间的部分。我的应用程序将是一个极端的例子,它将告诉用户精确到秒的时间。请注意,这是一个带有钩子的功能性React组件。如果你不理解代码,不用担心,我一会儿就会告诉你在浏览器中呈现的内容。

Timer.jsx

import React, { useState, useEffect } from 'react';

const getCurrentTimestamp = () => new Date().toLocaleTimeString();

export const Timer = () => {
  const [time, setTime] = useState(getCurrentTimestamp());
  useEffect(() => {
    let refresh = setInterval(() => {
      setTime(getCurrentTimestamp());
    }, 1000);
    return () => {
      clearInterval(refresh);
    };
  }, []);

  return <div>The time is {time}</div>;
};

如果我启动我的应用程序并在浏览器中加载它,我看到一个非常简单的动态时钟。

image.png

测试我们的时钟的快照

这是我的Timer 组件的一个非常简单的Storybook测试。

import React from 'react';
import { Timer } from '../timer';

export default {
  title: 'Components/Timer',
  component: Timer,
};

export const Default = () => <Timer />;

然而,每当我对这个组件进行快照测试时,它就会失败

image.png

每次我对该组件进行快照时,时间都会改变,所以快照当然会失败:我们每次都会得到不同的渲染。

修复这个问题:模拟出我们的动态组件

幸运的是,有一个非常简单的方法可以解决我们的问题在这个例子中,我们与故事书有关的快照是由一个配置文件驱动的,storybook.test.jsx 。在进行任何修改之前,这个配置文件看起来像这样。

import initStoryshots from '@storybook/addon-storyshots';
initStoryshots();

我们可以通过模拟从timer.jsx 文件中导入Timer 来修改这个文件!这样,在我们的快照测试中对该组件的任何使用将使用我们在这里提供的模拟,而不是实际的组件。

import React from 'react';
import initStoryshots from '@storybook/addon-storyshots';

jest.mock('../timer.tsx', () => ({
  Timer: () => <timer />,
}));

initStoryshots();

在这里,我们基本上告诉jest,不要为快照测试渲染我们的动态组件,只要继续渲染<timer /> 。这样,我们就不会被动态快照所困扰,但我们也能保证定时器在它应该呈现的时候呈现。

我们现在可以运行我们的快照测试了,并且不再被这些频繁变化的组件所困扰了