| /** | 
|  * @file        S&OP DateTimeSelector component to wrap common methods the team encounter during development | 
|  * @description DateTimeSelector class extending Abstraction API's QDateTimeSelector. | 
|  * All S&OP page objects inherit from our own class (inheriting e2e/Abstraction API), but we can propose common methods to them. | 
|  * @author      Clarence (clarence.chan@3ds.com) | 
|  * @copyright   Dassault Systèmes | 
|  */ | 
| import { QDateTimeSelector } from '../e2elib/lib/api/pageobjects/qdatetimeselector.component'; | 
| import { ElementFinder } from '../e2elib/node_modules/protractor/built'; | 
| import { UIActionSOP } from './objectsop'; | 
| import { QUtils } from '../e2elib/lib/src/main/qutils.class'; | 
| import { QDateTimeOmitOptions } from '../e2elib/lib/api/types'; | 
|   | 
| export class DateTimeSelectorSOP extends QDateTimeSelector implements UIActionSOP { | 
|   private readonly _separator = '-'; | 
|   private readonly _omit: QDateTimeOmitOptions; // Hide the datetime portions that are not present for this field in web app | 
|   | 
|   public constructor(componentPath: string, omit: QDateTimeOmitOptions = {hour: true, minute: true, second: true}, isCustomPath?: boolean, elementObj?: ElementFinder) { | 
|     super(componentPath, isCustomPath, elementObj); | 
|     this._omit = omit; | 
|   } | 
|   | 
|   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 datetimeselector ${await this.getComponentLabel()}. Expecting action link text '${expectedActionLinkText}'.`); | 
|   | 
|     if (isActionLinkMatch) { | 
|       await this.clickActionLink(); | 
|     } | 
|   } | 
|   | 
|   public getDateFromString(value: string): Date { | 
|     let date = new Date(1899, 11, 31, 0, 0, 0, 0); // This is default Quintiq value if datetime component only shows time | 
|     let dateOnly = ''; | 
|     if (!this._omit.date) { | 
|       const dateMatchArr = value.match(new RegExp('(\\d{1,2}-\\w{3}-\\d{4})', 'g')); | 
|       if (dateMatchArr !== null) { | 
|         dateOnly = dateMatchArr[0]; | 
|   | 
|         const tokens = dateOnly.split(this._separator); | 
|         date = new Date(`${tokens[1]} ${tokens[0]}, ${tokens[2]}`); // Format "Jan 1, 2020" | 
|       } | 
|     } | 
|   | 
|     const timeMatchArr = value.match(new RegExp('(\\d{2}:\\d{2}(:\\d{2})?)', 'g')); | 
|     let timeOnly = ''; | 
|     if (timeMatchArr !== null) { | 
|       timeOnly = timeMatchArr[0]; | 
|     } | 
|   | 
|     const timeTokens = timeOnly.split(':'); | 
|     if (!this._omit.hour) { | 
|       const hourToken = timeTokens.shift(); | 
|       date.setHours(Number(hourToken)); | 
|     } | 
|   | 
|     if (!this._omit.minute) { | 
|       const minToken = timeTokens.shift(); | 
|       date.setMinutes(Number(minToken)); | 
|     } | 
|   | 
|     if (!this._omit.second) { | 
|       const secToken = timeTokens.shift(); | 
|       date.setSeconds(Number(secToken)); | 
|     } | 
|   | 
|     return date; | 
|   } | 
|   | 
|   /** | 
|    * Returns the string representation of the datetimeselector for the visible datetime portions only. | 
|    * Thus not able use Abstraction API getDate/getDateTime methods as that returns Date. | 
|    * Example: If datetimeselector showing only hours and minutes, we will return only what is visible as string value. | 
|    * | 
|    * @returns Full datetime value string that potential to be returned is "1-Jan-2020 14:30:20" (down to the seconds). Or just either the date or time portion as string. | 
|    */ | 
|   public async getValueString(): Promise<string> { | 
|     let dateStr = ''; | 
|     // If field showing date, format the date str with format "1-Jan-2020" | 
|     if (!this._omit.date) { | 
|       const day = (await this.getDay()).padStart(2, '0'); | 
|       const month = await this.getMonth(); | 
|       const year = await this.getYear(); | 
|       dateStr = `${day}${this._separator}${month}${this._separator}${year}`; | 
|     } | 
|   | 
|     // If field showing any time portions, format the string value | 
|     let timeStr = ''; | 
|     if (!this._omit.hour) { | 
|       timeStr = timeStr + (await this.getHour()).padStart(2, '0'); | 
|     } | 
|   | 
|     if (!this._omit.minute) { | 
|       if (timeStr !== '') { | 
|         timeStr = `${timeStr  }:`; | 
|       } | 
|   | 
|       timeStr = timeStr + (await this.getMinute()).padStart(2, '0'); | 
|     } | 
|   | 
|     if (!this._omit.second) { | 
|       if (timeStr !== '') { | 
|         timeStr = `${timeStr  }:`; | 
|       } | 
|   | 
|       timeStr = timeStr + (await this.getSecond()).padStart(2, '0'); | 
|     } | 
|   | 
|     // Format the final string to return (either both date+time available, or only one of them). | 
|     const spaceBetweenDateAndTime = (dateStr !== '' && timeStr !== '') ? ' ' : ''; // If both date+time available, put a space between them. | 
|     const finalDateStr = `${dateStr}${spaceBetweenDateAndTime}${timeStr}`; | 
|   | 
|     return finalDateStr; | 
|   } | 
|   | 
|   public async setValue(value: string): Promise<void> { | 
|     // Convert user input string into Date object | 
|     const dateTime: Date = this.getDateFromString(value); | 
|   | 
|     // Send the Date object into Abstraction API method which knows how to fill in our datetimeselector in web app | 
|     await this.setDateTime(dateTime, this._omit); | 
|   } | 
|   | 
|   public async toggleValue(): Promise<void> { | 
|     const previousDateValue = await this.getValueString(); | 
|     const previousDate = this.getDateFromString(previousDateValue); | 
|     previousDate.setDate(previousDate.getDate() + 1); | 
|     previousDate.setHours(previousDate.getHours() + 1); | 
|     previousDate.setMinutes (previousDate.getMinutes() + 1); | 
|     previousDate.setSeconds(previousDate.getSeconds() + 1); | 
|     await this.setDateTime(previousDate, this._omit); | 
|   } | 
|   | 
|   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 datetimeselector ${await this.getComponentLabel()} supports batch edit (expected enable = ${expectedEnable} & action link = ${expectedActionLinkText}).`); | 
|   } | 
|   | 
|   public async verifyHasMaskError(expectedValue: boolean): Promise<void> { | 
|     // Implements UIActionSOP | 
|     await this.hasMaskError(expectedValue); | 
|   } | 
|   | 
|   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 datetimeselector ${await this.getComponentLabel()}.`); | 
|   } | 
|   | 
|   public async verifyValue(expectedValue: string): Promise<void> { | 
|     const actualDate = await this.getDateTime(); // Get Date object from the datetimeselector component in web app | 
|     const expectedDate = this.getDateFromString(expectedValue); // Get Date object from user expected string | 
|   | 
|     // Cannot direct compare Dates, use valueOf which returns the primitive underlying value such as 823230245000 | 
|     const datesEqual = actualDate.valueOf() === expectedDate.valueOf(); | 
|     expect(datesEqual).toBe(true, `Verify value fail for datetimeselector ${await this.getComponentLabel()}. Expected = ${expectedValue}, actual = ${await this.getValueString()}.`); | 
|   } | 
|   | 
|   public async verifyVisible(expectedValue: string): Promise<void> { | 
|     expect(await this.isVisible()).toBe(expectedValue.toLowerCase() === 'true', `Verify visible state for datetimeselector ${await this.getComponentLabel()}.`); | 
|   } | 
|  } |