diff --git a/superset/assets/javascripts/components/Timer.jsx b/superset/assets/javascripts/components/Timer.jsx index f108e4ce1b21d..b221859d196e3 100644 --- a/superset/assets/javascripts/components/Timer.jsx +++ b/superset/assets/javascripts/components/Timer.jsx @@ -2,12 +2,28 @@ import React from 'react'; import PropTypes from 'prop-types'; import { now, fDuration } from '../modules/dates'; -class Timer extends React.PureComponent { +const propTypes = { + endTime: PropTypes.number, + isRunning: PropTypes.bool.isRequired, + startTime: PropTypes.number, + status: PropTypes.string, + style: PropTypes.object, +}; + +const defaultProps = { + endTime: null, + startTime: null, + status: 'success', + style: null, +}; + +export default class Timer extends React.PureComponent { constructor(props) { super(props); this.state = { clockStr: '', }; + this.stopwatch = this.stopwatch.bind(this); } componentWillMount() { this.startTimer(); @@ -16,13 +32,12 @@ class Timer extends React.PureComponent { this.stopTimer(); } startTimer() { - if (!(this.timer)) { - this.timer = setInterval(this.stopwatch.bind(this), 30); + if (!this.timer) { + this.timer = setInterval(this.stopwatch, 30); } } stopTimer() { - clearInterval(this.timer); - this.timer = null; + this.timer = clearInterval(this.timer); } stopwatch() { if (this.props && this.props.startTime) { @@ -54,19 +69,6 @@ class Timer extends React.PureComponent { return timerSpan; } } -Timer.propTypes = { - startTime: PropTypes.number, - endTime: PropTypes.number, - isRunning: PropTypes.bool.isRequired, - status: PropTypes.string, - style: PropTypes.object, -}; - -Timer.defaultProps = { - startTime: null, - endTime: null, - status: 'success', - style: null, -}; -export default Timer; +Timer.propTypes = propTypes; +Timer.defaultProps = defaultProps; diff --git a/superset/assets/spec/javascripts/sqllab/Timer_spec.jsx b/superset/assets/spec/javascripts/sqllab/Timer_spec.jsx index 9bad34c32ee7b..21a8a4fb3d442 100644 --- a/superset/assets/spec/javascripts/sqllab/Timer_spec.jsx +++ b/superset/assets/spec/javascripts/sqllab/Timer_spec.jsx @@ -1,6 +1,6 @@ import React from 'react'; -import { shallow } from 'enzyme'; -import { describe, it } from 'mocha'; +import { mount } from 'enzyme'; +import { describe, it, beforeEach } from 'mocha'; import { expect } from 'chai'; import Timer from '../../../javascripts/components/Timer'; @@ -8,18 +8,44 @@ import { now } from '../../../javascripts/modules/dates'; describe('Timer', () => { + let wrapper; const mockedProps = { startTime: now(), endTime: null, isRunning: true, - state: 'warning', + status: 'warning', }; - it('is valid', () => { - expect(React.isValidElement()) - .to.equal(true); + + beforeEach(() => { + wrapper = mount(); + }); + + it('is a valid element', () => { + expect(React.isValidElement()).to.equal(true); + }); + + it('componentWillMount starts timer after 30ms and sets state.clockStr', () => { + expect(wrapper.state().clockStr).to.equal(''); + setTimeout(() => { + expect(wrapper.state().clockStr).not.equal(''); + }, 31); }); - it('renders a span', () => { - const wrapper = shallow(); - expect(wrapper.find('span')).to.have.length(1); + + it('calls startTimer on mount', () => { + const startTimerSpy = sinon.spy(Timer.prototype, 'startTimer'); + wrapper.mount(); + expect(Timer.prototype.startTimer.calledOnce); + startTimerSpy.restore(); + }); + + it('calls stopTimer on unmount', () => { + const stopTimerSpy = sinon.spy(Timer.prototype, 'stopTimer'); + wrapper.unmount(); + expect(Timer.prototype.stopTimer.calledOnce); + stopTimerSpy.restore(); + }); + + it('renders a span with the correct class', () => { + expect(wrapper.find('span').hasClass('label-warning')).to.equal(true); }); });