mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2024-11-10 19:56:54 +03:00
feature(redux-devtools-test-generator): convert to TypeScript (#634)
* stash * stash * compiles * Tests * finish * fix packages * somemore * update snapshot
This commit is contained in:
parent
d1c222d847
commit
d49535da03
|
@ -18,12 +18,14 @@
|
|||
"babel-loader": "^8.1.0",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"cross-env": "^7.0.2",
|
||||
"css-loader": "^4.2.1",
|
||||
"eslint": "^7.6.0",
|
||||
"eslint-config-prettier": "^6.11.0",
|
||||
"eslint-plugin-babel": "^5.3.1",
|
||||
"eslint-plugin-jest": "^23.20.0",
|
||||
"eslint-plugin-prettier": "^3.1.4",
|
||||
"eslint-plugin-react": "^7.20.5",
|
||||
"file-loader": "^6.0.0",
|
||||
"fork-ts-checker-webpack-plugin": "^5.1.0",
|
||||
"html-webpack-plugin": "^4.3.0",
|
||||
"jest": "^26.2.2",
|
||||
|
|
|
@ -36,6 +36,14 @@
|
|||
"prepublishOnly": "npm run clean && npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/base16": "^1.0.2",
|
||||
"@types/codemirror": "^0.0.97",
|
||||
"@types/prop-types": "^15.7.3",
|
||||
"@types/react-jsonschema-form": "^1.7.4",
|
||||
"@types/react-select": "^3.0.19",
|
||||
"@types/redux-devtools-themes": "^1.0.0",
|
||||
"@types/simple-element-resize-detector": "^1.3.0",
|
||||
"@types/styled-components": "^5.1.2",
|
||||
"base16": "^1.0.0",
|
||||
"codemirror": "^5.56.0",
|
||||
"color": "^3.1.2",
|
||||
|
@ -51,11 +59,8 @@
|
|||
"devDependencies": {
|
||||
"@storybook/addon-essentials": "^6.0.21",
|
||||
"@storybook/react": "^6.0.21",
|
||||
"@types/codemirror": "^0.0.97",
|
||||
"@types/enzyme": "^3.10.5",
|
||||
"@types/enzyme-adapter-react-16": "^1.0.6",
|
||||
"@types/react-jsonschema-form": "^1.7.4",
|
||||
"@types/react-select": "^3.0.19",
|
||||
"csstype": "^3.0.2",
|
||||
"enzyme": "^3.11.0",
|
||||
"enzyme-adapter-react-16": "^1.15.3",
|
||||
|
|
|
@ -44,13 +44,13 @@ function isForm<P>(rest?: FormProps<P>): rest is FormProps<P> {
|
|||
}
|
||||
|
||||
export default class Dialog<P> extends (PureComponent || Component)<
|
||||
DialogProps | (DialogProps & FormProps<P>)
|
||||
DialogProps | (Omit<DialogProps, 'onSubmit'> & FormProps<P>)
|
||||
> {
|
||||
submitButton?: HTMLInputElement | null;
|
||||
|
||||
onSubmit = () => {
|
||||
if (this.submitButton) this.submitButton.click();
|
||||
else this.props.onSubmit();
|
||||
else (this.props.onSubmit as () => void)();
|
||||
};
|
||||
|
||||
getFormButtonRef: React.RefCallback<HTMLInputElement> = (node) => {
|
||||
|
|
|
@ -23,7 +23,7 @@ export interface EditorProps {
|
|||
theme?: Base16Theme;
|
||||
foldGutter: boolean;
|
||||
autofocus: boolean;
|
||||
onChange: (value: string, change: CodeMirror.EditorChangeLinkedList) => void;
|
||||
onChange?: (value: string, change: CodeMirror.EditorChangeLinkedList) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -47,7 +47,7 @@ export default class Editor extends Component<EditorProps> {
|
|||
|
||||
if (this.props.onChange) {
|
||||
this.cm.on('change', (doc, change) => {
|
||||
this.props.onChange(doc.getValue(), change);
|
||||
this.props.onChange!(doc.getValue(), change);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
declare module 'simple-element-resize-detector' {
|
||||
export default function (
|
||||
element: HTMLElement,
|
||||
handler: () => void
|
||||
): HTMLIFrameElement;
|
||||
}
|
|
@ -25,14 +25,7 @@ describe('Editor', function () {
|
|||
|
||||
return range;
|
||||
};
|
||||
const wrapper = mount(
|
||||
<Editor
|
||||
value="var a = 1;"
|
||||
onChange={() => {
|
||||
//noop
|
||||
}}
|
||||
/>
|
||||
);
|
||||
const wrapper = mount(<Editor value="var a = 1;" />);
|
||||
|
||||
it('renders correctly', () => {
|
||||
expect(mountToJson(wrapper)).toMatchSnapshot();
|
||||
|
|
|
@ -7,7 +7,6 @@ exports[`Editor renders correctly 1`] = `
|
|||
lineNumbers={true}
|
||||
lineWrapping={false}
|
||||
mode="javascript"
|
||||
onChange={[Function]}
|
||||
readOnly={false}
|
||||
value="var a = 1;"
|
||||
>
|
||||
|
|
|
@ -2,10 +2,10 @@ import React from 'react';
|
|||
import { connect } from 'react-redux';
|
||||
import { createDevTools } from 'redux-devtools';
|
||||
import DockMonitor from 'redux-devtools-dock-monitor';
|
||||
import { Location } from 'history';
|
||||
import DevtoolsInspector from '../../../src/DevtoolsInspector';
|
||||
import getOptions from './getOptions';
|
||||
import { base16Themes } from '../../../src/utils/createStylingFromTheme';
|
||||
import { Location } from 'history';
|
||||
import { DemoAppState } from './reducers';
|
||||
|
||||
const CustomComponent = () => (
|
||||
|
|
|
@ -194,7 +194,7 @@ const createRootReducer = (
|
|||
): Reducer<DemoAppState, DemoAppAction> =>
|
||||
combineReducers<DemoAppState, DemoAppAction>({
|
||||
router: connectRouter(history) as Reducer<RouterState, DemoAppAction>,
|
||||
timeoutUpdateEnabled: (state = false, action: DemoAppAction) =>
|
||||
timeoutUpdateEnabled: (state = false, action) =>
|
||||
action.type === 'TOGGLE_TIMEOUT_UPDATE'
|
||||
? action.timeoutUpdateEnabled
|
||||
: state,
|
||||
|
@ -207,7 +207,7 @@ const createRootReducer = (
|
|||
// noop
|
||||
}
|
||||
) => state,
|
||||
array: (state = [], action: DemoAppAction) =>
|
||||
array: (state = [], action) =>
|
||||
action.type === 'PUSH'
|
||||
? [...state, Math.random()]
|
||||
: action.type === 'POP'
|
||||
|
@ -215,13 +215,13 @@ const createRootReducer = (
|
|||
: action.type === 'REPLACE'
|
||||
? [Math.random(), ...state.slice(1)]
|
||||
: state,
|
||||
hugeArrays: (state = [], action: DemoAppAction) =>
|
||||
hugeArrays: (state = [], action) =>
|
||||
action.type === 'PUSH_HUGE_ARRAY' ? [...state, ...HUGE_ARRAY] : state,
|
||||
hugeObjects: (state = [], action: DemoAppAction) =>
|
||||
hugeObjects: (state = [], action) =>
|
||||
action.type === 'ADD_HUGE_OBJECT' ? [...state, HUGE_OBJECT] : state,
|
||||
iterators: (state = [], action: DemoAppAction) =>
|
||||
iterators: (state = [], action) =>
|
||||
action.type === 'ADD_ITERATOR' ? [...state, createIterator()] : state,
|
||||
nested: (state = NESTED, action: DemoAppAction) =>
|
||||
nested: (state = NESTED, action) =>
|
||||
action.type === 'CHANGE_NESTED'
|
||||
? {
|
||||
...state,
|
||||
|
@ -238,29 +238,26 @@ const createRootReducer = (
|
|||
},
|
||||
}
|
||||
: state,
|
||||
recursive: (state: { obj?: unknown }[] = [], action: DemoAppAction) =>
|
||||
recursive: (state: { obj?: unknown }[] = [], action) =>
|
||||
action.type === 'ADD_RECURSIVE' ? [...state, { ...RECURSIVE }] : state,
|
||||
immutables: (
|
||||
state: Immutable.Map<string, unknown>[] = [],
|
||||
action: DemoAppAction
|
||||
) =>
|
||||
immutables: (state: Immutable.Map<string, unknown>[] = [], action) =>
|
||||
action.type === 'ADD_IMMUTABLE_MAP' ? [...state, IMMUTABLE_MAP] : state,
|
||||
maps: (state: Map<string, MapValue>[] = [], action: DemoAppAction) =>
|
||||
maps: (state: Map<string, MapValue>[] = [], action) =>
|
||||
action.type === 'ADD_NATIVE_MAP' ? [...state, NATIVE_MAP] : state,
|
||||
immutableNested: (state = IMMUTABLE_NESTED, action: DemoAppAction) =>
|
||||
immutableNested: (state = IMMUTABLE_NESTED, action) =>
|
||||
action.type === 'CHANGE_IMMUTABLE_NESTED'
|
||||
? state.updateIn(
|
||||
['long', 'nested', 0, 'path', 'to', 'a'],
|
||||
(str: string) => str + '!'
|
||||
)
|
||||
: state,
|
||||
addFunction: (state = null, action: DemoAppAction) =>
|
||||
addFunction: (state = null, action) =>
|
||||
action.type === 'ADD_FUNCTION' ? { f: FUNC } : state,
|
||||
addSymbol: (state = null, action: DemoAppAction) =>
|
||||
addSymbol: (state = null, action) =>
|
||||
action.type === 'ADD_SYMBOL'
|
||||
? { s: window.Symbol('symbol'), error: new Error('TEST') }
|
||||
: state,
|
||||
shuffleArray: (state = DEFAULT_SHUFFLE_ARRAY, action: DemoAppAction) =>
|
||||
shuffleArray: (state = DEFAULT_SHUFFLE_ARRAY, action) =>
|
||||
action.type === 'SHUFFLE_ARRAY' ? shuffle(state) : state,
|
||||
});
|
||||
|
||||
|
|
|
@ -53,11 +53,9 @@
|
|||
"redux-devtools-themes": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/runtime": "^7.11.2",
|
||||
"@types/dateformat": "^3.0.1",
|
||||
"@types/hex-rgba": "^1.0.0",
|
||||
"@types/history": "^4.7.7",
|
||||
"@types/lodash.debounce": "^4.0.6",
|
||||
"@types/lodash.shuffle": "^4.2.6",
|
||||
"@types/react": "^16.9.46",
|
||||
"@types/react-dragula": "^1.1.0",
|
||||
|
@ -67,7 +65,6 @@
|
|||
"connected-react-router": "^6.8.0",
|
||||
"history": "^4.10.1",
|
||||
"immutable": "^4.0.0-rc.12",
|
||||
"lodash.isequalwith": "^4.4.0",
|
||||
"lodash.shuffle": "^4.2.0",
|
||||
"react": "^16.13.1",
|
||||
"react-bootstrap": "^1.3.0",
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
import DevtoolsInspector from './DevtoolsInspector';
|
||||
export default DevtoolsInspector;
|
||||
export { Tab, TabComponentProps } from './ActionPreview';
|
||||
export { DevtoolsInspectorState } from './redux';
|
||||
export { base16Themes } from './utils/createStylingFromTheme';
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
{
|
||||
"presets": ["@babel/preset-env", "@babel/preset-react"],
|
||||
"presets": [
|
||||
"@babel/preset-env",
|
||||
"@babel/preset-react",
|
||||
"@babel/preset-typescript"
|
||||
],
|
||||
"plugins": [
|
||||
"@babel/plugin-proposal-class-properties",
|
||||
"@babel/plugin-proposal-do-expressions"
|
||||
"@babel/plugin-transform-runtime"
|
||||
]
|
||||
}
|
||||
|
|
1
packages/redux-devtools-test-generator/.eslintignore
Normal file
1
packages/redux-devtools-test-generator/.eslintignore
Normal file
|
@ -0,0 +1 @@
|
|||
lib
|
37
packages/redux-devtools-test-generator/.eslintrc.js
Normal file
37
packages/redux-devtools-test-generator/.eslintrc.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
module.exports = {
|
||||
extends: '../../.eslintrc',
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.ts', '*.tsx'],
|
||||
extends: '../../eslintrc.ts.react.base.json',
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['./tsconfig.json'],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['demo/**/*.ts', 'demo/**/*.tsx'],
|
||||
extends: '../../eslintrc.ts.react.base.json',
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['./demo/tsconfig.json'],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['demo/config/webpack.config.ts'],
|
||||
extends: '../../eslintrc.ts.base.json',
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['./demo/config/tsconfig.json'],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['test/*.ts', 'test/*.tsx'],
|
||||
extends: '../../eslintrc.ts.react.jest.base.json',
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['./test/tsconfig.json'],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
|
@ -29,7 +29,7 @@ const testComponent = (props) => (
|
|||
);
|
||||
|
||||
export default createDevTools(
|
||||
<Inspector
|
||||
<InspectorMonitor
|
||||
tabs: defaultTabs => [...defaultTabs, { name: 'Test', component: testComponent }]
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"extends": "../../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"include": ["webpack.config.ts"]
|
||||
}
|
|
@ -1,14 +1,14 @@
|
|||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||
|
||||
const pkg = require('./package.json');
|
||||
import * as path from 'path';
|
||||
import * as webpack from 'webpack';
|
||||
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
||||
import { CleanWebpackPlugin } from 'clean-webpack-plugin';
|
||||
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
|
||||
import pkg from '../../package.json';
|
||||
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
|
||||
module.exports = {
|
||||
devtool: 'eval-source-map',
|
||||
mode: process.env.NODE_ENV || 'development',
|
||||
entry: isProduction
|
||||
? ['./demo/src/js/index']
|
||||
: [
|
||||
|
@ -20,39 +20,14 @@ module.exports = {
|
|||
path: path.join(__dirname, 'demo/dist'),
|
||||
filename: 'js/bundle.js',
|
||||
},
|
||||
plugins: [
|
||||
new CleanWebpackPlugin(),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
template: 'demo/src/index.html',
|
||||
package: pkg,
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
NODE_ENV: JSON.stringify(process.env.NODE_ENV),
|
||||
},
|
||||
}),
|
||||
].concat(
|
||||
isProduction
|
||||
? [
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
compress: { warnings: false },
|
||||
output: { comments: false },
|
||||
}),
|
||||
]
|
||||
: [new webpack.HotModuleReplacementPlugin()]
|
||||
),
|
||||
resolve: {
|
||||
extensions: ['.js', '.jsx'],
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
test: /\.(js|ts)x?$/,
|
||||
loader: 'babel-loader',
|
||||
include: [
|
||||
path.join(__dirname, 'src'),
|
||||
path.join(__dirname, 'demo/src/js'),
|
||||
path.join(__dirname, '../../src'),
|
||||
path.join(__dirname, '../src/js'),
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -66,6 +41,22 @@ module.exports = {
|
|||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
||||
},
|
||||
plugins: [
|
||||
new CleanWebpackPlugin(),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
template: 'demo/src/index.html',
|
||||
package: pkg,
|
||||
}),
|
||||
new ForkTsCheckerWebpackPlugin({
|
||||
typescript: {
|
||||
configFile: 'demo/tsconfig.json',
|
||||
},
|
||||
}),
|
||||
].concat(isProduction ? [] : [new webpack.HotModuleReplacementPlugin()]),
|
||||
devServer: isProduction
|
||||
? null
|
||||
: {
|
||||
|
@ -78,4 +69,5 @@ module.exports = {
|
|||
},
|
||||
historyApiFallback: true,
|
||||
},
|
||||
devtool: 'eval-source-map',
|
||||
};
|
|
@ -1,11 +1,35 @@
|
|||
import React from 'react';
|
||||
import React, { CSSProperties } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import pkg from '../../../package.json';
|
||||
import { Button, Toolbar, Spacer } from 'devui';
|
||||
import getOptions from './getOptions';
|
||||
import { push as pushRoute } from 'connected-react-router';
|
||||
import pkg from '../../../package.json';
|
||||
import getOptions from './getOptions';
|
||||
import { DemoAppState } from './reducers';
|
||||
import {
|
||||
AddFunctionAction,
|
||||
AddHugeObjectAction,
|
||||
AddImmutableMapAction,
|
||||
AddIteratorAction,
|
||||
AddRecursiveAction,
|
||||
AddSymbolAction,
|
||||
ChangeImmutableNestedAction,
|
||||
ChangeNestedAction,
|
||||
HugePayloadAction,
|
||||
IncrementAction,
|
||||
PopAction,
|
||||
PushAction,
|
||||
PushHugeArrayAction,
|
||||
ReplaceAction,
|
||||
ShuffleArrayAction,
|
||||
TimeoutUpdateAction,
|
||||
ToggleTimeoutUpdateAction,
|
||||
} from './reducers';
|
||||
|
||||
const styles = {
|
||||
const styles: {
|
||||
wrapper: CSSProperties;
|
||||
muted: CSSProperties;
|
||||
link: CSSProperties;
|
||||
} = {
|
||||
wrapper: {
|
||||
height: '100vh',
|
||||
width: '450px',
|
||||
|
@ -24,7 +48,30 @@ const styles = {
|
|||
|
||||
const ROOT = '/'; // process.env.NODE_ENV === 'production' ? '/' : '/';
|
||||
|
||||
class DemoApp extends React.Component {
|
||||
interface Props
|
||||
extends Omit<DemoAppState, 'addFunction' | 'addSymbol' | 'shuffleArray'> {
|
||||
toggleTimeoutUpdate: (timeoutUpdateEnabled: boolean) => void;
|
||||
timeoutUpdate: () => void;
|
||||
increment: () => void;
|
||||
push: () => void;
|
||||
pop: () => void;
|
||||
replace: () => void;
|
||||
changeNested: () => void;
|
||||
pushHugeArray: () => void;
|
||||
addIterator: () => void;
|
||||
addHugeObject: () => void;
|
||||
addRecursive: () => void;
|
||||
addImmutableMap: () => void;
|
||||
changeImmutableNested: () => void;
|
||||
hugePayload: () => void;
|
||||
addFunction: () => void;
|
||||
addSymbol: () => void;
|
||||
shuffleArray: () => void;
|
||||
}
|
||||
|
||||
class DemoApp extends React.Component<Props> {
|
||||
timeout?: number;
|
||||
|
||||
render() {
|
||||
const options = getOptions(this.props.router.location);
|
||||
|
||||
|
@ -48,7 +95,7 @@ class DemoApp extends React.Component {
|
|||
<Toolbar>
|
||||
<Spacer />
|
||||
<Button onClick={this.props.pushHugeArray}>Push Huge Array</Button>
|
||||
<Button onClick={this.props.addHugeObect}>Add Huge Object</Button>
|
||||
<Button onClick={this.props.addHugeObject}>Add Huge Object</Button>
|
||||
<Button onClick={this.props.hugePayload}>Huge Payload</Button>
|
||||
<Spacer />
|
||||
</Toolbar>
|
||||
|
@ -98,36 +145,40 @@ class DemoApp extends React.Component {
|
|||
this.props.toggleTimeoutUpdate(enabled);
|
||||
|
||||
if (enabled) {
|
||||
this.timeout = setInterval(this.props.timeoutUpdate, 1000);
|
||||
this.timeout = window.setInterval(this.props.timeoutUpdate, 1000);
|
||||
} else {
|
||||
clearTimeout(this.timeout);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default connect((state) => state, {
|
||||
toggleTimeoutUpdate: (timeoutUpdateEnabled) => ({
|
||||
export default connect((state: DemoAppState) => state, {
|
||||
toggleTimeoutUpdate: (
|
||||
timeoutUpdateEnabled: boolean
|
||||
): ToggleTimeoutUpdateAction => ({
|
||||
type: 'TOGGLE_TIMEOUT_UPDATE',
|
||||
timeoutUpdateEnabled,
|
||||
}),
|
||||
timeoutUpdate: () => ({ type: 'TIMEOUT_UPDATE' }),
|
||||
increment: () => ({ type: 'INCREMENT' }),
|
||||
push: () => ({ type: 'PUSH' }),
|
||||
pop: () => ({ type: 'POP' }),
|
||||
replace: () => ({ type: 'REPLACE' }),
|
||||
changeNested: () => ({ type: 'CHANGE_NESTED' }),
|
||||
pushHugeArray: () => ({ type: 'PUSH_HUGE_ARRAY' }),
|
||||
addIterator: () => ({ type: 'ADD_ITERATOR' }),
|
||||
addHugeObect: () => ({ type: 'ADD_HUGE_OBJECT' }),
|
||||
addRecursive: () => ({ type: 'ADD_RECURSIVE' }),
|
||||
addImmutableMap: () => ({ type: 'ADD_IMMUTABLE_MAP' }),
|
||||
changeImmutableNested: () => ({ type: 'CHANGE_IMMUTABLE_NESTED' }),
|
||||
hugePayload: () => ({
|
||||
timeoutUpdate: (): TimeoutUpdateAction => ({ type: 'TIMEOUT_UPDATE' }),
|
||||
increment: (): IncrementAction => ({ type: 'INCREMENT' }),
|
||||
push: (): PushAction => ({ type: 'PUSH' }),
|
||||
pop: (): PopAction => ({ type: 'POP' }),
|
||||
replace: (): ReplaceAction => ({ type: 'REPLACE' }),
|
||||
changeNested: (): ChangeNestedAction => ({ type: 'CHANGE_NESTED' }),
|
||||
pushHugeArray: (): PushHugeArrayAction => ({ type: 'PUSH_HUGE_ARRAY' }),
|
||||
addIterator: (): AddIteratorAction => ({ type: 'ADD_ITERATOR' }),
|
||||
addHugeObject: (): AddHugeObjectAction => ({ type: 'ADD_HUGE_OBJECT' }),
|
||||
addRecursive: (): AddRecursiveAction => ({ type: 'ADD_RECURSIVE' }),
|
||||
addImmutableMap: (): AddImmutableMapAction => ({ type: 'ADD_IMMUTABLE_MAP' }),
|
||||
changeImmutableNested: (): ChangeImmutableNestedAction => ({
|
||||
type: 'CHANGE_IMMUTABLE_NESTED',
|
||||
}),
|
||||
hugePayload: (): HugePayloadAction => ({
|
||||
type: 'HUGE_PAYLOAD',
|
||||
payload: Array.from({ length: 10000 }).map((_, i) => i),
|
||||
}),
|
||||
addFunction: () => ({ type: 'ADD_FUNCTION' }),
|
||||
addSymbol: () => ({ type: 'ADD_SYMBOL' }),
|
||||
shuffleArray: () => ({ type: 'SHUFFLE_ARRAY' }),
|
||||
addFunction: (): AddFunctionAction => ({ type: 'ADD_FUNCTION' }),
|
||||
addSymbol: (): AddSymbolAction => ({ type: 'ADD_SYMBOL' }),
|
||||
shuffleArray: (): ShuffleArrayAction => ({ type: 'SHUFFLE_ARRAY' }),
|
||||
pushRoute,
|
||||
})(DemoApp);
|
|
@ -1,12 +1,18 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createDevTools } from 'redux-devtools';
|
||||
import InspectorMonitor from 'redux-devtools-inspector-monitor';
|
||||
import InspectorMonitor, {
|
||||
base16Themes,
|
||||
Tab,
|
||||
} from 'redux-devtools-inspector-monitor';
|
||||
import DockMonitor from 'redux-devtools-dock-monitor';
|
||||
import { Location } from 'history';
|
||||
import getOptions from './getOptions';
|
||||
import TestGenerator from '../../../src';
|
||||
import { DemoAppState } from './reducers';
|
||||
import { Action } from 'redux';
|
||||
|
||||
export const getDevTools = (location) =>
|
||||
export const getDevTools = (location: { search: string }) =>
|
||||
createDevTools(
|
||||
<DockMonitor
|
||||
defaultIsVisible
|
||||
|
@ -15,27 +21,28 @@ export const getDevTools = (location) =>
|
|||
changeMonitorKey="ctrl-m"
|
||||
>
|
||||
<InspectorMonitor
|
||||
theme={getOptions(location).theme}
|
||||
shouldPersistState
|
||||
theme={getOptions(location).theme as keyof typeof base16Themes}
|
||||
invertTheme={!getOptions(location).dark}
|
||||
supportImmutable={getOptions(location).supportImmutable}
|
||||
tabs={(defaultTabs) => [
|
||||
{
|
||||
name: 'Test',
|
||||
component: TestGenerator,
|
||||
},
|
||||
...defaultTabs,
|
||||
]}
|
||||
tabs={(defaultTabs) =>
|
||||
[
|
||||
{
|
||||
name: 'Test',
|
||||
component: TestGenerator,
|
||||
},
|
||||
...defaultTabs,
|
||||
] as Tab<unknown, Action<unknown>>[]
|
||||
}
|
||||
/>
|
||||
</DockMonitor>
|
||||
);
|
||||
|
||||
const UnconnectedDevTools = ({ location }) => {
|
||||
const UnconnectedDevTools = ({ location }: { location: Location }) => {
|
||||
const DevTools = getDevTools(location);
|
||||
return <DevTools />;
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
const mapStateToProps = (state: DemoAppState) => ({
|
||||
location: state.router.location,
|
||||
});
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
export default function getOptions(location) {
|
||||
return {
|
||||
useExtension: location.search.indexOf('ext') !== -1,
|
||||
supportImmutable: location.search.indexOf('immutable') !== -1,
|
||||
theme: do {
|
||||
const match = location.search.match(/theme=([^&]+)/);
|
||||
match ? match[1] : 'inspector';
|
||||
},
|
||||
dark: location.search.indexOf('dark') !== -1,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
export interface Options {
|
||||
useExtension: boolean;
|
||||
supportImmutable: boolean;
|
||||
theme: string;
|
||||
dark: boolean;
|
||||
}
|
||||
|
||||
export default function getOptions(location: { search: string }) {
|
||||
return {
|
||||
useExtension: location.search.indexOf('ext') !== -1,
|
||||
supportImmutable: location.search.indexOf('immutable') !== -1,
|
||||
theme: getTheme(),
|
||||
dark: location.search.indexOf('dark') !== -1,
|
||||
};
|
||||
}
|
||||
|
||||
function getTheme() {
|
||||
const match = /theme=([^&]+)/.exec(location.search);
|
||||
return match ? match[1] : 'inspector';
|
||||
}
|
|
@ -1,22 +1,27 @@
|
|||
import '@babel/polyfill';
|
||||
import 'devui/lib/presets';
|
||||
import React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import { Container } from 'devui';
|
||||
import DemoApp from './DemoApp';
|
||||
import { Provider } from 'react-redux';
|
||||
import createRootReducer from './reducers';
|
||||
import { createStore, applyMiddleware, compose } from 'redux';
|
||||
import {
|
||||
createStore,
|
||||
applyMiddleware,
|
||||
compose,
|
||||
StoreEnhancer,
|
||||
StoreEnhancerStoreCreator,
|
||||
} from 'redux';
|
||||
import logger from 'redux-logger';
|
||||
import { Route } from 'react-router';
|
||||
import { createBrowserHistory } from 'history';
|
||||
import { ConnectedRouter, routerMiddleware } from 'connected-react-router';
|
||||
import { persistState } from 'redux-devtools';
|
||||
import DemoApp from './DemoApp';
|
||||
import createRootReducer from './reducers';
|
||||
import getOptions from './getOptions';
|
||||
import { ConnectedDevTools, getDevTools } from './DevTools';
|
||||
|
||||
function getDebugSessionKey() {
|
||||
const matches = window.location.href.match(/[?&]debug_session=([^&#]+)\b/);
|
||||
const matches = /[?&]debug_session=([^&#]+)\b/.exec(window.location.href);
|
||||
return matches && matches.length > 0 ? matches[1] : null;
|
||||
}
|
||||
|
||||
|
@ -30,21 +35,23 @@ const DevTools = getDevTools(window.location);
|
|||
const history = createBrowserHistory();
|
||||
|
||||
const useDevtoolsExtension =
|
||||
!!window.__REDUX_DEVTOOLS_EXTENSION__ &&
|
||||
!!((window as unknown) as { __REDUX_DEVTOOLS_EXTENSION__: unknown }) &&
|
||||
getOptions(window.location).useExtension;
|
||||
|
||||
const enhancer = compose(
|
||||
applyMiddleware(logger, routerMiddleware(history)),
|
||||
(...args) => {
|
||||
(next: StoreEnhancerStoreCreator) => {
|
||||
const instrument = useDevtoolsExtension
|
||||
? window.__REDUX_DEVTOOLS_EXTENSION__()
|
||||
? ((window as unknown) as {
|
||||
__REDUX_DEVTOOLS_EXTENSION__(): StoreEnhancer;
|
||||
}).__REDUX_DEVTOOLS_EXTENSION__()
|
||||
: DevTools.instrument();
|
||||
return instrument(...args);
|
||||
return instrument(next);
|
||||
},
|
||||
persistState(getDebugSessionKey())
|
||||
);
|
||||
|
||||
const store = createStore(createRootReducer(history), {}, enhancer);
|
||||
const store = createStore(createRootReducer(history), enhancer);
|
||||
|
||||
render(
|
||||
<Provider store={store}>
|
|
@ -1,125 +0,0 @@
|
|||
import Immutable from 'immutable';
|
||||
import shuffle from 'lodash.shuffle';
|
||||
import { combineReducers } from 'redux';
|
||||
import { connectRouter } from 'connected-react-router';
|
||||
|
||||
const NESTED = {
|
||||
long: {
|
||||
nested: [
|
||||
{
|
||||
path: {
|
||||
to: {
|
||||
a: 'key',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const IMMUTABLE_NESTED = Immutable.fromJS(NESTED);
|
||||
|
||||
/* eslint-disable babel/new-cap */
|
||||
|
||||
const IMMUTABLE_MAP = Immutable.Map({
|
||||
map: Immutable.Map({ a: 1, b: 2, c: 3 }),
|
||||
list: Immutable.List(['a', 'b', 'c']),
|
||||
set: Immutable.Set(['a', 'b', 'c']),
|
||||
stack: Immutable.Stack(['a', 'b', 'c']),
|
||||
seq: Immutable.Seq([1, 2, 3, 4, 5, 6, 7, 8]),
|
||||
});
|
||||
|
||||
/* eslint-enable babel/new-cap */
|
||||
|
||||
const HUGE_ARRAY = Array.from({ length: 5000 }).map((_, key) => ({
|
||||
str: 'key ' + key,
|
||||
}));
|
||||
|
||||
const HUGE_OBJECT = Array.from({ length: 5000 }).reduce(
|
||||
(o, _, key) => ((o['key ' + key] = 'item ' + key), o),
|
||||
{}
|
||||
);
|
||||
|
||||
const FUNC = function (a, b, c) {
|
||||
return a + b + c;
|
||||
};
|
||||
|
||||
const RECURSIVE = {};
|
||||
RECURSIVE.obj = RECURSIVE;
|
||||
|
||||
function createIterator() {
|
||||
const iterable = {};
|
||||
iterable[window.Symbol.iterator] = function* iterator() {
|
||||
for (var i = 0; i < 333; i++) {
|
||||
yield 'item ' + i;
|
||||
}
|
||||
};
|
||||
|
||||
return iterable;
|
||||
}
|
||||
|
||||
const DEFAULT_SHUFFLE_ARRAY = [0, 1, null, { id: 1 }, { id: 2 }, 'string'];
|
||||
|
||||
const createRootReducer = (history) =>
|
||||
combineReducers({
|
||||
router: connectRouter(history),
|
||||
timeoutUpdateEnabled: (state = false, action) =>
|
||||
action.type === 'TOGGLE_TIMEOUT_UPDATE'
|
||||
? action.timeoutUpdateEnabled
|
||||
: state,
|
||||
store: (state = 0, action) =>
|
||||
action.type === 'INCREMENT' ? state + 1 : state,
|
||||
undefined: (state = { val: undefined }) => state,
|
||||
null: (state = null) => state,
|
||||
func: (state = () => {}) => state,
|
||||
array: (state = [], action) =>
|
||||
action.type === 'PUSH'
|
||||
? [...state, Math.random()]
|
||||
: action.type === 'POP'
|
||||
? state.slice(0, state.length - 1)
|
||||
: action.type === 'REPLACE'
|
||||
? [Math.random(), ...state.slice(1)]
|
||||
: state,
|
||||
hugeArrays: (state = [], action) =>
|
||||
action.type === 'PUSH_HUGE_ARRAY' ? [...state, ...HUGE_ARRAY] : state,
|
||||
hugeObjects: (state = [], action) =>
|
||||
action.type === 'ADD_HUGE_OBJECT' ? [...state, HUGE_OBJECT] : state,
|
||||
iterators: (state = [], action) =>
|
||||
action.type === 'ADD_ITERATOR' ? [...state, createIterator()] : state,
|
||||
nested: (state = NESTED, action) =>
|
||||
action.type === 'CHANGE_NESTED'
|
||||
? {
|
||||
...state,
|
||||
long: {
|
||||
nested: [
|
||||
{
|
||||
path: {
|
||||
to: {
|
||||
a: state.long.nested[0].path.to.a + '!',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
: state,
|
||||
recursive: (state = [], action) =>
|
||||
action.type === 'ADD_RECURSIVE' ? [...state, { ...RECURSIVE }] : state,
|
||||
immutables: (state = [], action) =>
|
||||
action.type === 'ADD_IMMUTABLE_MAP' ? [...state, IMMUTABLE_MAP] : state,
|
||||
immutableNested: (state = IMMUTABLE_NESTED, action) =>
|
||||
action.type === 'CHANGE_IMMUTABLE_NESTED'
|
||||
? state.updateIn(
|
||||
['long', 'nested', 0, 'path', 'to', 'a'],
|
||||
(str) => str + '!'
|
||||
)
|
||||
: state,
|
||||
addFunction: (state = null, action) =>
|
||||
action.type === 'ADD_FUNCTION' ? { f: FUNC } : state,
|
||||
addSymbol: (state = null, action) =>
|
||||
action.type === 'ADD_SYMBOL' ? { s: window.Symbol('symbol') } : state,
|
||||
shuffleArray: (state = DEFAULT_SHUFFLE_ARRAY, action) =>
|
||||
action.type === 'SHUFFLE_ARRAY' ? shuffle(state) : state,
|
||||
});
|
||||
|
||||
export default createRootReducer;
|
232
packages/redux-devtools-test-generator/demo/src/js/reducers.ts
Normal file
232
packages/redux-devtools-test-generator/demo/src/js/reducers.ts
Normal file
|
@ -0,0 +1,232 @@
|
|||
import Immutable from 'immutable';
|
||||
import shuffle from 'lodash.shuffle';
|
||||
import { combineReducers, Reducer } from 'redux';
|
||||
import {
|
||||
connectRouter,
|
||||
LocationChangeAction,
|
||||
RouterState,
|
||||
} from 'connected-react-router';
|
||||
import { History } from 'history';
|
||||
|
||||
type Nested = { long: { nested: { path: { to: { a: string } } }[] } };
|
||||
|
||||
const NESTED = {
|
||||
long: {
|
||||
nested: [
|
||||
{
|
||||
path: {
|
||||
to: {
|
||||
a: 'key',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const IMMUTABLE_NESTED = Immutable.fromJS(NESTED);
|
||||
|
||||
const IMMUTABLE_MAP = Immutable.Map({
|
||||
map: Immutable.Map({ a: 1, b: 2, c: 3 }),
|
||||
list: Immutable.List(['a', 'b', 'c']),
|
||||
set: Immutable.Set(['a', 'b', 'c']),
|
||||
stack: Immutable.Stack(['a', 'b', 'c']),
|
||||
seq: Immutable.Seq([1, 2, 3, 4, 5, 6, 7, 8]),
|
||||
});
|
||||
|
||||
const HUGE_ARRAY = Array.from({ length: 5000 }).map((_, key) => ({
|
||||
str: `key ${key}`,
|
||||
}));
|
||||
|
||||
const HUGE_OBJECT = Array.from({ length: 5000 }).reduce(
|
||||
(o: { [key: string]: string }, _, key) => (
|
||||
(o[`key ${key}`] = `item ${key}`), o
|
||||
),
|
||||
{}
|
||||
);
|
||||
|
||||
const FUNC = function (a: number, b: number, c: number) {
|
||||
return a + b + c;
|
||||
};
|
||||
|
||||
const RECURSIVE: { obj?: unknown } = {};
|
||||
RECURSIVE.obj = RECURSIVE;
|
||||
|
||||
function createIterator() {
|
||||
const iterable: { [Symbol.iterator](): IterableIterator<string> } = {
|
||||
[Symbol.iterator]: function* iterator() {
|
||||
for (let i = 0; i < 333; i++) {
|
||||
yield `item ${i}`;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
return iterable;
|
||||
}
|
||||
|
||||
const DEFAULT_SHUFFLE_ARRAY = [0, 1, null, { id: 1 }, { id: 2 }, 'string'];
|
||||
|
||||
export interface ToggleTimeoutUpdateAction {
|
||||
type: 'TOGGLE_TIMEOUT_UPDATE';
|
||||
timeoutUpdateEnabled: boolean;
|
||||
}
|
||||
export interface TimeoutUpdateAction {
|
||||
type: 'TIMEOUT_UPDATE';
|
||||
}
|
||||
export interface IncrementAction {
|
||||
type: 'INCREMENT';
|
||||
}
|
||||
export interface PushAction {
|
||||
type: 'PUSH';
|
||||
}
|
||||
export interface PopAction {
|
||||
type: 'POP';
|
||||
}
|
||||
export interface ReplaceAction {
|
||||
type: 'REPLACE';
|
||||
}
|
||||
export interface ChangeNestedAction {
|
||||
type: 'CHANGE_NESTED';
|
||||
}
|
||||
export interface PushHugeArrayAction {
|
||||
type: 'PUSH_HUGE_ARRAY';
|
||||
}
|
||||
export interface AddIteratorAction {
|
||||
type: 'ADD_ITERATOR';
|
||||
}
|
||||
export interface AddHugeObjectAction {
|
||||
type: 'ADD_HUGE_OBJECT';
|
||||
}
|
||||
export interface AddRecursiveAction {
|
||||
type: 'ADD_RECURSIVE';
|
||||
}
|
||||
export interface AddImmutableMapAction {
|
||||
type: 'ADD_IMMUTABLE_MAP';
|
||||
}
|
||||
export interface ChangeImmutableNestedAction {
|
||||
type: 'CHANGE_IMMUTABLE_NESTED';
|
||||
}
|
||||
export interface HugePayloadAction {
|
||||
type: 'HUGE_PAYLOAD';
|
||||
payload: number[];
|
||||
}
|
||||
export interface AddFunctionAction {
|
||||
type: 'ADD_FUNCTION';
|
||||
}
|
||||
export interface AddSymbolAction {
|
||||
type: 'ADD_SYMBOL';
|
||||
}
|
||||
export interface ShuffleArrayAction {
|
||||
type: 'SHUFFLE_ARRAY';
|
||||
}
|
||||
type DemoAppAction =
|
||||
| ToggleTimeoutUpdateAction
|
||||
| TimeoutUpdateAction
|
||||
| IncrementAction
|
||||
| PushAction
|
||||
| PopAction
|
||||
| ReplaceAction
|
||||
| ChangeNestedAction
|
||||
| PushHugeArrayAction
|
||||
| AddIteratorAction
|
||||
| AddHugeObjectAction
|
||||
| AddRecursiveAction
|
||||
| AddImmutableMapAction
|
||||
| ChangeImmutableNestedAction
|
||||
| HugePayloadAction
|
||||
| AddFunctionAction
|
||||
| AddSymbolAction
|
||||
| ShuffleArrayAction
|
||||
| LocationChangeAction;
|
||||
|
||||
export interface DemoAppState {
|
||||
router: RouterState;
|
||||
timeoutUpdateEnabled: boolean;
|
||||
store: number;
|
||||
undefined: { val: undefined };
|
||||
null: null;
|
||||
func: () => void;
|
||||
array: number[];
|
||||
hugeArrays: { str: string }[];
|
||||
hugeObjects: { [key: string]: string }[];
|
||||
iterators: { [Symbol.iterator](): IterableIterator<string> }[];
|
||||
nested: Nested;
|
||||
recursive: { obj?: unknown }[];
|
||||
immutables: Immutable.Map<string, unknown>[];
|
||||
immutableNested: Immutable.Map<unknown, unknown>;
|
||||
addFunction: { f: (a: number, b: number, c: number) => number } | null;
|
||||
addSymbol: { s: symbol; error: Error } | null;
|
||||
shuffleArray: unknown[];
|
||||
}
|
||||
|
||||
const createRootReducer = (
|
||||
history: History
|
||||
): Reducer<DemoAppState, DemoAppAction> =>
|
||||
combineReducers<DemoAppState, DemoAppAction>({
|
||||
router: connectRouter(history) as Reducer<RouterState, DemoAppAction>,
|
||||
timeoutUpdateEnabled: (state = false, action) =>
|
||||
action.type === 'TOGGLE_TIMEOUT_UPDATE'
|
||||
? action.timeoutUpdateEnabled
|
||||
: state,
|
||||
store: (state = 0, action) =>
|
||||
action.type === 'INCREMENT' ? state + 1 : state,
|
||||
undefined: (state = { val: undefined }) => state,
|
||||
null: (state = null) => state,
|
||||
func: (
|
||||
state = () => {
|
||||
// noop
|
||||
}
|
||||
) => state,
|
||||
array: (state = [], action) =>
|
||||
action.type === 'PUSH'
|
||||
? [...state, Math.random()]
|
||||
: action.type === 'POP'
|
||||
? state.slice(0, state.length - 1)
|
||||
: action.type === 'REPLACE'
|
||||
? [Math.random(), ...state.slice(1)]
|
||||
: state,
|
||||
hugeArrays: (state = [], action) =>
|
||||
action.type === 'PUSH_HUGE_ARRAY' ? [...state, ...HUGE_ARRAY] : state,
|
||||
hugeObjects: (state = [], action) =>
|
||||
action.type === 'ADD_HUGE_OBJECT' ? [...state, HUGE_OBJECT] : state,
|
||||
iterators: (state = [], action) =>
|
||||
action.type === 'ADD_ITERATOR' ? [...state, createIterator()] : state,
|
||||
nested: (state = NESTED, action) =>
|
||||
action.type === 'CHANGE_NESTED'
|
||||
? {
|
||||
...state,
|
||||
long: {
|
||||
nested: [
|
||||
{
|
||||
path: {
|
||||
to: {
|
||||
a: state.long.nested[0].path.to.a + '!',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
: state,
|
||||
recursive: (state = [], action) =>
|
||||
action.type === 'ADD_RECURSIVE' ? [...state, { ...RECURSIVE }] : state,
|
||||
immutables: (state = [], action) =>
|
||||
action.type === 'ADD_IMMUTABLE_MAP' ? [...state, IMMUTABLE_MAP] : state,
|
||||
immutableNested: (state = IMMUTABLE_NESTED, action) =>
|
||||
action.type === 'CHANGE_IMMUTABLE_NESTED'
|
||||
? state.updateIn(
|
||||
['long', 'nested', 0, 'path', 'to', 'a'],
|
||||
(str: string) => str + '!'
|
||||
)
|
||||
: state,
|
||||
addFunction: (state = null, action) =>
|
||||
action.type === 'ADD_FUNCTION' ? { f: FUNC } : state,
|
||||
addSymbol: (state = null, action) =>
|
||||
action.type === 'ADD_SYMBOL'
|
||||
? { s: window.Symbol('symbol'), error: new Error('TEST') }
|
||||
: state,
|
||||
shuffleArray: (state = DEFAULT_SHUFFLE_ARRAY, action) =>
|
||||
action.type === 'SHUFFLE_ARRAY' ? shuffle(state) : state,
|
||||
});
|
||||
|
||||
export default createRootReducer;
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.react.base.json",
|
||||
"compilerOptions": {
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"include": ["../src", "src"]
|
||||
}
|
4
packages/redux-devtools-test-generator/jest.config.js
Normal file
4
packages/redux-devtools-test-generator/jest.config.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
setupFilesAfterEnv: ['<rootDir>/test/setup.ts'],
|
||||
};
|
|
@ -2,22 +2,6 @@
|
|||
"name": "redux-devtools-test-generator",
|
||||
"version": "0.6.2",
|
||||
"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",
|
||||
"test": "jest --no-cache",
|
||||
"prepare": "npm run clean && npm run build",
|
||||
"prepublishOnly": "npm run test && npm run clean && npm run build"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/reduxjs/redux-devtools.git"
|
||||
},
|
||||
"keywords": [
|
||||
"redux",
|
||||
"devtools",
|
||||
|
@ -28,35 +12,64 @@
|
|||
"time travel",
|
||||
"live edit"
|
||||
],
|
||||
"author": "Mihail Diordiev <zalmoxisus@gmail.com> (https://github.com/zalmoxisus)",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-test-generator",
|
||||
"bugs": {
|
||||
"url": "https://github.com/reduxjs/redux-devtools/issues"
|
||||
},
|
||||
"homepage": "https://github.com/reduxjs/redux-devtools",
|
||||
"license": "MIT",
|
||||
"author": "Mihail Diordiev <zalmoxisus@gmail.com> (https://github.com/zalmoxisus)",
|
||||
"files": [
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/reduxjs/redux-devtools.git"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "webpack-dev-server --config demo/config/webpack.config.ts",
|
||||
"build": "npm run build:types && npm run build:js",
|
||||
"build:types": "tsc --emitDeclarationOnly",
|
||||
"build:js": "babel src --out-dir lib --extensions \".ts,.tsx\" --source-maps inline",
|
||||
"clean": "rimraf lib",
|
||||
"test": "jest",
|
||||
"lint": "eslint . --ext .ts,.tsx",
|
||||
"lint:fix": "eslint . --ext .ts,.tsx --fix",
|
||||
"type-check": "tsc --noEmit",
|
||||
"type-check:watch": "npm run type-check -- --watch",
|
||||
"preversion": "npm run type-check && npm run lint && npm run test",
|
||||
"prepublishOnly": "npm run clean && npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/prop-types": "^15.7.3",
|
||||
"devui": "^1.0.0-6",
|
||||
"es6template": "^1.0.5",
|
||||
"javascript-stringify": "^2.0.1",
|
||||
"jsan": "^3.1.13",
|
||||
"object-path": "^0.11.4",
|
||||
"prop-types": "^15.7.2",
|
||||
"react-icons": "^3.10.0",
|
||||
"simple-diff": "^1.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.10.5",
|
||||
"@babel/core": "^7.11.1",
|
||||
"@babel/plugin-proposal-class-properties": "^7.10.4",
|
||||
"@babel/plugin-proposal-do-expressions": "^7.10.4",
|
||||
"@babel/polyfill": "^7.10.4",
|
||||
"@babel/preset-env": "^7.11.0",
|
||||
"@babel/preset-react": "^7.10.4",
|
||||
"babel-loader": "^8.1.0",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"@types/history": "^4.7.7",
|
||||
"@types/jsan": "^3.1.0",
|
||||
"@types/lodash.shuffle": "^4.2.6",
|
||||
"@types/object-path": "^0.11.0",
|
||||
"@types/react": "^16.9.46",
|
||||
"@types/react-router": "^5.1.8",
|
||||
"@types/redux-logger": "^3.0.8",
|
||||
"connected-react-router": "^6.8.0",
|
||||
"css-loader": "^4.2.1",
|
||||
"enzyme": "^3.11.0",
|
||||
"enzyme-adapter-react-16": "^1.15.3",
|
||||
"enzyme-to-json": "^3.5.0",
|
||||
"expect": "^26.2.0",
|
||||
"file-loader": "^6.0.0",
|
||||
"history": "^4.10.1",
|
||||
"html-webpack-plugin": "^4.3.0",
|
||||
"immutable": "^4.0.0-rc.12",
|
||||
"jest": "^26.2.2",
|
||||
"lodash.isequalwith": "^4.4.0",
|
||||
"lodash.shuffle": "^4.2.0",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-redux": "^7.2.1",
|
||||
"react-router": "^5.2.0",
|
||||
|
@ -64,27 +77,11 @@
|
|||
"redux-devtools": "^3.7.0",
|
||||
"redux-devtools-dock-monitor": "^1.2.0",
|
||||
"redux-devtools-inspector-monitor": "^0.14.0",
|
||||
"redux-logger": "^3.0.6",
|
||||
"rimraf": "^3.0.2",
|
||||
"seamless-immutable": "^7.1.4",
|
||||
"style-loader": "^1.2.1",
|
||||
"webpack": "^4.44.1",
|
||||
"webpack-dev-server": "^3.11.0"
|
||||
"redux-logger": "^3.0.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"devui": "^1.0.0-6",
|
||||
"es6template": "^1.0.5",
|
||||
"javascript-stringify": "^2.0.1",
|
||||
"jsan": "^3.1.13",
|
||||
"object-path": "^0.11.4",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.13.1",
|
||||
"react-icons": "^3.10.0",
|
||||
"simple-diff": "^1.6.0"
|
||||
},
|
||||
"jest": {
|
||||
"setupFilesAfterEnv": [
|
||||
"<rootDir>/test/setup.js"
|
||||
]
|
||||
"peerDependencies": {
|
||||
"@types/react": "^16.3.18",
|
||||
"react": "^16.3.0",
|
||||
"redux-devtools-inspector-monitor": "^0.14.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,38 +1,54 @@
|
|||
import React, { PureComponent, Component } from 'react';
|
||||
import React, { PureComponent, Component, ReactNode } 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 diff, { Event } from 'simple-diff';
|
||||
import es6template from 'es6template';
|
||||
import { Editor } from 'devui';
|
||||
import { TabComponentProps } from 'redux-devtools-inspector-monitor';
|
||||
import { Action } from 'redux';
|
||||
import { AssertionLocals, DispatcherLocals, WrapLocals } from './types';
|
||||
|
||||
export const fromPath = (path) =>
|
||||
export const fromPath = (path: (string | number)[]) =>
|
||||
path.map((a) => (typeof a === 'string' ? `.${a}` : `[${a}]`)).join('');
|
||||
|
||||
function getState(s, defaultValue) {
|
||||
function getState<S>(
|
||||
s: { state: S; error?: string } | undefined,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
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);
|
||||
export function compare<S>(
|
||||
s1: { state: S; error?: string } | undefined,
|
||||
s2: { state: S; error?: string },
|
||||
cb: (value: { path: string; curState: number | string | undefined }) => void,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
defaultValue?: {}
|
||||
) {
|
||||
const paths: string[] = []; // Already processed
|
||||
function generate(
|
||||
event: Event | { type: 'move-item'; newPath: (string | number)[] }
|
||||
) {
|
||||
let curState: number | string | undefined;
|
||||
let path = fromPath(event.newPath);
|
||||
|
||||
if (type === 'remove-item' || type === 'move-item') {
|
||||
if (event.type === 'remove-item' || event.type === 'move-item') {
|
||||
if (paths.length && paths.indexOf(path) !== -1) return;
|
||||
paths.push(path);
|
||||
const v = objectPath.get(s2.state, newPath);
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
const v = objectPath.get((s2.state as unknown) as object, event.newPath);
|
||||
curState = v.length;
|
||||
path += '.length';
|
||||
} else if (type === 'add-item') {
|
||||
generate({ type: 'move-item', newPath });
|
||||
path += `[${newIndex}]`;
|
||||
curState = stringify(newValue);
|
||||
} else if (event.type === 'add-item') {
|
||||
generate({ type: 'move-item', newPath: event.newPath });
|
||||
path += `[${event.newIndex}]`;
|
||||
curState = stringify(event.newValue);
|
||||
} else {
|
||||
curState = stringify(newValue);
|
||||
curState = stringify(event.newValue);
|
||||
}
|
||||
|
||||
// console.log(`expect(store${path}).toEqual(${curState});`);
|
||||
|
@ -45,17 +61,34 @@ export function compare(s1, s2, cb, defaultValue) {
|
|||
).forEach(generate);
|
||||
}
|
||||
|
||||
export default class TestGenerator extends (PureComponent || Component) {
|
||||
getMethod(action) {
|
||||
let type = action.type;
|
||||
interface Props<S, A extends Action<unknown>>
|
||||
extends Omit<TabComponentProps<S, A>, 'monitorState' | 'updateMonitorState'> {
|
||||
name?: string;
|
||||
isVanilla?: boolean;
|
||||
wrap?: string | ((locals: WrapLocals) => string);
|
||||
dispatcher?: string | ((locals: DispatcherLocals) => string);
|
||||
assertion?: string | ((locals: AssertionLocals) => string);
|
||||
useCodemirror: boolean;
|
||||
indentation?: number;
|
||||
header?: ReactNode;
|
||||
}
|
||||
|
||||
export default class TestGenerator<
|
||||
S,
|
||||
A extends Action<unknown>
|
||||
> extends (PureComponent || Component)<Props<S, A>> {
|
||||
getMethod(action: A) {
|
||||
let type: string = action.type as string;
|
||||
if (type[0] === '┗') type = type.substr(1).trim();
|
||||
let args = action.arguments;
|
||||
if (args) args = args.map((arg) => stringify(arg)).join(',');
|
||||
else args = '';
|
||||
const args = ((action as unknown) as { arguments: unknown[] }).arguments
|
||||
? ((action as unknown) as { arguments: unknown[] }).arguments
|
||||
.map((arg) => stringify(arg))
|
||||
.join(',')
|
||||
: '';
|
||||
return `${type}(${args})`;
|
||||
}
|
||||
|
||||
getAction(action) {
|
||||
getAction(action: A) {
|
||||
if (action.type === '@@INIT') return '{}';
|
||||
return stringify(action);
|
||||
}
|
||||
|
@ -76,7 +109,7 @@ export default class TestGenerator extends (PureComponent || Component) {
|
|||
if (typeof assertion === 'string')
|
||||
assertion = es6template.compile(assertion);
|
||||
if (typeof wrap === 'string') {
|
||||
const ident = wrap.match(/\n.+\$\{assertions}/);
|
||||
const ident = /\n.+\$\{assertions}/.exec(wrap);
|
||||
if (ident) indentation = ident[0].length - 13;
|
||||
wrap = es6template.compile(wrap);
|
||||
}
|
||||
|
@ -94,21 +127,30 @@ export default class TestGenerator extends (PureComponent || Component) {
|
|||
else i = computedStates.length - 1;
|
||||
const startIdx = i > 0 ? i : 1;
|
||||
|
||||
const addAssertions = ({ path, curState }) => {
|
||||
r += space + assertion({ path, curState }) + '\n';
|
||||
const addAssertions = ({
|
||||
path,
|
||||
curState,
|
||||
}: {
|
||||
path: string;
|
||||
curState: number | string | undefined;
|
||||
}) => {
|
||||
r += `${space}${(assertion as (locals: AssertionLocals) => string)({
|
||||
path,
|
||||
curState,
|
||||
})}\n`;
|
||||
};
|
||||
|
||||
while (actions[i]) {
|
||||
if (
|
||||
!isVanilla ||
|
||||
/* eslint-disable-next-line no-useless-escape */
|
||||
/^┗?\s?[a-zA-Z0-9_@.\[\]-]+?$/.test(actions[i].action.type)
|
||||
/^┗?\s?[a-zA-Z0-9_@.\[\]-]+?$/.test(actions[i].action.type as string)
|
||||
) {
|
||||
if (isFirst) isFirst = false;
|
||||
else r += space;
|
||||
if (!isVanilla || actions[i].action.type[0] !== '@') {
|
||||
if (!isVanilla || (actions[i].action.type as string)[0] !== '@') {
|
||||
r +=
|
||||
dispatcher({
|
||||
(dispatcher as (locals: DispatcherLocals) => string)({
|
||||
action: !isVanilla
|
||||
? this.getAction(actions[i].action)
|
||||
: this.getMethod(actions[i].action),
|
||||
|
@ -131,7 +173,7 @@ export default class TestGenerator extends (PureComponent || Component) {
|
|||
}
|
||||
}
|
||||
i++;
|
||||
if (i > selectedActionId) break;
|
||||
if (i > selectedActionId!) break;
|
||||
}
|
||||
|
||||
r = r.trim();
|
||||
|
@ -139,11 +181,14 @@ export default class TestGenerator extends (PureComponent || Component) {
|
|||
if (!isVanilla) r = wrap({ name, assertions: r });
|
||||
else {
|
||||
r = wrap({
|
||||
name: /^[a-zA-Z0-9_-]+?$/.test(name) ? name : 'Store',
|
||||
name: /^[a-zA-Z0-9_-]+?$/.test(name as string) ? name : 'Store',
|
||||
actionName:
|
||||
(selectedActionId === null || selectedActionId > 0) &&
|
||||
actions[startIdx]
|
||||
? actions[startIdx].action.type.replace(/[^a-zA-Z0-9_-]+/, '')
|
||||
? (actions[startIdx].action.type as string).replace(
|
||||
/[^a-zA-Z0-9_-]+/,
|
||||
''
|
||||
)
|
||||
: 'should return the initial state',
|
||||
initialState: stringify(computedStates[startIdx - 1].state),
|
||||
assertions: r,
|
||||
|
@ -167,25 +212,10 @@ export default class TestGenerator extends (PureComponent || Component) {
|
|||
|
||||
return <Editor value={code} />;
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
useCodemirror: true,
|
||||
selectedActionId: null,
|
||||
startActionId: null,
|
||||
};
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
|
@ -0,0 +1,6 @@
|
|||
declare module 'es6template' {
|
||||
const _default: {
|
||||
compile<Locals>(template: string): (locals: Locals) => string;
|
||||
};
|
||||
export default _default;
|
||||
}
|
|
@ -8,16 +8,22 @@ import {
|
|||
Notification,
|
||||
Dialog,
|
||||
} from 'devui';
|
||||
import { formSchema, uiSchema, defaultFormData } from './templateForm';
|
||||
import { MdAdd } from 'react-icons/md';
|
||||
import { MdEdit } from 'react-icons/md';
|
||||
import { Action } from 'redux';
|
||||
import {
|
||||
DevtoolsInspectorState,
|
||||
TabComponentProps,
|
||||
} from 'redux-devtools-inspector-monitor';
|
||||
import { formSchema, uiSchema, defaultFormData } from './templateForm';
|
||||
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';
|
||||
import { Template } from './types';
|
||||
|
||||
export const getDefaultTemplates = (/* lib */) =>
|
||||
export const getDefaultTemplates = (/* lib */): Template[] =>
|
||||
/*
|
||||
if (lib === 'redux') {
|
||||
return [mochaTemplate, tapeTemplate, avaTemplate];
|
||||
|
@ -26,15 +32,27 @@ export const getDefaultTemplates = (/* lib */) =>
|
|||
*/
|
||||
[jestTemplate, mochaTemplate, tapeTemplate, avaTemplate];
|
||||
|
||||
export default class TestTab extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { dialogStatus: null };
|
||||
}
|
||||
interface TestGeneratorMonitorState {
|
||||
hideTip?: boolean;
|
||||
selected?: number;
|
||||
templates?: Template[];
|
||||
}
|
||||
|
||||
getPersistedState = () => this.props.monitorState.testGenerator || {};
|
||||
interface State {
|
||||
dialogStatus: 'Add' | 'Edit' | null;
|
||||
}
|
||||
|
||||
handleSelectTemplate = (selectedTemplate) => {
|
||||
export default class TestTab<S, A extends Action<unknown>> extends Component<
|
||||
TabComponentProps<S, A>,
|
||||
State
|
||||
> {
|
||||
state: State = { dialogStatus: null };
|
||||
|
||||
getPersistedState = (): TestGeneratorMonitorState =>
|
||||
(this.props.monitorState as { testGenerator?: TestGeneratorMonitorState })
|
||||
.testGenerator || {};
|
||||
|
||||
handleSelectTemplate = (selectedTemplate: Template) => {
|
||||
const { templates = getDefaultTemplates() } = this.getPersistedState();
|
||||
this.updateState({ selected: templates.indexOf(selectedTemplate) });
|
||||
};
|
||||
|
@ -47,7 +65,7 @@ export default class TestTab extends Component {
|
|||
this.setState({ dialogStatus: null });
|
||||
};
|
||||
|
||||
handleSubmit = ({ formData: template }) => {
|
||||
handleSubmit = ({ formData: template }: { formData: Template }) => {
|
||||
const {
|
||||
templates = getDefaultTemplates(),
|
||||
selected = 0,
|
||||
|
@ -90,13 +108,15 @@ export default class TestTab extends Component {
|
|||
this.setState({ dialogStatus: 'Edit' });
|
||||
};
|
||||
|
||||
updateState = (newState) => {
|
||||
updateState = (newState: TestGeneratorMonitorState) => {
|
||||
this.props.updateMonitorState({
|
||||
testGenerator: {
|
||||
...this.props.monitorState.testGenerator,
|
||||
...(this.props.monitorState as {
|
||||
testGenerator?: TestGeneratorMonitorState;
|
||||
}).testGenerator,
|
||||
...newState,
|
||||
},
|
||||
});
|
||||
} as Partial<DevtoolsInspectorState>);
|
||||
};
|
||||
|
||||
render() {
|
||||
|
@ -128,7 +148,7 @@ export default class TestTab extends Component {
|
|||
{!assertion ? (
|
||||
<Notification>No template for tests specified.</Notification>
|
||||
) : (
|
||||
<TestGenerator
|
||||
<TestGenerator<S, A>
|
||||
isVanilla={false}
|
||||
assertion={assertion}
|
||||
dispatcher={dispatcher}
|
||||
|
@ -142,7 +162,7 @@ export default class TestTab extends Component {
|
|||
</Notification>
|
||||
)}
|
||||
{dialogStatus && (
|
||||
<Dialog
|
||||
<Dialog<Template>
|
||||
open
|
||||
title={`${dialogStatus} test template`}
|
||||
onDismiss={this.handleCloseDialog}
|
||||
|
@ -164,20 +184,20 @@ export default class TestTab extends Component {
|
|||
</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,
|
||||
};
|
||||
static 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,
|
||||
};
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
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,21 @@
|
|||
import { AssertionLocals, DispatcherLocals, WrapLocals } from '../../types';
|
||||
|
||||
export const name = 'Ava template';
|
||||
|
||||
export const dispatcher = ({ action, prevState }: DispatcherLocals) =>
|
||||
`state = reducers(${prevState!}, ${action!});`;
|
||||
|
||||
export const assertion = ({ curState }: AssertionLocals) =>
|
||||
`t.deepEqual(state, ${curState!});`;
|
||||
|
||||
export const wrap = ({ assertions }: WrapLocals) =>
|
||||
`import test from 'ava';
|
||||
import reducers from '../../reducers';
|
||||
|
||||
test('reducers', (t) => {
|
||||
let state;
|
||||
${assertions}
|
||||
});
|
||||
`;
|
||||
|
||||
export default { name, assertion, dispatcher, wrap };
|
|
@ -1,18 +0,0 @@
|
|||
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,20 @@
|
|||
import { AssertionLocals, DispatcherLocals, WrapLocals } from '../../types';
|
||||
|
||||
export const name = 'Jest template';
|
||||
|
||||
export const dispatcher = ({ action, prevState }: DispatcherLocals) =>
|
||||
`state = reducers(${prevState!}, ${action!});`;
|
||||
|
||||
export const assertion = ({ curState }: AssertionLocals) =>
|
||||
`expect(state).toEqual(${curState!});`;
|
||||
|
||||
export const wrap = ({ assertions }: WrapLocals) =>
|
||||
`import reducers from '../../reducers';
|
||||
|
||||
test('reducers', () => {
|
||||
let state;
|
||||
${assertions}
|
||||
});
|
||||
`;
|
||||
|
||||
export default { name, assertion, dispatcher, wrap };
|
|
@ -1,21 +0,0 @@
|
|||
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,23 @@
|
|||
import { AssertionLocals, DispatcherLocals, WrapLocals } from '../../types';
|
||||
|
||||
export const name = 'Mocha template';
|
||||
|
||||
export const dispatcher = ({ action, prevState }: DispatcherLocals) =>
|
||||
`state = reducers(${prevState!}, ${action!});`;
|
||||
|
||||
export const assertion = ({ curState }: AssertionLocals) =>
|
||||
`expect(state).toEqual(${curState!});`;
|
||||
|
||||
export const wrap = ({ assertions }: WrapLocals) =>
|
||||
`import expect from 'expect';
|
||||
import reducers from '../../reducers';
|
||||
|
||||
describe('reducers', () => {
|
||||
it('should handle actions', () => {
|
||||
let state;
|
||||
${assertions}
|
||||
});
|
||||
});
|
||||
`;
|
||||
|
||||
export default { name, assertion, dispatcher, wrap };
|
|
@ -1,19 +0,0 @@
|
|||
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,22 @@
|
|||
import { AssertionLocals, DispatcherLocals, WrapLocals } from '../../types';
|
||||
|
||||
export const name = 'Tape template';
|
||||
|
||||
export const dispatcher = ({ action, prevState }: DispatcherLocals) =>
|
||||
`state = reducers(${prevState!}, ${action!});`;
|
||||
|
||||
export const assertion = ({ curState }: AssertionLocals) =>
|
||||
`t.deepEqual(state, ${curState!});`;
|
||||
|
||||
export const wrap = ({ assertions }: WrapLocals) =>
|
||||
`import test from 'tape';
|
||||
import reducers from '../../reducers';
|
||||
|
||||
test('reducers', (t) => {
|
||||
let state;
|
||||
${assertions}
|
||||
t.end();
|
||||
});
|
||||
`;
|
||||
|
||||
export default { name, assertion, dispatcher, wrap };
|
64
packages/redux-devtools-test-generator/src/simple-diff.ts
Normal file
64
packages/redux-devtools-test-generator/src/simple-diff.ts
Normal file
|
@ -0,0 +1,64 @@
|
|||
declare module 'simple-diff' {
|
||||
interface AddEvent {
|
||||
oldPath: (string | number)[];
|
||||
newPath: (string | number)[];
|
||||
type: 'add';
|
||||
oldValue: undefined;
|
||||
newValue: unknown;
|
||||
}
|
||||
|
||||
interface RemoveEvent {
|
||||
oldPath: (string | number)[];
|
||||
newPath: (string | number)[];
|
||||
type: 'remove';
|
||||
oldValue: unknown;
|
||||
newValue: undefined;
|
||||
}
|
||||
|
||||
interface ChangeEvent {
|
||||
oldPath: (string | number)[];
|
||||
newPath: (string | number)[];
|
||||
type: 'change';
|
||||
oldValue: unknown;
|
||||
newValue: unknown;
|
||||
}
|
||||
|
||||
interface AddItemEvent {
|
||||
oldPath: (string | number)[];
|
||||
newPath: (string | number)[];
|
||||
type: 'add-item';
|
||||
oldIndex: -1;
|
||||
curIndex: -1;
|
||||
newIndex: number;
|
||||
newValue: unknown;
|
||||
}
|
||||
|
||||
interface RemoveItemEvent {
|
||||
oldPath: (string | number)[];
|
||||
newPath: (string | number)[];
|
||||
type: 'remove-item';
|
||||
oldIndex: number;
|
||||
curIndex: number;
|
||||
newIndex: -1;
|
||||
oldValue: unknown;
|
||||
}
|
||||
|
||||
interface MoveItemEvent {
|
||||
oldPath: (string | number)[];
|
||||
newPath: (string | number)[];
|
||||
type: 'move-item';
|
||||
oldIndex: number;
|
||||
curIndex: number;
|
||||
newIndex: number;
|
||||
}
|
||||
|
||||
export type Event =
|
||||
| AddEvent
|
||||
| RemoveEvent
|
||||
| ChangeEvent
|
||||
| AddItemEvent
|
||||
| RemoveItemEvent
|
||||
| MoveItemEvent;
|
||||
|
||||
export default function (oldObj: unknown, newObj: unknown): Event[];
|
||||
}
|
|
@ -1,21 +1,23 @@
|
|||
import { Template } from './types';
|
||||
|
||||
export const formSchema = {
|
||||
type: 'object',
|
||||
type: 'object' as const,
|
||||
required: ['name'],
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string',
|
||||
type: 'string' as const,
|
||||
title: 'Template name',
|
||||
},
|
||||
dispatcher: {
|
||||
type: 'string',
|
||||
type: 'string' as const,
|
||||
title: 'Dispatcher: ({ action, prevState }) => (`<template>`)',
|
||||
},
|
||||
assertion: {
|
||||
type: 'string',
|
||||
type: 'string' as const,
|
||||
title: 'Assertion: ({ curState }) => (`<template>`)',
|
||||
},
|
||||
wrap: {
|
||||
type: 'string',
|
||||
type: 'string' as const,
|
||||
title:
|
||||
'Wrap code: ({ name, initialState, assertions }) => (`<template>`)',
|
||||
},
|
||||
|
@ -34,7 +36,7 @@ export const uiSchema = {
|
|||
},
|
||||
};
|
||||
|
||||
export const defaultFormData = {
|
||||
export const defaultFormData: Template = {
|
||||
dispatcher: 'state = reducers(${prevState}, ${action});',
|
||||
assertion: 't.deepEqual(state, ${curState});',
|
||||
wrap: `test('reducers', (t) => {
|
23
packages/redux-devtools-test-generator/src/types.ts
Normal file
23
packages/redux-devtools-test-generator/src/types.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
export interface DispatcherLocals {
|
||||
action: string | undefined;
|
||||
prevState: string | undefined;
|
||||
}
|
||||
|
||||
export interface AssertionLocals {
|
||||
path: string;
|
||||
curState: number | string | undefined;
|
||||
}
|
||||
|
||||
export interface WrapLocals {
|
||||
name: string | undefined;
|
||||
assertions: string;
|
||||
actionName?: string;
|
||||
initialState?: string | undefined;
|
||||
}
|
||||
|
||||
export interface Template {
|
||||
name?: string;
|
||||
dispatcher: string;
|
||||
assertion: string;
|
||||
wrap: string;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
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,20 @@
|
|||
import { AssertionLocals, DispatcherLocals, WrapLocals } from '../../types';
|
||||
|
||||
export const name = 'Ava template';
|
||||
|
||||
export const dispatcher = ({ action }: DispatcherLocals) => `${action!};`;
|
||||
|
||||
export const assertion = ({ path, curState }: AssertionLocals) =>
|
||||
`t.deepEqual(state${path}, ${curState!});`;
|
||||
|
||||
export const wrap = ({ name, initialState, assertions }: WrapLocals) =>
|
||||
`import test from 'ava';
|
||||
import ${name!} from '../../stores/${name!}';
|
||||
|
||||
test('${name!}', (t) => {
|
||||
const store = new ${name!}(${initialState!});
|
||||
${assertions}
|
||||
});
|
||||
`;
|
||||
|
||||
export default { name, assertion, dispatcher, wrap };
|
|
@ -1,18 +0,0 @@
|
|||
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,20 @@
|
|||
import { AssertionLocals, DispatcherLocals, WrapLocals } from '../../types';
|
||||
|
||||
export const name = 'Mocha template';
|
||||
|
||||
export const dispatcher = ({ action }: DispatcherLocals) => `${action!};`;
|
||||
|
||||
export const assertion = ({ path, curState }: AssertionLocals) =>
|
||||
`expect(store${path}).toEqual(${curState!});`;
|
||||
|
||||
export const wrap = ({ name, initialState, assertions }: WrapLocals) =>
|
||||
`import expect from 'expect';
|
||||
import ${name!} from '../../stores/${name!}';
|
||||
|
||||
test('${name!}', (t) => {
|
||||
const store = new ${name!}(${initialState!});
|
||||
${assertions}
|
||||
});
|
||||
`;
|
||||
|
||||
export default { name, assertion, dispatcher, wrap };
|
|
@ -1,20 +0,0 @@
|
|||
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,27 @@
|
|||
import { AssertionLocals, DispatcherLocals, WrapLocals } from '../../types';
|
||||
|
||||
export const name = 'Mocha template';
|
||||
|
||||
export const dispatcher = ({ action }: DispatcherLocals) => `${action!};`;
|
||||
|
||||
export const assertion = ({ path, curState }: AssertionLocals) =>
|
||||
`expect(store${path}).toEqual(${curState!});`;
|
||||
|
||||
export const wrap = ({
|
||||
name,
|
||||
actionName,
|
||||
initialState,
|
||||
assertions,
|
||||
}: WrapLocals) =>
|
||||
`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 };
|
|
@ -1,19 +0,0 @@
|
|||
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,21 @@
|
|||
import { AssertionLocals, DispatcherLocals, WrapLocals } from '../../types';
|
||||
|
||||
export const name = 'Tape template';
|
||||
|
||||
export const dispatcher = ({ action }: DispatcherLocals) => `${action!};`;
|
||||
|
||||
export const assertion = ({ path, curState }: AssertionLocals) =>
|
||||
`t.deepEqual(state${path}, ${curState!});`;
|
||||
|
||||
export const wrap = ({ name, initialState, assertions }: WrapLocals) =>
|
||||
`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 };
|
|
@ -1,28 +1,42 @@
|
|||
import React from 'react';
|
||||
import { render } from 'enzyme';
|
||||
import { renderToJson } from 'enzyme-to-json';
|
||||
import { PerformAction } from 'redux-devtools-instrument';
|
||||
import { Action } from 'redux';
|
||||
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 actions: { [actionId: number]: PerformAction<Action<unknown>> } = {
|
||||
0: {
|
||||
type: 'PERFORM_ACTION',
|
||||
action: { type: '@@INIT' },
|
||||
timestamp: 0,
|
||||
stack: undefined,
|
||||
},
|
||||
1: {
|
||||
type: 'PERFORM_ACTION',
|
||||
action: { type: 'INCREMENT_COUNTER' },
|
||||
timestamp: 0,
|
||||
stack: undefined,
|
||||
},
|
||||
};
|
||||
|
||||
const computedStates = [{ state: { counter: 0 } }, { state: { counter: 1 } }];
|
||||
|
||||
const TestGeneratorAsAny = TestGenerator as any;
|
||||
|
||||
describe('TestGenerator component', () => {
|
||||
it('should show warning message when no params provided', () => {
|
||||
const component = render(<TestGenerator useCodemirror={false} />);
|
||||
const component = render(<TestGeneratorAsAny useCodemirror={false} />);
|
||||
expect(renderToJson(component)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should be empty when no actions provided', () => {
|
||||
const component = render(
|
||||
<TestGenerator
|
||||
<TestGeneratorAsAny
|
||||
assertion={fnTemplate.assertion}
|
||||
dispatcher={fnTemplate.dispatcher}
|
||||
wrap={fnTemplate.wrap}
|
||||
|
@ -34,7 +48,7 @@ describe('TestGenerator component', () => {
|
|||
|
||||
it("should match function template's test for first action", () => {
|
||||
const component = render(
|
||||
<TestGenerator
|
||||
<TestGeneratorAsAny
|
||||
assertion={fnTemplate.assertion}
|
||||
dispatcher={fnTemplate.dispatcher}
|
||||
wrap={fnTemplate.wrap}
|
||||
|
@ -49,7 +63,7 @@ describe('TestGenerator component', () => {
|
|||
|
||||
it("should match string template's test for first action", () => {
|
||||
const component = render(
|
||||
<TestGenerator
|
||||
<TestGeneratorAsAny
|
||||
assertion={strTemplate.assertion}
|
||||
dispatcher={strTemplate.dispatcher}
|
||||
wrap={strTemplate.wrap}
|
||||
|
@ -64,7 +78,7 @@ describe('TestGenerator component', () => {
|
|||
|
||||
it('should generate test for the last action when selectedActionId not specified', () => {
|
||||
const component = render(
|
||||
<TestGenerator
|
||||
<TestGeneratorAsAny
|
||||
assertion={fnTemplate.assertion}
|
||||
dispatcher={fnTemplate.dispatcher}
|
||||
wrap={fnTemplate.wrap}
|
||||
|
@ -78,7 +92,7 @@ describe('TestGenerator component', () => {
|
|||
|
||||
it('should generate test for vanilla js class', () => {
|
||||
const component = render(
|
||||
<TestGenerator
|
||||
<TestGeneratorAsAny
|
||||
assertion={fnVanillaTemplate.assertion}
|
||||
dispatcher={fnVanillaTemplate.dispatcher}
|
||||
wrap={fnVanillaTemplate.wrap}
|
||||
|
@ -95,7 +109,7 @@ describe('TestGenerator component', () => {
|
|||
|
||||
it('should generate test for vanilla js class with string template', () => {
|
||||
const component = render(
|
||||
<TestGenerator
|
||||
<TestGeneratorAsAny
|
||||
assertion={strVanillaTemplate.assertion}
|
||||
dispatcher={strVanillaTemplate.dispatcher}
|
||||
wrap={strVanillaTemplate.wrap}
|
|
@ -12,11 +12,11 @@ const computedStates = [
|
|||
{ state: [0, 2, 3, 4] },
|
||||
];
|
||||
|
||||
const test = (s1, s2) =>
|
||||
const test = (s1: { state: unknown } | undefined, s2: { state: unknown }) =>
|
||||
compare(s1, s2, ({ path, curState }) =>
|
||||
expect(`expect(store${path}).toEqual(${curState});`).toBe(
|
||||
assertion({ path, curState })
|
||||
)
|
||||
expect(
|
||||
`expect(store${path}).toEqual(${curState as number | string});`
|
||||
).toBe(assertion({ path, curState }))
|
||||
);
|
||||
|
||||
describe('Assertions', () => {
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.react.base.json",
|
||||
"include": ["../src", "."]
|
||||
}
|
8
packages/redux-devtools-test-generator/tsconfig.json
Normal file
8
packages/redux-devtools-test-generator/tsconfig.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "../../tsconfig.react.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib",
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
40
yarn.lock
40
yarn.lock
|
@ -387,14 +387,6 @@
|
|||
"@babel/helper-plugin-utils" "^7.10.4"
|
||||
"@babel/plugin-syntax-decorators" "^7.10.4"
|
||||
|
||||
"@babel/plugin-proposal-do-expressions@^7.10.4":
|
||||
version "7.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-do-expressions/-/plugin-proposal-do-expressions-7.10.4.tgz#9a5190f3bf4818f83e41d673ee517ff76cf8e4ed"
|
||||
integrity sha512-Gcc2wLVeMceRdP6m9tdDygP01lbUVmaQGBRoIRJZxzPfB5VTiUgmn1jGfORgqbEVgUpG0IQm/z4q5Y/qzG+8JQ==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.10.4"
|
||||
"@babel/plugin-syntax-do-expressions" "^7.10.4"
|
||||
|
||||
"@babel/plugin-proposal-dynamic-import@^7.10.4":
|
||||
version "7.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz#ba57a26cb98b37741e9d5bca1b8b0ddf8291f17e"
|
||||
|
@ -530,13 +522,6 @@
|
|||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.10.4"
|
||||
|
||||
"@babel/plugin-syntax-do-expressions@^7.10.4":
|
||||
version "7.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-do-expressions/-/plugin-syntax-do-expressions-7.10.4.tgz#0c7ebb749500c6bfa99a9f926db3bfd6cdbaded9"
|
||||
integrity sha512-HyvaTg1aiwGo2I+Pu0nyurRMjIP7J89GpuZ2mcQ0fhO6Jt3BnyhEPbNJFG1hRE99NAPNfPYh93/7HO+GPVkTKg==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.10.4"
|
||||
|
||||
"@babel/plugin-syntax-dynamic-import@^7.8.0", "@babel/plugin-syntax-dynamic-import@^7.8.3":
|
||||
version "7.8.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3"
|
||||
|
@ -977,14 +962,6 @@
|
|||
"@babel/helper-create-regexp-features-plugin" "^7.10.4"
|
||||
"@babel/helper-plugin-utils" "^7.10.4"
|
||||
|
||||
"@babel/polyfill@^7.10.4":
|
||||
version "7.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.10.4.tgz#915e5bfe61490ac0199008e35ca9d7d151a8e45a"
|
||||
integrity sha512-8BYcnVqQ5kMD2HXoHInBH7H1b/uP3KdnwCYXOqFnXqguOyuu443WXusbIUbWEfY3Z0Txk0M1uG/8YuAMhNl6zg==
|
||||
dependencies:
|
||||
core-js "^2.6.5"
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/preset-env@^7.11.0":
|
||||
version "7.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.11.0.tgz#860ee38f2ce17ad60480c2021ba9689393efb796"
|
||||
|
@ -1192,7 +1169,7 @@
|
|||
core-js "^2.6.5"
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
|
||||
"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
|
||||
version "7.11.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736"
|
||||
integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==
|
||||
|
@ -3653,6 +3630,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/npmlog/-/npmlog-4.1.2.tgz#d070fe6a6b78755d1092a3dc492d34c3d8f871c4"
|
||||
integrity sha512-4QQmOF5KlwfxJ5IGXFIudkeLCdMABz03RcUXu+LCb24zmln8QW6aDjuGl4d4XPVLf2j+FnjelHTP7dvceAFbhA==
|
||||
|
||||
"@types/object-path@^0.11.0":
|
||||
version "0.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/object-path/-/object-path-0.11.0.tgz#0b744309b2573dc8bf867ef589b6288be998e602"
|
||||
integrity sha512-/tuN8jDbOXcPk+VzEVZzzAgw1Byz7s/itb2YI10qkSyy6nykJH02DuhfrflxVdAdE7AZ91h5X6Cn0dmVdFw2TQ==
|
||||
|
||||
"@types/overlayscrollbars@^1.9.0":
|
||||
version "1.12.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/overlayscrollbars/-/overlayscrollbars-1.12.0.tgz#98456caceca8ad73bd5bb572632a585074e70764"
|
||||
|
@ -3828,6 +3810,11 @@
|
|||
"@types/express-serve-static-core" "*"
|
||||
"@types/mime" "*"
|
||||
|
||||
"@types/simple-element-resize-detector@^1.3.0":
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/simple-element-resize-detector/-/simple-element-resize-detector-1.3.0.tgz#19b40d71fefa1876ac5d4ba585197ef438946353"
|
||||
integrity sha512-z89ForrCNg+4uwTHjwBCM9LjcsXYC/4O8u3tSi+82v2LCbfiYFpkjH/qQVkDewFBK6FUG7RRV7jw78EGs2maoQ==
|
||||
|
||||
"@types/source-list-map@*":
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9"
|
||||
|
@ -11635,11 +11622,6 @@ lodash.isequal@^4.5.0:
|
|||
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
|
||||
integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
|
||||
|
||||
lodash.isequalwith@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isequalwith/-/lodash.isequalwith-4.4.0.tgz#266726ddd528f854f21f4ea98a065606e0fbc6b0"
|
||||
integrity sha1-Jmcm3dUo+FTyH06pigZWBuD7xrA=
|
||||
|
||||
lodash.isinteger@^4.0.4:
|
||||
version "4.0.4"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343"
|
||||
|
|
Loading…
Reference in New Issue
Block a user