Skip to content
Snippets Groups Projects
Commit 0b701243 authored by Paul Kaplan's avatar Paul Kaplan Committed by GitHub
Browse files

Merge pull request #452 from bogusred/feature/jest-setup

Feature/jest setup
parents c68653a3 846eed5c
No related branches found
No related tags found
No related merge requests found
......@@ -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.
......
......@@ -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"
}
}
}
// __mocks__/fileMock.js
module.exports = 'test-file-stub';
// __mocks__/styleMock.js
module.exports = {};
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ButtonComponent matches snapshot 1`] = `
<span
className=""
onClick={[Function]}
role="button"
/>
`;
// 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>
`;
/* 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();
});
});
/* 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);
});
});
// 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"
/>
`;
/* 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.
});
/* 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();
});
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment