Skip to content

Commit 872d2f2

Browse files
committed
Testing and creating a PlaybackControls container and Button component
1 parent dff83e4 commit 872d2f2

File tree

8 files changed

+194
-23
lines changed

8 files changed

+194
-23
lines changed

app/Player.jsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
'use strict';
2+
3+
import React, { Component } from 'react';
4+
import { Provider } from 'react-redux';
5+
import configureStore from './store/configurePlayerStore';
6+
import PlaybackControls from './containers/PlaybackControls.jsx';
7+
8+
const store = configureStore();
9+
10+
class Player extends Component {
11+
render() {
12+
return <Provider store={store}>
13+
<div>
14+
<video>
15+
<source src={this.props.src} />
16+
</video>
17+
<PlaybackControls />
18+
</div>
19+
</Provider>;
20+
}
21+
}
22+
23+
Player.propTypes = {
24+
src: React.PropTypes.string
25+
};
26+
27+
export default Player;

app/components/Button.jsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
'use strict';
2+
3+
import React, { Component } from 'react';
4+
5+
class Button extends Component {
6+
constructor(props) {
7+
super(props);
8+
}
9+
10+
render() {
11+
return (
12+
<button onClick={this.props.onClick}>{this.props.text}</button>
13+
);
14+
}
15+
}
16+
17+
Button.propTypes = {
18+
onClick: React.PropTypes.func,
19+
text: React.PropTypes.string
20+
};
21+
22+
export default Button;

app/containers/PlaybackControls.jsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
'use strict';
2+
3+
import React, { Component } from 'react';
4+
5+
import { bindActionCreators } from 'redux';
6+
import { connect } from 'react-redux';
7+
8+
import { isPlaying } from '../actions/isPlaying';
9+
import { hasStopped } from '../actions/hasStopped';
10+
11+
import Button from '../components/Button.jsx';
12+
13+
export class PlaybackControls extends Component {
14+
_onPlayButtonClick() {
15+
this.props.isPlayingAction(!this.props.isPlaying);
16+
}
17+
18+
_onStopButtonClick() {
19+
this.props.hasStoppedAction(true);
20+
}
21+
22+
render() {
23+
const text = this.props.isPlaying ? 'pause' : 'play';
24+
25+
return (
26+
<div>
27+
<Button onClick={this._onPlayButtonClick.bind(this)} text={text} />
28+
<Button onClick={this._onStopButtonClick.bind(this)} text="stop" />
29+
</div>
30+
);
31+
}
32+
}
33+
34+
PlaybackControls.propTypes = {
35+
isPlaying: React.PropTypes.bool,
36+
isPlayingAction: React.PropTypes.func,
37+
hasStoppedAction: React.PropTypes.func
38+
};
39+
40+
function mapStateToProps(state) {
41+
return {
42+
isPlaying: state.playback.isPlaying
43+
};
44+
}
45+
46+
function mapDispatchToProps(dispatch) {
47+
return {
48+
isPlayingAction: bindActionCreators(isPlaying, dispatch),
49+
hasStoppedAction: bindActionCreators(hasStopped, dispatch)
50+
};
51+
}
52+
53+
export default connect(
54+
mapStateToProps,
55+
mapDispatchToProps
56+
)(PlaybackControls);

app/containers/Player.jsx

Lines changed: 0 additions & 21 deletions
This file was deleted.

app/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
import React from 'react';
44
import ReactDOM from 'react-dom';
5-
import Player from './containers/Player.jsx';
5+
import Player from './Player.jsx';
66

77
ReactDOM.render(
88
React.createElement(Player, {
9-
src: '/SampleVideo_640x360_10mb.mp4'
9+
src: './SampleVideo_640x360_10mb.mp4'
1010
}),
1111
document.getElementById('app')
1212
);

test/components/Button.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
'use strict';
2+
3+
import React from 'react';
4+
import assert from 'assert';
5+
import { shallow } from 'enzyme';
6+
import sinon from 'sinon';
7+
8+
import Button from '../../app/components/Button.jsx';
9+
10+
describe('<Button />', () => {
11+
it('calls the onClick prop when the button is clicked', () => {
12+
const onClickSpy = sinon.spy();
13+
const wrapper = shallow(
14+
<Button onClick={onClickSpy} />
15+
);
16+
17+
wrapper.find('button').simulate('click');
18+
assert.equal(onClickSpy.calledOnce, true);
19+
});
20+
it('contains the text prop', () => {
21+
const text = 'Foo bar';
22+
const wrapper = shallow(
23+
<Button text={text} />
24+
);
25+
26+
assert.equal(wrapper.text(), text);
27+
});
28+
});

