mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2025-03-03 10:45:48 +03:00
Move redux-devtools-test-generator package (#438)
* Move from zalmoxisus/redux-devtools-test-generator * Update package and links * Fix CI
This commit is contained in:
parent
4f6ac0279a
commit
2f91b8765c
|
@ -1,13 +1,12 @@
|
||||||
sudo: false
|
sudo: false
|
||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- "lts/*"
|
|
||||||
- "stable"
|
- "stable"
|
||||||
cache:
|
cache:
|
||||||
yarn: true
|
yarn: true
|
||||||
directories:
|
directories:
|
||||||
- "node_modules"
|
- "node_modules"
|
||||||
script:
|
script:
|
||||||
- npm run build:all
|
- yarn build:all
|
||||||
- npm run lint
|
- yarn lint
|
||||||
- npm test
|
- yarn test
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-eslint": "^10.0.0",
|
"babel-eslint": "^10.0.0",
|
||||||
"eslint-plugin-react": "7.4.0",
|
"eslint-plugin-react": "7.4.0",
|
||||||
|
"eslint-plugin-flowtype": "3.2.0",
|
||||||
"lerna": "3.4.2"
|
"lerna": "3.4.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
3
packages/redux-devtools-test-generator/.babelrc
Normal file
3
packages/redux-devtools-test-generator/.babelrc
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"presets": ["es2015-loose", "stage-0", "react"]
|
||||||
|
}
|
3
packages/redux-devtools-test-generator/.eslintignore
Normal file
3
packages/redux-devtools-test-generator/.eslintignore
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
lib
|
||||||
|
demo
|
||||||
|
**/node_modules
|
18
packages/redux-devtools-test-generator/.eslintrc
Normal file
18
packages/redux-devtools-test-generator/.eslintrc
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"extends": "eslint-config-airbnb",
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"jest": true,
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"prefer-template": 0,
|
||||||
|
"no-shadow": 0,
|
||||||
|
"comma-dangle": 0,
|
||||||
|
"react/sort-comp": 0
|
||||||
|
},
|
||||||
|
"parser": "babel-eslint",
|
||||||
|
"plugins": [
|
||||||
|
"react"
|
||||||
|
]
|
||||||
|
}
|
21
packages/redux-devtools-test-generator/LICENSE.md
Normal file
21
packages/redux-devtools-test-generator/LICENSE.md
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2016 Mihail Diordiev
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
54
packages/redux-devtools-test-generator/README.md
Normal file
54
packages/redux-devtools-test-generator/README.md
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
Redux DevTools Test Generator
|
||||||
|
==============================
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install --save-dev redux-devtools-test-generator
|
||||||
|
```
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
If you use [Redux DevTools Extension](https://github.com/zalmoxisus/redux-devtools-extension), [Remote Redux DevTools](https://github.com/zalmoxisus/remote-redux-devtools) or [RemoteDev](https://github.com/zalmoxisus/remotedev), it's already there, and no additional actions required.
|
||||||
|
|
||||||
|
With [`redux-devtools`](https://github.com/reduxjs/redux-devtools) and [`redux-devtools-inspector`](https://github.com/reduxjs/redux-devtools/packages/redux-devtools-inspector):
|
||||||
|
|
||||||
|
##### `containers/DevTools.js`
|
||||||
|
|
||||||
|
```js
|
||||||
|
import React from 'react';
|
||||||
|
import { createDevTools } from 'redux-devtools';
|
||||||
|
import Inspector from 'redux-devtools-inspector';
|
||||||
|
import TestGenerator from 'redux-devtools-test-generator';
|
||||||
|
import mochaTemplate from 'redux-devtools-test-generator/lib/redux/mocha'; // If using default tests.
|
||||||
|
|
||||||
|
const testComponent = (props) => (
|
||||||
|
<TestGenerator
|
||||||
|
expect={mochaTemplate.expect} wrap={mochaTemplate.wrap} useCodemirror
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default createDevTools(
|
||||||
|
<Inspector
|
||||||
|
tabs: defaultTabs => [...defaultTabs, { name: 'Test', component: testComponent }]
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Instead of `mochaTemplate.expect` and `mochaTemplate.wrap` you can use your function templates.
|
||||||
|
|
||||||
|
If `useCodemirror` specified, include `codemirror/lib/codemirror.css` style and optionally themes from `codemirror/theme/`.
|
||||||
|
|
||||||
|
### Props
|
||||||
|
|
||||||
|
Name | Description
|
||||||
|
------------- | -------------
|
||||||
|
`assertion` | String template or function with an object argument containing `action`, `prevState`, `curState` keys, which returns a string representing the assertion (see the [function](https://github.com/zalmoxisus/redux-devtools-test-generator/blob/master/src/redux/mocha/index.js#L1-L3) or [template](https://github.com/zalmoxisus/redux-devtools-test-generator/blob/master/src/redux/mocha/template.js#L1)).
|
||||||
|
[`wrap`] | Optional string template or function which gets `assertions` argument and returns a string (see the example [function](https://github.com/zalmoxisus/redux-devtools-test-generator/blob/master/src/redux/mocha/index.js#L5-L14) or [template](https://github.com/zalmoxisus/redux-devtools-test-generator/blob/master/src/redux/mocha/template.js#L3-L12)).
|
||||||
|
[`useCodemirror`] | Boolean. If specified will use codemirror styles.
|
||||||
|
[`theme`] | String. Name of [the codemirror theme](https://codemirror.net/demo/theme.html).
|
||||||
|
|
||||||
|
### License
|
||||||
|
|
||||||
|
MIT
|
91
packages/redux-devtools-test-generator/package.json
Normal file
91
packages/redux-devtools-test-generator/package.json
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
{
|
||||||
|
"name": "redux-devtools-test-generator",
|
||||||
|
"version": "0.5.1",
|
||||||
|
"description": "Generate tests for redux devtools.",
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"files": [
|
||||||
|
"lib"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"start": "webpack-dev-server",
|
||||||
|
"clean": "rimraf lib",
|
||||||
|
"build": "babel src --out-dir lib",
|
||||||
|
"lint": "eslint src test",
|
||||||
|
"test": "jest --no-cache",
|
||||||
|
"prepare": "npm run clean && npm run build",
|
||||||
|
"prepublishOnly": "npm run lint && npm run test && npm run clean && npm run build"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/reduxjs/redux-devtools.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"redux",
|
||||||
|
"devtools",
|
||||||
|
"test",
|
||||||
|
"flux",
|
||||||
|
"react",
|
||||||
|
"hot reloading",
|
||||||
|
"time travel",
|
||||||
|
"live edit"
|
||||||
|
],
|
||||||
|
"author": "Mihail Diordiev <zalmoxisus@gmail.com> (https://github.com/zalmoxisus)",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/reduxjs/redux-devtools/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/reduxjs/redux-devtools",
|
||||||
|
"devDependencies": {
|
||||||
|
"babel-cli": "^6.10.1",
|
||||||
|
"babel-core": "^6.10.4",
|
||||||
|
"babel-eslint": "^6.0.5",
|
||||||
|
"babel-loader": "^6.2.4",
|
||||||
|
"babel-preset-es2015": "^6.9.0",
|
||||||
|
"babel-preset-es2015-loose": "^7.0.0",
|
||||||
|
"babel-preset-react": "^6.5.0",
|
||||||
|
"babel-preset-stage-0": "^6.5.0",
|
||||||
|
"babel-register": "^6.11.6",
|
||||||
|
"clean-webpack-plugin": "^0.1.15",
|
||||||
|
"css-loader": "^0.26.1",
|
||||||
|
"enzyme": "^2.6.0",
|
||||||
|
"enzyme-to-json": "^1.3.0",
|
||||||
|
"eslint": "^2.13.1",
|
||||||
|
"eslint-config-airbnb": "^9.0.1",
|
||||||
|
"eslint-plugin-import": "^1.9.2",
|
||||||
|
"eslint-plugin-jsx-a11y": "^1.5.3",
|
||||||
|
"eslint-plugin-react": "^5.2.2",
|
||||||
|
"expect": "^1.20.1",
|
||||||
|
"export-files-webpack-plugin": "0.0.1",
|
||||||
|
"file-loader": "^0.10.0",
|
||||||
|
"html-webpack-plugin": "^2.28.0",
|
||||||
|
"jest": "^23.6.0",
|
||||||
|
"lodash.shuffle": "^4.2.0",
|
||||||
|
"nyan-progress-webpack-plugin": "^1.1.4",
|
||||||
|
"react-addons-test-utils": "^15.1.0",
|
||||||
|
"react-dom": "^15.1.0",
|
||||||
|
"react-redux": "^5.0.2",
|
||||||
|
"react-router": "^3.0.2",
|
||||||
|
"react-router-redux": "^4.0.8",
|
||||||
|
"redux": "^3.6.0",
|
||||||
|
"redux-devtools": "^3.3.2",
|
||||||
|
"redux-devtools-dock-monitor": "^1.1.1",
|
||||||
|
"redux-logger": "^2.8.1",
|
||||||
|
"remotedev-inspector-monitor": "^0.11.0",
|
||||||
|
"rimraf": "^2.5.2",
|
||||||
|
"style-loader": "^0.13.1",
|
||||||
|
"url-loader": "^0.5.7",
|
||||||
|
"webpack": "^2.2.1",
|
||||||
|
"webpack-dev-server": "^2.3.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"devui": "^1.0.0-0",
|
||||||
|
"es6template": "^1.0.4",
|
||||||
|
"javascript-stringify": "^1.2.0",
|
||||||
|
"jsan": "^3.1.3",
|
||||||
|
"object-path": "^0.11.1",
|
||||||
|
"prop-types": "^15.5.10",
|
||||||
|
"react": "^15.1.0",
|
||||||
|
"react-icons": "^2.2.3",
|
||||||
|
"simple-diff": "^1.3.0"
|
||||||
|
}
|
||||||
|
}
|
180
packages/redux-devtools-test-generator/src/TestGenerator.js
Normal file
180
packages/redux-devtools-test-generator/src/TestGenerator.js
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
import React, { PureComponent, Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import stringify from 'javascript-stringify';
|
||||||
|
import objectPath from 'object-path';
|
||||||
|
import jsan from 'jsan';
|
||||||
|
import diff from 'simple-diff';
|
||||||
|
import es6template from 'es6template';
|
||||||
|
import { Editor } from 'devui';
|
||||||
|
|
||||||
|
export const fromPath = (path) => (
|
||||||
|
path
|
||||||
|
.map(a => (
|
||||||
|
typeof a === 'string' ? `.${a}` : `[${a}]`
|
||||||
|
))
|
||||||
|
.join('')
|
||||||
|
);
|
||||||
|
|
||||||
|
function getState(s, defaultValue) {
|
||||||
|
if (!s) return defaultValue;
|
||||||
|
return JSON.parse(jsan.stringify(s.state));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function compare(s1, s2, cb, defaultValue) {
|
||||||
|
const paths = []; // Already processed
|
||||||
|
function generate({ type, newPath, newValue, newIndex }) {
|
||||||
|
let curState;
|
||||||
|
let path = fromPath(newPath);
|
||||||
|
|
||||||
|
if (type === 'remove-item' || type === 'move-item') {
|
||||||
|
if (paths.length && paths.indexOf(path) !== -1) return;
|
||||||
|
paths.push(path);
|
||||||
|
const v = objectPath.get(s2.state, newPath);
|
||||||
|
curState = v.length;
|
||||||
|
path += '.length';
|
||||||
|
} else if (type === 'add-item') {
|
||||||
|
generate({ type: 'move-item', newPath });
|
||||||
|
path += `[${newIndex}]`;
|
||||||
|
curState = stringify(newValue);
|
||||||
|
} else {
|
||||||
|
curState = stringify(newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log(`expect(store${path}).toEqual(${curState});`);
|
||||||
|
cb({ path, curState });
|
||||||
|
}
|
||||||
|
|
||||||
|
diff(getState(s1, defaultValue), getState(s2, defaultValue)/* , { idProp: '*' } */)
|
||||||
|
.forEach(generate);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class TestGenerator extends (PureComponent || Component) {
|
||||||
|
getMethod(action) {
|
||||||
|
let type = action.type;
|
||||||
|
if (type[0] === '┗') type = type.substr(1).trim();
|
||||||
|
let args = action.arguments;
|
||||||
|
if (args) args = args.map(arg => stringify(arg)).join(',');
|
||||||
|
else args = '';
|
||||||
|
return `${type}(${args})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
getAction(action) {
|
||||||
|
if (action.type === '@@INIT') return '{}';
|
||||||
|
return stringify(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
generateTest() {
|
||||||
|
const {
|
||||||
|
computedStates, actions, selectedActionId, startActionId, isVanilla, name
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
if (!actions || !computedStates || computedStates.length < 1) return '';
|
||||||
|
|
||||||
|
let { wrap, assertion, dispatcher, indentation } = this.props;
|
||||||
|
if (typeof assertion === 'string') assertion = es6template.compile(assertion);
|
||||||
|
if (typeof wrap === 'string') {
|
||||||
|
const ident = wrap.match(/\n.+\$\{assertions}/);
|
||||||
|
if (ident) indentation = ident[0].length - 13;
|
||||||
|
wrap = es6template.compile(wrap);
|
||||||
|
}
|
||||||
|
if (typeof dispatcher === 'string') dispatcher = es6template.compile(dispatcher);
|
||||||
|
|
||||||
|
let space = '';
|
||||||
|
if (indentation) space = Array(indentation).join(' ');
|
||||||
|
|
||||||
|
let r = '';
|
||||||
|
let isFirst = true;
|
||||||
|
let i;
|
||||||
|
if (startActionId !== null) i = startActionId;
|
||||||
|
else if (selectedActionId !== null) i = selectedActionId;
|
||||||
|
else i = computedStates.length - 1;
|
||||||
|
const startIdx = i > 0 ? i : 1;
|
||||||
|
|
||||||
|
const addAssertions = ({ path, curState }) => {
|
||||||
|
r += space + assertion({ path, curState }) + '\n';
|
||||||
|
};
|
||||||
|
|
||||||
|
while (actions[i]) {
|
||||||
|
if (!isVanilla || /^┗?\s?[a-zA-Z0-9_@.\[\]-]+?$/.test(actions[i].action.type)) {
|
||||||
|
if (isFirst) isFirst = false;
|
||||||
|
else r += space;
|
||||||
|
if (!isVanilla || actions[i].action.type[0] !== '@') {
|
||||||
|
r += dispatcher({
|
||||||
|
action: !isVanilla ?
|
||||||
|
this.getAction(actions[i].action) :
|
||||||
|
this.getMethod(actions[i].action),
|
||||||
|
prevState: i > 0 ? stringify(computedStates[i - 1].state) : undefined
|
||||||
|
}) + '\n';
|
||||||
|
}
|
||||||
|
if (!isVanilla) {
|
||||||
|
addAssertions({ path: '', curState: stringify(computedStates[i].state) });
|
||||||
|
} else {
|
||||||
|
compare(computedStates[i - 1], computedStates[i], addAssertions, isVanilla && {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
if (i > selectedActionId) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = r.trim();
|
||||||
|
if (wrap) {
|
||||||
|
if (!isVanilla) r = wrap({ name, assertions: r });
|
||||||
|
else {
|
||||||
|
r = wrap({
|
||||||
|
name: /^[a-zA-Z0-9_-]+?$/.test(name) ? name : 'Store',
|
||||||
|
actionName: (selectedActionId === null || selectedActionId > 0) && actions[startIdx] ?
|
||||||
|
actions[startIdx].action.type.replace(/[^a-zA-Z0-9_-]+/, '') :
|
||||||
|
'should return the initial state',
|
||||||
|
initialState: stringify(computedStates[startIdx - 1].state),
|
||||||
|
assertions: r
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const code = this.generateTest();
|
||||||
|
|
||||||
|
if (!this.props.useCodemirror) {
|
||||||
|
return (
|
||||||
|
<textarea
|
||||||
|
style={{ padding: '10px', width: '100%', height: '100%' }}
|
||||||
|
defaultValue={code}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Editor value={code} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TestGenerator.propTypes = {
|
||||||
|
name: PropTypes.string,
|
||||||
|
isVanilla: PropTypes.bool,
|
||||||
|
computedStates: PropTypes.array,
|
||||||
|
actions: PropTypes.object,
|
||||||
|
selectedActionId: PropTypes.number,
|
||||||
|
startActionId: PropTypes.number,
|
||||||
|
wrap: PropTypes.oneOfType([
|
||||||
|
PropTypes.func,
|
||||||
|
PropTypes.string
|
||||||
|
]),
|
||||||
|
dispatcher: PropTypes.oneOfType([
|
||||||
|
PropTypes.func,
|
||||||
|
PropTypes.string
|
||||||
|
]),
|
||||||
|
assertion: PropTypes.oneOfType([
|
||||||
|
PropTypes.func,
|
||||||
|
PropTypes.string
|
||||||
|
]),
|
||||||
|
useCodemirror: PropTypes.bool,
|
||||||
|
indentation: PropTypes.number,
|
||||||
|
header: PropTypes.element
|
||||||
|
};
|
||||||
|
|
||||||
|
TestGenerator.defaultProps = {
|
||||||
|
useCodemirror: true,
|
||||||
|
selectedActionId: null,
|
||||||
|
startActionId: null
|
||||||
|
};
|
167
packages/redux-devtools-test-generator/src/index.js
Normal file
167
packages/redux-devtools-test-generator/src/index.js
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Toolbar, Container, Button, Select, Notification, Dialog } from 'devui';
|
||||||
|
import { formSchema, uiSchema, defaultFormData } from './templateForm';
|
||||||
|
import AddIcon from 'react-icons/lib/md/add';
|
||||||
|
import EditIcon from 'react-icons/lib/md/edit';
|
||||||
|
import TestGenerator from './TestGenerator';
|
||||||
|
import jestTemplate from './redux/jest/template';
|
||||||
|
import mochaTemplate from './redux/mocha/template';
|
||||||
|
import tapeTemplate from './redux/tape/template';
|
||||||
|
import avaTemplate from './redux/ava/template';
|
||||||
|
|
||||||
|
export const getDefaultTemplates = (/* lib */) => (
|
||||||
|
/*
|
||||||
|
if (lib === 'redux') {
|
||||||
|
return [mochaTemplate, tapeTemplate, avaTemplate];
|
||||||
|
}
|
||||||
|
return [mochaVTemplate, tapeVTemplate, avaVTemplate];
|
||||||
|
*/
|
||||||
|
[jestTemplate, mochaTemplate, tapeTemplate, avaTemplate]
|
||||||
|
);
|
||||||
|
|
||||||
|
export default class TestTab extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = { dialogStatus: null };
|
||||||
|
}
|
||||||
|
|
||||||
|
getPersistedState = () => (
|
||||||
|
this.props.monitorState.testGenerator || {}
|
||||||
|
);
|
||||||
|
|
||||||
|
handleSelectTemplate = selectedTemplate => {
|
||||||
|
const { templates = getDefaultTemplates() } = this.getPersistedState();
|
||||||
|
this.updateState({ selected: templates.indexOf(selectedTemplate) });
|
||||||
|
};
|
||||||
|
|
||||||
|
handleCloseTip = () => {
|
||||||
|
this.updateState({ hideTip: true });
|
||||||
|
};
|
||||||
|
|
||||||
|
handleCloseDialog = () => {
|
||||||
|
this.setState({ dialogStatus: null });
|
||||||
|
};
|
||||||
|
|
||||||
|
handleSubmit = ({ formData: template }) => {
|
||||||
|
const { templates = getDefaultTemplates(), selected = 0 } = this.getPersistedState();
|
||||||
|
if (this.state.dialogStatus === 'Add') {
|
||||||
|
this.updateState({
|
||||||
|
selected: templates.length,
|
||||||
|
templates: [...templates, template]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const editedTemplates = [...templates];
|
||||||
|
editedTemplates[selected] = template;
|
||||||
|
this.updateState({
|
||||||
|
templates: editedTemplates
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.handleCloseDialog();
|
||||||
|
};
|
||||||
|
|
||||||
|
handleRemove = () => {
|
||||||
|
const { templates = getDefaultTemplates(), selected = 0 } = this.getPersistedState();
|
||||||
|
this.updateState({
|
||||||
|
selected: 0,
|
||||||
|
templates: templates.length === 1 ? undefined : [
|
||||||
|
...templates.slice(0, selected),
|
||||||
|
...templates.slice(selected + 1)
|
||||||
|
]
|
||||||
|
});
|
||||||
|
this.handleCloseDialog();
|
||||||
|
};
|
||||||
|
|
||||||
|
addTemplate = () => {
|
||||||
|
this.setState({ dialogStatus: 'Add' });
|
||||||
|
};
|
||||||
|
|
||||||
|
editTemplate = () => {
|
||||||
|
this.setState({ dialogStatus: 'Edit' });
|
||||||
|
};
|
||||||
|
|
||||||
|
updateState = newState => {
|
||||||
|
this.props.updateMonitorState({
|
||||||
|
testGenerator: {
|
||||||
|
...this.props.monitorState.testGenerator,
|
||||||
|
...newState
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { monitorState, updateMonitorState, ...rest } = this.props; // eslint-disable-line no-unused-vars, max-len
|
||||||
|
const { dialogStatus } = this.state;
|
||||||
|
const persistedState = this.getPersistedState();
|
||||||
|
const { selected = 0, templates = getDefaultTemplates() } = persistedState;
|
||||||
|
const template = templates[selected];
|
||||||
|
const { name, assertion, dispatcher, wrap } = template;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<Toolbar>
|
||||||
|
<Select
|
||||||
|
options={templates}
|
||||||
|
valueKey="name"
|
||||||
|
labelKey="name"
|
||||||
|
value={name}
|
||||||
|
simpleValue={false}
|
||||||
|
onChange={this.handleSelectTemplate}
|
||||||
|
/>
|
||||||
|
<Button onClick={this.editTemplate}><EditIcon /></Button>
|
||||||
|
<Button onClick={this.addTemplate}><AddIcon /></Button>
|
||||||
|
</Toolbar>
|
||||||
|
{!assertion ?
|
||||||
|
<Notification>
|
||||||
|
No template for tests specified.
|
||||||
|
</Notification>
|
||||||
|
:
|
||||||
|
<TestGenerator
|
||||||
|
isVanilla={false}
|
||||||
|
assertion={assertion}
|
||||||
|
dispatcher={dispatcher}
|
||||||
|
wrap={wrap}
|
||||||
|
{...rest}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
{!persistedState.hideTip && assertion && rest.startActionId === null &&
|
||||||
|
<Notification onClose={this.handleCloseTip}>
|
||||||
|
Hold <b>SHIFT</b> key to select more actions.
|
||||||
|
</Notification>
|
||||||
|
}
|
||||||
|
{dialogStatus &&
|
||||||
|
<Dialog
|
||||||
|
open
|
||||||
|
title={`${dialogStatus} test template`}
|
||||||
|
onDismiss={this.handleCloseDialog}
|
||||||
|
onSubmit={this.handleSubmit}
|
||||||
|
actions={[
|
||||||
|
<Button key="cancel" onClick={this.handleCloseDialog}>Cancel</Button>,
|
||||||
|
<Button key="remove" onClick={this.handleRemove}>Remove</Button>
|
||||||
|
]}
|
||||||
|
submitText={dialogStatus}
|
||||||
|
schema={formSchema}
|
||||||
|
uiSchema={uiSchema}
|
||||||
|
formData={dialogStatus === 'Edit' ? template : defaultFormData}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TestTab.propTypes = {
|
||||||
|
monitorState: PropTypes.shape({
|
||||||
|
testGenerator: PropTypes.shape({
|
||||||
|
templates: PropTypes.array,
|
||||||
|
selected: PropTypes.number,
|
||||||
|
hideTip: PropTypes.bool
|
||||||
|
})
|
||||||
|
}).isRequired,
|
||||||
|
/*
|
||||||
|
options: PropTypes.shape({
|
||||||
|
lib: PropTypes.string
|
||||||
|
}).isRequired,
|
||||||
|
*/
|
||||||
|
updateMonitorState: PropTypes.func.isRequired
|
||||||
|
};
|
|
@ -0,0 +1,21 @@
|
||||||
|
export const name = 'Ava template';
|
||||||
|
|
||||||
|
export const dispatcher = ({ action, prevState }) => (
|
||||||
|
`state = reducers(${prevState}, ${action});`
|
||||||
|
);
|
||||||
|
|
||||||
|
export const assertion = ({ curState }) => (
|
||||||
|
`t.deepEqual(state, ${curState});`
|
||||||
|
);
|
||||||
|
|
||||||
|
export const wrap = ({ assertions }) => (
|
||||||
|
`import test from 'ava';
|
||||||
|
import reducers from '../../reducers';
|
||||||
|
|
||||||
|
test('reducers', (t) => {
|
||||||
|
let state;
|
||||||
|
${assertions}
|
||||||
|
});
|
||||||
|
`);
|
||||||
|
|
||||||
|
export default { name, assertion, dispatcher, wrap };
|
|
@ -0,0 +1,17 @@
|
||||||
|
export const name = 'Ava template';
|
||||||
|
|
||||||
|
export const dispatcher = 'state = reducers(${prevState}, ${action});';
|
||||||
|
|
||||||
|
export const assertion = 't.deepEqual(state, ${curState});';
|
||||||
|
|
||||||
|
export const wrap = (
|
||||||
|
`import test from 'ava';
|
||||||
|
import reducers from '../../reducers';
|
||||||
|
|
||||||
|
test('reducers', (t) => {
|
||||||
|
let state;
|
||||||
|
\${assertions}
|
||||||
|
});
|
||||||
|
`);
|
||||||
|
|
||||||
|
export default { name, assertion, dispatcher, wrap };
|
|
@ -0,0 +1,20 @@
|
||||||
|
export const name = 'Jest template';
|
||||||
|
|
||||||
|
export const dispatcher = ({ action, prevState }) => (
|
||||||
|
`state = reducers(${prevState}, ${action});`
|
||||||
|
);
|
||||||
|
|
||||||
|
export const assertion = ({ curState }) => (
|
||||||
|
`expect(state).toEqual(${curState});`
|
||||||
|
);
|
||||||
|
|
||||||
|
export const wrap = ({ assertions }) => (
|
||||||
|
`import reducers from '../../reducers';
|
||||||
|
|
||||||
|
test('reducers', () => {
|
||||||
|
let state;
|
||||||
|
${assertions}
|
||||||
|
});
|
||||||
|
`);
|
||||||
|
|
||||||
|
export default { name, assertion, dispatcher, wrap };
|
|
@ -0,0 +1,16 @@
|
||||||
|
export const name = 'Jest template';
|
||||||
|
|
||||||
|
export const dispatcher = 'state = reducers(${prevState}, ${action});';
|
||||||
|
|
||||||
|
export const assertion = 'expect(state).toEqual(${curState});';
|
||||||
|
|
||||||
|
export const wrap = (
|
||||||
|
`import reducers from '../../reducers';
|
||||||
|
|
||||||
|
test('reducers', () => {
|
||||||
|
let state;
|
||||||
|
\${assertions}
|
||||||
|
});
|
||||||
|
`);
|
||||||
|
|
||||||
|
export default { name, assertion, dispatcher, wrap };
|
|
@ -0,0 +1,23 @@
|
||||||
|
export const name = 'Mocha template';
|
||||||
|
|
||||||
|
export const dispatcher = ({ action, prevState }) => (
|
||||||
|
`state = reducers(${prevState}, ${action});`
|
||||||
|
);
|
||||||
|
|
||||||
|
export const assertion = ({ curState }) => (
|
||||||
|
`expect(state).toEqual(${curState});`
|
||||||
|
);
|
||||||
|
|
||||||
|
export const wrap = ({ assertions }) => (
|
||||||
|
`import expect from 'expect';
|
||||||
|
import reducers from '../../reducers';
|
||||||
|
|
||||||
|
describe('reducers', () => {
|
||||||
|
it('should handle actions', () => {
|
||||||
|
let state;
|
||||||
|
${assertions}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
`);
|
||||||
|
|
||||||
|
export default { name, assertion, dispatcher, wrap };
|
|
@ -0,0 +1,19 @@
|
||||||
|
export const name = 'Mocha template';
|
||||||
|
|
||||||
|
export const dispatcher = 'state = reducers(${prevState}, ${action});';
|
||||||
|
|
||||||
|
export const assertion = 'expect(state).toEqual(${curState});';
|
||||||
|
|
||||||
|
export const wrap = (
|
||||||
|
`import expect from 'expect';
|
||||||
|
import reducers from '../../reducers';
|
||||||
|
|
||||||
|
describe('reducers', () => {
|
||||||
|
it('should handle actions', () => {
|
||||||
|
let state;
|
||||||
|
\${assertions}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
`);
|
||||||
|
|
||||||
|
export default { name, assertion, dispatcher, wrap };
|
|
@ -0,0 +1,22 @@
|
||||||
|
export const name = 'Tape template';
|
||||||
|
|
||||||
|
export const dispatcher = ({ action, prevState }) => (
|
||||||
|
`state = reducers(${prevState}, ${action});`
|
||||||
|
);
|
||||||
|
|
||||||
|
export const assertion = ({ curState }) => (
|
||||||
|
`t.deepEqual(state, ${curState});`
|
||||||
|
);
|
||||||
|
|
||||||
|
export const wrap = ({ assertions }) => (
|
||||||
|
`import test from 'tape';
|
||||||
|
import reducers from '../../reducers';
|
||||||
|
|
||||||
|
test('reducers', (t) => {
|
||||||
|
let state;
|
||||||
|
${assertions}
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
`);
|
||||||
|
|
||||||
|
export default { name, assertion, dispatcher, wrap };
|
|
@ -0,0 +1,18 @@
|
||||||
|
export const name = 'Tape template';
|
||||||
|
|
||||||
|
export const dispatcher = 'state = reducers(${prevState}, ${action});';
|
||||||
|
|
||||||
|
export const assertion = 't.deepEqual(state, ${curState});';
|
||||||
|
|
||||||
|
export const wrap = (
|
||||||
|
`import test from 'tape';
|
||||||
|
import reducers from '../../reducers';
|
||||||
|
|
||||||
|
test('reducers', (t) => {
|
||||||
|
let state;
|
||||||
|
\${assertions}
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
`);
|
||||||
|
|
||||||
|
export default { name, assertion, dispatcher, wrap };
|
42
packages/redux-devtools-test-generator/src/templateForm.js
Normal file
42
packages/redux-devtools-test-generator/src/templateForm.js
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
export const formSchema = {
|
||||||
|
type: 'object',
|
||||||
|
required: ['name'],
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
title: 'Template name'
|
||||||
|
},
|
||||||
|
dispatcher: {
|
||||||
|
type: 'string',
|
||||||
|
title: 'Dispatcher: ({ action, prevState }) => (`<template>`)'
|
||||||
|
},
|
||||||
|
assertion: {
|
||||||
|
type: 'string',
|
||||||
|
title: 'Assertion: ({ curState }) => (`<template>`)'
|
||||||
|
},
|
||||||
|
wrap: {
|
||||||
|
type: 'string',
|
||||||
|
title: 'Wrap code: ({ name, initialState, assertions }) => (`<template>`)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const uiSchema = {
|
||||||
|
dispatcher: {
|
||||||
|
'ui:widget': 'textarea'
|
||||||
|
},
|
||||||
|
assertion: {
|
||||||
|
'ui:widget': 'textarea'
|
||||||
|
},
|
||||||
|
wrap: {
|
||||||
|
'ui:widget': 'textarea'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const defaultFormData = {
|
||||||
|
dispatcher: 'state = reducers(${prevState}, ${action});',
|
||||||
|
assertion: 't.deepEqual(state, ${curState});',
|
||||||
|
wrap: `test('reducers', (t) => {
|
||||||
|
\${assertions}
|
||||||
|
});`
|
||||||
|
};
|
|
@ -0,0 +1,21 @@
|
||||||
|
export const name = 'Ava template';
|
||||||
|
|
||||||
|
export const dispatcher = ({ action }) => (
|
||||||
|
`${action};`
|
||||||
|
);
|
||||||
|
|
||||||
|
export const assertion = ({ path, curState }) => (
|
||||||
|
`t.deepEqual(state${path}, ${curState});`
|
||||||
|
);
|
||||||
|
|
||||||
|
export const wrap = ({ name, initialState, assertions }) => (
|
||||||
|
`import test from 'ava';
|
||||||
|
import ${name} from '../../stores/${name}';
|
||||||
|
|
||||||
|
test('${name}', (t) => {
|
||||||
|
const store = new ${name}(${initialState});
|
||||||
|
${assertions}
|
||||||
|
});
|
||||||
|
`);
|
||||||
|
|
||||||
|
export default { name, assertion, dispatcher, wrap };
|
|
@ -0,0 +1,17 @@
|
||||||
|
export const name = 'Ava template';
|
||||||
|
|
||||||
|
export const dispatcher = '${action};';
|
||||||
|
|
||||||
|
export const assertion = 't.deepEqual(state${path}, ${curState});';
|
||||||
|
|
||||||
|
export const wrap = (
|
||||||
|
`import test from 'ava';
|
||||||
|
import \${name} from '../../stores/\${name}';
|
||||||
|
|
||||||
|
test('\${name}', (t) => {
|
||||||
|
const store = new \${name}(\${initialState});
|
||||||
|
\${assertions}
|
||||||
|
});
|
||||||
|
`);
|
||||||
|
|
||||||
|
export default { name, assertion, dispatcher, wrap };
|
|
@ -0,0 +1,21 @@
|
||||||
|
export const name = 'Mocha template';
|
||||||
|
|
||||||
|
export const dispatcher = ({ action }) => (
|
||||||
|
`${action};`
|
||||||
|
);
|
||||||
|
|
||||||
|
export const assertion = ({ path, curState }) => (
|
||||||
|
`expect(store${path}).toEqual(${curState});`
|
||||||
|
);
|
||||||
|
|
||||||
|
export const wrap = ({ name, initialState, assertions }) => (
|
||||||
|
`import expect from 'expect';
|
||||||
|
import ${name} from '../../stores/${name}';
|
||||||
|
|
||||||
|
test('${name}', (t) => {
|
||||||
|
const store = new ${name}(${initialState});
|
||||||
|
${assertions}
|
||||||
|
});
|
||||||
|
`);
|
||||||
|
|
||||||
|
export default { name, assertion, dispatcher, wrap };
|
|
@ -0,0 +1,17 @@
|
||||||
|
export const name = 'Mocha template';
|
||||||
|
|
||||||
|
export const dispatcher = '${action};';
|
||||||
|
|
||||||
|
export const assertion = 'expect(store${path}).toEqual(${curState});';
|
||||||
|
|
||||||
|
export const wrap = (
|
||||||
|
`import expect from 'expect';
|
||||||
|
import \${name} from '../../stores/\${name}';
|
||||||
|
|
||||||
|
test('\${name}', (t) => {
|
||||||
|
const store = new \${name}(\${initialState});
|
||||||
|
\${assertions}
|
||||||
|
});
|
||||||
|
`);
|
||||||
|
|
||||||
|
export default { name, assertion, dispatcher, wrap };
|
|
@ -0,0 +1,23 @@
|
||||||
|
export const name = 'Mocha template';
|
||||||
|
|
||||||
|
export const dispatcher = ({ action }) => (
|
||||||
|
`${action};`
|
||||||
|
);
|
||||||
|
|
||||||
|
export const assertion = ({ path, curState }) => (
|
||||||
|
`expect(store${path}).toEqual(${curState});`
|
||||||
|
);
|
||||||
|
|
||||||
|
export const wrap = ({ name, actionName, initialState, assertions }) => (
|
||||||
|
`import expect from 'expect';
|
||||||
|
import ${name} from '../../stores/${name}';
|
||||||
|
|
||||||
|
describe('${name}', () => {
|
||||||
|
it('${actionName}', () => {
|
||||||
|
const store = new ${name}(${initialState});
|
||||||
|
${assertions}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
`);
|
||||||
|
|
||||||
|
export default { name, assertion, dispatcher, wrap };
|
|
@ -0,0 +1,19 @@
|
||||||
|
export const name = 'Mocha template';
|
||||||
|
|
||||||
|
export const dispatcher = '${action};';
|
||||||
|
|
||||||
|
export const assertion = 'expect(store${path}).toEqual(${curState});';
|
||||||
|
|
||||||
|
export const wrap = (
|
||||||
|
`import expect from 'expect';
|
||||||
|
import \${name} from '../../stores/\${name}';
|
||||||
|
|
||||||
|
describe('\${name}', () => {
|
||||||
|
it('\${actionName}', () => {
|
||||||
|
const store = new \${name}(\${initialState});
|
||||||
|
\${assertions}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
`);
|
||||||
|
|
||||||
|
export default { name, assertion, dispatcher, wrap };
|
|
@ -0,0 +1,22 @@
|
||||||
|
export const name = 'Tape template';
|
||||||
|
|
||||||
|
export const dispatcher = ({ action }) => (
|
||||||
|
`${action};`
|
||||||
|
);
|
||||||
|
|
||||||
|
export const assertion = ({ path, curState }) => (
|
||||||
|
`t.deepEqual(state${path}, ${curState});`
|
||||||
|
);
|
||||||
|
|
||||||
|
export const wrap = ({ name, initialState, assertions }) => (
|
||||||
|
`import test from 'tape';
|
||||||
|
import ${name} from '../../stores/${name}';
|
||||||
|
|
||||||
|
test('${name}', (t) => {
|
||||||
|
const store = new ${name}(${initialState});
|
||||||
|
${assertions}
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
`);
|
||||||
|
|
||||||
|
export default { name, assertion, dispatcher, wrap };
|
|
@ -0,0 +1,18 @@
|
||||||
|
export const name = 'Tape template';
|
||||||
|
|
||||||
|
export const dispatcher = '${action};';
|
||||||
|
|
||||||
|
export const assertion = 't.deepEqual(state${path}, ${curState});';
|
||||||
|
|
||||||
|
export const wrap = (
|
||||||
|
`import test from 'tape';
|
||||||
|
import \${name} from '../../stores/\${name}';
|
||||||
|
|
||||||
|
test('\${name}', (t) => {
|
||||||
|
const store = new \${name}(\${initialState});
|
||||||
|
\${assertions}
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
`);
|
||||||
|
|
||||||
|
export default { name, assertion, dispatcher, wrap };
|
|
@ -0,0 +1,91 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { render } from 'enzyme';
|
||||||
|
import { renderToJson } from 'enzyme-to-json';
|
||||||
|
import TestGenerator from '../src/TestGenerator';
|
||||||
|
import fnTemplate from '../src/redux/mocha';
|
||||||
|
import strTemplate from '../src/redux/mocha/template';
|
||||||
|
import fnVanillaTemplate from '../src/vanilla/mocha';
|
||||||
|
import strVanillaTemplate from '../src/vanilla/mocha/template';
|
||||||
|
|
||||||
|
const actions = {
|
||||||
|
0: { type: 'PERFORM_ACTION', action: { type: '@@INIT' } },
|
||||||
|
1: { type: 'PERFORM_ACTION', action: { type: 'INCREMENT_COUNTER' } }
|
||||||
|
};
|
||||||
|
|
||||||
|
const computedStates = [
|
||||||
|
{ state: { counter: 0 } },
|
||||||
|
{ state: { counter: 1 } }
|
||||||
|
];
|
||||||
|
|
||||||
|
describe('TestGenerator component', () => {
|
||||||
|
it('should show warning message when no params provided', () => {
|
||||||
|
const component = render(<TestGenerator useCodemirror={false} />);
|
||||||
|
expect(renderToJson(component)).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be empty when no actions provided', () => {
|
||||||
|
const component = render(
|
||||||
|
<TestGenerator
|
||||||
|
assertion={fnTemplate.assertion} dispatcher={fnTemplate.dispatcher} wrap={fnTemplate.wrap}
|
||||||
|
useCodemirror={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
expect(renderToJson(component)).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should match function template\'s test for first action', () => {
|
||||||
|
const component = render(
|
||||||
|
<TestGenerator
|
||||||
|
assertion={fnTemplate.assertion} dispatcher={fnTemplate.dispatcher} wrap={fnTemplate.wrap}
|
||||||
|
actions={actions} computedStates={computedStates} selectedActionId={1}
|
||||||
|
useCodemirror={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
expect(renderToJson(component)).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should match string template\'s test for first action', () => {
|
||||||
|
const component = render(
|
||||||
|
<TestGenerator
|
||||||
|
assertion={strTemplate.assertion} dispatcher={strTemplate.dispatcher}
|
||||||
|
wrap={strTemplate.wrap} useCodemirror={false}
|
||||||
|
actions={actions} computedStates={computedStates} selectedActionId={1}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
expect(renderToJson(component)).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should generate test for the last action when selectedActionId not specified', () => {
|
||||||
|
const component = render(
|
||||||
|
<TestGenerator
|
||||||
|
assertion={fnTemplate.assertion} dispatcher={fnTemplate.dispatcher} wrap={fnTemplate.wrap}
|
||||||
|
actions={actions} computedStates={computedStates} useCodemirror={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
expect(renderToJson(component)).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should generate test for vanilla js class', () => {
|
||||||
|
const component = render(
|
||||||
|
<TestGenerator
|
||||||
|
assertion={fnVanillaTemplate.assertion} dispatcher={fnVanillaTemplate.dispatcher}
|
||||||
|
wrap={fnVanillaTemplate.wrap}
|
||||||
|
actions={actions} computedStates={computedStates} selectedActionId={1}
|
||||||
|
isVanilla name="SomeStore" useCodemirror={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
expect(renderToJson(component)).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should generate test for vanilla js class with string template', () => {
|
||||||
|
const component = render(
|
||||||
|
<TestGenerator
|
||||||
|
assertion={strVanillaTemplate.assertion} dispatcher={strVanillaTemplate.dispatcher}
|
||||||
|
wrap={strVanillaTemplate.wrap}
|
||||||
|
actions={actions} computedStates={computedStates} selectedActionId={1}
|
||||||
|
isVanilla name="SomeStore" useCodemirror={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
expect(renderToJson(component)).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,103 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`TestGenerator component should be empty when no actions provided 1`] = `
|
||||||
|
<textarea
|
||||||
|
style="padding:10px;width:100%;height:100%;"
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`TestGenerator component should generate test for the last action when selectedActionId not specified 1`] = `
|
||||||
|
<textarea
|
||||||
|
style="padding:10px;width:100%;height:100%;"
|
||||||
|
>
|
||||||
|
import expect from 'expect';
|
||||||
|
import reducers from '../../reducers';
|
||||||
|
|
||||||
|
describe('reducers', () => {
|
||||||
|
it('should handle actions', () => {
|
||||||
|
let state;
|
||||||
|
state = reducers({counter:0}, {type:'INCREMENT_COUNTER'});
|
||||||
|
expect(state).toEqual({counter:1});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
</textarea>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`TestGenerator component should generate test for vanilla js class 1`] = `
|
||||||
|
<textarea
|
||||||
|
style="padding:10px;width:100%;height:100%;"
|
||||||
|
>
|
||||||
|
import expect from 'expect';
|
||||||
|
import SomeStore from '../../stores/SomeStore';
|
||||||
|
|
||||||
|
describe('SomeStore', () => {
|
||||||
|
it('INCREMENT_COUNTER', () => {
|
||||||
|
const store = new SomeStore({counter:0});
|
||||||
|
INCREMENT_COUNTER();
|
||||||
|
expect(store.counter).toEqual(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
</textarea>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`TestGenerator component should generate test for vanilla js class with string template 1`] = `
|
||||||
|
<textarea
|
||||||
|
style="padding:10px;width:100%;height:100%;"
|
||||||
|
>
|
||||||
|
import expect from 'expect';
|
||||||
|
import SomeStore from '../../stores/SomeStore';
|
||||||
|
|
||||||
|
describe('SomeStore', () => {
|
||||||
|
it('INCREMENT_COUNTER', () => {
|
||||||
|
const store = new SomeStore({counter:0});
|
||||||
|
INCREMENT_COUNTER();
|
||||||
|
expect(store.counter).toEqual(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
</textarea>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`TestGenerator component should match function template's test for first action 1`] = `
|
||||||
|
<textarea
|
||||||
|
style="padding:10px;width:100%;height:100%;"
|
||||||
|
>
|
||||||
|
import expect from 'expect';
|
||||||
|
import reducers from '../../reducers';
|
||||||
|
|
||||||
|
describe('reducers', () => {
|
||||||
|
it('should handle actions', () => {
|
||||||
|
let state;
|
||||||
|
state = reducers({counter:0}, {type:'INCREMENT_COUNTER'});
|
||||||
|
expect(state).toEqual({counter:1});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
</textarea>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`TestGenerator component should match string template's test for first action 1`] = `
|
||||||
|
<textarea
|
||||||
|
style="padding:10px;width:100%;height:100%;"
|
||||||
|
>
|
||||||
|
import expect from 'expect';
|
||||||
|
import reducers from '../../reducers';
|
||||||
|
|
||||||
|
describe('reducers', () => {
|
||||||
|
it('should handle actions', () => {
|
||||||
|
let state;
|
||||||
|
state = reducers({counter:0}, {type:'INCREMENT_COUNTER'});
|
||||||
|
expect(state).toEqual({counter:1});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
</textarea>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`TestGenerator component should show warning message when no params provided 1`] = `
|
||||||
|
<textarea
|
||||||
|
style="padding:10px;width:100%;height:100%;"
|
||||||
|
/>
|
||||||
|
`;
|
|
@ -0,0 +1,85 @@
|
||||||
|
import { assertion } from '../src/vanilla/mocha';
|
||||||
|
import { compare } from '../src/TestGenerator';
|
||||||
|
|
||||||
|
const computedStates = [
|
||||||
|
{ state: { o1: 0 } },
|
||||||
|
{ state: { o1: 0, o2: 1 } },
|
||||||
|
{ state: { o1: 0, o2: 'a' } },
|
||||||
|
{ state: { o1: [{ t: 1 }], o3: { t: 2 } } },
|
||||||
|
{ state: { o1: [{ t: 3 }], o3: { t: 2 } } },
|
||||||
|
{ state: [0, 1, 2, 3, 4] },
|
||||||
|
{ state: [0, 3] },
|
||||||
|
{ state: [0, 2, 3, 4] }
|
||||||
|
];
|
||||||
|
|
||||||
|
const test = (s1, s2) => compare(s1, s2,
|
||||||
|
({ path, curState }) => (
|
||||||
|
expect(`expect(store${path}).toEqual(${curState});`)
|
||||||
|
.toBe(assertion({ path, curState }))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
describe('Assertions', () => {
|
||||||
|
it('should return initial state', () => {
|
||||||
|
test(
|
||||||
|
undefined,
|
||||||
|
computedStates[0]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add element', () => {
|
||||||
|
test(
|
||||||
|
computedStates[0],
|
||||||
|
computedStates[1]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove element', () => {
|
||||||
|
test(
|
||||||
|
computedStates[1],
|
||||||
|
computedStates[0]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should change element', () => {
|
||||||
|
test(
|
||||||
|
computedStates[1],
|
||||||
|
computedStates[2]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add, change and remove elements', () => {
|
||||||
|
test(
|
||||||
|
computedStates[2],
|
||||||
|
computedStates[3]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should change in array', () => {
|
||||||
|
test(
|
||||||
|
computedStates[3],
|
||||||
|
computedStates[4]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove elements in array', () => {
|
||||||
|
test(
|
||||||
|
computedStates[5],
|
||||||
|
computedStates[6]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add elements in array', () => {
|
||||||
|
test(
|
||||||
|
computedStates[6],
|
||||||
|
computedStates[5]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add and change elements in array', () => {
|
||||||
|
test(
|
||||||
|
computedStates[5],
|
||||||
|
computedStates[7]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
84
packages/redux-devtools-test-generator/webpack.config.js
Normal file
84
packages/redux-devtools-test-generator/webpack.config.js
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
const path = require('path');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
const CleanWebpackPlugin = require('clean-webpack-plugin');
|
||||||
|
const ExportFilesWebpackPlugin = require('export-files-webpack-plugin');
|
||||||
|
const NyanProgressWebpackPlugin = require('nyan-progress-webpack-plugin');
|
||||||
|
|
||||||
|
const pkg = require('./package.json');
|
||||||
|
|
||||||
|
const isProduction = process.env.NODE_ENV === 'production';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
devtool: 'eval',
|
||||||
|
entry: isProduction ?
|
||||||
|
['./demo/src/js/index'] :
|
||||||
|
[
|
||||||
|
'webpack-dev-server/client?http://localhost:3000',
|
||||||
|
'webpack/hot/only-dev-server',
|
||||||
|
'./demo/src/js/index'
|
||||||
|
],
|
||||||
|
output: {
|
||||||
|
path: path.join(__dirname, 'demo/dist'),
|
||||||
|
filename: 'js/bundle.js'
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new CleanWebpackPlugin(isProduction ? ['demo/dist'] : []),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
inject: true,
|
||||||
|
template: 'demo/src/index.html',
|
||||||
|
filename: 'index.html',
|
||||||
|
package: pkg
|
||||||
|
}),
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env': {
|
||||||
|
NODE_ENV: JSON.stringify(process.env.NODE_ENV)
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
new NyanProgressWebpackPlugin()
|
||||||
|
].concat(isProduction ? [
|
||||||
|
new webpack.optimize.UglifyJsPlugin({
|
||||||
|
compress: { warnings: false },
|
||||||
|
output: { comments: false }
|
||||||
|
})
|
||||||
|
] : [
|
||||||
|
new ExportFilesWebpackPlugin('demo/dist/index.html'),
|
||||||
|
new webpack.HotModuleReplacementPlugin()
|
||||||
|
]),
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js', '.jsx']
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [{
|
||||||
|
test: /\.jsx?$/,
|
||||||
|
loader: 'babel-loader',
|
||||||
|
include: [
|
||||||
|
path.join(__dirname, 'src'),
|
||||||
|
path.join(__dirname, 'demo/src/js')
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
use: [
|
||||||
|
{ loader: 'style-loader' },
|
||||||
|
{ loader: 'css-loader' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(ttf|eot|svg|woff|woff2)$/,
|
||||||
|
loader: 'file-loader',
|
||||||
|
options: { outputPath: 'fonts/', publicPath: 'fonts/' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
devServer: isProduction ? null : {
|
||||||
|
quiet: false,
|
||||||
|
port: 3001,
|
||||||
|
hot: true,
|
||||||
|
stats: {
|
||||||
|
chunkModules: false,
|
||||||
|
colors: true
|
||||||
|
},
|
||||||
|
historyApiFallback: true
|
||||||
|
}
|
||||||
|
};
|
|
@ -20,7 +20,7 @@
|
||||||
"lint:fix": "eslint --fix src test",
|
"lint:fix": "eslint --fix src test",
|
||||||
"test": "jest --no-cache",
|
"test": "jest --no-cache",
|
||||||
"prepare": "npm run clean && npm run build",
|
"prepare": "npm run clean && npm run build",
|
||||||
"prepublishOnly": "npm run lint && npm run test"
|
"prepublishOnly": "npm run lint && npm run test && npm run clean && npm run build"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-cli": "^6.10.1",
|
"babel-cli": "^6.10.1",
|
||||||
|
|
Loading…
Reference in New Issue
Block a user