Commit 12dc6e90 authored by Jaden DIEFENBAUGH's avatar Jaden DIEFENBAUGH
Browse files

[js][tc] finished test for creating test/iris/1, better logic for block double-click

parent ac51a1e3
......@@ -4113,6 +4113,24 @@
"integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=",
"dev": true
},
"deep-equal-in-any-order": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/deep-equal-in-any-order/-/deep-equal-in-any-order-1.0.10.tgz",
"integrity": "sha512-hzh3IwlIKwT885r5b/b4bXCXxzR7S9N+Dreuoommdykcnvlg0A+pS81wMU4ZsFz98CH4KBI8eWbAfDHWl7akTg==",
"dev": true,
"requires": {
"lodash": "^4.17.10",
"sort-any": "^1.1.12"
},
"dependencies": {
"lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
}
}
},
"deep-is": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
......@@ -13030,6 +13048,15 @@
}
}
},
"sort-any": {
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/sort-any/-/sort-any-1.1.12.tgz",
"integrity": "sha512-RaVPeOjzn5tjhAfvQstA34gPiG/HT+1MefSsG0KHIMhXjLlZREYSIkxlYaCRvdwLKNgpsgM6nvpLEY1Y0Ja9FQ==",
"dev": true,
"requires": {
"lodash": "^4.17.4"
}
},
"source-list-map": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz",
......
......@@ -37,6 +37,7 @@
"chai-enzyme": "^1.0.0-beta.1",
"cross-env": "^5.2.0",
"css-loader": "^1.0.0",
"deep-equal-in-any-order": "^1.0.10",
"enzyme": "^3.3.0",
"enzyme-adapter-react-16": "^1.1.1",
"eslint": "^5.2.0",
......
......@@ -910,13 +910,15 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
}
}
lastClickBlockName = ''
lastClickMs = 0
// handles left clicking on a block
handleBlockClick = (blockName: string, set: BlockSet) => {
const currTime = Date.now();
// 1sec throttling
const delay = 1000;
if(currTime - this.lastClickMs > delay){
if(currTime - this.lastClickMs > delay || blockName !== this.lastClickBlockName){
this.lastClickBlockName = blockName;
const newMBI = {
set,
name: blockName,
......@@ -926,6 +928,7 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
modalBlockInfo: newMBI,
});
}
this.lastClickBlockName = blockName;
this.lastClickMs = currTime;
}
......
// @flow
import React from 'react';
import { expect } from 'chai';
import chai, { expect } from 'chai';
import { mount } from 'enzyme';
import sinon from 'sinon';
import { spies } from '@test';
// sometimes we dont care about order of items in arrays when comparing objects deeply
import deepEqualInAnyOrder from 'deep-equal-in-any-order';
import { getValidToolchainObj as getValidObj, getValidDatabaseObj, getValidAlgorithmObj } from '@helpers/beat';
import { ToolchainEditor as C } from '.';
......@@ -14,7 +16,12 @@ import testTcs from '@test/test_tcs.json';
import testDbs from '@test/test_dbs.json';
import testAlgs from '@test/test_algs.json';
describe('<ToolchainEditor />', () => {
chai.use(deepEqualInAnyOrder);
describe('<ToolchainEditor />', function() {
// these tests might take a long time, comparatively
this.timeout(10000);
let wrapper;
afterEach(() => {
......@@ -115,11 +122,520 @@ describe('<ToolchainEditor />', () => {
const _selectBlocks = (bNames: string[]) => { return; };
const selectBlocks = sinon.spy(_selectBlocks);
/* add blocks via contextmenu handler */
// pretend to right click at a spot by calling the event handler
wrapper.instance().handleSvgContextMenu({}, { clicked: 'addDataset', x: 1, y: 1, selectBlocks });
// dataset 1 training_data @ 6,0
wrapper.instance().handleSvgContextMenu({}, { clicked: 'addDataset', x: 6, y: 0, selectBlocks });
wrapper.update();
expect(updateFunc.callCount).to.equal(1);
expect(wrapper.props().data.contents.datasets.length).to.equal(1);
// dataset 2 @ 6,5
wrapper.instance().handleSvgContextMenu({}, { clicked: 'addDataset', x: 6, y: 5, selectBlocks });
wrapper.update();
expect(updateFunc.callCount).to.equal(2);
expect(wrapper.props().data.contents.datasets.length).to.equal(2);
// block 1 (training) @ 19,0
wrapper.instance().handleSvgContextMenu({}, { clicked: 'addBlock', x: 19, y: 0, selectBlocks });
wrapper.update();
expect(updateFunc.callCount).to.equal(3);
expect(wrapper.props().data.contents.blocks.length).to.equal(1);
// block 2 (testing) @ 32,3
wrapper.instance().handleSvgContextMenu({}, { clicked: 'addBlock', x: 32, y: 3, selectBlocks });
wrapper.update();
expect(updateFunc.callCount).to.equal(4);
expect(wrapper.props().data.contents.blocks.length).to.equal(2);
// block 3 (analyzer) @ 46,4
wrapper.instance().handleSvgContextMenu({}, { clicked: 'addAnalyzer', x: 46, y: 4, selectBlocks });
wrapper.update();
expect(updateFunc.callCount).to.equal(5);
expect(wrapper.props().data.contents.analyzers.length).to.equal(1);
/* open edit modal for each & edit blocks via input onChange stuff */
// training_data
wrapper.find('rect#block_dataset').simulate('click');
wrapper.update();
expect(wrapper.find('ToolchainModal').props().active).to.equal(true);
expect(wrapper.find('.modal').find('CacheInput').props().value).to.equal('dataset');
wrapper.find('.modal').find('CacheInput').prop('onChange')( { target: { value: 'training_data' }});
wrapper.update();
wrapper.find('.modal button.btn-secondary').simulate('click');
wrapper.update();
wrapper.find('.modal button.btn-secondary').simulate('click');
wrapper.update();
wrapper.find('.modal CacheInput[value="output"]').prop('onChange')( { target: { value: 'measurements' }});
wrapper.update();
wrapper.find('.modal CacheInput[value="output0"]').prop('onChange')( { target: { value: 'species' }});
wrapper.update();
wrapper.find('button.close').simulate('click');
wrapper.update();
expect(wrapper.find('ToolchainModal').props().active).to.equal(false);
expect(wrapper.props().data.contents.datasets[0]).to.deep.equal({
'name': 'training_data',
'outputs': [
'measurements',
'species'
]
});
// testing_data
wrapper.find('rect#block_dataset0').simulate('click');
wrapper.update();
expect(wrapper.find('ToolchainModal').props().active).to.equal(true);
expect(wrapper.find('.modal').find('CacheInput').props().value).to.equal('dataset0');
wrapper.find('.modal').find('CacheInput').prop('onChange')( { target: { value: 'testing_data' }});
wrapper.update();
wrapper.find('.modal button.btn-secondary').simulate('click');
wrapper.update();
wrapper.find('.modal button.btn-secondary').simulate('click');
wrapper.update();
wrapper.find('.modal CacheInput[value="output"]').prop('onChange')( { target: { value: 'measurements' }});
wrapper.update();
wrapper.find('.modal CacheInput[value="output0"]').prop('onChange')( { target: { value: 'species' }});
wrapper.update();
wrapper.find('button.close').simulate('click');
wrapper.update();
expect(wrapper.props().data.contents.datasets[1]).to.deep.equal({
'name': 'testing_data',
'outputs': [
'measurements',
'species'
]
});
// training_alg
wrapper.find('rect#block_block').simulate('click');
wrapper.update();
expect(wrapper.find('ToolchainModal').props().active).to.equal(true);
expect(wrapper.find('.modal').find('CacheInput').props().value).to.equal('block');
wrapper.find('.modal').find('CacheInput').prop('onChange')( { target: { value: 'training_alg' }});
wrapper.update();
wrapper.find('.modal button.btn-secondary').at(0).simulate('click');
wrapper.update();
wrapper.find('.modal button.btn-secondary').at(0).simulate('click');
wrapper.update();
wrapper.find('.modal button.btn-secondary').at(1).simulate('click');
wrapper.update();
wrapper.find('.modal CacheInput[value="input"]').prop('onChange')( { target: { value: 'measurements' }});
wrapper.update();
wrapper.find('.modal CacheInput[value="input0"]').prop('onChange')( { target: { value: 'species' }});
wrapper.update();
wrapper.find('.modal CacheInput[value="output"]').prop('onChange')( { target: { value: 'lda_machine' }});
wrapper.update();
wrapper.find('button.close').simulate('click');
wrapper.update();
expect(wrapper.props().data.contents.blocks[0]).to.deep.equal({
'name': 'training_alg',
'inputs': [
'measurements',
'species'
],
'outputs': [
'lda_machine'
],
'synchronized_channel': 'training_data',
});
// testing_alg
wrapper.find('rect#block_block0').simulate('click');
wrapper.update();
expect(wrapper.find('ToolchainModal').props().active).to.equal(true);
expect(wrapper.find('.modal').find('CacheInput').props().value).to.equal('block0');
wrapper.find('.modal').find('CacheInput').prop('onChange')( { target: { value: 'testing_alg' }});
wrapper.update();
wrapper.find('.modal button.btn-secondary').at(0).simulate('click');
wrapper.update();
wrapper.find('.modal button.btn-secondary').at(0).simulate('click');
wrapper.update();
wrapper.find('.modal button.btn-secondary').at(1).simulate('click');
wrapper.update();
wrapper.find('.modal CacheInput[value="input"]').prop('onChange')( { target: { value: 'measurements' }});
wrapper.update();
wrapper.find('.modal CacheInput[value="input0"]').prop('onChange')( { target: { value: 'lda_machine' }});
wrapper.update();
wrapper.find('.modal CacheInput[value="output"]').prop('onChange')( { target: { value: 'scores' }});
wrapper.update();
wrapper.find('button.close').simulate('click');
wrapper.update();
expect(wrapper.props().data.contents.blocks[1]).to.deep.equal({
'name': 'testing_alg',
'inputs': [
'measurements',
'lda_machine'
],
'outputs': [
'scores'
],
'synchronized_channel': 'training_data',
});
// analyzer
wrapper.find('rect#block_analyzer').simulate('click');
wrapper.update();
expect(wrapper.find('ToolchainModal').props().active).to.equal(true);
expect(wrapper.find('.modal').find('CacheInput').props().value).to.equal('analyzer');
wrapper.find('.modal button.btn-secondary').simulate('click');
wrapper.update();
wrapper.find('.modal button.btn-secondary').simulate('click');
wrapper.update();
wrapper.find('.modal CacheInput[value="input"]').prop('onChange')( { target: { value: 'scores' }});
wrapper.update();
wrapper.find('.modal CacheInput[value="input0"]').prop('onChange')( { target: { value: 'species' }});
wrapper.update();
wrapper.find('button.close').simulate('click');
wrapper.update();
expect(wrapper.props().data.contents.analyzers[0]).to.deep.equal({
'name': 'analyzer',
'inputs': [
'scores',
'species'
],
'synchronized_channel': 'training_data',
});
/* connect stuff via createConnections() */
// channel: training_data
wrapper.instance().createConnections([{ from: 'training_data.measurements', to: 'training_alg.measurements', channel: 'training_data' }]);
// channel: training_data
wrapper.instance().createConnections([{ from: 'training_data.species', to: 'training_alg.species', channel: 'training_data' }]);
// channel: training_data
wrapper.instance().createConnections([{ from: 'training_alg.lda_machine', to: 'testing_alg.lda_machine', channel: 'training_data' }]);
// channel: testing_data
wrapper.instance().createConnections([{ from: 'testing_data.measurements', to: 'testing_alg.measurements', channel: 'testing_data' }]);
// channel: training_data
wrapper.instance().createConnections([{ from: 'testing_alg.scores', to: 'analyzer.scores', channel: 'training_data' }]);
// channel: testing_data
wrapper.instance().createConnections([{ from: 'testing_data.species', to: 'analyzer.species', channel: 'testing_data' }]);
/* fix channels */
// testing_alg
wrapper.find('rect#block_testing_alg').simulate('click');
wrapper.update();
expect(wrapper.find('ToolchainModal').props().active).to.equal(true);
wrapper.find('.modal select').prop('onChange')( { target: { value: 'testing_data' }});
wrapper.update();
wrapper.find('button.close').simulate('click');
wrapper.update();
expect(wrapper.props().data.contents.blocks[1]).to.deep.equal({
'name': 'testing_alg',
'inputs': [
'measurements',
'lda_machine'
],
'outputs': [
'scores'
],
'synchronized_channel': 'testing_data',
});
// analyzer
wrapper.find('rect#block_analyzer').simulate('click');
wrapper.update();
expect(wrapper.find('ToolchainModal').props().active).to.equal(true);
wrapper.find('.modal select').prop('onChange')( { target: { value: 'testing_data' }});
wrapper.update();
wrapper.find('button.close').simulate('click');
wrapper.update();
expect(wrapper.props().data.contents.analyzers[0]).to.deep.equal({
'name': 'analyzer',
'inputs': [
'scores',
'species'
],
'synchronized_channel': 'testing_data',
});
/* theres alot of expect statements here for a reason:
* each statement checks a sub-part of the toolchain
* its redundant when the test passes but helpful when somethings off,
* you can narrow the part of the tc that isn't right alot quicker
*/
const data = wrapper.props().data;
const ch1 = data.contents.representation.channel_colors['training_data'];
const ch2 = data.contents.representation.channel_colors['testing_data'];
expect(data.contents.datasets).to.deep.equalInAnyOrder( [
{
'name': 'training_data',
'outputs': [
'measurements',
'species'
]
},
{
'name': 'testing_data',
'outputs': [
'measurements',
'species'
]
}
]);
expect(data.contents.blocks).to.deep.equalInAnyOrder([
{
'inputs': [
'measurements',
'species'
],
'name': 'training_alg',
'outputs': [
'lda_machine'
],
'synchronized_channel': 'training_data'
},
{
'inputs': [
'lda_machine',
'measurements'
],
'name': 'testing_alg',
'outputs': [
'scores'
],
'synchronized_channel': 'testing_data'
}
]);
expect(data.contents.analyzers).to.deep.equalInAnyOrder([
{
'inputs': [
'scores',
'species'
],
'name': 'analyzer',
'synchronized_channel': 'testing_data'
}
]);
expect(data.contents.connections).to.deep.equalInAnyOrder([
{
'channel': 'testing_data',
'from': 'testing_alg.scores',
'to': 'analyzer.scores'
},
{
'channel': 'training_data',
'from': 'training_alg.lda_machine',
'to': 'testing_alg.lda_machine'
},
{
'channel': 'testing_data',
'from': 'testing_data.measurements',
'to': 'testing_alg.measurements'
},
{
'channel': 'training_data',
'from': 'training_data.measurements',
'to': 'training_alg.measurements'
},
{
'channel': 'training_data',
'from': 'training_data.species',
'to': 'training_alg.species'
},
{
'channel': 'testing_data',
'from': 'testing_data.species',
'to': 'analyzer.species'
}
]);
expect(data.contents.representation).to.deep.equalInAnyOrder({
'blocks': {
'analyzer': {
'col': 46,
'height': 3,
'row': 4,
'width': 10
},
'testing_alg': {
'col': 32,
'height': 3,
'row': 3,
'width': 10
},
'testing_data': {
'col': 6,
'height': 3,
'row': 5,
'width': 10
},
'training_alg': {
'col': 19,
'height': 3,
'row': 0,
'width': 10
},
'training_data': {
'col': 6,
'height': 3,
'row': 0,
'width': 10
}
},
'channel_colors': {
'testing_data': ch2,
'training_data': ch1
},
'connections': {
'testing_alg.scores/analyzer.scores': [],
'testing_data.measurements/testing_alg.measurements': [],
'testing_data.species/analyzer.species': [],
'training_alg.lda_machine/testing_alg.lda_machine': [],
'training_data.measurements/training_alg.measurements': [],
'training_data.species/training_alg.species': []
}
});
expect(data).to.deep.equalInAnyOrder({
'name': 'test/iris/1',
'contents': {
'description': '',
'datasets': [
{
'name': 'training_data',
'outputs': [
'measurements',
'species'
]
},
{
'name': 'testing_data',
'outputs': [
'measurements',
'species'
]
}
],
'blocks': [
{
'inputs': [
'measurements',
'species'
],
'name': 'training_alg',
'outputs': [
'lda_machine'
],
'synchronized_channel': 'training_data'
},
{
'inputs': [
'lda_machine',
'measurements'
],
'name': 'testing_alg',
'outputs': [
'scores'
],
'synchronized_channel': 'testing_data'
}
],
'analyzers': [
{
'inputs': [
'scores',
'species'
],
'name': 'analyzer',
'synchronized_channel': 'testing_data'
}
],
'connections': [
{
'channel': 'testing_data',
'from': 'testing_alg.scores',
'to': 'analyzer.scores'
},
{
'channel': 'training_data',
'from': 'training_alg.lda_machine',
'to': 'testing_alg.lda_machine'
},
{
'channel': 'testing_data',
'from': 'testing_data.measurements',
'to': 'testing_alg.measurements'
},
{
'channel': 'training_data',
'from': 'training_data.measurements',
'to': 'training_alg.measurements'
},
{
'channel': 'training_data',
'from': 'training_data.species',
'to': 'training_alg.species'
},
{
'channel': 'testing_data',
'from': 'testing_data.species',
'to': 'analyzer.species'
}
],
'representation': {
'blocks': {
'analyzer': {
'col': 46,
'height': 3,
'row': 4,