| /** | 
|  * @file        S&OP DurationSelector component to wrap common methods the team encounter during development | 
|  * @description DurationSelector class extending e2elib's DurationSelector. | 
|  * All S&OP page objects inherit from our own class (inheriting e2e/libappbase), but we can propose common methods to them. | 
|  * @author      Clarence (clarence.chan@3ds.com) | 
|  * @copyright   Dassault Systèmes | 
|  */ | 
| import { QUtils } from '../e2elib/lib/src/main/qutils.class'; | 
| import { DurationSelector } from '../e2elib/lib/src/pageobjects/durationselector.component'; | 
| import { ElementFinder } from '../e2elib/node_modules/protractor/built'; | 
| import { UIActionSOP } from './objectsop'; | 
|   | 
| /** | 
|  * Customize duration interface. All fields are optional to allow setting/getting parts of the duration only (e.g set days and hours only). | 
|  */ | 
| export interface DurationInput { | 
|   Days?: number; | 
|   Hours?: number; | 
|   Minutes?: number; | 
|   Seconds?: number; | 
| } | 
|   | 
| /** | 
|  * Helper class to format duration input string and convert from string to DurationInput interface. | 
|  */ | 
| export class DurationInputHelper { | 
|   /** | 
|    * Format the string to represent a DurationInput interface. | 
|    * The returned string NOT to be used directly but always use methods from this class to convert between formats (as internal representation are allowed to change). | 
|    * | 
|    * @param input DurationInput object to represent the duration portions to be set. | 
|    * @returns The duration input string. | 
|    */ | 
|   public static getDurationString(input: DurationInput): string { | 
|     let value = 'D:H:M:S'; | 
|   | 
|     // Must explicit check instead of using shorthand if(input.Days) | 
|     if (input.Days !== undefined) { | 
|       value = value.replace('D', input.Days.toString()); | 
|     } | 
|   | 
|     if (input.Hours !== undefined) { | 
|       value = value.replace('H', input.Hours.toString()); | 
|     } | 
|   | 
|     if (input.Minutes !== undefined) { | 
|       value = value.replace('M', input.Minutes.toString()); | 
|     } | 
|   | 
|     if (input.Seconds !== undefined) { | 
|       value = value.replace('S', input.Seconds.toString()); | 
|     } | 
|   | 
|     return value; | 
|   } | 
|   | 
|   /** | 
|    * Convert duration input string to a DurationInput interface. Check each DurationInput property to be present before accessing its value as all properties are marked optional. | 
|    * | 
|    * @param value The duration input string retrived via DurationInputHelper.getDurationString method. | 
|    * @returns The DurationInput object representing a duration. | 
|    */ | 
|   public static getDurationInput(value: string): DurationInput { | 
|     const tokens = value.split(':'); | 
|     const durationInput: DurationInput = {}; | 
|   | 
|     if (tokens[0] !== 'D') { | 
|       durationInput.Days = (tokens[0] as unknown) as number; // Convert to unknown first as there's warning before casting to number | 
|     } | 
|   | 
|     if (tokens[1] !== 'H') { | 
|       durationInput.Hours = (tokens[1] as unknown) as number; | 
|     } | 
|   | 
|     if (tokens[2] !== 'M') { | 
|       durationInput.Minutes = (tokens[2] as unknown) as number; | 
|     } | 
|   | 
|     if (tokens[3] !== 'S') { | 
|       durationInput.Seconds = (tokens[3] as unknown) as number; | 
|     } | 
|   | 
|     return durationInput; | 
|   } | 
| } | 
|   | 
| export class DurationSelectorSOP extends DurationSelector implements UIActionSOP { | 
|   private readonly _durationFormat: DurationInput; | 
|   | 
|   public constructor(componentPath: string, durationFormat: DurationInput, isCustomPath?: boolean, elementObj?: ElementFinder) { | 
|     super(componentPath, isCustomPath, elementObj); | 
|     this._durationFormat = durationFormat; | 
|   } | 
|   | 
|   public async clickActionLinkText(expectedActionLinkText: string): Promise<void> { | 
|     const isActionLinkMatch = await this.hasActionLink() && await this.getActionLinkText() === expectedActionLinkText; | 
|     expect(isActionLinkMatch).toBe(true, `Unable to proceed click action link for duration selector ${await this.getComponentLabel()}. Expecting action link text '${expectedActionLinkText}'.`); | 
|   | 
|     if (isActionLinkMatch) { | 
|       await this.clickActionLink(); | 
|     } | 
|   } | 
|   | 
|   public async getValueString(): Promise<string> { | 
|     const days = Number(await this.getDay()); | 
|     const hours = Number(await this.getHour()); | 
|     const minutes = Number(await this.getMinute()); | 
|     const seconds = Number(await this.getSecond()); | 
|     const inputDuration: DurationInput = {Days: days, Hours: hours, Minutes: minutes, Seconds: seconds}; | 
|     return DurationInputHelper.getDurationString(inputDuration); | 
|   } | 
|   | 
|   public async setValue(value: string): Promise<void> { | 
|     if (await this.isDisabled() && await this.hasActionLink()) { | 
|       await this.clickActionLink(); | 
|     } | 
|   | 
|     await this.setDurationParts(value); | 
|   } | 
|   | 
|   public async toggleValue(): Promise<void> { | 
|     // Get current values for each duration parts | 
|     const days = Number(await this.getDay()); | 
|     const hours = Number(await this.getHour()); | 
|     const minutes = Number(await this.getMinute()); | 
|     const seconds = Number(await this.getSecond()); | 
|   | 
|     // Increment every parts of the duration (from days to seconds) so that cater for all scenarios to have duration UI to be changed value | 
|     // This way, no need to check if UI is showing the part before incrementing as we manipulating Date object itself | 
|     const incrementValue = 1; | 
|     // Must use UTC methods else timezone makes querying value not accurate | 
|     // Month argument is 0-based, 0 = January | 
|     const d = new Date(Date.UTC(1970, 0, 1)); | 
|     d.setUTCDate(d.getUTCDate() + days + incrementValue); | 
|     d.setUTCHours(d.getUTCHours() + hours + incrementValue); | 
|     d.setUTCMinutes(d.getUTCMinutes() + minutes + incrementValue); | 
|     d.setUTCSeconds(d.getUTCSeconds() + seconds + incrementValue); | 
|   | 
|     // Need build DurationInput interface to only contain what UI is displaying | 
|     const currentDuration: DurationInput = {}; | 
|     if (this._durationFormat.Days !== undefined) { | 
|       currentDuration.Days = d.getUTCDate() - 1; // As date initialized with 1st Jan 1970 thus we need subtract it out | 
|     } | 
|   | 
|     if (this._durationFormat.Hours !== undefined) { | 
|       currentDuration.Hours = d.getUTCHours(); | 
|     } | 
|   | 
|     if (this._durationFormat.Minutes !== undefined) { | 
|       currentDuration.Minutes = d.getUTCMinutes(); | 
|     } | 
|   | 
|     if (this._durationFormat.Seconds !== undefined) { | 
|       currentDuration.Seconds = d.getUTCSeconds(); | 
|     } | 
|   | 
|     await this.setValue(DurationInputHelper.getDurationString(currentDuration)); | 
|   } | 
|   | 
|   public async verifyBatchEditEnabled(expectedEnable: boolean, expectedActionLinkText: string): Promise<void> { | 
|     const isBatchEditEnableDisableOK = await this.hasActionLink() && | 
|                                        await this.getActionLinkText() === expectedActionLinkText && | 
|                                        !await this.isDisabled() === expectedEnable; | 
|     expect(isBatchEditEnableDisableOK).toBe(true, `Verify duration selector ${await this.getComponentLabel()} supports batch edit (expected enable = ${expectedEnable} & action link = ${expectedActionLinkText}).`); | 
|   } | 
|   | 
|   public async verifyHasMaskError(expectedValue: boolean): Promise<void> { | 
|     // Implements UIActionSOP | 
|     const actualHasMaskError = await this.hasMaskError(expectedValue); | 
|     expect(actualHasMaskError).toBe(expectedValue, `Verify has mask error for duration selector ${await this.getComponentLabel()}.`); | 
|   } | 
|   | 
|   public async verifyTooltip(expectedValue: string): Promise<void> { | 
|     const tooltip = await QUtils.getTooltip(this.tooltipLabelElement, true, true, true); | 
|     expect(tooltip).toBe(expectedValue, `Hover ${await this.getComponentLabel()} to verify tooltip.`); | 
|   } | 
|   | 
|   public async verifyEnabled(expectedEnable: boolean): Promise<void> { | 
|     expect(!await this.isDisabled()).toBe(expectedEnable, `Verify enable state for duration selector ${await this.getComponentLabel()}.`); | 
|   } | 
|   | 
|   public async verifyValue(expectedValue: string): Promise<void> { | 
|     const expectedDuration: DurationInput =  DurationInputHelper.getDurationInput(expectedValue); | 
|     let expectedDurationStr = ''; | 
|     let actualDurationStr = ''; | 
|   | 
|     if (expectedDuration.Days) { | 
|       const actualDays = await this.getDay(); | 
|       // Convert days to number as getDay() returns 00 string format (thus later problem if compare 0 to 00 which results false) | 
|       actualDurationStr = `${Number(actualDays)} days`; | 
|       expectedDurationStr = `${expectedDuration.Days.toString()} days`; | 
|     } | 
|   | 
|     if (expectedDuration.Hours) { | 
|       const actualHours = await this.getHour(); | 
|       actualDurationStr = `${actualDurationStr}, ${Number(actualHours)} hours`; | 
|       expectedDurationStr = `${expectedDurationStr}, ${expectedDuration.Hours.toString()} hours`; | 
|     } | 
|   | 
|     if (expectedDuration.Minutes) { | 
|       const actualMinutes = await this.getMinute(); | 
|       actualDurationStr = `${actualDurationStr}, ${Number(actualMinutes)} minutes`; | 
|       expectedDurationStr = `${expectedDurationStr}, ${expectedDuration.Minutes.toString()} minutes`; | 
|     } | 
|   | 
|     if (expectedDuration.Seconds) { | 
|       const actualSeconds = await this.getSecond(); | 
|       actualDurationStr = `${actualDurationStr}, ${Number(actualSeconds)} seconds`; | 
|       expectedDurationStr = `${expectedDurationStr}, ${expectedDuration.Seconds.toString()} seconds`; | 
|     } | 
|   | 
|     expect(actualDurationStr).toBe(expectedDurationStr, `Verify duration selector ${await this.getComponentLabel()}.`); | 
|   } | 
|   | 
|   public async verifyVisible(expectedValue: string): Promise<void> { | 
|     expect(await this.isVisible()).toBe(expectedValue.toLowerCase() === 'true', `Verify visible state for duration selector ${await this.getComponentLabel()}.`); | 
|   } | 
|   | 
|   private async setDurationParts(value: string): Promise<void> { | 
|     const duration: DurationInput =  DurationInputHelper.getDurationInput(value); | 
|   | 
|     if (duration.Days) { | 
|       await this.setDay(duration.Days.toString()); | 
|     } | 
|   | 
|     if (duration.Hours) { | 
|       await this.setHour(duration.Hours.toString()); | 
|     } | 
|   | 
|     if (duration.Minutes) { | 
|       await this.setMinute(duration.Minutes.toString()); | 
|     } | 
|   | 
|     if (duration.Seconds) { | 
|       await this.setSecond(duration.Seconds.toString()); | 
|     } | 
|   } | 
| } |