From 287fe5802e435bc9c92154fe6f6f8adb664ee0a7 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Mon, 18 Feb 2019 16:15:53 +0100
Subject: [PATCH 01/21] =?UTF-8?q?Liste=20des=20modules=20de=20calcul:=20le?=
 =?UTF-8?q?s=20boutons=20de=20cr=C3=A9ation=20portent=20l'ID=20du=20type?=
 =?UTF-8?q?=20de=20module?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../calculator-list/calculator-list.component.html          | 2 +-
 .../components/calculator-list/calculator-list.component.ts | 6 ++++--
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/src/app/components/calculator-list/calculator-list.component.html b/src/app/components/calculator-list/calculator-list.component.html
index 925ebed11..25c88f025 100644
--- a/src/app/components/calculator-list/calculator-list.component.html
+++ b/src/app/components/calculator-list/calculator-list.component.html
@@ -24,7 +24,7 @@
         <mat-card-actions>
             <div class="container" fxLayout="column" fxLayoutAlign="left" fxLayoutGap="10px">
                 <button mat-raised-button color="accent" *ngFor="let calc of theme.calculators" class="theme-calculator"
-                    (click)="create(calc.type)" [innerHTML]="calc.label"></button>
+                    (click)="create(calc.type)" [innerHTML]="calc.label" [id]="calc.buttonId"></button>
             </div>
         </mat-card-actions>
     
