在测试中禁用React的CSSTransitionGroup

12

我正在使用CSSTransitionGroup来在元素出现或离开DOM时进行动画处理。它运行良好。

现在,我想对该组件进行单元测试。我创建了一个临时的DOM节点并将其附加到<body>上,然后将我的组件渲染到其中,然后执行一些操作。结果,我期望一个子DOM节点消失。

问题: 动画类被应用,并且组件会一直保留在DOM中,直到CSS动画结束。这意味着我的测试也应该等待几百毫秒,然后才能断言该元素是否已经消失。但我不能这样做——我希望我的测试尽可能快速,因为这些是单元测试。

问题: 有没有一种方法可以在不添加额外选项的情况下禁用CSS过渡效果?

我尝试过的: 单元测试本身可以正常工作。我可以通过向组件传递一个参数来摆脱动画效果,使其不使用CSSTransitionGroup。所以最坏的情况是,我会这样做。但我正在寻找更好的解决方案。

我还可以断言元素上存在“-enter”/“-enter-active”/“-leave”/“-leave-active”类。虽然这种方法似乎有些hacky,因为我可以想象到一种情况,在该元素上应用了这些类,但元素仍然留在DOM中。我不想采用这种方法。


1
你可以模拟组件。如果你正在使用Jest,你可以使用ReactTestUtils.mockComponent。我不会费心直接测试CSSTransitionGroup的功能。 - Aaron Beall
在运行测试时,尝试使用Monkey Patching React组件,然后在那里禁用CSSTransitionGroup。 - Shining Love Star
最终我还是这么做了,@AdamGoldman。你提醒我应该在这里回答自己的问题。 - kamituel
6个回答

8

4
只使用jest时,它也能正常工作。 - Lisandro
2
非常简单,易上手! - Neurotransmitter

5

使用Jest,这是我想出的解决方案。我模拟了Transition组件。由于我的导入看起来像这样:import {Transition} from 'react-transition-group',所以我创建了以下内容:

根据我的jest配置,任何在__mocks__文件夹中找到的内容都将被用来代替任何导入。

__mocks__/react-transition-group/index.js

import Transition from './Transition'

export { Transition }
//more exports to come as I use other parts of react-transition-group

__mocks__/react-transition-group/Transition.js:

import React from 'react'

export default (props) => (
  <div>
    {props.in ? props.children() : null}
  </div>
)

这样,孩子们会立即显示出来 - "Transition" 已经基本上被禁用了。

** 这适用于 react-transition-group 的版本 v2.4.0


2
我相信使用proxyquire(在基于browserify的构建中使用proxyquireify)有一种更简洁的解决方案。这受到之前答案的启发。 ./stubs/react_css_transition_group.js:
const { createElement: el, Component } = require('react')

class ReactCSSTransitionGroup extends Component {
  constructor(props) {
    super(props)
  }

  render() {
    const { children, component } = this.props

    return el(component, null, children)
  }
}

ReactCSSTransitionGroup.defaultProps = {
  component: 'div'
}

module.exports = ReactCSSTransitionGroup

./foo_test.js:

const test = require('tape')
const { mount } = require('enzyme')
const { createElement: el } = require('react')
const proxyquire = require('proxyquireify')(require)

const CSSTransitionGroup = require('./stubs/react_css_transition_group')

const Foo = proxyquire('../src/foo', {
  'react-addons-css-transition-group': CSSTransitionGroup
})

/* pseudocode */
test('something about bar', (assert) => {
  assert.plan(1)

  const foo = el(Foo)
  const wrapper = mount(foo)

  assert.equal(wrapper.find('p').first().text(), 'bar')
})

希望这能帮助未来阅读此问题的读者。

1
我采用的方法既可以轻松禁用测试中的动画,又不需要每个动画组件支持任何特定于测试的参数。
由于我使用ClojureScript,语法可能对某些人来说不太熟悉,但我将进行一些注释以使其更清晰:
;; By default, in non-unit-test code, animations are enabled.
(def ^:dynamic animations-enabled true)

;; Custom component that essentially wraps React.addons.CSSTransitionGroup,
;; but modifies props passed to it whenever animations-enabled
;; is set to false.
(def css-transition-group
  (let [rc-anim-cls (rc/adapt-react-class js/React.addons.CSSTransitionGroup)]
  (rc/create-class
    {:reagent-render
     (fn [anim-spec & children]
       (let [anim-spec-2 (if animations-enabled
                           ;; If animations are enabled,
                           ;; pass props through with no change.
                           anim-spec
                           ;; If animations are disabled,
                           ;; override that in props before passing
                           ;; them to CSSTransitionGroup.
                           (assoc anim-spec
                                  :transition-enter false
                                  :transition-leave false))]
       (into [rc-anim-cls anim-spec-2] children)))})))

在常规代码中,这个类的使用方式与标准的CSSTransitionGroup完全相同。
然而,在单元测试中,我可以将animations-enabled绑定为false,并安全地断言DOM元素被立即添加/删除:
(binding [anim/animations-enabled false]
  ;; Create component that uses animations. It will not be
  ;; animated though.
  )

我喜欢当有人在没有任何评论的情况下对我的答案进行了踩。无论如何...到目前为止,这种方法对我们来说效果很好。 - kamituel
1
可能是因为如果你是一名普通的JS开发者,上面的内容就没有意义了。什么是“绑定”?全局变量? - U Avalos

0

我在理解提供的ClojureScript答案时遇到了很大的困难,因为我有类似的需求,但似乎这是唯一的谷歌搜索结果。

以下是我如何使用sinon解决它的方法:

    transitionGroupStub = sinon.stub(ReactCSSTransitionGroup.prototype, 'render', function () {
        return React.createElement('DIV', null, this.props.children)
    })

基本上在div内部渲染整个CSS过渡组件,通过传递子元素。这可能不太美观,但对于我的需求来说似乎非常有效。

我听到你说,Lisp 刚开始看起来很难理解 ;) 然而,你的解决方案很有道理。它不是完全和我的一样(我在一个测试特定的类中包装了 CSSTransitionGroup,而你使用了存根),所以我会说我的代码更简洁 - 或许是这样,但你的避免了额外的类。干杯! - kamituel

-2
根据这个计划, react-addons-css-transition-group 正在被弃用。所以也许可以使用react-motion

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接