UNPKG

create-locator

Version:

Creates HTML element locators for tests 📌

708 lines (621 loc) • 23.1 kB
/// <reference path="./react.d.ts" /> /** * Any locator, that is locator that matches any other locators (for use in unit tests). */ export type AnyLocator = ((parameters?: any) => AnyMark) & WithLocator; /** * A mark that matches any locator (for use in unit tests). */ export type AnyMark = WithMark<any> & WithErrorAttribute; /** * Attributes object. */ export type Attributes = Readonly<Record<string, string>>; /** * Symbol key for saving component parameters of locator. */ export declare const COMPONENT_PARAMETERS: unique symbol; /** * `createLocator` overload for component locator. */ export type CreateComponentLocator = <Properties extends Partial<PropertiesWithMarkConstraint>>( this: void, properties: PropertiesError<Properties> extends string ? PropertiesError<Properties> : Properties, ) => CreateLocator<PropertiesError<Properties> extends string ? never : Properties>; /** * Presentation of `createLocator` function in types. * Creates locator type by properties and optional `MappingResult` type. */ export type CreateLocator< PropertiesOrRootLocator extends Partial<PropertiesWithMarkConstraint> | WithLocator, MappingResult = HiddenKey, > = true extends | (PropertiesOrRootLocator extends Partial<PropertiesWithMarkConstraint> | WithLocator ? false : true) | IsEqual<PropertiesOrRootLocator, never> | IsEqual<PropertiesOrRootLocator, WithLocator> ? unknown : IsEqual<MappingResult, HiddenKey> extends true ? PropertiesOrRootLocator extends WithLocator ? PropertiesOrRootLocator : PropertiesOrRootLocator extends Partial<WithMark> ? IsEqual<LocatorTreeFromMark<PropertiesOrRootLocator>, unknown> extends true ? unknown : IsEqual<LocatorTreeFromMark<PropertiesOrRootLocator>, object> extends true ? unknown : LocatorFromLocatorTree<LocatorTreeFromMark<PropertiesOrRootLocator>> : unknown : PropertiesOrRootLocator extends WithLocator ? NormalizeTree<LocatorTreeFromLocator<PropertiesOrRootLocator>, MappingResult> : unknown; /** * Type of `createRootLocator` function (with overloads). */ export type CreateRootLocatorFunction = CreateRootLocator & CreateRootLocatorWithMapping; /** * Symbol key for generating type error on HTML elements. */ export declare const ERROR_ATTRIBUTE: GetErrorAttribute<keyof React.AriaAttributes & symbol>; /** * Filled options of root locator, maybe with mapping attributes function. */ export type FilledRootOptions = Partial<MapAttributes<Attributes>> & RootOptionsWithDefaults; /** * Presentation of `getLocatorParameters` function in types. * Get type of parameters of component locator by component properties. */ export type GetLocatorParameters< Properties extends Partial<PropertiesWithMarkWithParametersConstraint>, > = true extends | (Properties extends Partial<PropertiesWithMarkWithParametersConstraint> ? false : true) | IsEqual<Properties, never> | IsEqual<ExtractNodeComponentParameters<LocatorTreeFromMark<Properties>>, {}> ? unknown : ExtractNodeComponentParameters<LocatorTreeFromMark<Properties>>; /** * Type of `getLocatorParameters` function. */ export type GetLocatorParametersFunction = < Properties extends Partial<PropertiesWithMarkWithParametersConstraint>, >( this: void, properties: PropertiesError<Properties> extends string ? PropertiesError<Properties> : Properties, ) => GetLocatorParameters<PropertiesError<Properties> extends string ? never : Properties>; /** * Symbol key for saving hidden normalized tree. */ export declare const HIDDEN: unique symbol; /** * Symbol key for tree of empty locator (i.e. `Locator<void>`). */ export declare const IS_EMPTY_LOCATOR: unique symbol; /** * Creates component locator type by locator description and locator parameters. */ export type Locator< Description extends LocatorDescriptionConstraint, Parameters extends ParametersConstraint = void, ComponentParameters extends ParametersConstraint | 'sameParameters' = void, > = true extends | (Description extends LocatorDescriptionConstraint ? false : true) | (Parameters extends ParametersConstraint ? false : true) | (ComponentParameters extends ParametersConstraint | 'sameParameters' ? false : true) | IsEqual<Description, never> | IsEqual<Parameters, never> | IsEqual<ComponentParameters, never> ? unknown : LocatorFromLocatorTree< LocatorTree< Description, AddUndefinedIfRequiredParametersEmpty<Parameters>, AddUndefinedIfRequiredParametersEmpty< IsEqual<ComponentParameters, 'sameParameters'> extends true ? Parameters : ComponentParameters > > >; /** * Symbol key to define locator. */ export declare const LOCATOR: unique symbol; /** * Constraint of locator, that is the argument of `Mark`. */ export type LocatorConstraint = WithLocator; /** * Constraint of description of locator tree, that is the first argument of `Locator` and `Node`. */ export type LocatorDescriptionConstraint = Readonly< Record<string, (ParametersConstraint & WithErrorAttribute) | void | WithLocator | WithNode> & Partial< WithComponentParameters<NotLocatorDescription> & WithHidden<NotLocatorDescription> & WithLocator<NotLocatorDescription> & WithMark<NotLocatorDescription> & WithNode<NotLocatorDescription> & WithParameters<NotLocatorDescription> > > | void; /** * Creates locator type by locator description and locator parameters * for component, behaves like an element. */ export type LocatorOfElement< Description extends LocatorDescriptionConstraint, Parameters extends ParametersConstraint = void, ComponentParameters extends ParametersConstraint | 'sameParameters' = void, > = true extends | (Description extends LocatorDescriptionConstraint ? false : true) | (Parameters extends ParametersConstraint ? false : true) | (ComponentParameters extends ParametersConstraint | 'sameParameters' ? false : true) | IsEqual<Description, never> | IsEqual<Parameters, never> | IsEqual<ComponentParameters, never> ? unknown : LocatorFromLocatorTree< LocatorTree< Description, AddUndefinedIfRequiredParametersEmpty<Parameters>, AddUndefinedIfRequiredParametersEmpty< IsEqual<ComponentParameters, 'sameParameters'> extends true ? Parameters : ComponentParameters >, 'LocatorOfElement' > >; /** * Creates mark with component locator type for component properties. */ export type Mark<SomeLocator extends LocatorConstraint> = true extends | (SomeLocator extends LocatorConstraint ? false : true) | IsEqual<SomeLocator, never> | IsEqual<LocatorTreeFromLocator<SomeLocator>, unknown> ? unknown : WithMark<LocatorTreeFromLocator<SomeLocator>> & WithErrorAttribute< | 'The mark of locator should be removed from spreaded properties using the removeMarkFromProperties' | CannotMarkElementMessage >; /** * Symbol key for saving locator tree in mark (in properties object). */ export declare const MARK: unique symbol; /** * Creates node locator type by locator description and locator parameters. */ export type Node< Description extends LocatorDescriptionConstraint, Parameters extends ParametersConstraint = void, > = true extends | (Description extends LocatorDescriptionConstraint ? false : true) | (Parameters extends ParametersConstraint ? false : true) | IsEqual<Description, never> | IsEqual<Parameters, never> ? unknown : WithNode< LocatorTree<Description, AddUndefinedIfRequiredParametersEmpty<Parameters>, void, 'Node'> > & WithErrorAttribute<'Node cannot be used here'>; /** * Symbol key for saving locator tree of node locator. */ export declare const NODE: unique symbol; /** * Symbol key for saving locator parameters. */ export declare const PARAMETERS: unique symbol; /** * Constraint of locator parameters, that is the second argument of `Locator` and `Node`. */ export type ParametersConstraint = Attributes | void; /** * Constraint of properties with mark, that is the argument of `createLocator` and `removeMarkFromProperties`. */ export type PropertiesWithMarkConstraint = WithMark; /** * Constraint of properties with mark with parameters, that is the argument of `getLocatorParameters`. */ export type PropertiesWithMarkWithParametersConstraint = WithMark<WithComponentParameters>; /** * Presentation of `removeMarkFromProperties` function in types. * Returns type of properties without locator mark. */ export type RemoveMarkFromProperties<Properties extends Partial<PropertiesWithMarkConstraint>> = true extends IsEqual<Properties, never> ? unknown : Omit<Properties, ErrorAttributeKey | MarkKey>; /** * Type of `removeMarkFromProperties` function. */ export type RemoveMarkFromPropertiesFunction = < Properties extends Partial<PropertiesWithMarkConstraint>, >( this: void, properties: PropertiesError<Properties> extends string ? PropertiesError<Properties> : Properties, ) => RemoveMarkFromProperties<PropertiesError<Properties> extends string ? never : Properties>; /** * Options of root locator (as `createLocator` second argument). */ export type RootOptions = Partial<FilledRootOptions>; /** * Symbol key for saving locator tree for prototype keys. */ export declare const TREE: unique symbol; /** * Adds `IS_EMPTY_LOCATOR` key if locator tree is empty (i.e. for `Locator<void>`). */ type AddIsEmptyLocatorKeyIfNeeded<Tree> = IsEqual<string & keyof Tree, never> extends true ? WithIsEmptyLocator : {}; /** * Adds `undefined` to parameters if there are no required parameters. */ type AddUndefinedIfRequiredParametersEmpty<Parameters> = IsRequiredParametersEmpty<Parameters> extends true ? Parameters | undefined : Parameters; /** * The function part of the base node. */ type BaseLocatorFunction<Parameters, Return> = ( this: void, ...arguments: LocatorArguments<Parameters> ) => Return; /** * Base node of locator tree (by locator parameters, locator component parameters, * optional subtree and `IsChildLocator` flag). */ type BaseNode< Parameters, ComponentParameters, Subtree = undefined, IsChildLocator extends boolean = false, ParametersInArguments = IsChildLocator extends true ? ComponentParameters : Parameters, > = (IsParametersEmpty<ParametersInArguments> extends true ? ((this: void) => LocatorCallResult<Subtree, IsChildLocator>) & WithErrorAttribute<'The locator should be called'> : BaseLocatorFunction<ParametersInArguments, LocatorCallResult<Subtree, IsChildLocator>> & WithErrorAttribute<'The locator should be called (maybe with parameters)'>) & (IsParametersEmpty<ComponentParameters> extends true ? {} : WithComponentParameters<ComponentParameters>) & (IsParametersEmpty<Parameters> extends true ? {} : WithParameters<Parameters>); /** * Error message for situations where a HTML element is marked with a component locator. */ type CannotMarkElementMessage = 'Cannot mark HTML element with component locator'; /** * Type of symbol key for saving component parameters of locator. */ type ComponentParametersKey = typeof COMPONENT_PARAMETERS; /** * `createLocator` overload for root locator. */ type CreateRootLocator = <RootLocator extends WithLocator>( this: void, pathPrefix: IsEqual<RootLocator, WithLocator> extends true ? never : string, rootOptions?: Partial<RootOptionsWithDefaults>, ) => CreateLocator<RootLocator>; /** * `createLocator` overload for root locator with attributes mapping. */ type CreateRootLocatorWithMapping = <RootLocator extends WithLocator, MappingResult>( this: void, pathPrefix: IsEqual<RootLocator, WithLocator> extends true ? never : string, rootOptions: Partial<RootOptionsWithDefaults> & MapAttributes<MappingResult>, ) => CreateLocator<RootLocator, MappingResult>; /** * Base type of error attribute value for all HTML elements. */ type ErrorAttributeBaseType = | 'https://www.npmjs.com/package/create-locator#error-attribute' | undefined; /** * Type of symbol key for generating type error on HTML elements. */ type ErrorAttributeKey = typeof ERROR_ATTRIBUTE; /** * Extracts component parameters from some base node. */ type ExtractNodeComponentParameters<SomeNode> = SomeNode extends WithComponentParameters ? SomeNode[ComponentParametersKey] : {}; /** * Extracts parameters from some base or normalized node. */ type ExtractNodeParameters<SomeNode> = SomeNode extends WithParameters ? SomeNode[ParametersKey] : {}; /** * Get error attribute key from `React.AriaAttributes` interface. */ type GetErrorAttribute<Attribute extends keyof React.AriaAttributes & symbol> = Attribute extends unknown ? IsEqual<React.AriaAttributes[Attribute], ErrorAttributeBaseType> extends true ? Attribute : never : never; /** * Type of symbol key for saving hidden normalized tree. */ type HiddenKey = typeof HIDDEN; /** * Returns `true` if types are exactly equal, `false` otherwise. * `IsEqual<{foo: string}, {foo: string}>` = `true`. * `IsEqual<{readonly foo: string}, {foo: string}>` = `false`. */ type IsEqual<X, Y> = (<Type>() => Type extends X ? 1 : 2) extends <Type>() => Type extends Y ? 1 : 2 ? true : false; /** * Returns `true` if type includes `undefined`, `false` otherwise. * `IsIncludeUndefined<string>` = `false`. * `IsIncludeUndefined<number | undefined>` = `true`. */ type IsIncludeUndefined<Type> = true extends (Type extends undefined ? true : never) ? true : false; /** * Type of symbol key for tree of empty locator (i.e. `Locator<void>`). */ type IsEmptyLocatorKey = typeof IS_EMPTY_LOCATOR; /** * Returns error string if properties object is not valid for `CreateComponentLocator` * and other functions, `undefined` otherwise. */ type PropertiesError<Properties> = Properties extends Partial<WithMark<never>> ? 'Properties are unmarked by any locator; use & Mark<SomeLocator>' : Properties extends Partial<WithMark<WithLocator<'LocatorOfElement'>>> ? Properties extends WithErrorAttribute ? undefined : 'This component does not behave like an element; use Locator instead of LocatorOfElement for it' : Properties extends WithErrorAttribute ? 'This component behaves like an element; use LocatorOfElement for it' : undefined; /** * Returns `true` if parameters is empty, `false` otherwise. * `IsParametersEmpty<{foo: string}>` = `false`. * `IsParametersEmpty<{}>` = `true`. */ type IsParametersEmpty<Parameters> = Keys<Parameters> extends never ? true : false; /** * Returns `true` if there are no required parameters, `false` otherwise. */ type IsRequiredParametersEmpty<Parameters> = RequiredKeys<Parameters> extends never ? true : false; /** * Returns all keys of type. * `Keys<{foo: string}>` = `"foo"`. * `Keys<{foo: string} | {bar?: number}>` = `"foo" | "bar"`. */ type Keys<Type> = Type extends unknown ? keyof Type : never; /** * Arguments of locator as function by locator parameters. */ type LocatorArguments<Parameters> = IsIncludeUndefined<Parameters> extends true ? [parameters?: Parameters] : [parameters: Parameters]; /** * Locator call result by locator tree and `IsChildLocator` flag. */ type LocatorCallResult<Tree, IsChildLocator extends boolean = false> = Tree extends object ? WithMark<Tree> & WithErrorAttribute< IsChildLocator extends true ? Tree extends WithLocator<'LocatorOfElement'> ? undefined : CannotMarkElementMessage : undefined > : Attributes; /** * Type of runtime locator object by locator tree. */ type LocatorFromLocatorTree<Tree> = BaseNode< ExtractNodeParameters<Tree>, ExtractNodeComponentParameters<Tree>, Tree > & { readonly [Key in string & keyof Tree]: TreeNode<Key, UnwrapTree<Tree[Key]>>; } & WithLocator<Tree extends WithLocator ? Tree[LocatorKey] : 'Locator'>; /** * Type of symbol key to define locator. */ type LocatorKey = typeof LOCATOR; /** * Creates locator tree by locator description, locator parameters, * locator component parameters and locator kind. */ type LocatorTree< Description, Parameters, ComponentParameters, Kind = 'Locator', MergedDescriptions = UnionToIntersection<Description>, > = BaseNode<Parameters, ComponentParameters> & { readonly [Key in string & keyof MergedDescriptions]-?: TreeNode< Key, LocatorTreeNode<Key, Exclude<MergedDescriptions[Key], undefined>> >; } & WithLocator<Kind> & AddIsEmptyLocatorKeyIfNeeded<MergedDescriptions>; /** * Get locator tree from locator object. */ type LocatorTreeFromLocator<SomeLocator> = SomeLocator extends WithLocator ? BaseNode<ExtractNodeParameters<SomeLocator>, ExtractNodeComponentParameters<SomeLocator>> & { readonly [Key in string & keyof SomeLocator]: TreeNode<Key, UnwrapTree<SomeLocator[Key]>>; } & WithLocator<SomeLocator[LocatorKey]> & AddIsEmptyLocatorKeyIfNeeded<SomeLocator> : unknown; /** * Get locator tree from properties with mark. */ type LocatorTreeFromMark<Properties extends Partial<PropertiesWithMarkConstraint>> = Exclude< Properties[MarkKey], undefined >; /** * Creates locator tree node by locator description node. */ type LocatorTreeNode<Key, DescriptionNode> = [DescriptionNode] extends [WithLocator] ? BaseNode< ExtractNodeParameters<DescriptionNode>, ExtractNodeComponentParameters<DescriptionNode>, LocatorTreeFromLocator<DescriptionNode>, true > & WithHidden<TreeNode<Key, NormalizeTree<LocatorTreeFromLocator<DescriptionNode>>>> : [DescriptionNode] extends [WithNode] ? DescriptionNode[NodeKey] : BaseNode<AddUndefinedIfRequiredParametersEmpty<DescriptionNode>, {}>; /** * Additional option of root locator for mapping attributes. */ type MapAttributes<MappingResult> = { readonly mapAttributesChain: (this: void, attributes: readonly Attributes[]) => MappingResult; }; /** * Type of symbol key for saving locator tree in mark (in properties object). */ type MarkKey = typeof MARK; /** * Type of symbol key for saving locator tree of node locator. */ type NodeKey = typeof NODE; /** * Normalize base node of locator tree by base node and mapping result. */ type NormalizeBaseNode<BaseNode, MappingResult> = BaseNode extends WithParameters ? NormalizedLocatorFunction<BaseNode, MappingResult> & WithParameters<BaseNode[ParametersKey]> : (this: void) => MappingResult; /** * The function part of the or normalized base node. */ type NormalizedLocatorFunction<UnwrappedTree extends WithParameters, MappingResult> = (( this: void, parameters: UnwrappedTree[ParametersKey], ) => NormalizeTreeWithParameters<UnwrappedTree, MappingResult>) & ((this: void) => MappingResult); /** * Normalize list of subnodes of locator tree. */ type NormalizeListOfSubnodes<Subnodes, MappingResult> = { readonly [Key in string & keyof Subnodes]: TreeNode< Key, NormalizeSubnode<UnwrapTree<Subnodes[Key]>, MappingResult> >; }; /** * Normalize subnode of locator tree. */ type NormalizeSubnode<Subnode, MappingResult> = Subnode extends WithHidden ? IsEqual<MappingResult, void> extends true ? Subnode[HiddenKey] : NormalizeTree<Subnode[HiddenKey], MappingResult> : NormalizeTree<Subnode, MappingResult>; /** * Normalize locator tree to hidden internal brief presentation (so-called normalized tree). */ type NormalizeTree<Tree, MappingResult = void> = NormalizeBaseNode< UnwrapTree<Tree>, MappingResult > & NormalizeListOfSubnodes<UnwrapTree<Tree>, MappingResult>; /** * Normalize unwrapped locator tree, which will be used as the return value * when calling normalized tree nodes with parameters. */ type NormalizeTreeWithParameters<UnwrappedTree extends WithParameters, MappingResult> = (( this: void, ) => MappingResult) & WithParameters<UnwrappedTree[ParametersKey]> & NormalizeListOfSubnodes<UnwrappedTree, MappingResult>; /** * Message for type error in `Locator<...>` and `Node<...>` first argument. */ type NotLocatorDescription = 'Not a locator tree description'; /** * Type of symbol key for saving locator parameters. */ type ParametersKey = typeof PARAMETERS; /** * Keys of prototypes of `Object` and `Function`. */ type PrototypeKeys = string & (keyof typeof Object.prototype | keyof typeof Function.prototype); /** * Returns required keys of type. * `RequiredKeys<{foo: string}>` = `"foo"`. * `RequiredKeys<{foo: string, bar?: number}>` = `"foo"`. */ type RequiredKeys<Type, TypeKeys = Keys<Type>> = TypeKeys extends Keys<Type> ? Type extends Required<Pick<Type, TypeKeys>> ? TypeKeys : never : never; /** * Options of root locator with defaults values. */ type RootOptionsWithDefaults = Readonly<{ isProduction: boolean; parameterAttributePrefix: string; pathAttribute: string; pathSeparator: string; }>; /** * Type of symbol key for saving locator tree for prototype keys. */ type TreeKey = typeof TREE; /** * Wrap tree node with tree key for prototype keys. */ type TreeNode<Key, Tree> = Key extends PrototypeKeys ? Tree & WithTree<Tree> : Tree; /** * Converts union of types to intersection of this types. */ type UnionToIntersection<Union> = (Union extends any ? (arg: Union) => void : never) extends ( arg: infer Intersection, ) => void ? Intersection : never; /** * Unwrap tree node from tree key, if any. */ type UnwrapTree<Tree> = Tree extends WithTree ? Tree[TreeKey] : Tree; /** * Any node of locator tree with some component parameters. */ type WithComponentParameters<Parameters = unknown> = Readonly< Record<ComponentParametersKey, Parameters> >; /** * Object (usually properties object) with error message in error attribute key. */ type WithErrorAttribute<Message extends string | undefined = undefined> = Partial< Readonly<Record<ErrorAttributeKey, Message | ErrorAttributeBaseType>> >; /** * Object with hidden normalized tree of locators. */ type WithHidden<NormalizedTree = object> = Readonly<Record<HiddenKey, NormalizedTree>>; /** * Object with symbol key for tree of empty locator (i.e. `Locator<void>`). */ type WithIsEmptyLocator = Readonly<Record<IsEmptyLocatorKey, undefined>>; /** * Object with locator key with locator kind (it's locator itself). */ type WithLocator<Kind = string> = Readonly<Record<LocatorKey, Kind>>; /** * Object with mark with locator tree (unnormalized tree of locators, produced by `Locator<...>`). */ type WithMark<Tree = object> = Readonly<Record<MarkKey, Tree>>; /** * Object with node locator (produced by `Node<...>`). */ type WithNode<Tree = object> = Readonly<Record<NodeKey, Tree>>; /** * Any node of locator tree with some parameters. */ type WithParameters<Parameters = unknown> = Readonly<Record<ParametersKey, Parameters>>; /** * Object with tree of locators under some prototype key. */ type WithTree<Tree = object> = Readonly<Record<TreeKey, Tree>>;