diff --git a/src/app/components/calculator-list/calculator-list.component.ts b/src/app/components/calculator-list/calculator-list.component.ts
index aef92e3e1..4a084aa81 100644
--- a/src/app/components/calculator-list/calculator-list.component.ts
+++ b/src/app/components/calculator-list/calculator-list.component.ts
@@ -50,7 +50,8 @@ export class CalculatorListComponent implements OnInit {
                     for (const calcType of theme.calculators) {
                         item.calculators.push({
                             type: calcType,
-                            label: ServiceFactory.instance.formulaireService.getLocalisedTitleFromCalculatorType(calcType)
+                            label: ServiceFactory.instance.formulaireService.getLocalisedTitleFromCalculatorType(calcType),
+                            buttonId: "create-calc-" + calcType
                         });
                         // mark as used
                         const index = unusedCalculators.indexOf(calcType);
@@ -77,7 +78,8 @@ export class CalculatorListComponent implements OnInit {
                     if (t !== CalculatorType.Structure) {
                         unusedTheme.calculators.push({
                             type: t,
-                            label: ServiceFactory.instance.formulaireService.getLocalisedTitleFromCalculatorType(t)
+                            label: ServiceFactory.instance.formulaireService.getLocalisedTitleFromCalculatorType(t),
+                            buttonId: "create-calc-" + t
                         });
                     }
                 }
-- 
GitLab


From 6199a10803ddfa78a81845c8ce0573f2b750368d Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Mon, 18 Feb 2019 16:36:33 +0100
Subject: [PATCH 02/21] Les input et select ont des IDs explicites

---
 .../base-param-input.component.ts             | 13 ++++++++-----
 .../calc-name.component.html                  |  2 +-
 .../generic-calculator/calc-name.component.ts |  2 +-
 .../generic-input/generic-input.component.ts  | 19 ++++++++++++++-----
 .../generic-select.component.html             |  2 +-
 .../results-graph/graph-type.component.ts     |  4 ++++
 .../select-field-line.component.ts            |  5 ++++-
 7 files changed, 33 insertions(+), 14 deletions(-)

diff --git a/src/app/components/base-param-input/base-param-input.component.ts b/src/app/components/base-param-input/base-param-input.component.ts
index f89955f56..e04b0a460 100644
--- a/src/app/components/base-param-input/base-param-input.component.ts
+++ b/src/app/components/base-param-input/base-param-input.component.ts
@@ -2,11 +2,12 @@
 
 import { Component, ChangeDetectorRef } from "@angular/core";
 
-import { Message, ParamDefinition, ParamDomain, ParamDomainValue, Observable, isNumeric } from "jalhyd";
+import { Message, ParamDefinition, ParamDomain, ParamDomainValue, Observable } from "jalhyd";
 
 import { I18nService } from "../../services/internationalisation/internationalisation.service";
 import { GenericInputComponent } from "../generic-input/generic-input.component";
 import { ServiceFactory } from "../../services/service-factory";
+import { NgParameter } from "../../formulaire/ngparam";
 
 export class NgBaseParam extends Observable {
     private _param: ParamDefinition;
@@ -98,8 +99,8 @@ export class BaseParamInputComponent extends GenericInputComponent {
     /**
      * paramètre géré
      */
-    private get _paramDef(): NgBaseParam {
-        return this._model;
+    private get _paramDef(): NgParameter {
+        return this._model as NgParameter;
     }
 
     /**
@@ -119,13 +120,15 @@ export class BaseParamInputComponent extends GenericInputComponent {
     protected setModelValue(sender: any, v: any) {
         this._tmp = v;
         try {
-            this._paramDef.setValue(v);
+            this._paramDef.setValue(null, v);
         } catch (e) {
             // géré par validateModelValue()
         }
     }
 
     protected validateModelValue(v: any): { isValid: boolean, message: string } {
-        return this._model.validateModelValue(v);
+        if (this._model instanceof NgBaseParam) {
+            return this._model.validateModelValue(v);
+        }
     }
 }
diff --git a/src/app/components/generic-calculator/calc-name.component.html b/src/app/components/generic-calculator/calc-name.component.html
index 3866997a9..85c1f9c06 100644
--- a/src/app/components/generic-calculator/calc-name.component.html
+++ b/src/app/components/generic-calculator/calc-name.component.html
@@ -1,5 +1,5 @@
 <mat-form-field>
     <input matInput #inputControl="ngModel" class="form-control" type="text"
-        [id]="inputId" [(ngModel)]="uiValue" [placeholder]="title" required>
+        id="calc-name-input" [(ngModel)]="uiValue" [placeholder]="title" required>
     <mat-error>{{ errorMessage }}</mat-error>
 </mat-form-field>
diff --git a/src/app/components/generic-calculator/calc-name.component.ts b/src/app/components/generic-calculator/calc-name.component.ts
index 70c236305..208d11e97 100644
--- a/src/app/components/generic-calculator/calc-name.component.ts
+++ b/src/app/components/generic-calculator/calc-name.component.ts
@@ -19,7 +19,7 @@ export class CalculatorNameComponent extends GenericInputComponent {
      * formulaire géré
      */
     private get _form(): FormulaireDefinition {
-        return this._model;
+        return this._model as FormulaireDefinition;
     }
 
     /**
diff --git a/src/app/components/generic-input/generic-input.component.ts b/src/app/components/generic-input/generic-input.component.ts
index a7cd9064c..4b34c8113 100644
--- a/src/app/components/generic-input/generic-input.component.ts
+++ b/src/app/components/generic-input/generic-input.component.ts
@@ -2,6 +2,8 @@ import { Input, Output, EventEmitter, ChangeDetectorRef, OnChanges, ViewChild }
 import { NgModel } from "@angular/forms";
 import { BaseComponent } from "../base/base.component";
 import { isNumeric } from "jalhyd";
+import { FormulaireDefinition } from "../../formulaire/definition/form-definition";
+import { NgParameter } from "../../formulaire/ngparam";
 
 /**
  * classe de gestion générique d'un champ de saisie avec titre, validation et message d'erreur
@@ -17,7 +19,7 @@ export abstract class GenericInputComponent extends BaseComponent implements OnC
     /**
      * entité mémoire gérée
      */
-    protected _model: any; // NgBaseParam mais aussi FormDefinition parfois (!?)
+    protected _model: NgParameter | FormulaireDefinition; // CalcName utilise un FormDefinition ici !?
 
     /**
      * flag de désactivation de l'input
@@ -31,9 +33,18 @@ export abstract class GenericInputComponent extends BaseComponent implements OnC
     public showError = true;
 
     /**
-     * id de l'input, pour accorder <label> et <input> sans ambiguïté
+     * id de l'input, utilisé notamment pour les tests
      */
-    public inputId = "input1";
+    public get inputId() {
+        let id = "input-1";
+        if (this._model) {
+            // unique input id based on parameter symbol
+            if (this._model instanceof NgParameter) {
+                id = (this._model as NgParameter).symbol;
+            }
+        }
+        return id;
+    }
 
     /**
      * chaîne affichée dans l'input quand aucune valeur n'est saisie
@@ -79,8 +90,6 @@ export abstract class GenericInputComponent extends BaseComponent implements OnC
 
     constructor(private cdRef: ChangeDetectorRef) {
         super();
-        // generate "unique" input id
-        this.inputId = "form-" + btoa(String(Math.random())).substring(2, 10);
     }
 
     public get isDisabled(): boolean {
diff --git a/src/app/components/generic-select/generic-select.component.html b/src/app/components/generic-select/generic-select.component.html
index da7a82515..005ac9427 100644
--- a/src/app/components/generic-select/generic-select.component.html
+++ b/src/app/components/generic-select/generic-select.component.html
@@ -1,5 +1,5 @@
 <mat-form-field>
-    <mat-select [placeholder]="label" [(value)]="selectedValue">
+    <mat-select [id]="selectId" [placeholder]="label" [(value)]="selectedValue">
         <mat-option *ngFor="let e of entries" [value]="e">
             {{ entryLabel(e) }}
         </mat-option>
diff --git a/src/app/components/results-graph/graph-type.component.ts b/src/app/components/results-graph/graph-type.component.ts
index c96f6c532..3ed06955a 100644
--- a/src/app/components/results-graph/graph-type.component.ts
+++ b/src/app/components/results-graph/graph-type.component.ts
@@ -17,6 +17,10 @@ export class GraphTypeSelectComponent implements IObservable {
 
     private _observable: Observable;
 
+    public get selectId() {
+        return "graph-type"; // for generic select component
+    }
+
     constructor(private intlService: I18nService) {
         this._observable = new Observable();
         this._entriesLabels = [
diff --git a/src/app/components/select-field-line/select-field-line.component.ts b/src/app/components/select-field-line/select-field-line.component.ts
index a7840110a..61c4cc62a 100644
--- a/src/app/components/select-field-line/select-field-line.component.ts
+++ b/src/app/components/select-field-line/select-field-line.component.ts
@@ -5,7 +5,6 @@ import { SelectEntry } from "../../formulaire/select-entry";
 
 @Component({
     selector: "select-field-line",
-    // templateUrl: "./select-field-line.component.html",
     templateUrl: "../generic-select/generic-select.component.html",
     styleUrls: [
         "./select-field-line.component.scss"
@@ -15,6 +14,10 @@ export class SelectFieldLineComponent {
     @Input()
     private _select: SelectField;
 
+    public get selectId() {
+        return this._select.id;
+    }
+
     public get entries(): SelectEntry[] {
         if (! this._select) {
             return [];
-- 
GitLab


From 9fe60143e580406748280114396746ac6e7f446a Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Mon, 18 Feb 2019 17:42:19 +0100
Subject: [PATCH 03/21] Ajout test e2e pour #129

---
 e2e/calculator.po.ts                          |  26 +-
 e2e/list.po.ts                                |   5 +
 e2e/load-sesssion.e2e-spec.ts                 |  66 +-
 e2e/session-6-calc.test.json                  | 812 +++++++++++++++++-
 e2e/session-optional-params.test.json         | 160 ++++
 protractor.conf.js                            |  11 +-
 .../calculator.component.html                 |   6 +-
 7 files changed, 1073 insertions(+), 13 deletions(-)
 create mode 100644 e2e/session-optional-params.test.json

diff --git a/e2e/calculator.po.ts b/e2e/calculator.po.ts
index d4b7a51d5..be6a5eb4b 100644
--- a/e2e/calculator.po.ts
+++ b/e2e/calculator.po.ts
@@ -1,4 +1,4 @@
-import { browser, by, element } from "protractor";
+import { by, element, ElementFinder } from "protractor";
 
 export class CalculatorPage {
 
@@ -9,4 +9,28 @@ export class CalculatorPage {
   getHeader1() {
     return element(by.css("h1"));
   }
+
+  getSelectById(id: string) {
+    return element(by.css("mat-select#" + id));
+  }
+
+  getInputById(id: string) {
+    return element(by.css("input#" + id));
+  }
+
+  getSaveSessionButton() {
+    return element(by.css("dialog-save-session button[type=submit]"));
+  }
+
+  async clickSaveCalcButton() {
+    return await element(by.css("#save-calc")).click();
+  }
+
+  async changeSelectValue(elt: ElementFinder, index: number) {
+    await elt.click();
+    const options = (await elt.getAttribute("aria-owns")).split(" ");
+    const optId = options[index];
+    const option = element(by.id(optId));
+    await option.click();
+  }
 }
diff --git a/e2e/list.po.ts b/e2e/list.po.ts
index 2f06248a1..4e32624df 100644
--- a/e2e/list.po.ts
+++ b/e2e/list.po.ts
@@ -27,4 +27,9 @@ export class ListPage {
     const r = Math.min((Math.floor(Math.random() * l)), (l - 1));
     return menuEntries.get(r).click();
   }
+
+  async clickMenuEntryForCalcType(type: number) {
+    const but = element(by.css("#create-calc-" + type));
+    return but.click();
+  }
 }
diff --git a/e2e/load-sesssion.e2e-spec.ts b/e2e/load-sesssion.e2e-spec.ts
index 39f919a41..b288a375f 100644
--- a/e2e/load-sesssion.e2e-spec.ts
+++ b/e2e/load-sesssion.e2e-spec.ts
@@ -1,21 +1,27 @@
 import { AppPage } from "./app.po";
+import { ListPage } from "./list.po";
+import { CalculatorPage } from "./calculator.po";
 import { Navbar } from "./navbar.po";
 import { SideNav } from "./sidenav.po";
 import { browser } from "protractor";
 
-describe("ngHyd − start page", () => {
-  let page: AppPage;
+describe("ngHyd − save and load sessions", () => {
+  let startPage: AppPage;
+  let listPage: ListPage;
+  let calcPage: CalculatorPage;
   let navbar: Navbar;
   let sidenav: SideNav;
 
   beforeEach(() => {
-    page = new AppPage();
+    startPage = new AppPage();
+    listPage = new ListPage();
+    calcPage = new CalculatorPage();
     navbar = new Navbar();
     sidenav = new SideNav();
   });
 
   it("when loading session-6-calc.test.json file from home page, 6 calculators should be loaded", async () => {
-    await page.navigateTo();
+    await startPage.navigateTo();
 
     await navbar.clickMenuButton();
     await browser.sleep(200);
@@ -29,8 +35,52 @@ describe("ngHyd − start page", () => {
     expect(await navbar.getAllCalculatorTabs().count()).toBe(6);
   });
 
-  /*it("when app starts, user should see the list of available compute nodes", () => {
-    page.navigateTo();
-    expect(page.getListLength()).toBeGreaterThan(8);
-  });*/
+  it("when loading session-optional-params.test.json file from home page, the calculator should be loaded", async () => {
+    await startPage.navigateTo();
+
+    await navbar.clickMenuButton();
+    await browser.sleep(200);
+
+    await sidenav.clickLoadSessionButton();
+    await browser.sleep(200);
+
+    await sidenav.loadSessionFile("./session-optional-params.test.json");
+    await browser.sleep(200);
+
+    expect(await navbar.getAllCalculatorTabs().count()).toBe(1);
+  });
+
+  it("when saving a calculator, the current parameter values should be found in the file", async () => {
+    await startPage.navigateTo();
+
+    await listPage.clickMenuEntryForCalcType(2); // Section paramétrée
+    await browser.sleep(500);
+
+    await calcPage.changeSelectValue(calcPage.getSelectById("select_section"), 2); // mode "circulaire"
+
+    await calcPage.getInputById("Ks").clear(); // coefficient de Strickler
+    await calcPage.getInputById("Ks").sendKeys("42");
+
+    await calcPage.clickSaveCalcButton();
+
+    // see: https://stackoverflow.com/questions/21935696/protractor-e2e-test-case-for-downloading-pdf-file
+    const fs = require("fs");
+    const path = require("path");
+    const os = require("os");
+    const filename = path.resolve(os.homedir(), "Téléchargements/session.json");
+    if (fs.existsSync(filename)) {
+        // Make sure the browser doesn't have to rename the download.
+        fs.unlinkSync(filename);
+    }
+
+    await calcPage.getSaveSessionButton().click();
+    await browser.sleep(1000);
+    const fileContent = fs.readFileSync(filename, { encoding: "utf8" });
+
+    // tslint:disable-next-line:quotemark
+    expect(fileContent).toContain('{"id":"select_section","selected_id":"select_section_circ"}');
+    // tslint:disable-next-line:quotemark
+    expect(fileContent).toContain('{"param":{"id":"Ks","values":{"mode":"SINGLE","value":42}}}');
+  });
+
 });
diff --git a/e2e/session-6-calc.test.json b/e2e/session-6-calc.test.json
index 070c2019f..4dab5ec3d 100644
--- a/e2e/session-6-calc.test.json
+++ b/e2e/session-6-calc.test.json
@@ -1 +1,811 @@
-{"session":{"elements":[{"form":{"id":"Conduite distributrice (MTJmNH)","uid":"MTJmNH","props":{"calcType":0,"nodeType":0},"elements":[{"fieldset":{"id":"fs_hydraulique","props":{"calcType":0,"nodeType":0},"elements":[{"param":{"id":"Q","values":{"mode":"SINGLE","value":3}}},{"param":{"id":"D","values":{"mode":"SINGLE","value":1.2}}},{"param":{"id":"J","values":{"mode":"CALCUL"}}},{"param":{"id":"Lg","values":{"mode":"SINGLE","value":100}}},{"param":{"id":"Nu","values":{"mode":"SINGLE","value":0.000001}}}]}},{"fieldset":{"id":"fs_param_calc","props":{"calcType":0,"nodeType":0},"elements":[{"param":{"id":"Pr","values":{"mode":"SINGLE","value":0.0001}}}]}}]}},{"form":{"id":"Lechapt-Calmon (NHdtdT)","uid":"NHdtdT","props":{"calcType":1,"nodeType":0},"elements":[{"fieldset":{"id":"fs_materiau","props":{"calcType":1,"nodeType":0},"elements":[{"select":{"id":"select_material","selected_id":"select_material_1"}},{"param":{"id":"L","values":{"mode":"SINGLE","value":1.863}}},{"param":{"id":"M","values":{"mode":"SINGLE","value":2}}},{"param":{"id":"N","values":{"mode":"SINGLE","value":5.33}}}]}},{"fieldset":{"id":"fs_hydraulique","props":{"calcType":1,"nodeType":0},"elements":[{"param":{"id":"Q","values":{"mode":"SINGLE","value":3}}},{"param":{"id":"D","values":{"mode":"SINGLE","value":1.2}}},{"param":{"id":"J","values":{"mode":"CALCUL"}}},{"param":{"id":"Lg","values":{"mode":"SINGLE","value":100}}}]}},{"fieldset":{"id":"fs_param_calc","props":{"calcType":1,"nodeType":0},"elements":[{"param":{"id":"Pr","values":{"mode":"SINGLE","value":0.0001}}}]}}]}},{"form":{"id":"Section paramétrée (YjZxc2)","uid":"YjZxc2","props":{"calcType":2,"nodeType":2},"elements":[{"fieldset":{"id":"fs_section","props":{"calcType":2,"nodeType":2},"elements":[{"select":{"id":"select_section","selected_id":"select_section_rect"}},{"param":{"id":"LargeurBerge","values":{"mode":"SINGLE","value":2.5}}}]}},{"fieldset":{"id":"fs_bief","props":{"calcType":2,"nodeType":2},"elements":[{"param":{"id":"Ks","values":{"mode":"SINGLE","value":40}}},{"param":{"id":"If","values":{"mode":"SINGLE","value":0.001}}},{"param":{"id":"YB","values":{"mode":"SINGLE","value":1}}}]}},{"fieldset":{"id":"fs_hydraulique","props":{"calcType":2,"nodeType":2},"elements":[{"param":{"id":"Q","values":{"mode":"SINGLE","value":1.2}}},{"param":{"id":"Y","values":{"mode":"SINGLE","value":0.8}}}]}},{"fieldset":{"id":"fs_param_calc","props":{"calcType":2,"nodeType":2},"elements":[{"param":{"id":"Pr","values":{"mode":"SINGLE","value":0.0001}}}]}},{"fieldset":{"id":"fs_computed_var","props":{"calcType":2,"nodeType":2},"elements":[{"select":{"id":"select_target","selected_id":"select_target_Hs"}}]}}]}},{"form":{"id":"Régime uniforme (ZmEwcX)","uid":"ZmEwcX","props":{"calcType":3,"nodeType":2},"elements":[{"fieldset":{"id":"fs_section","props":{"calcType":3,"nodeType":2},"elements":[{"select":{"id":"select_section","selected_id":"select_section_rect"}},{"param":{"id":"LargeurBerge","values":{"mode":"SINGLE","value":2.5}}}]}},{"fieldset":{"id":"fs_bief","props":{"calcType":3,"nodeType":2},"elements":[{"param":{"id":"Ks","values":{"mode":"SINGLE","value":40}}},{"param":{"id":"If","values":{"mode":"SINGLE","value":0.001}}},{"param":{"id":"YB","values":{"mode":"SINGLE","value":1}}}]}},{"fieldset":{"id":"fs_hydraulique","props":{"calcType":3,"nodeType":2},"elements":[{"param":{"id":"Q","values":{"mode":"CALCUL"}}},{"param":{"id":"Y","values":{"mode":"SINGLE","value":0.8}}}]}},{"fieldset":{"id":"fs_param_calc","props":{"calcType":3,"nodeType":2},"elements":[{"param":{"id":"Pr","values":{"mode":"SINGLE","value":0.0001}}}]}}]}},{"form":{"id":"Courbes de remous (NHdmeG)","uid":"NHdmeG","props":{"calcType":4,"nodeType":2},"elements":[{"fieldset":{"id":"fs_section","props":{"calcType":4,"nodeType":2},"elements":[{"select":{"id":"select_section","selected_id":"select_section_rect"}},{"param":{"id":"LargeurBerge","values":{"mode":"SINGLE","value":2.5}}}]}},{"fieldset":{"id":"fs_bief","props":{"calcType":4,"nodeType":2},"elements":[{"param":{"id":"Ks","values":{"mode":"SINGLE","value":40}}},{"param":{"id":"Long","values":{"mode":"SINGLE","value":100}}},{"param":{"id":"If","values":{"mode":"SINGLE","value":0.001}}},{"param":{"id":"YB","values":{"mode":"SINGLE","value":1}}}]}},{"fieldset":{"id":"fs_condlim","props":{"calcType":4,"nodeType":2},"elements":[{"param":{"id":"Q","values":{"mode":"SINGLE","value":1.2}}},{"param":{"id":"Yaval","values":{"mode":"SINGLE","value":0.4}}},{"param":{"id":"Yamont","values":{"mode":"SINGLE","value":0.15}}}]}},{"fieldset":{"id":"fs_param_calc","props":{"calcType":4,"nodeType":2},"elements":[{"param":{"id":"Dx","values":{"mode":"SINGLE","value":5}}},{"param":{"id":"Pr","values":{"mode":"SINGLE","value":0.0001}}},{"select":{"id":"select_resolution","selected_id":"select_resolution_trap"}}]}},{"fieldset":{"id":"fs_target_data","props":{"calcType":4,"nodeType":2},"elements":[{"select":{"id":"select_target","selected_id":"select_target_none"}}]}}]}},{"form":{"id":"Lois d'ouvrages (Yzgxan)","uid":"Yzgxan","props":{"calcType":8,"nodeType":0},"elements":[{"fieldset":{"id":"fs_param_hydro","props":{"calcType":8,"nodeType":0},"elements":[{"param":{"id":"Q","values":{"mode":"CALCUL"}}},{"param":{"id":"Z1","values":{"mode":"SINGLE","value":102}}},{"param":{"id":"Z2","values":{"mode":"SINGLE","value":101.5}}}]}},{"fieldset_container":{"id":"struct_container","elements":[{"fieldset":{"id":"fs_ouvrage","props":{"calcType":7,"nodeType":5,"structureType":1,"loiDebit":1},"elements":[{"select":{"id":"select_ouvrage","selected_id":"select_ouvrage_vanne_rect"}},{"select":{"id":"select_loidebit1","selected_id":"select_loidebit1_cem88d"}},{"select":{"id":"select_loidebit2","selected_id":"select_loidebit2_cem88v"}},{"select":{"id":"select_loidebit3","selected_id":"select_loidebit3_seuiltriang"}},{"select":{"id":"select_loidebit4","selected_id":"select_loidebit4_seuiltriangtrunc"}},{"param":{"id":"ZDV","values":{"mode":"SINGLE","value":100}}},{"param":{"id":"L","values":{"mode":"SINGLE","value":2}}},{"param":{"id":"W","values":{"mode":"SINGLE","value":null}}},{"param":{"id":"Cd","values":{"mode":"SINGLE","value":0.4}}}]}}]}},{"fieldset":{"id":"fs_param_calc","props":{"calcType":8,"nodeType":0},"elements":[{"param":{"id":"Pr","values":{"mode":"SINGLE","value":0.0001}}}]}}]}}]}}
\ No newline at end of file
+{
+    "session": {
+        "elements": [
+            {
+                "form": {
+                    "id": "Conduite distributrice (MTJmNH)",
+                    "uid": "MTJmNH",
+                    "props": {
+                        "calcType": 0,
+                        "nodeType": 0
+                    },
+                    "elements": [
+                        {
+                            "fieldset": {
+                                "id": "fs_hydraulique",
+                                "props": {
+                                    "calcType": 0,
+                                    "nodeType": 0
+                                },
+                                "elements": [
+                                    {
+                                        "param": {
+                                            "id": "Q",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 3
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "D",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 1.2
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "J",
+                                            "values": {
+                                                "mode": "CALCUL"
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "Lg",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 100
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "Nu",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 0.000001
+                                            }
+                                        }
+                                    }
+                                ]
+                            }
+                        },
+                        {
+                            "fieldset": {
+                                "id": "fs_param_calc",
+                                "props": {
+                                    "calcType": 0,
+                                    "nodeType": 0
+                                },
+                                "elements": [
+                                    {
+                                        "param": {
+                                            "id": "Pr",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 0.0001
+                                            }
+                                        }
+                                    }
+                                ]
+                            }
+                        }
+                    ]
+                }
+            },
+            {
+                "form": {
+                    "id": "Lechapt-Calmon (NHdtdT)",
+                    "uid": "NHdtdT",
+                    "props": {
+                        "calcType": 1,
+                        "nodeType": 0
+                    },
+                    "elements": [
+                        {
+                            "fieldset": {
+                                "id": "fs_materiau",
+                                "props": {
+                                    "calcType": 1,
+                                    "nodeType": 0
+                                },
+                                "elements": [
+                                    {
+                                        "select": {
+                                            "id": "select_material",
+                                            "selected_id": "select_material_1"
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "L",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 1.863
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "M",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 2
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "N",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 5.33
+                                            }
+                                        }
+                                    }
+                                ]
+                            }
+                        },
+                        {
+                            "fieldset": {
+                                "id": "fs_hydraulique",
+                                "props": {
+                                    "calcType": 1,
+                                    "nodeType": 0
+                                },
+                                "elements": [
+                                    {
+                                        "param": {
+                                            "id": "Q",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 3
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "D",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 1.2
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "J",
+                                            "values": {
+                                                "mode": "CALCUL"
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "Lg",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 100
+                                            }
+                                        }
+                                    }
+                                ]
+                            }
+                        },
+                        {
+                            "fieldset": {
+                                "id": "fs_param_calc",
+                                "props": {
+                                    "calcType": 1,
+                                    "nodeType": 0
+                                },
+                                "elements": [
+                                    {
+                                        "param": {
+                                            "id": "Pr",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 0.0001
+                                            }
+                                        }
+                                    }
+                                ]
+                            }
+                        }
+                    ]
+                }
+            },
+            {
+                "form": {
+                    "id": "Section paramétrée (YjZxc2)",
+                    "uid": "YjZxc2",
+                    "props": {
+                        "calcType": 2,
+                        "nodeType": 2
+                    },
+                    "elements": [
+                        {
+                            "fieldset": {
+                                "id": "fs_section",
+                                "props": {
+                                    "calcType": 2,
+                                    "nodeType": 2
+                                },
+                                "elements": [
+                                    {
+                                        "select": {
+                                            "id": "select_section",
+                                            "selected_id": "select_section_rect"
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "LargeurBerge",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 2.5
+                                            }
+                                        }
+                                    }
+                                ]
+                            }
+                        },
+                        {
+                            "fieldset": {
+                                "id": "fs_bief",
+                                "props": {
+                                    "calcType": 2,
+                                    "nodeType": 2
+                                },
+                                "elements": [
+                                    {
+                                        "param": {
+                                            "id": "Ks",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 40
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "If",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 0.001
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "YB",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 1
+                                            }
+                                        }
+                                    }
+                                ]
+                            }
+                        },
+                        {
+                            "fieldset": {
+                                "id": "fs_hydraulique",
+                                "props": {
+                                    "calcType": 2,
+                                    "nodeType": 2
+                                },
+                                "elements": [
+                                    {
+                                        "param": {
+                                            "id": "Q",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 1.2
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "Y",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 0.8
+                                            }
+                                        }
+                                    }
+                                ]
+                            }
+                        },
+                        {
+                            "fieldset": {
+                                "id": "fs_param_calc",
+                                "props": {
+                                    "calcType": 2,
+                                    "nodeType": 2
+                                },
+                                "elements": [
+                                    {
+                                        "param": {
+                                            "id": "Pr",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 0.0001
+                                            }
+                                        }
+                                    }
+                                ]
+                            }
+                        },
+                        {
+                            "fieldset": {
+                                "id": "fs_computed_var",
+                                "props": {
+                                    "calcType": 2,
+                                    "nodeType": 2
+                                },
+                                "elements": [
+                                    {
+                                        "select": {
+                                            "id": "select_target",
+                                            "selected_id": "select_target_Hs"
+                                        }
+                                    }
+                                ]
+                            }
+                        }
+                    ]
+                }
+            },
+            {
+                "form": {
+                    "id": "Régime uniforme (ZmEwcX)",
+                    "uid": "ZmEwcX",
+                    "props": {
+                        "calcType": 3,
+                        "nodeType": 2
+                    },
+                    "elements": [
+                        {
+                            "fieldset": {
+                                "id": "fs_section",
+                                "props": {
+                                    "calcType": 3,
+                                    "nodeType": 2
+                                },
+                                "elements": [
+                                    {
+                                        "select": {
+                                            "id": "select_section",
+                                            "selected_id": "select_section_rect"
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "LargeurBerge",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 2.5
+                                            }
+                                        }
+                                    }
+                                ]
+                            }
+                        },
+                        {
+                            "fieldset": {
+                                "id": "fs_bief",
+                                "props": {
+                                    "calcType": 3,
+                                    "nodeType": 2
+                                },
+                                "elements": [
+                                    {
+                                        "param": {
+                                            "id": "Ks",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 40
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "If",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 0.001
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "YB",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 1
+                                            }
+                                        }
+                                    }
+                                ]
+                            }
+                        },
+                        {
+                            "fieldset": {
+                                "id": "fs_hydraulique",
+                                "props": {
+                                    "calcType": 3,
+                                    "nodeType": 2
+                                },
+                                "elements": [
+                                    {
+                                        "param": {
+                                            "id": "Q",
+                                            "values": {
+                                                "mode": "CALCUL"
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "Y",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 0.8
+                                            }
+                                        }
+                                    }
+                                ]
+                            }
+                        },
+                        {
+                            "fieldset": {
+                                "id": "fs_param_calc",
+                                "props": {
+                                    "calcType": 3,
+                                    "nodeType": 2
+                                },
+                                "elements": [
+                                    {
+                                        "param": {
+                                            "id": "Pr",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 0.0001
+                                            }
+                                        }
+                                    }
+                                ]
+                            }
+                        }
+                    ]
+                }
+            },
+            {
+                "form": {
+                    "id": "Courbes de remous (NHdmeG)",
+                    "uid": "NHdmeG",
+                    "props": {
+                        "calcType": 4,
+                        "nodeType": 2
+                    },
+                    "elements": [
+                        {
+                            "fieldset": {
+                                "id": "fs_section",
+                                "props": {
+                                    "calcType": 4,
+                                    "nodeType": 2
+                                },
+                                "elements": [
+                                    {
+                                        "select": {
+                                            "id": "select_section",
+                                            "selected_id": "select_section_rect"
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "LargeurBerge",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 2.5
+                                            }
+                                        }
+                                    }
+                                ]
+                            }
+                        },
+                        {
+                            "fieldset": {
+                                "id": "fs_bief",
+                                "props": {
+                                    "calcType": 4,
+                                    "nodeType": 2
+                                },
+                                "elements": [
+                                    {
+                                        "param": {
+                                            "id": "Ks",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 40
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "Long",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 100
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "If",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 0.001
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "YB",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 1
+                                            }
+                                        }
+                                    }
+                                ]
+                            }
+                        },
+                        {
+                            "fieldset": {
+                                "id": "fs_condlim",
+                                "props": {
+                                    "calcType": 4,
+                                    "nodeType": 2
+                                },
+                                "elements": [
+                                    {
+                                        "param": {
+                                            "id": "Q",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 1.2
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "Yaval",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 0.4
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "Yamont",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 0.15
+                                            }
+                                        }
+                                    }
+                                ]
+                            }
+                        },
+                        {
+                            "fieldset": {
+                                "id": "fs_param_calc",
+                                "props": {
+                                    "calcType": 4,
+                                    "nodeType": 2
+                                },
+                                "elements": [
+                                    {
+                                        "param": {
+                                            "id": "Dx",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 5
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "Pr",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 0.0001
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "select": {
+                                            "id": "select_resolution",
+                                            "selected_id": "select_resolution_trap"
+                                        }
+                                    }
+                                ]
+                            }
+                        },
+                        {
+                            "fieldset": {
+                                "id": "fs_target_data",
+                                "props": {
+                                    "calcType": 4,
+                                    "nodeType": 2
+                                },
+                                "elements": [
+                                    {
+                                        "select": {
+                                            "id": "select_target",
+                                            "selected_id": "select_target_none"
+                                        }
+                                    }
+                                ]
+                            }
+                        }
+                    ]
+                }
+            },
+            {
+                "form": {
+                    "id": "Lois d'ouvrages (Yzgxan)",
+                    "uid": "Yzgxan",
+                    "props": {
+                        "calcType": 8,
+                        "nodeType": 0
+                    },
+                    "elements": [
+                        {
+                            "fieldset": {
+                                "id": "fs_param_hydro",
+                                "props": {
+                                    "calcType": 8,
+                                    "nodeType": 0
+                                },
+                                "elements": [
+                                    {
+                                        "param": {
+                                            "id": "Q",
+                                            "values": {
+                                                "mode": "CALCUL"
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "Z1",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 102
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "Z2",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 101.5
+                                            }
+                                        }
+                                    }
+                                ]
+                            }
+                        },
+                        {
+                            "fieldset_container": {
+                                "id": "struct_container",
+                                "elements": [
+                                    {
+                                        "fieldset": {
+                                            "id": "fs_ouvrage",
+                                            "props": {
+                                                "calcType": 7,
+                                                "nodeType": 5,
+                                                "structureType": 1,
+                                                "loiDebit": 1
+                                            },
+                                            "elements": [
+                                                {
+                                                    "select": {
+                                                        "id": "select_ouvrage",
+                                                        "selected_id": "select_ouvrage_vanne_rect"
+                                                    }
+                                                },
+                                                {
+                                                    "select": {
+                                                        "id": "select_loidebit1",
+                                                        "selected_id": "select_loidebit1_cem88d"
+                                                    }
+                                                },
+                                                {
+                                                    "select": {
+                                                        "id": "select_loidebit2",
+                                                        "selected_id": "select_loidebit2_cem88v"
+                                                    }
+                                                },
+                                                {
+                                                    "select": {
+                                                        "id": "select_loidebit3",
+                                                        "selected_id": "select_loidebit3_seuiltriang"
+                                                    }
+                                                },
+                                                {
+                                                    "select": {
+                                                        "id": "select_loidebit4",
+                                                        "selected_id": "select_loidebit4_seuiltriangtrunc"
+                                                    }
+                                                },
+                                                {
+                                                    "param": {
+                                                        "id": "ZDV",
+                                                        "values": {
+                                                            "mode": "SINGLE",
+                                                            "value": 100
+                                                        }
+                                                    }
+                                                },
+                                                {
+                                                    "param": {
+                                                        "id": "L",
+                                                        "values": {
+                                                            "mode": "SINGLE",
+                                                            "value": 2
+                                                        }
+                                                    }
+                                                },
+                                                {
+                                                    "param": {
+                                                        "id": "W",
+                                                        "values": {
+                                                            "mode": "SINGLE",
+                                                            "value": null
+                                                        }
+                                                    }
+                                                },
+                                                {
+                                                    "param": {
+                                                        "id": "Cd",
+                                                        "values": {
+                                                            "mode": "SINGLE",
+                                                            "value": 0.4
+                                                        }
+                                                    }
+                                                }
+                                            ]
+                                        }
+                                    }
+                                ]
+                            }
+                        },
+                        {
+                            "fieldset": {
+                                "id": "fs_param_calc",
+                                "props": {
+                                    "calcType": 8,
+                                    "nodeType": 0
+                                },
+                                "elements": [
+                                    {
+                                        "param": {
+                                            "id": "Pr",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 0.0001
+                                            }
+                                        }
+                                    }
+                                ]
+                            }
+                        }
+                    ]
+                }
+            }
+        ]
+    }
+}
\ No newline at end of file
diff --git a/e2e/session-optional-params.test.json b/e2e/session-optional-params.test.json
new file mode 100644
index 000000000..0d5cea59e
--- /dev/null
+++ b/e2e/session-optional-params.test.json
@@ -0,0 +1,160 @@
+{
+    "session": {
+        "elements": [
+            {
+                "form": {
+                    "id": "Section paramétrée",
+                    "uid": "ZDZ1Yn",
+                    "props": {
+                        "calcType": 2,
+                        "nodeType": 4
+                    },
+                    "elements": [
+                        {
+                            "fieldset": {
+                                "id": "fs_section",
+                                "props": {
+                                    "calcType": 2,
+                                    "nodeType": 4
+                                },
+                                "elements": [
+                                    {
+                                        "select": {
+                                            "id": "select_section",
+                                            "selected_id": "select_section_puiss"
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "k",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 0.5
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "LargeurBerge",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 4
+                                            }
+                                        }
+                                    }
+                                ]
+                            }
+                        },
+                        {
+                            "fieldset": {
+                                "id": "fs_bief",
+                                "props": {
+                                    "calcType": 2,
+                                    "nodeType": 4
+                                },
+                                "elements": [
+                                    {
+                                        "param": {
+                                            "id": "Ks",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 40
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "If",
+                                            "values": {
+                                                "mode": "MINMAX",
+                                                "min": 0.0005,
+                                                "max": 0.002,
+                                                "step": 0.00007500000000000001
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "YB",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 1
+                                            }
+                                        }
+                                    }
+                                ]
+                            }
+                        },
+                        {
+                            "fieldset": {
+                                "id": "fs_hydraulique",
+                                "props": {
+                                    "calcType": 2,
+                                    "nodeType": 4
+                                },
+                                "elements": [
+                                    {
+                                        "param": {
+                                            "id": "Q",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 1.2
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "param": {
+                                            "id": "Y",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 0.8
+                                            }
+                                        }
+                                    }
+                                ]
+                            }
+                        },
+                        {
+                            "fieldset": {
+                                "id": "fs_param_calc",
+                                "props": {
+                                    "calcType": 2,
+                                    "nodeType": 4
+                                },
+                                "elements": [
+                                    {
+                                        "param": {
+                                            "id": "Pr",
+                                            "values": {
+                                                "mode": "SINGLE",
+                                                "value": 0.0001
+                                            }
+                                        }
+                                    }
+                                ]
+                            }
+                        },
+                        {
+                            "fieldset": {
+                                "id": "fs_computed_var",
+                                "props": {
+                                    "calcType": 2,
+                                    "nodeType": 4,
+                                    "varCalc": "B"
+                                },
+                                "elements": [
+                                    {
+                                        "select": {
+                                            "id": "select_target",
+                                            "selected_id": "select_target_B"
+                                        }
+                                    }
+                                ]
+                            }
+                        }
+                    ]
+                }
+            }
+        ]
+    }
+}
\ No newline at end of file
diff --git a/protractor.conf.js b/protractor.conf.js
index a2584537b..8d5700529 100644
--- a/protractor.conf.js
+++ b/protractor.conf.js
@@ -9,7 +9,16 @@ exports.config = {
     './e2e/**/*.e2e-spec.ts'
   ],
   capabilities: {
-    'browserName': 'chrome'
+    browserName: 'chrome',
+    chromeOoptions: {
+      prefs: {
+        download: {
+            prompt_for_download: false, 
+            directory_upgrade: true,
+            default_directory: '/tmp/e2e-downloads' // @WARNING marche pas !?
+        },
+      },
+    },
   },
   directConnect: true,
   baseUrl: 'http://localhost:4201/',
