From 5fdf14956132d04fe788e1aa9cc894ac78a6a509 Mon Sep 17 00:00:00 2001 From: EmmaLRussell Date: Wed, 26 Jun 2024 11:17:51 +0100 Subject: [PATCH] fix unit tests --- .../src/app/excel/wodinModelOutputDownload.ts | 3 +- app/static/tests/mocks.ts | 26 +- .../unit/components/basic/basicApp.test.ts | 8 +- .../components/code/selectedVariables.test.ts | 26 +- .../tests/unit/components/fit/fitApp.test.ts | 8 +- .../tests/unit/components/fit/fitTab.test.ts | 4 +- .../components/mixins/baseSensitivity.test.ts | 29 ++- .../multiSensitivityTab.test.ts | 13 +- .../components/options/graphSettings.test.ts | 8 +- .../unit/components/options/linkData.test.ts | 13 +- .../components/options/optionsTab.test.ts | 30 ++- .../tests/unit/components/run/runPlot.test.ts | 32 +-- .../components/run/runStochasticPlot.test.ts | 19 +- .../tests/unit/components/run/runTab.test.ts | 28 ++- .../sensitivitySummaryDownload.test.ts | 15 +- .../sensitivitySummaryPlot.test.ts | 12 +- .../sensitivity/sensitivityTab.test.ts | 25 +- .../sensitivity/sensitivityTracesPlot.test.ts | 8 +- .../stochastic/stochasticApp.test.ts | 8 +- .../tests/unit/components/wodinPlot.test.ts | 14 +- .../excel/wodinModelOutputDownload.test.ts | 29 +-- app/static/tests/unit/serialiser.test.ts | 69 +++--- .../tests/unit/store/fitData/actions.test.ts | 48 ++-- .../store/graphSettings/mutations.test.ts | 31 --- .../tests/unit/store/graphs/actions.test.ts | 70 ++++++ .../tests/unit/store/graphs/mutations.test.ts | 40 ++++ .../tests/unit/store/model/actions.test.ts | 225 ++++++++---------- .../tests/unit/store/model/mutations.test.ts | 15 +- 28 files changed, 520 insertions(+), 336 deletions(-) delete mode 100644 app/static/tests/unit/store/graphSettings/mutations.test.ts create mode 100644 app/static/tests/unit/store/graphs/actions.test.ts create mode 100644 app/static/tests/unit/store/graphs/mutations.test.ts diff --git a/app/static/src/app/excel/wodinModelOutputDownload.ts b/app/static/src/app/excel/wodinModelOutputDownload.ts index 7ec234575..a22c4b810 100644 --- a/app/static/src/app/excel/wodinModelOutputDownload.ts +++ b/app/static/src/app/excel/wodinModelOutputDownload.ts @@ -46,7 +46,8 @@ export class WodinModelOutputDownload extends WodinExcelDownload { tEnd: end, nPoints: this._points }); - const selectedVariables = this._state.graphs.config.flatMap((c) => c.selectedVariables); + const selectedVariables = this._rootGetters[`graphs/${GraphsGetter.allSelectedVariables}`]; + console.log(`selectedVariables are ${JSON.stringify(selectedVariables)}`) const worksheet = WodinModelOutputDownload._generateModelledOutput( selectedVariables, diff --git a/app/static/tests/mocks.ts b/app/static/tests/mocks.ts index 6044e7e82..a1c6e7c4f 100644 --- a/app/static/tests/mocks.ts +++ b/app/static/tests/mocks.ts @@ -26,7 +26,7 @@ import { SensitivityVariationType } from "../src/app/store/sensitivity/state"; import { VersionsState } from "../src/app/store/versions/state"; -import { GraphSettingsState } from "../src/app/store/graphs/state"; +import { GraphsState } from "../src/app/store/graphs/state"; import { LanguageState } from "../translationPackage/store/state"; import { Language } from "../src/app/types/languageTypes"; import { noSensitivityUpdateRequired } from "../src/app/store/sensitivity/sensitivity"; @@ -72,8 +72,6 @@ export const mockModelState = (state: Partial = {}): ModelState => { compileRequired: false, paletteModel: null, odinModelCodeError: null, - selectedVariables: [], - unselectedVariables: [], ...state }; }; @@ -124,11 +122,19 @@ export const mockVersionsState = (states: Partial = {}): Versions }; }; -export const mockGraphSettingsState = (state: Partial = {}): GraphSettingsState => { +export const mockGraphsState = (state: Partial = {}): GraphsState => { return { - logScaleYAxis: false, - lockYAxis: false, - yAxisRange: [0, 0], + config: [ + { + selectedVariables: [], + unselectedVariables: [] + } + ], + settings: { + logScaleYAxis: false, + lockYAxis: false, + yAxisRange: [0, 0] + }, ...state }; }; @@ -229,7 +235,7 @@ export const mockBasicState = (state: Partial = {}): BasicState => { sensitivity: mockSensitivityState(), multiSensitivity: mockMultiSensitivityState(), versions: mockVersionsState(), - graphSettings: mockGraphSettingsState(), + graphs: mockGraphsState(), configured: false, persisted: true, language: mockLanguageState(), @@ -285,7 +291,7 @@ export const mockFitState = (state: Partial = {}): FitState => { multiSensitivity: mockMultiSensitivityState(), modelFit: mockModelFitState(), versions: mockVersionsState(), - graphSettings: mockGraphSettingsState(), + graphs: mockGraphsState(), configured: false, persisted: false, language: mockLanguageState(), @@ -319,7 +325,7 @@ export const mockStochasticState = (state: Partial = {}): Stoch sensitivity: mockSensitivityState(), multiSensitivity: mockMultiSensitivityState(), versions: mockVersionsState(), - graphSettings: mockGraphSettingsState(), + graphs: mockGraphsState(), configured: false, persisted: false, language: mockLanguageState(), diff --git a/app/static/tests/unit/components/basic/basicApp.test.ts b/app/static/tests/unit/components/basic/basicApp.test.ts index 68ef538b5..b736f0e9d 100644 --- a/app/static/tests/unit/components/basic/basicApp.test.ts +++ b/app/static/tests/unit/components/basic/basicApp.test.ts @@ -19,7 +19,7 @@ import { expectLeftWodinTabs, expectRightWodinTabs } from "../../../testUtils"; import HelpTab from "../../../../src/app/components/help/HelpTab.vue"; import BasicApp from "../../../../src/app/components/basic/BasicApp.vue"; import { BasicState } from "../../../../src/app/store/basic/state"; -import { mockBasicState, mockGraphSettingsState, mockModelState, mockSensitivityState } from "../../../mocks"; +import { mockBasicState, mockGraphsState, mockModelState, mockSensitivityState } from "../../../mocks"; import WodinApp from "../../../../src/app/components/WodinApp.vue"; import WodinPanels from "../../../../src/app/components/WodinPanels.vue"; import OptionsTab from "../../../../src/app/components/options/OptionsTab.vue"; @@ -28,6 +28,7 @@ import { ModelAction } from "../../../../src/app/store/model/actions"; import { VisualisationTab } from "../../../../src/app/store/appState/state"; import { AppStateMutation } from "../../../../src/app/store/appState/mutations"; import { AppConfig } from "../../../../src/app/types/responseTypes"; +import { getters as graphsGetters } from "../../../../src/app/store/graphs/getters"; const mockTooltipDirective = jest.fn(); @@ -64,9 +65,10 @@ describe("BasicApp", () => { errors: [] } }, - graphSettings: { + graphs: { namespaced: true, - state: mockGraphSettingsState() + state: mockGraphsState(), + getters: graphsGetters } } }); diff --git a/app/static/tests/unit/components/code/selectedVariables.test.ts b/app/static/tests/unit/components/code/selectedVariables.test.ts index 8ff521cc8..2fb1dd699 100644 --- a/app/static/tests/unit/components/code/selectedVariables.test.ts +++ b/app/static/tests/unit/components/code/selectedVariables.test.ts @@ -3,6 +3,7 @@ import { shallowMount } from "@vue/test-utils"; import { BasicState } from "../../../../src/app/store/basic/state"; import SelectedVariables from "../../../../src/app/components/code/SelectedVariables.vue"; import { ModelAction } from "../../../../src/app/store/model/actions"; +import {GraphsAction} from "../../../../src/app/store/graphs/actions"; describe("SelectedVariables", () => { const mockUpdateSelectedVariables = jest.fn(); @@ -11,6 +12,19 @@ describe("SelectedVariables", () => { const store = new Vuex.Store({ state: {} as any, modules: { + graphs: { + namespaced: true, + state: { + config: [ + { + selectedVariables: ["S", "R"], + } + ] + }, + actions: { + [GraphsAction.UpdateSelectedVariables]: mockUpdateSelectedVariables + } + }, model: { namespaced: true, state: { @@ -19,15 +33,11 @@ describe("SelectedVariables", () => { variables: ["S", "I", "R"] } }, - selectedVariables: ["S", "R"], paletteModel: { S: "#ff0000", I: "#00ff00", R: "#0000ff" } - }, - actions: { - [ModelAction.UpdateSelectedVariables]: mockUpdateSelectedVariables } } } @@ -63,7 +73,7 @@ describe("SelectedVariables", () => { const s = wrapper.findAll(".selected-variables-panel span.variable").at(0)!; await s.trigger("click"); expect(mockUpdateSelectedVariables).toBeCalledTimes(1); - expect(mockUpdateSelectedVariables.mock.calls[0][1]).toStrictEqual(["R"]); + expect(mockUpdateSelectedVariables.mock.calls[0][1]).toStrictEqual({index: 0, selectedVariables: ["R"]}); }); it("clicking an unselected variables selects it", async () => { @@ -71,20 +81,20 @@ describe("SelectedVariables", () => { const i = wrapper.findAll(".selected-variables-panel span.variable").at(1)!; await i.trigger("click"); expect(mockUpdateSelectedVariables).toBeCalledTimes(1); - expect(mockUpdateSelectedVariables.mock.calls[0][1]).toStrictEqual(["S", "R", "I"]); + expect(mockUpdateSelectedVariables.mock.calls[0][1]).toStrictEqual({index: 0, selectedVariables: ["S", "R", "I"]}); }); it("clicking select all link selects all variables", async () => { const wrapper = getWrapper(); wrapper.find("span#select-variables-all").trigger("click"); expect(mockUpdateSelectedVariables).toBeCalledTimes(1); - expect(mockUpdateSelectedVariables.mock.calls[0][1]).toStrictEqual(["S", "I", "R"]); + expect(mockUpdateSelectedVariables.mock.calls[0][1]).toStrictEqual({index: 0, selectedVariables: ["S", "I", "R"]}); }); it("clicking select none link unselects all variables", async () => { const wrapper = getWrapper(); wrapper.find("span#select-variables-none").trigger("click"); expect(mockUpdateSelectedVariables).toBeCalledTimes(1); - expect(mockUpdateSelectedVariables.mock.calls[0][1]).toStrictEqual([]); + expect(mockUpdateSelectedVariables.mock.calls[0][1]).toStrictEqual({index: 0, selectedVariables: []}); }); }); diff --git a/app/static/tests/unit/components/fit/fitApp.test.ts b/app/static/tests/unit/components/fit/fitApp.test.ts index 3c80dff07..b0ed9036b 100644 --- a/app/static/tests/unit/components/fit/fitApp.test.ts +++ b/app/static/tests/unit/components/fit/fitApp.test.ts @@ -22,7 +22,7 @@ import { FitState } from "../../../../src/app/store/fit/state"; import { mockFitDataState, mockFitState, - mockGraphSettingsState, + mockGraphsState, mockModelFitState, mockModelState, mockSensitivityState @@ -40,6 +40,7 @@ import { VisualisationTab } from "../../../../src/app/store/appState/state"; import { AppStateMutation } from "../../../../src/app/store/appState/mutations"; import { ModelFitGetter } from "../../../../src/app/store/modelFit/getters"; import { AppConfig } from "../../../../src/app/types/responseTypes"; +import { getters as graphsGetters } from "../../../../src/app/store/graphs/getters"; function mockResizeObserver(this: any) { this.observe = jest.fn(); @@ -86,9 +87,10 @@ describe("FitApp", () => { errors: [] } }, - graphSettings: { + graphs: { namespaced: true, - state: mockGraphSettingsState() + state: mockGraphsState(), + getters: graphsGetters } } }); diff --git a/app/static/tests/unit/components/fit/fitTab.test.ts b/app/static/tests/unit/components/fit/fitTab.test.ts index 6bdf574ff..abc2cf4be 100644 --- a/app/static/tests/unit/components/fit/fitTab.test.ts +++ b/app/static/tests/unit/components/fit/fitTab.test.ts @@ -10,7 +10,7 @@ import { FitState } from "../../../../src/app/store/fit/state"; import ActionRequiredMessage from "../../../../src/app/components/ActionRequiredMessage.vue"; import LoadingSpinner from "../../../../src/app/components/LoadingSpinner.vue"; import FitPlot from "../../../../src/app/components/fit/FitPlot.vue"; -import { mockFitState, mockGraphSettingsState } from "../../../mocks"; +import { mockFitState, mockGraphsState } from "../../../mocks"; import { WodinError } from "../../../../src/app/types/responseTypes"; import ErrorInfo from "../../../../src/app/components/ErrorInfo.vue"; @@ -38,7 +38,7 @@ describe("Fit Tab", () => { }, graphSettings: { namespaced: true, - state: mockGraphSettingsState() + state: mockGraphsState() }, modelFit: { namespaced: true, diff --git a/app/static/tests/unit/components/mixins/baseSensitivity.test.ts b/app/static/tests/unit/components/mixins/baseSensitivity.test.ts index 30834dfce..ea7fbb4c5 100644 --- a/app/static/tests/unit/components/mixins/baseSensitivity.test.ts +++ b/app/static/tests/unit/components/mixins/baseSensitivity.test.ts @@ -1,5 +1,4 @@ import Vuex from "vuex"; -import { nextTick } from "vue"; import { ModelState } from "../../../../src/app/store/model/state"; import baseSensitivity, { BaseSensitivityMixin } from "../../../../src/app/components/mixins/baseSensitivity"; import { BaseSensitivityState } from "../../../../src/app/store/sensitivity/state"; @@ -7,7 +6,9 @@ import { noSensitivityUpdateRequired } from "../../../../src/app/store/sensitivi import { AppState } from "../../../../src/app/store/appState/state"; import { BaseSensitivityMutation } from "../../../../src/app/store/sensitivity/mutations"; import { BaseSensitivityAction } from "../../../../src/app/store/sensitivity/actions"; +import { getters as graphGetters } from "../../../../src/app/store/graphs/getters"; import mock = jest.mock; +import {mockGraphsState} from "../../../mocks"; describe("baseSensitivity mixin", () => { const mockSensSetUserSummaryDownloadFileName = jest.fn(); @@ -20,11 +21,19 @@ describe("baseSensitivity mixin", () => { hasRunner = true, modelState: Partial = {}, sensitivityState: Partial = {}, - multiSensitivityState: Partial = {} + multiSensitivityState: Partial = {}, + selectedVariables: string[] = ["A"] ) => { return new Vuex.Store({ state: {} as any, modules: { + graphs: { + namespaced: true, + state: mockGraphsState({ + config: [ { selectedVariables, unselectedVariables: [] } ] + }), + getters: graphGetters + }, model: { namespaced: true, state: { @@ -121,23 +130,24 @@ describe("baseSensitivity mixin", () => { hasRunner: true, modelState: Partial, sensState: Partial, + selectedVariables: string[], expectedSensMsg: string, - expectedMultiSensMsg: string + expectedMultiSensMsg: string, ) => { - const sensStore = getStore(hasRunner, modelState, sensState); + const sensStore = getStore(hasRunner, modelState, sensState, {}, selectedVariables); const sensSut = baseSensitivity(sensStore, false); expect(sensSut.updateMsg.value).toBe(expectedSensMsg); - const multiSensStore = getStore(hasRunner, modelState, {}, sensState); + const multiSensStore = getStore(hasRunner, modelState, {}, sensState, selectedVariables); const multiSensSut = baseSensitivity(multiSensStore, true); expect(multiSensSut.updateMsg.value).toBe(expectedMultiSensMsg); }; it("returns empty update message when no update required", () => { - expectUpdateMsgForSensAndMultiSens(true, {}, {}, "", ""); + expectUpdateMsgForSensAndMultiSens(true, {}, {}, ["A"], "", ""); }); it("returns empty update message when update required, but there has been no run yet", () => { - expectUpdateMsgForSensAndMultiSens(true, { compileRequired: true }, { result: null }, "", ""); + expectUpdateMsgForSensAndMultiSens(true, { compileRequired: true }, { result: null }, ["A"], "", ""); }); it("returns expected update message when compile required", () => { @@ -145,6 +155,7 @@ describe("baseSensitivity mixin", () => { true, { compileRequired: true }, {}, + ["A"], "Model code has been updated. Compile code and Run Sensitivity to update.", "Model code has been updated. Compile code and Run Multi-sensitivity to update." ); @@ -153,8 +164,9 @@ describe("baseSensitivity mixin", () => { it("returns expected update message when there are no selected variables", () => { expectUpdateMsgForSensAndMultiSens( true, - { selectedVariables: [] }, {}, + {}, + [], "Please select at least one variable.", "Please select at least one variable." ); @@ -173,6 +185,7 @@ describe("baseSensitivity mixin", () => { true, {}, { sensitivityUpdateRequired }, + ["A"], "Plot is out of date: model code has been recompiled. Run Sensitivity to update.", "Status is out of date: model code has been recompiled. Run Multi-sensitivity to update." ); diff --git a/app/static/tests/unit/components/multiSensitivity/multiSensitivityTab.test.ts b/app/static/tests/unit/components/multiSensitivity/multiSensitivityTab.test.ts index 4f6f5ce1c..051815427 100644 --- a/app/static/tests/unit/components/multiSensitivity/multiSensitivityTab.test.ts +++ b/app/static/tests/unit/components/multiSensitivity/multiSensitivityTab.test.ts @@ -9,6 +9,7 @@ import ActionRequiredMessage from "../../../../src/app/components/ActionRequired import { MultiSensitivityState } from "../../../../src/app/store/multiSensitivity/state"; import ErrorInfo from "../../../../src/app/components/ErrorInfo.vue"; import SensitivitySummaryDownload from "../../../../src/app/components/sensitivity/SensitivitySummaryDownload.vue"; +import { getters as graphsGetters} from "../../../../src/app/store/graphs/getters"; describe("MultiSensitivityTab", () => { const mockRunMultiSensitivity = jest.fn(); @@ -22,12 +23,22 @@ describe("MultiSensitivityTab", () => { const store = new Vuex.Store({ state: {} as any, modules: { + graphs: { + namespaced: true, + state: { + config: [ + { + selectedVariables: ["A"] + } + ] + }, + getters: graphsGetters + }, model: { namespaced: true, state: { odin: {}, compileRequired: false, - selectedVariables: ["A"], ...modelState }, getters: { diff --git a/app/static/tests/unit/components/options/graphSettings.test.ts b/app/static/tests/unit/components/options/graphSettings.test.ts index 4807e7e0d..07dc5681f 100644 --- a/app/static/tests/unit/components/options/graphSettings.test.ts +++ b/app/static/tests/unit/components/options/graphSettings.test.ts @@ -11,11 +11,13 @@ describe("GraphSettings", () => { const getWrapper = (logScaleYAxis = true, lockYAxis = true) => { const store = new Vuex.Store({ modules: { - graphSettings: { + graphs: { namespaced: true, state: { - logScaleYAxis, - lockYAxis + settings: { + logScaleYAxis, + lockYAxis + } } as any, mutations: { [GraphsMutation.SetLogScaleYAxis]: mockSetLogScaleYAxis, diff --git a/app/static/tests/unit/components/options/linkData.test.ts b/app/static/tests/unit/components/options/linkData.test.ts index 7978a99a0..0cbe6e6bb 100644 --- a/app/static/tests/unit/components/options/linkData.test.ts +++ b/app/static/tests/unit/components/options/linkData.test.ts @@ -3,8 +3,9 @@ import Vuex from "vuex"; import LinkData from "../../../../src/app/components/options/LinkData.vue"; import { FitState } from "../../../../src/app/store/fit/state"; import { getters } from "../../../../src/app/store/fitData/getters"; -import { mockFitDataState, mockFitState, mockModelState } from "../../../mocks"; +import {mockFitDataState, mockFitState, mockGraphsState, mockModelState} from "../../../mocks"; import { FitDataAction } from "../../../../src/app/store/fitData/actions"; +import { getters as graphGetters } from "../../../../src/app/store/graphs/getters"; describe("LinkData", () => { const getWrapper = (includeColumns = true, includeValidModel = true, mockUpdateLinkedVariable = jest.fn()) => { @@ -29,6 +30,13 @@ describe("LinkData", () => { [FitDataAction.UpdateLinkedVariable]: mockUpdateLinkedVariable } }, + graphs: { + namespaced: true, + state: mockGraphsState({ + config: [ { selectedVariables: ["I", "R"], unselectedVariables: [] } ] + }), + getters: graphGetters + }, model: { namespaced: true, state: mockModelState({ @@ -37,8 +45,7 @@ describe("LinkData", () => { metadata: { variables: includeValidModel ? ["S", "I", "R"] : [] } - } as any, - selectedVariables: ["I", "R"] + } as any }) } } diff --git a/app/static/tests/unit/components/options/optionsTab.test.ts b/app/static/tests/unit/components/options/optionsTab.test.ts index 20b3ee6de..d94e31319 100644 --- a/app/static/tests/unit/components/options/optionsTab.test.ts +++ b/app/static/tests/unit/components/options/optionsTab.test.ts @@ -42,8 +42,10 @@ describe("OptionsTab", () => { sensitivity: { paramSettings: {} }, - graphSettings: { - logScaleYAxis: false + graphs: { + settings: { + logScaleYAxis: false + } } } as any; @@ -53,8 +55,10 @@ describe("OptionsTab", () => { appType: AppType.Basic, openVisualisationTab: VisualisationTab.Run, model: mockModelState(), - graphSettings: { - logScaleYAxis: false + graphs: { + settings: { + logScaleYAxis: false + } } } as any, modules: { @@ -97,8 +101,10 @@ describe("OptionsTab", () => { state: { appType: AppType.Basic, openVisualisationTab: VisualisationTab.Run, - graphSettings: { - logScaleYAxis: false + graphs: { + settings: { + logScaleYAxis: false + } } } as any, modules: { @@ -148,8 +154,10 @@ describe("OptionsTab", () => { fitData: { columnToFit: null }, - graphSettings: { - logScaleYAxis: false + graphs: { + settings: { + logScaleYAxis: false + } } } as any, modules: { @@ -202,8 +210,10 @@ describe("OptionsTab", () => { run: mockRunState({ parameterValues: { param1: 1, param2: 2.2 } }), - graphSettings: { - logScaleYAxis: false + graphs: { + settings: { + logScaleYAxis: false + } } } as any }); diff --git a/app/static/tests/unit/components/run/runPlot.test.ts b/app/static/tests/unit/components/run/runPlot.test.ts index 47b6d3004..de3eae704 100644 --- a/app/static/tests/unit/components/run/runPlot.test.ts +++ b/app/static/tests/unit/components/run/runPlot.test.ts @@ -9,7 +9,7 @@ import WodinPlot from "../../../../src/app/components/WodinPlot.vue"; import { BasicState } from "../../../../src/app/store/basic/state"; import { FitDataGetter } from "../../../../src/app/store/fitData/getters"; import { getters as runGetters } from "../../../../src/app/store/run/getters"; -import { mockBasicState, mockRunState } from "../../../mocks"; +import {mockBasicState, mockGraphsState, mockRunState} from "../../../mocks"; describe("RunPlot", () => { const mockSolution = jest.fn().mockReturnValue({ @@ -83,6 +83,10 @@ describe("RunPlot", () => { const selectedVariables = ["S", "I"]; + const graphsState = { + config: [ { selectedVariables, unselectedVariables: [] } ] + }; + afterEach(() => { jest.clearAllMocks(); }); @@ -90,9 +94,9 @@ describe("RunPlot", () => { it("renders as expected when model has solution", () => { const store = new Vuex.Store({ state: { + graphs: graphsState, model: { - paletteModel, - selectedVariables + paletteModel }, run: mockRunState({ endTime: 99, @@ -182,9 +186,9 @@ describe("RunPlot", () => { it("renders as expected when there are parameter set solutions", () => { const store = new Vuex.Store({ state: { + graphs: graphsState, model: { - paletteModel, - selectedVariables + paletteModel } } as any, modules: { @@ -348,9 +352,9 @@ describe("RunPlot", () => { it("renders as expected when model has no solution", () => { const store = new Vuex.Store({ state: { + graphs: graphsState, model: { - paletteModel, - selectedVariables + paletteModel }, run: mockRunState({ endTime: 99 @@ -379,9 +383,7 @@ describe("RunPlot", () => { it("fades plot when fadePlot prop is true", () => { const store = new Vuex.Store({ state: { - model: { - selectedVariables - }, + graphs: graphsState, run: mockRunState() } as any }); @@ -411,9 +413,9 @@ describe("RunPlot", () => { const store = new Vuex.Store({ state: { model: { - paletteModel, - selectedVariables + paletteModel }, + graphs: graphsState, run: mockRunState({ endTime: 99, resultOde: mockResult, @@ -519,9 +521,9 @@ describe("RunPlot", () => { it("placeholder message indicates no variables selected", () => { const store = new Vuex.Store({ state: { - model: { - selectedVariables: [] - }, + graphs: mockGraphsState({ + config: [ { selectedVariables: [] } ] + } as any), run: mockRunState() } as any }); diff --git a/app/static/tests/unit/components/run/runStochasticPlot.test.ts b/app/static/tests/unit/components/run/runStochasticPlot.test.ts index bb0340bb7..eb7cfbe67 100644 --- a/app/static/tests/unit/components/run/runStochasticPlot.test.ts +++ b/app/static/tests/unit/components/run/runStochasticPlot.test.ts @@ -8,7 +8,7 @@ import RunStochasticPlot from "../../../../src/app/components/run/RunStochasticP import WodinPlot from "../../../../src/app/components/WodinPlot.vue"; import { StochasticState } from "../../../../src/app/store/stochastic/state"; import RunPlot from "../../../../src/app/components/run/RunPlot.vue"; -import { mockModelState, mockRunState } from "../../../mocks"; +import {mockGraphsState, mockModelState, mockRunState} from "../../../mocks"; describe("RunPlot for stochastic", () => { const mockSolution = jest.fn().mockReturnValue({ @@ -32,6 +32,8 @@ describe("RunPlot for stochastic", () => { const selectedVariables = ["S", "I", "R"]; + const graphsState = mockGraphsState( { config: [ { selectedVariables, unselectedVariables: [] } ] } ); + afterEach(() => { jest.clearAllMocks(); }); @@ -39,7 +41,8 @@ describe("RunPlot for stochastic", () => { it("renders as expected when model has stochastic result", () => { const store = new Vuex.Store({ state: { - model: mockModelState({ paletteModel, selectedVariables }), + graphs: graphsState, + model: mockModelState({ paletteModel }), run: { endTime: 99, numberOfReplicates: 20, @@ -102,7 +105,8 @@ describe("RunPlot for stochastic", () => { it("renders as expected when model has no stochastic result", () => { const store = new Vuex.Store({ state: { - model: mockModelState({ paletteModel, selectedVariables }), + graphs: graphsState, + model: mockModelState({ paletteModel }), run: mockRunState({ endTime: 99 }) @@ -130,7 +134,8 @@ describe("RunPlot for stochastic", () => { it("renders as expected when solution returns no data", () => { const store = new Vuex.Store({ state: { - model: mockModelState({ paletteModel, selectedVariables }), + graphs: graphsState, + model: mockModelState({ paletteModel }), run: { endTime: 99, resultDiscrete: { @@ -159,7 +164,8 @@ describe("RunPlot for stochastic", () => { it("fades plot when fadePlot prop is true", () => { const store = new Vuex.Store({ state: { - model: mockModelState({ selectedVariables }), + graphs: graphsState, + model: mockModelState(), run: mockRunState() } as any }); @@ -178,7 +184,8 @@ describe("RunPlot for stochastic", () => { it("doesn't show individual traces when replicates > maxReplicatesDisplay", () => { const store = new Vuex.Store({ state: { - model: mockModelState({ paletteModel, selectedVariables }), + graphs: graphsState, + model: mockModelState({ paletteModel }), run: { endTime: 99, numberOfReplicates: 51, diff --git a/app/static/tests/unit/components/run/runTab.test.ts b/app/static/tests/unit/components/run/runTab.test.ts index a0f13d743..f26cba83c 100644 --- a/app/static/tests/unit/components/run/runTab.test.ts +++ b/app/static/tests/unit/components/run/runTab.test.ts @@ -8,7 +8,7 @@ import Vuex from "vuex"; import { shallowMount } from "@vue/test-utils"; import { nextTick } from "vue"; import { BasicState } from "../../../../src/app/store/basic/state"; -import { mockBasicState, mockModelState, mockRunState, mockStochasticState } from "../../../mocks"; +import {mockBasicState, mockGraphsState, mockModelState, mockRunState, mockStochasticState} from "../../../mocks"; import { ModelState } from "../../../../src/app/store/model/state"; import { RunState } from "../../../../src/app/store/run/state"; import RunTab from "../../../../src/app/components/run/RunTab.vue"; @@ -19,19 +19,19 @@ import ActionRequiredMessage from "../../../../src/app/components/ActionRequired import DownloadOutput from "../../../../src/app/components/DownloadOutput.vue"; import LoadingSpinner from "../../../../src/app/components/LoadingSpinner.vue"; import { StochasticState } from "../../../../src/app/store/stochastic/state"; -import { DiscreteSeriesSet, OdinRunnerDiscrete } from "../../../../src/app/types/responseTypes"; +import { OdinRunnerDiscrete } from "../../../../src/app/types/responseTypes"; import { OdinRunResultDiscrete } from "../../../../src/app/types/wrapperTypes"; import { ModelGetter } from "../../../../src/app/store/model/getters"; import { AppType } from "../../../../src/app/store/appState/state"; import { RunMutation } from "../../../../src/app/store/run/mutations"; import { RunAction } from "../../../../src/app/store/run/actions"; +import { getters as graphGetters } from "../../../../src/app/store/graphs/getters"; describe("RunTab", () => { const defaultModelState = { odinRunnerOde: {} as any, odin: {} as any, - compileRequired: false, - selectedVariables: ["S"] + compileRequired: false }; const defaultRunState = { @@ -56,11 +56,19 @@ describe("RunTab", () => { modelState: Partial = defaultModelState, runState: Partial = defaultRunState, hasRunner = true, - appType = AppType.Basic + appType = AppType.Basic, + selectedVariables: string[] = ["S"] ) => { const store = new Vuex.Store({ state: mockBasicState({ appType }), modules: { + graphs: { + namespaced: true, + state: mockGraphsState({ + config: [ { selectedVariables, unselectedVariables: [] } ] + }), + getters: graphGetters + }, model: { namespaced: true, state: mockModelState(modelState), @@ -97,12 +105,18 @@ describe("RunTab", () => { const store = new Vuex.Store({ state: mockStochasticState(), modules: { + graphs: { + namespaced: true, + state: mockGraphsState({ + config: [ { selectedVariables: ["S"], unselectedVariables: [] } ] + }), + getters: graphGetters + }, model: { namespaced: true, state: mockModelState({ odin: {} as any, odinRunnerDiscrete: runner as any, - selectedVariables: ["S"], compileRequired }), getters: { @@ -229,7 +243,7 @@ describe("RunTab", () => { }); it("fades plot and show message when no selected variables", () => { - const wrapper = getWrapper({ selectedVariables: [] }); + const wrapper = getWrapper( defaultModelState, defaultRunState, true, AppType.Basic, []); expect(wrapper.findComponent(ActionRequiredMessage).props("message")).toBe( "Please select at least one variable." ); diff --git a/app/static/tests/unit/components/sensitivity/sensitivitySummaryDownload.test.ts b/app/static/tests/unit/components/sensitivity/sensitivitySummaryDownload.test.ts index 748e6327d..e807a3b99 100644 --- a/app/static/tests/unit/components/sensitivity/sensitivitySummaryDownload.test.ts +++ b/app/static/tests/unit/components/sensitivity/sensitivitySummaryDownload.test.ts @@ -13,6 +13,8 @@ import { BaseSensitivityAction, SensitivityAction } from "../../../../src/app/st import { BaseSensitivityMutation, SensitivityMutation } from "../../../../src/app/store/sensitivity/mutations"; import LoadingSpinner from "../../../../src/app/components/LoadingSpinner.vue"; import { ModelGetter } from "../../../../src/app/store/model/getters"; +import { getters as graphsGetters } from "../../../../src/app/store/graphs/getters"; +import {mockGraphsState} from "../../../mocks"; describe("SensitivitySummaryDownload", () => { const mockSetUserSummaryDownloadFileName = jest.fn(); @@ -78,7 +80,18 @@ describe("SensitivitySummaryDownload", () => { } }, multiSensitivity: multiSens ? sensMod : ({} as any), - sensitivity: multiSens ? minimalSensitivity : sensMod + sensitivity: multiSens ? minimalSensitivity : sensMod, + graphs: { + namespaced: true, + state: mockGraphsState({ + config: [ + { + selectedVariables: ["S"], unselectedVariables: [] + } + ] + }), + getters: graphsGetters + } } }); diff --git a/app/static/tests/unit/components/sensitivity/sensitivitySummaryPlot.test.ts b/app/static/tests/unit/components/sensitivity/sensitivitySummaryPlot.test.ts index c39888634..5eb4e6c6c 100644 --- a/app/static/tests/unit/components/sensitivity/sensitivitySummaryPlot.test.ts +++ b/app/static/tests/unit/components/sensitivity/sensitivitySummaryPlot.test.ts @@ -165,8 +165,7 @@ describe("SensitivitySummaryPlot", () => { S: "#ff0000", I: "#0000ff", R: "#00ff00" - }, - selectedVariables + } } }, run: { @@ -200,10 +199,13 @@ describe("SensitivitySummaryPlot", () => { [SensitivityMutation.SetLoading]: mockSetLoading } }, - graphSettings: { + graphs: { namespaced: true, state: { - logScaleYAxis + settings: { logScaleYAxis }, + config: [ + { selectedVariables } + ] } } } @@ -530,7 +532,7 @@ describe("SensitivitySummaryPlot", () => { it("redraws plot if graph setting changes", async () => { const wrapper = getWrapper(); - (store!.state as any).graphSettings.logScaleYAxis = true; + (store!.state as any).graphs.settings.logScaleYAxis = true; await nextTick(); expect(mockPlotlyNewPlot).toHaveBeenCalledTimes(2); }); diff --git a/app/static/tests/unit/components/sensitivity/sensitivityTab.test.ts b/app/static/tests/unit/components/sensitivity/sensitivityTab.test.ts index c6ea0569f..466b684ed 100644 --- a/app/static/tests/unit/components/sensitivity/sensitivityTab.test.ts +++ b/app/static/tests/unit/components/sensitivity/sensitivityTab.test.ts @@ -15,6 +15,7 @@ import LoadingSpinner from "../../../../src/app/components/LoadingSpinner.vue"; import { SensitivityMutation } from "../../../../src/app/store/sensitivity/mutations"; import SensitivitySummaryDownload from "../../../../src/app/components/sensitivity/SensitivitySummaryDownload.vue"; import LoadingButton from "../../../../src/app/components/LoadingButton.vue"; +import { getters as graphsGetters} from "../../../../src/app/store/graphs/getters"; jest.mock("plotly.js-basic-dist-min", () => {}); @@ -28,19 +29,30 @@ describe("SensitivityTab", () => { modelState: Partial = {}, sensitivityState: Partial = {}, batchPars: any = {}, - hasRunner = true + hasRunner = true, + selectedVariables = ["S"] ) => { const store = new Vuex.Store({ state: { appType } as any, modules: { + graphs: { + namespaced: true, + state: { + config: [ + { + selectedVariables + } + ] + }, + getters: graphsGetters + }, model: { namespaced: true, state: { odinRunnerOde: {}, odin: {}, - selectedVariables: ["S"], ...modelState }, getters: { @@ -223,7 +235,14 @@ describe("SensitivityTab", () => { } } } as any; - const wrapper = getWrapper(AppType.Basic, { selectedVariables: [] }, sensitivityState); + const wrapper = getWrapper( + AppType.Basic, + {}, + sensitivityState, + {}, + true, + [] + ); expect(wrapper.findComponent(ActionRequiredMessage).props("message")).toBe( "Please select at least one variable." ); diff --git a/app/static/tests/unit/components/sensitivity/sensitivityTracesPlot.test.ts b/app/static/tests/unit/components/sensitivity/sensitivityTracesPlot.test.ts index 55e9cc8e5..df7392936 100644 --- a/app/static/tests/unit/components/sensitivity/sensitivityTracesPlot.test.ts +++ b/app/static/tests/unit/components/sensitivity/sensitivityTracesPlot.test.ts @@ -408,8 +408,12 @@ describe("SensitivityTracesPlot", () => { state: { appType: stochastic ? AppType.Stochastic : AppType.Basic, model: { - paletteModel: mockPalette, - selectedVariables: hasSelectedVariables ? selectedVariables : [] + paletteModel: mockPalette + }, + graphs: { + config: [ + { selectedVariables: hasSelectedVariables ? selectedVariables : [] } + ] } } as any, modules: { diff --git a/app/static/tests/unit/components/stochastic/stochasticApp.test.ts b/app/static/tests/unit/components/stochastic/stochasticApp.test.ts index b5744dae2..d5ea4f40f 100644 --- a/app/static/tests/unit/components/stochastic/stochasticApp.test.ts +++ b/app/static/tests/unit/components/stochastic/stochasticApp.test.ts @@ -17,7 +17,7 @@ import { mount } from "@vue/test-utils"; import { expectLeftWodinTabs, expectRightWodinTabs } from "../../../testUtils"; import StochasticApp from "../../../../src/app/components/stochastic/StochasticApp.vue"; import { StochasticState } from "../../../../src/app/store/stochastic/state"; -import { mockModelState, mockGraphSettingsState, mockStochasticState } from "../../../mocks"; +import { mockModelState, mockGraphsState, mockStochasticState } from "../../../mocks"; import WodinApp from "../../../../src/app/components/WodinApp.vue"; import WodinPanels from "../../../../src/app/components/WodinPanels.vue"; import CodeTab from "../../../../src/app/components/code/CodeTab.vue"; @@ -30,6 +30,7 @@ import { ModelAction } from "../../../../src/app/store/model/actions"; import { AppStateMutation } from "../../../../src/app/store/appState/mutations"; import { VisualisationTab } from "../../../../src/app/store/appState/state"; import { AppConfig } from "../../../../src/app/types/responseTypes"; +import { getters as graphsGetters } from "../../../../src/app/store/graphs/getters"; const mockSetOpenVisualisationTab = jest.fn(); const mockTooltipDirective = jest.fn(); @@ -59,9 +60,10 @@ describe("StochasticApp", () => { [ModelAction.FetchOdinRunner]: jest.fn() } }, - graphSettings: { + graphs: { namespaced: true, - state: mockGraphSettingsState() + state: mockGraphsState(), + getters: graphsGetters } } }); diff --git a/app/static/tests/unit/components/wodinPlot.test.ts b/app/static/tests/unit/components/wodinPlot.test.ts index 23f0428fd..d8050c168 100644 --- a/app/static/tests/unit/components/wodinPlot.test.ts +++ b/app/static/tests/unit/components/wodinPlot.test.ts @@ -63,12 +63,14 @@ describe("WodinPlot", () => { const getStore = (logScaleYAxis = false, lockYAxis = false) => { return new Vuex.Store({ modules: { - graphSettings: { + graphs: { namespaced: true, state: { - logScaleYAxis, - lockYAxis, - yAxisRange: [10, 20] + settings: { + logScaleYAxis, + lockYAxis, + yAxisRange: [10, 20] + } }, mutations: { [GraphsMutation.SetYAxisRange]: mockSetYAxisRange @@ -437,7 +439,7 @@ describe("WodinPlot", () => { expect(mockOn).toBeCalledTimes(1); const store = (wrapper.vm as any).$store; - store.state.graphSettings.logScaleYAxis = true; + store.state.graphs.settings.logScaleYAxis = true; await nextTick(); expect(mockPlotDataFn).toBeCalledTimes(2); @@ -456,7 +458,7 @@ describe("WodinPlot", () => { await wrapper.setProps({ fadePlot: true }); const store = (wrapper.vm as any).$store; - store.state.graphSettings.logScaleYAxis = true; + store.state.graphs.settings.logScaleYAxis = true; await nextTick(); expect(mockPlotDataFn).toBeCalledTimes(1); diff --git a/app/static/tests/unit/excel/wodinModelOutputDownload.test.ts b/app/static/tests/unit/excel/wodinModelOutputDownload.test.ts index 3c46bb0e2..f350e6302 100644 --- a/app/static/tests/unit/excel/wodinModelOutputDownload.test.ts +++ b/app/static/tests/unit/excel/wodinModelOutputDownload.test.ts @@ -1,7 +1,7 @@ -import { ErrorsMutation } from "../../../src/app/store/errors/mutations"; import { mockBookNew, mockWriteFile } from "./mocks"; -import { mockBasicState, mockFitDataState, mockFitState, mockModelState, mockRunState } from "../../mocks"; +import { mockFitDataState, mockFitState, mockBasicState, mockRunState } from "../../mocks"; import { WodinModelOutputDownload } from "../../../src/app/excel/wodinModelOutputDownload"; +import { ErrorsMutation } from "../../../src/app/store/errors/mutations"; const mockSolution = jest.fn().mockImplementation((options) => { const x = options.mode === "grid" ? [options.tStart, options.tEnd] : options.times; @@ -20,9 +20,10 @@ describe("WodinModelOutputDownload", () => { parameterValues: { v1: 1.1, v2: 2.2 } }); - const modelState = mockModelState({ - selectedVariables: ["A", "B"] - }); + const rootGetters = { + "graphs/allSelectedVariables": ["A", "B"], + "fitData/nonTimeColumns": ["cases", "deaths"] + } beforeEach(() => { jest.clearAllMocks(); @@ -47,14 +48,14 @@ describe("WodinModelOutputDownload", () => { ] }; + it("downloads expected workbook for Basic app", () => { const rootState = mockBasicState({ - run: runState, - model: modelState + run: runState }); const commit = jest.fn(); - const sut = new WodinModelOutputDownload({ rootState, commit } as any, "myFile.xlsx", 101); + const sut = new WodinModelOutputDownload({ rootState, rootGetters, commit } as any, "myFile.xlsx", 101); sut.download(); expect(commit).not.toHaveBeenCalled(); @@ -74,10 +75,11 @@ describe("WodinModelOutputDownload", () => { expect(mockWriteFile.mock.calls[0][1]).toBe("myFile.xlsx"); }); + + it("downloads expected workbook for Fit app", () => { const rootState = mockFitState({ run: runState, - model: modelState, fitData: mockFitDataState({ data: [ { time: 0, cases: 1, deaths: 2 }, @@ -87,10 +89,6 @@ describe("WodinModelOutputDownload", () => { }) }); - const rootGetters = { - "fitData/nonTimeColumns": ["cases", "deaths"] - }; - const commit = jest.fn(); const sut = new WodinModelOutputDownload({ rootState, commit, rootGetters } as any, "myFile.xlsx", 101); @@ -139,12 +137,11 @@ describe("WodinModelOutputDownload", () => { } as any }; const rootState = mockBasicState({ - run: errorRunState, - model: modelState + run: errorRunState }); const commit = jest.fn(); - const sut = new WodinModelOutputDownload({ rootState, commit } as any, "myFile.xlsx", 101); + const sut = new WodinModelOutputDownload({ rootState, commit, rootGetters } as any, "myFile.xlsx", 101); sut.download(); expect(commit).toHaveBeenCalledTimes(1); diff --git a/app/static/tests/unit/serialiser.test.ts b/app/static/tests/unit/serialiser.test.ts index b49960a01..95e2a0222 100644 --- a/app/static/tests/unit/serialiser.test.ts +++ b/app/static/tests/unit/serialiser.test.ts @@ -11,7 +11,7 @@ import { FitState } from "../../src/app/store/fit/state"; import { mockCodeState, mockFitDataState, - mockGraphSettingsState, + mockGraphsState, mockModelFitState, mockModelState, mockMultiSensitivityState, @@ -20,7 +20,7 @@ import { mockSessionsState, mockVersionsState } from "../mocks"; -import { defaultState as defaultGraphSettingsState } from "../../src/app/store/graphs/graphs"; +import { defaultState as defaultGraphsState } from "../../src/app/store/graphs/graphs"; import { Language } from "../../src/app/types/languageTypes"; import { AdvancedOptions } from "../../src/app/types/responseTypes"; import { AdvancedComponentType } from "../../src/app/store/run/state"; @@ -76,9 +76,7 @@ describe("serialise", () => { }, odin: jest.fn(), paletteModel: { S: "#f00", I: "#0f0", R: "#00f" }, - odinModelCodeError: { error: "odin error", detail: "test odin error" }, - selectedVariables: ["S", "I"], - unselectedVariables: ["R"] + odinModelCodeError: { error: "odin error", detail: "test odin error" } }; const runState = { @@ -365,6 +363,20 @@ describe("serialise", () => { sessionsMetadata: [] }); + const graphsState = mockGraphsState({ + settings: { + logScaleYAxis: true, + lockYAxis: true, + yAxisRange: [1, 2] + }, + config: [ + { + selectedVariables: ["S", "I"], + unselectedVariables: ["R"] + } + ] + }); + const basicState: BasicState = { sessionId: "1234", sessionLabel: null, @@ -383,11 +395,7 @@ describe("serialise", () => { sensitivity: sensitivityState, multiSensitivity: multiSensitivityState, versions: { versions: null }, - graphSettings: { - logScaleYAxis: true, - lockYAxis: true, - yAxisRange: [1, 2] - }, + graphs: graphsState, configured: false, persisted: true, language: langaugeState, @@ -415,11 +423,7 @@ describe("serialise", () => { fitData: fitDataState, modelFit: modelFitState, versions: { versions: null }, - graphSettings: { - logScaleYAxis: true, - lockYAxis: true, - yAxisRange: [1, 2] - }, + graphs: graphsState, configured: false, persisted: true, language: langaugeState, @@ -433,9 +437,7 @@ describe("serialise", () => { odinModelResponse: modelState.odinModelResponse, hasOdin: true, odinModelCodeError: modelState.odinModelCodeError, - paletteModel: modelState.paletteModel, - selectedVariables: modelState.selectedVariables, - unselectedVariables: modelState.unselectedVariables + paletteModel: modelState.paletteModel }; const expectedRun = { runRequired: { @@ -503,12 +505,6 @@ describe("serialise", () => { } }; - const expectedGraphSettings = { - logScaleYAxis: true, - lockYAxis: true, - yAxisRange: [1, 2] - }; - const expectedFitData = { data: fitDataState.data, columns: ["time", "cases"], @@ -549,7 +545,7 @@ describe("serialise", () => { run: expectedRun, sensitivity: expectedSensitivity, multiSensitivity: expectedMultiSensitivity, - graphSettings: expectedGraphSettings + graphs: graphsState }; expect(JSON.parse(serialised)).toStrictEqual(expected); }); @@ -565,7 +561,7 @@ describe("serialise", () => { multiSensitivity: expectedMultiSensitivity, fitData: expectedFitData, modelFit: expectedModelFit, - graphSettings: expectedGraphSettings + graphs: graphsState }; expect(JSON.parse(serialised)).toStrictEqual(expected); }); @@ -630,7 +626,7 @@ describe("serialise", () => { ...expectedModelFit, result: { ...expectedModelFit.result, hasResult: false } }, - graphSettings: expectedGraphSettings + graphs: graphsState }; expect(JSON.parse(serialised)).toStrictEqual(expected); }); @@ -655,7 +651,7 @@ describe("serialise", () => { multiSensitivity: { ...expectedMultiSensitivity, result: null }, fitData: expectedFitData, modelFit: { ...expectedModelFit, result: null }, - graphSettings: expectedGraphSettings + graphs: graphsState }; expect(JSON.parse(serialised)).toStrictEqual(expected); }); @@ -671,7 +667,7 @@ describe("serialise", () => { fitData: mockFitDataState(), modelFit: mockModelFitState(), versions: mockVersionsState(), - graphSettings: mockGraphSettingsState() + graphs: mockGraphsState() } as any; const target = { @@ -686,7 +682,7 @@ describe("serialise", () => { fitData: {}, modelFit: {}, versions: null, - graphSettings: {} + graphs: {} } as any; deserialiseState(target, serialised); @@ -704,7 +700,7 @@ describe("serialise", () => { fitData: mockFitDataState(), modelFit: mockModelFitState(), versions: mockVersionsState(), - graphSettings: mockGraphSettingsState() + graphs: mockGraphsState() }); }); @@ -740,11 +736,12 @@ describe("serialise", () => { sensitivity: {}, fitData: {}, modelFit: {}, + graphs: defaultGraphsState, versions: null } as any; deserialiseState(target, serialised); - expect(target.model.selectedVariables).toStrictEqual(["S", "I", "R"]); - expect(target.model.unselectedVariables).toStrictEqual([]); + expect(target.graphs.config[0].selectedVariables).toStrictEqual(["S", "I", "R"]); + expect(target.graphs.config[0].unselectedVariables).toStrictEqual([]); }); it("deserialises default graph settings when undefined in serialised state", () => { @@ -774,12 +771,12 @@ describe("serialise", () => { fitData: {}, modelFit: {}, versions: null, - graphSettings: defaultGraphSettingsState + graphs: defaultGraphsState } as any; // sanity check - expect(target.graphSettings.logScaleYAxis).toBe(false); + expect(target.graphs.settings.logScaleYAxis).toBe(false); deserialiseState(target, serialised); - expect(target.graphSettings.logScaleYAxis).toBe(false); + expect(target.graphs.settings.logScaleYAxis).toBe(false); }); }); diff --git a/app/static/tests/unit/store/fitData/actions.test.ts b/app/static/tests/unit/store/fitData/actions.test.ts index 2025da73e..e255548ca 100644 --- a/app/static/tests/unit/store/fitData/actions.test.ts +++ b/app/static/tests/unit/store/fitData/actions.test.ts @@ -28,6 +28,10 @@ describe("Fit Data actions", () => { const updateSumOfSquaresArgs = [`modelFit/${ModelFitAction.UpdateSumOfSquares}`, null, { root: true }]; + const rootGetters = { + "graphs/allSelectedVariables": ["X", "Y"] + }; + afterEach(() => { resetAllMocks(); }); @@ -75,7 +79,8 @@ describe("Fit Data actions", () => { dispatch, state: mockState, rootState: mockRootState, - getters: mockGetters + getters: mockGetters, + rootGetters }; (actions[FitDataAction.Upload] as any)(context, file); expectFileRead(mockFileReader); @@ -117,7 +122,7 @@ describe("Fit Data actions", () => { const commit = jest.fn(); const dispatch = jest.fn(); - (actions[FitDataAction.Upload] as any)({ commit, dispatch }, file); + (actions[FitDataAction.Upload] as any)({ commit, dispatch, rootGetters }, file); expectFileRead(mockFileReader); setTimeout(() => { expect(commit).toHaveBeenCalledTimes(2); @@ -140,7 +145,7 @@ describe("Fit Data actions", () => { const commit = jest.fn(); const dispatch = jest.fn(); - (actions[FitDataAction.Upload] as any)({ commit, dispatch }, file); + (actions[FitDataAction.Upload] as any)({ commit, dispatch, rootGetters }, file); expectFileRead(mockFileReader); setTimeout(() => { expect(commit).toHaveBeenCalledTimes(2); @@ -170,7 +175,7 @@ describe("Fit Data actions", () => { const commit = jest.fn(); const dispatch = jest.fn(); - (actions[FitDataAction.Upload] as any)({ commit, dispatch }, file); + (actions[FitDataAction.Upload] as any)({ commit, dispatch, rootGetters }, file); expectFileRead(mockFileReader); setTimeout(() => { expect(commit).toHaveBeenCalledTimes(2); @@ -194,7 +199,7 @@ describe("Fit Data actions", () => { const commit = jest.fn(); const dispatch = jest.fn(); - (actions[FitDataAction.Upload] as any)({ commit, dispatch }, null); + (actions[FitDataAction.Upload] as any)({ commit, dispatch, rootGetters }, null); expect(mockFileReader.readAsText).not.toHaveBeenCalled(); setTimeout(() => { expect(commit).toHaveBeenCalledTimes(1); @@ -223,11 +228,14 @@ describe("Fit Data actions", () => { model: { odinModelResponse: { valid: true - }, - selectedVariables: ["B", "C", "D"] + } } }; + const testRootGetters = { + "graphs/allSelectedVariables": ["B", "C", "D"] + }; + const commit = jest.fn(); const dispatch = jest.fn(); @@ -236,7 +244,8 @@ describe("Fit Data actions", () => { dispatch, state, rootState, - getters + getters, + rootGetters: testRootGetters }); expect(commit).toHaveBeenCalledTimes(1); @@ -267,7 +276,8 @@ describe("Fit Data actions", () => { dispatch, state, rootState, - getters + getters, + rootGetters }); expect(commit).toHaveBeenCalledTimes(1); @@ -301,12 +311,7 @@ describe("Fit Data actions", () => { model: { odinModelResponse: { valid: true, - metadata: { - variables: ["A", "B", "C"] - } - }, - selectedVariables: ["A", "B", "C"], - unselectedVariables: [] + } } }; @@ -315,6 +320,10 @@ describe("Fit Data actions", () => { nonTimeColumns: ["Day1", "Cases"] }; + const testRootGetters = { + "graphs/allSelectedVariables": ["A", "B", "C"] + }; + const commit = jest.fn().mockImplementation((type: FitDataMutation, payload: string) => { if (type === FitDataMutation.SetTimeVariable) { state.timeVariable = payload; @@ -327,7 +336,8 @@ describe("Fit Data actions", () => { dispatch, state: testState, rootState, - getters: testGetters + getters: testGetters, + rootGetters: testRootGetters }, "Day2" ); @@ -358,7 +368,7 @@ describe("Fit Data actions", () => { }; const payload = { column: "a", variable: "I" }; - (actions[FitDataAction.UpdateLinkedVariable] as any)({ commit, dispatch, state: testState }, payload); + (actions[FitDataAction.UpdateLinkedVariable] as any)({ commit, dispatch, state: testState, rootGetters }, payload); expect(commit).toHaveBeenCalledTimes(2); expect(commit.mock.calls[0][0]).toBe(FitDataMutation.SetLinkedVariable); expect(commit.mock.calls[0][1]).toBe(payload); @@ -378,7 +388,7 @@ describe("Fit Data actions", () => { }; const payload = { column: "b", variable: "I" }; - (actions[FitDataAction.UpdateLinkedVariable] as any)({ commit, dispatch, state: testState }, payload); + (actions[FitDataAction.UpdateLinkedVariable] as any)({ commit, dispatch, state: testState, rootGetters }, payload); expect(commit).toHaveBeenCalledTimes(1); expect(commit.mock.calls[0][0]).toBe(FitDataMutation.SetLinkedVariable); expect(commit.mock.calls[0][1]).toBe(payload); @@ -389,7 +399,7 @@ describe("Fit Data actions", () => { it("updates column to fit", () => { const commit = jest.fn(); const dispatch = jest.fn(); - (actions[FitDataAction.UpdateColumnToFit] as any)({ commit, dispatch }, "col1"); + (actions[FitDataAction.UpdateColumnToFit] as any)({ commit, dispatch, rootGetters }, "col1"); expect(commit).toHaveBeenCalledTimes(2); expect(commit.mock.calls[0][0]).toBe(FitDataMutation.SetColumnToFit); expect(commit.mock.calls[0][1]).toBe("col1"); diff --git a/app/static/tests/unit/store/graphSettings/mutations.test.ts b/app/static/tests/unit/store/graphSettings/mutations.test.ts deleted file mode 100644 index 3629bdf36..000000000 --- a/app/static/tests/unit/store/graphSettings/mutations.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { mutations } from "../../../../src/app/store/graphs/mutations"; -import { GraphSettingsState } from "../../../../src/app/store/graphs/state"; - -describe("GraphSettings mutations", () => { - const state: GraphSettingsState = { - logScaleYAxis: false, - lockYAxis: false, - yAxisRange: [0, 0] as [number, number] - }; - - it("sets logScaleYAxis", () => { - mutations.SetLogScaleYAxis(state, true); - expect(state.logScaleYAxis).toBe(true); - }); - - it("sets lockYAxis", () => { - mutations.SetLockYAxis(state, true); - expect(state.lockYAxis).toBe(true); - }); - - it("sets yAxisRange", () => { - mutations.SetYAxisRange(state, { - x: [1, 2], - y: [3, 4] - }); - expect(state.yAxisRange).toStrictEqual({ - x: [1, 2], - y: [3, 4] - }); - }); -}); diff --git a/app/static/tests/unit/store/graphs/actions.test.ts b/app/static/tests/unit/store/graphs/actions.test.ts new file mode 100644 index 000000000..f113a1f33 --- /dev/null +++ b/app/static/tests/unit/store/graphs/actions.test.ts @@ -0,0 +1,70 @@ +import {mockAxios, mockFitState, mockModelState} from "../../../mocks"; +import {actions, GraphsAction} from "../../../../src/app/store/graphs/actions"; +import {GraphsMutation} from "../../../../src/app/store/graphs/mutations"; +import {AppType} from "../../../../src/app/store/appState/state"; +import {FitDataAction} from "../../../../src/app/store/fitData/actions"; + +describe("Graphs actions", () => { + const modelState = { + odinModelResponse: { + metadata: { + variables: [ "a", "b", "c" ] + } + } + } as any; + + const rootState = { + appType: AppType.Basic, + model: modelState + }; + + beforeEach(() => { + mockAxios.reset(); + }); + + it("Updates selected variables commits selection only, if not fit model", () => { + const state = mockModelState(); + const commit = jest.fn(); + const dispatch = jest.fn(); + + (actions[GraphsAction.UpdateSelectedVariables] as any)( + { + commit, + dispatch, + state, + rootState + }, + { index: 1, selectedVariables: ["a", "b"] } + ); + expect(commit).toHaveBeenCalledTimes(1); + expect(commit.mock.calls[0][0]).toBe(GraphsMutation.SetSelectedVariables); + expect(commit.mock.calls[0][1]).toStrictEqual({index: 1, selectedVariables: ["a", "b"], unselectedVariables: ["c"]}); + expect(dispatch).not.toHaveBeenCalled(); + }); + + it("Updates selected variables commits selection and updates linked variables if fit app", () => { + const state = mockModelState(); + const commit = jest.fn(); + const dispatch = jest.fn(); + const fitRootState = mockFitState({ + model: modelState + }); + + (actions[GraphsAction.UpdateSelectedVariables] as any)( + { + commit, + dispatch, + state, + rootState: fitRootState + }, + { index: 1, selectedVariables: ["a", "b"] } + ); + expect(commit).toHaveBeenCalledTimes(1); + expect(commit.mock.calls[0][0]).toBe(GraphsMutation.SetSelectedVariables); + expect(commit.mock.calls[0][1]).toStrictEqual({index: 1, selectedVariables: ["a", "b"], unselectedVariables: ["c"]}); + expect(dispatch).toHaveBeenCalledTimes(1); + expect(dispatch.mock.calls[0][0]).toBe(`fitData/${FitDataAction.UpdateLinkedVariables}`); + expect(dispatch.mock.calls[0][1]).toBe(null); + expect(dispatch.mock.calls[0][2]).toStrictEqual({ root: true }); + }); +}); \ No newline at end of file diff --git a/app/static/tests/unit/store/graphs/mutations.test.ts b/app/static/tests/unit/store/graphs/mutations.test.ts new file mode 100644 index 000000000..558cad908 --- /dev/null +++ b/app/static/tests/unit/store/graphs/mutations.test.ts @@ -0,0 +1,40 @@ +import { mutations } from "../../../../src/app/store/graphs/mutations"; +import { GraphsState } from "../../../../src/app/store/graphs/state"; +import {mockGraphsState, mockModelState} from "../../../mocks"; + +describe("Graphs mutations", () => { + const state: GraphsState = mockGraphsState(); + + it("sets logScaleYAxis", () => { + mutations.SetLogScaleYAxis(state, true); + expect(state.settings.logScaleYAxis).toBe(true); + }); + + it("sets lockYAxis", () => { + mutations.SetLockYAxis(state, true); + expect(state.settings.lockYAxis).toBe(true); + }); + + it("sets yAxisRange", () => { + mutations.SetYAxisRange(state, { + x: [1, 2], + y: [3, 4] + }); + expect(state.settings.yAxisRange).toStrictEqual({ + x: [1, 2], + y: [3, 4] + }); + }); + + it("SetSelectedVariables sets selected and unselected variables", () => { + const testState = mockGraphsState({ + config: [ + { selectedVariables: [], unselectedVariables: [] }, + { selectedVariables: [], unselectedVariables: [] } + ] + }); + mutations.SetSelectedVariables(testState, {index: 1, selectedVariables: ["x", "z"], unselectedVariables: ["y"]}); + expect(testState.config[1]).toStrictEqual({selectedVariables: ["x", "z"], unselectedVariables: ["y"]}); + expect(testState.config[0]).toStrictEqual({ selectedVariables: [], unselectedVariables: [] }); + }); +}); diff --git a/app/static/tests/unit/store/model/actions.test.ts b/app/static/tests/unit/store/model/actions.test.ts index b7381cbf3..8d902886a 100644 --- a/app/static/tests/unit/store/model/actions.test.ts +++ b/app/static/tests/unit/store/model/actions.test.ts @@ -14,7 +14,7 @@ import { actions, ModelAction } from "../../../../src/app/store/model/actions"; import { ModelMutation, mutations } from "../../../../src/app/store/model/mutations"; import { BasicState } from "../../../../src/app/store/basic/state"; import { AppType } from "../../../../src/app/store/appState/state"; -import { actions as runActions } from "../../../../src/app/store/run/actions"; +import {actions as runActions, RunAction} from "../../../../src/app/store/run/actions"; import { FitDataAction } from "../../../../src/app/store/fitData/actions"; import { ModelFitAction } from "../../../../src/app/store/modelFit/actions"; import { RunMutation, mutations as runMutations } from "../../../../src/app/store/run/mutations"; @@ -22,6 +22,8 @@ import { ModelFitMutation } from "../../../../src/app/store/modelFit/mutations"; import { BaseSensitivityMutation, SensitivityMutation } from "../../../../src/app/store/sensitivity/mutations"; import { MultiSensitivityMutation } from "../../../../src/app/store/multiSensitivity/mutations"; import { defaultSensitivityParamSettings } from "../../../../src/app/store/sensitivity/sensitivity"; +import { GraphsMutation } from "../../../../src/app/store/graphs/mutations"; +import {GraphsAction} from "../../../../src/app/store/graphs/actions"; describe("Model actions", () => { beforeEach(() => { @@ -37,6 +39,11 @@ describe("Model actions", () => { code: { currentCode: ["line1", "line2"] }, + graphs: { + config: [ + { selectedVariables: ["x", "y"], unselectedVariables: [] } + ] + }, sensitivity: { paramSettings: { parameterToVary: null @@ -171,7 +178,7 @@ describe("Model actions", () => { state: updatedParamState, rootState }); - expect(commit.mock.calls.length).toBe(10); + expect(commit.mock.calls.length).toBe(9); expect(commit.mock.calls[0][0]).toBe(ModelMutation.SetOdin); expect(commit.mock.calls[0][1]).toBe(3); expect(commit.mock.calls[1][0]).toBe(`run/${RunMutation.SetParameterValues}`); @@ -180,29 +187,29 @@ describe("Model actions", () => { expect(commit.mock.calls[2][0]).toBe(ModelMutation.SetPaletteModel); expect(commit.mock.calls[2][1]).toStrictEqual({ x: "#2e5cb8", y: "#cccc00", z: "#cc0044" }); // sets selected variables, retaining previous values, and defaulting new variables to selected - expect(commit.mock.calls[3][0]).toBe(ModelMutation.SetSelectedVariables); - expect(commit.mock.calls[3][1]).toStrictEqual(["x", "z"]); - expect(commit.mock.calls[4][0]).toBe(ModelMutation.SetCompileRequired); - expect(commit.mock.calls[4][1]).toBe(false); - expect(commit.mock.calls[5][0]).toBe(`run/${RunMutation.SetRunRequired}`); + expect(commit.mock.calls[3][0]).toBe(ModelMutation.SetCompileRequired); + expect(commit.mock.calls[3][1]).toBe(false); + expect(commit.mock.calls[4][0]).toBe(`run/${RunMutation.SetRunRequired}`); + expect(commit.mock.calls[4][1]).toStrictEqual({ modelChanged: true }); + expect(commit.mock.calls[5][0]).toBe(`sensitivity/${BaseSensitivityMutation.SetUpdateRequired}`); expect(commit.mock.calls[5][1]).toStrictEqual({ modelChanged: true }); - expect(commit.mock.calls[6][0]).toBe(`sensitivity/${BaseSensitivityMutation.SetUpdateRequired}`); + expect(commit.mock.calls[5][2]).toStrictEqual({ root: true }); + expect(commit.mock.calls[6][0]).toBe(`multiSensitivity/${BaseSensitivityMutation.SetUpdateRequired}`); expect(commit.mock.calls[6][1]).toStrictEqual({ modelChanged: true }); expect(commit.mock.calls[6][2]).toStrictEqual({ root: true }); - expect(commit.mock.calls[7][0]).toBe(`multiSensitivity/${BaseSensitivityMutation.SetUpdateRequired}`); - expect(commit.mock.calls[7][1]).toStrictEqual({ modelChanged: true }); - expect(commit.mock.calls[7][2]).toStrictEqual({ root: true }); // TODO: should this not also hit { sensitivityOptionsChanged: true } - expect(commit.mock.calls[8][0]).toBe(`sensitivity/${SensitivityMutation.SetParameterToVary}`); - expect(commit.mock.calls[8][1]).toBe("p2"); - expect(commit.mock.calls[8][2]).toStrictEqual({ root: true }); + expect(commit.mock.calls[7][0]).toBe(`sensitivity/${SensitivityMutation.SetParameterToVary}`); + expect(commit.mock.calls[7][1]).toBe("p2"); + expect(commit.mock.calls[7][2]).toStrictEqual({ root: true }); // Should remove old parameter from multiSensitivity array, but leave the remaining parameter - expect(commit.mock.calls[9][0]).toBe(`multiSensitivity/${MultiSensitivityMutation.SetParamSettings}`); - expect(commit.mock.calls[9][1]).toStrictEqual([{ parameterToVary: "p2" }]); - expect(commit.mock.calls[9][2]).toStrictEqual({ root: true }); + expect(commit.mock.calls[8][0]).toBe(`multiSensitivity/${MultiSensitivityMutation.SetParamSettings}`); + expect(commit.mock.calls[8][1]).toStrictEqual([{ parameterToVary: "p2" }]); + expect(commit.mock.calls[8][2]).toStrictEqual({ root: true }); // does not dispatch updated linked variables or update params to vary if app type is not Fit - expect(dispatch).not.toHaveBeenCalled(); + expect(dispatch.mock.calls.length).toBe(1); + expect(dispatch.mock.calls[0][0]).toBe(`graphs/${GraphsAction.UpdateSelectedVariables}`); + expect(dispatch.mock.calls[0][1]).toStrictEqual({ index: 0, selectedVariables: ["x", "y", "z"]}); }); it("does not set multi-sensitivity update required or parameter to vary when multiSensitivity not enabled", () => { @@ -212,6 +219,11 @@ describe("Model actions", () => { config: { multiSensitivity: false }, sensitivity: { paramSettings: {} + }, + graphs: { + config: [ + { selectedVariables: ["x", "y"], unselectedVariables: [] } + ] } }; (actions[ModelAction.CompileModel] as any)({ @@ -220,15 +232,16 @@ describe("Model actions", () => { state: updatedParamState, rootState: noMultiRootState }); - expect(commit.mock.calls.length).toBe(8); + expect(commit.mock.calls.length).toBe(7); expect(commit.mock.calls[0][0]).toBe(ModelMutation.SetOdin); expect(commit.mock.calls[1][0]).toBe(`run/${RunMutation.SetParameterValues}`); expect(commit.mock.calls[2][0]).toBe(ModelMutation.SetPaletteModel); - expect(commit.mock.calls[3][0]).toBe(ModelMutation.SetSelectedVariables); - expect(commit.mock.calls[4][0]).toBe(ModelMutation.SetCompileRequired); - expect(commit.mock.calls[5][0]).toBe(`run/${RunMutation.SetRunRequired}`); - expect(commit.mock.calls[6][0]).toBe(`sensitivity/${BaseSensitivityMutation.SetUpdateRequired}`); - expect(commit.mock.calls[7][0]).toBe(`sensitivity/${SensitivityMutation.SetParameterToVary}`); + expect(commit.mock.calls[3][0]).toBe(ModelMutation.SetCompileRequired); + expect(commit.mock.calls[4][0]).toBe(`run/${RunMutation.SetRunRequired}`); + expect(commit.mock.calls[5][0]).toBe(`sensitivity/${BaseSensitivityMutation.SetUpdateRequired}`); + expect(commit.mock.calls[6][0]).toBe(`sensitivity/${SensitivityMutation.SetParameterToVary}`); + expect(dispatch.mock.calls.length).toBe(1); + expect(dispatch.mock.calls[0][0]).toBe(`graphs/${GraphsAction.UpdateSelectedVariables}`); }); it("compile does not update multiSensitivity param settings if multisensitivity is not configured", () => { @@ -246,9 +259,9 @@ describe("Model actions", () => { state: updatedParamState, rootState: noMultiSensRootState }); - expect(commit.mock.calls.length).toBe(8); - expect(commit.mock.calls[7][0]).toBe(`sensitivity/${SensitivityMutation.SetParameterToVary}`); - expect(dispatch).not.toHaveBeenCalled(); + expect(commit.mock.calls.length).toBe(7); + expect(dispatch.mock.calls.length).toBe(1); + expect(commit.mock.calls[6][0]).toBe(`sensitivity/${SensitivityMutation.SetParameterToVary}`); }); it("compile updates multiSensitivity with default param settings if all previous settings are removed", () => { @@ -259,17 +272,19 @@ describe("Model actions", () => { } }; const commit = jest.fn(); + const dispatch = jest.fn(); (actions[ModelAction.CompileModel] as any)({ commit, + dispatch, state: updatedParamState, rootState: oldMultiSensRootState }); - expect(commit.mock.calls.length).toBe(10); - expect(commit.mock.calls[9][0]).toBe(`multiSensitivity/${MultiSensitivityMutation.SetParamSettings}`); - expect(commit.mock.calls[9][1]).toStrictEqual([ + expect(commit.mock.calls.length).toBe(9); + expect(commit.mock.calls[8][0]).toBe(`multiSensitivity/${MultiSensitivityMutation.SetParamSettings}`); + expect(commit.mock.calls[8][1]).toStrictEqual([ { ...defaultSensitivityParamSettings(), parameterToVary: "p2" } ]); - expect(commit.mock.calls[9][2]).toStrictEqual({ root: true }); + expect(commit.mock.calls[8][2]).toStrictEqual({ root: true }); }); it("compile model dispatches update linked variables and update params to vary for Fit apps", () => { @@ -291,6 +306,11 @@ describe("Model actions", () => { paramSettings: { parameterToVary: "p1" } + }, + graphs: { + config: [ + { selectedVariables: ["x", "y"], unselectedVariables: [] } + ] } }; const commit = jest.fn(); @@ -301,26 +321,27 @@ describe("Model actions", () => { state, rootState: fitRootState }); - expect(commit.mock.calls.length).toBe(9); + expect(commit.mock.calls.length).toBe(8); expect(commit.mock.calls[0][0]).toBe(ModelMutation.SetOdin); expect(commit.mock.calls[1][0]).toBe(`run/${RunMutation.SetParameterValues}`); expect(commit.mock.calls[2][0]).toBe(ModelMutation.SetPaletteModel); - expect(commit.mock.calls[3][0]).toBe(ModelMutation.SetSelectedVariables); - expect(commit.mock.calls[3][1]).toStrictEqual(["x", "y"]); - expect(commit.mock.calls[4][0]).toBe(ModelMutation.SetCompileRequired); - expect(commit.mock.calls[5][0]).toBe(`run/${RunMutation.SetRunRequired}`); - expect(commit.mock.calls[6][0]).toBe(`sensitivity/${BaseSensitivityMutation.SetUpdateRequired}`); - expect(commit.mock.calls[6][1]).toStrictEqual({ modelChanged: true }); - expect(commit.mock.calls[7][0]).toBe(`sensitivity/${SensitivityMutation.SetParameterToVary}`); - expect(commit.mock.calls[7][1]).toBe(null); + + expect(commit.mock.calls[3][0]).toBe(ModelMutation.SetCompileRequired); + expect(commit.mock.calls[4][0]).toBe(`run/${RunMutation.SetRunRequired}`); + expect(commit.mock.calls[5][0]).toBe(`sensitivity/${BaseSensitivityMutation.SetUpdateRequired}`); + expect(commit.mock.calls[5][1]).toStrictEqual({ modelChanged: true }); + expect(commit.mock.calls[6][0]).toBe(`sensitivity/${SensitivityMutation.SetParameterToVary}`); + expect(commit.mock.calls[6][1]).toBe(null); + expect(commit.mock.calls[6][2]).toStrictEqual({ root: true }); + expect(commit.mock.calls[7][0]).toBe(`modelFit/${ModelFitMutation.SetFitUpdateRequired}`); + expect(commit.mock.calls[7][1]).toStrictEqual({ modelChanged: true }); expect(commit.mock.calls[7][2]).toStrictEqual({ root: true }); - expect(commit.mock.calls[8][0]).toBe(`modelFit/${ModelFitMutation.SetFitUpdateRequired}`); - expect(commit.mock.calls[8][1]).toStrictEqual({ modelChanged: true }); - expect(commit.mock.calls[8][2]).toStrictEqual({ root: true }); - expect(dispatch).toHaveBeenCalledTimes(2); - expect(dispatch.mock.calls[0][0]).toBe(`fitData/${FitDataAction.UpdateLinkedVariables}`); - expect(dispatch.mock.calls[1][0]).toBe(`modelFit/${ModelFitAction.UpdateParamsToVary}`); + expect(dispatch).toHaveBeenCalledTimes(3); + expect(dispatch.mock.calls[0][0]).toBe(`graphs/${GraphsAction.UpdateSelectedVariables}`); + expect(dispatch.mock.calls[0][1]).toStrictEqual({index: 0, selectedVariables: ["x", "y"]}); + expect(dispatch.mock.calls[1][0]).toBe(`fitData/${FitDataAction.UpdateLinkedVariables}`); + expect(dispatch.mock.calls[2][0]).toBe(`modelFit/${ModelFitAction.UpdateParamsToVary}`); }); it("compile model does not update paramToVary if current parameter exists in new model", () => { @@ -365,17 +386,20 @@ describe("Model actions", () => { state, rootState: testRootState }); - expect(commit.mock.calls.length).toBe(9); + expect(commit.mock.calls.length).toBe(8); expect(commit.mock.calls[0][0]).toBe(ModelMutation.SetOdin); expect(commit.mock.calls[1][0]).toBe(`run/${RunMutation.SetParameterValues}`); expect(commit.mock.calls[2][0]).toBe(ModelMutation.SetPaletteModel); - expect(commit.mock.calls[3][0]).toBe(ModelMutation.SetSelectedVariables); - expect(commit.mock.calls[3][1]).toStrictEqual(["x", "y"]); - expect(commit.mock.calls[4][0]).toBe(ModelMutation.SetCompileRequired); - expect(commit.mock.calls[5][0]).toBe(`run/${RunMutation.SetRunRequired}`); - expect(commit.mock.calls[6][0]).toBe(`sensitivity/${BaseSensitivityMutation.SetUpdateRequired}`); - expect(commit.mock.calls[7][0]).toBe(`multiSensitivity/${BaseSensitivityMutation.SetUpdateRequired}`); - expect(commit.mock.calls[8][0]).toBe(`multiSensitivity/${MultiSensitivityMutation.SetParamSettings}`); + + expect(commit.mock.calls[3][0]).toBe(ModelMutation.SetCompileRequired); + expect(commit.mock.calls[4][0]).toBe(`run/${RunMutation.SetRunRequired}`); + expect(commit.mock.calls[5][0]).toBe(`sensitivity/${BaseSensitivityMutation.SetUpdateRequired}`); + expect(commit.mock.calls[6][0]).toBe(`multiSensitivity/${BaseSensitivityMutation.SetUpdateRequired}`); + expect(commit.mock.calls[7][0]).toBe(`multiSensitivity/${MultiSensitivityMutation.SetParamSettings}`); + + expect(dispatch.mock.calls.length).toBe(1); + expect(dispatch.mock.calls[0][0]).toBe(`graphs/${GraphsAction.UpdateSelectedVariables}`); + expect(dispatch.mock.calls[0][1]).toStrictEqual({ index: 0, selectedVariables: ["x", "y"] }); }); it("compile model does not update runRequired or compileRequired if compileRequired was false", () => { @@ -387,24 +411,25 @@ describe("Model actions", () => { variables: ["x", "y"] } } as any, - compileRequired: false, - selectedVariables: ["x", "y"], - unselectedVariables: [] + compileRequired: false }); const commit = jest.fn(); - (actions[ModelAction.CompileModel] as any)({ commit, state, rootState }); - expect(commit.mock.calls.length).toBe(6); + const dispatch = jest.fn(); + (actions[ModelAction.CompileModel] as any)({ commit, dispatch, state, rootState }); + expect(commit.mock.calls.length).toBe(5); expect(commit.mock.calls[0][0]).toBe(ModelMutation.SetOdin); expect(commit.mock.calls[0][1]).toBe(3); expect(commit.mock.calls[1][0]).toBe(`run/${RunMutation.SetParameterValues}`); expect(commit.mock.calls[1][1]).toStrictEqual({}); expect(commit.mock.calls[2][0]).toBe(ModelMutation.SetPaletteModel); - expect(commit.mock.calls[3][0]).toBe(ModelMutation.SetSelectedVariables); - expect(commit.mock.calls[3][1]).toStrictEqual(["x", "y"]); - expect(commit.mock.calls[4][0]).toBe(`sensitivity/${SensitivityMutation.SetParameterToVary}`); - expect(commit.mock.calls[4][1]).toBe(null); - expect(commit.mock.calls[5][0]).toBe(`multiSensitivity/${MultiSensitivityMutation.SetParamSettings}`); - expect(commit.mock.calls[5][1]).toStrictEqual([defaultSensitivityParamSettings()]); + expect(commit.mock.calls[3][0]).toBe(`sensitivity/${SensitivityMutation.SetParameterToVary}`); + expect(commit.mock.calls[3][1]).toBe(null); + expect(commit.mock.calls[4][0]).toBe(`multiSensitivity/${MultiSensitivityMutation.SetParamSettings}`); + expect(commit.mock.calls[4][1]).toStrictEqual([defaultSensitivityParamSettings()]); + + expect(dispatch.mock.calls.length).toBe(1); + expect(dispatch.mock.calls[0][0]).toBe(`graphs/${GraphsAction.UpdateSelectedVariables}`); + expect(dispatch.mock.calls[0][1]).toStrictEqual({ index: 0, selectedVariables: ["x", "y"]}); }); it("compile model does nothing if no odin response", () => { @@ -478,10 +503,11 @@ describe("Model actions", () => { mockAxios.onPost("/odin/model").reply(200, mockSuccess(testModel)); const commit = jest.spyOn(store, "commit"); + const dispatch = jest.spyOn(store, "dispatch"); await store.dispatch(`model/${ModelAction.DefaultModel}`); - expect(commit.mock.calls.length).toBe(11); + expect(commit.mock.calls.length).toBe(10); // fetch const postData = JSON.parse(mockAxios.history.post[0].data); @@ -506,20 +532,17 @@ describe("Model actions", () => { expect(commit.mock.calls[4][0]).toBe(`model/${ModelMutation.SetPaletteModel}`); expect(commit.mock.calls[4][1]).toStrictEqual({ x: "#2e5cb8", y: "#cc0044" }); - expect(commit.mock.calls[5][0]).toBe(`model/${ModelMutation.SetSelectedVariables}`); - expect(commit.mock.calls[5][1]).toStrictEqual(["x", "y"]); + expect(commit.mock.calls[5][0]).toBe(`model/${ModelMutation.SetCompileRequired}`); + expect(commit.mock.calls[5][1]).toBe(false); - expect(commit.mock.calls[6][0]).toBe(`model/${ModelMutation.SetCompileRequired}`); - expect(commit.mock.calls[6][1]).toBe(false); + expect(commit.mock.calls[6][0]).toBe(`run/${RunMutation.SetRunRequired}`); + expect(commit.mock.calls[6][1]).toStrictEqual({ modelChanged: true }); - expect(commit.mock.calls[7][0]).toBe(`run/${RunMutation.SetRunRequired}`); + expect(commit.mock.calls[7][0]).toBe(`sensitivity/${BaseSensitivityMutation.SetUpdateRequired}`); expect(commit.mock.calls[7][1]).toStrictEqual({ modelChanged: true }); - expect(commit.mock.calls[8][0]).toBe(`sensitivity/${BaseSensitivityMutation.SetUpdateRequired}`); - expect(commit.mock.calls[8][1]).toStrictEqual({ modelChanged: true }); - - expect(commit.mock.calls[9][0]).toBe(`sensitivity/${SensitivityMutation.SetParameterToVary}`); - expect(commit.mock.calls[9][1]).toStrictEqual("p1"); + expect(commit.mock.calls[8][0]).toBe(`sensitivity/${SensitivityMutation.SetParameterToVary}`); + expect(commit.mock.calls[8][1]).toStrictEqual("p1"); // runs const run = runner.wodinRun; @@ -528,55 +551,17 @@ describe("Model actions", () => { expect(run.mock.calls[0][2]).toBe(0); // start expect(run.mock.calls[0][3]).toBe(99); // end - expect(commit.mock.calls[10][0]).toBe(`run/${RunMutation.SetResultOde}`); - expect(commit.mock.calls[10][1]).toEqual({ + expect(commit.mock.calls[9][0]).toBe(`run/${RunMutation.SetResultOde}`); + expect(commit.mock.calls[9][1]).toEqual({ error: null, inputs: { endTime: 99, parameterValues: { p1: 1 } }, solution: "test solution" }); - }); - - it("Updates selected variables commits selection and updates linked variables if fit app", () => { - const state = mockModelState(); - const commit = jest.fn(); - const dispatch = jest.fn(); - const fitRootState = mockFitState(); - - (actions[ModelAction.UpdateSelectedVariables] as any)( - { - commit, - dispatch, - state, - rootState: fitRootState - }, - ["a", "b"] - ); - expect(commit).toHaveBeenCalledTimes(1); - expect(commit.mock.calls[0][0]).toBe(ModelMutation.SetSelectedVariables); - expect(commit.mock.calls[0][1]).toStrictEqual(["a", "b"]); - expect(dispatch).toHaveBeenCalledTimes(1); - expect(dispatch.mock.calls[0][0]).toBe(`fitData/${FitDataAction.UpdateLinkedVariables}`); - expect(dispatch.mock.calls[0][1]).toBe(null); - expect(dispatch.mock.calls[0][2]).toStrictEqual({ root: true }); - }); - it("Updates selected variables commits selection only, if not fit model", () => { - const state = mockModelState(); - const commit = jest.fn(); - const dispatch = jest.fn(); + expect(dispatch.mock.calls.length).toBe(3); + expect(dispatch.mock.calls[1][0]).toBe(`graphs/${GraphsAction.UpdateSelectedVariables}`); + expect(dispatch.mock.calls[1][1]).toStrictEqual({ index: 0, selectedVariables:["x", "y"]}); - (actions[ModelAction.UpdateSelectedVariables] as any)( - { - commit, - dispatch, - state, - rootState - }, - ["a", "b"] - ); - expect(commit).toHaveBeenCalledTimes(1); - expect(commit.mock.calls[0][0]).toBe(ModelMutation.SetSelectedVariables); - expect(commit.mock.calls[0][1]).toStrictEqual(["a", "b"]); - expect(dispatch).not.toHaveBeenCalled(); + expect(dispatch.mock.calls[2][0]).toBe(`run/${RunAction.RunModel}`); }); }); diff --git a/app/static/tests/unit/store/model/mutations.test.ts b/app/static/tests/unit/store/model/mutations.test.ts index 9a53d5907..8c5d4e9f0 100644 --- a/app/static/tests/unit/store/model/mutations.test.ts +++ b/app/static/tests/unit/store/model/mutations.test.ts @@ -1,4 +1,4 @@ -import { mutations } from "../../../../src/app/store/model/mutations"; + import { mutations } from "../../../../src/app/store/model/mutations"; import { mockError, mockModelState } from "../../../mocks"; describe("Model mutations", () => { @@ -68,17 +68,4 @@ describe("Model mutations", () => { mutations.SetCompileRequired(state, false); expect(state.compileRequired).toBe(false); }); - - it("SetSelectedVariables sets selected and unselected variables", () => { - const state = mockModelState({ - odinModelResponse: { - metadata: { - variables: ["x", "y", "z"] - } - } as any - }); - mutations.SetSelectedVariables(state, ["x", "z"]); - expect(state.selectedVariables).toStrictEqual(["x", "z"]); - expect(state.unselectedVariables).toStrictEqual(["y"]); - }); });