Skip to content

Commit

Permalink
refactor: no typecasts; JSDoc; method signature from expectExistence …
Browse files Browse the repository at this point in the history
…to expectAllExist; (#APD-483)
  • Loading branch information
JohannesDienst-askui committed Jun 19, 2024
1 parent 3c117dd commit be1e5ba
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 64 deletions.
7 changes: 1 addition & 6 deletions packages/askui-nodejs/src/execution/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1 @@
export {
UiControlClient,
RelationsForConvenienceMethods,
ExpectExistenceInputParameter,
ExpectExistenceReturnValue,
} from './ui-control-client';
export * from './ui-control-client';
119 changes: 67 additions & 52 deletions packages/askui-nodejs/src/execution/ui-control-client.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ValidationError } from 'yup';
import { CustomElement } from '../core/model/custom-element';
import { CustomElementJson } from '../core/model/custom-element-json';
import {
Expand All @@ -23,27 +24,27 @@ import { Instruction, StepReporter } from '../core/reporting';

export type RelationsForConvenienceMethods = 'nearestTo' | 'leftOf' | 'above' | 'rightOf' | 'below' | 'contains';
export type TextMatchingOption = 'similar' | 'exact' | 'regex';
export type ExpectExistenceInputParameterType = 'otherElement' | 'switch' | 'element' | 'container' | 'checkbox' | 'element' | 'button' | 'table' | 'text' | 'icon' | 'image' | 'textfield';
export interface ExpectExistenceInputParameterText {
export type ElementExistsQueryType = 'otherElement' | 'switch' | 'element' | 'container' | 'checkbox' | 'element' | 'button' | 'table' | 'text' | 'icon' | 'image' | 'textfield';
export interface ElementExistsQueryText {
value: string;
matching?: TextMatchingOption;
}
export interface ExpectExistenceInputParameterRelation {
export interface ElementExistsQueryRelation {
type: RelationsForConvenienceMethods;
text: string;
}
export interface ExpectExistenceInputParameter {
type: keyof Pick<FluentFilters, ExpectExistenceInputParameterType>;
text?: ExpectExistenceInputParameterText;
relation?: ExpectExistenceInputParameterRelation;
export interface ElementExistsQuery {
type: keyof Pick<FluentFilters, ElementExistsQueryType>;
text?: ElementExistsQueryText;
relation?: ElementExistsQueryRelation;
}
export interface ExpectExistenceElement extends ExpectExistenceInputParameter {
export interface ExpectExistenceElement extends ElementExistsQuery {
exists: boolean;
}
export type ExpectExistenceReturnValue = {
everythingExists: boolean;
export interface ExpectAllExistResult {
allExist: boolean;
elements: ExpectExistenceElement[];
};
}

export class UiControlClient extends ApiCommands {
private constructor(
Expand Down Expand Up @@ -374,6 +375,16 @@ export class UiControlClient extends ApiCommands {
}
}

private evaluateRelation(
command: FluentFiltersOrRelations,
relation: RelationsForConvenienceMethods,
text: string,
): FluentFiltersOrRelations;
private evaluateRelation(
command: FluentFiltersOrRelationsGetter,
relation: RelationsForConvenienceMethods,
text: string,
): FluentFiltersOrRelationsGetter;
// eslint-disable-next-line class-methods-use-this
private evaluateRelation(
command: FluentFiltersOrRelations | FluentFiltersOrRelationsGetter,
Expand All @@ -391,8 +402,10 @@ export class UiControlClient extends ApiCommands {
return command.below().text(text);
case 'contains':
return command.contains().text(text);
default:
case 'nearestTo':
return command.nearestTo().text(text);
default:
throw new ValidationError(`'relation' has to be 'nearestTo', 'leftOf', 'above', 'rightOf', 'below' or 'contains' but was '${relation}'`);
}
}

Expand Down Expand Up @@ -450,8 +463,8 @@ export class UiControlClient extends ApiCommands {
* @param {Object} params - Object containing required `label` property and
* optional `relation` property.
* @property {string} params.label - The label for the checkbox.
* @property {Object} params.relation - Object describing the relationship between
* the clicked checkbox and another element.
* @property {Object} [params.relation] - Object describing the relationship between
* the clicked checkbox and another element.
* @property {RelationsForConvenienceMethods} params.relation.type - The type of relation.
*/
async clickCheckbox(
Expand Down Expand Up @@ -488,7 +501,7 @@ export class UiControlClient extends ApiCommands {
* @param {Object} params - Object containing required `label` property and
* optional `relation` property.
* @property {string} params.label - The label for the checkbox.
* @property {Object} params.relation - Object describing the relationship between
* @property {Object} [params.relation] - Object describing the relationship between
* the clicked checkbox and another element.
* @property {RelationsForConvenienceMethods} params.relation.type - The type of relation.
*/
Expand Down Expand Up @@ -593,8 +606,8 @@ export class UiControlClient extends ApiCommands {
* @property {string} params.text - The text to be clicked.
* @property {string} params.matching - Whether the text is matched using similarity,
* exact match or a regular expression.
* @property {Object} params.relation - Object describing the relationship between the
* clicked text and another element.
* @property {Object} [params.relation] - Object describing the relationship between the
* clicked text and another element.
* @property {RelationsForConvenienceMethods} params.relation.type - The type of relation.
* @property {string} params.relation.text - The label or text associated with the
* related element or state.
Expand Down Expand Up @@ -622,24 +635,26 @@ export class UiControlClient extends ApiCommands {

private evaluateMatchingProperty(
command: FluentFiltersOrRelations,
text: ExpectExistenceInputParameterText,
text: ElementExistsQueryText,
): FluentFiltersOrRelations;
private evaluateMatchingProperty(
command: FluentFiltersOrRelationsGetter,
text: ExpectExistenceInputParameterText,
text: ElementExistsQueryText,
): FluentFiltersOrRelationsGetter;
// eslint-disable-next-line class-methods-use-this
private evaluateMatchingProperty(
command: FluentFiltersOrRelations | FluentFiltersOrRelationsGetter,
text: ExpectExistenceInputParameterText,
text: ElementExistsQueryText,
): FluentFiltersOrRelations | FluentFiltersOrRelationsGetter {
switch (text.matching ?? 'similar') {
case 'exact':
return command.withExactText(text.value);
case 'regex':
return command.withTextRegex(text.value);
default:
case 'similar':
return command.withText(text.value);
default:
throw new ValidationError(`'text.matching' property has to be 'similar', 'exact' or 'regex' but was '${text.matching}'`);
}
}

Expand All @@ -648,7 +663,7 @@ export class UiControlClient extends ApiCommands {
*
* **Examples:**
* ```typescript
* await aui.expectExistence([
* await aui.expectAllExist([
* {
* type: 'text',
* text: {
Expand All @@ -659,7 +674,7 @@ export class UiControlClient extends ApiCommands {
* ]);
*
* // Check for existence of multiple elements
* await aui.expectExistence([
* await aui.expectAllExist([
* {
* type: 'textfield',
* relation: {
Expand All @@ -676,59 +691,59 @@ export class UiControlClient extends ApiCommands {
* ]);
*
* // Validate existence
* const exists = await aui.expectExistence([...]);
* const exists = await aui.expectAllExist([...]);
* exists.everythingExists // true when every element exists
*
* // Check which elements do not exist
* // with the elements property
* const nonExistentElements = exists.elements.filter((e) => e.exists===false)
* ```
*
* @param {ExpectExistenceInputParameter[]} params - Objects containing the required property
* @param {ElementExistsQuery[]} query - Objects containing the required property
* 'type' and the optional properties
* 'text' and 'relation'.
* @property {string} params.type - The type of the element: 'otherElement' | 'switch' |
* 'element' | 'container' | 'checkbox' | 'element' |
* 'button' | 'table' | 'text' | 'icon' | 'image' | 'textfield'
* @property {Object} params.text - Object containing value and matching strategy.
* @property {string} params.text.value - The text to match for.
* @property {string} params.text.matching - Whether the text is matched using similarity,
* exact match or a regular expression.
* @property {Object} params.relation - Object describing the relationship between the
* clicked text and another element.
* @property {string} query.type - The type of the element: 'otherElement' | 'switch' |
* 'element' | 'container' | 'checkbox' | 'element' |
* 'button' | 'table' | 'text' | 'icon' | 'image' | 'textfield'
* @property {Object} [query.text] - Object containing value and matching strategy.
* @property {string} query.text.value - The text to match for.
* @property {string} [query.text.matching] - Whether the text is matched using similarity,
* exact match or a regular expression.
* @property {Object} [query.relation] - Object describing the relationship between the
* clicked text and another element.
* @property {RelationsForConvenienceMethods} params.relation.type - The type of relation.
* @property {string} params.relation.text - The label or text associated with the
* related element or state.
* @returns {ExpectExistenceReturnValue.everythingExists} - If every element exists.
* @returns {ExpectExistenceReturnValue.elements} - ExpectExistenceElement[].
* @property {string} query.relation.text - The label or text associated with the
* related element or state.
* @returns {ExpectAllExistResult.everythingExists} - If every element exists.
* @returns {ExpectAllExistResult.elements} - ExpectExistenceElement[].
*/
async expectExistence(
params: ExpectExistenceInputParameter[],
): Promise<ExpectExistenceReturnValue> {
const elements = await params.reduce(async (accumulatorPromise, param) => {
async expectAllExist(
query: ElementExistsQuery[],
): Promise<ExpectAllExistResult> {
const elements = await query.reduce(async (accumulatorPromise, subquery) => {
const acc = await accumulatorPromise;
const command = this.get()[param.type]();
let finalCommand = param.text !== undefined
? this.evaluateMatchingProperty(command, param.text)
const command = this.get()[subquery.type]();
let finalCommand = subquery.text !== undefined
? this.evaluateMatchingProperty(command, subquery.text)
: command;
if (param.relation) {
if (subquery.relation) {
finalCommand = this.evaluateRelation(
finalCommand,
param.relation.type,
param.relation.text,
) as FluentFiltersOrRelationsGetter;
subquery.relation.type,
subquery.relation.text,
);
}
return [
...acc,
{
...param,
...subquery,
exists: (await finalCommand.exec()).length > 0,
},
];
}, Promise.resolve([] as ExpectExistenceElement[]));
}, Promise.resolve<ExpectExistenceElement[]>([]));
return {
elements,
everythingExists: elements.every((el) => el.exists),
allExist: elements.every((el) => el.exists),
};
}
}
7 changes: 1 addition & 6 deletions packages/askui-nodejs/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
export { UiController } from './lib';
export {
UiControlClient,
RelationsForConvenienceMethods,
ExpectExistenceInputParameter,
ExpectExistenceReturnValue,
} from './execution';
export * from './execution';
export {
Instruction,
Reporter,
Expand Down

0 comments on commit be1e5ba

Please sign in to comment.