diff --git a/src/app/components/generic-calculator/calculator.component.html b/src/app/components/generic-calculator/calculator.component.html
index 7874908f3..cbf2ab0e5 100644
--- a/src/app/components/generic-calculator/calculator.component.html
+++ b/src/app/components/generic-calculator/calculator.component.html
@@ -5,10 +5,12 @@
         <div class="hyd-window-btns">
             <!-- bouton d'aide -->
             <mat-icon *ngIf="enableHelpButton" (click)="openHelp()" color="accent">help</mat-icon>
+            <!-- bouton de duplication -->
+            <mat-icon id="clone-calc" (click)="cloneCalculator()">file_copy</mat-icon>
             <!-- bouton de sauvegarde -->
-            <mat-icon (click)="saveCalculator()">save_alt</mat-icon>
+            <mat-icon id="save-calc" (click)="saveCalculator()">save_alt</mat-icon>
             <!-- bouton de fermeture -->
-            <mat-icon (click)="closeCalculator()">close</mat-icon>
+            <mat-icon id="close-calc" (click)="closeCalculator()">close</mat-icon>
         </div>
 
         <!-- titre -->
-- 
GitLab


From 79ec717f04a140f6be11b2ed7eb35b62b6c3280b Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Tue, 19 Feb 2019 14:45:09 +0100
Subject: [PATCH 04/21] Ajout script npm pour tests e2e sans recompiler

