-
David Dorchies authored
Refs #609
David Dorchies authoredRefs #609
calculator.po.ts 18.46 KiB
import { scrollPageToTop, scrollToElement } from "./util.po";
import { browser, $, $$, expect } from '@wdio/globals'
import { Key } from 'webdriverio'
export class CalculatorPage {
getInputLabels() {
return $$("ngparam-input input:not([disabled]) label");
}
getParamInputs() {
return $$("ngparam-input input.form-control");
}
async getParamInputsHavingCalcMode() {
const ret = [];
const inputs = await $$("param-field-line");
for (const inp of inputs) {
const toggle = await inp.$("mat-button-toggle.radio_cal > button");
if (await toggle.isExisting()) {
ret.push(inp);
}
}
return ret;
}
getHeader1() {
return $("h1");
}
/**
* return all selects in the calculator which id is in the form "select_*"
*/
getAllCalculatorSelects() {
return $$("mat-select[id^=select_]"); // all mat-select with id starting with "select_"
}
/**
* return select count which id is in the form "select_*"
*/
async getCalculatorSelectCount() {
const sels = await $$("mat-select[id^=select_]"); // all mat-select with id starting with "select_"
return sels.length;
}
/**
* get the option count of a select
*/
async getMatselectOptionCount(select) {
const sel = typeof (select) === "string" ? $(`#${select}`) : select;
await scrollToElement(sel);
if ((await sel.isExisting()) && (await sel.isDisplayed())) {
await sel.click();
const options = await $$(".cdk-overlay-container mat-option");
await browser.keys(Key.Escape); // close dropdown
return await options.length;
}
}
/**
* get the text of the all given select options
*/
async getMatselectOptionsText(select) {
const sel = typeof (select) === "string" ? await $(`#${select}`) : select;
await scrollToElement(sel);
await browser.pause(200);
if ((await sel.isExisting()) && (await sel.isDisplayed())) {
await sel.click();
await browser.pause(500);
const options = await $$(".cdk-overlay-container mat-option span");
let res = [];
const nopt = options.length;
for (let o = 0; o < nopt; o++) {
const opt = options[o];
res.push(await opt.getText())
}
await browser.keys(Key.Escape); // close dropdown
await browser.pause(500);
return res;
}
}
/**
* get select current option
*/
async getSelectCurrentOption(select) {
const id = await select.getAttribute("id");
return $("mat-select#" + id + " div[id^=mat-select-value-]");
}
/**
* get text of select current option
*/
async getMatselectCurrentOptionText(select): Promise<string> {
const currentOption = await this.getSelectCurrentOption(select);
await browser.pause(100);
const opt = await currentOption.$("span span");
await browser.pause(100);
const res = await opt.getText();
await browser.pause(100);
return res;
}
getSelectById(id: string) {
// return $(`#${id}`);
return $(`mat-select[id='${id}']`); // IDs cannot start by a number, so use this query form
}
async isMatSelectPresent(id: string) {
const sel = await $("mat-select#" + id);
return await sel.isExisting();
}
async getSelectValueText(select) {
const span = await select.$(".mat-select-value-text > span");
return await span.getText();
}
async isSelectEmpty(select) {
try {
const text = select.$(".mat-select-value-text > span");
await text.getAttribute("outerHTML"); // await anything trigger the error
return false;
} catch (e) { // should be NoSuchElementError
return true;
}
}
getInputById(id: string) {
// return $(`#${id}`);
return $(`input[id='${id}']`); // IDs cannot start by a number, so use this query form
}
getNgInputById(id: string) {
return $(`ngparam-input input[id='${id}']`); // IDs cannot start by a number, so use this query form
}
getSaveSessionButton() {
return $("dialog-save-session button[type=submit]");
}
getCalculateButton() {
return this.getButton("trigger-calculate");
}
getGeneratePabButton() {
return this.getButton("generate-pab");
}
getButton(id: string) {
return $(`button#${id}`);
}
getCheckedCalcModeButtons() {
return $$(`mat-button-toggle.radio_cal[ng-reflect-checked="true"]`);
}
getAddStructureButton() {
return $("fieldset-container .hyd-window-btns button.add-structure");
}
getCopyStructureButton() {
return $("fieldset-container .hyd-window-btns button.copy-structure");
}
getAllLinkButtons() {
return $$("mat-button-toggle.radio_link");
}
getPabResultsTable() {
return $(".pab-results-table-inner-container table");
}
getVariatedResultsTable() {
return $(".var-results-inner-container table");
}
getAllVariatedResultsTableHeaders() {
return $$("fixedvar-results var-results table thead th");
}
getAllVariatedResultsRows() {
return $$("fixedvar-results var-results table tbody tr");
}
getFixedResultsTable() {
return $(".fixed-results-inner-container table");
}
getAllFixedResultsRows() {
return $$("fixed-results table tbody tr");
}
/** return nth <tr> of given <table>, starting at 1 */
getNthRow(table, n: number) {
return table.$("tbody > tr:nth-of-type(" + n + ")");
}
/** return nth <td> of given <tr>, starting at 1 */
getNthColumn(tr, n: number) {
return tr.$("td:nth-of-type(" + n + ")");
}
async isNgParamPresent(id: string) {
const inp = await this.getNgInputById(id);
return await inp.isExisting();
}
/**
* find parameter mode radio button linked to an input
*/
async getInputRadioButton(input, mode: string) {
const tag = await input.getTagName();
await browser.pause(100);
const root = tag === "input" ? await this.findParentContainer(input) : input;
return await root.$(`mat-button-toggle.radio_${mode}`);
}
/**
* find parameter mode radio button linked to an input
*/
async getInputRadioButtonFromId(id, mode) {
const input = await this.getInputById(id);
return await this.getInputRadioButton(input, mode);
}
async inputHasCalcModeButton(input) {
const button = await this.getInputRadioButton(input, "cal");
return await button.isExisting();
}
async inputHasLinkModeButton(input) {
const button = await this.getInputRadioButton(input, "link");
return await button.isExisting();
}
async isRadioButtonChecked(radio) {
if (await radio.getTagName() !== "mat-button-toggle") {
radio = await this.getParentElement(radio);
}
const a = await radio.getAttribute("ng-reflect-checked");
return a === "true";
}
/**
* @returns true if "fixed mode" button linked to an input is selected
*/
async inputIsInFixedMode(input): Promise<boolean> {
const button = await this.getInputRadioButton(input, "fix");
return (await button.getAttribute("ng-reflect-checked")) === "true";
}
/**
* @returns true if "calculated mode" button linked to an input is selected
*/
async inputIsInCalculatedMode(input): Promise<boolean> {
const button = await this.getInputRadioButton(input, "cal");
return (await button.getAttribute("ng-reflect-checked")) === "true";
}
/**
* @returns true if "linked mode" button linked to an input is selected
*/
async inputIsInLinkedMode(input): Promise<boolean> {
const button = await this.getInputRadioButton(input, "link");
return (await button.getAttribute("ng-reflect-checked")) === "true";
}
async hasResults() {
return (await (this.presentAndVisible("fixedvar-results fixed-results > .fixed-results-container"))
||
(await this.presentAndVisible("fixedvar-results results-chart > chart-results-container"))
||
(await this.presentAndVisible("section-results fixed-results > .fixed-results-container"))
||
(await this.presentAndVisible("remous-results #main-chart"))
||
(await this.presentAndVisible("pab-results pab-results-table"))
||
(await this.presentAndVisible("pb-results pb-results-table"))
||
await this.presentAndVisible("pb-results pb-cloison-results")
||
await this.presentAndVisible("macrorugo-compound-results macrorugo-compound-results-table")
||
(await this.presentAndVisible("jet-results .fixed-results-container")));
}
async presentAndVisible(selector: string) {
const elt = await $(selector);
const res = (await elt.isExisting()) && (await elt.isDisplayed());
return res;
}
/**
* For a given <table> element, check that values of all cells of all rows in <tbody> are
* different from "NaN", "ERR" and optionally ""
* @param table a <table> ElementFinder
* @param allowEmpty if true, empty "" values will be considered valid
*/
async allRowsHaveValidResults(table, allowEmpty: boolean = false): Promise<boolean> {
let n = 0;
let ok = true;
const invalidValues = ["ERR", "NaN"];
if (!allowEmpty) {
invalidValues.push("");
}
const nbCols = await table.$$("thead th").length;
const rows = await table.$$("tbody tr");
for (const row of rows) {
for (let i = 0; i < nbCols; i++) {
// get i_th column of n_th row
const val = await row.$("td:nth-of-type(" + (i + 1) + ")").getText();
// console.log(`TABLE VAL ${n}/${i}=>`, val);
ok = ok && !invalidValues.includes(val);
}
n++;
}
return ok;
}
/**
* Returns true if this.hasResults() is true, and if results table are
* not empty and contain only valid values (no "NaN", no "", no "ERR")
*/
async hasValidResults(): Promise<boolean> {
let ok = false;
if (await this.hasResults()) {
ok = true;
// check fixed results
const frt = this.getFixedResultsTable();
if ((await frt.isExisting()) && (await frt.isDisplayed())) {
ok = ok && (await this.allRowsHaveValidResults(frt));
}
// check variated results
const vrt = this.getVariatedResultsTable();
if ((await vrt.isExisting()) && (await vrt.isDisplayed())) {
ok = ok && (await this.allRowsHaveValidResults(vrt));
}
// check PAB results
const prt = this.getPabResultsTable();
if ((await prt.isExisting()) && (await prt.isDisplayed())) {
ok = ok && (await this.allRowsHaveValidResults(prt, true));
}
}
return ok;
}
async hasLog() {
return (await this.nbLogEntries()) > 0;
}
async nbLogEntries() {
return await $$("log-entry").length;
}
/**
* return true if the nth log entry is an error
*/
async nthLogEntryIsError(n: number) {
const errs = await $$("log-entry");
const e = errs[n];
const icon = await e.$("div mat-icon");
const style = await icon.getAttribute("style");
return style.indexOf("color: red;") !== -1;
}
/**
* return true if the nth log entry is a warning
*/
async nthLogEntryIsWarning(n: number) {
const errs = await $$("log-entry");
const e = errs[n];
const icon = await e.$("div mat-icon");
const style = await icon.getAttribute("style");
return style.indexOf("color: orange;") !== -1;
}
async clickSaveCalcButton() {
await scrollPageToTop();
return await $("#save-calc").click();
}
async clickCloneCalcButton() {
const cloneButton = await $("#clone-calc");
await scrollToElement(cloneButton);
await cloneButton.click();
}
// check that "compute" button is in given enabled/disabled state
async checkCalcButtonEnabled(enabled: boolean) {
const calcButton = await this.getCalculateButton();
expect(await calcButton.isEnabled()).toBe(enabled);
return calcButton;
}
async getParentElement(elt) {
return elt.$("..");
}
// find parent element of elt having class "container"
async findParentContainer(elt) {
let i = 8; // garde fous
while (((await elt.getAttribute("class")) !== "container") && (i >= 0)) {
elt = await this.getParentElement(elt)
i--;
}
return elt;
}
async logElement(elt, attr = undefined) {
console.log("ELT TAG", await elt.getTagName());
console.log("ELT ID", await elt.getAttribute("id"));
console.log("ELT CLASS", await elt.getAttribute("class"));
// console.log("ELT VALUE '" + await elt.getAttribute("value") + "'");
console.log("ELT VALUE '" + await elt.getValue() + "'");
console.log("ELT TEXT '" + await elt.getText() + "'");
if (attr !== undefined) {
console.log(`ELT ATTR '${attr}'='${await elt.getAttribute(attr)}'`);
}
}
async logParamFieldLine(pfl) {
await this.logElement(pfl);
const inp = await pfl.$("ngparam-input input.form-control");
await this.logElement(inp)
}
/**
* @param paramFieldLine an <input> element
* @param mode "fix", "var", "cal" or "link"
*/
async setParamMode(elt, mode: string) {
await scrollToElement(elt);
await browser.pause(100);
const button = await this.getInputRadioButton(elt, mode);
await button.click();
// for "var" mode, close the modal
if (mode === "var") {
await browser.pause(500); // wait for the modal to appear
//await element(by.css("dialog-edit-param-values .mat-dialog-actions button")).click(); // clique "annuler" et non "valider" :
const cancelBtn = await $("dialog-edit-param-values .mat-dialog-actions button.mat-warn");
await cancelBtn.click();
await browser.pause(500); // wait for the navbar to reappear after modal dismissal
} else {
await browser.pause(200);
}
}
/**
* @param elt an <input> element
*/
async getLinkedValueSelect(elt) {
// get parent (div.container)
const container = await this.findParentContainer(elt);
// find <select>
const select = container.$("param-link mat-select");
return select;
}
/**
* Returns an object containing all the calculator's inputs values, indexed
* by parameter ID
*/
async storeAllInputValues() {
const inputs = await this.getParamInputs();
const values = {};
for (const i of inputs) {
const inputId = await i.getAttribute("id");
const inputValue = await i.getValue();
values[inputId] = +inputValue; // cast to number to avoid false negative (integers starting with 0)
};
return values;
}
/**
* Modifies all the calculator's editable inputs values by adding a random digit other than 0 at the end
*/
async modifyAllInputValues() {
const inputs = await this.getParamInputs();
for (const i of inputs) {
if (await i.isDisplayed()) {
// N in YAXN child of SPP module must not be float
const id = await i.getAttribute("id");
const isN = id.includes("_N"); // @TODO strengthen this clodo test
// Ob in Grille is set to 0.5 but cannot exceed 0.58; do not touch it
const isOb = id === "Ob";
const value = await i.getValue();
const hasDot = value.includes(".");
const hasExponent = value.includes("e");
let keys = "" + (Math.floor(Math.random() * 9) + 1);
if (!hasDot && !hasExponent && !isN) {
keys = "." + keys;
}
if (!isOb && (await i.getAttribute("disabled")) === null) {
await i.addValue(keys);
}
}
};
}
/**
* check that an input is empty
* @param id input id (parameter name)
* @param empty true to check input is empty, false to check it is NOT empty
*/
async checkEmptyInput(id: string, empty: boolean = true) {
const inp = await this.getInputById(id);
const val = await inp.getValue()
if (empty) {
expect(val).toEqual("");
}
else {
expect(val).not.toEqual("");
}
}
/**
* check that a input set is in a given (empty/filled) state
* @param inputIds id of the inputs to check
* @param emptys empty/not empty state array
*/
async checkEmptyOrFilledFields(inputIds: string[], emptys: boolean[]) {
let n = 0;
for (const id of inputIds) {
const inp = await this.getInputById(id);
const txt = await inp.getValue();
expect(txt === "").toEqual(emptys[n]);
n++;
}
}
/**
* get help button related to calculator
*/
getCalculatorHelpButton() {
return $("#help-calc");
}
/**
* reliable input clearing
*/
async clearInput(inp) {
await inp.click(); // make input get focus for browser.keys() to send key sequence to it
const txt = await inp.getValue();
const len = txt.length;
for (let n = 0; n < len; n++) {
await browser.keys(Key.Backspace);
}
}
async closeSnackBar() {
const sb = await $("simple-snack-bar button");
if ((await sb.isExisting()) && (await sb.isDisplayed())) {
await sb.click();
return true;
}
return false;
}
async closeSnackBars(n: number, pause: number) {
let stop: boolean;
do {
stop = !await this.closeSnackBar();
await browser.pause(pause);
n--;
} while (n > 0 && !stop);
}
}