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);
});
});