Skip to content

Commit

Permalink
Fixes and add unit tests
Browse files Browse the repository at this point in the history
Signed-off-by: abbyhu2000 <[email protected]>
  • Loading branch information
abbyhu2000 committed Sep 23, 2022
1 parent fdac910 commit 3e66361
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 51 deletions.
28 changes: 28 additions & 0 deletions src/plugins/wizard/public/application/utils/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"type": "object",
"properties": {
"styleState": {
"type": "object"
},
"visualizationState": {
"type": "object",
"properties": {
"activeVisualization": {
"type": "object",
"properties": {
"name": { "type": "string" },
"aggConfigParams": { "type": "array" }
},
"required": ["name", "aggConfigParams"],
"additionalProperties": false
},
"indexPattern": { "type": "string" },
"searchField": { "type": "string" }
},
"required": ["searchField"],
"additionalProperties": false
}
},
"required": ["styleState", "visualizationState"],
"additionalProperties": false
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
} from '../state_management';
import { useOpenSearchDashboards } from '../../../../../opensearch_dashboards_react/public';
import { setEditorState } from '../state_management/metadata_slice';
import { wizardStateValidation } from '../wizard_state_validation';
import { validateWizardState } from '../wizard_state_validation';

// This function can be used when instantiating a saved vis or creating a new one
// using url parameters, embedding and destroying it in DOM
Expand Down Expand Up @@ -69,7 +69,7 @@ export const useSavedWizardVis = (visualizationIdFromUrl: string | undefined) =>
indexPattern: savedWizardVis.searchSourceFields.index,
};

