Merge pull request #452 from bogusred/feature/jest-setup
Feature/jest setup
This commit is contained in:
commit
0b7012439c
11 files changed
+303
-1
No files matched your search
@@ -29,10 +29,25 @@ npm start
|
||||
Then go to [http://localhost:8601/](http://localhost:8601/) - the playground outputs the default GUI component
|
||||
|
||||
## Testing
|
||||
NOTE: If you're a windows user, please run these scripts in Windows `cmd.exe` instead of Git Bash/MINGW64.
|
||||
|
||||
Run linter, unit tests, and build.
|
||||
```bash
|
||||
npm test
|
||||
```
|
||||
|
||||
Run unit tests in isolation.
|
||||
```bash
|
||||
npm run unit-test
|
||||
```
|
||||
|
||||
Run unit tests in watch mode (watches for code changes and continuously runs tests). See [jest cli docs](https://facebook.github.io/jest/docs/en/cli.html#content) for more options.
|
||||
```bash
|
||||
npm run unit-test -- --watch
|
||||
```
|
||||
|
||||
You may want to review the documentation for [Jest](https://facebook.github.io/jest/docs/en/api.html) and [Enzyme](http://airbnb.io/enzyme/docs/api/) as you write your tests.
|
||||
|
||||
## Publishing to GitHub Pages
|
||||
|
||||
You can publish the GUI to github.io so that others on the Internet can view it.
|
||||
|
||||
+15
-1
@@ -11,7 +11,8 @@
|
||||
"i18n:src": "babel src > tmp.js && rimraf tmp.js && ./scripts/build-i18n-source.js ./translations/messages/ ./translations/",
|
||||
"lint": "eslint . --ext .js,.jsx",
|
||||
"start": "npm run i18n:msgs && webpack-dev-server",
|
||||
"test": "npm run lint && npm run build",
|
||||
"unit-test": "jest",
|
||||
"test": "npm run lint && npm run unit-test && npm run build",
|
||||
"watch": "webpack --progress --colors --watch"
|
||||
},
|
||||
"author": "Massachusetts Institute of Technology",
|
||||
@@ -39,12 +40,14 @@
|
||||
"classnames": "2.2.5",
|
||||
"copy-webpack-plugin": "4.0.1",
|
||||
"css-loader": "0.28.3",
|
||||
"enzyme": "^2.8.2",
|
||||
"eslint": "^3.16.1",
|
||||
"eslint-config-scratch": "^3.0.0",
|
||||
"eslint-plugin-react": "^7.0.1",
|
||||
"gh-pages": "github:rschamp/gh-pages#publish-branch-to-subfolder",
|
||||
"html-webpack-plugin": "2.28.0",
|
||||
"immutable": "3.8.1",
|
||||
"jest": "^20.0.4",
|
||||
"lodash.bindall": "4.4.0",
|
||||
"lodash.debounce": "4.0.8",
|
||||
"lodash.defaultsdeep": "4.6.0",
|
||||
@@ -65,6 +68,8 @@
|
||||
"react-modal": "2.2.2",
|
||||
"react-redux": "5.0.5",
|
||||
"react-style-proptype": "3.0.0",
|
||||
"react-test-renderer": "^15.5.4",
|
||||
"redux-mock-store": "^1.2.3",
|
||||
"react-tabs": "1.1.0",
|
||||
"redux": "3.7.0",
|
||||
"redux-throttle": "0.1.1",
|
||||
@@ -81,5 +86,14 @@
|
||||
"webpack": "^2.4.1",
|
||||
"webpack-dev-server": "^2.4.1",
|
||||
"xhr": "2.4.0"
|
||||
},
|
||||
"jest": {
|
||||
"testPathIgnorePatterns": [
|
||||
"src/test.js"
|
||||
],
|
||||
"moduleNameMapper": {
|
||||
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/test/__mocks__/fileMock.js",
|
||||
"\\.(css|less)$": "<rootDir>/test/__mocks__/styleMock.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
// __mocks__/fileMock.js
|
||||
|
||||
module.exports = 'test-file-stub';
|
||||
@@ -0,0 +1,3 @@
|
||||
// __mocks__/styleMock.js
|
||||
|
||||
module.exports = {};
|
||||
@@ -0,0 +1,9 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ButtonComponent matches snapshot 1`] = `
|
||||
<span
|
||||
className=""
|
||||
onClick={[Function]}
|
||||
role="button"
|
||||
/>
|
||||
`;
|
||||
@@ -0,0 +1,43 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`SpriteSelectorItemComponent matches snapshot when selected 1`] = `
|
||||
<div
|
||||
className="ponies undefined"
|
||||
onClick={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"alignContent": undefined,
|
||||
"alignItems": undefined,
|
||||
"alignSelf": undefined,
|
||||
"flexBasis": undefined,
|
||||
"flexDirection": undefined,
|
||||
"flexGrow": undefined,
|
||||
"flexShrink": undefined,
|
||||
"flexWrap": undefined,
|
||||
"height": undefined,
|
||||
"justifyContent": undefined,
|
||||
"width": undefined,
|
||||
}
|
||||
}
|
||||
>
|
||||
<div
|
||||
className=""
|
||||
onClick={[Function]}
|
||||
>
|
||||
<img
|
||||
className={undefined}
|
||||
src="test-file-stub"
|
||||
/>
|
||||
</div>
|
||||
<canvas
|
||||
className={undefined}
|
||||
height={32}
|
||||
width={32}
|
||||
/>
|
||||
<div
|
||||
className={undefined}
|
||||
>
|
||||
Pony sprite
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,24 @@
|
||||
/* eslint-env jest */
|
||||
const React = require('react'); // eslint-disable-line no-unused-vars
|
||||
const {shallow} = require('enzyme');
|
||||
const ButtonComponent = require('../../../src/components/button/button'); // eslint-disable-line no-unused-vars
|
||||
const renderer = require('react-test-renderer');
|
||||
|
||||
describe('ButtonComponent', () => {
|
||||
test('matches snapshot', () => {
|
||||
const onClick = jest.fn();
|
||||
const component = renderer.create(
|
||||
<ButtonComponent onClick={onClick}/>
|
||||
);
|
||||
expect(component.toJSON()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('triggers callback when clicked', () => {
|
||||
const onClick = jest.fn();
|
||||
const componentShallowWrapper = shallow(
|
||||
<ButtonComponent onClick={onClick}/>
|
||||
);
|
||||
componentShallowWrapper.simulate('click');
|
||||
expect(onClick).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,72 @@
|
||||
/* eslint-env jest */
|
||||
const React = require('react'); // eslint-disable-line no-unused-vars
|
||||
const {shallow} = require('enzyme');
|
||||
const SpriteSelectorItemComponent = require( // eslint-disable-line no-unused-vars
|
||||
'../../../src/components/sprite-selector-item/sprite-selector-item');
|
||||
const CostumeCanvas = require( // eslint-disable-line no-unused-vars
|
||||
'../../../src/components/costume-canvas/costume-canvas');
|
||||
const CloseButton = require('../../../src/components/close-button/close-button'); // eslint-disable-line no-unused-vars
|
||||
const renderer = require('react-test-renderer');
|
||||
|
||||
describe('SpriteSelectorItemComponent', () => {
|
||||
let className;
|
||||
let costumeURL;
|
||||
let name;
|
||||
let onClick;
|
||||
let onDeleteButtonClick;
|
||||
let selected;
|
||||
|
||||
// Wrap this in a function so it gets test specific states and can be reused.
|
||||
const getComponent = function () {
|
||||
return <SpriteSelectorItemComponent
|
||||
className={className}
|
||||
costumeURL={costumeURL}
|
||||
name={name}
|
||||
onClick={onClick}
|
||||
onDeleteButtonClick={onDeleteButtonClick}
|
||||
selected={selected}/>;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
className = 'ponies';
|
||||
costumeURL = 'https://scratch.mit.edu/foo/bar/pony';
|
||||
name = 'Pony sprite';
|
||||
onClick = jest.fn();
|
||||
onDeleteButtonClick = jest.fn();
|
||||
selected = true;
|
||||
});
|
||||
|
||||
test('matches snapshot when selected', () => {
|
||||
const component = renderer.create(getComponent());
|
||||
expect(component.toJSON()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('does not have a close box when not selected', () => {
|
||||
selected = false;
|
||||
const componentShallowWrapper = shallow(getComponent());
|
||||
expect(componentShallowWrapper.find(CloseButton).exists()).toBe(false);
|
||||
});
|
||||
|
||||
test('triggers callback when Box component is clicked', () => {
|
||||
const componentShallowWrapper = shallow(getComponent());
|
||||
componentShallowWrapper.simulate('click');
|
||||
expect(onClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('triggers callback when CloseButton component is clicked', () => {
|
||||
const componentShallowWrapper = shallow(getComponent());
|
||||
componentShallowWrapper.find(CloseButton).simulate('click');
|
||||
expect(onDeleteButtonClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('creates a CostumeCanvas when a costume url is defined', () => {
|
||||
const componentShallowWrapper = shallow(getComponent());
|
||||
expect(componentShallowWrapper.find(CostumeCanvas).exists()).toBe(true);
|
||||
});
|
||||
|
||||
test('does not create a CostumeCanvas when a costume url is null', () => {
|
||||
costumeURL = null;
|
||||
const componentShallowWrapper = shallow(getComponent());
|
||||
expect(componentShallowWrapper.find(CostumeCanvas).exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`GreenFlag Container renders active state 1`] = `
|
||||
<img
|
||||
className="undefined"
|
||||
onClick={[Function]}
|
||||
src="test-file-stub"
|
||||
title="Go"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`GreenFlag Container renders inactive state 1`] = `
|
||||
<img
|
||||
className=""
|
||||
onClick={[Function]}
|
||||
src="test-file-stub"
|
||||
title="Go"
|
||||
/>
|
||||
`;
|
||||
@@ -0,0 +1,40 @@
|
||||
/* eslint-env jest */
|
||||
const React = require('react'); // eslint-disable-line no-unused-vars
|
||||
const {shallow} = require('enzyme');
|
||||
const GreenFlag = require('../../../src/containers/green-flag'); // eslint-disable-line no-unused-vars
|
||||
const renderer = require('react-test-renderer');
|
||||
const VM = require('scratch-vm');
|
||||
|
||||
describe('GreenFlag Container', () => {
|
||||
let vm;
|
||||
beforeEach(() => {
|
||||
vm = new VM();
|
||||
});
|
||||
|
||||
test('renders active state', () => {
|
||||
const component = renderer.create(
|
||||
<GreenFlag active={true} vm={vm}/>
|
||||
);
|
||||
expect(component.toJSON()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('renders inactive state', () => {
|
||||
const component = renderer.create(
|
||||
<GreenFlag active={false} vm={vm}/>
|
||||
);
|
||||
expect(component.toJSON()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('triggers onClick when active', () => {
|
||||
const onClick = jest.fn();
|
||||
const componentShallowWrapper = shallow(
|
||||
<GreenFlag active={true} onClick={onClick} vm={vm}/>
|
||||
);
|
||||
componentShallowWrapper.simulate('click');
|
||||
expect(onClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
// @todo: Test for handles key events.
|
||||
// @todo: Test project run start.
|
||||
// @todo: Test project run stop.
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
/* eslint-env jest */
|
||||
const React = require('react'); // eslint-disable-line no-unused-vars
|
||||
const {mount} = require('enzyme');
|
||||
import configureStore from 'redux-mock-store';
|
||||
import {Provider} from 'react-redux'; // eslint-disable-line no-unused-vars
|
||||
|
||||
const SpriteSelectorItem = require( // eslint-disable-line no-unused-vars
|
||||
'../../../src/containers/sprite-selector-item');
|
||||
const CloseButton = require('../../../src/components/close-button/close-button'); // eslint-disable-line no-unused-vars
|
||||
|
||||
describe('SpriteSelectorItem Container', () => {
|
||||
const mockStore = configureStore();
|
||||
let className;
|
||||
let costumeURL;
|
||||
let name;
|
||||
let onClick;
|
||||
let onDeleteButtonClick;
|
||||
let selected;
|
||||
let id;
|
||||
let store;
|
||||
// Wrap this in a function so it gets test specific states and can be reused.
|
||||
const getContainer = function () {
|
||||
return <Provider store={store}><SpriteSelectorItem
|
||||
className={className}
|
||||
costumeURL={costumeURL}
|
||||
id={id}
|
||||
name={name}
|
||||
onClick={onClick}
|
||||
onDeleteButtonClick={onDeleteButtonClick}
|
||||
selected={selected}/></Provider>;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
store = mockStore();
|
||||
className = 'ponies';
|
||||
costumeURL = 'https://scratch.mit.edu/foo/bar/pony';
|
||||
id = 1337;
|
||||
name = 'Pony sprite';
|
||||
onClick = jest.fn();
|
||||
onDeleteButtonClick = jest.fn();
|
||||
selected = true;
|
||||
// Mock window.confirm() which is called when the close button is clicked.
|
||||
global.confirm = jest.fn(() => true);
|
||||
});
|
||||
|
||||
test('should confirm if the user really wants to delete the sprite', () => {
|
||||
const wrapper = mount(getContainer());
|
||||
wrapper.find(CloseButton).simulate('click');
|
||||
expect(global.confirm).toHaveBeenCalled();
|
||||
expect(onDeleteButtonClick).toHaveBeenCalledWith(1337);
|
||||
});
|
||||
|
||||
test('should not delete the sprite if the user cancels', () => {
|
||||
global.confirm = jest.fn(() => false);
|
||||
const wrapper = mount(getContainer());
|
||||
wrapper.find(CloseButton).simulate('click');
|
||||
expect(global.confirm).toHaveBeenCalled();
|
||||
expect(onDeleteButtonClick).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user