test/containers/PlaybackControls.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
'use strict';
2+
3+
import React from 'react';
4+
import assert from 'assert';
5+
import { shallow, render } from 'enzyme';
6+
import sinon from 'sinon';
7+
8+
import { PlaybackControls } from '../../app/containers/PlaybackControls.jsx';
9+
10+
describe('<PlaybackControls />', () => {
11+
it('should render 2 <Button /> components', () => {
12+
const wrapper = shallow(<PlaybackControls />);
13+
assert.equal(wrapper.find('Button').length, 2);
14+
});
15+
16+
describe('play/pause <Button />', () => {
17+
it('sets play as the button text when isPlaying === false', () => {
18+
const wrapper = render(<PlaybackControls isPlaying={false} />);
19+
20+
assert.equal(wrapper.find('button:nth-child(1)').text(), 'play');
21+
});
22+
23+
it('sets pause as the button text when isPlaying === true', () => {
24+
const wrapper = render(<PlaybackControls isPlaying={true} />);
25+
26+
assert.equal(wrapper.find('button:nth-child(1)').text(), 'pause');
27+
});
28+
29+
it('calls the isPlayingAction with true when the button is clicked and isPlaying === false', () => {
30+
const isPlayingActionSpy = sinon.spy();
31+
const wrapper = shallow(<PlaybackControls isPlaying={false} isPlayingAction={isPlayingActionSpy} />);
32+
33+
wrapper.find('Button').first().simulate('click');
34+
assert(isPlayingActionSpy.calledWith(true));
35+
});
36+
});
37+
38+
describe('stop <Button />', () => {
39+
it('sets stop as the button text', () => {
40+
const wrapper = render(<PlaybackControls isPlaying={true} />);
41+
42+
assert.equal(wrapper.find('button:nth-child(2)').text(), 'stop');
43+
});
44+
45+
it('calls the hasStoppedAction with true when the button is clicked', () => {
46+
const hasStoppedActionSpy = sinon.spy();
47+
const wrapper = shallow(<PlaybackControls isPlaying={true} hasStoppedAction={hasStoppedActionSpy} />);
48+
49+
wrapper.find('Button').at(1).simulate('click');
50+
assert(hasStoppedActionSpy.calledWith(true));
51+
});
52+
});
53+
});

test/reducers/playback.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ describe('playbackState', () => {
1717
type: IS_PLAYING,
1818
isPlaying: true
1919
});
20+
2021
assert.strictEqual(state.isPlaying, true);
2122
assert.strictEqual(state.isPaused, false);
2223
assert.strictEqual(state.hasStopped, false);
@@ -27,6 +28,7 @@ describe('playbackState', () => {
2728
type: IS_PLAYING,
2829
isPlaying: false
2930
});
31+
3032
assert.strictEqual(state.isPlaying, false);
3133
});
3234
});
@@ -41,6 +43,7 @@ describe('playbackState', () => {
4143
type: IS_PAUSED,
4244
isPaused: true
4345
});
46+
4447
assert.strictEqual(state.isPlaying, false);
4548
assert.strictEqual(state.isPaused, true);
4649
assert.strictEqual(state.hasStopped, false);
@@ -51,6 +54,7 @@ describe('playbackState', () => {
5154
type: IS_PAUSED,
5255
isPaused: false
5356
});
57+
5458
assert.strictEqual(state.isPaused, false);
5559
});
5660
});
@@ -65,6 +69,7 @@ describe('playbackState', () => {
6569
type: HAS_STOPPED,
6670
hasStopped: true
6771
});
72+
6873
assert.strictEqual(state.isPlaying, false);
6974
assert.strictEqual(state.isPaused, false);
7075
assert.strictEqual(state.hasStopped, true);
@@ -75,6 +80,7 @@ describe('playbackState', () => {
7580
type: HAS_STOPPED,
7681
hasStopped: false
7782
});
83+
7884
assert.strictEqual(state.hasStopped, false);
7985
});
8086
});

0 commit comments

Comments
 (0)