UNPKG

@stencil/playwright

Version:

Testing adapter to use Playwright with Stencil

953 lines (924 loc) 31.5 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // node_modules/deepmerge/dist/cjs.js var require_cjs = __commonJS({ "node_modules/deepmerge/dist/cjs.js"(exports2, module2) { "use strict"; var isMergeableObject = function isMergeableObject2(value) { return isNonNullObject(value) && !isSpecial(value); }; function isNonNullObject(value) { return !!value && typeof value === "object"; } function isSpecial(value) { var stringValue = Object.prototype.toString.call(value); return stringValue === "[object RegExp]" || stringValue === "[object Date]" || isReactElement(value); } var canUseSymbol = typeof Symbol === "function" && Symbol.for; var REACT_ELEMENT_TYPE = canUseSymbol ? Symbol.for("react.element") : 60103; function isReactElement(value) { return value.$$typeof === REACT_ELEMENT_TYPE; } function emptyTarget(val) { return Array.isArray(val) ? [] : {}; } function cloneUnlessOtherwiseSpecified(value, options) { return options.clone !== false && options.isMergeableObject(value) ? deepmerge(emptyTarget(value), value, options) : value; } function defaultArrayMerge(target, source, options) { return target.concat(source).map(function(element) { return cloneUnlessOtherwiseSpecified(element, options); }); } function getMergeFunction(key, options) { if (!options.customMerge) { return deepmerge; } var customMerge = options.customMerge(key); return typeof customMerge === "function" ? customMerge : deepmerge; } function getEnumerableOwnPropertySymbols(target) { return Object.getOwnPropertySymbols ? Object.getOwnPropertySymbols(target).filter(function(symbol) { return Object.propertyIsEnumerable.call(target, symbol); }) : []; } function getKeys(target) { return Object.keys(target).concat(getEnumerableOwnPropertySymbols(target)); } function propertyIsOnObject(object, property) { try { return property in object; } catch (_) { return false; } } function propertyIsUnsafe(target, key) { return propertyIsOnObject(target, key) && !(Object.hasOwnProperty.call(target, key) && Object.propertyIsEnumerable.call(target, key)); } function mergeObject(target, source, options) { var destination = {}; if (options.isMergeableObject(target)) { getKeys(target).forEach(function(key) { destination[key] = cloneUnlessOtherwiseSpecified(target[key], options); }); } getKeys(source).forEach(function(key) { if (propertyIsUnsafe(target, key)) { return; } if (propertyIsOnObject(target, key) && options.isMergeableObject(source[key])) { destination[key] = getMergeFunction(key, options)(target[key], source[key], options); } else { destination[key] = cloneUnlessOtherwiseSpecified(source[key], options); } }); return destination; } function deepmerge(target, source, options) { options = options || {}; options.arrayMerge = options.arrayMerge || defaultArrayMerge; options.isMergeableObject = options.isMergeableObject || isMergeableObject; options.cloneUnlessOtherwiseSpecified = cloneUnlessOtherwiseSpecified; var sourceIsArray = Array.isArray(source); var targetIsArray = Array.isArray(target); var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray; if (!sourceAndTargetTypesMatch) { return cloneUnlessOtherwiseSpecified(source, options); } else if (sourceIsArray) { return options.arrayMerge(target, source, options); } else { return mergeObject(target, source, options); } } deepmerge.all = function deepmergeAll(array, options) { if (!Array.isArray(array)) { throw new Error("first argument should be an array"); } return array.reduce(function(prev, next) { return deepmerge(prev, next, options); }, {}); }; var deepmerge_1 = deepmerge; module2.exports = deepmerge_1; } }); // node_modules/fast-deep-equal/index.js var require_fast_deep_equal = __commonJS({ "node_modules/fast-deep-equal/index.js"(exports2, module2) { "use strict"; module2.exports = function equal(a, b) { if (a === b) return true; if (a && b && typeof a == "object" && typeof b == "object") { if (a.constructor !== b.constructor) return false; var length, i, keys; if (Array.isArray(a)) { length = a.length; if (length != b.length) return false; for (i = length; i-- !== 0; ) if (!equal(a[i], b[i])) return false; return true; } if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags; if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf(); if (a.toString !== Object.prototype.toString) return a.toString() === b.toString(); keys = Object.keys(a); length = keys.length; if (length !== Object.keys(b).length) return false; for (i = length; i-- !== 0; ) if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false; for (i = length; i-- !== 0; ) { var key = keys[i]; if (!equal(a[key], b[key])) return false; } return true; } return a !== a && b !== b; }; } }); // src/index.ts var src_exports = {}; __export(src_exports, { createConfig: () => createConfig, goto: () => goto, locator: () => locator, matchers: () => matchers, setContent: () => setContent, spyOnEvent: () => spyOnEvent, test: () => test, waitForChanges: () => waitForChanges }); module.exports = __toCommonJS(src_exports); // src/create-config.ts var import_deepmerge = __toESM(require_cjs()); // src/load-config-meta.ts var import_compiler = require("@stencil/core/compiler"); // node_modules/find-up/index.js var import_node_path2 = __toESM(require("node:path"), 1); // node_modules/locate-path/index.js var import_node_process = __toESM(require("node:process"), 1); var import_node_path = __toESM(require("node:path"), 1); var import_node_fs = __toESM(require("node:fs"), 1); var import_node_url = require("node:url"); // node_modules/p-locate/node_modules/yocto-queue/index.js var Node = class { value; next; constructor(value) { this.value = value; } }; var Queue = class { #head; #tail; #size; constructor() { this.clear(); } enqueue(value) { const node = new Node(value); if (this.#head) { this.#tail.next = node; this.#tail = node; } else { this.#head = node; this.#tail = node; } this.#size++; } dequeue() { const current = this.#head; if (!current) { return; } this.#head = this.#head.next; this.#size--; return current.value; } clear() { this.#head = void 0; this.#tail = void 0; this.#size = 0; } get size() { return this.#size; } *[Symbol.iterator]() { let current = this.#head; while (current) { yield current.value; current = current.next; } } }; // node_modules/p-locate/node_modules/p-limit/index.js function pLimit(concurrency) { if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) { throw new TypeError("Expected `concurrency` to be a number from 1 and up"); } const queue = new Queue(); let activeCount = 0; const next = () => { activeCount--; if (queue.size > 0) { queue.dequeue()(); } }; const run = async (fn, resolve, args) => { activeCount++; const result = (async () => fn(...args))(); resolve(result); try { await result; } catch { } next(); }; const enqueue = (fn, resolve, args) => { queue.enqueue(run.bind(void 0, fn, resolve, args)); (async () => { await Promise.resolve(); if (activeCount < concurrency && queue.size > 0) { queue.dequeue()(); } })(); }; const generator = (fn, ...args) => new Promise((resolve) => { enqueue(fn, resolve, args); }); Object.defineProperties(generator, { activeCount: { get: () => activeCount }, pendingCount: { get: () => queue.size }, clearQueue: { value: () => { queue.clear(); } } }); return generator; } // node_modules/p-locate/index.js var EndError = class extends Error { constructor(value) { super(); this.value = value; } }; var testElement = async (element, tester) => tester(await element); var finder = async (element) => { const values = await Promise.all(element); if (values[1] === true) { throw new EndError(values[0]); } return false; }; async function pLocate(iterable, tester, { concurrency = Number.POSITIVE_INFINITY, preserveOrder = true } = {}) { const limit = pLimit(concurrency); const items = [...iterable].map((element) => [element, limit(testElement, element, tester)]); const checkLimit = pLimit(preserveOrder ? 1 : Number.POSITIVE_INFINITY); try { await Promise.all(items.map((element) => checkLimit(finder, element))); } catch (error) { if (error instanceof EndError) { return error.value; } throw error; } } // node_modules/locate-path/index.js var typeMappings = { directory: "isDirectory", file: "isFile" }; function checkType(type) { if (Object.hasOwnProperty.call(typeMappings, type)) { return; } throw new Error(`Invalid type specified: ${type}`); } var matchType = (type, stat) => stat[typeMappings[type]](); var toPath = (urlOrPath) => urlOrPath instanceof URL ? (0, import_node_url.fileURLToPath)(urlOrPath) : urlOrPath; async function locatePath(paths, { cwd = import_node_process.default.cwd(), type = "file", allowSymlinks = true, concurrency, preserveOrder } = {}) { checkType(type); cwd = toPath(cwd); const statFunction = allowSymlinks ? import_node_fs.promises.stat : import_node_fs.promises.lstat; return pLocate(paths, async (path_) => { try { const stat = await statFunction(import_node_path.default.resolve(cwd, path_)); return matchType(type, stat); } catch { return false; } }, { concurrency, preserveOrder }); } // node_modules/unicorn-magic/node.js var import_node_url2 = require("node:url"); function toPath2(urlOrPath) { return urlOrPath instanceof URL ? (0, import_node_url2.fileURLToPath)(urlOrPath) : urlOrPath; } // node_modules/find-up/index.js var findUpStop = Symbol("findUpStop"); async function findUpMultiple(name, options = {}) { let directory = import_node_path2.default.resolve(toPath2(options.cwd) ?? ""); const { root } = import_node_path2.default.parse(directory); const stopAt = import_node_path2.default.resolve(directory, toPath2(options.stopAt ?? root)); const limit = options.limit ?? Number.POSITIVE_INFINITY; const paths = [name].flat(); const runMatcher = async (locateOptions) => { if (typeof name !== "function") { return locatePath(paths, locateOptions); } const foundPath = await name(locateOptions.cwd); if (typeof foundPath === "string") { return locatePath([foundPath], locateOptions); } return foundPath; }; const matches = []; while (true) { const foundPath = await runMatcher({ ...options, cwd: directory }); if (foundPath === findUpStop) { break; } if (foundPath) { matches.push(import_node_path2.default.resolve(directory, foundPath)); } if (directory === stopAt || matches.length >= limit) { break; } directory = import_node_path2.default.dirname(directory); } return matches; } async function findUp(name, options = {}) { const matches = await findUpMultiple(name, { ...options, limit: 1 }); return matches[0]; } // src/load-config-meta.ts var import_fs = require("fs"); var import_path = require("path"); var DEFAULT_NAMESPACE = "app"; var DEFAULT_BASE_URL = "http://localhost:3333"; var DEFAULT_WEB_SERVER_URL = `${DEFAULT_BASE_URL}/ping`; var DEFAULT_STENCIL_ENTRY_PATH_PREFIX = "./build"; var DEFAULT_STENCIL_ENTRY_PATH = `${DEFAULT_STENCIL_ENTRY_PATH_PREFIX}/${DEFAULT_NAMESPACE}`; var loadConfigMeta = async () => { let baseURL = DEFAULT_BASE_URL; let webServerUrl = DEFAULT_WEB_SERVER_URL; let stencilNamespace = DEFAULT_NAMESPACE; let stencilEntryPath = DEFAULT_STENCIL_ENTRY_PATH; const stencilConfigPath = await findUp(["stencil.config.ts", "stencil.config.js"]); if (stencilConfigPath && (0, import_fs.existsSync)(stencilConfigPath)) { const { devServer, fsNamespace, outputTargets } = (await (0, import_compiler.loadConfig)({ configPath: stencilConfigPath })).config; const wwwTarget = outputTargets.find((o) => o.type === "www"); if (wwwTarget) { let relativePath = (0, import_path.relative)(devServer.root, wwwTarget.dir); relativePath = relativePath === "" ? "." : relativePath; if (!relativePath.startsWith(".")) { relativePath = `./${relativePath}`; } stencilEntryPath = `${relativePath}/build/${fsNamespace}`; } else { stencilEntryPath = `${DEFAULT_STENCIL_ENTRY_PATH_PREFIX}/${fsNamespace}`; console.warn( `No "www" output target found in the Stencil config. Using default entry path: "${stencilEntryPath}". Tests using 'setContent' may fail to execute.` ); } baseURL = `${devServer.protocol}://${devServer.address}:${devServer.port}`; webServerUrl = `${baseURL}${devServer.pingRoute ?? ""}`; stencilNamespace = fsNamespace; } else { const msg = stencilConfigPath ? `Unable to find your project's Stencil configuration file, starting from '${stencilConfigPath}'. Falling back to defaults.` : `No Stencil config file was found matching the glob 'stencil.config.{ts,js}' in the current or parent directories. Falling back to defaults.`; console.warn(msg); } return { baseURL, webServerUrl, stencilNamespace, stencilEntryPath }; }; // src/create-config.ts var createConfig = async (overrides = {}) => { const { webServerUrl, baseURL, stencilEntryPath, stencilNamespace } = await loadConfigMeta(); process.env["STENCIL_NAMESPACE" /* STENCIL_NAMESPACE */] = stencilNamespace; process.env["STENCIL_ENTRY_PATH" /* STENCIL_ENTRY_PATH */] = stencilEntryPath; return (0, import_deepmerge.default)( { testMatch: "*.e2e.ts", use: { baseURL }, webServer: { command: "stencil build --dev --watch --serve --no-open", url: webServerUrl, reuseExistingServer: !!!process.env.CI, // Max time to wait for dev server to start before aborting, defaults to 60000 (60 seconds) timeout: void 0, // Pipe the dev server output to the console // Gives visibility to the developer if the dev server fails to start stdout: "pipe" } }, overrides ); }; // src/matchers/to-have-first-received-event-detail.ts var import_test = require("@playwright/test"); var import_fast_deep_equal = __toESM(require_fast_deep_equal()); function toHaveFirstReceivedEventDetail(eventSpy, eventDetail) { if (eventSpy === null || eventSpy === void 0) { return { message: () => `expected spy to have received event, but it was not defined`, pass: false }; } if (typeof eventSpy.then === "function") { return { message: () => `expected spy to have received event, but it was not resolved (did you forget an await operator?).`, pass: false }; } if (eventSpy.eventName === null || eventSpy.eventName === void 0) { return { message: () => `toHaveReceivedEventDetail did not receive an event spy`, pass: false }; } if (eventSpy.firstEvent === null || eventSpy.firstEvent === void 0) { return { message: () => `event "${eventSpy.eventName}" was not received`, pass: false }; } const pass = (0, import_fast_deep_equal.default)(eventSpy.firstEvent.detail, eventDetail); (0, import_test.expect)(eventSpy.lastEvent.detail).toEqual(eventDetail); return { message: () => `expected event "${eventSpy.eventName}" detail to ${pass ? "not " : ""}equal`, pass }; } // src/matchers/to-have-nth-received-event-detail.ts var import_test2 = require("@playwright/test"); var import_fast_deep_equal2 = __toESM(require_fast_deep_equal()); function toHaveNthReceivedEventDetail(eventSpy, index, eventDetail) { if (eventSpy === null || eventSpy === void 0) { return { message: () => `expected spy to have received event, but it was not defined`, pass: false }; } if (typeof eventSpy.then === "function") { return { message: () => `expected spy to have received event, but it was not resolved (did you forget an await operator?).`, pass: false }; } if (eventSpy.eventName === null || eventSpy.eventName === void 0) { return { message: () => `toHaveReceivedEventDetail did not receive an event spy`, pass: false }; } if (eventSpy.firstEvent === null || eventSpy.firstEvent === void 0) { return { message: () => `event "${eventSpy.eventName}" was not received`, pass: false }; } const event = eventSpy.events[index]; if (event === null || event === void 0) { return { message: () => `event at index ${index} was not received`, pass: false }; } const pass = (0, import_fast_deep_equal2.default)(event.detail, eventDetail); (0, import_test2.expect)(event.detail).toEqual(eventDetail); return { message: () => `expected event "${eventSpy.eventName}" detail to ${pass ? "not " : ""}equal`, pass }; } // src/matchers/to-have-received-event.ts function toHaveReceivedEvent(eventSpy) { if (eventSpy === void 0 || eventSpy === null) { return { message: () => `expected spy to have received event, but it was not defined`, pass: false }; } if (typeof eventSpy.then === "function") { return { message: () => `expected spy to have received event, but it was not resolved (did you forget an await operator?).`, pass: false }; } const pass = eventSpy.events.length > 0; if (pass) { return { message: () => `expected to have called ${eventSpy.eventName} event`, pass: true }; } return { message: () => `expected to have not called ${eventSpy.eventName} event`, pass: false }; } // src/matchers/to-have-received-event-detail.ts var import_test3 = require("@playwright/test"); var import_fast_deep_equal3 = __toESM(require_fast_deep_equal()); function toHaveReceivedEventDetail(eventSpy, eventDetail) { if (eventSpy === null || eventSpy === void 0) { return { message: () => `toHaveReceivedEventDetail event spy is null`, pass: false }; } if (typeof eventSpy.then === "function") { return { message: () => `expected spy to have received event, but it was not resolved (did you forget an await operator?).`, pass: false }; } if (!eventSpy.eventName) { return { message: () => `toHaveReceivedEventDetail did not receive an event spy`, pass: false }; } if (eventSpy.lastEvent === null || eventSpy.lastEvent === void 0) { return { message: () => `event "${eventSpy.eventName}" was not received`, pass: false }; } const pass = (0, import_fast_deep_equal3.default)(eventSpy.lastEvent.detail, eventDetail); (0, import_test3.expect)(eventSpy.lastEvent.detail).toEqual(eventDetail); return { message: () => `expected event "${eventSpy.eventName}" detail to ${pass ? "not " : ""}equal`, pass }; } // src/matchers/to-have-received-event-times.ts function toHaveReceivedEventTimes(eventSpy, count) { if (!eventSpy) { return { message: () => `toHaveReceivedEventTimes event spy is null`, pass: false }; } if (typeof eventSpy.then === "function") { return { message: () => `expected spy to have received event, but it was not resolved (did you forget an await operator?).`, pass: false }; } if (!eventSpy.eventName) { return { message: () => `toHaveReceivedEventTimes did not receive an event spy`, pass: false }; } const pass = eventSpy.length === count; return { message: () => `expected event "${eventSpy.eventName}" to have been called ${count} times, but it was called ${eventSpy.events.length} times`, pass }; } // src/matchers/index.ts var matchers = { toHaveReceivedEvent, toHaveReceivedEventDetail, toHaveReceivedEventTimes, toHaveFirstReceivedEventDetail, toHaveNthReceivedEventDetail }; // src/page/utils/goto.ts var goto = async (page, url, originalFn, options) => { const result = await Promise.all([ page.waitForFunction(() => window.testAppLoaded === true, { // This timeout was taken from the existing Playwright adapter in the Ionic Framework repository. // They tested this number and found it to be a reliable timeout for the Stencil components to be hydrated. timeout: 4750 }), originalFn(url, options) ]); return result[1]; }; // src/page/event-spy.ts var EventSpy = class { constructor(eventName) { this.eventName = eventName; /** * Keeping track of a cursor ensures that no two spy.next() calls point to the same event. */ this.cursor = 0; this.queuedHandler = []; this.events = []; } get length() { return this.events.length; } get firstEvent() { return this.events[0] ?? null; } get lastEvent() { return this.events[this.events.length - 1] ?? null; } next() { const { cursor } = this; this.cursor++; const next = this.events[cursor]; if (next !== void 0) { return Promise.resolve(next); } else { let resolve; const promise = new Promise((r) => resolve = r); this.queuedHandler.push(resolve); return promise.then(() => this.events[cursor]); } } push(ev) { this.events.push(ev); const next = this.queuedHandler.shift(); if (next) { next(); } } }; var initPageEvents = async (page) => { page._e2eEventsIds = 0; page._e2eEvents = /* @__PURE__ */ new Map(); await page.exposeFunction("stencilOnEvent", (id, ev) => { const context = page._e2eEvents.get(id); if (context) { context.callback(ev); } }); }; var addE2EListener = async (page, elmHandle, eventName, callback) => { const id = page._e2eEventsIds++; page._e2eEvents.set(id, { eventName, callback }); await elmHandle.evaluate( (elm, [eventName2, id2]) => { window.stencilSerializeEventTarget = (target) => { if (!target) { return null; } if (target === window) { return { serializedWindow: true }; } if (target === document) { return { serializedDocument: true }; } if (target.nodeType != null) { const serializedElement = { serializedElement: true, nodeName: target.nodeName, nodeValue: target.nodeValue, nodeType: target.nodeType, tagName: target.tagName, className: target.className, id: target.id }; return serializedElement; } return null; }; window.serializeStencilEvent = (orgEv) => { const serializedEvent = { bubbles: orgEv.bubbles, cancelBubble: orgEv.cancelBubble, cancelable: orgEv.cancelable, composed: orgEv.composed, currentTarget: window.stencilSerializeEventTarget(orgEv.currentTarget), defaultPrevented: orgEv.defaultPrevented, detail: orgEv.detail, eventPhase: orgEv.eventPhase, isTrusted: orgEv.isTrusted, returnValue: orgEv.returnValue, srcElement: window.stencilSerializeEventTarget(orgEv.srcElement), target: window.stencilSerializeEventTarget(orgEv.target), timeStamp: orgEv.timeStamp, type: orgEv.type, isSerializedEvent: true }; return serializedEvent; }; elm.addEventListener(eventName2, (ev) => { window.stencilOnEvent(id2, window.serializeStencilEvent(ev)); }); }, [eventName, id] ); }; // src/page/utils/locator.ts var locator = (page, originalFn, selector, options) => { const locator2 = originalFn(selector, options); locator2.spyOnEvent = async (eventName) => { const spy = new EventSpy(eventName); const handle = await locator2.evaluateHandle((node) => node); await addE2EListener(page, handle, eventName, (ev) => spy.push(ev)); return spy; }; return locator2; }; // src/page/utils/set-content.ts var setContent = async (page, html, testInfo, options) => { if (page.isClosed()) { throw new Error("setContent unavailable: page is already closed"); } const baseUrl = testInfo.project.use.baseURL; const baseEntryPath = process.env.STENCIL_ENTRY_PATH; const output = ` <!DOCTYPE html> <html lang="en"> <head> <title>Stencil Playwright Test</title> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0" /> <script src="${baseEntryPath}.js" nomodule></script> <script type="module" src="${baseEntryPath}.esm.js"></script> </head> <body> ${html} </body> </html> `; if (baseUrl) { await page.route(baseUrl, (route) => { if (route.request().url() === `${baseUrl}/`) { route.fulfill({ status: 200, contentType: "text/html", body: output }); } else { route.continue(); } }); await page.goto(`${baseUrl}#`, options); } else { throw new Error("setContent unavailable: no dev server base URL provided"); } }; // src/page/utils/spy-on-event.ts var spyOnEvent = async (page, eventName) => { const spy = new EventSpy(eventName); const handle = await page.evaluateHandle(() => window); await addE2EListener(page, handle, eventName, (ev) => spy.push(ev)); return spy; }; // src/page/utils/wait-for-changes.ts var waitForChanges = async (page, timeoutMs = 100) => { try { if (page.isClosed()) { return; } await page.evaluate(() => { return new Promise((resolve) => { requestAnimationFrame(() => { const promiseChain = []; const waitComponentOnReady = (elm, promises) => { if ("shadowRoot" in elm && elm.shadowRoot instanceof ShadowRoot) { waitComponentOnReady(elm.shadowRoot, promises); } const children = elm.children; const len = children.length; for (let i = 0; i < len; i++) { const childElm = children[i]; const childStencilElm = childElm; if (childElm.tagName.includes("-") && typeof childStencilElm.componentOnReady === "function") { promises.push(childStencilElm.componentOnReady()); } waitComponentOnReady(childElm, promises); } }; waitComponentOnReady(document.documentElement, promiseChain); Promise.all(promiseChain).then(() => resolve()).catch(() => resolve()); }); }); }); if (page.isClosed()) { return; } await page.waitForTimeout(timeoutMs); } catch (e) { console.error(e); } }; // src/playwright-page.ts var import_test4 = require("@playwright/test"); async function extendPageFixture(page) { if (!process.env["STENCIL_NAMESPACE" /* STENCIL_NAMESPACE */] || !process.env["STENCIL_ENTRY_PATH" /* STENCIL_ENTRY_PATH */]) { const { stencilNamespace, stencilEntryPath } = await loadConfigMeta(); if (!process.env["STENCIL_NAMESPACE" /* STENCIL_NAMESPACE */]) { process.env["STENCIL_NAMESPACE" /* STENCIL_NAMESPACE */] = stencilNamespace; } if (!process.env["STENCIL_ENTRY_PATH" /* STENCIL_ENTRY_PATH */]) { process.env["STENCIL_ENTRY_PATH" /* STENCIL_ENTRY_PATH */] = stencilEntryPath; } } const originalGoto = page.goto.bind(page); const originalLocator = page.locator.bind(page); await page.addInitScript(() => { window.addEventListener("appload", () => { window.testAppLoaded = true; }); }); page.goto = (url, options) => goto(page, url, originalGoto, options); page.setContent = (html, options) => setContent(page, html, test.info(), options); page.locator = (selector, options) => locator(page, originalLocator, selector, options); page.waitForChanges = (timeoutMs) => waitForChanges(page, timeoutMs); page.spyOnEvent = (eventName) => spyOnEvent(page, eventName); await initPageEvents(page); return page; } var test = import_test4.test.extend({ page: async ({ page }, use) => { page = await extendPageFixture(page); await use(page); }, skip: { browser: (browserNameOrFunction, reason = `The functionality that is being tested is not applicable to this browser.`) => { const browserName = import_test4.test.info().project.use.browserName; if (typeof browserNameOrFunction === "function") { import_test4.test.skip(browserNameOrFunction(browserName), reason); } else { import_test4.test.skip(browserName === browserNameOrFunction, reason); } }, mode: (mode, reason = `The functionality that is being tested is not applicable to ${mode} mode`) => { import_test4.test.skip(import_test4.test.info().project.metadata.mode === mode, reason); } } }); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { createConfig, goto, locator, matchers, setContent, spyOnEvent, test, waitForChanges }); //# sourceMappingURL=index.cjs.map