Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
language: node_js
node_js:
- 6.6
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
"clean": "rimraf dist/*",
"copy": "copyfiles -f ./src/index.html ./dist && copyfiles -u 1 \"./src/static/**\" ./dist",
"dist": "npm run clean && npm run copy && webpack --progress --bail --env dist -p",
"lint": "eslint ./src",
"lint": "npm run lint:src && npm run lint:test",
"lint:src": "eslint ./src",
"lint:test": "eslint ./test",
"posttest": "npm run lint",
"release:major": "npm version prerelease && git push --follow-tags && npm publish --tag beta",
"release:minor": "npm version prerelease && git push --follow-tags && npm publish --tag beta",
Expand Down Expand Up @@ -61,7 +63,7 @@
"phantomjs-prebuilt": "^2.1.7",
"react-addons-test-utils": "^15.0.1",
"rimraf": "^2.5.2",
"sinon": "^1.17.3",
"sinon": "^2.3.2",
"style-loader": "^0.13.1",
"stylus": "^0.54.5",
"stylus-loader": "^2.1.0",
Expand Down
6 changes: 3 additions & 3 deletions src/containers/Palette.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { bindActionCreators } from 'redux';
import { changeColor, changeWidth } from '../actions/';
import Main from '../components/Palette';

class Palette extends Component {
export class Palette extends Component {
render() {
return <Main actions={this.props.actions} palette={this.props.palette} />;
}
Expand All @@ -19,11 +19,11 @@ Palette.propTypes = {
palette: PropTypes.object.isRequired
};

function mapStateToProps(state) {
export function mapStateToProps(state) {
return { palette: state.palette };
}

function mapDispatchToProps(dispatch) {
export function mapDispatchToProps(dispatch) {
const actions = { changeColor, changeWidth };
return { actions: bindActionCreators(actions, dispatch) };
}
Expand Down
12 changes: 12 additions & 0 deletions test/actions/changeColorTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import action from 'actions/changeColor';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

テストは各モジュールの unit test というより、ユーザのアクションベースでやっていって良いような気がします。

たとえば、changeColor のテストだと、Pallet 上の "red" パネルをクリック and タッチする。というユーザのアクションを与えて、結果的に、きちんと Canvas の color が変わっていることをチェックしていけば良いかと思います。

DevTools のテストはこんな感じです。
https://github.com/devtools-html/debugger.html/tree/master/src/test/mochitest

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dadaa そうなんですね

となると、unit test はいらなくなるでしょうか。

import { CHANGE_COLOR } from 'actions/const';

describe('changeColor', () => {
it('should create an action to change the color', () => {
const color = '#010101';
expect(action(color)).to.deep.equal({
type: CHANGE_COLOR,
color
});
});
});
12 changes: 12 additions & 0 deletions test/actions/changeWidthTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import action from 'actions/changeWidth';
import { CHANGE_WIDTH } from 'actions/const';

describe('changeWidth', () => {
it('should create an action to change the width', () => {
const lineWidth = 40;
expect(action(lineWidth)).to.deep.equal({
type: CHANGE_WIDTH,
width: lineWidth
});
});
});
65 changes: 65 additions & 0 deletions test/all/changeColorTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React from 'react';
import { Provider } from 'react-redux';
import sinon from 'sinon';
import { shallow, mount } from 'enzyme';
import Pen from 'components/Pen';
import App from 'containers/App';
import configureStore from 'stores';
import action from 'actions/changeColor';
import { CHANGE_COLOR } from 'actions/const';
import reducer from 'reducers/palette';

describe('changeColor', () => {
describe('all', () => {
let app;
const color = '#795548';
beforeEach(() => {
app = mount(
<Provider store={configureStore()}>
<App />
</Provider>
);
});
it('the canvas should change color when a pen is clicked', () => {
const canvas = app.find('Canvas');
const pen = app.find('Pen').filterWhere(n => n.prop('color') === color);
expect(canvas.node.ctx.strokeStyle).to.not.equal(color);
pen.simulate('mousedown');
canvas.node.penDown({ clientX: 0, clientY: 0 });
expect(canvas.node.ctx.strokeStyle).to.equal(color);
});
it('the pen should become active when the pen is clicked', () => {
const pen = app.find('Pen').filterWhere(n => n.prop('color') === color);
expect(pen.node.state.styleName).to.not.have.include('pen-active');
pen.simulate('mousedown');
expect(pen.node.state.styleName).to.have.include('pen-active');
});
});
it('the action should be created when a pen is clicked', () => {
let color = '#010101';
let currentColor = '#020202';
let onChangeColor = sinon.spy();
let pen = shallow(
<Pen
color={color}
currentColor={currentColor}
onChangeColor={onChangeColor} />
);
pen.simulate('mousedown');
expect(onChangeColor.withArgs(color).calledOnce).to.equal(true);
});
it('should create an action to change the color', () => {
const color = '#010101';
expect(action(color)).to.deep.equal({
type: CHANGE_COLOR,
color
});
});
it('should handle CHANGE_COLOR', () => {
const color = '#010101';
expect(reducer(void 0, {
type: CHANGE_COLOR,
color
})).to.have.property('color', color);
});
});
19 changes: 17 additions & 2 deletions test/components/AppTest.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,32 @@
import React from 'react';
import { shallow } from 'enzyme';
import App from 'components/App';
import Palette from 'containers/Palette';
import Canvas from 'components/Canvas';

describe('<App />', function () {
const colorTest = 'red';
const widthTest = 20;
const paletteTest = {
color: colorTest,
width: widthTest
};

beforeEach(function () {
this.component = shallow(<App />);
this.component = shallow(<App palette={paletteTest} />);
});

describe('when rendering the component', function () {

it('should have a className of "index"', function () {
expect(this.component.hasClass('index')).to.equal(true);
});
it('should have a palette', function () {
expect(this.component.contains(<Palette />)).to.equal(true);
});
it('should have a canvas', function () {
expect(this.component.contains(
<Canvas color={paletteTest.color} width={paletteTest.width} />
)).to.equal(true);
});
});
});
180 changes: 176 additions & 4 deletions test/components/CanvasTest.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,190 @@
import React from 'react';
import { shallow } from 'enzyme';
import { mount } from 'enzyme';
import sinon from 'sinon';
import Canvas from 'components/Canvas.js';

describe('<Canvas />', function () {
let testColor;
let testWidth;

let component;
beforeEach(function () {
component = shallow(<Canvas />);
testColor = 'red';
testWidth = 20;
component = mount(<Canvas color={testColor} width={testWidth} />);
});

describe('when rendering the component', function () {
it('should have a canvas', function () {
expect(component.find('canvas')).to.have.length(1);
});
});

describe('#getPosition', function () {
const clientX = 10;
const clientY = 20;
it('should return when clientX and clientY', function () {
expect(component.instance().getPosition({
clientX, clientY
})).to.deep.equal({
x: clientX,
y: clientY
});
});
it('should return when touches', function () {
expect(component.instance().getPosition({
touches: [{
clientX, clientY
}]
})).to.deep.equal({
x: clientX,
y: clientY
});
});
});

describe('#pushPosition', function () {
it('should push position to positions', function () {
const pos = { x: 10, y: 20 };
component.instance().pushPosition(pos.x, pos.y);
expect(component.instance().positions).to.have.length(1);
expect(component.instance().positions[0]).to.deep.equal(pos);
});
});

describe('#penDown', function () {
it('should change strokeStyle', function () {
const color = '#008000';
component.setProps({ color });
component.instance().penDown({
clientX: 0,
clientY: 0
});
expect(component.instance().ctx.strokeStyle).to.equal(color);
});
it('should change lineWidth', function () {
const width = 200;
component.setProps({ width });
component.instance().penDown({
clientX: 0,
clientY: 0
});
expect(component.instance().ctx.lineWidth).to.equal(width);
});
it('should set isDownPen to true', function () {
component.instance().penDown({
clientX: 0,
clientY: 0
});
expect(component.instance().isDownPen).to.equal(true);
});
it('should update ctx settings', function () {
component.instance().penDown({
clientX: 0,
clientY: 0
});
expect(component.instance().ctx.lineCap).to.equal('round');
expect(component.instance().ctx.lineJoin).to.equal('round');
});
});

describe('#penMove', function () {
it('should draw a line', function () {
const lineToSpy = sinon.spy(component.instance().ctx, 'lineTo');
const x = 20;
const y = 30;
component.instance().isDownPen = true;
component.instance().penMove({
clientX: x,
clientY: y
});
expect(lineToSpy.withArgs(x, y).calledOnce).to.equal(true);
lineToSpy.restore();
});
});

describe('#penUp', function () {
it('should set isDownPen to false', function () {
component.instance().isDownPen = true;
component.instance().penUp();
expect(component.instance().isDownPen).to.equal(false);
});
it('should clear positions', function () {
component.instance().positions = [{ x: 100, y: 100 }];
component.instance().penUp();
expect(component.instance().positions).to.have.length(0);
});
});

// check overall flow

describe('mousedown', function () {
it('should change strokeStyle', function () {
const color = '#010101';
component.setProps({ color });
component.simulate('mousedown', {
clientX: 100,
clientY: 100
});
expect(component.instance().ctx.strokeStyle).to.equal(color);
});
});

describe('touchstart', function () {
it('should change strokeStyle', function () {
const color = '#010101';
component.setProps({ color });
component.simulate('touchstart', {
touches: [{
clientX: 100,
clientY: 100
}]
});
expect(component.instance().ctx.strokeStyle).to.equal(color);
});
});

describe('mousemove', function () {
it('should call lineTo', function () {
const x = 100;
const y = 200;
const lineToSpy = sinon.spy(component.instance().ctx, 'lineTo');
component.instance().isDownPen = true;
component.simulate('mousemove', {
clientX: x, clientY: y
});
expect(lineToSpy.withArgs(x, y).calledOnce).to.equal(true);
});
});

describe('touchmove', function () {
it('should call lineTo', function () {
const x = 100;
const y = 200;
const lineToSpy = sinon.spy(component.instance().ctx, 'lineTo');
component.instance().isDownPen = true;
component.simulate('touchmove', {
touches: [{
clientX: x, clientY: y
}]
});
expect(lineToSpy.withArgs(x, y).calledOnce).to.equal(true);
});
});

describe('mouseup', function () {
it('should set isDownPen to false', function () {
component.instance().isDownPen = true;
component.simulate('mouseup');
expect(component.instance().isDownPen).to.equal(false);
});
});

it('should have a className of "canvas-component"', function () {
expect(component.hasClass('canvas-component')).to.equal(true);
describe('touchend', function () {
it('should set isDownPen to false', function () {
component.instance().isDownPen = true;
component.simulate('touchend');
expect(component.instance().isDownPen).to.equal(false);
});
});
});
Loading