From 6a95fa0077dd27f49213c0dbd2b86566d0520e59 Mon Sep 17 00:00:00 2001 From: EmmaLRussell Date: Sun, 5 Nov 2023 13:59:00 +0000 Subject: [PATCH 1/4] display model fit error --- app/static/src/app/components/fit/FitTab.vue | 9 +++++ app/static/src/app/serialise.ts | 3 +- .../src/app/store/appState/mutations.ts | 3 +- app/static/src/app/store/modelFit/actions.ts | 40 ++++++++++--------- app/static/src/app/store/modelFit/modelFit.ts | 3 +- .../src/app/store/modelFit/mutations.ts | 12 +++++- app/static/src/app/store/modelFit/state.ts | 2 + .../src/app/types/serialisationTypes.ts | 3 +- app/static/src/app/userMessages.ts | 1 + 9 files changed, 52 insertions(+), 24 deletions(-) diff --git a/app/static/src/app/components/fit/FitTab.vue b/app/static/src/app/components/fit/FitTab.vue index e0577c0f7..c8d6b7566 100644 --- a/app/static/src/app/components/fit/FitTab.vue +++ b/app/static/src/app/components/fit/FitTab.vue @@ -21,6 +21,7 @@
{{cancelledMsg}}
+ @@ -39,10 +40,12 @@ import { ModelFitMutation } from "../../store/modelFit/mutations"; import { fitRequirementsExplanation, fitUpdateRequiredExplanation } from "./support"; import { allTrue, anyTrue } from "../../utils"; import LoadingButton from "../LoadingButton.vue"; +import ErrorInfo from "@/app/components/ErrorInfo.vue"; export default defineComponent({ name: "FitTab", components: { + ErrorInfo, LoadingSpinner, FitPlot, ActionRequiredMessage, @@ -57,6 +60,7 @@ export default defineComponent({ const canFitModel = computed(() => allTrue(fitRequirements.value)); const compileRequired = computed(() => store.state.model.compileRequired); const fitUpdateRequired = computed(() => store.state.modelFit.fitUpdateRequired); + const error = computed(() => store.state.modelFit.error); const fitModel = () => store.dispatch(`${namespace}/${ModelFitAction.FitModel}`); const cancelFit = () => store.commit(`${namespace}/${ModelFitMutation.SetFitting}`, false); @@ -68,6 +72,10 @@ export default defineComponent({ const sumOfSquares = computed(() => store.state.modelFit.sumOfSquares); const actionRequiredMessage = computed(() => { + if (error.value) { + return userMessages.modelFit.errorOccurred; + } + if (!allTrue(fitRequirements.value)) { return fitRequirementsExplanation(fitRequirements.value); } @@ -119,6 +127,7 @@ export default defineComponent({ cancelledMsg, sumOfSquares, actionRequiredMessage, + error, iconType, iconClass }; diff --git a/app/static/src/app/serialise.ts b/app/static/src/app/serialise.ts index 7585566c4..f768e98a4 100644 --- a/app/static/src/app/serialise.ts +++ b/app/static/src/app/serialise.ts @@ -130,7 +130,8 @@ function serialiseModelFit(modelFit: ModelFitState): SerialisedModelFitState { converged: modelFit.converged, sumOfSquares: modelFit.sumOfSquares, paramsToVary: modelFit.paramsToVary, - result: serialiseSolutionResult(modelFit.result) + result: serialiseSolutionResult(modelFit.result), + error: modelFit.error }; } diff --git a/app/static/src/app/store/appState/mutations.ts b/app/static/src/app/store/appState/mutations.ts index 67128a618..93de9390e 100644 --- a/app/static/src/app/store/appState/mutations.ts +++ b/app/static/src/app/store/appState/mutations.ts @@ -21,7 +21,8 @@ export enum AppStateMutation { export const StateUploadMutations = [ AppStateMutation.ClearQueuedStateUpload, AppStateMutation.SetQueuedStateUpload, - AppStateMutation.SetStateUploadInProgress + AppStateMutation.SetStateUploadInProgress, + AppStateMutation.SetPersisted ] as string[]; export const appStateMutations: MutationTree = { diff --git a/app/static/src/app/store/modelFit/actions.ts b/app/static/src/app/store/modelFit/actions.ts index a7c8ca8e2..6dd584308 100644 --- a/app/static/src/app/store/modelFit/actions.ts +++ b/app/static/src/app/store/modelFit/actions.ts @@ -50,24 +50,28 @@ export const actions: ActionTree = { const { advancedSettings } = rootState.run; const advancedSettingsOdin = convertAdvancedSettingsToOdin(advancedSettings, pars.base); - const simplex = odinRunnerOde!.wodinFit( - odin!, - data, - pars, - linkedVariable, - advancedSettingsOdin, - {} - ); - - const inputs = { - data, - endTime, - link - }; - - commit(ModelFitMutation.SetFitUpdateRequired, null); - commit(ModelFitMutation.SetInputs, inputs); - dispatch(ModelFitAction.FitModelStep, simplex); + try { + const simplex = odinRunnerOde!.wodinFit( + odin!, + data, + pars, + linkedVariable, + advancedSettingsOdin, + {} + ); + + const inputs = { + data, + endTime, + link + }; + commit(ModelFitMutation.SetFitUpdateRequired, null); + commit(ModelFitMutation.SetInputs, inputs); + dispatch(ModelFitAction.FitModelStep, simplex); + } catch (e: unknown) { + commit(ModelFitMutation.SetError, {error: "Model fit error", detail: (e as Error).message}); + commit(ModelFitMutation.SetFitting, false); + } } }, diff --git a/app/static/src/app/store/modelFit/modelFit.ts b/app/static/src/app/store/modelFit/modelFit.ts index a5bca25b3..0048dc8c6 100644 --- a/app/static/src/app/store/modelFit/modelFit.ts +++ b/app/static/src/app/store/modelFit/modelFit.ts @@ -18,7 +18,8 @@ export const defaultState: ModelFitState = { sumOfSquares: null, paramsToVary: [], inputs: null, - result: null + result: null, + error: null }; export const modelFit = { diff --git a/app/static/src/app/store/modelFit/mutations.ts b/app/static/src/app/store/modelFit/mutations.ts index 976ec1e88..d8ed59750 100644 --- a/app/static/src/app/store/modelFit/mutations.ts +++ b/app/static/src/app/store/modelFit/mutations.ts @@ -1,6 +1,6 @@ import { MutationTree } from "vuex"; import { ModelFitInputs, ModelFitState, FitUpdateRequiredReasons } from "./state"; -import { SimplexResult } from "../../types/responseTypes"; +import {SimplexResult, WodinError} from "../../types/responseTypes"; export enum ModelFitMutation { SetFitting = "SetFitting", @@ -8,12 +8,16 @@ export enum ModelFitMutation { SetInputs = "SetInputs", SetParamsToVary = "SetParamsToVary", SetSumOfSquares = "SetSumOfSquares", - SetFitUpdateRequired = "SetFitUpdateRequired" + SetFitUpdateRequired = "SetFitUpdateRequired", + SetError = "SetError" } export const mutations: MutationTree = { [ModelFitMutation.SetFitting](state: ModelFitState, payload: boolean) { state.fitting = payload; + if (payload) { + state.error = null + } }, [ModelFitMutation.SetResult](state: ModelFitState, payload: SimplexResult) { @@ -43,6 +47,10 @@ export const mutations: MutationTree = { state.sumOfSquares = payload; }, + [ModelFitMutation.SetError](state: ModelFitState, payload: WodinError) { + state.error = payload; + }, + [ModelFitMutation.SetFitUpdateRequired](state: ModelFitState, payload: null | Partial) { if (payload === null) { state.fitUpdateRequired = { diff --git a/app/static/src/app/store/modelFit/state.ts b/app/static/src/app/store/modelFit/state.ts index e2fe35acf..33ebe3fec 100644 --- a/app/static/src/app/store/modelFit/state.ts +++ b/app/static/src/app/store/modelFit/state.ts @@ -1,5 +1,6 @@ import { OdinFitResult } from "../../types/wrapperTypes"; import type { FitData, FitDataLink } from "../fitData/state"; +import {WodinError} from "../../types/responseTypes"; export interface ModelFitInputs { data: FitData; @@ -25,6 +26,7 @@ export interface ModelFitState { paramsToVary: string[], inputs: ModelFitInputs | null, // all inputs except parameters, which vary result: OdinFitResult | null, // full solution for current best fit, + error: null | WodinError } export interface ModelFitRequirements { diff --git a/app/static/src/app/types/serialisationTypes.ts b/app/static/src/app/types/serialisationTypes.ts index 19fc54d5e..8f242a946 100644 --- a/app/static/src/app/types/serialisationTypes.ts +++ b/app/static/src/app/types/serialisationTypes.ts @@ -77,7 +77,8 @@ export interface SerialisedModelFitState { converged: boolean | null, sumOfSquares: number | null, paramsToVary: string[], - result: SerialisedRunResult | null + result: SerialisedRunResult | null, + error: null | WodinError } export interface SerialisedAppState { diff --git a/app/static/src/app/userMessages.ts b/app/static/src/app/userMessages.ts index d6c9968c9..f4c43cf1e 100644 --- a/app/static/src/app/userMessages.ts +++ b/app/static/src/app/userMessages.ts @@ -56,6 +56,7 @@ export default { notFittedYet: "Model has not been fitted.", selectParamToVary: "Please select at least one parameter to vary during model fit.", compileRequired: "Model code has been updated. Compile code and Fit Model for updated best fit.", + errorOccurred: "An error occurred during model fit.", updateFitReasons: { prefix: "Fit is out of date:", unknown: "unknown reasons, contact the administrator, as this is unexpected", From 4f2b21f70ef76fe5daf6270c9f971b7d67299320 Mon Sep 17 00:00:00 2001 From: EmmaLRussell Date: Mon, 6 Nov 2023 09:40:15 +0000 Subject: [PATCH 2/4] e2e test --- app/static/src/app/components/fit/FitTab.vue | 2 +- app/static/tests/e2e/fit.etest.ts | 35 +++++++++++++++++++ app/static/tests/mocks.ts | 1 + .../tests/unit/components/fit/fitTab.test.ts | 16 ++++++++- app/static/tests/unit/serialiser.test.ts | 2 ++ .../tests/unit/store/modelFit/actions.test.ts | 34 ++++++++++++++++++ .../unit/store/modelFit/mutations.test.ts | 16 +++++++++ 7 files changed, 104 insertions(+), 2 deletions(-) diff --git a/app/static/src/app/components/fit/FitTab.vue b/app/static/src/app/components/fit/FitTab.vue index c8d6b7566..375281416 100644 --- a/app/static/src/app/components/fit/FitTab.vue +++ b/app/static/src/app/components/fit/FitTab.vue @@ -40,7 +40,7 @@ import { ModelFitMutation } from "../../store/modelFit/mutations"; import { fitRequirementsExplanation, fitUpdateRequiredExplanation } from "./support"; import { allTrue, anyTrue } from "../../utils"; import LoadingButton from "../LoadingButton.vue"; -import ErrorInfo from "@/app/components/ErrorInfo.vue"; +import ErrorInfo from "../ErrorInfo.vue"; export default defineComponent({ name: "FitTab", diff --git a/app/static/tests/e2e/fit.etest.ts b/app/static/tests/e2e/fit.etest.ts index cf38deb17..43b22eba6 100644 --- a/app/static/tests/e2e/fit.etest.ts +++ b/app/static/tests/e2e/fit.etest.ts @@ -163,6 +163,41 @@ test.describe("Wodin App model fit tests", () => { expect(newSumOfSquares).not.toEqual(sumOfSquares); }); + test("can show model fit error", async ({page}) => { + // Upload data + await uploadCSVData(page, realisticFitData); + await page.click(":nth-match(.wodin-right .nav-tabs a, 2)"); + + // link variables + await page.click(":nth-match(.wodin-left .nav-tabs a, 3)"); + const linkContainer = await page.locator(":nth-match(.collapse .container, 1)"); + const select1 = await linkContainer.locator(":nth-match(select, 1)"); + await select1.selectOption("E"); + + await expect(await page.innerText("#optimisation label#target-fit-label")).toBe("Cases ~ E"); + + // select param to vary + await page.click(":nth-match(.wodin-right .nav-tabs a, 2)"); + await expect(await page.innerText("#select-param-msg")) + .toBe("Please select at least one parameter to vary during model fit.") + await page.click(":nth-match(input.vary-param-check, 1)"); + await page.click(":nth-match(input.vary-param-check, 2)"); + + // change advanced setting to sabotage fit + await page.click(":nth-match(.collapse-title, 6)"); // Open Advanced Settings + const advancedSettingPanel = await page.locator("#advanced-settings-panel"); + const input1 = await advancedSettingPanel.locator(":nth-match(input, 1)"); + const input2 = await advancedSettingPanel.locator(":nth-match(input, 2)"); + await input1.fill("7"); + await input2.fill("-1"); + + await page.click(".wodin-right .wodin-content div.mt-4 button#fit-btn"); + console.log("15"); + + await expect(await page.locator(".fit-tab .action-required-msg")).toHaveText("An error occurred during model fit.", {timeout}); + await expect(await page.innerText(".fit-tab #error-info")).toContain("Model fit error: Integration failure"); + }); + test("can see expected update required messages when code changes", async ({ page }) => { await runFit(page); await expectUpdateFitMsg(page, ""); diff --git a/app/static/tests/mocks.ts b/app/static/tests/mocks.ts index f62fe4b54..959c8bb32 100644 --- a/app/static/tests/mocks.ts +++ b/app/static/tests/mocks.ts @@ -239,6 +239,7 @@ export const mockModelFitState = (state: Partial = {}): ModelFitS paramsToVary: [], inputs: null, result: null, + error: null, ...state }; }; diff --git a/app/static/tests/unit/components/fit/fitTab.test.ts b/app/static/tests/unit/components/fit/fitTab.test.ts index b0c5d99bf..65c538a0f 100644 --- a/app/static/tests/unit/components/fit/fitTab.test.ts +++ b/app/static/tests/unit/components/fit/fitTab.test.ts @@ -1,4 +1,6 @@ // Mock plotly before import RunTab, which indirectly imports plotly via FitPlot +import ErrorInfo from "../../../../src/app/components/ErrorInfo.vue"; + jest.mock("plotly.js-basic-dist-min", () => {}); /* eslint-disable import/first */ @@ -11,6 +13,7 @@ import ActionRequiredMessage from "../../../../src/app/components/ActionRequired import LoadingSpinner from "../../../../src/app/components/LoadingSpinner.vue"; import FitPlot from "../../../../src/app/components/fit/FitPlot.vue"; import { mockFitState, mockGraphSettingsState } from "../../../mocks"; +import {WodinError} from "../../../../src/app/types/responseTypes"; describe("Fit Tab", () => { const getWrapper = ( @@ -22,7 +25,8 @@ describe("Fit Tab", () => { fitting = false, sumOfSquares: number | null = 2.1, mockFitModel = jest.fn(), - mockSetFitting = jest.fn() + mockSetFitting = jest.fn(), + error: WodinError | null = null ) => { const store = new Vuex.Store({ state: mockFitState(), @@ -45,6 +49,7 @@ describe("Fit Tab", () => { fitting, sumOfSquares, fitUpdateRequired, + error, result: { solution: jest.fn() } @@ -82,6 +87,7 @@ describe("Fit Tab", () => { expect(fitPlot.findAll("span").at(0)!.text()).toBe("Iterations: 10"); expect(fitPlot.findAll("span").at(1)!.text()).toBe("Sum of squares: 2.1"); expect(fitPlot.find("#fit-cancelled-msg").exists()).toBe(false); + expect(wrapper.findComponent(ErrorInfo).props("error")).toBe(null); }); it("renders as expected when fit is running", () => { @@ -169,6 +175,14 @@ describe("Fit Tab", () => { expect(fitPlot.findAll("span").at(1)!.text()).toBe("Sum of squares: 2.1"); }); + it("renders model fit error as expected", () => { + const error = {error: "test error", detail: "test detail"}; + const wrapper = getWrapper({}, false, {}, 10, true, false, 2.1, jest.fn(), jest.fn(), error); + expect(wrapper.findComponent(ErrorInfo).props("error")).toStrictEqual(error); + expect(wrapper.findComponent(ActionRequiredMessage).props("message")) + .toBe("An error occurred during model fit."); + }); + it("dispatches fit action on click button", async () => { const mockFitModel = jest.fn(); const wrapper = getWrapper({}, false, false, null, null, false, null, mockFitModel); diff --git a/app/static/tests/unit/serialiser.test.ts b/app/static/tests/unit/serialiser.test.ts index 318603c40..31778b3b8 100644 --- a/app/static/tests/unit/serialiser.test.ts +++ b/app/static/tests/unit/serialiser.test.ts @@ -292,6 +292,7 @@ describe("serialise", () => { const modelFitState = { fitting: false, + error: { error: "fit run error", detail: "fit run detail" }, fitUpdateRequired: { modelChanged: false, dataChanged: false, @@ -482,6 +483,7 @@ describe("serialise", () => { }; const expectedModelFit = { + error: { error: "fit run error", detail: "fit run detail" }, fitUpdateRequired: { modelChanged: false, dataChanged: false, diff --git a/app/static/tests/unit/store/modelFit/actions.test.ts b/app/static/tests/unit/store/modelFit/actions.test.ts index cfc1c02a2..55c59beee 100644 --- a/app/static/tests/unit/store/modelFit/actions.test.ts +++ b/app/static/tests/unit/store/modelFit/actions.test.ts @@ -135,6 +135,40 @@ describe("ModelFit actions", () => { expect(mockWodinFit).not.toHaveBeenCalled(); }); + it("FitModel commits error thrown during wodinFit", () => { + const runner = { + wodinFit: jest.fn().mockImplementation(() => { throw {message: "TEST ERROR"}; }), + wodinFitValue: mockWodinFitValue + } as any; + const errorModelState = mockModelState({ + odin: mockOdin, + odinRunnerOde: runner + }); + + const errorRootState = {...rootState, model: errorModelState}; + + const getters = { fitRequirements: {} }; + const link = { time: "t", data: "v", model: "S" }; + const rootGetters = { + "fitData/link": link, + "fitData/dataEnd": 100 + }; + const commit = jest.fn(); + const dispatch = jest.fn(); + (actions[ModelFitAction.FitModel] as any)({ + commit, dispatch, state, rootState: errorRootState, rootGetters, getters + }); + + expect(commit).toHaveBeenCalledTimes(3); + expect(commit.mock.calls[0][0]).toBe(ModelFitMutation.SetFitting); + expect(commit.mock.calls[0][1]).toBe(true); + expect(commit.mock.calls[1][0]).toBe(ModelFitMutation.SetError); + expect(commit.mock.calls[1][1]).toStrictEqual({error: "Model fit error", detail: "TEST ERROR"}); + expect(commit.mock.calls[2][0]).toBe(ModelFitMutation.SetFitting); + expect(commit.mock.calls[2][1]).toBe(false); + + }); + it("FitModelStep commits expected changes and dispatches further step if not converged", (done) => { const result = { converged: false, diff --git a/app/static/tests/unit/store/modelFit/mutations.test.ts b/app/static/tests/unit/store/modelFit/mutations.test.ts index ea6e0b5f2..2f5c90d2b 100644 --- a/app/static/tests/unit/store/modelFit/mutations.test.ts +++ b/app/static/tests/unit/store/modelFit/mutations.test.ts @@ -18,6 +18,22 @@ describe("ModelFit mutations", () => { expect(state.fitting).toBe(true); }); + it("SetFitting sets error to null if fitting is true", () => { + const error = {error: "test", detail: "test detail"}; + const state = mockModelFitState({ error }); + mutations.SetFitting(state, false); + expect(state.error).toBe(error); + mutations.SetFitting(state, true); + expect(state.error).toBe(null); + }); + + it("sets error", () => { + const error = {error: "test", detail: "test detail"}; + const state = mockModelFitState(); + mutations.SetError(state, error); + expect(state.error).toBe(error); + }); + it("sets model fit inputs", () => { const state = mockModelFitState(); mutations.SetInputs(state, mockInputs); From aa503a024a3716cebe43febb1b5f3f12bebdda28 Mon Sep 17 00:00:00 2001 From: EmmaLRussell Date: Mon, 6 Nov 2023 09:45:02 +0000 Subject: [PATCH 3/4] lint --- app/static/src/app/components/fit/FitTab.vue | 4 ++-- app/static/src/app/store/modelFit/actions.ts | 2 +- app/static/src/app/store/modelFit/mutations.ts | 4 ++-- app/static/src/app/store/modelFit/state.ts | 2 +- app/static/tests/e2e/fit.etest.ts | 7 ++++--- app/static/tests/unit/components/fit/fitTab.test.ts | 7 +++---- app/static/tests/unit/store/modelFit/actions.test.ts | 7 +++---- app/static/tests/unit/store/modelFit/mutations.test.ts | 4 ++-- 8 files changed, 18 insertions(+), 19 deletions(-) diff --git a/app/static/src/app/components/fit/FitTab.vue b/app/static/src/app/components/fit/FitTab.vue index 375281416..289763544 100644 --- a/app/static/src/app/components/fit/FitTab.vue +++ b/app/static/src/app/components/fit/FitTab.vue @@ -45,7 +45,7 @@ import ErrorInfo from "../ErrorInfo.vue"; export default defineComponent({ name: "FitTab", components: { - ErrorInfo, + ErrorInfo, LoadingSpinner, FitPlot, ActionRequiredMessage, @@ -73,7 +73,7 @@ export default defineComponent({ const actionRequiredMessage = computed(() => { if (error.value) { - return userMessages.modelFit.errorOccurred; + return userMessages.modelFit.errorOccurred; } if (!allTrue(fitRequirements.value)) { diff --git a/app/static/src/app/store/modelFit/actions.ts b/app/static/src/app/store/modelFit/actions.ts index 6dd584308..16822b78a 100644 --- a/app/static/src/app/store/modelFit/actions.ts +++ b/app/static/src/app/store/modelFit/actions.ts @@ -69,7 +69,7 @@ export const actions: ActionTree = { commit(ModelFitMutation.SetInputs, inputs); dispatch(ModelFitAction.FitModelStep, simplex); } catch (e: unknown) { - commit(ModelFitMutation.SetError, {error: "Model fit error", detail: (e as Error).message}); + commit(ModelFitMutation.SetError, { error: "Model fit error", detail: (e as Error).message }); commit(ModelFitMutation.SetFitting, false); } } diff --git a/app/static/src/app/store/modelFit/mutations.ts b/app/static/src/app/store/modelFit/mutations.ts index d8ed59750..cde61b45c 100644 --- a/app/static/src/app/store/modelFit/mutations.ts +++ b/app/static/src/app/store/modelFit/mutations.ts @@ -1,6 +1,6 @@ import { MutationTree } from "vuex"; import { ModelFitInputs, ModelFitState, FitUpdateRequiredReasons } from "./state"; -import {SimplexResult, WodinError} from "../../types/responseTypes"; +import { SimplexResult, WodinError } from "../../types/responseTypes"; export enum ModelFitMutation { SetFitting = "SetFitting", @@ -16,7 +16,7 @@ export const mutations: MutationTree = { [ModelFitMutation.SetFitting](state: ModelFitState, payload: boolean) { state.fitting = payload; if (payload) { - state.error = null + state.error = null; } }, diff --git a/app/static/src/app/store/modelFit/state.ts b/app/static/src/app/store/modelFit/state.ts index 33ebe3fec..cb264a2f6 100644 --- a/app/static/src/app/store/modelFit/state.ts +++ b/app/static/src/app/store/modelFit/state.ts @@ -1,6 +1,6 @@ import { OdinFitResult } from "../../types/wrapperTypes"; import type { FitData, FitDataLink } from "../fitData/state"; -import {WodinError} from "../../types/responseTypes"; +import { WodinError } from "../../types/responseTypes"; export interface ModelFitInputs { data: FitData; diff --git a/app/static/tests/e2e/fit.etest.ts b/app/static/tests/e2e/fit.etest.ts index 43b22eba6..589347400 100644 --- a/app/static/tests/e2e/fit.etest.ts +++ b/app/static/tests/e2e/fit.etest.ts @@ -163,7 +163,7 @@ test.describe("Wodin App model fit tests", () => { expect(newSumOfSquares).not.toEqual(sumOfSquares); }); - test("can show model fit error", async ({page}) => { + test("can show model fit error", async ({ page }) => { // Upload data await uploadCSVData(page, realisticFitData); await page.click(":nth-match(.wodin-right .nav-tabs a, 2)"); @@ -179,7 +179,7 @@ test.describe("Wodin App model fit tests", () => { // select param to vary await page.click(":nth-match(.wodin-right .nav-tabs a, 2)"); await expect(await page.innerText("#select-param-msg")) - .toBe("Please select at least one parameter to vary during model fit.") + .toBe("Please select at least one parameter to vary during model fit."); await page.click(":nth-match(input.vary-param-check, 1)"); await page.click(":nth-match(input.vary-param-check, 2)"); @@ -194,7 +194,8 @@ test.describe("Wodin App model fit tests", () => { await page.click(".wodin-right .wodin-content div.mt-4 button#fit-btn"); console.log("15"); - await expect(await page.locator(".fit-tab .action-required-msg")).toHaveText("An error occurred during model fit.", {timeout}); + await expect(await page.locator(".fit-tab .action-required-msg")) + .toHaveText("An error occurred during model fit.", { timeout }); await expect(await page.innerText(".fit-tab #error-info")).toContain("Model fit error: Integration failure"); }); diff --git a/app/static/tests/unit/components/fit/fitTab.test.ts b/app/static/tests/unit/components/fit/fitTab.test.ts index 65c538a0f..3408250fe 100644 --- a/app/static/tests/unit/components/fit/fitTab.test.ts +++ b/app/static/tests/unit/components/fit/fitTab.test.ts @@ -1,6 +1,4 @@ // Mock plotly before import RunTab, which indirectly imports plotly via FitPlot -import ErrorInfo from "../../../../src/app/components/ErrorInfo.vue"; - jest.mock("plotly.js-basic-dist-min", () => {}); /* eslint-disable import/first */ @@ -13,7 +11,8 @@ import ActionRequiredMessage from "../../../../src/app/components/ActionRequired import LoadingSpinner from "../../../../src/app/components/LoadingSpinner.vue"; import FitPlot from "../../../../src/app/components/fit/FitPlot.vue"; import { mockFitState, mockGraphSettingsState } from "../../../mocks"; -import {WodinError} from "../../../../src/app/types/responseTypes"; +import { WodinError } from "../../../../src/app/types/responseTypes"; +import ErrorInfo from "../../../../src/app/components/ErrorInfo.vue"; describe("Fit Tab", () => { const getWrapper = ( @@ -176,7 +175,7 @@ describe("Fit Tab", () => { }); it("renders model fit error as expected", () => { - const error = {error: "test error", detail: "test detail"}; + const error = { error: "test error", detail: "test detail" }; const wrapper = getWrapper({}, false, {}, 10, true, false, 2.1, jest.fn(), jest.fn(), error); expect(wrapper.findComponent(ErrorInfo).props("error")).toStrictEqual(error); expect(wrapper.findComponent(ActionRequiredMessage).props("message")) diff --git a/app/static/tests/unit/store/modelFit/actions.test.ts b/app/static/tests/unit/store/modelFit/actions.test.ts index 55c59beee..72dffa13c 100644 --- a/app/static/tests/unit/store/modelFit/actions.test.ts +++ b/app/static/tests/unit/store/modelFit/actions.test.ts @@ -137,7 +137,7 @@ describe("ModelFit actions", () => { it("FitModel commits error thrown during wodinFit", () => { const runner = { - wodinFit: jest.fn().mockImplementation(() => { throw {message: "TEST ERROR"}; }), + wodinFit: jest.fn().mockImplementation(() => { throw new Error("TEST ERROR"); }), wodinFitValue: mockWodinFitValue } as any; const errorModelState = mockModelState({ @@ -145,7 +145,7 @@ describe("ModelFit actions", () => { odinRunnerOde: runner }); - const errorRootState = {...rootState, model: errorModelState}; + const errorRootState = { ...rootState, model: errorModelState }; const getters = { fitRequirements: {} }; const link = { time: "t", data: "v", model: "S" }; @@ -163,10 +163,9 @@ describe("ModelFit actions", () => { expect(commit.mock.calls[0][0]).toBe(ModelFitMutation.SetFitting); expect(commit.mock.calls[0][1]).toBe(true); expect(commit.mock.calls[1][0]).toBe(ModelFitMutation.SetError); - expect(commit.mock.calls[1][1]).toStrictEqual({error: "Model fit error", detail: "TEST ERROR"}); + expect(commit.mock.calls[1][1]).toStrictEqual({ error: "Model fit error", detail: "TEST ERROR" }); expect(commit.mock.calls[2][0]).toBe(ModelFitMutation.SetFitting); expect(commit.mock.calls[2][1]).toBe(false); - }); it("FitModelStep commits expected changes and dispatches further step if not converged", (done) => { diff --git a/app/static/tests/unit/store/modelFit/mutations.test.ts b/app/static/tests/unit/store/modelFit/mutations.test.ts index 2f5c90d2b..53fc89945 100644 --- a/app/static/tests/unit/store/modelFit/mutations.test.ts +++ b/app/static/tests/unit/store/modelFit/mutations.test.ts @@ -19,7 +19,7 @@ describe("ModelFit mutations", () => { }); it("SetFitting sets error to null if fitting is true", () => { - const error = {error: "test", detail: "test detail"}; + const error = { error: "test", detail: "test detail" }; const state = mockModelFitState({ error }); mutations.SetFitting(state, false); expect(state.error).toBe(error); @@ -28,7 +28,7 @@ describe("ModelFit mutations", () => { }); it("sets error", () => { - const error = {error: "test", detail: "test detail"}; + const error = { error: "test", detail: "test detail" }; const state = mockModelFitState(); mutations.SetError(state, error); expect(state.error).toBe(error); From 9c155c51c2836c179d1574c471aab4947b054b0d Mon Sep 17 00:00:00 2001 From: EmmaLRussell Date: Mon, 6 Nov 2023 10:06:19 +0000 Subject: [PATCH 4/4] take out debug --- app/static/tests/e2e/fit.etest.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/app/static/tests/e2e/fit.etest.ts b/app/static/tests/e2e/fit.etest.ts index 589347400..c6618064f 100644 --- a/app/static/tests/e2e/fit.etest.ts +++ b/app/static/tests/e2e/fit.etest.ts @@ -192,7 +192,6 @@ test.describe("Wodin App model fit tests", () => { await input2.fill("-1"); await page.click(".wodin-right .wodin-content div.mt-4 button#fit-btn"); - console.log("15"); await expect(await page.locator(".fit-tab .action-required-msg")) .toHaveText("An error occurred during model fit.", { timeout });