Commit 5fa0cdd3 authored by Sascha Herzinger's avatar Sascha Herzinger
Browse files

lots of new tests and code cleanup

parent 4aa65d75
Pipeline #3359 passed with stages
in 3 minutes and 39 seconds
import {version} from '../package.json'
import { version } from '../package.json'
import store from './store/store'
import RequestManager from './services/request-manager'
import ChartManager from './services/chart-manager'
......
......@@ -104,12 +104,12 @@ export default {
context.commit(types.UNSET_TASK, taskID)
},
/**
* Commits a control panel vm for keeping track of all such instances.
* @param context The context of the action.
* @param vm The vm of the control panel.
* Commits panel states to control them on a global level.
* @param context: The context of the action.
* @param options: An object that contains options for a control panel.
*/
addControlPanel: (context, vm) => {
context.commit(types.ADD_CONTROL_PANEL, vm)
setControlPanel: (context, options) => {
context.commit(types.SET_CONTROL_PANEL, options)
},
/**
* Commits an option object if it is defined that all components can access for configuration.
......
......@@ -5,7 +5,7 @@ export default {
requestManager: state => state.requestManager,
chartManager: state => state.chartManager,
stateManager: state => state.stateManager,
controlPanels: state => state.controlPanels,
controlPanel: state => state.controlPanel,
filter: state => name => state.filters[name],
options: state => state.options
}
......@@ -7,6 +7,6 @@ export default {
SET_FILTER: 'SET_FILTER',
SET_TASK: 'SET_TASK',
UNSET_TASK: 'UNSET_TASK',
ADD_CONTROL_PANEL: 'ADD_CONTROL_PANEL',
SET_CONTROL_PANEL: 'SET_CONTROL_PANEL',
SET_OPTIONS: 'SET_OPTIONS'
}
......@@ -34,8 +34,8 @@ export default {
[types.UNSET_TASK] (state, taskID) {
Vue.delete(state.tasks, taskID)
},
[types.ADD_CONTROL_PANEL] (state, vm) {
state.controlPanels.push(vm)
[types.SET_CONTROL_PANEL] (state, options) {
Object.assign(state.controlPanel, options)
},
[types.SET_OPTIONS] (state, options) {
Object.assign(state.options, options)
......
......@@ -12,7 +12,10 @@ const state = {
requestManager: null,
chartManager: null,
stateManager: null,
controlPanels: [],
controlPanel: {
locked: false,
expanded: false
},
subsets: [],
filters: {
ids: []
......@@ -22,9 +25,17 @@ const state = {
}
}
export default new Vuex.Store({
const store = new Vuex.Store({
state,
getters,
actions,
mutations
})
const initialState = JSON.parse(JSON.stringify(store.state))
export function resetState () {
store.replaceState(JSON.parse(JSON.stringify(initialState)))
}
export default store
<template>
<chart v-on:resize="resize">
<control-panel class="fjs-control-panel">
<control-panel class="fjs-control-panel" name="Boxplot Panel">
<data-box class="fjs-data-box"
header="Numerical Variables"
dataType="numerical"
......
<template>
<chart v-on:resize="resize">
<control-panel class="fjs-control-panel">
<control-panel class="fjs-control-panel" name="Correlation Analysis">
<data-box class="fjs-data-box"
header="Numerical Variables"
dataType="numerical,numerical_array"
......
<template>
<chart v-on:resize="resize">
<control-panel class="fjs-control-panel">
<control-panel class="fjs-control-panel" name="Heatmap Panel">
<data-box class="fjs-data-box"
header="Numerical Variables"
dataType="numerical_array"
......
<template>
<chart v-on:resize="resize">
<control-panel class="fjs-control-panel">
<control-panel class="fjs-control-panel" name="PCA Panel">
<data-box class="fjs-data-box"
header="Numerical Variables"
dataType="numerical,numerical_array"
......
<template>
<div class="fjs-control-panel"
:style="{width: shown ? '15vw' : '1vw', left: left, right: right}"
:style="{width: width, left: left, right: right}"
v-show="focused"
@mouseover="locked ? noop() : show()"
@mouseout="locked ? noop() : hide()">
@mouseover="show()"
@mouseout="hide()">
<span class="fjs-panel-label" v-show="!expanded">Control Panel</span>
<div class="fjs-panel-header">
<span v-show="shown">{{ chartName }}</span>
<span v-show="expanded">{{ name }}</span>
<i class="fjs-lock-btn material-icons" @click="toggleLock">{{ lockIcon }}</i>
</div>
<span class="fjs-panel-label" v-show="!shown">Control Panel</span>
<div v-show="shown">
<div v-show="expanded">
<slot/>
<hr class="fjs-seperator"/>
<task-view/>
......@@ -22,75 +22,68 @@
import store from '../../store/store'
export default {
name: 'control-panel',
props: {},
data () {
return {
focused: true,
locked: false,
expanded: false,
shown: true
focused: true
}
},
props: {
name: {
type: String,
required: true
}
},
computed: {
locked () {
return store.getters.controlPanel.locked
},
expanded () {
return store.getters.controlPanel.expanded
},
lockIcon () {
return this.locked ? 'lock' : 'lock_open'
},
chartName () {
return this.$parent.$parent.$options.name
},
left () {
return store.getters.options.controlPanelPosition === 'left' ? 0 : ''
},
right () {
return store.getters.options.controlPanelPosition === 'right' ? 0 : ''
},
width () {
return this.expanded ? '15vw' : '1vw'
}
},
methods: {
noop () {},
toggleLock () {
this.locked = !this.locked
this.propagateState()
store.dispatch('setControlPanel', {locked: !store.getters.controlPanel.locked})
},
show () {
this.expanded = true
this.propagateState()
this.shown = true
if (!this.locked) {
store.dispatch('setControlPanel', {expanded: true})
}
},
hide () {
this.expanded = false
this.propagateState()
this.shown = false
if (!this.locked) {
store.dispatch('setControlPanel', {expanded: false})
}
},
focus () {
this.unfocusAll()
this.focused = true
this.$nextTick(() => {
this.expanded ? this.show(false) : this.hide(false)
this.expanded ? this.show() : this.hide()
})
},
unFocus () {
this.focused = false
},
unfocusAll () {
store.getters.controlPanels.forEach(panel => {
panel.unFocus()
})
},
propagateState () {
store.getters.controlPanels.forEach(panel => {
panel.locked = this.locked
panel.expanded = this.expanded
Array.prototype.forEach.call(document.querySelectorAll('.fjs-control-panel'), panel => {
panel.__vue__.unFocus()
})
}
},
mounted () {
window.addEventListener('resize', () => {
this.expanded ? this.show(false) : this.hide(false)
})
this.hide()
},
created () {
store.dispatch('addControlPanel', this)
this.unfocusAll()
this.focused = true
},
......
......@@ -65,7 +65,8 @@
},
computed: {
items () {
return store.getters.data.filter(item => ~this.dataType.split(',').map(s => s.trim()).indexOf(item.data_type))
return store.getters.data
.filter(item => ~this.dataType.split(',').map(s => s.trim()).indexOf(item.data_type))
},
transformedIDs () {
return this.selectedIDs.map(id => `$${JSON.stringify({id, filters: { feature: this.featureFilter[id] }})}$`)
......
<template>
<div class="fjs-task-view">
<div class="fjs-state-container" v-for="task in incompleteTasks">
<div class="fjs-state-container"
v-for="task in tasks"
v-if="task.taskState === 'SUBMITTED' || task.taskState === 'FAILED'">
<loader class="fjs-loader" :style="{opacity: task.taskState === 'SUBMITTED' ? 1 : 0}"/>
<span class="fjs-submitted" v-if="task.taskState === 'SUBMITTED'">{{ task.taskName }}</span>
<span class="fjs-failed" v-else>{{ task.taskMessage }}</span>
......@@ -17,18 +19,9 @@
components: {
Loader
},
data () {
return {
}
},
computed: {
tasks () {
return store.getters.tasks
},
incompleteTasks () {
return Object.keys(this.tasks)
.filter(key => { return this.tasks[key].taskState !== 'SUCCESS' })
.map(key => this.tasks[key])
}
},
methods: {
......
......@@ -88,10 +88,10 @@
}
function setCharts () {
// fjs.setChart('correlation-analysis', '.container-1')
fjs.setChart('correlation-analysis', '.container-1')
fjs.setChart('boxplot', '.container-2')
// fjs.setChart('heatmap', '.container-3')
// fjs.setChart('pca-analysis', '.container-4')
fjs.setChart('heatmap', '.container-3')
fjs.setChart('pca-analysis', '.container-4')
}
function resize () {
......
import ControlPanel from '../src/vue/components/ControlPanel.vue'
import Vue from 'vue'
import store, { resetState } from '../src/store/store'
describe('ControlPanel', () => {
let vm
beforeEach(() => {
resetState()
const div1 = document.createElement('div')
div1.id = 'div1'
const div2 = document.createElement('div')
div2.id = 'div2'
document.body.appendChild(div1)
document.body.appendChild(div2)
const Component = Vue.extend(ControlPanel)
vm = new Component({propsData: {name: 'foo'}}).$mount('#div1')
})
afterEach(() => {
document.body.innerHTML = ''
})
it('is not locked initially', () => {
expect(vm.lockIcon).toBe('lock_open')
expect(vm.locked).toBeFalsy()
})
it('is locked if other panel is locked', () => {
const Component = Vue.extend(ControlPanel)
const _vm = new Component({propsData: {name: 'foo'}}).$mount('#div2')
_vm.$el.querySelector('.fjs-lock-btn').click()
Vue.nextTick(() => {
expect(vm.lockIcon).toBe('lock')
expect(vm.locked).toBeTruthy()
})
})
it('is not expanded initially', () => {
expect(vm.expanded).toBeFalsy()
})
it('is expanded if other panel is expanded', () => {
const Component = Vue.extend(ControlPanel)
const _vm = new Component({propsData: {name: 'foo'}}).$mount('#div2')
expect(_vm.expanded).toBeFalsy()
expect(vm.expanded).toBeFalsy()
_vm.show()
Vue.nextTick(() => {
expect(_vm.expanded).toBeTruthy()
expect(vm.expanded).toBeTruthy()
})
})
it('adapts width when expanded state changes', () => {
expect(vm.width).toBe('1vw')
store.dispatch('setControlPanel', {expanded: true})
Vue.nextTick(() => {
expect(vm.width).toBe('15vw')
})
})
it('expands when show() is called and not locked', () => {
expect(vm.expanded).toBeFalsy()
expect(vm.locked).toBeFalsy()
vm.show()
Vue.nextTick(() => {
expect(vm.expanded).toBeTruthy()
expect(vm.locked).toBeFalsy()
})
})
it('does not expand when show() is called and locked', () => {
expect(vm.locked).toBeFalsy()
expect(vm.expanded).toBeFalsy()
vm.toggleLock()
vm.show()
Vue.nextTick(() => {
expect(vm.locked).toBeTruthy()
expect(vm.expanded).toBeFalsy()
})
})
it('collapses when hide() is called and not locked', () => {
vm.show()
Vue.nextTick(() => {
expect(vm.expanded).toBeTruthy()
expect(vm.locked).toBeFalsy()
vm.hide()
Vue.nextTick(() => {
expect(vm.expanded).toBeFalsy()
})
})
})
it('does not collapse when hide() is called and locked', () => {
vm.show()
vm.toggleLock()
Vue.nextTick(() => {
expect(vm.expanded).toBeTruthy()
expect(vm.locked).toBeTruthy()
vm.hide()
Vue.nextTick(() => {
expect(vm.expanded).toBeTruthy()
})
})
})
it('new panel has auto focus', () => {
const Component = Vue.extend(ControlPanel)
const _vm = new Component({propsData: {name: 'foo'}}).$mount('#div2')
expect(vm.focused).toBeFalsy()
expect(_vm.focused).toBeTruthy()
})
})
import Vue from 'vue'
import DataBox from '../src/vue/components/DataBox.vue'
import store from '../src/store/store'
import store, { resetState } from '../src/store/store'
describe('DataBox', () => {
afterEach(() => {
store.state.data = []
resetState()
})
it('has correct name', () => {
......
......@@ -3,22 +3,20 @@ import RequestManager from '../src/services/request-manager'
import ChartManager from '../src/services/chart-manager'
import Vue from 'vue'
import stateSaver from '../src/vue/mixins/state-saver'
import store from '../src/store/store'
import store, { resetState } from '../src/store/store'
import Chart from '../src/vue/components/Chart.vue'
describe('state manager', () => {
let stateManager
beforeAll(() => {
let vm
beforeEach(() => {
resetState()
stateManager = new StateManager()
const chartManager = new ChartManager()
const requestManager = new RequestManager(
{handler: '', dataSource: '', fractalisNode: '', getAuth: () => {}})
store.dispatch('setRequestManager', requestManager)
store.dispatch('setChartManager', chartManager)
})
let vm
beforeEach(() => {
const container = document.createElement('div')
const el = document.createElement('div')
el.id = 'chart'
......
import TaskView from '../src/vue/components/TaskView.vue'
import store, { resetState } from '../src/store/store'
import Vue from 'vue'
import RequestManager from '../src/services/request-manager'
describe('TaskView', () => {
let vm
beforeEach(() => {
resetState()
const requestManager = new RequestManager(
{handler: '', dataSource: '', fractalisNode: '', getAuth: () => {}})
store.dispatch('setRequestManager', requestManager)
const Component = Vue.extend(TaskView)
vm = new Component().$mount()
})
it('shows all SUBMITTED or FAILED tasks in store', () => {
store.dispatch('setTask', {taskID: 1, taskName: 'A', taskState: 'SUBMITTED'})
store.dispatch('setTask', {taskID: 2, taskName: 'B', taskState: 'SUCCESS'})
store.dispatch('setTask', {taskID: 3, taskName: 'C', taskState: 'SUBMITTED'})
store.dispatch('setTask', {taskID: 4, taskName: 'D', taskState: 'FAILED'})
store.dispatch('setTask', {taskID: 5, taskName: 'E', taskState: 'YAY'})
store.dispatch('setTask', {taskID: 6, taskName: 'F', taskState: 'PENDING'})
Vue.nextTick(() => {
expect(Object.keys(store.getters.tasks).length).toBe(6)
expect(Object.keys(vm.incompleteTasks).length).toBe(2)
expect(vm.$el.querySelectorAll('.fjs-state-container').length).toBe(3)
expect(vm.$el.querySelectorAll('.fjs-submitted').length).toBe(2)
expect(vm.$el.querySelectorAll('.fjs-failed').length).toBe(1)
})
})
it('cancel button works', () => {
store.dispatch('setTask', {taskID: 1, taskName: 'A', taskState: 'SUBMITTED'})
store.dispatch('setTask', {taskID: 2, taskName: 'B', taskState: 'FAILED'})
Vue.nextTick(() => {
expect(Object.keys(store.getters.tasks).length).toBe(2)
expect(vm.$el.querySelectorAll('.fjs-state-container').length).toBe(2)
vm.$el.querySelectorAll('.fjs-cancel-btn').forEach(button => button.click())
Vue.nextTick(() => {
expect(Object.keys(store.getters.tasks).length).toBe(0)
expect(vm.$el.querySelectorAll('.fjs-state-container').length).toBe(0)
})
})
})
})
Markdown is supported
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