From 8b4263081c9fcc0f463e441bc834002e5f3f4038 Mon Sep 17 00:00:00 2001 From: Thorsten Kober Date: Fri, 23 May 2025 16:34:19 -0400 Subject: [PATCH 1/3] update helpers.mjs --- resources/shared/helpers.mjs | 39 +++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/resources/shared/helpers.mjs b/resources/shared/helpers.mjs index 729d5f3a4..dc415b0f5 100644 --- a/resources/shared/helpers.mjs +++ b/resources/shared/helpers.mjs @@ -1,28 +1,53 @@ /** - * Helper Methods + * Recursively queries the DOM for an element, traversing through shadow DOMs. * - * Various methods that are extracted from the Page class. + * @param {Element|ShadowRoot} lookupStartNode The node or shadow root to start the lookup from. + * @param {string[]} path An array of CSS selectors representing the path to the target element. + * @returns {Element|null} The target element if found, otherwise null. */ -export function getParent(lookupStartNode, path) { +export function recursivelyQuerySelector(lookupStartNode, path) { lookupStartNode = lookupStartNode.shadowRoot ?? lookupStartNode; - const parent = path.reduce((root, selector) => { + const target = path.reduce((root, selector) => { const node = root.querySelector(selector); return node.shadowRoot ?? node; }, lookupStartNode); - return parent; + return target; } +/** + * Retrieves a single DOM element, optionally traversing through shadow DOMs to a specified path before the final selection. + * + * @param {string} selector The CSS selector for the desired element. + * @param {string[]} [path=[]] An optional array of CSS selectors to reach the desired shadowRoot or parent element. + * @param {Element|ShadowRoot} [lookupStartNode=document] The starting node for the lookup. + * @returns {Element|null} The found element, or null if not found. + */ export function getElement(selector, path = [], lookupStartNode = document) { - const element = getParent(lookupStartNode, path).querySelector(selector); + const element = recursivelyQuerySelector(lookupStartNode, path).querySelector(selector); return element; } +/** + * Retrieves all DOM elements matching a selector, optionally traversing through shadow DOMs to a specified path before the final selection. + * + * @param {string} selector The CSS selector for the desired elements. + * @param {string[]} [path=[]] An optional array of CSS selectors to reach the desired shadowRoot or parent element. + * @param {Element|ShadowRoot} [lookupStartNode=document] The starting node for the lookup. + * @returns {Element[]} An array of found elements. + */ export function getAllElements(selector, path = [], lookupStartNode = document) { - const elements = Array.from(getParent(lookupStartNode, path).querySelectorAll(selector)); + const elements = Array.from(recursivelyQuerySelector(lookupStartNode, path).querySelectorAll(selector)); return elements; } +/** + * Forces a reflow/layout of the document by requesting a DOM property that triggers it. + * This can be useful for ensuring that styles and positions are up-to-date before + * performing measurements or animations. It also returns an element from the center of the viewport. + * + * @returns {Element|null} An element at the center of the viewport, or null if no element is there. + */ export function forceLayout() { const rect = document.body.getBoundingClientRect(); const e = document.elementFromPoint((rect.width / 2) | 0, (rect.height / 2) | 0); From 67d1e561776f5fd8098f24a3299cdc82ad686ad5 Mon Sep 17 00:00:00 2001 From: Thorsten Kober Date: Fri, 23 May 2025 16:53:56 -0400 Subject: [PATCH 2/3] more cleanup --- resources/shared/benchmark.mjs | 18 +++++++++--------- resources/shared/test-invoker.mjs | 6 ++---- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/resources/shared/benchmark.mjs b/resources/shared/benchmark.mjs index b691e86ac..176b7a4ed 100644 --- a/resources/shared/benchmark.mjs +++ b/resources/shared/benchmark.mjs @@ -13,7 +13,7 @@ export class BenchmarkStep { this.run = run; } - async runAndRecord(params, suite, test, callback) { + async runAndRecordStep(params, suite, test, callback) { const testRunner = new TestRunner(null, null, params, suite, test, callback); const result = await testRunner.runTest(); return result; @@ -26,9 +26,9 @@ export class BenchmarkStep { * A single test suite that contains one or more test steps. */ export class BenchmarkSuite { - constructor(name, tests) { + constructor(name, steps) { this.name = name; - this.tests = tests; + this.steps = steps; } record(_test, syncTime, asyncTime) { @@ -41,7 +41,7 @@ export class BenchmarkSuite { return results; } - async runAndRecord(params, onProgress) { + async runAndRecordSuite(params, onProgress) { const measuredValues = { tests: {}, total: 0, @@ -51,11 +51,11 @@ export class BenchmarkSuite { performance.mark(suiteStartLabel); - for (const test of this.tests) { - const result = await test.runAndRecord(params, this, test, this.record); - measuredValues.tests[test.name] = result; + for (const step of this.steps) { + const result = await step.runAndRecordStep(params, this, step, this.record); + measuredValues.tests[step.name] = result; measuredValues.total += result.total; - onProgress?.(test.name); + onProgress?.(step.name); } performance.mark(suiteEndLabel); @@ -103,7 +103,7 @@ export class BenchmarkConnector { const suite = this.suites[event.data.name]; if (!suite) console.error(`Suite with the name of "${event.data.name}" not found!`); - const { result } = await suite.runAndRecord(params, (test) => this.sendMessage({ type: "step-complete", status: "success", appId: this.appId, name: this.name, test })); + const { result } = await suite.runAndRecordSuite(params, (test) => this.sendMessage({ type: "step-complete", status: "success", appId: this.appId, name: this.name, test })); this.sendMessage({ type: "suite-complete", status: "success", appId: this.appId, result }); this.disconnect(); break; diff --git a/resources/shared/test-invoker.mjs b/resources/shared/test-invoker.mjs index 7bf105bdc..91d857e68 100644 --- a/resources/shared/test-invoker.mjs +++ b/resources/shared/test-invoker.mjs @@ -5,9 +5,7 @@ class TestInvoker { this._reportCallback = reportCallback; this._params = params; } -} -class BaseRAFTestInvoker extends TestInvoker { start() { return new Promise((resolve) => { if (this._params.waitBeforeSync) @@ -18,7 +16,7 @@ class BaseRAFTestInvoker extends TestInvoker { } } -class RAFTestInvoker extends BaseRAFTestInvoker { +class RAFTestInvoker extends TestInvoker { _scheduleCallbacks(resolve) { requestAnimationFrame(() => this._syncCallback()); requestAnimationFrame(() => { @@ -33,7 +31,7 @@ class RAFTestInvoker extends BaseRAFTestInvoker { } } -class AsyncRAFTestInvoker extends BaseRAFTestInvoker { +class AsyncRAFTestInvoker extends TestInvoker { static mc = new MessageChannel(); _scheduleCallbacks(resolve) { let gotTimer = false; From b593619ce6d5c1314087f4bec4ede9c635c91a76 Mon Sep 17 00:00:00 2001 From: Thorsten Kober Date: Tue, 15 Jul 2025 11:55:34 -0400 Subject: [PATCH 3/3] remove disabled tag from test --- resources/tests.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/tests.mjs b/resources/tests.mjs index 7f7077f9f..77e2989f2 100644 --- a/resources/tests.mjs +++ b/resources/tests.mjs @@ -263,7 +263,6 @@ Suites.push({ name: "TodoMVC-WebComponents-PostMessage", url: "resources/todomvc/vanilla-examples/javascript-web-components/dist/index.html", tags: ["experimental", "todomvc", "webcomponents"], - disabled: true, async prepare() {}, type: "remote", /* config: {