import { TestLabel } from '@ephox/bedrock-client'; import { Adt, Arr, Optional, Result } from '@ephox/katamari'; import { Attribute, type SugarElement, TextContent, Truncate } from '@ephox/sugar'; import * as SizzleFind from '../alien/SizzleFind'; interface TargetAdt { fold: ( self: (element: SugarElement, selector: string) => T, children: (element: SugarElement, selector: string) => T, descendants: (element: SugarElement, selector: string) => T ) => T; match: (branches: { self: (element: SugarElement, selector: string) => T; children: (element: SugarElement, selector: string) => T; descendants: (element: SugarElement, selector: string) => T; }) => T; log: (label: string) => void; } const targets: { self: (element: SugarElement, selector: string) => TargetAdt; children: (element: SugarElement, selector: string) => TargetAdt; descendants: (element: SugarElement, selector: string) => TargetAdt; } = Adt.generate([ { self: [ 'element', 'selector' ] }, { children: [ 'element', 'selector' ] }, { descendants: [ 'element', 'selector' ] } ]); const derive = (element: SugarElement, selector: string) => { // Not sure if error is what I want here. if (selector === undefined) { throw new Error('No selector passed through'); } else if (selector.indexOf('root:') === 0) { return targets.self(element, selector.substring('root:'.length)); } else if (selector.indexOf('root>') === 0) { return targets.children(element, selector.substring('root>'.length)); } else { return targets.descendants(element, selector); } }; const matchesSelf = (element: SugarElement, selector: string): Optional> => SizzleFind.matches(element, selector) ? Optional.some(element) : Optional.none(); const select = (element: SugarElement, selector: string): Optional> => derive(element, selector).fold>>( matchesSelf, SizzleFind.child, SizzleFind.descendant ); const selectAll = (element: SugarElement, selector: string): Array> => derive(element, selector).fold>>( (element, selector) => matchesSelf(element, selector).toArray(), SizzleFind.children, SizzleFind.descendants ); const toResult = (message: TestLabel, option: Optional): Result => option.fold( () => Result.error(TestLabel.asString(message)), Result.value ); const findIn = (container: SugarElement, selector: string): Result, TestLabel> => toResult( () => 'Could not find selector: ' + selector + ' in ' + Truncate.getHtml(container), select(container, selector) ); const findAllIn = (container: SugarElement, selector: string): Array> => selectAll(container, selector); const findTargetByLabel = (container: SugarElement, labelText: string): Result, TestLabel> => { const label = Arr.find(selectAll(container, 'label'), (e) => TextContent.get(e) === labelText); const targetByLabelOptional = label .bind((label) => { const forAttribute = Optional.from(Attribute.get(label, 'for')); return forAttribute.fold( () => select(label, 'button,input,meter,output,progress,select,textarea'), (inputId) => select(container, `#${inputId}`) ); }); return toResult( () => 'Could not find target by label: ' + labelText + ' in ' + Truncate.getHtml(container), targetByLabelOptional ); }; export { select, findIn, findAllIn, findTargetByLabel };