Created
March 24, 2025 11:29
-
-
Save christian-bromann/3d525e86c5dccec9e8171d3a795bc8b4 to your computer and use it in GitHub Desktop.
WebdriverIO Workshop Script for Chapter 13th
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface NodeInfo { | |
// xpath: string | |
cssSelector: string | |
tagName: string | |
role?: string | |
name?: string | null | |
description?: string | |
isDisabled?: boolean | |
isAccessible: boolean | |
children?: NodeInfo[] | |
attributes?: Record<string, string> | |
isVisible: boolean | |
value?: string | |
textContent?: string | |
} | |
declare global { | |
interface Window { | |
__wdioDomAccessibilityAPI: { | |
computeAccessibleDescription: (node: HTMLElement) => string | |
computeAccessibleName: (node: HTMLElement) => string | |
getRole: (node: HTMLElement) => string | |
isDisabled: (node: HTMLElement) => boolean | |
isInaccessible: (node: HTMLElement) => boolean | |
isSubtreeInaccessible: (node: HTMLElement) => boolean | |
} | |
__wdioGetXPath: (node: HTMLElement) => string | |
__wdioGetCssSelector: (node: HTMLElement) => string | |
} | |
} | |
export function captureAccessibilityTree(root = document.body) { | |
// Using native Accessibility APIs | |
if (!window.getComputedStyle) { | |
return null | |
} | |
/** | |
* injected via `addInitScript` after session initialization | |
*/ | |
const { | |
computeAccessibleDescription, | |
computeAccessibleName, | |
getRole, | |
isDisabled, | |
isInaccessible, | |
} = window.__wdioDomAccessibilityAPI | |
// const getXPath = window.__wdioGetXPath | |
const getCssSelector = window.__wdioGetCssSelector | |
function processNode(node: HTMLElement) { | |
const isVisible = node.checkVisibility({ | |
opacityProperty: true, | |
visibilityProperty: true, | |
contentVisibilityAuto: true | |
}) | |
// const xpath = getXPath(node) | |
const cssSelector = getCssSelector(node) | |
const isInaccessibleProp = isInaccessible(node) | |
const role = getRole(node) | |
const name = computeAccessibleName(node) | |
const description = computeAccessibleDescription(node) | |
const isDisabledProp = isDisabled(node) | |
/** | |
* If the node is not visible and not accessible, we can skip it | |
*/ | |
if (!isVisible && isInaccessibleProp) { | |
return null | |
} | |
// Collect all attributes | |
const attributes = Array.from(node.attributes) | |
.reduce((attributes, attr) => { | |
attributes[attr.name] = attr.value | |
return attributes | |
}, {} as Record<string, string>) | |
// Process child nodes | |
const children = Array.from(node.children) | |
.reduce((c, child) => { | |
const childInfo = processNode(child as HTMLElement) | |
if (childInfo) { | |
c.push(childInfo) | |
} | |
return c | |
}, [] as NodeInfo[]) | |
const nodeInfo: NodeInfo = { | |
// xpath, | |
cssSelector, | |
tagName: node.tagName, | |
isVisible, | |
isAccessible: !isInaccessibleProp, | |
...(Object.keys(attributes).length > 0 ? { attributes } : {}) | |
} | |
const textContent = Array.from(node.childNodes) | |
.filter((child) => child.nodeType === Node.TEXT_NODE) | |
.map((child) => child.textContent) | |
.filter(Boolean) | |
.join(' ') | |
if (role) { | |
nodeInfo.role = role | |
} | |
if (name) { | |
nodeInfo.name = name | |
} | |
if (textContent) { | |
nodeInfo.textContent = textContent | |
} | |
if (description) { | |
nodeInfo.description = description | |
} | |
if (children.length > 0) { | |
nodeInfo.children = children | |
} | |
if (isDisabledProp) { | |
nodeInfo.isDisabled = isDisabledProp | |
} | |
if ('value' in node && node.value && typeof node.value === 'string') { | |
nodeInfo.value = node.value | |
} | |
return nodeInfo | |
} | |
return processNode(root) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import path from 'path' | |
import url from 'url' | |
import fs from 'fs/promises' | |
import type { Services } from '@wdio/types' | |
// ... | |
const __dirname = path.dirname(url.fileURLToPath(import.meta.url)) | |
const a11yScript = path.resolve(__dirname, 'thirdParty', 'dom-accessibility-api.js') | |
const a11yScriptContent = await fs.readFile(a11yScript, 'utf-8') | |
const getCssSelectorScript = path.resolve(__dirname, 'thirdParty', 'get-css-selector.js') | |
const getCssSelectorScriptContent = await fs.readFile(getCssSelectorScript, 'utf-8') | |
export default class ValidationService implements Services.ServiceInstance { | |
async before (_: never, __: never, browser: WebdriverIO.Browser) { | |
/** | |
* register scripts | |
*/ | |
const contextId = await browser.getWindowHandle() | |
await Promise.all([ | |
this.#registerScripts(a11yScriptContent, contextId), | |
this.#registerScripts(getCssSelectorScriptContent, contextId) | |
]) | |
/** | |
* add validate command to browser | |
*/ | |
log.info(`Adding validate command to browser`) | |
browser.addCommand('validate', this.#validate.bind(this)) | |
} | |
/** | |
* Custom command to validate the current state of the application | |
* @param prompt - The prompt to validate | |
* @returns nothing, but throws an error if the validation is invalid | |
*/ | |
async #validate(prompt: string) { | |
// your implementation | |
} | |
/** | |
* Register a script in the browser for the current context and future page loads | |
* with the given context. | |
* | |
* @param fn - The script to register | |
* @param contextId - The context to register the script in | |
* @returns A promise that resolves when the script is registered | |
*/ | |
#registerScripts (fn: string, contextId: string) { | |
if (!this.#browser) { | |
return | |
} | |
function handleScriptError (err: unknown) { | |
const error = err instanceof Error ? err : new Error(`unknown error: ${err}`) | |
log.error('⚠️ Error adding script', error.message) | |
} | |
const functionDeclaration = `${fn}` | |
return Promise.all([ | |
this.#browser.scriptAddPreloadScript({ | |
functionDeclaration, | |
contexts: [contextId] | |
}).catch(handleScriptError), | |
this.#browser.scriptCallFunction({ | |
functionDeclaration, | |
target: { context: contextId }, | |
awaitPromise: false | |
}).catch(handleScriptError) | |
]) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function domAccessibilityAPIScipt () {var e=Object.prototype.toString;function t(t){return"function"==typeof t||"[object Function]"===e.call(t)}var r=Math.pow(2,53)-1;function n(e){var t=function(e){var t=Number(e);return isNaN(t)?0:0!==t&&isFinite(t)?(t>0?1:-1)*Math.floor(Math.abs(t)):t}(e);return Math.min(Math.max(t,0),r)}function i(e,r){var i=Array,a=Object(e);if(null==e)throw new TypeError("Array.from requires an array-like object - not null or undefined");if(void 0!==r&&!t(r))throw new TypeError("Array.from: when provided, the second argument must be a function");for(var o,u=n(a.length),l=t(i)?Object(new i(u)):new Array(u),d=0;d<u;)o=a[d],l[d]=r?r(o,d):o,d+=1;return l.length=u,l}function a(e){return a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},a(e)}function o(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,u(n.key),n)}}function u(e){var t=function(e,t){if("object"!=a(e)||!e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!=a(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==a(t)?t:t+""}var l="undefined"==typeof Set?Set:function(){return e=function e(){var t,r,n,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),t=this,n=void 0,(r=u(r="items"))in t?Object.defineProperty(t,r,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[r]=n,this.items=i},(t=[{key:"add",value:function(e){return!1===this.has(e)&&this.items.push(e),this}},{key:"clear",value:function(){this.items=[]}},{key:"delete",value:function(e){var t=this.items.length;return this.items=this.items.filter((function(t){return t!==e})),t!==this.items.length}},{key:"forEach",value:function(e){var t=this;this.items.forEach((function(r){e(r,r,t)}))}},{key:"has",value:function(e){return-1!==this.items.indexOf(e)}},{key:"size",get:function(){return this.items.length}}])&&o(e.prototype,t),r&&o(e,r),Object.defineProperty(e,"prototype",{writable:!1}),e;var e,t,r}();function d(e){var t;return null!==(t=e.localName)&&void 0!==t?t:e.tagName.toLowerCase()}var c={article:"article",aside:"complementary",button:"button",datalist:"listbox",dd:"definition",details:"group",dialog:"dialog",dt:"term",fieldset:"group",figure:"figure",form:"form",footer:"contentinfo",h1:"heading",h2:"heading",h3:"heading",h4:"heading",h5:"heading",h6:"heading",header:"banner",hr:"separator",html:"document",legend:"legend",li:"listitem",math:"math",main:"main",menu:"list",nav:"navigation",ol:"list",optgroup:"group",option:"option",output:"status",progress:"progressbar",section:"region",summary:"button",table:"table",tbody:"rowgroup",textarea:"textbox",tfoot:"rowgroup",td:"cell",th:"columnheader",thead:"rowgroup",tr:"row",ul:"list"},s={caption:new Set(["aria-label","aria-labelledby"]),code:new Set(["aria-label","aria-labelledby"]),deletion:new Set(["aria-label","aria-labelledby"]),emphasis:new Set(["aria-label","aria-labelledby"]),generic:new Set(["aria-label","aria-labelledby","aria-roledescription"]),insertion:new Set(["aria-label","aria-labelledby"]),none:new Set(["aria-label","aria-labelledby"]),paragraph:new Set(["aria-label","aria-labelledby"]),presentation:new Set(["aria-label","aria-labelledby"]),strong:new Set(["aria-label","aria-labelledby"]),subscript:new Set(["aria-label","aria-labelledby"]),superscript:new Set(["aria-label","aria-labelledby"])};function f(e,t){return function(e,t){return["aria-atomic","aria-busy","aria-controls","aria-current","aria-description","aria-describedby","aria-details","aria-dropeffect","aria-flowto","aria-grabbed","aria-hidden","aria-keyshortcuts","aria-label","aria-labelledby","aria-live","aria-owns","aria-relevant","aria-roledescription"].some((function(r){var n;return e.hasAttribute(r)&&!(null!==(n=s[t])&&void 0!==n&&n.has(r))}))}(e,t)}function b(e){var t=function(e){var t=e.getAttribute("role");if(null!==t){var r=t.trim().split(" ")[0];if(r.length>0)return r}return null}(e);if(null===t||-1!==p.indexOf(t)){var r=function(e){var t=c[d(e)];if(void 0!==t)return t;switch(d(e)){case"a":case"area":case"link":if(e.hasAttribute("href"))return"link";break;case"img":return""!==e.getAttribute("alt")||f(e,"img")?"img":"presentation";case"input":var r=e.type;switch(r){case"button":case"image":case"reset":case"submit":return"button";case"checkbox":case"radio":return r;case"range":return"slider";case"email":case"tel":case"text":case"url":return e.hasAttribute("list")?"combobox":"textbox";case"search":return e.hasAttribute("list")?"combobox":"searchbox";case"number":return"spinbutton";default:return null}case"select":return e.hasAttribute("multiple")||e.size>1?"listbox":"combobox"}return null}(e);if(-1===p.indexOf(t||"")||f(e,r||""))return r}return t}var p=["presentation","none"];function m(e){return null!==e&&e.nodeType===e.ELEMENT_NODE}function v(e){return m(e)&&"caption"===d(e)}function h(e){return m(e)&&"input"===d(e)}function y(e){return m(e)&&"legend"===d(e)}function g(e){return function(e){return m(e)&&void 0!==e.ownerSVGElement}(e)&&"title"===d(e)}function w(e,t){if(m(e)&&e.hasAttribute(t)){var r=e.getAttribute(t).split(" "),n=e.getRootNode?e.getRootNode():e.ownerDocument;return r.map((function(e){return n.getElementById(e)})).filter((function(e){return null!==e}))}return[]}function S(e,t){return!!m(e)&&-1!==t.indexOf(b(e))}function E(e,t){if(!m(e))return!1;if("range"===t)return S(e,["meter","progressbar","scrollbar","slider","spinbutton"]);throw new TypeError("No knowledge about abstract role '".concat(t,"'. This is likely a bug :("))}function x(e,t){var r=i(e.querySelectorAll(t));return w(e,"aria-owns").forEach((function(e){r.push.apply(r,i(e.querySelectorAll(t)))})),r}function A(e){return m(t=e)&&"select"===d(t)?e.selectedOptions||x(e,"[selected]"):x(e,'[aria-selected="true"]');var t}function O(e){return h(e)||m(t=e)&&"textarea"===d(t)?e.value:e.textContent||"";var t}function j(e){var t=e.getPropertyValue("content");return/^["'].*["']$/.test(t)?t.slice(1,-1):""}function N(e){var t=d(e);return"button"===t||"input"===t&&"hidden"!==e.getAttribute("type")||"meter"===t||"output"===t||"progress"===t||"select"===t||"textarea"===t}function P(e){if(N(e))return e;var t=null;return e.childNodes.forEach((function(e){if(null===t&&m(e)){var r=P(e);null!==r&&(t=r)}})),t}function k(e){if(void 0!==e.control)return e.control;var t=e.getAttribute("for");return null!==t?e.ownerDocument.getElementById(t):P(e)}function I(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=new l,n="undefined"==typeof Map?void 0:new Map,a=function(e){var t=(null===e.ownerDocument?e:e.ownerDocument).defaultView;if(null===t)throw new TypeError("no window available");return t}(e),o=t.compute,u=void 0===o?"name":o,c=t.computedStyleSupportsPseudoElements,s=void 0===c?void 0!==t.getComputedStyle:c,f=t.getComputedStyle,b=void 0===f?a.getComputedStyle.bind(a):f,x=t.hidden,P=void 0!==x&&x,I=function(e,t){if(void 0!==t)throw new Error("use uncachedGetComputedStyle directly for pseudo elements");if(void 0===n)return b(e);var r=n.get(e);if(r)return r;var i=b(e,t);return n.set(e,i),i};function L(e,t){var r,n,a="";if(m(e)&&s){var o=j(b(e,"::before"));a="".concat(o," ").concat(a)}if((function(e){return m(e)&&"slot"===d(e)}(e)?0===(n=(r=e).assignedNodes()).length?i(r.childNodes):n:i(e.childNodes).concat(w(e,"aria-owns"))).forEach((function(e){var r=C(e,{isEmbeddedInLabel:t.isEmbeddedInLabel,isReferenced:!1,recursion:!0}),n="inline"!==(m(e)?I(e).getPropertyValue("display"):"inline")?" ":"";a+="".concat(n).concat(r).concat(n)})),m(e)&&s){var u=j(b(e,"::after"));a="".concat(a," ").concat(u)}return a.trim()}function R(e,t){var n=e.getAttributeNode(t);return null===n||r.has(n)||""===n.value.trim()?null:(r.add(n),n.value)}function T(e){if(!m(e))return null;if(function(e){return m(e)&&"fieldset"===d(e)}(e)){r.add(e);for(var t=i(e.childNodes),n=0;n<t.length;n+=1){var a=t[n];if(y(a))return C(a,{isEmbeddedInLabel:!1,isReferenced:!1,recursion:!1})}}else if(function(e){return m(e)&&"table"===d(e)}(e)){r.add(e);for(var o=i(e.childNodes),u=0;u<o.length;u+=1){var l=o[u];if(v(l))return C(l,{isEmbeddedInLabel:!1,isReferenced:!1,recursion:!1})}}else{if(function(e){return m(e)&&"svg"===d(e)}(e)){r.add(e);for(var c=i(e.childNodes),s=0;s<c.length;s+=1){var f=c[s];if(g(f))return f.textContent}return null}if("img"===d(e)||"area"===d(e)){var b=R(e,"alt");if(null!==b)return b}else if(function(e){return m(e)&&"optgroup"===d(e)}(e)){var p=R(e,"label");if(null!==p)return p}}if(h(e)&&("button"===e.type||"submit"===e.type||"reset"===e.type)){var w=R(e,"value");if(null!==w)return w;if("submit"===e.type)return"Submit";if("reset"===e.type)return"Reset"}var E,x,A=null===(x=(E=e).labels)?x:void 0!==x?i(x):N(E)?i(E.ownerDocument.querySelectorAll("label")).filter((function(e){return k(e)===E})):null;if(null!==A&&0!==A.length)return r.add(e),i(A).map((function(e){return C(e,{isEmbeddedInLabel:!0,isReferenced:!1,recursion:!0})})).filter((function(e){return e.length>0})).join(" ");if(h(e)&&"image"===e.type){var O=R(e,"alt");if(null!==O)return O;var j=R(e,"title");return null!==j?j:"Submit Query"}if(S(e,["button"])){var P=L(e,{isEmbeddedInLabel:!1,isReferenced:!1});if(""!==P)return P}return null}function C(e,t){if(r.has(e))return"";if(!P&&function(e,t){if(!m(e))return!1;if(e.hasAttribute("hidden")||"true"===e.getAttribute("aria-hidden"))return!0;var r=t(e);return"none"===r.getPropertyValue("display")||"hidden"===r.getPropertyValue("visibility")}(e,I)&&!t.isReferenced)return r.add(e),"";var n=m(e)?e.getAttributeNode("aria-labelledby"):null,a=null===n||r.has(n)?[]:w(e,"aria-labelledby");if("name"===u&&!t.isReferenced&&a.length>0)return r.add(n),a.map((function(e){return C(e,{isEmbeddedInLabel:t.isEmbeddedInLabel,isReferenced:!0,recursion:!1})})).join(" ");var o,l=t.recursion&&(S(o=e,["button","combobox","listbox","textbox"])||E(o,"range"))&&"name"===u;if(!l){var d=(m(e)&&e.getAttribute("aria-label")||"").trim();if(""!==d&&"name"===u)return r.add(e),d;if(!function(e){return S(e,p)}(e)){var c=T(e);if(null!==c)return r.add(e),c}}if(S(e,["menu"]))return r.add(e),"";if(l||t.isEmbeddedInLabel||t.isReferenced){if(S(e,["combobox","listbox"])){r.add(e);var s=A(e);return 0===s.length?h(e)?e.value:"":i(s).map((function(e){return C(e,{isEmbeddedInLabel:t.isEmbeddedInLabel,isReferenced:!1,recursion:!0})})).join(" ")}if(E(e,"range"))return r.add(e),e.hasAttribute("aria-valuetext")?e.getAttribute("aria-valuetext"):e.hasAttribute("aria-valuenow")?e.getAttribute("aria-valuenow"):e.getAttribute("value")||"";if(S(e,["textbox"]))return r.add(e),O(e)}if(function(e){return S(e,["button","cell","checkbox","columnheader","gridcell","heading","label","legend","link","menuitem","menuitemcheckbox","menuitemradio","option","radio","row","rowheader","switch","tab","tooltip","treeitem"])}(e)||m(e)&&t.isReferenced||function(e){return v(e)}(e)){var f=L(e,{isEmbeddedInLabel:t.isEmbeddedInLabel,isReferenced:!1});if(""!==f)return r.add(e),f}if(e.nodeType===e.TEXT_NODE)return r.add(e),e.textContent||"";if(t.recursion)return r.add(e),L(e,{isEmbeddedInLabel:t.isEmbeddedInLabel,isReferenced:!1});var b=function(e){return m(e)?R(e,"title"):null}(e);return null!==b?(r.add(e),b):(r.add(e),"")}return C(e,{isEmbeddedInLabel:!1,isReferenced:"description"===u,recursion:!1}).trim().replace(/\s\s+/g," ")}function L(e){return L="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},L(e)}function R(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function T(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?R(Object(r),!0).forEach((function(t){C(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):R(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function C(e,t,r){var n;return n=function(e,t){if("object"!=L(e)||!e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!=L(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(t,"string"),(t="symbol"==L(n)?n:n+"")in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function D(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=w(e,"aria-describedby").map((function(e){return I(e,T(T({},t),{},{compute:"description"}))})).join(" ");if(""===r){var n=e.getAttribute("aria-description");r=null===n?"":n}if(""===r){var i=e.getAttribute("title");r=null===i?"":i}return r}function M(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return S(e,["caption","code","deletion","emphasis","generic","insertion","none","paragraph","presentation","strong","subscript","superscript"])?"":I(e,t)}function V(e){var t,r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=r.getComputedStyle,i=void 0===n?null===(t=e.ownerDocument.defaultView)||void 0===t?void 0:t.getComputedStyle:n,a=r.isSubtreeInaccessible,o=void 0===a?q:a;if("function"!=typeof i)throw new TypeError("Owner document of the element needs to have an associated window.");if("hidden"===i(e).visibility)return!0;for(var u=e;u;){if(o(u,{getComputedStyle:i}))return!0;u=u.parentElement}return!1}function q(e){var t,r=(arguments.length>1&&void 0!==arguments[1]?arguments[1]:{}).getComputedStyle,n=void 0===r?null===(t=e.ownerDocument.defaultView)||void 0===t?void 0:t.getComputedStyle:r;if("function"!=typeof n)throw new TypeError("Owner document of the element needs to have an associated window.");return!0===e.hidden||("true"===e.getAttribute("aria-hidden")||"none"===n(e).display)}var z=new Set(["button","fieldset","input","optgroup","option","select","textarea"]);function B(e){var t=d(e);return!(!z.has(t)||!e.hasAttribute("disabled"))||"true"===e.getAttribute("aria-disabled")} | |
window.__wdioDomAccessibilityAPI = {computeAccessibleDescription: D, computeAccessibleName: M, getRole: b, isDisabled: B, isInaccessible: V, isSubtreeInaccessible: q}} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function getCssSelectorScript () { | |
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.CssSelectorGenerator=e():t.CssSelectorGenerator=e()}(self,(()=>(()=>{"use strict";var t={d:(e,n)=>{for(var r in n)t.o(n,r)&&!t.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:n[r]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};function n(t){return"object"==typeof t&&null!==t&&t.nodeType===Node.ELEMENT_NODE}t.r(e),t.d(e,{default:()=>Q,getCssSelector:()=>K});const r={NONE:"",DESCENDANT:" ",CHILD:" > "},o={id:"id",class:"class",tag:"tag",attribute:"attribute",nthchild:"nthchild",nthoftype:"nthoftype"},i="CssSelectorGenerator";function c(t="unknown problem",...e){console.warn(`${i}: ${t}`,...e)}const u={selectors:[o.id,o.class,o.tag,o.attribute],includeTag:!1,whitelist:[],blacklist:[],combineWithinSelector:!0,combineBetweenSelectors:!0,root:null,maxCombinations:Number.POSITIVE_INFINITY,maxCandidates:Number.POSITIVE_INFINITY};function s(t){return t instanceof RegExp}function a(t){return["string","function"].includes(typeof t)||s(t)}function l(t){return Array.isArray(t)?t.filter(a):[]}function f(t){const e=[Node.DOCUMENT_NODE,Node.DOCUMENT_FRAGMENT_NODE,Node.ELEMENT_NODE];return function(t){return t instanceof Node}(t)&&e.includes(t.nodeType)}function d(t,e){if(f(t))return t.contains(e)||c("element root mismatch","Provided root does not contain the element. This will most likely result in producing a fallback selector using element's real root node. If you plan to use the selector using provided root (e.g. `root.querySelector`), it will not work as intended."),t;const n=e.getRootNode({composed:!1});return f(n)?(n!==document&&c("shadow root inferred","You did not provide a root and the element is a child of Shadow DOM. This will produce a selector using ShadowRoot as a root. If you plan to use the selector using document as a root (e.g. `document.querySelector`), it will not work as intended."),n):S(e)}function m(t){return"number"==typeof t?t:Number.POSITIVE_INFINITY}function p(t=[]){const[e=[],...n]=t;return 0===n.length?e:n.reduce(((t,e)=>t.filter((t=>e.includes(t)))),e)}function g(t){return[].concat(...t)}function h(t){const e=t.map((t=>{if(s(t))return e=>t.test(e);if("function"==typeof t)return e=>{const n=t(e);return"boolean"!=typeof n?(c("pattern matcher function invalid","Provided pattern matching function does not return boolean. It's result will be ignored.",t),!1):n};if("string"==typeof t){const e=new RegExp("^"+t.replace(/[|\\{}()[\]^$+?.]/g,"\\$&").replace(/\*/g,".+")+"$");return t=>e.test(t)}return c("pattern matcher invalid","Pattern matching only accepts strings, regular expressions and/or functions. This item is invalid and will be ignored.",t),()=>!1}));return t=>e.some((e=>e(t)))}function b(t,e,n){const r=Array.from(d(n,t[0]).querySelectorAll(e));return r.length===t.length&&t.every((t=>r.includes(t)))}function y(t,e){e=null!=e?e:S(t);const r=[];let o=t;for(;n(o)&&o!==e;)r.push(o),o=o.parentElement;return r}function N(t,e){return p(t.map((t=>y(t,e))))}function S(t){return t.ownerDocument.querySelector(":root")}const E=", ",v=new RegExp(["^$","\\s"].join("|")),w=new RegExp(["^$"].join("|")),I=[o.nthoftype,o.tag,o.id,o.class,o.attribute,o.nthchild],T=h(["class","id","ng-*"]);function O({name:t}){return`[${t}]`}function C({name:t,value:e}){return`[${t}='${e}']`}function x({nodeName:t,nodeValue:e}){return{name:Y(t),value:Y(null!=e?e:void 0)}}function j(t){const e=Array.from(t.attributes).filter((e=>function({nodeName:t,nodeValue:e},n){const r=n.tagName.toLowerCase();return!(["input","option"].includes(r)&&"value"===t||"src"===t&&(null==e?void 0:e.startsWith("data:"))||T(t))}(e,t))).map(x);return[...e.map(O),...e.map(C)]}function A(t){var e;return(null!==(e=t.getAttribute("class"))&&void 0!==e?e:"").trim().split(/\s+/).filter((t=>!w.test(t))).map((t=>`.${Y(t)}`))}function $(t){var e;const n=null!==(e=t.getAttribute("id"))&&void 0!==e?e:"",r=`#${Y(n)}`,o=t.getRootNode({composed:!1});return!v.test(n)&&b([t],r,o)?[r]:[]}function D(t){const e=t.parentNode;if(e){const r=Array.from(e.childNodes).filter(n).indexOf(t);if(r>-1)return[`:nth-child(${String(r+1)})`]}return[]}function R(t){return[Y(t.tagName.toLowerCase())]}function P(t){const e=[...new Set(g(t.map(R)))];return 0===e.length||e.length>1?[]:[e[0]]}function _(t){const e=P([t])[0],n=t.parentElement;if(n){const r=Array.from(n.children).filter((t=>t.tagName.toLowerCase()===e)),o=r.indexOf(t);if(o>-1)return[`${e}:nth-of-type(${String(o+1)})`]}return[]}function k(t=[],{maxResults:e=Number.POSITIVE_INFINITY}={}){return Array.from(function*(t=[],{maxResults:e=Number.POSITIVE_INFINITY}={}){let n=0,r=M(1);for(;r.length<=t.length&&n<e;){n+=1;const e=r.map((e=>t[e]));yield e,r=L(r,t.length-1)}}(t,{maxResults:e}))}function L(t=[],e=0){const n=t.length;if(0===n)return[];const r=[...t];r[n-1]+=1;for(let t=n-1;t>=0;t--)if(r[t]>e){if(0===t)return M(n+1);r[t-1]++,r[t]=r[t-1]+1}return r[n-1]>e?M(n+1):r}function M(t=1){return Array.from(Array(t).keys())}const V=":".charCodeAt(0).toString(16).toUpperCase(),F=/[ !"#$%&'()\[\]{|}<>*+,./;=?@^`~\\]/;function Y(t=""){return CSS?CSS.escape(t):function(t=""){return t.split("").map((t=>":"===t?`\\${V} `:F.test(t)?`\\${t}`:escape(t).replace(/%/g,"\\"))).join("")}(t)}const W={tag:P,id:function(t){return 0===t.length||t.length>1?[]:$(t[0])},class:function(t){return p(t.map(A))},attribute:function(t){return p(t.map(j))},nthchild:function(t){return p(t.map(D))},nthoftype:function(t){return p(t.map(_))}},q={tag:R,id:$,class:A,attribute:j,nthchild:D,nthoftype:_};function B(t){return t.includes(o.tag)||t.includes(o.nthoftype)?[...t]:[...t,o.tag]}function G(t={}){const e=[...I];return t[o.tag]&&t[o.nthoftype]&&e.splice(e.indexOf(o.tag),1),e.map((e=>{return(r=t)[n=e]?r[n].join(""):"";var n,r})).join("")}function H(t,e,n="",o){const i=function(t,e){return""===e?t:function(t,e){return[...t.map((t=>e+r.DESCENDANT+t)),...t.map((t=>e+r.CHILD+t))]}(t,e)}(function(t,e,n){const r=function(t,e){const{blacklist:n,whitelist:r,combineWithinSelector:o,maxCombinations:i}=e,c=h(n),u=h(r);return function(t){const{selectors:e,includeTag:n}=t,r=[...e];return n&&!r.includes("tag")&&r.push("tag"),r}(e).reduce(((e,n)=>{const r=function(t,e){return(0,W[e])(t)}(t,n),s=function(t=[],e,n){return t.filter((t=>n(t)||!e(t)))}(r,c,u),a=function(t=[],e){return t.sort(((t,n)=>{const r=e(t),o=e(n);return r&&!o?-1:!r&&o?1:0}))}(s,u);return e[n]=o?k(a,{maxResults:i}):a.map((t=>[t])),e}),{})}(t,n),o=function(t,e){return function(t){const{selectors:e,combineBetweenSelectors:n,includeTag:r,maxCandidates:o}=t,i=n?k(e,{maxResults:o}):e.map((t=>[t]));return r?i.map(B):i}(e).map((e=>function(t,e){const n={};return t.forEach((t=>{const r=e[t];r&&r.length>0&&(n[t]=r)})),function(t={}){let e=[];return Object.entries(t).forEach((([t,n])=>{e=n.flatMap((n=>0===e.length?[{[t]:n}]:e.map((e=>Object.assign(Object.assign({},e),{[t]:n})))))})),e}(n).map(G)}(e,t))).filter((t=>t.length>0))}(r,n),i=g(o);return[...new Set(i)]}(t,0,o),n);for(const n of i)if(b(t,n,e))return n;return null}function U(t){return{value:t,include:!1}}function z({selectors:t,operator:e}){let n=[...I];t[o.tag]&&t[o.nthoftype]&&(n=n.filter((t=>t!==o.tag)));let r="";return n.forEach((e=>{var n;(null!==(n=t[e])&&void 0!==n?n:[]).forEach((({value:t,include:e})=>{e&&(r+=t)}))})),e+r}function J(t){return[":root",...y(t).reverse().map((t=>{const e=function(t,e,n=r.NONE){const o={};return e.forEach((e=>{Reflect.set(o,e,function(t,e){return q[e](t)}(t,e).map(U))})),{element:t,operator:n,selectors:o}}(t,[o.nthchild],r.CHILD);return e.selectors.nthchild.forEach((t=>{t.include=!0})),e})).map(z)].join("")}function K(t,e={}){var r;const i=function(t){(t instanceof NodeList||t instanceof HTMLCollection)&&(t=Array.from(t));const e=(Array.isArray(t)?t:[t]).filter(n);return[...new Set(e)]}(t),c=function(t,e={}){const n=Object.assign(Object.assign({},u),e);return{selectors:(r=n.selectors,Array.isArray(r)?r.filter((t=>{return e=o,n=t,Object.values(e).includes(n);var e,n})):[]),whitelist:l(n.whitelist),blacklist:l(n.blacklist),root:d(n.root,t),combineWithinSelector:!!n.combineWithinSelector,combineBetweenSelectors:!!n.combineBetweenSelectors,includeTag:!!n.includeTag,maxCombinations:m(n.maxCombinations),maxCandidates:m(n.maxCandidates)};var r}(i[0],e),s=null!==(r=c.root)&&void 0!==r?r:S(i[0]);let a="",f=s;function p(){return function(t,e,n="",r){if(0===t.length)return null;const o=[t.length>1?t:[],...N(t,e).map((t=>[t]))];for(const t of o){const o=H(t,e,n,r);if(o)return{foundElements:t,selector:o}}return null}(i,f,a,c)}let g=p();for(;g;){const{foundElements:t,selector:e}=g;if(b(i,e,s))return e;f=t[0],a=e,g=p()}return i.length>1?i.map((t=>K(t,c))).join(E):function(t){return t.map(J).join(E)}(i)}const Q=K;return e})())); | |
window.__wdioGetCssSelector = CssSelectorGenerator.default; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment