Skip to content

Commit

Permalink
added ability to pause with clicking, added a11y props, added tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jchen-eb committed Apr 2, 2018
1 parent a596a6d commit b6f1fda
Show file tree
Hide file tree
Showing 2 changed files with 186 additions and 25 deletions.
46 changes: 39 additions & 7 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default class Lottie extends React.Component {
autoplay,
animationData,
rendererSettings,
segments
segments,
},
eventListeners,
} = this.props;
Expand Down Expand Up @@ -43,12 +43,10 @@ export default class Lottie extends React.Component {
componentDidUpdate() {
if (this.props.isStopped) {
this.stop();
} else if (this.props.segments) {
this.playSegments();
} else {
if (this.props.segments) {
this.playSegments();
} else {
this.play();
}
this.play();
}

this.pause();
Expand Down Expand Up @@ -107,8 +105,25 @@ export default class Lottie extends React.Component {
});
}

handleClickToPause = () => {
// The pause() method is for handling pausing by passing a prop isPaused
// This method is for handling the ability to pause by clicking on the animation
if (this.anim.isPaused) {
this.anim.play();
} else {
this.anim.pause();
}
}

render() {
const {width, height} = this.props;
const {
width,
height,
ariaRole,
ariaLabel,
isClickToPauseDisabled,
title
} = this.props;

const getSize = (initial) => {
let size;
Expand All @@ -129,12 +144,21 @@ export default class Lottie extends React.Component {
margin: '0 auto',
};

const onClickHandler = isClickToPauseDisabled ? () => null : this.handleClickToPause;

return (
// Bug with eslint rules https://github.com/airbnb/javascript/issues/1374
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
<div
ref={(c) => {
this.el = c;
}}
style={lottieStyles}
onClick={onClickHandler}
title={title}
role={ariaRole}
aria-label={ariaLabel}
tabIndex="0"
/>
);
}
Expand All @@ -150,11 +174,19 @@ Lottie.propTypes = {
speed: PropTypes.number,
segments: PropTypes.arrayOf(PropTypes.number),
direction: PropTypes.number,
ariaRole: PropTypes.string,
ariaLabel: PropTypes.string,
isClickToPauseDisabled: PropTypes.bool,
title: PropTypes.string,
};

Lottie.defaultProps = {
eventListeners: [],
isStopped: false,
isPaused: false,
speed: 1,
ariaRole: 'button',
ariaLabel: 'animation',
isClickToPauseDisabled: false,
title: '',
};
165 changes: 147 additions & 18 deletions src/tests/index.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,157 @@
import React from 'react';
import { shallow, mount } from 'enzyme';
import Button from '../index';
import { expect } from 'chai';
import sinon from 'sinon';
import ReactLottie from '../index';
import pinjump from '../stories/pinjump.json';
import beatingHeart from '../stories/beating-heart.json';

const { describe, it } = global;
const defaultOptions = {
loop: true,
autoplay: true,
animationData: pinjump,
rendererSettings: {
preserveAspectRatio: 'xMidYMid slice',
},
};

describe('react-lottie', () => {
describe('props', () => {
describe('isClickToPauseDisabled', () => {
it('should prevent handleClickToPause from being called when true', () => {
const component = mount(<ReactLottie options={defaultOptions} />);
const spy = sinon.stub();

component.instance().handleClickToPause = spy;
component.instance().forceUpdate();
component.find('div').at(0).simulate('click');

expect(spy.callCount).to.equal(1);

spy.reset();
component.setProps({ isClickToPauseDisabled: true });
component.find('div').at(0).simulate('click');

expect(spy.callCount).to.equal(0);
});
});

describe('ariaRole, ariaLabel, and title', () => {
it('should set the aria role correctly', () => {
const component = shallow(
<ReactLottie
options={defaultOptions}
ariaRole="test"
ariaLabel="testlabel"
title="title"
/>
);

expect(component.find('div').prop('role')).to.equal('test');
expect(component.find('div').prop('aria-label')).to.equal('testlabel');
expect(component.find('div').prop('title')).to.equal('title');
});
});

describe('Button', () => {
it('should show the given text', () => {
const text = 'The Text';
const wrapper = shallow(<Button>{text}</Button>);
expect(wrapper.text()).to.be.equal(text);
describe('height and width', () => {
it('should set the inline styles correctly', () => {
const component = shallow(
<ReactLottie
options={defaultOptions}
height={199}
width={188}
/>
);

expect(component.find('div').prop('style').height).to.equal('199px');
expect(component.find('div').prop('style').width).to.equal('188px');
});
});
});

it('should handle the click event', () => {
const clickMe = sinon.stub();
// Here we do a JSDOM render. So, that's why we need to
// wrap this with a div.
const wrapper = mount(
<div>
<Button onClick={ clickMe }>ClickMe</Button>
</div>
);

wrapper.find('button').simulate('click');
expect(clickMe.callCount).to.be.equal(1);
describe('when props change', () => {
it('should change the animation that is being played', () => {
const component = mount(<ReactLottie options={defaultOptions} />);

expect(component.instance().anim.animationData).to.equal(pinjump);

component.setProps({
options: {
...defaultOptions,
animationData: beatingHeart,
},
});

expect(component.instance().anim.animationData).to.equal(beatingHeart);
});
});

describe('component lifecycle', () => {
describe('componentDidMount', () => {
it('should register events', () => {
const registerEventsSpy = sinon.stub();
const component = mount(<ReactLottie options={defaultOptions} />);

component.instance().registerEvents = registerEventsSpy;
component.update();

component.instance().componentDidMount();

expect(registerEventsSpy.callCount).to.equal(1);
});

it('should load the animation', () => {
const component = mount(<ReactLottie options={defaultOptions} />);
const animation = component.instance().anim;

expect(animation.animationData).to.equal(pinjump);
});
});

describe('componentWillUpdate', () => {
it('should register events when animationData changes', () => {
const registerEventsSpy = sinon.stub();
const component = mount(<ReactLottie options={defaultOptions} />);

component.instance().registerEvents = registerEventsSpy;
component.update();

component.instance().componentWillUpdate({
options: {
...defaultOptions,
animationData: beatingHeart,
},
});

expect(registerEventsSpy.callCount).to.equal(1);
});
});

describe('componentDidUnmount', () => {
it('should de-register events', () => {
const spy = sinon.stub();
const component = mount(<ReactLottie options={defaultOptions} />);

component.instance().deRegisterEvents = spy;
component.update();
component.unmount();

expect(spy.callCount).to.equal(1);
});

it('should destroy the animation', () => {
const spy = sinon.stub();
const component = mount(<ReactLottie options={defaultOptions} />);

component.instance().anim = {
destroy: spy,
};

component.unmount();

expect(spy.callCount).to.equal(1);
});
});
});
});

0 comments on commit b6f1fda

Please sign in to comment.