首页 > 解决方案 > 使用 toJSON 或不使用 Jest 进行快照测试

问题描述

我是 React 新手,我正在测试我的组件。在实施快照测试时,我发现了以下两种方法:

方法一

import React from 'react'
import renderer from 'react-test-renderer'
import Projects from './Projects'

it('renders Projects component properly', () => {
  const tree = renderer.create(<Projects />)
  expect(tree).toMatchSnapshot()
})

方法二

import React from 'react'
import renderer from 'react-test-renderer'
import Projects from './Projects'

it('renders Projects component properly', () => {
  const component = renderer.create(<Projects />)
  const tree = component.toJSON()
  expect(tree).toMatchSnapshot()
})

调用toJSON组件重要吗(方法 2)还是可以直接将其传递给检查toMatchSnapshot(方法 1)?有人可以解释一下两种方法在性能方面的区别吗?

标签: javascriptreactjsjestjs

解决方案


TL;博士

toMatchSnapshot使用 matcher时toJSON,在传递给的对象上调用expect. 它是某种检查链的一部分,对于绝大多数实际情况,性能影响可能可以忽略不计。我建议toJSON只遵循“显式优于隐式”的原则以及内在行为可能会发生变化的事实。

解释

匹配器使用序列对象的SnapshotStatesmatch方法。只需使用一组插件调用漂亮格式。serialize

这是pretty-format的入口点,我在那里添加了评论:

function prettyFormat(
  val: unknown,
  options?: PrettyFormat.OptionsReceived,
): string {
  if (options) {
    validateOptions(options);
    if (options.plugins) {
      const plugin = findPlugin(options.plugins, val);
      /* When val is a result of `toJSON` call 
         it has a $$typeof: Symbol.for('react.test.json') field so  
         it is handled by ReactTestComponent plugin in this point */
      if (plugin !== null) {
        return printPlugin(plugin, val, getConfig(options), '', 0, []);
      }
    }
  }

  // When `toJSON` is not called `printBasicValue` is invoked but is it pointless
  const basicResult = printBasicValue(
    val,
    getPrintFunctionName(options),
    getEscapeRegex(options),
    getEscapeString(options),
  );
  if (basicResult !== null) {
    return basicResult;
  }

  return printComplexValue(val, getConfig(options), '', 0, []);
}

printBasicValue只需执行一组检查,对于一个对象,所有检查都失败,因此printComplexValue轮到它。这是一个.toJSON()被调用的片段。

  if (
    config.callToJSON &&
    !hitMaxDepth &&
    val.toJSON &&
    typeof val.toJSON === 'function' &&
    !hasCalledToJSON
  ) {
    return printer(val.toJSON(), config, indentation, depth, refs, true);
  }

printer找到一个插件并在一开始就调用它,所以没关系。

  const plugin = findPlugin(config.plugins, val);
  if (plugin !== null) {
    return printPlugin(plugin, val, config, indentation, depth, refs);
  }

您可以注意到,toJSON通过设置配置选项或其他一些我认为对于快照情况无关紧要的条件,调用可能会被禁用,但仍然如此。


推荐阅读