playwright-reselect
Version:
A tiny helper to wright test once and reuse the logic anywhere
1 lines • 19.9 kB
Source Map (JSON)
{"version":3,"sources":["../src/index.ts","../src/utils/reselect.ts","../src/utils/reselect.types.ts"],"sourcesContent":["export { reselectTree } from './utils/reselect.js';\nexport { defineBranch, defineTree } from './utils/reselect.types.js';\nexport type { Ctx, ExpectChain } from './utils/reselect.types.js';","import type {\n\tTreeDescription,\n\tNodeFromDesc as NodeFromDesc,\n\tWrapDebugType,\n\tCtx,\n\tNodeDescription,\n} from './reselect.types.js';\nimport { Page, Locator as L, Locator, expect } from '@playwright/test';\n\n/**\n * Root of the \"in()\" tree.\n */\nexport type InReturnFromDesc<T extends TreeDescription> = {\n\t[K in keyof T]: () => NodeFromDesc<T[K]>;\n};\n\nfunction createExpectChain(locator: Locator) {\n\tconst base = expect(locator); // real Playwright expect object\n\n\tfunction wrapMatcherObject(obj: any, parentChain: any) {\n\t\tconst chain: any = {};\n\n\t\tfor (const key of Object.keys(obj)) {\n\t\t\tconst value = obj[key];\n\n\t\t\tif (typeof value === 'function') {\n\t\t\t\tchain[key] = async (...args: any[]) => {\n\t\t\t\t\tawait value.apply(obj, args);\n\t\t\t\t\treturn parentChain; // return top chain\n\t\t\t\t};\n\t\t\t}\n\n\t\t\telse if (typeof value === 'object' && value !== null) {\n\t\t\t\t// Nested matchers like `.not`\n\t\t\t\tchain[key] = wrapMatcherObject(value, parentChain);\n\t\t\t}\n\t\t}\n\n\t\treturn chain;\n\t}\n\n\tconst topChain: any = {};\n\tObject.assign(topChain, wrapMatcherObject(base, topChain));\n\n\treturn topChain as {\n\t\t[K in keyof ReturnType<typeof expect<Locator>>]:\n\t\tReturnType<typeof expect<Locator>>[K] extends (...a: infer A) => any\n\t\t? (...a: A) => Promise<any>\n\t\t: ReturnType<typeof expect<Locator>>[K] extends object\n\t\t? typeof createExpectChain extends (...args: any[]) => infer T ? T : never\n\t\t: never;\n\t};\n}\n\n\nfunction wrapLocator(locator: L): WrapDebugType {\n\t//@ts-ignore\n\tconst wrapped: WrapDebugType = Object.assign(locator, {\n\t\tdebug: debug(locator),\n\t\texpectChain: () => createExpectChain(locator),\n\t});\n\n\treturn wrapped;\n}\n\nfunction prettyHtml(html: string): string {\n\tconst formatted: string[] = [];\n\tconst regex = /(>)(<)(\\/*)/g;\n\thtml = html.replace(regex, '$1\\n$2$3'); // split tags to separate lines\n\n\tlet indent = 0;\n\tconst padding = ' ';\n\n\thtml.split('\\n').forEach((line) => {\n\t\tconst trimmed = line.trim();\n\n\t\tif (trimmed.match(/^<\\/\\w/)) {\n\t\t\t// closing tag → decrease indent\n\t\t\tindent = Math.max(indent - 1, 0);\n\t\t}\n\n\t\tformatted.push(padding.repeat(indent) + trimmed);\n\n\t\tif (trimmed.match(/^<\\w[^>]*[^\\/]>$/)) {\n\t\t\t// opening tag with children\n\t\t\tindent++;\n\t\t}\n\t});\n\n\treturn formatted.join('\\n');\n}\n\n/**\n * Recursively collect all aliases from a descriptor's descendants\n */\nfunction collectDescendantAliases(\n\tdesc: NodeDescription, \n\tcurrentPath: string[] = []\n): Map<string, { path: string[], descriptor: NodeDescription }> {\n\tconst aliases = new Map<string, { path: string[], descriptor: NodeDescription }>();\n\n\t// Recursively collect from children\n\tif (desc.children) {\n\t\tfor (const key of Object.keys(desc.children)) {\n\t\t\tconst childDesc = desc.children[key];\n\t\t\t\n\t\t\t// If this child has an alias, add it with the path to reach it\n\t\t\tif (childDesc.alias) {\n\t\t\t\taliases.set(childDesc.alias, { \n\t\t\t\t\tpath: [...currentPath, key], \n\t\t\t\t\tdescriptor: childDesc \n\t\t\t\t});\n\t\t\t}\n\t\t\t\n\t\t\t// Recursively collect aliases from this child's descendants\n\t\t\tconst childAliases = collectDescendantAliases(childDesc, [...currentPath, key]);\n\t\t\t// Merge child aliases into our collection\n\t\t\tchildAliases.forEach((value, aliasName) => {\n\t\t\t\taliases.set(aliasName, value);\n\t\t\t});\n\t\t}\n\t}\n\n\treturn aliases;\n}\n\nfunction debug(locator: Locator) {\n\treturn async () => {\n\t\ttry {\n\t\t\tconst html = await locator.evaluate((el: HTMLElement) => el.outerHTML);\n\t\t\tconst output = `\\n[DEBUG] ${locator.toString()}\\n${prettyHtml(html)}\\n`;\n\t\t\tconsole.log(output);\n\t\t\treturn output;\n\t\t} catch (err) {\n\t\t\tconsole.error('[DEBUG ERROR] Could not read innerHTML:', err);\n\t\t\treturn err;\n\t\t}\n\t};\n}\n\n/**\n * Build a node object from its description.\n */\nfunction createNode<D extends NodeDescription>(ctx: Ctx, desc: D, currentPath?: string[]): NodeFromDesc<D> {\n\t// Capture the current locator state when this node is created\n\t// @ts-ignore\n\tconst capturedSelector = ctx.locator['_selector'];\n\n\t// Collect all descendant aliases for skipToAlias\n\t// Each alias stores its descriptor (the complete branch definition with all children/custom methods)\n\t// This allows the alias to return the full subtree as if navigating to it directly\n\tconst descendantAliases = collectDescendantAliases(desc);\n\n\tconst node: any = {\n\t\tget: () => {\n\t\t\t// @ts-ignore\n\t\t\tconst locator = ctx.page.locator(ctx.locator['_selector']);\n\t\t\tctx.locator = ctx.page.locator(':root'); // reset after get() call\n\t\t\treturn wrapLocator(locator);\n\t\t},\n\t\tdebug: debug(ctx.locator),\n\t\texpectChain: () => createExpectChain(ctx.locator),\n\t\tskipToAlias: () => {\n\t\t\t// Return an object with a method for each descendant alias\n\t\t\t// When an alias method is called, it returns the complete subtree\n\t\t\t// by using the stored descriptor (which contains all children and custom methods)\n\t\t\tconst aliasesObject: any = {};\n\t\t\t\n\t\t\tdescendantAliases.forEach((aliasData, aliasName) => {\n\t\t\t\taliasesObject[aliasName] = () => {\n\t\t\t\t\t// Build the locator path from current node to the aliased node\n\t\t\t\t\t// Start from the current captured selector\n\t\t\t\t\tctx.locator = ctx.page.locator(capturedSelector);\n\n\t\t\t\t\t// Navigate through each step in the path, calling build() to update ctx.locator\n\t\t\t\t\tlet currentDesc: NodeDescription = desc;\n\t\t\t\t\tfor (const childKey of aliasData.path) {\n\t\t\t\t\t\tif (!currentDesc.children || !currentDesc.children[childKey]) {\n\t\t\t\t\t\t\tthrow new Error(`Invalid path to alias \"${aliasName}\"`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcurrentDesc = currentDesc.children[childKey];\n\t\t\t\t\t\tcurrentDesc.build(ctx);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Return a node using the aliased descriptor\n\t\t\t\t\t// This descriptor is the complete branch definition, so the returned node\n\t\t\t\t\t// has all the same children and custom methods as if we had navigated normally\n\t\t\t\t\treturn createNode(ctx, aliasData.descriptor, [...(currentPath || []), ...aliasData.path]);\n\t\t\t\t};\n\t\t\t});\n\t\t\t\n\t\t\treturn aliasesObject;\n\t\t}\n\t};\n\n\t// Children\n\tif (desc.children) {\n\t\tfor (const key of Object.keys(desc.children)) {\n\t\t\tconst childDesc = desc.children[key];\n\t\t\tnode[key] = () => {\n\t\t\t\tchildDesc.build(ctx); // concatenate the ctx\n\n\t\t\t\tconst childPath = currentPath ? [...currentPath, key] : [key];\n\t\t\t\tconst childNode = createNode(ctx, childDesc, childPath);\n\n\t\t\t\t// Check if this child's build function registered an alias\n\t\t\t\t// by checking if the locator has changed and looking for alias calls\n\t\t\t\treturn childNode;\n\t\t\t};\n\t\t}\n\t}\n\t// Custom methods\n\tif (desc.custom) {\n\t\tfor (const key of Object.keys(desc.custom)) {\n\t\t\tconst fn = desc.custom[key];\n\t\t\tnode[key] = (...args: any[]) => {\n\t\t\t\tconst result = fn(ctx, ...args);\n\t\t\t\tctx.locator = ctx.page.locator(':root'); // reset after custom getter call\n\t\t\t\treturn wrapLocator(result);\n\t\t\t};\n\t\t}\n\t}\n\n\tObject.assign(node, {\n\t\tinspect: () => {\n\t\t\t// @ts-ignore\n\t\t\tconsole.log('[INSPECT] ' + ctx.locator['_selector']);\n\t\t\treturn node;\n\t\t}\n\t});\n\treturn node;\n}\n\n/**\n * Build the root object\n */\nfunction createRoot<T extends TreeDescription>(ctx: Ctx): InReturnFromDesc<T> {\n\tconst root: any = {};\n\tfor (const rootKey of Object.keys(ctx.descriptor)) {\n\t\tconst nodeDesc = ctx.descriptor[rootKey];\n\t\troot[rootKey] = () => {\n\t\t\tnodeDesc.build(ctx); // concatenate the ctx\n\t\t\treturn createNode(ctx, nodeDesc, [rootKey]);\n\t\t};\n\t}\n\n\treturn root;\n}\n\n/**\n * Main TestLocatorResolver class.\n */\nexport class TestLocatorResolver<T> implements Ctx {\n\tpage: Page;\n\tdescriptor: any;\n\tlocator: L;\n\n\t/**\n\t * Creates an instance of TestLocatorResolver.\n\t * @param {Page} page\n\t * @param {*} descriptor\n\t * representation of the testing UI logic\n\t * Each node MUST have:\n\t * - entry: string\n\t * - build(ctx: Ctx): void\n\t * and MAY have:\n\t * - custom: { [name]: (ctx, ...args) => any }\n\t * - children: LocatorTreeDescription\n\t *\n\t * Example abstract node:\n\t *\n\t * ```ts\n\t * someNode: {\n\t * entry: 'some-node-id',\n\t * build: (ctx: Ctx) => {\n\t * ctx.locator = ctx.page.locator('#some-node-id');\n\t * },\n\t * custom: {\n\t * doSomething: (ctx: Ctx, x: number) => x * 2,\n\t * },\n\t * children: {\n\t * // recursion...\n\t * }\n\t * }\n\t * ```\n\t *\n\t * Changing this object changes BOTH the runtime behavior and\n\t * @memberof TestLocatorResolver\n\t */\n\n\tconstructor(page: Page, descriptor: T) {\n\t\tif (!descriptor) {\n\t\t\tthrow new Error('new TestLocatorResolver(page, descriptor): descriptor is required');\n\t\t}\n\t\tif (!page) {\n\t\t\tthrow new Error('new TestLocatorResolver(page, descriptor): page is required');\n\t\t}\n\t\tthis.page = page;\n\t\tthis.descriptor = descriptor;\n\t\t// @ts-ignore\n\t\tthis.locator = page.locator(':root'); // initial, will be overwritten by build()\n\t\tObject.assign(this, createRoot(this));\n\t}\n}\n\nexport const reselectTree = <T extends TreeDescription>(treeDescription: T) => (page: Page): InReturnFromDesc<T> => {\n\t// @ts-ignore\n\treturn new TestLocatorResolver<T>(page, treeDescription);\n};\n","import { Page, expect, Locator } from '@playwright/test';\n\n/**\n * Shared context passed into build/custom functions.\n */\nexport type Ctx = {\n\tpage: Page;\n\tlocator: Locator;\n\tdescriptor: TreeDescription;\n};\n\n/**\n * A custom method on a node:\n * - first arg MUST be ctx: Ctx\n * - rest args are what the user will actually pass when calling from the node.\n */\nexport type CustomFn = (ctx: Ctx, ...args: any[]) => Locator;\n\nexport type DescriptorType = {\n\t[key: string]: NodeDescription;\n};\n\n/**\n * Describes a node configuration for building and managing child nodes.\n * @property {Function} build - Function that constructs the node within a given context.\n * @property {DescriptorType} [children] - Optional child node descriptors.\n * @property {Record<string, CustomFn>} [custom] - Optional mapping of custom function names to their implementations.\n * @property {string} [alias] - Optional alias name for this node, allowing direct access from root.\n */\nexport type NodeDescription = {\n\tbuild: (ctx: Ctx) => void;\n\tchildren?: DescriptorType;\n\tcustom?: Record<string, CustomFn>;\n\talias?: string;\n};\n\n/**\n * Utility: get the \"user-visible\" arguments of a CustomFn\n * (everything after the initial ctx).\n */\nexport type CustomFnArgs<T> = T extends (ctx: Ctx, ...args: infer A) => any ? A : never;\n\n/**\n * Helper to define a branch/node with proper type inference for aliases\n */\nexport const defineBranch = <const T extends NodeDescription>(branch: T): T => branch;\n\n/**\n * Helper to define the tree with proper type inference for aliases\n */\nexport const defineTree = <const T extends TreeDescription>(tree: T): T => tree;\n\n/**\n * Description of the locator tree:\n * - build: how to update ctx.locator at this node\n * - children: nested nodes\n * - custom: extra methods on this node (e.g. getTitle)\n */\nexport type TreeDescription = {\n\t[key: string]: NodeDescription;\n};\n\n/**\n * Collect direct aliases (nodes with alias property) from a TreeDescription\n */\ntype DirectAliases<T extends TreeDescription> = {\n\t[K in keyof T as T[K] extends { alias: infer A extends string } ? A : never]: T[K]\n};\n\n/**\n * Recursively collect all descendant aliases from nested children\n */\ntype NestedAliases<T extends TreeDescription> = UnionToIntersection<\n\t{\n\t\t[K in keyof T]: T[K] extends { children: infer C extends TreeDescription }\n\t\t? DirectAliases<C> & NestedAliases<C>\n\t\t: {}\n\t}[keyof T]\n>;\n\n/**\n * Helper type to convert union to intersection\n */\ntype UnionToIntersection<U> =\n\t(U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;\n\n/**\n * Extract all descendant aliases from a descriptor, merging all found aliases\n */\nexport type ExtractDescendantAliases<D> = \n\tD extends { children: infer C extends TreeDescription }\n\t? DirectAliases<C> & NestedAliases<C>\n\t\t: {};\n\n/**\n * Type for the object returned by skipToAlias().\n * Maps alias names to methods that jump directly to aliased descendant nodes.\n * \n * **TypeScript Navigation Limitation:**\n * Ctrl+Click on alias method calls (e.g., `.headerLogo()`) shows the type definition,\n * not the actual node source. This is a TypeScript limitation with mapped types.\n * \n * **Workaround:** Use destructuring for better IDE navigation:\n * ```ts\n * const { headerLogo, search } = select(page).app().skipToAlias();\n * await headerLogo().click(); // Ctrl+Click on \"headerLogo\" works here\n * ```\n */\nexport type AliasesObject<D> = {\n\t[K in keyof ExtractDescendantAliases<D>]: () => NodeFromDesc<ExtractDescendantAliases<D>[K] & NodeDescription>\n};\n\n\nexport type Get = Locator & {\n\tdebug: () => Promise<void>;\t\n\texpectChain: () => ChainType;\n};\n\n/**\n * One node in the chain, derived from a description:\n * - always has get(): Locator\n * - has child methods if children are defined\n * - has custom methods if custom is defined\n */\nexport type NodeFromDesc<D extends { children?: TreeDescription; custom?: Record<string, CustomFn> }> = {\n\t// get() → wrapped locator with .debug()\n\tget: () => Get;\n\tinspect: () => NodeFromDesc<D>;\n\tdebug: () => Promise<void>;\n\texpectChain: () => ChainType;\n\tskipToAlias: () => AliasesObject<D>;\n\n} & (D['children'] extends TreeDescription\n\t? {\n\t\t\t[K in keyof D['children']]: () => NodeFromDesc<D['children'][K]>;\n\t }\n\t: {}) &\n\t(D['custom'] extends Record<string, CustomFn>\n\t\t? {\n\t\t\t\t// custom getters also return wrapped locator with .debug()\n\t\t\t\t[K in keyof D['custom']]: (...a: CustomFnArgs<D['custom'][K]>) => Get;\n\t\t }\n\t\t: {});\n\nexport type WrapDebugType = Locator & {\n\tdebug: () => Promise<void>;\n\texpectChain: () => ChainType;\n\talias?: (name: string) => void;\n};\n\n// chain\nconst base = expect; // the real Playwright expect object\n\nconst chain: any = {};\n\nfor (const key of Object.keys(base)) {\n const value = (base as any)[key];\n\n if (typeof value === 'function') {\n chain[key] = async (...args: any[]) => {\n await value.apply(base, args);\n return chain; // allow chaining\n };\n }\n}\n\nexport type ChainType = {\n [K in keyof ReturnType<typeof expect<Locator>>]: ReturnType<typeof expect<Locator>>[K] extends (...a: infer A) => any ? (...a: A) => Promise<any> & typeof chain : never;\n};\n\nexport type ExpectChain = ReturnType<typeof expect<Locator>>;"],"mappings":"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","names":["index_exports","__export","defineBranch","defineTree","reselectTree","__toCommonJS","import_test","createExpectChain","locator","base","wrapMatcherObject","obj","parentChain","chain","key","value","args","topChain","wrapLocator","debug","prettyHtml","html","formatted","regex","indent","padding","line","trimmed","collectDescendantAliases","desc","currentPath","aliases","childDesc","aliasName","el","output","err","createNode","ctx","capturedSelector","descendantAliases","node","aliasesObject","aliasData","currentDesc","childKey","childPath","fn","result","createRoot","root","rootKey","nodeDesc","TestLocatorResolver","page","descriptor","reselectTree","treeDescription","import_test","defineBranch","branch","defineTree","tree","base","chain","key","value","args"]}