const isInvalid = wizardStateValidation({ styleState, visualizationState });
const isInvalid = validateWizardState({ styleState, visualizationState });
if (isInvalid) {
const err = isInvalid[0];
const errMsg = err.instancePath + ' ' + err.message;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { validateWizardState } from './wizard_state_validation';

describe('wizard state validation', () => {
const validStyleState = {
addLegend: true,
addTooltip: true,
legendPosition: '',
type: 'metric',
};
const validVisualizationState = {
activeVisualization: {
name: 'metric',
aggConfigParams: [],
},
indexPattern: '',
searchField: '',
};
describe('return null when validation suceeds', () => {
test('with correct wizard state that every field present', () => {
const validationResult = validateWizardState({
styleState: validStyleState,
visualizationState: validVisualizationState,
});
expect(validationResult).toEqual(undefined);
});
test('with correct wizard that optional field not present', () => {
const validEmptyStyleState = {};
const validEmptyVisualizationState = {
searchField: '',
};
const validationResult = validateWizardState({
styleState: validEmptyStyleState,
visualizationState: validEmptyVisualizationState,
});
expect(validationResult).toEqual(undefined);
});
});
describe('return error when validation fails', () => {
describe('style state validation fails', () => {
test('with non object type', () => {
const validationResult = validateWizardState({
styleState: [],
visualizationState: validVisualizationState,
});
expect(validationResult).not.toEqual(undefined);
});
});
describe('visualization state validation fails', () => {
test('with no search field', () => {
const vizStateWithoutSearchField = {
activeVisualization: {
name: 'metric',
aggConfigParams: [],
},
indexPattern: '',
};
const validationResult = validateWizardState({
styleState: validStyleState,
visualizationState: vizStateWithoutSearchField,
});
expect(validationResult).not.toEqual(undefined);
});
test('with wrong search field type', () => {
const vizStateWithWrongSearchField = {
searchField: {},
};
const validationResult = validateWizardState({
styleState: validStyleState,
visualizationState: vizStateWithWrongSearchField,
});
expect(validationResult).not.toEqual(undefined);
});
test('with wrong index pattern type', () => {
const vizStateWithWrongIndexPattern = {
indexPattern: {},
searchField: '',
};
const validationResult = validateWizardState({
styleState: validStyleState,
visualizationState: vizStateWithWrongIndexPattern,
});
expect(validationResult).not.toEqual(undefined);
});
test('with wrong activeVisualization type', () => {
const vizStateWithWrongActiveViz = {
activeVisualization: '',
searchField: '',
};
const validationResult = validateWizardState({
styleState: validStyleState,
visualizationState: vizStateWithWrongActiveViz,
});
expect(validationResult).not.toEqual(undefined);
});
test('with wrong activeVisualization name type', () => {
const vizStateWithWrongActiveVizName = {
activeVisualization: {
name: {},
},
searchField: '',
};
const validationResult = validateWizardState({
styleState: validStyleState,
visualizationState: vizStateWithWrongActiveVizName,
});
expect(validationResult).not.toEqual(undefined);
});
test('with wrong activeVisualization agg type', () => {
const vizStateWithWrongActiveVizAgg = {
activeVisualization: {
aggConfigParams: {},
},
searchField: '',
};
const validationResult = validateWizardState({
styleState: validStyleState,
visualizationState: vizStateWithWrongActiveVizAgg,
});
expect(validationResult).not.toEqual(undefined);
});
});
describe('wizard state validation fail', () => {
test('with non object wizard state type', () => {
const validationResult = validateWizardState([]);
expect(validationResult).not.toEqual(undefined);
});
test('without styleState', () => {
const validationResult = validateWizardState({
visualizationState: validVisualizationState,
});
expect(validationResult).not.toEqual(undefined);
});
test('without vizState', () => {
const validationResult = validateWizardState({ styleState: validStyleState });
expect(validationResult).not.toEqual(undefined);
});
test('with extra state other than style and visualization', () => {
const validationResult = validateWizardState({
styleState: validStyleState,
visualizationState: validVisualizationState,
extra: {},
});
expect(validationResult).not.toEqual(undefined);
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,50 +4,14 @@
*/

import Ajv from 'ajv';
import wizardStateSchema from './schema.json';

export const wizardStateValidation = (wizardState) => {
export const validateWizardState = (wizardState) => {
const ajv = new Ajv();
const vizTypeEnum = ['metric', 'line', 'area', 'histogram'];

const wizardStateSchema = {
type: 'object',
properties: {
styleState: {
type: 'object',
properties: {
addLegend: { type: 'boolean' },
addTooltip: { type: 'boolean' },
legendPosition: { type: 'string' },
type: { enum: vizTypeEnum },
},
required: ['addLegend', 'addTooltip', 'type'],
},
visualizationState: {
type: 'object',
properties: {
activeVisualization: {
type: 'object',
properties: {
name: { enum: vizTypeEnum },
aggConfigParams: { type: 'array' },
},
required: ['name', 'aggConfigParams'],
additionalProperties: false,
},
indexPattern: { type: 'string' },
searchField: { type: 'string' },
},
required: ['activeVisualization', 'searchField', 'indexPattern'],
additionalProperties: false,
},
},
required: ['styleState', 'visualizationState'],
additionalProperties: false,
};

const isWizardStateValid = ajv.validate(wizardStateSchema, wizardState);
const validateState = ajv.compile(wizardStateSchema);
const isWizardStateValid = validateState(wizardState);

if (!isWizardStateValid) {
return ajv.errors;
return validateState.errors;
}
};
16 changes: 8 additions & 8 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -11911,10 +11911,10 @@ [email protected]:
resolved "https://registry.yarnpkg.com/leaflet-responsive-popup/-/leaflet-responsive-popup-0.6.4.tgz#b93d9368ef9f96d6dc911cf5b96d90e08601c6b3"
integrity sha512-2D8G9aQA6NHkulDBPN9kqbUCkCpWQQ6dF0xFL11AuEIWIbsL4UC/ZPP5m8GYM0dpU6YTlmyyCh1Tz+cls5Q4dg==

"leaflet-vega@npm:@amoo-miki/[email protected].7":
version "0.8.7"
resolved "https://registry.yarnpkg.com/@amoo-miki/leaflet-vega/-/leaflet-vega-0.8.7.tgz#8faca1b4b8e2ef7d48667ac6faad9204f4da7153"
integrity sha512-T4M5yziwj3Fi9Adsbce+cdWqPjON0BRwEjwqLlPMoirU1vhifA6YKrlZkVzJrK0IIm+hdfMCLkBz33gD8fdxzQ==
"leaflet-vega@npm:@amoo-miki/[email protected].8":
version "0.8.8"
resolved "https://registry.yarnpkg.com/@amoo-miki/leaflet-vega/-/leaflet-vega-0.8.8.tgz#675abf37d72fbea859755e982f4fd19dea776557"
integrity sha512-W2gGgFDxzy/XUx+fQJfz0NYVXsKl7V+G6QywiMcOV5NEodDId9c60up7NNf+cfM7ggpo+5BuLqrKmosuGO1CsA==
dependencies:
vega-spec-injector "^0.0.2"

Expand Down Expand Up @@ -18353,10 +18353,10 @@ vega-hierarchy@~4.1.0:
vega-dataflow "^5.7.3"
vega-util "^1.15.2"

"vega-interpreter@npm:@amoo-miki/[email protected].5":
version "1.0.5"
resolved "https://registry.yarnpkg.com/@amoo-miki/vega-forced-csp-compliant-interpreter/-/vega-forced-csp-compliant-interpreter-1.0.5.tgz#49970be9b00ca7e45ced0617fbf373c77a28aab4"
integrity sha512-lfeU77lVoUbSCC6N1ywdKg+I6K08xpkd82TLon+LebtKyC8aLCe7P5Dd/89zAPyFwRyobKftHu8z0xpV7R7a4Q==
"vega-interpreter@npm:@amoo-miki/[email protected].6":
version "1.0.6"
resolved "https://registry.yarnpkg.com/@amoo-miki/vega-forced-csp-compliant-interpreter/-/vega-forced-csp-compliant-interpreter-1.0.6.tgz#5cffdf12b7fe12dc936194edd9e8519506c38716"
integrity sha512-9S5nTTVd8JVKobcWp5iwirIeePiamwH1J9uSZPuG5kcF0TUBvGu++ERKjNdst5Qck7e4R6/7vjx2wVf58XUarg==

vega-label@~1.2.0:
version "1.2.0"
Expand Down

0 comments on commit 3e66361

Please sign in to comment.