---
 package.json | 1 +
 1 file changed, 1 insertion(+)

diff --git a/package.json b/package.json
index bb1875351..e63f1f4b8 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,7 @@
     "test": "ng test",
     "lint": "ng lint",
     "e2e": "ng e2e",
+    "e2equick": "ng e2e --dev-server-target= --baseUrl=http://localhost:4200",
     "jalhyd": "rm node_modules/jalhyd; cd ../jalhyd; npm run build; cd ../nghyd; npm install ../jalhyd;",
     "mathjax": "rsync -az --delete node_modules/mathjax docs-fr/javascripts;",
     "mkdocs": "npm run mathjax; find docs-fr/javascripts/ -name '*.md' -type f -delete; python3 -m mkdocs build",
-- 
GitLab


From 2bea458e7108a82a863276a68c8cd8e05f2a1a18 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Tue, 19 Feb 2019 14:45:40 +0100
Subject: [PATCH 05/21] =?UTF-8?q?Couleur=20de=20fond=20du=20<body>=20harmo?=
 =?UTF-8?q?nis=C3=A9e=20avec=20celle=20du=20app-content?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/styles.scss | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/styles.scss b/src/styles.scss
index 013d064f6..6fdf91aec 100644
--- a/src/styles.scss
+++ b/src/styles.scss
@@ -6,7 +6,11 @@
 
 html, body { height: 100%; }
 
