UNPKG

@yuebai008/cli

Version:

Command line interface for rapid qg-minigame development

1 lines 34.6 kB
var SelectorType,StepType,AssertedEventType;!function(e){e.CSS="css",e.ARIA="aria",e.Text="text",e.XPath="xpath",e.Pierce="pierce"}(SelectorType=SelectorType||(SelectorType={})),function(e){e.Change="change",e.Click="click",e.Close="close",e.CustomStep="customStep",e.DoubleClick="doubleClick",e.EmulateNetworkConditions="emulateNetworkConditions",e.Hover="hover",e.KeyDown="keyDown",e.KeyUp="keyUp",e.Navigate="navigate",e.Scroll="scroll",e.SetViewport="setViewport",e.WaitForElement="waitForElement",e.WaitForExpression="waitForExpression"}(StepType=StepType||(StepType={})),function(e){e.Navigation="navigation"}(AssertedEventType=AssertedEventType||(AssertedEventType={}));var Schema=Object.freeze({__proto__:null,get SelectorType(){return SelectorType},get StepType(){return StepType},get AssertedEventType(){return AssertedEventType}});function assertAllStepTypesAreHandled(e){throw new Error(`Unknown step type: ${e.type}`)}const typeableInputTypes=new Set(["textarea","text","url","tel","search","password","number","email"]),pointerDeviceTypes=new Set(["mouse","pen","touch"]),mouseButtonMap=new Map([["primary","left"],["auxiliary","middle"],["secondary","right"],["back","back"],["forward","forward"]]);function hasProperty(e,t){if(!Object.prototype.hasOwnProperty.call(e,t))return!1;return void 0!==e[t]}function isObject(e){return"object"==typeof e&&null!==e}function isString(e){return"string"==typeof e}function isNumber(e){return"number"==typeof e}function isArray(e){return Array.isArray(e)}function isBoolean(e){return"boolean"==typeof e}function isIntegerArray(e){return isArray(e)&&e.every((e=>Number.isInteger(e)))}function isKnownDeviceType(e){return"string"==typeof e&&pointerDeviceTypes.has(e)}function isKnownMouseButton(e){return"string"==typeof e&&mouseButtonMap.has(e)}function parseTarget(e){if(hasProperty(e,"target")&&isString(e.target))return e.target}function parseFrame(e){if(hasProperty(e,"frame")){if(isIntegerArray(e.frame))return e.frame;throw new Error("Step `frame` is not an integer array")}}function parseNumber(e,t){if(hasProperty(e,t)){const n=e[t];if(isNumber(n))return n}throw new Error(`Step.${t} is not a number`)}function parseBoolean(e,t){if(hasProperty(e,t)){const n=e[t];if(isBoolean(n))return n}throw new Error(`Step.${t} is not a boolean`)}function parseOptionalNumber(e,t){if(hasProperty(e,t))return parseNumber(e,t)}function parseOptionalString(e,t){if(hasProperty(e,t))return parseString(e,t)}function parseOptionalBoolean(e,t){if(hasProperty(e,t))return parseBoolean(e,t)}function parseString(e,t){if(hasProperty(e,t)){const n=e[t];if(isString(n))return n}throw new Error(`Step.${t} is not a string`)}function parseSelectors(e){if(!hasProperty(e,"selectors"))throw new Error("Step does not have required selectors");if(!isArray(e.selectors))throw new Error("Step selectors are not an array");if(0===e.selectors.length)throw new Error("Step does not have required selectors");return e.selectors.map((e=>{if(!isString(e)&&!isArray(e))throw new Error("Selector is not an array or string");return isArray(e)?e.map((e=>{if(!isString(e))throw new Error("Selector element is not a string");return e})):e}))}function parseOptionalSelectors(e){if(hasProperty(e,"selectors"))return parseSelectors(e)}function parseAssertedEvent(e){if(!isObject(e))throw new Error("Asserted event is not an object");if(!hasProperty(e,"type"))throw new Error("Asserted event is missing type");if(e.type===AssertedEventType.Navigation)return{type:AssertedEventType.Navigation,url:parseOptionalString(e,"url"),title:parseOptionalString(e,"title")};throw new Error("Unknown assertedEvent type")}function parseAssertedEvents(e){if(isArray(e))return e.map(parseAssertedEvent)}function parseBaseStep(e,t){if(hasProperty(t,"timeout")&&isNumber(t.timeout)&&!validTimeout(t.timeout))throw new Error(timeoutErrorMessage);return{type:e,assertedEvents:hasProperty(t,"assertedEvents")?parseAssertedEvents(t.assertedEvents):void 0,timeout:hasProperty(t,"timeout")&&isNumber(t.timeout)?t.timeout:void 0}}function parseStepWithTarget(e,t){return{...parseBaseStep(e,t),target:parseTarget(t)}}function parseStepWithFrame(e,t){return{...parseStepWithTarget(e,t),frame:parseFrame(t)}}function parseStepWithSelectors(e,t){return{...parseStepWithFrame(e,t),selectors:parseSelectors(t)}}function parseClickAttributes(e){const t={offsetX:parseNumber(e,"offsetX"),offsetY:parseNumber(e,"offsetY"),duration:parseOptionalNumber(e,"duration")},n=parseOptionalString(e,"deviceType");if(n){if(!isKnownDeviceType(n))throw new Error(`'deviceType' for click steps must be one of the following: ${[...pointerDeviceTypes].join(", ")}`);t.deviceType=n}const r=parseOptionalString(e,"button");if(r){if(!isKnownMouseButton(r))throw new Error(`'button' for click steps must be one of the following: ${[...mouseButtonMap.keys()].join(", ")}`);t.button=r}return t}function parseClickStep(e){return{...parseStepWithSelectors(StepType.Click,e),...parseClickAttributes(e),type:StepType.Click}}function parseDoubleClickStep(e){return{...parseStepWithSelectors(StepType.DoubleClick,e),...parseClickAttributes(e),type:StepType.DoubleClick}}function parseHoverStep(e){return{...parseStepWithSelectors(StepType.Hover,e),type:StepType.Hover}}function parseChangeStep(e){return{...parseStepWithSelectors(StepType.Change,e),type:StepType.Change,value:parseString(e,"value")}}function parseKeyDownStep(e){return{...parseStepWithTarget(StepType.KeyDown,e),type:StepType.KeyDown,key:parseString(e,"key")}}function parseKeyUpStep(e){return{...parseStepWithTarget(StepType.KeyUp,e),type:StepType.KeyUp,key:parseString(e,"key")}}function parseEmulateNetworkConditionsStep(e){return{...parseStepWithTarget(StepType.EmulateNetworkConditions,e),type:StepType.EmulateNetworkConditions,download:parseNumber(e,"download"),upload:parseNumber(e,"upload"),latency:parseNumber(e,"latency")}}function parseCloseStep(e){return{...parseStepWithTarget(StepType.Close,e),type:StepType.Close}}function parseSetViewportStep(e){return{...parseStepWithTarget(StepType.SetViewport,e),type:StepType.SetViewport,width:parseNumber(e,"width"),height:parseNumber(e,"height"),deviceScaleFactor:parseNumber(e,"deviceScaleFactor"),isMobile:parseBoolean(e,"isMobile"),hasTouch:parseBoolean(e,"hasTouch"),isLandscape:parseBoolean(e,"isLandscape")}}function parseScrollStep(e){return{...parseStepWithFrame(StepType.Scroll,e),type:StepType.Scroll,x:parseOptionalNumber(e,"x"),y:parseOptionalNumber(e,"y"),selectors:parseOptionalSelectors(e)}}function parseNavigateStep(e){return{...parseStepWithTarget(StepType.Navigate,e),type:StepType.Navigate,target:parseTarget(e),url:parseString(e,"url")}}function parseWaitForElementStep(e){const t=parseOptionalString(e,"operator");if(t&&">="!==t&&"=="!==t&&"<="!==t)throw new Error("WaitForElement step's operator is not one of '>=','==','<='");if(hasProperty(e,"attributes")&&(!isObject(e.attributes)||Object.values(e.attributes).some((e=>"string"!=typeof e))))throw new Error("WaitForElement step's attribute is not a dictionary of strings");if(hasProperty(e,"properties")&&!isObject(e.properties))throw new Error("WaitForElement step's attribute is not an object");return{...parseStepWithSelectors(StepType.WaitForElement,e),type:StepType.WaitForElement,operator:t,count:parseOptionalNumber(e,"count"),visible:parseOptionalBoolean(e,"visible"),attributes:hasProperty(e,"attributes")?e.attributes:void 0,properties:hasProperty(e,"properties")?e.properties:void 0}}function parseWaitForExpressionStep(e){if(!hasProperty(e,"expression"))throw new Error("waitForExpression step is missing `expression`");return{...parseStepWithFrame(StepType.WaitForExpression,e),type:StepType.WaitForExpression,expression:parseString(e,"expression")}}function parseCustomStep(e){if(!hasProperty(e,"name"))throw new Error("customStep is missing name");if(!isString(e.name))throw new Error("customStep's name is not a string");return{...parseStepWithFrame(StepType.CustomStep,e),type:StepType.CustomStep,name:e.name,parameters:hasProperty(e,"parameters")?e.parameters:void 0}}function parseStep(e,t){if(!isObject(e))throw new Error(t?`Step ${t} is not an object`:"Step is not an object");if(!hasProperty(e,"type"))throw new Error(t?`Step ${t} does not have a type`:"Step does not have a type");if(!isString(e.type))throw new Error(t?`Type of the step ${t} is not a string`:"Type of the step is not a string");switch(e.type){case StepType.Click:return parseClickStep(e);case StepType.DoubleClick:return parseDoubleClickStep(e);case StepType.Hover:return parseHoverStep(e);case StepType.Change:return parseChangeStep(e);case StepType.KeyDown:return parseKeyDownStep(e);case StepType.KeyUp:return parseKeyUpStep(e);case StepType.EmulateNetworkConditions:return parseEmulateNetworkConditionsStep(e);case StepType.Close:return parseCloseStep(e);case StepType.SetViewport:return parseSetViewportStep(e);case StepType.Scroll:return parseScrollStep(e);case StepType.Navigate:return parseNavigateStep(e);case StepType.CustomStep:return parseCustomStep(e);case StepType.WaitForElement:return parseWaitForElementStep(e);case StepType.WaitForExpression:return parseWaitForExpressionStep(e);default:throw new Error(`Step type ${e.type} is not supported`)}}function parseSteps(e){const t=[];if(!isArray(e))throw new Error("Recording `steps` is not an array");for(const[n,r]of e.entries())t.push(parseStep(r,n));return t}function cleanUndefined(e){return JSON.parse(JSON.stringify(e))}const minTimeout=1,maxTimeout=3e4,timeoutErrorMessage=`Timeout is not between ${minTimeout} and ${maxTimeout} milliseconds`;function validTimeout(e){return e>=minTimeout&&e<=maxTimeout}function parse(e){if(!isObject(e))throw new Error("Recording is not an object");if(!hasProperty(e,"title"))throw new Error("Recording is missing `title`");if(!isString(e.title))throw new Error("Recording `title` is not a string");if(hasProperty(e,"timeout")&&!isNumber(e.timeout))throw new Error("Recording `timeout` is not a number");if(!hasProperty(e,"steps"))throw new Error("Recording is missing `steps`");if(hasProperty(e,"timeout")&&isNumber(e.timeout)&&!validTimeout(e.timeout))throw new Error(timeoutErrorMessage);return cleanUndefined({title:e.title,timeout:hasProperty(e,"timeout")&&isNumber(e.timeout)?e.timeout:void 0,selectorAttribute:hasProperty(e,"selectorAttribute")&&isString(e.selectorAttribute)?e.selectorAttribute:void 0,steps:parseSteps(e.steps)})}function getSelectorType(e){for(const t of Object.values(SelectorType))if(e.startsWith(`${t}/`))return t;return SelectorType.CSS}function selectorToPElementSelector(e){function t(e){return e.replace(/['"()]/g,"\\$&")}Array.isArray(e)||(e=[e]);return e.map((e=>{switch(getSelectorType(e)){case SelectorType.ARIA:return`::-p-aria(${t(e.substring(SelectorType.ARIA.length+1))})`;case SelectorType.CSS:return e;case SelectorType.XPath:return`::-p-xpath(${t(e.substring(SelectorType.XPath.length+1))})`;case SelectorType.Pierce:return`:scope >>> ${e.substring(SelectorType.Pierce.length+1)}`;case SelectorType.Text:return`::-p-text(${t(e.substring(SelectorType.Text.length+1))})`}})).join(" >>>> ")}class StringifyExtension{async beforeAllSteps(e,t){}async afterAllSteps(e,t){}async beforeEachStep(e,t,n){}async stringifyStep(e,t,n){}async afterEachStep(e,t,n){}}class JSONStringifyExtension extends StringifyExtension{async beforeAllSteps(e,t){const n={...t,steps:void 0},r=JSON.stringify(n,null,e.getIndent()).split("\n");r.pop(),r[r.length-1]+=",",r.push(e.getIndent()+'"steps": ['),e.appendLine(r.join("\n")).startBlock().startBlock()}async afterAllSteps(e){e.endBlock().endBlock().appendLine(e.getIndent()+"]").appendLine("}")}async stringifyStep(e,t,n){const r=JSON.stringify(t,null,e.getIndent());if(!n)return void e.appendLine(r);const a=n.steps.lastIndexOf(t)===n.steps.length-1?"":",";e.appendLine(r+a)}}class InMemoryLineWriter{#e;#t=0;#n=[];constructor(e){this.#e=e}appendLine(e){const t=e.split("\n").map((e=>e?this.#e.repeat(this.#t)+e.trimEnd():""));return this.#n.push(...t),this}startBlock(){return this.#t++,this}endBlock(){if(this.#t--,this.#t<0)throw new Error("Extra endBlock");return this}toString(){return this.#n.join("\n")+"\n"}getIndent(){return this.#e}getSize(){return this.#n.length}}function formatJSONAsJS(e,t){const n=[];return format(e,n,1,t),n.join("")}function format(e,t=[],n=1,r=" "){switch(typeof e){case"bigint":case"symbol":case"function":case"undefined":throw new Error("Invalid JSON");case"number":case"boolean":t.push(String(e));break;case"string":t.push(formatAsJSLiteral(e));break;case"object":if(null===e)t.push("null");else if(Array.isArray(e)){t.push("[\n");for(let a=0;a<e.length;a++)t.push(r.repeat(n)),format(e[a],t,n+1,r),a!==e.length-1&&t.push(","),t.push("\n");t.push(r.repeat(n-1)+"]")}else{t.push("{\n");const a=Object.keys(e);for(let i=0;i<a.length;i++){const o=a[i],s=e[o];void 0!==s&&(t.push(r.repeat(n)),t.push(o),t.push(": "),format(s,t,n+1,r),i!==a.length-1&&t.push(","),t.push("\n"))}t.push(r.repeat(n-1)+"}")}break;default:throw new Error("Unknown object type")}return t}const toHexadecimal=(e,t)=>e.toString(16).toUpperCase().padStart(t,"0"),escapedReplacements=new Map([["\b","\\b"],["\f","\\f"],["\n","\\n"],["\r","\\r"],["\t","\\t"],["\v","\\v"],["'","\\'"],["\\","\\\\"],["\x3c!--","\\x3C!--"],["<script","\\x3Cscript"],["</script","\\x3C/script"]]),formatAsJSLiteral=e=>{const t=/(\\|<(?:!--|\/?script))|(\p{Control})|(\p{Surrogate})/gu,n=/(\\|'|<(?:!--|\/?script))|(\p{Control})|(\p{Surrogate})/gu,r=(e,t,n,r)=>{if(n){if(escapedReplacements.has(n))return escapedReplacements.get(n);return"\\x"+toHexadecimal(n.charCodeAt(0),2)}if(r){return"\\u"+toHexadecimal(r.charCodeAt(0),4)}return t?escapedReplacements.get(t)||"":e};let a="",i="";return e.includes("'")?e.includes('"')?e.includes("`")||e.includes("${")?(i="'",a=e.replace(n,r)):(i="`",a=e.replace(t,r)):(i='"',a=e.replace(t,r)):(i="'",a=e.replace(t,r)),`${i}${a}${i}`};class PuppeteerStringifyExtension extends StringifyExtension{#r=!1;async beforeAllSteps(e,t){e.appendLine("const puppeteer = require('puppeteer'); // v20.7.4 or later"),e.appendLine(""),e.appendLine("(async () => {").startBlock(),e.appendLine("const browser = await puppeteer.launch({headless: 'new'});"),e.appendLine("const page = await browser.newPage();"),e.appendLine(`const timeout = ${t.timeout||defaultTimeout};`),e.appendLine("page.setDefaultTimeout(timeout);"),e.appendLine(""),this.#r=!1}async afterAllSteps(e,t){if(e.appendLine(""),e.appendLine("await browser.close();"),e.appendLine(""),this.#r)for(const t of waitForElementHelper.split("\n"))e.appendLine(t);e.endBlock().appendLine("})().catch(err => {").startBlock(),e.appendLine("console.error(err);"),e.appendLine("process.exit(1);"),e.endBlock().appendLine("});")}async stringifyStep(e,t,n){if(e.appendLine("{").startBlock(),void 0!==t.timeout&&e.appendLine(`const timeout = ${t.timeout};`),this.#a(e,t),t.assertedEvents){e.appendLine("const promises = [];"),e.appendLine("const startWaitingForEvents = () => {").startBlock();for(const n of t.assertedEvents){if(n.type!==AssertedEventType.Navigation)throw new Error(`Event type ${n.type} is not supported`);e.appendLine(`promises.push(${"frame"in t&&t.frame?"frame":"targetPage"}.waitForNavigation());`)}e.endBlock().appendLine("}")}this.#i(e,t),t.assertedEvents&&e.appendLine("await Promise.all(promises);"),e.endBlock().appendLine("}")}#o(e,t){"main"===t?e.appendLine("const targetPage = page;"):(e.appendLine(`const target = await browser.waitForTarget(t => t.url() === ${formatJSONAsJS(t,e.getIndent())}, { timeout });`),e.appendLine("const targetPage = await target.page();"),e.appendLine("targetPage.setDefaultTimeout(timeout);"))}#s(e,t){e.appendLine("let frame = targetPage.mainFrame();");for(const n of t)e.appendLine(`frame = frame.childFrames()[${n}];`)}#a(e,t){this.#o(e,t.target||"main"),t.frame&&this.#s(e,t.frame)}#p(e,t,n){e.appendLine("await puppeteer.Locator.race([").startBlock(),e.appendLine(t.selectors.map((n=>`${t.frame?"frame":"targetPage"}.locator(${formatJSONAsJS(selectorToPElementSelector(n),e.getIndent())})`)).join(",\n")),e.endBlock().appendLine("])"),e.startBlock().appendLine(".setTimeout(timeout)"),t.assertedEvents?.length&&e.appendLine(".on('action', () => startWaitingForEvents())"),n(),e.endBlock()}#l(e,t){this.#p(e,t,(()=>{e.appendLine(".click({"),t.duration&&e.appendLine(` delay: ${t.duration},`),t.button&&e.appendLine(` button: '${mouseButtonMap.get(t.button)}',`),e.appendLine(" offset: {"),e.appendLine(` x: ${t.offsetX},`),e.appendLine(` y: ${t.offsetY},`),e.appendLine(" },"),e.appendLine("});")}))}#u(e,t){this.#p(e,t,(()=>{e.appendLine(".click({"),e.appendLine(" count: 2,"),t.duration&&e.appendLine(` delay: ${t.duration},`),t.button&&e.appendLine(` button: '${mouseButtonMap.get(t.button)}',`),e.appendLine(" offset: {"),e.appendLine(` x: ${t.offsetX},`),e.appendLine(` y: ${t.offsetY},`),e.appendLine(" },"),e.appendLine("});")}))}#c(e,t){this.#p(e,t,(()=>{e.appendLine(".hover();")}))}#f(e,t){this.#p(e,t,(()=>{e.appendLine(`.fill(${formatJSONAsJS(t.value,e.getIndent())});`)}))}#S(e,t){e.appendLine("await targetPage.emulateNetworkConditions({"),e.appendLine(` offline: ${!t.download&&!t.upload},`),e.appendLine(` downloadThroughput: ${t.download},`),e.appendLine(` uploadThroughput: ${t.upload},`),e.appendLine(` latency: ${t.latency},`),e.appendLine("});")}#d(e,t){e.appendLine(`await targetPage.keyboard.down(${formatJSONAsJS(t.key,e.getIndent())});`)}#y(e,t){e.appendLine(`await targetPage.keyboard.up(${formatJSONAsJS(t.key,e.getIndent())});`)}#m(e,t){e.appendLine("await targetPage.close()")}#w(e,t){e.appendLine(`await targetPage.setViewport(${formatJSONAsJS({width:t.width,height:t.height},e.getIndent())})`)}#h(e,t){"selectors"in t?this.#p(e,t,(()=>{e.appendLine(`.scroll({ scrollTop: ${t.y}, scrollLeft: ${t.x}});`)})):e.appendLine(`await targetPage.evaluate((x, y) => { window.scroll(x, y); }, ${t.x}, ${t.y})`)}#i(e,t){switch(t.type){case StepType.Click:return this.#l(e,t);case StepType.DoubleClick:return this.#u(e,t);case StepType.Hover:return this.#c(e,t);case StepType.Change:return this.#f(e,t);case StepType.EmulateNetworkConditions:return this.#S(e,t);case StepType.KeyDown:return this.#d(e,t);case StepType.KeyUp:return this.#y(e,t);case StepType.Close:return this.#m(e,t);case StepType.SetViewport:return this.#w(e,t);case StepType.Scroll:return this.#h(e,t);case StepType.Navigate:return this.#g(e,t);case StepType.WaitForElement:return this.#T(e,t);case StepType.WaitForExpression:return this.#E(e,t);case StepType.CustomStep:return;default:return assertAllStepTypesAreHandled(t)}}#g(e,t){t.assertedEvents?.length&&e.appendLine("startWaitingForEvents();"),e.appendLine(`await targetPage.goto(${formatJSONAsJS(t.url,e.getIndent())});`)}#E(e,t){e.appendLine(`await ${t.frame?"frame":"targetPage"}.waitForFunction(${formatJSONAsJS(t.expression,e.getIndent())}, { timeout });`)}#T(e,t){this.#r=!0,e.appendLine(`await waitForElement(${formatJSONAsJS(t,e.getIndent())}, ${t.frame?"frame":"targetPage"}, timeout);`)}}const defaultTimeout=5e3,waitForElementHelper="async function waitForElement(step, frame, timeout) {\n const {\n count = 1,\n operator = '>=',\n visible = true,\n properties,\n attributes,\n } = step;\n const compFn = {\n '==': (a, b) => a === b,\n '>=': (a, b) => a >= b,\n '<=': (a, b) => a <= b,\n }[operator];\n await waitForFunction(async () => {\n const elements = await querySelectorsAll(step.selectors, frame);\n let result = compFn(elements.length, count);\n const elementsHandle = await frame.evaluateHandle((...elements) => {\n return elements;\n }, ...elements);\n await Promise.all(elements.map((element) => element.dispose()));\n if (result && (properties || attributes)) {\n result = await elementsHandle.evaluate(\n (elements, properties, attributes) => {\n for (const element of elements) {\n if (attributes) {\n for (const [name, value] of Object.entries(attributes)) {\n if (element.getAttribute(name) !== value) {\n return false;\n }\n }\n }\n if (properties) {\n if (!isDeepMatch(properties, element)) {\n return false;\n }\n }\n }\n return true;\n\n function isDeepMatch(a, b) {\n if (a === b) {\n return true;\n }\n if ((a && !b) || (!a && b)) {\n return false;\n }\n if (!(a instanceof Object) || !(b instanceof Object)) {\n return false;\n }\n for (const [key, value] of Object.entries(a)) {\n if (!isDeepMatch(value, b[key])) {\n return false;\n }\n }\n return true;\n }\n },\n properties,\n attributes\n );\n }\n await elementsHandle.dispose();\n return result === visible;\n }, timeout);\n}\n\nasync function querySelectorsAll(selectors, frame) {\n for (const selector of selectors) {\n const result = await querySelectorAll(selector, frame);\n if (result.length) {\n return result;\n }\n }\n return [];\n}\n\nasync function querySelectorAll(selector, frame) {\n if (!Array.isArray(selector)) {\n selector = [selector];\n }\n if (!selector.length) {\n throw new Error('Empty selector provided to querySelectorAll');\n }\n let elements = [];\n for (let i = 0; i < selector.length; i++) {\n const part = selector[i];\n if (i === 0) {\n elements = await frame.$$(part);\n } else {\n const tmpElements = elements;\n elements = [];\n for (const el of tmpElements) {\n elements.push(...(await el.$$(part)));\n }\n }\n if (elements.length === 0) {\n return [];\n }\n if (i < selector.length - 1) {\n const tmpElements = [];\n for (const el of elements) {\n const newEl = (await el.evaluateHandle(el => el.shadowRoot ? el.shadowRoot : el)).asElement();\n if (newEl) {\n tmpElements.push(newEl);\n }\n }\n elements = tmpElements;\n }\n }\n return elements;\n}\n\nasync function waitForFunction(fn, timeout) {\n let isActive = true;\n const timeoutId = setTimeout(() => {\n isActive = false;\n }, timeout);\n while (isActive) {\n const result = await fn();\n if (result) {\n clearTimeout(timeoutId);\n return;\n }\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n throw new Error('Timed out');\n}",alpha="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",charToIdx=alpha.split("").reduce(((e,t,n)=>(e.set(t,n),e)),new Map),LEAST_5_BIT_MASK=31,CONTINUATION_BIT_MASK=32,MAX_INT=2147483647;function encodeInt(e){if(e<0)throw new Error("Only postive integers and zero are supported");if(e>MAX_INT)throw new Error("Only integers between 0 and "+MAX_INT+" are supported");const t=[];do{let n=e&LEAST_5_BIT_MASK;(e>>>=5)>0&&(n|=CONTINUATION_BIT_MASK),t.push(alpha[n])}while(0!==e);return t.join("")}function encode(e){const t=[];for(const n of e)t.push(encodeInt(n));return t.join("")}function decode(e){const t=[],n=e.split("");let r=0,a=0;for(const e of n){const n=charToIdx.get(e);r|=(n&LEAST_5_BIT_MASK)<<a,a+=5;n&CONTINUATION_BIT_MASK||(t.push(r),r=0,a=0)}return t}const SOURCE_MAP_PREFIX="//# recorderSourceMap=";async function stringify(e,t){t||(t={});const n=t.extension??new PuppeteerStringifyExtension,r=t.writer??new InMemoryLineWriter(t.indentation??" ");await(n.beforeAllSteps?.(r,e));const a=[1];for(const t of e.steps){const i=r.getSize();await(n.beforeEachStep?.(r,t,e)),await n.stringifyStep(r,t,e),await(n.afterEachStep?.(r,t,e));const o=r.getSize();a.push(i,o-i)}return await(n.afterAllSteps?.(r,e)),r.appendLine(SOURCE_MAP_PREFIX+encode(a)),r.toString()}async function stringifyStep(e,t){t||(t={});let n=t.extension;n||(n=new PuppeteerStringifyExtension),t.indentation||(t.indentation=" ");const r=t.writer??new InMemoryLineWriter(t.indentation??" ");return await(n.beforeEachStep?.(r,e)),await n.stringifyStep(r,e),await(n.afterEachStep?.(r,e)),r.toString()}function isSourceMapLine(e){return e.trim().startsWith(SOURCE_MAP_PREFIX)}function parseSourceMap(e){const t=e.split("\n");for(let e=t.length-1;e>=0;e--){const n=t[e];if(isSourceMapLine(n))return decode(n.trim().substring(SOURCE_MAP_PREFIX.length))}}function stripSourceMap(e){return e.split("\n").filter((e=>!isSourceMapLine(e))).join("\n")}class RunnerExtension{async beforeAllSteps(e){}async afterAllSteps(e){}async beforeEachStep(e,t){}async runStep(e,t){}async afterEachStep(e,t){}}const comparators={"==":(e,t)=>e===t,">=":(e,t)=>e>=t,"<=":(e,t)=>e<=t};class PuppeteerRunnerExtension extends RunnerExtension{browser;page;timeout;constructor(e,t,n){super(),this.browser=e,this.page=t,this.timeout=n?.timeout||5e3}async#b(e){try{await e._client().send("Emulation.setAutomationOverride",{enabled:!0})}catch{}}#v(e,t){return e.timeout||t?.timeout||this.timeout}async runStep(e,t){const n=this.#v(e,t),r=this.page,a=this.browser,i=await getTargetPageForStep(a,r,e,n);let o=null;if(!i&&e.target){const t=r.frames();for(const n of t)if(n.isOOPFrame()&&n.url()===e.target){o=n;break}o||(o=await r.waitForFrame(e.target,{timeout:n}))}const s=o||i;if(!s)throw new Error("Target is not found for step: "+JSON.stringify(e));await this.#b(s);const p=await getFrame(s,e);await this.runStepInFrame(e,r,s,p,n)}async runStepInFrame(e,t,n,r,a){let i=null;const o=()=>{i=waitForEvents(r,e,a)},s=this.page.locatorRace;switch(e.type){case StepType.DoubleClick:await s(e.selectors.map((e=>r.locator(selectorToPElementSelector(e))))).setTimeout(a).on("action",(()=>o())).click({count:2,button:e.button&&mouseButtonMap.get(e.button),delay:e.duration,offset:{x:e.offsetX,y:e.offsetY}});break;case StepType.Click:await s(e.selectors.map((e=>r.locator(selectorToPElementSelector(e))))).setTimeout(a).on("action",(()=>o())).click({delay:e.duration,button:e.button&&mouseButtonMap.get(e.button),offset:{x:e.offsetX,y:e.offsetY}});break;case StepType.Hover:await s(e.selectors.map((e=>r.locator(selectorToPElementSelector(e))))).setTimeout(a).on("action",(()=>o())).hover();break;case StepType.EmulateNetworkConditions:o(),await t.emulateNetworkConditions(e);break;case StepType.KeyDown:o(),await t.keyboard.down(e.key),await t.waitForTimeout(100);break;case StepType.KeyUp:o(),await t.keyboard.up(e.key),await t.waitForTimeout(100);break;case StepType.Close:"close"in n&&(o(),await n.close());break;case StepType.Change:await s(e.selectors.map((e=>r.locator(selectorToPElementSelector(e))))).on("action",(()=>o())).setTimeout(a).fill(e.value);break;case StepType.SetViewport:"setViewport"in n&&(o(),await n.setViewport(e));break;case StepType.Scroll:"selectors"in e?await s(e.selectors.map((e=>r.locator(selectorToPElementSelector(e))))).on("action",(()=>o())).setTimeout(a).scroll({scrollLeft:e.x||0,scrollTop:e.y||0}):(o(),await r.evaluate(((e,t)=>{window.scroll(e,t)}),e.x||0,e.y||0));break;case StepType.Navigate:o(),await r.goto(e.url);break;case StepType.WaitForElement:try{o(),await waitForElement(e,r,a)}catch(e){throw"Timed out"===e.message?new Error("waitForElement timed out. The element(s) could not be found."):e}break;case StepType.WaitForExpression:o(),await r.waitForFunction(e.expression,{timeout:a});break;case StepType.CustomStep:break;default:assertAllStepTypesAreHandled(e)}await i}}class PuppeteerRunnerOwningBrowserExtension extends PuppeteerRunnerExtension{async afterAllSteps(){await this.browser.close()}}async function getFrame(e,t){let n="mainFrame"in e?e.mainFrame():e;if("frame"in t&&t.frame)for(const e of t.frame)n=n.childFrames()[e];return n}async function getTargetPageForStep(e,t,n,r){if(!n.target||"main"===n.target)return t;const a=await e.waitForTarget((e=>e.url()===n.target),{timeout:r}),i=await a.page();return i?(i.setDefaultTimeout(r),i):null}async function waitForEvents(e,t,n){const r=[];if(t.assertedEvents)for(const a of t.assertedEvents){if(a.type!==AssertedEventType.Navigation)throw new Error(`Event type ${a.type} is not supported`);r.push(e.waitForNavigation({timeout:n}))}await Promise.all(r)}async function waitForElement(e,t,n){const{count:r=1,operator:a=">=",visible:i=!0,properties:o,attributes:s}=e,p=comparators[a];await waitForFunction((async()=>{const n=await querySelectorsAll(e.selectors,t);let a=p(n.length,r);const l=await t.evaluateHandle(((...e)=>e),...n);return await Promise.all(n.map((e=>e.dispose()))),a&&(o||s)&&(a=await l.evaluate(((e,t,n)=>{if(n)for(const t of e)for(const[e,r]of Object.entries(n))if(t.getAttribute(e)!==r)return!1;if(t)for(const n of e)if(!r(t,n))return!1;return!0;function r(e,t){if(e===t)return!0;if(e&&!t||!e&&t)return!1;if(!(e instanceof Object&&t instanceof Object))return!1;for(const[n,a]of Object.entries(e))if(!r(a,t[n]))return!1;return!0}}),o,s)),await l.dispose(),a===i}),n)}async function querySelectorsAll(e,t){for(const n of e){const e=await querySelectorAll(n,t);if(e.length)return e}return[]}async function querySelectorAll(e,t){if(Array.isArray(e)||(e=[e]),!e.length)throw new Error("Empty selector provided to querySelectorAll");let n=await t.$$(e[0]);if(!n.length)return[];for(const t of e.slice(1,e.length))if(n=(await Promise.all(n.map((async e=>{const n=await e.evaluateHandle((e=>e.shadowRoot?e.shadowRoot:e)),r=await n.$$(t);return n.dispose(),e.dispose(),r})))).flat(),!n.length)return[];return n}async function waitForFunction(e,t){let n=!0;const r=setTimeout((()=>{n=!1}),t);for(;n;){if(await e())return void clearTimeout(r);await new Promise((e=>setTimeout(e,100)))}throw new Error("Timed out")}async function _runStepWithHooks(e,t,n){await(e.beforeEachStep?.(t,n)),await e.runStep(t,n),await(e.afterEachStep?.(t,n))}class Runner{#A;#L;#F=!1;constructor(e){this.#L=e}abort(){this.#F=!0}set flow(e){this.#A=e}async runBeforeAllSteps(e){await(this.#L.beforeAllSteps?.(e))}async runAfterAllSteps(e){await(this.#L.afterAllSteps?.(e))}async runStep(e){await _runStepWithHooks(this.#L,e)}async run(){if(!this.#A)throw new Error("Set the flow on the runner instance before calling `run`.");const e=this.#A;if(this.#F=!1,await(this.#L.beforeAllSteps?.(e)),this.#F)return!1;for(const t of e.steps){if(this.#F)return await(this.#L.afterAllSteps?.(e)),!1;await _runStepWithHooks(this.#L,t,e)}return await(this.#L.afterAllSteps?.(e)),!0}}async function createRunner(e,t){const n=e instanceof RunnerExtension?void 0:e,r=new Runner((e instanceof RunnerExtension?e:t)??await createPuppeteerRunnerOwningBrowserExtension());return n&&(r.flow=n),r}async function createPuppeteerRunnerOwningBrowserExtension(){const{default:e}=await import("puppeteer"),t=await e.launch({headless:"new"}),n=await t.newPage();return new PuppeteerRunnerOwningBrowserExtension(t,n)}class PuppeteerReplayStringifyExtension extends StringifyExtension{async beforeAllSteps(e){e.appendLine("import url from 'url';"),e.appendLine("import { createRunner } from '@puppeteer/replay';"),e.appendLine(""),e.appendLine("export async function run(extension) {").startBlock(),e.appendLine("const runner = await createRunner(extension);"),e.appendLine(""),e.appendLine("await runner.runBeforeAllSteps();"),e.appendLine("")}async afterAllSteps(e){e.appendLine(""),e.appendLine("await runner.runAfterAllSteps();").endBlock().appendLine("}"),e.appendLine(""),e.appendLine("if (process && import.meta.url === url.pathToFileURL(process.argv[1]).href) {").startBlock().appendLine("run()").endBlock().appendLine("}")}async stringifyStep(e,t){e.appendLine(`await runner.runStep(${formatJSONAsJS(t,e.getIndent())});`)}}function isNavigationStep(e){return Boolean(e.type===StepType.Navigate||e.assertedEvents?.some((e=>e.type===AssertedEventType.Navigation)))}function isMobileFlow(e){for(const t of e.steps)if(t.type===StepType.SetViewport)return t.isMobile;return!1}class LighthouseStringifyExtension extends PuppeteerStringifyExtension{#k=!1;async beforeAllSteps(e,t){e.appendLine("const fs = require('fs');"),await super.beforeAllSteps(e,t),e.appendLine("const lhApi = await import('lighthouse'); // v10.0.0 or later");e.appendLine(`const flags = ${formatJSONAsJS({screenEmulation:{disabled:!0}},e.getIndent())}`),isMobileFlow(t)?e.appendLine("const config = undefined;"):e.appendLine("const config = lhApi.desktopConfig;"),e.appendLine(`const lhFlow = await lhApi.startFlow(page, {name: ${formatJSONAsJS(t.title,e.getIndent())}, config, flags});`)}async stringifyStep(e,t,n){if(t.type===StepType.SetViewport)return void await super.stringifyStep(e,t,n);const r=isNavigationStep(t);r?(this.#k&&(e.appendLine("await lhFlow.endTimespan();"),this.#k=!1),e.appendLine("await lhFlow.startNavigation();")):this.#k||(e.appendLine("await lhFlow.startTimespan();"),this.#k=!0),await super.stringifyStep(e,t,n),r&&e.appendLine("await lhFlow.endNavigation();")}async afterAllSteps(e,t){this.#k&&e.appendLine("await lhFlow.endTimespan();"),e.appendLine("const lhFlowReport = await lhFlow.generateReport();"),e.appendLine("fs.writeFileSync(__dirname + '/flow.report.html', lhFlowReport)"),await super.afterAllSteps(e,t)}}class LighthouseRunnerExtension extends PuppeteerRunnerExtension{#x=!1;#P=!1;#N;async createFlowResult(){if(!this.#N)throw new Error("Cannot get flow result before running the flow");return this.#N.createFlowResult()}async beforeAllSteps(e){await(super.beforeAllSteps?.(e));const{startFlow:t,desktopConfig:n}=await import("lighthouse");let r;isMobileFlow(e)||(r=n),this.#N=await t(this.page,{config:r,flags:{screenEmulation:{disabled:!0}},name:e.title})}async beforeEachStep(e,t){await(super.beforeEachStep?.(e,t)),e.type!==StepType.SetViewport&&(isNavigationStep(e)?(this.#x&&(await this.#N.endTimespan(),this.#x=!1),await this.#N.startNavigation(),this.#P=!0):this.#x||(await this.#N.startTimespan(),this.#x=!0))}async afterEachStep(e,t){this.#P&&(await this.#N.endNavigation(),this.#P=!1),await(super.afterEachStep?.(e,t))}async afterAllSteps(e){this.#x&&await this.#N.endTimespan(),await(super.afterAllSteps?.(e))}}export{AssertedEventType,JSONStringifyExtension,LighthouseRunnerExtension,LighthouseStringifyExtension,PuppeteerReplayStringifyExtension,PuppeteerRunnerExtension,PuppeteerRunnerOwningBrowserExtension,PuppeteerStringifyExtension,Runner,RunnerExtension,Schema,SelectorType,StepType,StringifyExtension,assertAllStepTypesAreHandled,createRunner,formatAsJSLiteral,formatJSONAsJS,getSelectorType,maxTimeout,minTimeout,mouseButtonMap,parse,parseSourceMap,parseStep,pointerDeviceTypes,selectorToPElementSelector,stringify,stringifyStep,stripSourceMap,typeableInputTypes,validTimeout};