mirror of
https://github.com/moroshko/rxviz.git
synced 2026-01-18 16:22:20 +00:00
1050 lines
21 KiB
JavaScript
1050 lines
21 KiB
JavaScript
import sortBy from 'lodash.sortby';
|
|
import {
|
|
defaultMainColor,
|
|
defaultShapeColor,
|
|
defaultObservableColor,
|
|
colors
|
|
} from './colors';
|
|
import { isTimeout, updateData, getModel } from './data-parser';
|
|
|
|
const expectToEqual = (calculatedModel, expectedModel) => {
|
|
expect(calculatedModel.observables).toEqual(expectedModel.observables);
|
|
expect(sortBy(calculatedModel.connectors, 'time')).toEqual(
|
|
expectedModel.connectors
|
|
);
|
|
};
|
|
|
|
describe('isTimeout', () => {
|
|
it('returns false if value is not an object', () => {
|
|
expect(isTimeout(null)).toBe(false);
|
|
});
|
|
|
|
it('returns false if value is not meta', () => {
|
|
expect(isTimeout({ timeout: true })).toBe(false);
|
|
});
|
|
|
|
it('returns false if value is meta but not timeout', () => {
|
|
expect(isTimeout({ meta: true, something: 'else' })).toBe(false);
|
|
});
|
|
|
|
it('returns true if value is meta and timeout', () => {
|
|
expect(isTimeout({ meta: true, timeout: true })).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('updateData', () => {
|
|
it('updates empty values with empty path', () => {
|
|
const observable = {
|
|
type: 'observable',
|
|
values: [
|
|
// Update here
|
|
]
|
|
};
|
|
const path = [];
|
|
const value = {
|
|
time: 1000,
|
|
text: '1',
|
|
textStyle: {
|
|
fill: '#fff'
|
|
},
|
|
color: colors[1]
|
|
};
|
|
|
|
expect(updateData(observable, path, value)).toEqual({
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
text: '1',
|
|
textStyle: {
|
|
fill: '#fff'
|
|
},
|
|
color: colors[1]
|
|
}
|
|
]
|
|
});
|
|
});
|
|
|
|
it('updates non empty values with empty path', () => {
|
|
const observable = {
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
text: '1',
|
|
color: colors[1]
|
|
}
|
|
// Update here
|
|
]
|
|
};
|
|
const path = [];
|
|
const value = {
|
|
time: 3000,
|
|
completed: true
|
|
};
|
|
|
|
expect(updateData(observable, path, value)).toEqual({
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
text: '1',
|
|
color: colors[1]
|
|
},
|
|
{
|
|
time: 3000,
|
|
completed: true
|
|
}
|
|
]
|
|
});
|
|
});
|
|
|
|
it('updates values with simple path', () => {
|
|
const observable = {
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
text: '1'
|
|
}
|
|
// Update here
|
|
],
|
|
color: colors[1]
|
|
}
|
|
]
|
|
};
|
|
const path = [0];
|
|
const value = {
|
|
time: 2000,
|
|
completed: true
|
|
};
|
|
|
|
expect(updateData(observable, path, value)).toEqual({
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
text: '1'
|
|
},
|
|
{
|
|
time: 2000,
|
|
completed: true
|
|
}
|
|
],
|
|
color: colors[1]
|
|
}
|
|
]
|
|
});
|
|
});
|
|
|
|
it('updates values with deep path', () => {
|
|
const observable = {
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
text: '1'
|
|
},
|
|
{
|
|
time: 2000,
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 2000,
|
|
text: '2'
|
|
},
|
|
{
|
|
time: 3000,
|
|
text: '3'
|
|
},
|
|
{
|
|
time: 4000,
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 4000,
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 4000,
|
|
text: '4'
|
|
}
|
|
// Update here
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
time: 6000,
|
|
completed: true
|
|
}
|
|
]
|
|
}
|
|
]
|
|
};
|
|
const path = [1, 2, 0];
|
|
const value = {
|
|
time: 5000,
|
|
completed: true
|
|
};
|
|
|
|
expect(updateData(observable, path, value)).toEqual({
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
text: '1'
|
|
},
|
|
{
|
|
time: 2000,
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 2000,
|
|
text: '2'
|
|
},
|
|
{
|
|
time: 3000,
|
|
text: '3'
|
|
},
|
|
{
|
|
time: 4000,
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 4000,
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 4000,
|
|
text: '4'
|
|
},
|
|
{
|
|
time: 5000,
|
|
completed: true
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
time: 6000,
|
|
completed: true
|
|
}
|
|
]
|
|
}
|
|
]
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('getModel', () => {
|
|
it('returns model for non observable', () => {
|
|
const data = 'non observable';
|
|
|
|
expect(getModel({ data })).toEqual({
|
|
observables: [],
|
|
connectors: []
|
|
});
|
|
});
|
|
|
|
it('returns model for empty observable', () => {
|
|
const data = {
|
|
type: 'observable',
|
|
values: []
|
|
};
|
|
|
|
expect(getModel({ data })).toEqual({
|
|
observables: [
|
|
{
|
|
values: [],
|
|
startTime: 0,
|
|
mainColor: defaultMainColor
|
|
}
|
|
],
|
|
connectors: []
|
|
});
|
|
});
|
|
|
|
it('returns model for errored observable without tooltip', () => {
|
|
const data = {
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
text: '1'
|
|
},
|
|
{
|
|
time: 2000,
|
|
error: true
|
|
}
|
|
]
|
|
};
|
|
|
|
expect(getModel({ data })).toEqual({
|
|
observables: [
|
|
{
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
text: '1',
|
|
color: defaultShapeColor
|
|
}
|
|
],
|
|
error: {
|
|
time: 2000
|
|
},
|
|
startTime: 0,
|
|
endTime: 2000,
|
|
mainColor: defaultMainColor
|
|
}
|
|
],
|
|
connectors: []
|
|
});
|
|
});
|
|
|
|
it('returns model for errored observable with tooltip', () => {
|
|
const data = {
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
text: '1'
|
|
},
|
|
{
|
|
time: 2000,
|
|
error: true,
|
|
tooltip: {
|
|
text: 'Something bad happened',
|
|
textStyle: {
|
|
fontFamily: 'monospace',
|
|
whiteSpace: 'pre'
|
|
}
|
|
}
|
|
}
|
|
]
|
|
};
|
|
|
|
expect(getModel({ data })).toEqual({
|
|
observables: [
|
|
{
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
text: '1',
|
|
color: defaultShapeColor
|
|
}
|
|
],
|
|
error: {
|
|
time: 2000,
|
|
tooltip: {
|
|
text: 'Something bad happened',
|
|
textStyle: {
|
|
fontFamily: 'monospace',
|
|
whiteSpace: 'pre'
|
|
}
|
|
}
|
|
},
|
|
startTime: 0,
|
|
endTime: 2000,
|
|
mainColor: defaultMainColor
|
|
}
|
|
],
|
|
connectors: []
|
|
});
|
|
});
|
|
|
|
it('returns model for completed observable', () => {
|
|
const data = {
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
text: '1',
|
|
color: colors[1]
|
|
},
|
|
{
|
|
time: 2000,
|
|
text: '...',
|
|
tooltip: {
|
|
text: '12345678',
|
|
textStyle: {
|
|
fontSize: 10
|
|
}
|
|
}
|
|
},
|
|
{
|
|
time: 3000,
|
|
completed: true
|
|
}
|
|
]
|
|
};
|
|
|
|
expect(getModel({ data })).toEqual({
|
|
observables: [
|
|
{
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
text: '1',
|
|
color: colors[1]
|
|
},
|
|
{
|
|
time: 2000,
|
|
text: '...',
|
|
tooltip: {
|
|
text: '12345678',
|
|
textStyle: {
|
|
fontSize: 10
|
|
}
|
|
},
|
|
color: defaultShapeColor
|
|
}
|
|
],
|
|
completed: {
|
|
time: 3000,
|
|
lastValueBeforeCompletedTime: 2000
|
|
},
|
|
startTime: 0,
|
|
endTime: 3000,
|
|
mainColor: defaultMainColor
|
|
}
|
|
],
|
|
connectors: []
|
|
});
|
|
});
|
|
|
|
it('returns model for higher order observable', () => {
|
|
const data = {
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
text: '1'
|
|
},
|
|
{
|
|
time: 3000,
|
|
text: '3'
|
|
}
|
|
],
|
|
color: colors[1],
|
|
tooltip: {
|
|
text: 'This is observable'
|
|
}
|
|
},
|
|
{
|
|
time: 2000,
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 2000,
|
|
text: '2'
|
|
},
|
|
{
|
|
time: 4000,
|
|
text: '4'
|
|
}
|
|
],
|
|
color: 'blue'
|
|
},
|
|
{
|
|
time: 3000,
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 4000,
|
|
completed: true
|
|
}
|
|
],
|
|
color: '#333'
|
|
}
|
|
]
|
|
};
|
|
|
|
expectToEqual(getModel({ data }), {
|
|
observables: [
|
|
{
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
isObservable: true,
|
|
text: '',
|
|
color: colors[1],
|
|
tooltip: {
|
|
text: 'This is observable'
|
|
}
|
|
},
|
|
{
|
|
time: 2000,
|
|
isObservable: true,
|
|
text: '',
|
|
color: 'blue'
|
|
},
|
|
{
|
|
time: 3000,
|
|
isObservable: true,
|
|
text: '',
|
|
color: '#333'
|
|
}
|
|
],
|
|
startTime: 0,
|
|
mainColor: defaultMainColor
|
|
},
|
|
{
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
text: '1',
|
|
color: defaultShapeColor
|
|
},
|
|
{
|
|
time: 3000,
|
|
text: '3',
|
|
color: defaultShapeColor
|
|
}
|
|
],
|
|
startTime: 1000,
|
|
mainColor: colors[1] /* Inherited color */
|
|
},
|
|
{
|
|
values: [
|
|
{
|
|
time: 2000,
|
|
text: '2',
|
|
color: defaultShapeColor
|
|
},
|
|
{
|
|
time: 4000,
|
|
text: '4',
|
|
color: defaultShapeColor
|
|
}
|
|
],
|
|
startTime: 2000,
|
|
mainColor: 'blue' /* Inherited color */
|
|
},
|
|
{
|
|
values: [],
|
|
completed: {
|
|
time: 4000
|
|
},
|
|
startTime: 3000,
|
|
endTime: 4000,
|
|
mainColor: '#333' /* Inherited color */
|
|
}
|
|
],
|
|
connectors: [
|
|
{
|
|
time: 1000,
|
|
fromIndex: 0,
|
|
toIndex: 1,
|
|
color: colors[1]
|
|
},
|
|
{
|
|
time: 2000,
|
|
fromIndex: 0,
|
|
toIndex: 2,
|
|
color: 'blue'
|
|
},
|
|
{
|
|
time: 3000,
|
|
fromIndex: 0,
|
|
toIndex: 3,
|
|
color: '#333'
|
|
}
|
|
]
|
|
});
|
|
});
|
|
|
|
it('uses renderer to build the model', () => {
|
|
const data = {
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
value:
|
|
'1' /* When renderer exists, values are passed, not text. */
|
|
},
|
|
{
|
|
time: 2000,
|
|
error: true
|
|
}
|
|
]
|
|
}
|
|
]
|
|
};
|
|
const renderer = ({ isObservable, isError, value }) => {
|
|
if (isObservable) {
|
|
return {
|
|
text: 'OBS',
|
|
color: 'blue'
|
|
};
|
|
}
|
|
|
|
if (isError) {
|
|
return {
|
|
tooltip: {
|
|
text: 'Error'
|
|
}
|
|
};
|
|
}
|
|
|
|
return {
|
|
text: `Value: ${value}`,
|
|
textStyle: {
|
|
fontSize: 10
|
|
}
|
|
};
|
|
};
|
|
|
|
expectToEqual(getModel({ data, renderer }), {
|
|
observables: [
|
|
{
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
isObservable: true,
|
|
text: 'OBS',
|
|
color: 'blue'
|
|
}
|
|
],
|
|
startTime: 0,
|
|
mainColor: defaultMainColor
|
|
},
|
|
{
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
text: 'Value: 1',
|
|
textStyle: {
|
|
fontSize: 10
|
|
},
|
|
color: defaultShapeColor
|
|
}
|
|
],
|
|
startTime: 1000,
|
|
endTime: 2000,
|
|
error: {
|
|
error: true,
|
|
time: 2000,
|
|
tooltip: {
|
|
text: 'Error'
|
|
}
|
|
},
|
|
mainColor: 'blue' /* Inherited color */
|
|
}
|
|
],
|
|
connectors: [
|
|
{
|
|
time: 1000,
|
|
fromIndex: 0,
|
|
toIndex: 1,
|
|
color: 'blue'
|
|
}
|
|
]
|
|
});
|
|
});
|
|
|
|
it('does not inherit main color when inheritMainColor is false', () => {
|
|
const data = {
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
text: '1'
|
|
}
|
|
],
|
|
color: colors[1]
|
|
}
|
|
]
|
|
};
|
|
const inheritMainColor = false;
|
|
|
|
expectToEqual(getModel({ data, inheritMainColor }), {
|
|
observables: [
|
|
{
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
isObservable: true,
|
|
text: '',
|
|
color: colors[1]
|
|
}
|
|
],
|
|
startTime: 0,
|
|
mainColor: defaultMainColor
|
|
},
|
|
{
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
text: '1',
|
|
color: defaultShapeColor
|
|
}
|
|
],
|
|
startTime: 1000,
|
|
mainColor: defaultMainColor
|
|
}
|
|
],
|
|
connectors: [
|
|
{
|
|
time: 1000,
|
|
fromIndex: 0,
|
|
toIndex: 1,
|
|
color: defaultMainColor
|
|
}
|
|
]
|
|
});
|
|
});
|
|
|
|
it('merges values when mergeThreshold exists', () => {
|
|
const data = {
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
text: '1'
|
|
},
|
|
{
|
|
time: 1010,
|
|
text: '2'
|
|
},
|
|
{
|
|
time: 1022,
|
|
text: '3'
|
|
},
|
|
{
|
|
time: 2000,
|
|
text: '...',
|
|
tooltip: {
|
|
text: 'Four'
|
|
}
|
|
},
|
|
{
|
|
time: 2012,
|
|
text: '5'
|
|
}
|
|
]
|
|
};
|
|
const mergeThreshold = 100;
|
|
|
|
expectToEqual(getModel({ data, mergeThreshold }), {
|
|
observables: [
|
|
{
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
count: 3,
|
|
text: '...',
|
|
tooltip: {
|
|
text: '1, 2, 3'
|
|
},
|
|
color: defaultShapeColor
|
|
},
|
|
{
|
|
time: 2000,
|
|
count: 2,
|
|
text: '...',
|
|
tooltip: {
|
|
text: 'Four, 5'
|
|
},
|
|
color: defaultShapeColor
|
|
}
|
|
],
|
|
startTime: 0,
|
|
mainColor: defaultMainColor
|
|
}
|
|
],
|
|
connectors: []
|
|
});
|
|
});
|
|
|
|
it('returns model for deep higher order observable', () => {
|
|
const data = {
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
text: '1'
|
|
},
|
|
{
|
|
time: 3000,
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 4000,
|
|
text: '4'
|
|
},
|
|
{
|
|
time: 4000,
|
|
completed: true
|
|
}
|
|
]
|
|
},
|
|
{
|
|
time: 5000,
|
|
completed: true
|
|
}
|
|
],
|
|
color: '#123'
|
|
},
|
|
{
|
|
time: 2000,
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 2000,
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 2000,
|
|
text: '2'
|
|
},
|
|
{
|
|
time: 3000,
|
|
text: '3'
|
|
},
|
|
{
|
|
time: 3000,
|
|
completed: true
|
|
}
|
|
],
|
|
color: '#111'
|
|
},
|
|
{
|
|
time: 4000,
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 4000,
|
|
text: '4'
|
|
},
|
|
{
|
|
time: 5000,
|
|
text: '5'
|
|
}
|
|
],
|
|
color: '#222'
|
|
},
|
|
{
|
|
time: 5000,
|
|
type: 'observable',
|
|
values: [
|
|
{
|
|
time: 5000,
|
|
text: '5'
|
|
}
|
|
],
|
|
color: '#333'
|
|
},
|
|
{
|
|
time: 5000,
|
|
completed: true
|
|
}
|
|
],
|
|
color: '#456'
|
|
}
|
|
]
|
|
};
|
|
|
|
expectToEqual(getModel({ data }), {
|
|
observables: [
|
|
{
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
isObservable: true,
|
|
text: '',
|
|
color: '#123'
|
|
},
|
|
{
|
|
time: 2000,
|
|
isObservable: true,
|
|
text: '',
|
|
color: '#456'
|
|
}
|
|
],
|
|
startTime: 0,
|
|
mainColor: '#000000'
|
|
},
|
|
{
|
|
values: [
|
|
{
|
|
time: 1000,
|
|
text: '1',
|
|
color: defaultShapeColor
|
|
},
|
|
{
|
|
time: 3000,
|
|
isObservable: true,
|
|
text: '',
|
|
color: defaultObservableColor
|
|
}
|
|
],
|
|
completed: {
|
|
time: 5000,
|
|
lastValueBeforeCompletedTime: 3000
|
|
},
|
|
startTime: 1000,
|
|
endTime: 5000,
|
|
mainColor: '#123'
|
|
},
|
|
{
|
|
values: [
|
|
{
|
|
time: 2000,
|
|
isObservable: true,
|
|
text: '',
|
|
color: '#111'
|
|
},
|
|
{
|
|
time: 4000,
|
|
isObservable: true,
|
|
text: '',
|
|
color: '#222'
|
|
},
|
|
{
|
|
time: 5000,
|
|
isObservable: true,
|
|
text: '',
|
|
color: '#333'
|
|
}
|
|
],
|
|
completed: {
|
|
time: 5000,
|
|
lastValueBeforeCompletedTime: 5000
|
|
},
|
|
startTime: 2000,
|
|
endTime: 5000,
|
|
mainColor: '#456'
|
|
},
|
|
{
|
|
values: [
|
|
{
|
|
time: 2000,
|
|
text: '2',
|
|
color: defaultShapeColor
|
|
},
|
|
{
|
|
time: 3000,
|
|
text: '3',
|
|
color: defaultShapeColor
|
|
}
|
|
],
|
|
completed: {
|
|
time: 3000,
|
|
lastValueBeforeCompletedTime: 3000
|
|
},
|
|
startTime: 2000,
|
|
endTime: 3000,
|
|
mainColor: '#111'
|
|
},
|
|
{
|
|
values: [
|
|
{
|
|
time: 4000,
|
|
text: '4',
|
|
color: defaultShapeColor
|
|
}
|
|
],
|
|
completed: {
|
|
time: 4000,
|
|
lastValueBeforeCompletedTime: 4000
|
|
},
|
|
startTime: 3000,
|
|
endTime: 4000,
|
|
mainColor: defaultObservableColor /* Inherited color */
|
|
},
|
|
{
|
|
values: [
|
|
{
|
|
time: 4000,
|
|
text: '4',
|
|
color: defaultShapeColor
|
|
},
|
|
{
|
|
time: 5000,
|
|
text: '5',
|
|
color: defaultShapeColor
|
|
}
|
|
],
|
|
startTime: 4000,
|
|
mainColor: '#222'
|
|
},
|
|
{
|
|
values: [
|
|
{
|
|
time: 5000,
|
|
text: '5',
|
|
color: defaultShapeColor
|
|
}
|
|
],
|
|
startTime: 5000,
|
|
mainColor: '#333'
|
|
}
|
|
],
|
|
connectors: [
|
|
{
|
|
time: 1000,
|
|
fromIndex: 0,
|
|
toIndex: 1,
|
|
color: '#123'
|
|
},
|
|
{
|
|
time: 2000,
|
|
fromIndex: 0,
|
|
toIndex: 2,
|
|
color: '#456'
|
|
},
|
|
{
|
|
time: 2000,
|
|
fromIndex: 2,
|
|
toIndex: 3,
|
|
color: '#111'
|
|
},
|
|
{
|
|
time: 3000,
|
|
fromIndex: 1,
|
|
toIndex: 4,
|
|
color: defaultObservableColor /* Inherited color */
|
|
},
|
|
{
|
|
time: 4000,
|
|
fromIndex: 2,
|
|
toIndex: 5,
|
|
color: '#222'
|
|
},
|
|
{
|
|
time: 5000,
|
|
fromIndex: 2,
|
|
toIndex: 6,
|
|
color: '#333'
|
|
}
|
|
]
|
|
});
|
|
});
|
|
});
|