From 9e25a9484687638cc7fdd1622e0db496023fcf5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Mon, 13 Feb 2023 17:07:37 +0100 Subject: [PATCH 1/9] test(e2e): check solver empty fields in various cases refs #601 --- e2e/calculator.po.ts | 10 +- e2e/preferences.po.ts | 17 ++++ e2e/solveur.e2e-spec.ts | 200 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 219 insertions(+), 8 deletions(-) diff --git a/e2e/calculator.po.ts b/e2e/calculator.po.ts index af1e1803c..45b3aa06a 100644 --- a/e2e/calculator.po.ts +++ b/e2e/calculator.po.ts @@ -421,11 +421,17 @@ export class CalculatorPage { /** * check that an input is empty * @param id input id (parameter name) + * @param empty true to check input is empty, false to check it is NOT empty */ - async checkEmptyInput(id: string) { + async checkEmptyInput(id: string, empty: boolean = true) { const inp = this.getInputById(id); const val = await inp.getAttribute("value"); - expect(val).toEqual(""); + if (empty) { + expect(val).toEqual(""); + } + else { + expect(val).not.toEqual(""); + } } /** diff --git a/e2e/preferences.po.ts b/e2e/preferences.po.ts index 264ebb84f..678f07954 100644 --- a/e2e/preferences.po.ts +++ b/e2e/preferences.po.ts @@ -65,6 +65,23 @@ export class PreferencesPage { } } + /** + * enable/disable option "empty fields on module creation" + * @param b true to enable "empty fields on module creation" option, false to disable it (fill fields with default values) + */ + async setEmptyFields(b: boolean) { + await this.navigateTo(); + await browser.sleep(200); + + if (b) { + await this.enableEvilEmptyFields(); + } + else { + await this.disableEvilEmptyFields(); + } + await browser.sleep(200); + } + async setIterationCount(n: number) { const input = this.getInputFromName("nmi"); input.clear(); diff --git a/e2e/solveur.e2e-spec.ts b/e2e/solveur.e2e-spec.ts index 89ca70d6e..281aeec5a 100644 --- a/e2e/solveur.e2e-spec.ts +++ b/e2e/solveur.e2e-spec.ts @@ -11,7 +11,6 @@ import { scrollPageToTop } from "./util.po"; * Clone calculators */ describe("Solveur - ", () => { - let startPage: AppPage; let listPage: ListPage; let calcPage: CalculatorPage; let navbar: Navbar; @@ -19,7 +18,6 @@ describe("Solveur - ", () => { let prefPage: PreferencesPage; beforeAll(async () => { - startPage = new AppPage(); prefPage = new PreferencesPage(); listPage = new ListPage(); calcPage = new CalculatorPage(); @@ -28,10 +26,8 @@ describe("Solveur - ", () => { }); beforeEach(async () => { - await prefPage.navigateTo(); // disable evil option "empty fields on module creation" - await prefPage.disableEvilEmptyFields(); - await browser.sleep(200); + await prefPage.setEmptyFields(false); // force language to prevent issues due to default browser language await prefPage.changeLanguage(1); // fr await browser.sleep(200); @@ -171,7 +167,7 @@ describe("Solveur - ", () => { // check "search parameter" value has not changed expect(await calcPage.getSelectValueText(sel)).toEqual(selText); }); - + it("check solver searched parameter is set to 'bottom slope'", async () => { // open "canal critical slope" example const examples = await element.all(by.css("#examples-list .load-example")); @@ -188,3 +184,195 @@ describe("Solveur - ", () => { expect(selText).toEqual("If - Pente du fond (Sec. param.)"); }); }); + +/** + * solver with empty fields option + */ +describe("Solveur - nghyd#601 with empty fields option", () => { + let prefPage: PreferencesPage; + let navBar: Navbar; + let listPage: ListPage; + let calcPage: CalculatorPage; + + beforeAll(async () => { + prefPage = new PreferencesPage(); + navBar = new Navbar(); + listPage = new ListPage(); + calcPage = new CalculatorPage(); + }); + + async function openCalculator(id: number) { + await navBar.clickNewCalculatorButton(); + await browser.sleep(200); + + await listPage.clickMenuEntryForCalcType(id); + await browser.sleep(200); + } + + async function openSolver() { + await openCalculator(22); + } + + beforeEach(async () => { + // enable evil option "empty fields on module creation" + await prefPage.setEmptyFields(true); + }); + + it("check solver with empty fields option does not fill inputs - solver alone", async () => { + // open new solver calculator + await openSolver(); + + // check inputs are empty + await calcPage.checkEmptyInput("Ytarget"); + await browser.sleep(200); + + await calcPage.checkEmptyInput("Xinit"); + await browser.sleep(200); + }); + + it("check solver with empty fields option does not fill target parameter input", async () => { + // open "parallel structures" calculator + await openCalculator(8); + + // open second "parallel structures" calculator + await openCalculator(8); + + // link Q to first calculator's + const inpQ = calcPage.getInputById("Q"); + await calcPage.setParamMode(inpQ, "link"); + await browser.sleep(200); + + // open new solver calculator + await openSolver(); + + // check target parameter input is empty + await calcPage.checkEmptyInput("Ytarget"); + await browser.sleep(200); + + // check initial value input is not empty + await calcPage.checkEmptyInput("Xinit"); + await browser.sleep(200); + }); + + it("check removing and recreating solver with empty fields option does not fill target parameter input", async () => { + await navBar.clickNewCalculatorButton(); + await browser.sleep(200); + + // open "channel flow with hydraulic structures" example + const examples = await element.all(by.css("#examples-list .load-example")); + await examples[1].click(); + await browser.sleep(500); + + // close existing "solver" calculator + await navBar.middleClickCalculatorTab(3); + await browser.sleep(500); + + // open new solver calculator + await openSolver(); + + // check target parameter input is empty + await calcPage.checkEmptyInput("Ytarget"); + await browser.sleep(200); + + // check initial value input is not empty + await calcPage.checkEmptyInput("Xinit", false); + await browser.sleep(200); + }); +}); + +/** + * solver without empty fields option + */ +describe("Solveur - nghyd#601 without empty fields option", () => { + let prefPage: PreferencesPage; + let navBar: Navbar; + let listPage: ListPage; + let calcPage: CalculatorPage; + + beforeAll(async () => { + prefPage = new PreferencesPage(); + navBar = new Navbar(); + listPage = new ListPage(); + calcPage = new CalculatorPage(); + }); + + async function openCalculator(id: number) { + await navBar.clickNewCalculatorButton(); + await browser.sleep(200); + + await listPage.clickMenuEntryForCalcType(id); + await browser.sleep(200); + } + + async function openSolver() { + await openCalculator(22); + } + + beforeEach(async () => { + await browser.manage().window().setPosition(2000, 30); + + // disable evil option "empty fields on module creation" + await prefPage.setEmptyFields(false); + }); + + it("check solver without empty fields option does not fill inputs - solver alone", async () => { + // open new solver calculator + await openSolver(); + + // check inputs are empty + await calcPage.checkEmptyInput("Ytarget"); + await browser.sleep(200); + + await calcPage.checkEmptyInput("Xinit"); + await browser.sleep(200); + }); + + it("check solver without empty fields option fills inputs", async () => { + // open "parallel structures" calculator + await openCalculator(8); + + // open second "parallel structures" calculator + await openCalculator(8); + + // link Q to first calculator's + const inpQ = calcPage.getInputById("Q"); + await calcPage.setParamMode(inpQ, "link"); + await browser.sleep(200); + + // open new solver calculator + await openSolver(); + + // check target parameter input is not empty + await calcPage.checkEmptyInput("Ytarget", false); + await browser.sleep(200); + + // check initial value input is not empty + await calcPage.checkEmptyInput("Xinit", false); + await browser.sleep(200); + }); + + it("check removing and recreating solver without empty fields option fills inputs", async () => { + await navBar.clickNewCalculatorButton(); + await browser.sleep(200); + + // open "channel flow with hydraulic structures" example + const examples = await element.all(by.css("#examples-list .load-example")); + await examples[1].click(); + await browser.sleep(500); + + // close existing "solver" calculator + await navBar.middleClickCalculatorTab(3); + await browser.sleep(500); + + // open new solver calculator + await openSolver(); + + // check target parameter input is not empty + await calcPage.checkEmptyInput("Ytarget", false); + await browser.sleep(200); + + // check initial value input is not empty + await calcPage.checkEmptyInput("Xinit", false); + await browser.sleep(200); + }); +}); -- GitLab From 884d8d3c9a816f7eadab445c13621ef82053ffc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Tue, 14 Feb 2023 10:11:46 +0100 Subject: [PATCH 2/9] refactor: unused code in FormulaireSolveur.update() refs #601 --- src/app/formulaire/definition/form-solveur.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/app/formulaire/definition/form-solveur.ts b/src/app/formulaire/definition/form-solveur.ts index 0a3d446ef..0e3e8db93 100644 --- a/src/app/formulaire/definition/form-solveur.ts +++ b/src/app/formulaire/definition/form-solveur.ts @@ -47,11 +47,10 @@ export class FormulaireSolveur extends FormulaireFixedVar { } } // copied from FormFixedVar, to avoid calling super.update() - if (data.action === "propertyChange") { + else if (data.action === "propertyChange") { this.reset(); } - - if (sender instanceof SelectField) { + else if (sender instanceof SelectField) { if (sender.id === "select_target_nub" && data.action === "select") { // update Solveur property: Nub to calculate try { @@ -81,9 +80,7 @@ export class FormulaireSolveur extends FormulaireFixedVar { // reflect changes in GUI const inputXinit = this.getFormulaireNodeById("Xinit") as NgParameter; inputXinit.notifyValueModified(this); - } - } else if (sender instanceof SelectField) { - if (sender.id === this._targettedResultSelectId) { + } else if (sender.id === this._targettedResultSelectId) { // refresh parameters selector this.refreshParameterEntries(); } -- GitLab From fa7fd1b614e3f429f4c13abebb06cfd22727d1f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Tue, 14 Feb 2023 12:45:40 +0100 Subject: [PATCH 3/9] feat: solver: set Ytarget to undefined if "empty fields" option is set refs #601 --- .../calculator.component.ts | 1 + .../formulaire/definition/form-definition.ts | 13 +++++++++++++ src/app/formulaire/definition/form-solveur.ts | 19 ++++++++++++++++++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/app/components/generic-calculator/calculator.component.ts b/src/app/components/generic-calculator/calculator.component.ts index 49e81d946..48997ffc9 100644 --- a/src/app/components/generic-calculator/calculator.component.ts +++ b/src/app/components/generic-calculator/calculator.component.ts @@ -412,6 +412,7 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe */ protected afterFirstViewChecked() { this.updateUIValidity(); + this.formulaire.setFirstDisplayCompleted(); } public onCloseForm() { diff --git a/src/app/formulaire/definition/form-definition.ts b/src/app/formulaire/definition/form-definition.ts index 9acb17e78..740e50d8f 100644 --- a/src/app/formulaire/definition/form-definition.ts +++ b/src/app/formulaire/definition/form-definition.ts @@ -62,6 +62,11 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs */ protected _calcResults: CalculatorResults[]; + /** + * Flag indiquant que le composant calculette est proche de la fin du 1er affichage (1er appel à AfterViewChecked) + */ + private _firstDisplay: boolean = true; + constructor(parent?: FormulaireNode) { super(parent); SessionSettings.instance.addObserver(this); @@ -81,6 +86,14 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs return this._calculateDisabled; } + public get isFirstDisplay(): boolean { + return this._firstDisplay; + } + + public setFirstDisplayCompleted() { + this._firstDisplay = false; + } + public getPropValue(key: string): any { if (this._currentNub === undefined) return this.defaultProperties[key]; diff --git a/src/app/formulaire/definition/form-solveur.ts b/src/app/formulaire/definition/form-solveur.ts index 0e3e8db93..cf2807a7f 100644 --- a/src/app/formulaire/definition/form-solveur.ts +++ b/src/app/formulaire/definition/form-solveur.ts @@ -1,9 +1,10 @@ -import { IObservable, ParamDefinition, Nub } from "jalhyd"; +import { IObservable, ParamDefinition, Nub, Props, Solveur } from "jalhyd"; import { NgParameter } from "../elements/ngparam"; import { FormulaireFixedVar } from "./form-fixedvar"; import { SelectField } from "../elements/select/select-field"; import { FieldSet } from "../elements/fieldset"; +import { ServiceFactory } from "app/services/service-factory"; /** * Formulaire pour les Solveurs @@ -34,6 +35,16 @@ export class FormulaireSolveur extends FormulaireFixedVar { } } + public initNub(props?: Props) { + super.initNub(props); + + // subscribe to Ytarget to be able to reset it during form construction (with empty fields option set) + // cf. nghyd#601 + + const n: Solveur = this._currentNub as Solveur; + n.prms.Ytarget.addObserver(this); + } + // interface Observer public update(sender: IObservable, data: any) { @@ -84,6 +95,12 @@ export class FormulaireSolveur extends FormulaireFixedVar { // refresh parameters selector this.refreshParameterEntries(); } + } else if (sender instanceof ParamDefinition) { + if (data.action === "paramdefinitionAfterValue" && sender.symbol === "Ytarget") { + if (this.isFirstDisplay && ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit) { + sender.setValue(undefined); + } + } } } -- GitLab From e143ed562c61bd18ed7b781ebbbd2ef3fd7bca30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Tue, 28 Feb 2023 12:48:42 +0100 Subject: [PATCH 4/9] test(e2e): check that input empty in empty fields mode when modifying the target module refs #601 --- e2e/solveur.e2e-spec.ts | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/e2e/solveur.e2e-spec.ts b/e2e/solveur.e2e-spec.ts index 281aeec5a..9c7160e07 100644 --- a/e2e/solveur.e2e-spec.ts +++ b/e2e/solveur.e2e-spec.ts @@ -375,4 +375,34 @@ describe("Solveur - nghyd#601 without empty fields option", () => { await calcPage.checkEmptyInput("Xinit", false); await browser.sleep(200); }); + + it(" with empty fields option, check selecting a target module does not fill inputs", async () => { + // disable evil option "empty fields on module creation" + await prefPage.setEmptyFields(false); + await browser.sleep(200); + + await navBar.clickNewCalculatorButton(); + await browser.sleep(200); + + // open "channel flow with hydraulic structures" example + const examples = await element.all(by.css("#examples-list .load-example")); + await examples[1].click(); + await browser.sleep(500); + + // close existing "solver" calculator + await navBar.middleClickCalculatorTab(3); + await browser.sleep(500); + + // open new solver calculator + await openSolver(); + await browser.sleep(500); + + // select other target module + const ntc = calcPage.getSelectById("select_target_nub"); + await calcPage.changeSelectValue(ntc, 1); + + // check target value input is empty + await calcPage.checkEmptyInput("Ytarget", true); + await browser.sleep(200); + }); }); -- GitLab From 56759310114d05f9a4ed1c9ca03248bfd03480d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Wed, 1 Mar 2023 10:43:38 +0100 Subject: [PATCH 5/9] fix: FieldSet.updateFields(): update inputs with nub values in case clearing is not forced refs #601 --- src/app/formulaire/elements/fieldset.ts | 29 +++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/app/formulaire/elements/fieldset.ts b/src/app/formulaire/elements/fieldset.ts index 7b709eb76..73e6b8535 100644 --- a/src/app/formulaire/elements/fieldset.ts +++ b/src/app/formulaire/elements/fieldset.ts @@ -4,7 +4,8 @@ import { IProperties, Observer, Nub, - enumValueFromString + enumValueFromString, + ParamValueMode } from "jalhyd"; import { FormulaireElement } from "./formulaire-element"; @@ -215,8 +216,32 @@ export class FieldSet extends FormulaireElement implements IProperties { public updateFields(forceClear: boolean) { if (forceClear) { this.clearFields(); + this.parseFields(); } - this.parseFields(); + else { + const nub = this.parentForm.currentNub; + for (const e of this.parentForm.allFormElements) { + if (e instanceof NgParameter) { + const p: ParamDefinition = nub.getParameter(e.symbol); + switch (e.paramDefinition.valueMode) { + case ParamValueMode.SINGLE: + e.setValue(this, p.singleValue); + break; + + case ParamValueMode.MINMAX: + e.setMinValue(this, p.min); + e.setMaxValue(this, p.max); + e.setStepValue(this, p.step); + break; + + case ParamValueMode.LISTE: + e.setValueList(this, p.valueList); + break; + } + } + } + } + this.updateLocalisation(); // for all select fields known by the form, set selected value -- GitLab From 6b533b601ff6a56388b8c9e4c14bb8f250770d7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Wed, 1 Mar 2023 14:33:05 +0100 Subject: [PATCH 6/9] fix(e2e): solver: wrong 'empty field' option value refs #601 --- e2e/solveur.e2e-spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/e2e/solveur.e2e-spec.ts b/e2e/solveur.e2e-spec.ts index e6956e3a6..8c8383565 100644 --- a/e2e/solveur.e2e-spec.ts +++ b/e2e/solveur.e2e-spec.ts @@ -377,8 +377,8 @@ describe("Solveur - nghyd#601 without empty fields option", () => { }); it(" with empty fields option, check selecting a target module does not fill inputs", async () => { - // disable evil option "empty fields on module creation" - await prefPage.setEmptyFields(false); + // enable evil option "empty fields on module creation" + await prefPage.setEmptyFields(true); await browser.sleep(200); await navBar.clickNewCalculatorButton(); @@ -399,7 +399,7 @@ describe("Solveur - nghyd#601 without empty fields option", () => { // select other target module const ntc = calcPage.getSelectById("select_target_nub"); - await calcPage.changeSelectValue(ntc, 1); + await changeSelectValue(ntc, 1); // check target value input is empty await calcPage.checkEmptyInput("Ytarget", true); -- GitLab From 5b6ccdcb6a03b67bc193dbc380c5542b7fa0626a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Wed, 1 Mar 2023 14:33:51 +0100 Subject: [PATCH 7/9] update jalhyd_branch to 342-solveur-multimodule-le-module-existe-toujours-apres-suppression refs #601 --- jalhyd_branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jalhyd_branch b/jalhyd_branch index cf4a15c27..50cc6a0b1 100644 --- a/jalhyd_branch +++ b/jalhyd_branch @@ -1 +1 @@ -215-conduites-en-charge-ajouter-loi-de-strickler-exercice-dans-livre-de-bennis +342-solveur-multimodule-le-module-existe-toujours-apres-suppression -- GitLab From a9822a466b8097e41bb4fec422d70c98946ce831 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Wed, 1 Mar 2023 14:34:13 +0100 Subject: [PATCH 8/9] fix: solver form: in empty fields mode, selecting a different target module does not leave unchanged the target Y field refs #601 --- src/app/formulaire/definition/form-solveur.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/app/formulaire/definition/form-solveur.ts b/src/app/formulaire/definition/form-solveur.ts index 1bc0f0b82..4052054a6 100644 --- a/src/app/formulaire/definition/form-solveur.ts +++ b/src/app/formulaire/definition/form-solveur.ts @@ -1,4 +1,4 @@ -import { IObservable, ParamDefinition, Nub, Props, Solveur } from "jalhyd"; +import { IObservable, ParamDefinition, Nub, Props, Solveur, SolveurParams } from "jalhyd"; import { NgParameter } from "../elements/ngparam"; import { FormulaireFixedVar } from "./form-fixedvar"; @@ -60,6 +60,16 @@ export class FormulaireSolveur extends FormulaireFixedVar { // copied from FormFixedVar, to avoid calling super.update() else if (data.action === "propertyChange") { this.reset(); + if (data.name === "nubToCalculate") { + const n = (this.currentNub as Solveur).nubToCalculate; + if (n !== undefined) { + const prms: SolveurParams = this.currentNub.prms as SolveurParams; + // update Ytarget + if (prms.Ytarget.singleValue === undefined && !ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit) { + prms.Ytarget.singleValue = n.calculatedParam.singleValue; + } + } + } } else if (sender instanceof SelectField) { if (sender.id === "select_target_nub" && data.action === "select") { -- GitLab From 6f84eb64a5bd35dab76100ef4b52c41d971d77f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Fri, 3 Mar 2023 15:50:54 +0100 Subject: [PATCH 9/9] refactor: solver form: remove useless update() code refs #601 --- src/app/formulaire/definition/form-solveur.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/app/formulaire/definition/form-solveur.ts b/src/app/formulaire/definition/form-solveur.ts index 4052054a6..08318dd8c 100644 --- a/src/app/formulaire/definition/form-solveur.ts +++ b/src/app/formulaire/definition/form-solveur.ts @@ -105,12 +105,6 @@ export class FormulaireSolveur extends FormulaireFixedVar { // refresh parameters selector this.refreshParameterEntries(); } - } else if (sender instanceof ParamDefinition) { - if (data.action === "paramdefinitionAfterValue" && sender.symbol === "Ytarget") { - if (this.isFirstDisplay && ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit) { - sender.setValue(undefined); - } - } } } -- GitLab