/**
|
* @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());
|
}
|
}
|
}
|