Commit ac831105 authored by Jaden DIEFENBAUGH's avatar Jaden DIEFENBAUGH
Browse files

[js][df] refactor dataformat editor & tests

parent 26eb6b0d
......@@ -31,6 +31,7 @@ import CacheInput from '../CacheInput.jsx';
import DeleteInputBtn from '../DeleteInputBtn.jsx';
import TypedField from '../TypedField.jsx';
import * as Actions from '@store/actions.js';
import { BUILTIN_TYPES, getValidDataformatObj as getValidObj } from '@helpers/beat';
import type {
BeatObject,
......@@ -42,10 +43,7 @@ type Props = {
data: BeatObject,
dataformats: BeatObject[],
saveFunc: (BeatObject) => any,
};
type State = {
cache: any,
updateFunc: (BeatObject) => any,
};
const isObj = (obj): boolean => !Array.isArray(obj) && typeof obj === 'object' && obj !== null;
......@@ -223,36 +221,24 @@ const RecursiveObj = ({ obj, dfs, updateFunc }: {obj: any, dfs: string[], update
</div>
);
export class DataformatEditor extends React.Component<Props, State> {
export class DataformatEditor extends React.Component<Props> {
constructor(props: Props) {
super(props);
}
state = {
cache: getValidObj(this.props.data),
}
componentWillReceiveProps (nextProps: Props) {
this.setState({
cache: getValidObj(nextProps.data),
});
}
setContents = (newContents: any) => {
this.setState({
cache: {
...this.state.cache,
contents: {
'#description': this.state.cache.contents['#description'],
...newContents,
}
this.props.updateFunc({
...this.props.data,
contents: {
'#description': this.props.data.contents['#description'],
...newContents,
}
});
}
allDfs = () => this.props.dataformats.map(d => d.name).concat(BUILTIN_TYPES);
filteredContents = (obj: any = this.state.cache.contents) => Object.entries(obj).filter(([n, v]) => n !== '#description').reduce((o, [n, v]) => ({...o, [n]: v}), {});
filteredContents = (obj: any = this.props.data.contents) => Object.entries(obj).filter(([n, v]) => n !== '#description').reduce((o, [n, v]) => ({...o, [n]: v}), {});
render = () => (
<div>
......@@ -261,9 +247,9 @@ export class DataformatEditor extends React.Component<Props, State> {
className='mx-auto'
outline
color='secondary'
onClick={() => this.props.saveFunc(this.state.cache)}
onClick={() => this.props.saveFunc(this.props.data)}
>
Save Changes (Changes are <ValidSchemaBadge entity='dataformat' obj={this.state.cache} />)
Save Changes (Changes are <ValidSchemaBadge entity='dataformat' obj={this.props.data} />)
</Button>
</div>
<Form onSubmit={(e) => e.preventDefault()}>
......@@ -274,8 +260,8 @@ export class DataformatEditor extends React.Component<Props, State> {
type='text'
name='description'
placeholder='Dataformat description...'
value={this.state.cache.contents['#description']}
onChange={e => this.setContents({ ...this.state.cache.contents, '#description': e.target.value})}
value={this.props.data.contents['#description']}
onChange={e => this.setContents({ ...this.props.data.contents, '#description': e.target.value})}
/>
</FormGroup>
</FormGroup>
......@@ -287,10 +273,20 @@ export class DataformatEditor extends React.Component<Props, State> {
}
const mapStateToProps = (state, ownProps) => {
const dfs = Selectors.dataformatGet(state);
const obj = {
dataformats: Selectors.dataformatGet(state),
dataformats: dfs,
data: dfs[ownProps.index] || getValidObj()
};
return obj;
};
export default connect(mapStateToProps)(DataformatEditor);
const mapDispatchToProps = (dispatch, ownProps) => ({
// replace the obj in the Redux store with the new object
updateFunc: (obj) => {
console.log(`dispatching for ${ obj.name }`);
dispatch(Actions[`dataformatUpdate`](obj.name, obj));
},
});
export default connect(mapStateToProps, mapDispatchToProps)(DataformatEditor);
......@@ -5,6 +5,7 @@ import { mount } from 'enzyme';
import sinon from 'sinon';
import { spies } from '@test';
import { getValidDataformatObj as getValidObj } from '@helpers/beat';
import { DataformatEditor as C } from '.';
import testDfs from '@test/test_dfs.json';
......@@ -22,26 +23,29 @@ describe('<DataformatEditor />', () => {
{
name: 'test/df/1',
contents: {
'#description': '',
'field_1': 'string',
}
}
].concat(testDfs);
].concat(testDfs.map(df => getValidObj(df)));
dfs.forEach(function(df){
const saveFunc = () => {};
const updateFunc = () => {};
it(`${ df.name }`, () => {
wrapper = mount(
<C
data={df}
dataformats={dfs}
saveFunc={saveFunc}
updateFunc={updateFunc}
/>
);
expect(wrapper).to.have.props(
['data', 'dataformats', 'saveFunc']
['data', 'dataformats', 'saveFunc', 'updateFunc']
).deep.equal(
[df, dfs, saveFunc]
[df, dfs, saveFunc, updateFunc]
);
});
});
......@@ -51,30 +55,39 @@ describe('<DataformatEditor />', () => {
it('system/integer/1', () => {
const dfName = 'system/integer/1';
const saveFunc = sinon.spy();
const _updateFunc = (obj) => {
wrapper.setProps && wrapper.setProps({ data: obj });
};
const updateFunc = sinon.spy(_updateFunc);
wrapper = mount(
<C
data={{name: dfName, contents: {}}}
data={getValidObj({name: dfName, contents: {}})}
dataformats={testDfs.filter(d => d.name !== dfName)}
saveFunc={saveFunc}
updateFunc={updateFunc}
/>
);
expect(wrapper).to.have.props(
['data', 'dataformats', 'saveFunc']
['data', 'dataformats', 'saveFunc', 'updateFunc']
);
expect(wrapper.state('cache')).to.have.property('name', dfName);
expect(wrapper.props().data).to.have.property('name', dfName);
wrapper.find('input[name="description"]').simulate('change', { target: { value: 'Single (32 bits) integer value'}});
expect(wrapper.state('cache').contents).to.have.property('#description', 'Single (32 bits) integer value');
expect(wrapper.props().data.contents).to.have.property('#description', 'Single (32 bits) integer value');
expect(updateFunc.callCount).to.equal(1);
wrapper.find('button.btn-success').simulate('click');
expect(updateFunc.callCount).to.equal(2);
wrapper.find('CacheInput[placeholder="Name..."]').prop('onChange')( { target: { value: 'value' }});
expect(updateFunc.callCount).to.equal(3);
wrapper.find('select').simulate('change', { target: { value: 'int32' }});
expect(wrapper.state('cache').contents).to.have.property('value', 'int32');
expect(updateFunc.callCount).to.equal(4);
expect(wrapper.props().data.contents).to.have.property('value', 'int32');
expect(wrapper.state('cache')).to.deep.equal({
expect(wrapper.props().data).to.deep.equal({
'name': 'system/integer/1',
'contents': {
'#description': 'Single (32 bits) integer value',
......@@ -86,11 +99,16 @@ describe('<DataformatEditor />', () => {
it('system/array_1d_text/1', () => {
const dfName = 'system/array_1d_text/1';
const saveFunc = sinon.spy();
const _updateFunc = (obj) => {
wrapper.setProps && wrapper.setProps({ data: obj });
};
const updateFunc = sinon.spy(_updateFunc);
wrapper = mount(
<C
data={{name: dfName, contents: {}}}
data={getValidObj({name: dfName, contents: {}})}
dataformats={testDfs.filter(d => d.name !== dfName)}
saveFunc={saveFunc}
updateFunc={updateFunc}
/>
);
......@@ -98,15 +116,15 @@ describe('<DataformatEditor />', () => {
['data', 'dataformats', 'saveFunc']
);
expect(wrapper.state('cache')).to.have.property('name', dfName);
expect(wrapper.props().data).to.have.property('name', dfName);
wrapper.find('button.btn-success').simulate('click');
wrapper.find('CacheInput[placeholder="Name..."]').prop('onChange')( { target: { value: 'text' }});
wrapper.find('select').simulate('change', { target: { value: 'array' }});
expect(wrapper.state('cache').contents).to.have.deep.property('text', [0, 'string']);
expect(wrapper.props().data.contents).to.have.deep.property('text', [0, 'string']);
expect(wrapper.state('cache')).to.deep.equal({
expect(wrapper.props().data).to.deep.equal({
'name': 'system/array_1d_text/1',
'contents': {
'#description': '',
......@@ -121,11 +139,16 @@ describe('<DataformatEditor />', () => {
it('system/array_2d_floats/1', () => {
const dfName = 'system/array_2d_floats/1';
const saveFunc = sinon.spy();
const _updateFunc = (obj) => {
wrapper.setProps && wrapper.setProps({ data: obj });
};
const updateFunc = sinon.spy(_updateFunc);
wrapper = mount(
<C
data={{name: dfName, contents: {}}}
data={getValidObj({name: dfName, contents: {}})}
dataformats={testDfs.filter(d => d.name !== dfName)}
saveFunc={saveFunc}
updateFunc={updateFunc}
/>
);
......@@ -133,10 +156,10 @@ describe('<DataformatEditor />', () => {
['data', 'dataformats', 'saveFunc']
);
expect(wrapper.state('cache')).to.have.property('name', dfName);
expect(wrapper.props().data).to.have.property('name', dfName);
wrapper.find('input[name="description"]').simulate('change', { target: { value: 'Basic format containing a two-dimensional array of float values'}});
expect(wrapper.state('cache').contents).to.have.property('#description', 'Basic format containing a two-dimensional array of float values');
expect(wrapper.props().data.contents).to.have.property('#description', 'Basic format containing a two-dimensional array of float values');
wrapper.find('button.btn-success').simulate('click');
wrapper.find('CacheInput[placeholder="Name..."]').prop('onChange')( { target: { value: 'value' }});
......@@ -145,9 +168,9 @@ describe('<DataformatEditor />', () => {
wrapper.find('input[type="number"][min="1"]').simulate('change', { target: { value: '2' }});
wrapper.find('select').at(1).simulate('change', { target: { value: 'float64' }});
expect(wrapper.state('cache').contents).to.have.deep.property('value', [0, 0, 'float64']);
expect(wrapper.props().data.contents).to.have.deep.property('value', [0, 0, 'float64']);
expect(wrapper.state('cache')).to.deep.equal({
expect(wrapper.props().data).to.deep.equal({
'name': 'system/array_2d_floats/1',
'contents': {
'#description': 'Basic format containing a two-dimensional array of float values',
......@@ -163,11 +186,16 @@ describe('<DataformatEditor />', () => {
it('plot/bar/1', () => {
const dfName = 'plot/bar/1';
const saveFunc = sinon.spy();
const _updateFunc = (obj) => {
wrapper.setProps && wrapper.setProps({ data: obj });
};
const updateFunc = sinon.spy(_updateFunc);
wrapper = mount(
<C
data={{name: dfName, contents: {}}}
data={getValidObj({name: dfName, contents: {}})}
dataformats={testDfs.filter(d => d.name !== dfName)}
saveFunc={saveFunc}
updateFunc={updateFunc}
/>
);
......@@ -175,40 +203,40 @@ describe('<DataformatEditor />', () => {
['data', 'dataformats', 'saveFunc']
);
expect(wrapper.state('cache')).to.have.property('name', dfName);
expect(wrapper.props().data).to.have.property('name', dfName);
wrapper.find('input[name="description"]').simulate('change', { target: { value: 'Array of bar plots'}});
expect(wrapper.state('cache').contents).to.have.property('#description', 'Array of bar plots');
expect(wrapper.props().data.contents).to.have.property('#description', 'Array of bar plots');
// 'data' field
wrapper.find('.dfLevel button.btn-success').simulate('click');
wrapper.find('.dfLevel .field0 CacheInput[placeholder="Name..."]').prop('onChange')( { target: { value: 'data' }});
wrapper.find('.dfLevel .field0 select').simulate('change', { target: { value: 'array' }});
wrapper.find('.dfLevel .field0 select.subtype').simulate('change', { target: { value: 'object' }});
expect(wrapper.state('cache').contents).to.have.deep.property('data', [0, {}]);
expect(wrapper.props().data.contents).to.have.deep.property('data', [0, {}]);
// 'label' subfield
wrapper.find('.dfLevel .field0 .dfLevel button.btn-success').simulate('click');
wrapper.find('.dfLevel .field0 .dfLevel .field0 CacheInput[placeholder="Name..."]').prop('onChange')( { target: { value: 'label' }});
wrapper.find('.dfLevel .field0 .dfLevel .field0 select').simulate('change', { target: { value: 'string' }});
expect(wrapper.state('cache').contents.data[1]).to.have.deep.property('label', 'string');
expect(wrapper.props().data.contents.data[1]).to.have.deep.property('label', 'string');
// 'x' subfield
wrapper.find('.dfLevel .field0 .dfLevel button.btn-success').simulate('click');
wrapper.find('.dfLevel .field0 .dfLevel .field1 CacheInput[placeholder="Name..."]').prop('onChange')( { target: { value: 'x' }});
wrapper.find('.dfLevel .field0 .dfLevel .field1 select').simulate('change', { target: { value: 'array' }});
wrapper.find('.dfLevel .field0 .dfLevel .field1 select.subtype').simulate('change', { target: { value: 'float64' }});
expect(wrapper.state('cache').contents.data[1]).to.have.deep.property('x', [0, 'float64']);
expect(wrapper.props().data.contents.data[1]).to.have.deep.property('x', [0, 'float64']);
// 'y' subfield
wrapper.find('.dfLevel .field0 .dfLevel button.btn-success').simulate('click');
wrapper.find('.dfLevel .field0 .dfLevel .field2 CacheInput[placeholder="Name..."]').prop('onChange')( { target: { value: 'y' }});
wrapper.find('.dfLevel .field0 .dfLevel .field2 select').simulate('change', { target: { value: 'array' }});
wrapper.find('.dfLevel .field0 .dfLevel .field2 select.subtype').simulate('change', { target: { value: 'float64' }});
expect(wrapper.state('cache').contents.data[1]).to.have.deep.property('y', [0, 'float64']);
expect(wrapper.props().data.contents.data[1]).to.have.deep.property('y', [0, 'float64']);
expect(wrapper.state('cache')).to.deep.equal({
expect(wrapper.props().data).to.deep.equal({
'name': 'plot/bar/1',
'contents': {
'#description': 'Array of bar plots',
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment