Reputation: 35970
I'm using CSSTransitionGroup
to animate an element when it appears in the DOM, or when it leaves the DOM. It works well.
Now - I want to unit test this component. I'm creating a temporary DOM node and I attach it to the <body>
, I render my component into it, and then I perform some actions. As a result, I expect a child DOM node to disappear.
The problem: Animation classes are applied, and component is kept in the DOM until CSS animations end. This means my test should also wait for a few hundred milliseconds before I can assert for that element being gone. I cannot do that - I want my tests to be fast, as those are unit tests.
The question: Is there a way to disable CSS transitions without adding extra options to my component?
What I tried:
Unit testing itself works well. I can get rid of animations by passing a parameter to my component that will make it not use CSSTransitionGroup
. So - worst case scenario - I'll do just that. But I'm looking for a better solution.
I could also assert that "-enter"/"-enter-active"/"-leave"/"-leave-active" classes are present on an element in question. That seems a bit hacky though, as I could imagine a bug where those classes would be applied, but element would remain in the DOM. I'd prefer not to resort to this approach.
Upvotes: 13
Views: 6305
Reputation: 5068
import { config } from 'react-transition-group'
config.disabled = true
this helped me to get rid of animations with enzyme
Upvotes: 8
Reputation: 2746
Using Jest this is the solution I came up with. I mocked the Transition
component. Since my import looks like import {Transition} from 'react-transition-group'
this is what I created:
Based on my jest config, anything found in my __mocks__
folder is used instead of any imports.
__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>
)
This way, children is immediately rendered - the "Transition
" is pretty much disabled.
**This works for v2.4.0
of react-transition-group
Upvotes: 5
Reputation: 1029
According to this plans
react-addons-css-transition-group is under deprecation. So maybe use react-motion instead?
Upvotes: -3
Reputation: 24996
I believe there is a neater solution using proxyquire
(proxyquireify
in my browserify
based build). Inspired by the previous answers.
./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')
})
Hope that helps future readers of this question.
Upvotes: 2
Reputation: 5773
I had a really tough time reasoning about the ClojureScript answer provided, had a similar requirement and noted this is seemingly the only google result returned.
Here's how I solved it, using sinon:
transitionGroupStub = sinon.stub(ReactCSSTransitionGroup.prototype, 'render', function () {
return React.createElement('DIV', null, this.props.children)
})
Basically stub out the entire css transition group to render inside a div passing along the children. This may not be pretty, but it seems to work pretty well for my needs.
Upvotes: 0
Reputation: 35970
I went with the approach that on the one hand, makes it easy to disable animations in test, and on the other - doesn't require any test-specific parameters to be supported by each of the animated components.
Since I use ClojureScript, syntax might be unfamiliar to some, but I'll comment it a bit to make it clearer:
;; 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)))})))
In regular code, this class will be used in exactly the same way as standard CSSTransitionGroup
would be used.
In unit tests, however, I can bind animations-enabled
as false
and safely assert on DOM elements being added/removed immediately:
(binding [anim/animations-enabled false]
;; Create component that uses animations. It will not be
;; animated though.
)
Upvotes: 1