-body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
+body {
+    margin: 0;
+    font-family: Roboto, "Helvetica Neue", sans-serif;
+    background-color: #FAFAFA; // harmonize with app-content
+}
 
 button {
     &:focus {
-- 
GitLab


From ae74c7368bfd65e0ab68c8a261c52b865ba0da0b Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Tue, 19 Feb 2019 14:46:58 +0100
Subject: [PATCH 06/21] =?UTF-8?q?Les=20modules,=20param=C3=A8tres=20li?=
 =?UTF-8?q?=C3=A9s=20et=20calcul=C3=A9s=20ont=20des=20ID=20explicites?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../generic-calculator/calculator.component.html      |  2 +-
 .../generic-calculator/calculator.component.scss      |  2 +-
 .../generic-calculator/calculator.component.ts        |  4 ++++
 .../param-computed/param-computed.component.html      |  2 +-
 .../param-computed/param-computed.component.ts        | 11 +++++++++++
 .../components/param-link/param-link.component.html   |  3 ++-
 src/app/components/param-link/param-link.component.ts |  4 ++++
 7 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/src/app/components/generic-calculator/calculator.component.html b/src/app/components/generic-calculator/calculator.component.html
index cbf2ab0e5..4c2623ff5 100644
--- a/src/app/components/generic-calculator/calculator.component.html
+++ b/src/app/components/generic-calculator/calculator.component.html
@@ -1,4 +1,4 @@
-<mat-card id="calculator-card">
+<mat-card class="calculator-card" [id]="ID">
 
     <mat-card-header>
 
diff --git a/src/app/components/generic-calculator/calculator.component.scss b/src/app/components/generic-calculator/calculator.component.scss
index 2346a4874..68df692b8 100644
--- a/src/app/components/generic-calculator/calculator.component.scss
+++ b/src/app/components/generic-calculator/calculator.component.scss
@@ -24,7 +24,7 @@ mat-card {
     margin-bottom: 2em;
 
     // main card
-    &#calculator-card {
+    &.calculator-card {
 
         > mat-card-header {
             margin-bottom: .5em;
diff --git a/src/app/components/generic-calculator/calculator.component.ts b/src/app/components/generic-calculator/calculator.component.ts
index 3496192aa..9f5a30847 100644
--- a/src/app/components/generic-calculator/calculator.component.ts
+++ b/src/app/components/generic-calculator/calculator.component.ts
@@ -87,6 +87,10 @@ export class GenericCalculatorComponent extends BaseComponent implements OnInit,
     private intlService: I18nService;
     private formulaireService: FormulaireService;
 
+    public get ID() {
+        return this._formulaire.uid;
+    }
+
     constructor(
         private route: ActivatedRoute,
         private confirmCloseCalcDialog: MatDialog
diff --git a/src/app/components/param-computed/param-computed.component.html b/src/app/components/param-computed/param-computed.component.html
index 0751e36bf..eb582f98d 100644
--- a/src/app/components/param-computed/param-computed.component.html
+++ b/src/app/components/param-computed/param-computed.component.html
@@ -1,6 +1,6 @@
 <!-- a fake input bound to nothing, for the sake of UI consistency -->
 <mat-form-field>
-    <input matInput disabled class="form-control" type="text" [ngModel]="infoText" [placeholder]="param.title">
+    <input matInput disabled [id]="inputId" class="form-control" type="text" [ngModel]="infoText" [placeholder]="param.title">
     <button *ngIf="isDicho" mat-icon-button class="param-computed-more" (click)="openDialog()">
         <mat-icon>more_horiz</mat-icon>
     </button>
diff --git a/src/app/components/param-computed/param-computed.component.ts b/src/app/components/param-computed/param-computed.component.ts
index 6bfced00b..889c3f10b 100644
--- a/src/app/components/param-computed/param-computed.component.ts
+++ b/src/app/components/param-computed/param-computed.component.ts
@@ -20,6 +20,17 @@ export class ParamComputedComponent {
     @Input()
     public title: string;
 
+    /**
+     * id de l'input, utilisé notamment pour les tests
+     */
+    public get inputId() {
+        let id = "calc_input-1";
+        if (this.param) {
+            id = "calc_" + this.param.symbol;
+        }
+        return id;
+    }
+
     constructor(
         private editInitialValueDialog: MatDialog,
         private intlService: I18nService
diff --git a/src/app/components/param-link/param-link.component.html b/src/app/components/param-link/param-link.component.html
index 5b198816b..b49373434 100644
--- a/src/app/components/param-link/param-link.component.html
+++ b/src/app/components/param-link/param-link.component.html
@@ -1,5 +1,6 @@
 <mat-form-field>
-    <mat-select [name]='"linked-param_" + param.uid' required [placeholder]="param.title" [(ngModel)]="currentLinkedParam">
+    <mat-select [id]="selectId" [name]="selectId" [placeholder]="param.title"
+        [(ngModel)]="currentLinkedParam" required>
         <mat-option *ngFor="let e of linkableParams" [value]="e">
             {{ selectItemLabel(e) }}
         </mat-option>
diff --git a/src/app/components/param-link/param-link.component.ts b/src/app/components/param-link/param-link.component.ts
index 9e28788f7..4903a1461 100644
--- a/src/app/components/param-link/param-link.component.ts
+++ b/src/app/components/param-link/param-link.component.ts
@@ -54,6 +54,10 @@ export class ParamLinkComponent implements OnChanges, Observer, OnDestroy {
 
     private _formService: FormulaireService;
 
+    public get selectId() {
+        return  "linked_" + this.param.symbol;
+    }
+
     constructor(
         private intlService: I18nService
     ) {
-- 
GitLab


From baabf8112f0eaebc693ca3e7470a581c6a8f70b4 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Tue, 19 Feb 2019 14:47:18 +0100
Subject: [PATCH 07/21] Renommage test e2e

---
 e2e/load-save-sesssion.e2e-spec.ts | 86 ++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)
 create mode 100644 e2e/load-save-sesssion.e2e-spec.ts

diff --git a/e2e/load-save-sesssion.e2e-spec.ts b/e2e/load-save-sesssion.e2e-spec.ts
new file mode 100644
index 000000000..b288a375f
--- /dev/null
+++ b/e2e/load-save-sesssion.e2e-spec.ts
@@ -0,0 +1,86 @@
+import { AppPage } from "./app.po";
+import { ListPage } from "./list.po";
+import { CalculatorPage } from "./calculator.po";
+import { Navbar } from "./navbar.po";
+import { SideNav } from "./sidenav.po";
+import { browser } from "protractor";
+
+describe("ngHyd − save and load sessions", () => {
+  let startPage: AppPage;
+  let listPage: ListPage;
+  let calcPage: CalculatorPage;
+  let navbar: Navbar;
+  let sidenav: SideNav;
+
+  beforeEach(() => {
+    startPage = new AppPage();
+    listPage = new ListPage();
+    calcPage = new CalculatorPage();
+    navbar = new Navbar();
+    sidenav = new SideNav();
+  });
+
+  it("when loading session-6-calc.test.json file from home page, 6 calculators should be loaded", async () => {
+    await startPage.navigateTo();
+
+    await navbar.clickMenuButton();
+    await browser.sleep(200);
+
+    await sidenav.clickLoadSessionButton();
+    await browser.sleep(200);
+
+    await sidenav.loadSessionFile("./session-6-calc.test.json");
+    await browser.sleep(200);
+
+    expect(await navbar.getAllCalculatorTabs().count()).toBe(6);
+  });
+
+  it("when loading session-optional-params.test.json file from home page, the calculator should be loaded", async () => {
+    await startPage.navigateTo();
+
+    await navbar.clickMenuButton();
+    await browser.sleep(200);
+
+    await sidenav.clickLoadSessionButton();
+    await browser.sleep(200);
+
+    await sidenav.loadSessionFile("./session-optional-params.test.json");
+    await browser.sleep(200);
+
+    expect(await navbar.getAllCalculatorTabs().count()).toBe(1);
+  });
+
+  it("when saving a calculator, the current parameter values should be found in the file", async () => {
+    await startPage.navigateTo();
+
+    await listPage.clickMenuEntryForCalcType(2); // Section paramétrée
+    await browser.sleep(500);
+
+    await calcPage.changeSelectValue(calcPage.getSelectById("select_section"), 2); // mode "circulaire"
+
+    await calcPage.getInputById("Ks").clear(); // coefficient de Strickler
+    await calcPage.getInputById("Ks").sendKeys("42");
+
+    await calcPage.clickSaveCalcButton();
+
+    // see: https://stackoverflow.com/questions/21935696/protractor-e2e-test-case-for-downloading-pdf-file
+    const fs = require("fs");
+    const path = require("path");
+    const os = require("os");
+    const filename = path.resolve(os.homedir(), "Téléchargements/session.json");
+    if (fs.existsSync(filename)) {
+        // Make sure the browser doesn't have to rename the download.
+        fs.unlinkSync(filename);
+    }
+
+    await calcPage.getSaveSessionButton().click();
+    await browser.sleep(1000);
+    const fileContent = fs.readFileSync(filename, { encoding: "utf8" });
+
+    // tslint:disable-next-line:quotemark
+    expect(fileContent).toContain('{"id":"select_section","selected_id":"select_section_circ"}');
+    // tslint:disable-next-line:quotemark
+    expect(fileContent).toContain('{"param":{"id":"Ks","values":{"mode":"SINGLE","value":42}}}');
+  });
+
+});
-- 
GitLab


From 98fcba35e993d1a193241cd89b9745b5eea066af Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Tue, 19 Feb 2019 14:48:00 +0100
Subject: [PATCH 08/21] =?UTF-8?q?Am=C3=A9lioration=20fiabilit=C3=A9=20test?=
 =?UTF-8?q?=20(undefined)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/app/components/fixedvar-results/fixed-results.component.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/app/components/fixedvar-results/fixed-results.component.ts b/src/app/components/fixedvar-results/fixed-results.component.ts
index cf23921d8..8207c30c1 100644
--- a/src/app/components/fixedvar-results/fixed-results.component.ts
+++ b/src/app/components/fixedvar-results/fixed-results.component.ts
@@ -81,7 +81,7 @@ export class FixedResultsComponent {
             && res.extraResults
         ) {
             // 2.1. main result (sometimes empty, for ex. in "Section paramétrée")
-            if (res.name && res.resultElement.vCalc) {
+            if (res.name && res.resultElement.vCalc !== undefined) {
                 data.push({
                     label: this._fixedResults.calculatedParameterHeader,
                     value: this.intlService.formatResult(res.name, res.resultElement.vCalc),
-- 
GitLab


From b34ac22a694d33260186b89535943e21c8a893af Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Tue, 19 Feb 2019 14:51:53 +0100
Subject: [PATCH 09/21] Fix #89, #129

---
 src/app/formulaire/ngparam.ts                  | 18 +++++++++++-------
 .../services/formulaire/formulaire.service.ts  |  3 ++-
 2 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/src/app/formulaire/ngparam.ts b/src/app/formulaire/ngparam.ts
index 82cca313a..8bf3c34f7 100644
--- a/src/app/formulaire/ngparam.ts
+++ b/src/app/formulaire/ngparam.ts
@@ -304,7 +304,6 @@ export class NgParameter extends InputField implements Observer {
         if (super.verifiesDependency(d)) {
             return true;
         }
-
         switch (d.masterCondition.type) {
             case DependencyConditionType.HasValue: {
                     const mc: ValueDependencyCondition = <ValueDependencyCondition>d.masterCondition;
@@ -326,21 +325,20 @@ export class NgParameter extends InputField implements Observer {
         res["mode"] = ParamValueMode[vm];
         switch (vm) {
             case ParamValueMode.SINGLE:
-                res["value"] = this._paramValues.singleValue;
+                res["value"] = this.getValue();
                 break;
 
             case ParamValueMode.MINMAX:
-                res["min"] = this._paramValues.min;
-                res["max"] = this._paramValues.max;
-                res["step"] = this._paramValues.step;
+                res["min"] = this.minValue;
+                res["max"] = this.maxValue;
+                res["step"] = this.stepValue;
                 break;
 
             case ParamValueMode.LISTE:
-                res["values"] = this._paramValues.valueList;
+                res["values"] = this.valueList;
                 break;
 
             case ParamValueMode.LINK:
-                // @TODO copié à l'arrache, vérifier que ça marche
                 res["form_uid"] = ServiceFactory.instance.formulaireService.getFormulaireFromNubId(this._paramDef.referencedNub["uid"]).uid;
                 res["ref"] = this.paramDefinition.referenceDefinition;
                 break;
@@ -378,6 +376,12 @@ export class NgParameter extends InputField implements Observer {
                 break;
 
             case ParamValueMode.LINK:
+                const uid: string = json["form_uid"];
+                const ref: string = json["ref"];
+                this._paramValues.valueMode = ParamValueMode.LINK;
+                // formulaire dont le Nub est la cible du lien
+                const destForm = ServiceFactory.instance.formulaireService.getFormulaireFromId(uid);
+                this._paramValues.defineReference(destForm.currentNub, ref);
                 break;  // cf FormulaireService.updateParamsLinks()
 
             default:
diff --git a/src/app/services/formulaire/formulaire.service.ts b/src/app/services/formulaire/formulaire.service.ts
index dda5ad7a3..b2a43ee0e 100644
--- a/src/app/services/formulaire/formulaire.service.ts
+++ b/src/app/services/formulaire/formulaire.service.ts
@@ -424,7 +424,7 @@ export class FormulaireService extends Observable {
         });
     }
 
-    private deserialiseForm(elements: {}): Promise<FormulaireDefinition> {
+    public deserialiseForm(elements: {}): Promise<FormulaireDefinition> {
         const props = elements["props"];
         const ct: CalculatorType = props["calcType"];
         return this.createFormulaire(ct, elements);
@@ -441,6 +441,7 @@ export class FormulaireService extends Observable {
                 const form = element[keys[0]];
 
                 for (const i of formInfos) {
+                    // on the loadSession dialog, was the checkbox checked for this calculator ?
                     if (i["uid"] === form["uid"] && i["selected"]) {
                         return this.deserialiseForm(form);
                     }
-- 
GitLab


From 5344abd72586a176f5c5911884c0e47d65be6b00 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Tue, 19 Feb 2019 15:09:52 +0100
Subject: [PATCH 10/21] Renommage fichier de test

---
 ...-spec.ts => load-save-session.e2e-spec.ts} |  0
 e2e/load-sesssion.e2e-spec.ts                 | 86 -------------------
 2 files changed, 86 deletions(-)
 rename e2e/{load-save-sesssion.e2e-spec.ts => load-save-session.e2e-spec.ts} (100%)
 delete mode 100644 e2e/load-sesssion.e2e-spec.ts

diff --git a/e2e/load-save-sesssion.e2e-spec.ts b/e2e/load-save-session.e2e-spec.ts
similarity index 100%
rename from e2e/load-save-sesssion.e2e-spec.ts
rename to e2e/load-save-session.e2e-spec.ts
diff --git a/e2e/load-sesssion.e2e-spec.ts b/e2e/load-sesssion.e2e-spec.ts
deleted file mode 100644
index b288a375f..000000000
--- a/e2e/load-sesssion.e2e-spec.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-import { AppPage } from "./app.po";
-import { ListPage } from "./list.po";
-import { CalculatorPage } from "./calculator.po";
-import { Navbar } from "./navbar.po";
-import { SideNav } from "./sidenav.po";
-import { browser } from "protractor";
-
-describe("ngHyd − save and load sessions", () => {
-  let startPage: AppPage;
-  let listPage: ListPage;
-  let calcPage: CalculatorPage;
-  let navbar: Navbar;
-  let sidenav: SideNav;
-
-  beforeEach(() => {
-    startPage = new AppPage();
-    listPage = new ListPage();
-    calcPage = new CalculatorPage();
-    navbar = new Navbar();
-    sidenav = new SideNav();
-  });
-
-  it("when loading session-6-calc.test.json file from home page, 6 calculators should be loaded", async () => {
-    await startPage.navigateTo();
-
-    await navbar.clickMenuButton();
-    await browser.sleep(200);
-
-    await sidenav.clickLoadSessionButton();
-    await browser.sleep(200);
-
-    await sidenav.loadSessionFile("./session-6-calc.test.json");
-    await browser.sleep(200);
-
-    expect(await navbar.getAllCalculatorTabs().count()).toBe(6);
-  });
-
-  it("when loading session-optional-params.test.json file from home page, the calculator should be loaded", async () => {
-    await startPage.navigateTo();
-
-    await navbar.clickMenuButton();
-    await browser.sleep(200);
-
-    await sidenav.clickLoadSessionButton();
-    await browser.sleep(200);
-
-    await sidenav.loadSessionFile("./session-optional-params.test.json");
-    await browser.sleep(200);
-
-    expect(await navbar.getAllCalculatorTabs().count()).toBe(1);
-  });
-
-  it("when saving a calculator, the current parameter values should be found in the file", async () => {
-    await startPage.navigateTo();
-
-    await listPage.clickMenuEntryForCalcType(2); // Section paramétrée
-    await browser.sleep(500);
-
-    await calcPage.changeSelectValue(calcPage.getSelectById("select_section"), 2); // mode "circulaire"
-
-    await calcPage.getInputById("Ks").clear(); // coefficient de Strickler
-    await calcPage.getInputById("Ks").sendKeys("42");
-
-    await calcPage.clickSaveCalcButton();
-
-    // see: https://stackoverflow.com/questions/21935696/protractor-e2e-test-case-for-downloading-pdf-file
-    const fs = require("fs");
-    const path = require("path");
-    const os = require("os");
-    const filename = path.resolve(os.homedir(), "Téléchargements/session.json");
-    if (fs.existsSync(filename)) {
-        // Make sure the browser doesn't have to rename the download.
-        fs.unlinkSync(filename);
-    }
-
-    await calcPage.getSaveSessionButton().click();
-    await browser.sleep(1000);
-    const fileContent = fs.readFileSync(filename, { encoding: "utf8" });
-
-    // tslint:disable-next-line:quotemark
-    expect(fileContent).toContain('{"id":"select_section","selected_id":"select_section_circ"}');
-    // tslint:disable-next-line:quotemark
-    expect(fileContent).toContain('{"param":{"id":"Ks","values":{"mode":"SINGLE","value":42}}}');
-  });
-
-});
-- 
GitLab


From e3d46151996464821867cd3a16901805110e1fd0 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Tue, 19 Feb 2019 15:38:45 +0100
Subject: [PATCH 11/21] Fix #131

---
 src/app/components/param-link/param-link.component.ts | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/src/app/components/param-link/param-link.component.ts b/src/app/components/param-link/param-link.component.ts
index 4903a1461..bbc231d26 100644
--- a/src/app/components/param-link/param-link.component.ts
+++ b/src/app/components/param-link/param-link.component.ts
@@ -80,11 +80,9 @@ export class ParamLinkComponent implements OnChanges, Observer, OnDestroy {
 
     public set currentLinkedParam(p: any) {
         for (let i = 0; i < this._linkableParams.length; i++) {
-            if (this._linkableParams[i].value.uid === p.uid) {
+            if (this._linkableParams[i].nub.uid === p.nub.uid) {
                 this.linkTo(i);
                 break;
-            } else {
-                i++;
             }
         }
     }
-- 
GitLab


From a7a129004b7453e21904ab16cb0cd4b4fe4940c7 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Tue, 19 Feb 2019 16:17:15 +0100
Subject: [PATCH 12/21] Fix #133

---
 src/app/formulaire/formulaire-node.ts         |  5 ++++
 .../services/formulaire/formulaire.service.ts | 23 ++++++++++++++++++-
 2 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/src/app/formulaire/formulaire-node.ts b/src/app/formulaire/formulaire-node.ts
index 627e38f7d..128f39a67 100644
--- a/src/app/formulaire/formulaire-node.ts
+++ b/src/app/formulaire/formulaire-node.ts
@@ -56,6 +56,11 @@ export abstract class FormulaireNode implements IObservable {
         return this._uid;
     }
 
+    /** utiliser uniquement pour charger des sessions (désérialisation JSON) */
+    public setUid(uid: string) {
+        this._uid = uid;
+    }
+
     /**
      * cherche un FormulaireNode par son id de conf
      */
diff --git a/src/app/services/formulaire/formulaire.service.ts b/src/app/services/formulaire/formulaire.service.ts
index b2a43ee0e..8be740fa2 100644
--- a/src/app/services/formulaire/formulaire.service.ts
+++ b/src/app/services/formulaire/formulaire.service.ts
@@ -81,6 +81,20 @@ export class FormulaireService extends Observable {
             });
     }
 
+    /**
+     * retourne true si l'uid passé en paramètre est déjà utilisé par un formulaire
+     * @param uid uid à tester
+     */
+    private formUIDAlreadyUsed(uid: string): boolean {
+        let alreadyUsed = false;
+        for (const f of this._formulaires) {
+            if (f.uid === uid) {
+                alreadyUsed = true;
+            }
+        }
+        return alreadyUsed;
+    }
+
     public updateLocalisation() {
         for (const c of EnumEx.getValues(CalculatorType)) {
             const prom: Promise<StringMap> = this.loadLocalisation(c);
@@ -149,10 +163,17 @@ export class FormulaireService extends Observable {
     /**
      * crée un formulaire d'un type donné
      * @param ct type de formulaire
-     * @param jsonState
+     * @param jsonState descripteur sérialisé du formulaire, le cal échéant
      */
     public createFormulaire(ct: CalculatorType, jsonState?: {}): Promise<FormulaireDefinition> {
         const f: FormulaireDefinition = this.newFormulaire(ct);
+        // conserver l'UID d'origine, sauf en cas de collision
+        if (jsonState !== undefined) {
+            const originalUID = jsonState["uid"];
+            if (originalUID !== undefined && ! this.formUIDAlreadyUsed(originalUID)) {
+                f.setUid(originalUID);
+            }
+        }
         this._formulaires.push(f);
 
         const prom: Promise<any> = this.loadConfig(ct);
-- 
GitLab


From f863b16e3278311a5dd8f6f9fb59a546b7feed2b Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Tue, 19 Feb 2019 16:19:31 +0100
Subject: [PATCH 13/21] Fix #50 clonage d'un module de calcul

---
 .../components/generic-calculator/calculator.component.ts    | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/app/components/generic-calculator/calculator.component.ts b/src/app/components/generic-calculator/calculator.component.ts
index 9f5a30847..806b37777 100644
--- a/src/app/components/generic-calculator/calculator.component.ts
+++ b/src/app/components/generic-calculator/calculator.component.ts
@@ -403,4 +403,9 @@ export class GenericCalculatorComponent extends BaseComponent implements OnInit,
             }
         });
     }
+
+    public cloneCalculator() {
+        const serializedForm = this._formulaire.JSONserialise()["form"];
+        this.formulaireService.deserialiseForm(serializedForm);
+    }
 }
-- 
GitLab


From a5118b15b42a1f4f5a008cb80929676eb5605839 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Tue, 19 Feb 2019 16:33:49 +0100
Subject: [PATCH 14/21] =?UTF-8?q?M=C3=A0J=20version=20package.json:=204.1.?=
 =?UTF-8?q?0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index e63f1f4b8..0ffdf2dc9 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "nghyd",
-  "version": "4.0.0",
+  "version": "4.1.0",
   "license": "MIT",
   "scripts": {
     "ng": "ng",
-- 
GitLab


From c3f54b212b9c7e414f48c9d52936795fea9f88ce Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Tue, 19 Feb 2019 16:38:06 +0100
Subject: [PATCH 15/21] =?UTF-8?q?Chargement=20d'une=20session=20avec=20par?=
 =?UTF-8?q?am=C3=A8tre=20li=C3=A9:=20protection=20contre=20formulaire=20ci?=
 =?UTF-8?q?ble=20inexistant?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/app/formulaire/ngparam.ts | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/app/formulaire/ngparam.ts b/src/app/formulaire/ngparam.ts
index 8bf3c34f7..1c82a275a 100644
--- a/src/app/formulaire/ngparam.ts
+++ b/src/app/formulaire/ngparam.ts
@@ -381,8 +381,14 @@ export class NgParameter extends InputField implements Observer {
                 this._paramValues.valueMode = ParamValueMode.LINK;
                 // formulaire dont le Nub est la cible du lien
                 const destForm = ServiceFactory.instance.formulaireService.getFormulaireFromId(uid);
-                this._paramValues.defineReference(destForm.currentNub, ref);
-                break;  // cf FormulaireService.updateParamsLinks()
+                if (destForm) {
+                    this._paramValues.defineReference(destForm.currentNub, ref);
+                } else {
+                    // @TODO et si la cible du lien n'existe pas ??
+                    // cf FormulaireService.updateParamsLinks()
+                    console.log("LA CIBLE DU LIEN N'EXISTE PAS !!");
+                }
+                break;
 
             default:
                 throw new Error(`session file : invalid value mode '${json["mode"]}' in param object`);
-- 
GitLab


From 64bf86d34243f93f358c36fa4af01d5dfbdc5c55 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Tue, 19 Feb 2019 17:01:45 +0100
Subject: [PATCH 16/21] Curseur "pointer" sur les champs d'upload de fichiers

---
 .../dialog-edit-param-values.component.html                   | 2 +-
 .../dialog-load-session/dialog-load-session.component.html    | 2 +-
 src/styles.scss                                               | 4 ++++
 3 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html
index 9ce4c7853..2720065f1 100644
--- a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html
+++ b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html
@@ -88,7 +88,7 @@
 
                 <div fxHide.xs fxFlex.gt-xs="0 0 16px"></div>
 
-                <mat-form-field class="values-file" fxFlex.gt-xs="1 0 auto" fxFlex.lt-sm="1 0 100%">
+                <mat-form-field class="values-file file-input-field" fxFlex.gt-xs="1 0 auto" fxFlex.lt-sm="1 0 100%">
                     <ngx-mat-file-input #valuesFile [placeholder]="uitextImportFile"
                         (change)="onFileSelected($event)" formControlName="file">
                     </ngx-mat-file-input>
diff --git a/src/app/components/dialog-load-session/dialog-load-session.component.html b/src/app/components/dialog-load-session/dialog-load-session.component.html
index b9f411fb7..0473b4cde 100644
--- a/src/app/components/dialog-load-session/dialog-load-session.component.html
+++ b/src/app/components/dialog-load-session/dialog-load-session.component.html
@@ -4,7 +4,7 @@
 
   <div mat-dialog-content>
 
-    <mat-form-field>
+    <mat-form-field class="file-input-field">
       <ngx-mat-file-input id="session-file-input" #sessionFile formControlName="file"[placeholder]="uitextLoadSessionFilename"
         (change)="onFileSelected($event)"></ngx-mat-file-input>
       <button mat-icon-button matSuffix *ngIf="!sessionFile.empty" (click)="sessionFile.clear($event)">
diff --git a/src/styles.scss b/src/styles.scss
index 6fdf91aec..ae70c285c 100644
--- a/src/styles.scss
+++ b/src/styles.scss
@@ -44,6 +44,10 @@ mat-form-field {
     }
 }
 
+.file-input-field {
+    cursor: pointer;
+}
+
 .eight-em-bottom-padding {
     padding-bottom: 8em;
 }
-- 
GitLab


From 7ec02b555e0301d58f9ff4735b9fcf647c0d28d8 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Wed, 20 Feb 2019 15:51:23 +0100
Subject: [PATCH 17/21] =?UTF-8?q?M=C3=A0J=20version=20package-lock.json:?=
 =?UTF-8?q?=204.1.0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 package-lock.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package-lock.json b/package-lock.json
index 5a2713b26..bead599e1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "nghyd",
-  "version": "1.2.0",
+  "version": "4.1.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
-- 
GitLab


From a3d7dade3d0192384bb181c315542a1f7a6b8cf3 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Wed, 20 Feb 2019 15:51:59 +0100
Subject: [PATCH 18/21] Ajout test e2e : clonage de module de calcul

---
 e2e/calculator.po.ts       | 40 +++++++++++++++++++++-
 e2e/clone-calc.e2e-spec.ts | 68 ++++++++++++++++++++++++++++++++++++++
 protractor.conf.js         |  1 +
 3 files changed, 108 insertions(+), 1 deletion(-)
 create mode 100644 e2e/clone-calc.e2e-spec.ts

diff --git a/e2e/calculator.po.ts b/e2e/calculator.po.ts
index be6a5eb4b..9d05454ed 100644
--- a/e2e/calculator.po.ts
+++ b/e2e/calculator.po.ts
@@ -1,4 +1,4 @@
-import { by, element, ElementFinder } from "protractor";
+import { by, element, ElementFinder, browser } from "protractor";
 
 export class CalculatorPage {
 
@@ -22,10 +22,21 @@ export class CalculatorPage {
     return element(by.css("dialog-save-session button[type=submit]"));
   }
 
+  scrollTo(elt: ElementFinder) {
+    browser.controlFlow().execute(function() {
+      browser.executeScript("arguments[0].scrollIntoView(true)", elt.getWebElement());
+    });
+  }
+
   async clickSaveCalcButton() {
     return await element(by.css("#save-calc")).click();
   }
 
+  async clickCloneCalcButton() {
+    const cloneButton = element(by.css("#clone-calc"));
+    return await cloneButton.click();
+  }
+
   async changeSelectValue(elt: ElementFinder, index: number) {
     await elt.click();
     const options = (await elt.getAttribute("aria-owns")).split(" ");
@@ -33,4 +44,31 @@ export class CalculatorPage {
     const option = element(by.id(optId));
     await option.click();
   }
+
+  // find parent element of elt having class "container"
+  async findParentContainer(elt: ElementFinder): Promise<ElementFinder> {
+    let i = 8; // garde fous
+    while ((await elt.getAttribute("class") !== "container") && (i >= 0)) {
+      elt = elt.element(by.xpath(".."));
+      i--;
+    }
+    return elt;
+  }
+
+  /**
+   * @param elt an <input> element
+   * @param mode "fix", "var", "cal" or "link"
+   */
+  async setParamMode(elt: ElementFinder, mode: string) {
+    // get parent (div.container)
+    const container = await this.findParentContainer(elt);
+    // find radio buttons
+    const button = container.element(by.css("button#radio_" + mode + "-button"));
+    await button.click();
+    // for "var" mode, close the modal
+    if (mode === "var") {
+      await browser.sleep(500);
+      await element(by.css("dialog-edit-param-values .mat-dialog-actions button")).click();
+    }
+  }
 }
diff --git a/e2e/clone-calc.e2e-spec.ts b/e2e/clone-calc.e2e-spec.ts
new file mode 100644
index 000000000..21b6206f7
--- /dev/null
+++ b/e2e/clone-calc.e2e-spec.ts
@@ -0,0 +1,68 @@
+import { AppPage } from "./app.po";
+import { ListPage } from "./list.po";
+import { CalculatorPage } from "./calculator.po";
+import { Navbar } from "./navbar.po";
+import { SideNav } from "./sidenav.po";
+import { browser } from "protractor";
+
+describe("ngHyd − clone a calculator", () => {
+  let startPage: AppPage;
+  let listPage: ListPage;
+  let calcPage: CalculatorPage;
+  let navbar: Navbar;
+  let sidenav: SideNav;
+
+  beforeEach(() => {
+    startPage = new AppPage();
+    listPage = new ListPage();
+    calcPage = new CalculatorPage();
+    navbar = new Navbar();
+    sidenav = new SideNav();
+  });
+
+  it("when cloning a calculator, the clone should have the same values for all parameters", async () => {
+    await startPage.navigateTo();
+
+    // 1. create target modules for linked parameter
+    await listPage.clickMenuEntryForCalcType(3); // Régime uniforme
+    await browser.sleep(500);
+    const debitRU = calcPage.getInputById("calc_Q"); // "Débit" is calculated by default
+    await calcPage.setParamMode(debitRU, "fix");
+    await browser.sleep(500);
+
+    await navbar.clickNewCalculatorButton();
+    await listPage.clickMenuEntryForCalcType(4); // Courbe de remous
+    await browser.sleep(500);
+
+    // 2. create source module to clone
+    await navbar.clickNewCalculatorButton();
+    await listPage.clickMenuEntryForCalcType(2); // Section paramétrée
+    await browser.sleep(500);
+
+    // 3. change and store source parameter values
+    const sourceValues = {
+      k: 0.6,
+      Ks: 42
+    };
+    // await calcPage.changeSelectValue(calcPage.getSelectById("select_section"), 3); // mode "parabolique"
+    // await calcPage.getInputById("k").clear();
+    // await calcPage.getInputById("k").sendKeys(sourceValues["k"]);
+    await calcPage.getInputById("Ks").clear();
+    await calcPage.getInputById("Ks").sendKeys(sourceValues["Ks"]);
+    // link "Débit" to "Courbe de remous"
+    const debitSP = calcPage.getInputById("Q");
+    await calcPage.setParamMode(debitSP, "link");
+    await browser.sleep(500);
+    await calcPage.changeSelectValue(calcPage.getSelectById("linked_Q"), 1); // "Courbe de remous"
+    await browser.sleep(500);
+
+    // otherwise clickCloneCalcButton() fails with "Element is not clickable at point"
+    await browser.executeScript("window.scrollTo(0, 0);");
+    await calcPage.clickCloneCalcButton();
+    await browser.sleep(500);
+    // 4. check the cloned module
+    expect(await navbar.getAllCalculatorTabs().count()).toBe(4);
+    await navbar.clickCalculatorTab(3); // n°3 should be the latest
+
+  });
+});
diff --git a/protractor.conf.js b/protractor.conf.js
index 8d5700529..a4cc5bdba 100644
--- a/protractor.conf.js
+++ b/protractor.conf.js
@@ -33,5 +33,6 @@ exports.config = {
       project: 'e2e/tsconfig.e2e.json'
     });
     jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
+    browser.manage().window().setSize(1600, 1000);
   }
 };
-- 
GitLab


From 82a98af7a76b73755e4f61d744268449fcdc6d2c Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Wed, 20 Feb 2019 15:52:23 +0100
Subject: [PATCH 19/21] ID des modules de calcul : protection contre undefined

---
 .../components/generic-calculator/calculator.component.ts   | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/app/components/generic-calculator/calculator.component.ts b/src/app/components/generic-calculator/calculator.component.ts
index 806b37777..e8c970323 100644
--- a/src/app/components/generic-calculator/calculator.component.ts
+++ b/src/app/components/generic-calculator/calculator.component.ts
@@ -88,7 +88,11 @@ export class GenericCalculatorComponent extends BaseComponent implements OnInit,
     private formulaireService: FormulaireService;
 
     public get ID() {
-        return this._formulaire.uid;
+        if (this._formulaire) {
+            return this._formulaire.uid;
+        } else {
+            return "calculator_1";
+        }
     }
 
     constructor(
-- 
GitLab


From ec03eb10972b9063f329ad84032ad604e6781535 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Wed, 20 Feb 2019 15:54:01 +0100
Subject: [PATCH 20/21] =?UTF-8?q?D=C3=A9s=C3=A9rialisation=20des=20<select?=
 =?UTF-8?q?>=20:=20mini=20modif?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/app/formulaire/select-field.ts | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/app/formulaire/select-field.ts b/src/app/formulaire/select-field.ts
index 3bfadc6cf..a8162bac4 100644
--- a/src/app/formulaire/select-field.ts
+++ b/src/app/formulaire/select-field.ts
@@ -43,6 +43,7 @@ export class SelectField extends Field {
 
     public setValue(v: SelectEntry) {
         if (this._selectedEntry !== v) {
+            console.log("++++ select field : notify observers", v);
             this._selectedEntry = v;
             this.notifyObservers({
                 "action": "select",
@@ -145,7 +146,7 @@ export class SelectField extends Field {
                     const sel = elements[k];
                     for (const e of this._entries) {
                         if (e.id === sel) {
-                            this._selectedEntry = e;
+                            this.setValue(e);
                             break;
                         }
                     }
-- 
GitLab


From b33cb9a858dd8121ccdbb941e017d4c8763544ee Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Wed, 20 Feb 2019 15:54:30 +0100
Subject: [PATCH 21/21] =?UTF-8?q?Suppression=20imports=20inutilis=C3=A9s?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/app/formulaire/definition/form-def-section.ts | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/src/app/formulaire/definition/form-def-section.ts b/src/app/formulaire/definition/form-def-section.ts
index f4fe312ca..9ad2dbf71 100644
--- a/src/app/formulaire/definition/form-def-section.ts
+++ b/src/app/formulaire/definition/form-def-section.ts
@@ -1,10 +1,3 @@
-import {
-    ComputeNodeType, ParamsSectionTrapez, cSnTrapez, ParamsSectionRectang, cSnRectang,
-    ParamsSectionCirc, cSnCirc, ParamsSectionPuiss, cSnPuiss, acSection, ParamsEquation
-} from "jalhyd";
-
-import { SelectField } from "../select-field";
-import { Field } from "../field";
 import { NgParameter, ParamRadioConfig } from "../ngparam";
 import { FormulaireDefinition } from "./form-definition";
 import { FieldSet } from "../fieldset";
-- 
GitLab