| import { AppBase } from '../libappbase/appbase'; | 
| import { | 
|   ActionBarPageData, | 
|   ActionBarPageDevelop, | 
|   ActionBarPageHome, | 
|   ActionBarPageInventory, | 
|   ActionBarPageScenario, | 
|   ActionBarPageScenarioAnalysis, | 
|   ActionBarPagePlan, | 
|   ActionBarPageScenarioSelection, | 
|   ActionBarPageSales, | 
|   ActionBarPageScenarioComparison, | 
|   ActionBarPageWorkflow, | 
| } from './actionbarpages'; | 
| import { DialogSelectDemoDataset } from './dialogs/dialog.demodataset'; | 
| import { DialogStrategy } from './dialogs/dialog.strategy'; | 
| import { FormKPI, GaugeIDValueMap, ListKPISelectionContextMenuItem } from './forms/form.kpi'; | 
| import { FormNavigationPanel } from './forms/navigationpanel/form.navigationpanel'; | 
| import { | 
|   ViewAccount, | 
|   ViewEntity, | 
|   ViewExternalSupplies, | 
|   ViewInventoryCosts, | 
|   ViewOperationCost, | 
|   ViewStockingCost, | 
|   ViewUnitCost, | 
|   ViewOptimizerStrategies, | 
|   ViewCurrency, | 
|   ViewPeriod, | 
|   ViewScenarioAnalysisCost, | 
|   ViewScenario, | 
|   ViewSupplyPlanning, | 
|   ViewProduct, | 
|   ViewGeneralSettings, | 
|   ViewCampaignsAndTransitions, | 
|   ViewCampaigns, | 
|   ViewStockCapacity, | 
|   ViewSalesSegments, | 
|   ViewUnitsOfMeasure, | 
|   ViewScenarioAnalysisOverview, | 
|   ViewRecipes, | 
|   ViewCapacitiesTime, | 
|   ViewCapacitiesQuantity, | 
|   ViewCapacitiesStockingPoints, | 
|   ViewScenarioComparisonCost, | 
|   ViewForecasts, | 
|   ViewCustomerOrders, | 
|   ViewFeedback, | 
|   ViewProductionPlan, | 
|   ViewSupplyCost, | 
|   ViewCalendar, | 
|   ViewTripPlan, | 
|   ViewPurchasingPlan, | 
|   ViewTransportationCost, | 
|   ViewBlendingPlan, | 
|   ViewRouting, | 
| } from './views'; | 
| import { DataKPIName, DataKPIPercentage } from '../libmp/data/data.kpi'; | 
| import { by, ElementFinder } from '../e2elib/node_modules/protractor/built'; | 
| import { ListScenarioContextMenuItem, ScenarioManager } from './forms/form.scenario'; | 
| import { ViewBase } from '../libappbase/viewbase'; | 
| import { UIWaitSOP } from '../libappsop/objectsop'; | 
| import { DropDownListSOP } from '../libappsop/dropdownlistsop'; | 
| import { ButtonSOP } from '../libappsop/buttonsop'; | 
| import { ViewScenarioAnalysisUnitCapacity } from './views/view.scenarioanalysis.unitcapacity'; | 
| import { ViewScenarioAnalysisBottleneckResources } from './views/view.scenarioanalysis.bottleneckresources'; | 
|   | 
| export class AppMP extends AppBase { | 
|   private static _appMP: AppMP; | 
|   | 
|   // Action bar page | 
|   public abpDevelop = new ActionBarPageDevelop(); | 
|   public abpInventory = new ActionBarPageInventory(); | 
|   public abpScenario = new ActionBarPageScenario(); | 
|   public abpPlan = new ActionBarPagePlan(); | 
|   public abpHome = new ActionBarPageHome(); | 
|   public abpScenarioAnalysis = new ActionBarPageScenarioAnalysis(); | 
|   public abpScenarioSelection = new ActionBarPageScenarioSelection(); | 
|   public abpSales = new ActionBarPageSales(); | 
|   public abpData = new ActionBarPageData(); | 
|   public abpScenarioComparison = new ActionBarPageScenarioComparison(); | 
|   public abpWorkflow = new ActionBarPageWorkflow(); | 
|   | 
|   // Views | 
|   public viewScenario = new ViewScenario(); | 
|   public viewCustomerOrders = new ViewCustomerOrders(); | 
|   public viewCurrency = new ViewCurrency(); | 
|   public viewExternalSupplies = new ViewExternalSupplies(); | 
|   public viewOptimizerStrategies = new ViewOptimizerStrategies(); | 
|   public viewUnitCost = new ViewUnitCost(); | 
|   public viewSupplyPlanning = new ViewSupplyPlanning(); | 
|   public viewInventoryCosts = new ViewInventoryCosts(); | 
|   public viewAccount = new ViewAccount(); | 
|   public viewEntity = new ViewEntity(); | 
|   public viewForecasts = new ViewForecasts(); | 
|   public viewOperationCost = new ViewOperationCost(); | 
|   public viewStockingCost = new ViewStockingCost(); | 
|   public viewSupplyCost = new ViewSupplyCost(); | 
|   public viewScenarioAnalysisOverview = new ViewScenarioAnalysisOverview(); | 
|   public viewScenarioAnalysisCost = new ViewScenarioAnalysisCost(); | 
|   public viewPeriod = new ViewPeriod(); | 
|   public viewProduct = new ViewProduct(); | 
|   public viewRecipes = new ViewRecipes(); | 
|   public viewGeneralSettings = new ViewGeneralSettings(); | 
|   public viewCampaignsAndTransitions = new ViewCampaignsAndTransitions(); | 
|   public viewCampaign = new ViewCampaigns(); | 
|   public viewFeedback = new ViewFeedback(); | 
|   public viewStockCapacity = new ViewStockCapacity(); | 
|   public viewSalesSegments = new ViewSalesSegments(); | 
|   public viewUnitsOfMeasure = new ViewUnitsOfMeasure(); | 
|   public viewCapacitiesTime = new ViewCapacitiesTime(); | 
|   public viewScenarioAnalysisUnitCapacity = new ViewScenarioAnalysisUnitCapacity(); | 
|   public viewScenarioAnalysisBottleneckResources = new ViewScenarioAnalysisBottleneckResources(); | 
|   public viewCapacitiesQuantity = new ViewCapacitiesQuantity(); | 
|   public viewCapacitiesStockingPoints = new ViewCapacitiesStockingPoints(); | 
|   public viewScenarioComparisonCost = new ViewScenarioComparisonCost(); | 
|   public viewCalendar = new ViewCalendar(); | 
|   public viewProductionPlan = new ViewProductionPlan(); | 
|   public viewTripPlan = new ViewTripPlan(); | 
|   public viewPurchasingPlan = new ViewPurchasingPlan(); | 
|   public viewTransportationCost = new ViewTransportationCost(); | 
|   public viewBlendingPlan = new ViewBlendingPlan(); | 
|   public viewRouting = new ViewRouting(); | 
|   | 
|   // Forms | 
|   public frmKPI = new FormKPI(); | 
|   public formNavigation = new FormNavigationPanel(); | 
|   | 
|   // Dialogs | 
|   public dlgDemoDataset = new DialogSelectDemoDataset(); | 
|   public dlgStrategy = new DialogStrategy(); | 
|   | 
|   // UI elements at fixed action bar (top right) | 
|   public btnCreateAssumption = new ButtonSOP('ButtonCreateAssumption'); | 
|   public btnUndo = new ButtonSOP('buttonUndo'); | 
|   public ddlActiveScenario = new DropDownListSOP('DropDownListScenario'); // Shows current selected/active scenario | 
|   | 
|   // Get singleton instance of AppMP | 
|   public static getInstance(): AppMP { | 
|     if (AppMP._appMP === undefined) { | 
|       AppMP._appMP = new AppMP(); | 
|     } | 
|   | 
|     return AppMP._appMP; | 
|   } | 
|   | 
|   /** | 
|    * Copied from e2elib qinputtype as the logic is bugged (not able retrieve action link text) | 
|    * Retrieve action link text of input component such as editfield, etc | 
|    * Remove once e2elib fixes the bug | 
|    * | 
|    * @param element ElementFinder of input component to retrieve action link text | 
|    * @returns Action link text | 
|    */ | 
|   public static async getActionLinkText(element: ElementFinder): Promise<string> { | 
|     const elem = element.element(by.css('.qActionLink')); | 
|   | 
|     return elem.isPresent().then((ispresent: boolean) => { | 
|       if (ispresent) { | 
|         // Original code from e2elib which is bugged (as actionlinktext is always empty, the actual text is contained within child button html node) | 
|         // return element.getAttribute('actionlinktext'); | 
|         return elem.getText(); | 
|       } else { | 
|         return ''; | 
|       } | 
|     }); | 
|   } | 
|   | 
|   /** | 
|    * Returns the step to create demo data for spec file "it" description. | 
|    * | 
|    * @param demoType Demo data such as Metal, Food, etc. | 
|    * @param scenario The scenario within the demo data (e.g Base) | 
|    * @returns The step informing which UI to use and which demo data to be used | 
|    */ | 
|   public static getDemoDataPath(demoType: string, scenario: string): string { | 
|     return `Open ${AppMP.getInstance().abpDevelop.startDemoPath}, select ${demoType} demo and ${scenario} scenario`; | 
|   } | 
|   | 
|   // To avoid initialization externally | 
|   private constructor() { | 
|     super(); | 
|   } | 
|   | 
|   /** | 
|    * Create demo dataset in MP | 
|    * | 
|    * @param demo type of demo, types could be Food or Metals | 
|    * @param scenario type of scenario | 
|    * @param needWaitOptimizerComplete Default true to wait for optimizer run completion by checking fulfillment target KPI = 100% | 
|    * @example await createDemoDataset('Food', 'Base') | 
|    */ | 
|   public async createDemoDataset(demo: string, scenario: string, needWaitOptimizerComplete: boolean = true): Promise<void> { | 
|     // wait until abp develop is visible | 
|     await this.abpDevelop.isVisible(); | 
|     // Open Develop action bar page | 
|     await this.abpDevelop.click(); | 
|     // Click on the Start Demo button | 
|     await this.abpDevelop.btnStartDemo.click(); | 
|     // Wait until Start Demo Dialog is present | 
|     await this.dlgDemoDataset.waitUntilPresent(); | 
|   | 
|     await this.dlgDemoDataset.selectDemoDataset(demo, scenario); | 
|   | 
|     if (needWaitOptimizerComplete) { | 
|       // Wait until the optimizer run finished by verifying KPI Fulfillment Target = 100.0% | 
|       const gaugeValueMap: GaugeIDValueMap[] = [{ gaugeName: DataKPIName.FulfillmentTarget, value: DataKPIPercentage._100_0 }]; | 
|       await this.waitForKPICompletion(gaugeValueMap); | 
|     } | 
|   } | 
|   | 
|   /** | 
|    * Use in each spec's afterall() to cleanup demo datasets and logout. | 
|    */ | 
|   public async cleanupAndLogout(): Promise<void> { | 
|     const excludeDeleteScenarioWithPrefix = 'ADSO-'; // Not to delete scenario with this prefix, reused for few tests | 
|   | 
|     // Delete all datasets | 
|     await this.viewScenario.switchTo(); | 
|     await this.viewScenario.formScenario.lstScenario.deleteAllScenarios(ScenarioManager.AllScenarios, excludeDeleteScenarioWithPrefix); | 
|     await this.viewScenario.formScenario.lstScenario.deleteAllScenarios(ScenarioManager.RecycleBin); | 
|     await this.logout(); | 
|   } | 
|   | 
|   /** | 
|    * Open Scenario view and select scenario as active. | 
|    * | 
|    * @param scenarioName Scenario name to set as active. | 
|    */ | 
|   public async selectScenario(scenarioName: string): Promise<void> { | 
|     await this.viewScenario.switchTo(); | 
|     await this.viewScenario.formScenario.lstScenario.expandFolderAndSelectMenu(scenarioName, ListScenarioContextMenuItem.Select); | 
|   } | 
|   | 
|   /** | 
|    * Quick way to select active scenario via top right dropdown which is accesible in all views. | 
|    * Caveat is the scenario name must be unique to use this method. | 
|    * | 
|    * @param scenarioName Scenario name to select. | 
|    */ | 
|   public async selectScenarioViaDropdown(scenarioName: string): Promise<void> { | 
|     await this.ddlActiveScenario.selectItemSOP(scenarioName); | 
|     await this.verifyActiveScenario(scenarioName); | 
|   } | 
|   | 
|   /** | 
|    * Verify if active scenario dropdown (top right) is showing the correct scenario. | 
|    * | 
|    * @param name Expected scenario name to be active. | 
|    */ | 
|   public async verifyActiveScenario(name: string): Promise<void> { | 
|     expect(await this.ddlActiveScenario.getSelectedString()).toBe(name, `Expected scenario '${name}' to be selected in active scenario dropdown (top right).`); | 
|   } | 
|   | 
|   /** | 
|    * Open view Scenario Analyisis > Costs, and ensure the target KPI(s) reaches the expected value | 
|    * | 
|    * @param targetKPI target KPI and its expected value | 
|    */ | 
|   public async waitForKPICompletion(targetKPI: GaugeIDValueMap[]): Promise<void> { | 
|     // Open view Scenario Analysis > Costs | 
|     await this.viewScenarioAnalysisCost.switchTo(); | 
|     // Open KPI Selection panel | 
|     await this.frmKPI.openKPISelectionPanel(); | 
|     // Deselect all KPI | 
|     await this.frmKPI.panelKPISelection.lstKPISelection.deselectAllKPI(); | 
|   | 
|     // Select KPI in KPI selection list | 
|     for (const map of targetKPI) { | 
|       const row = await this.frmKPI.panelKPISelection.lstKPISelection.getRow({ Name: map.gaugeName }); | 
|       await this.frmKPI.panelKPISelection.lstKPISelection.selectContextMenu(ListKPISelectionContextMenuItem.Select, row); | 
|     } | 
|     // Open KPI dashboard panel | 
|     await this.frmKPI.openKPIDashboardPanel(); | 
|   | 
|     // Wait until the KPI reaches the expected value | 
|     for (const map of targetKPI) { | 
|       await this.frmKPI.panelKPIDashboard.gaugeKPIDashboard.waitForKPI(map.gaugeName, map.value); | 
|     } | 
|     // Reset view Scenario Analysis > Costs | 
|     await this.resetActiveView(this.viewScenarioAnalysisCost); | 
|   } | 
|   | 
|   /** | 
|    * Reset active view via Home action bar page. This much faster than opening view manager and search the list to reset. | 
|    * Local test faster by ~20 seconds which is significant saving. | 
|    * If use this (compare to the base Reset in ViewBase), ensure reset before opening new view as reset is always on current active view. | 
|    * | 
|    * @param view View to reset which should implement @interface UIWaitSOP | 
|    */ | 
|   public async resetActiveView(view: ViewBase): Promise<void> { | 
|     await this.abpHome.click(); | 
|     await this.abpHome.btnResetActiveView.click(); | 
|   | 
|     const viewImplementWaitSOP = view as unknown as UIWaitSOP; // Need cast to unknown before able check if implement interface UIWaitSOP | 
|     if (viewImplementWaitSOP) { | 
|       await viewImplementWaitSOP.waitUILoaded(); | 
|     } | 
|   } | 
| } | 
|   | 
| export enum Demo { | 
|   Food = 'Food', | 
|   Metals = 'Metals', | 
| } | 
|   | 
| export enum Scenario { | 
|   Base = 'Base', | 
|   FoodBaseWithRecall = 'Base + recall', | 
| } | 
|   | 
| export enum Timeout { | 
|   Short = 10000, | 
|   Medium = 30000, | 
|   Long = 60000, | 
|   ButtonState = 1000, | 
| } | 
|   | 
| /** | 
|  * Image attribute names common to all lists. | 
|  */ | 
| export enum ImageAttribute { | 
|   IsEmpty = 'EMPTY', // No image attribute | 
|   IsDefault = 'FLASH', // Default row in list (used by currency and UoM for now) | 
| } | 
|   | 
| export enum QuintiqUser { | 
|   Administrator = 'administrator', | 
|   QuintiqService = 'svc_qtq.sqc', // Admin user in the pipeline (created by DevOps for all teams) | 
| } | 
|   | 
| // Step description to re-use in spec file to prevent scriptor re-write each time | 
| const stepAppMP = { | 
|   loginAs: (user: string): string => `Login as "${user}".`, | 
|   logout: (): string => 'Logout from the application.', | 
|   selectScenario: (scenarioName: string): string => | 
|     `Open view ${AppMP.getInstance().viewScenario.viewPath}. Right click scenario '${scenarioName}' and click menu ${ | 
|       ListScenarioContextMenuItem.Select.Label | 
|     } to set as active scenario.`, | 
|   selectScenarioViaDropdown: (scenarioName: string): string => `In fixed action bar (top right), select active scenario = ${scenarioName}.`, | 
| }; | 
|   | 
| export { stepAppMP as StepAppMP }; |