From 099ab8652d4b25e1d4f23c159fa4b684d7c9c517 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Tue, 30 Sep 2025 12:50:52 -0400 Subject: [PATCH 01/31] test(wtr): use vitest spy instead of jasmine --- .../test/signal/protocol/index.spec.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/@lwc/integration-not-karma/test/signal/protocol/index.spec.js b/packages/@lwc/integration-not-karma/test/signal/protocol/index.spec.js index e1b12420a3..ebd82e0e4f 100644 --- a/packages/@lwc/integration-not-karma/test/signal/protocol/index.spec.js +++ b/packages/@lwc/integration-not-karma/test/signal/protocol/index.spec.js @@ -11,7 +11,7 @@ import Throws from 'x/throws'; // Note for testing purposes the signal implementation uses LWC module resolution to simplify things. // In production the signal will come from a 3rd party library. import { Signal } from 'x/signal'; -import { jasmine } from '../../../helpers/jasmine.js'; +import { fn as mockFn } from '@vitest/spy'; import { resetDOM } from '../../../helpers/reset.js'; describe('signal protocol', () => { @@ -190,7 +190,7 @@ describe('signal protocol', () => { it('does not subscribe if the signal shape is incorrect', async () => { const elm = createElement('x-child', { is: Child }); - const subscribe = jasmine.createSpy(); + const subscribe = mockFn(); // Note the signals property is value's' and not value const signal = { values: 'initial value', subscribe }; elm.signal = signal; @@ -202,7 +202,7 @@ describe('signal protocol', () => { it('does not subscribe if the signal is not added as trusted signal', async () => { const elm = createElement('x-child', { is: Child }); - const subscribe = jasmine.createSpy(); + const subscribe = mockFn(); // Note this follows the shape of the signal implementation // but it's not added as a trusted signal (add using lwc.addTrustedSignal) const signal = { From a249b96c9bcf0a10bb41bd7542ef6c0590183715 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Mon, 6 Oct 2025 14:42:01 -0400 Subject: [PATCH 02/31] test(wtr): add API version 66 coverage to CI --- .github/workflows/web-test-runner.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/web-test-runner.yml b/.github/workflows/web-test-runner.yml index 3db9f7dd3b..425bc13d69 100644 --- a/.github/workflows/web-test-runner.yml +++ b/.github/workflows/web-test-runner.yml @@ -60,6 +60,7 @@ jobs: - run: API_VERSION=60 yarn test - run: API_VERSION=61 yarn test - run: API_VERSION=62 yarn test + - run: API_VERSION=66 yarn test - run: DISABLE_NATIVE_CUSTOM_ELEMENT_LIFECYCLE=1 yarn test || true - run: DISABLE_STATIC_CONTENT_OPTIMIZATION=1 yarn test - run: ENABLE_ARIA_REFLECTION_GLOBAL_POLYFILL=1 yarn test From 1e50ff1d49c5e281c60ea48f8f42453ee916129d Mon Sep 17 00:00:00 2001 From: Will Harney Date: Mon, 6 Oct 2025 16:36:09 -0400 Subject: [PATCH 03/31] test(wtr): indent consistently probably still wrongly, tho --- packages/@lwc/integration-not-karma/configs/base.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/@lwc/integration-not-karma/configs/base.js b/packages/@lwc/integration-not-karma/configs/base.js index 9dae0c90c7..339c4e9881 100644 --- a/packages/@lwc/integration-not-karma/configs/base.js +++ b/packages/@lwc/integration-not-karma/configs/base.js @@ -64,7 +64,8 @@ export default (options) => { }, ], testRunnerHtml: (testFramework) => - ` + ` + - `, + + `, }; }; From 715cac860a4521bee6a8f1f05ba6f5e89ed1e0bf Mon Sep 17 00:00:00 2001 From: Will Harney Date: Tue, 7 Oct 2025 14:03:19 -0400 Subject: [PATCH 04/31] test(wtr): move base config into shared dir --- packages/@lwc/integration-not-karma/configs/hydration.js | 2 +- packages/@lwc/integration-not-karma/configs/integration.js | 2 +- .../configs/{base.js => shared/base-config.js} | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename packages/@lwc/integration-not-karma/configs/{base.js => shared/base-config.js} (96%) diff --git a/packages/@lwc/integration-not-karma/configs/hydration.js b/packages/@lwc/integration-not-karma/configs/hydration.js index 1b085ad761..a03f370cf4 100644 --- a/packages/@lwc/integration-not-karma/configs/hydration.js +++ b/packages/@lwc/integration-not-karma/configs/hydration.js @@ -1,5 +1,5 @@ import * as options from '../helpers/options.js'; -import createConfig from './base.js'; +import createConfig from './shared/base-config.js'; import hydrationTestPlugin from './plugins/serve-hydration.js'; const SHADOW_MODE = options.SHADOW_MODE_OVERRIDE ?? 'native'; diff --git a/packages/@lwc/integration-not-karma/configs/integration.js b/packages/@lwc/integration-not-karma/configs/integration.js index f7b2b8618a..0ce6a84d5b 100644 --- a/packages/@lwc/integration-not-karma/configs/integration.js +++ b/packages/@lwc/integration-not-karma/configs/integration.js @@ -1,6 +1,6 @@ import { importMapsPlugin } from '@web/dev-server-import-maps'; import * as options from '../helpers/options.js'; -import createConfig from './base.js'; +import createConfig from './shared/base-config.js'; import testPlugin from './plugins/serve-integration.js'; const SHADOW_MODE = options.SHADOW_MODE_OVERRIDE ?? 'synthetic'; diff --git a/packages/@lwc/integration-not-karma/configs/base.js b/packages/@lwc/integration-not-karma/configs/shared/base-config.js similarity index 96% rename from packages/@lwc/integration-not-karma/configs/base.js rename to packages/@lwc/integration-not-karma/configs/shared/base-config.js index 339c4e9881..b33ef595a6 100644 --- a/packages/@lwc/integration-not-karma/configs/base.js +++ b/packages/@lwc/integration-not-karma/configs/shared/base-config.js @@ -1,6 +1,6 @@ import { join } from 'node:path'; import { LWC_VERSION } from '@lwc/shared'; -import { resolvePathOutsideRoot } from '../helpers/utils.js'; +import { resolvePathOutsideRoot } from '../../helpers/utils.js'; /** * We want to convert from parsed options (true/false) to a `process.env` with only strings. @@ -43,7 +43,7 @@ export default (options) => { concurrency: 1, browserLogs: false, nodeResolve: true, - rootDir: join(import.meta.dirname, '..'), + rootDir: join(import.meta.dirname, '../..'), plugins: [ { name: 'lwc-base-plugin', From 22cfa8da691f34d4f187b8d41220a85ba31ccdf6 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Tue, 7 Oct 2025 14:46:25 -0400 Subject: [PATCH 05/31] test(wtr): run tests in multiple browsers --- .../src/libs/signal-tracker/index.ts | 25 +++++++-- .../configs/shared/base-config.js | 5 +- .../configs/shared/browsers.js | 56 +++++++++++++++++++ .../@lwc/integration-not-karma/package.json | 5 +- .../index.spec.js | 4 +- yarn.lock | 56 ++++++++++++++++++- 6 files changed, 139 insertions(+), 12 deletions(-) create mode 100644 packages/@lwc/integration-not-karma/configs/shared/browsers.js diff --git a/packages/@lwc/engine-core/src/libs/signal-tracker/index.ts b/packages/@lwc/engine-core/src/libs/signal-tracker/index.ts index 4a6d04745b..bdabbde6da 100644 --- a/packages/@lwc/engine-core/src/libs/signal-tracker/index.ts +++ b/packages/@lwc/engine-core/src/libs/signal-tracker/index.ts @@ -44,6 +44,19 @@ export function unsubscribeFromSignals(target: object) { type CallbackFunction = () => void; +/** + * A normalized string representation of an error, because browsers behave differently + */ +const errorWithStack = (err: unknown): string => { + if (typeof err !== 'object' || err === null) { + return String(err); + } + const stack = 'stack' in err ? String(err.stack) : ''; + const message = 'message' in err ? String(err.message) : ''; + const constructor = err.constructor.name; + return stack.includes(message) ? stack : `${constructor}: ${message}\n${stack}`; +}; + /** * This class is used to keep track of the signals associated to a given object. * It is used to prevent the LWC engine from subscribing duplicate callbacks multiple times @@ -67,9 +80,9 @@ class SignalTracker { } } catch (err: any) { logWarnOnce( - `Attempted to subscribe to an object that has the shape of a signal but received the following error: ${ - err?.stack ?? err - }` + `Attempted to subscribe to an object that has the shape of a signal but received the following error: ${errorWithStack( + err + )}` ); } } @@ -79,9 +92,9 @@ class SignalTracker { this.signalToUnsubscribeMap.forEach((unsubscribe) => unsubscribe()); } catch (err: any) { logWarnOnce( - `Attempted to call a signal's unsubscribe callback but received the following error: ${ - err?.stack ?? err - }` + `Attempted to call a signal's unsubscribe callback but received the following error: ${errorWithStack( + err + )}` ); } } diff --git a/packages/@lwc/integration-not-karma/configs/shared/base-config.js b/packages/@lwc/integration-not-karma/configs/shared/base-config.js index b33ef595a6..72c84ce27a 100644 --- a/packages/@lwc/integration-not-karma/configs/shared/base-config.js +++ b/packages/@lwc/integration-not-karma/configs/shared/base-config.js @@ -1,6 +1,7 @@ import { join } from 'node:path'; import { LWC_VERSION } from '@lwc/shared'; import { resolvePathOutsideRoot } from '../../helpers/utils.js'; +import { getBrowsers } from './browsers.js'; /** * We want to convert from parsed options (true/false) to a `process.env` with only strings. @@ -37,11 +38,13 @@ export default (options) => { }); return { + browsers: getBrowsers(options), + browserLogs: false, // FIXME: Parallelism breaks tests that rely on focus/requestAnimationFrame, because they often // time out before they receive focus. But it also makes the full suite take 3x longer to run... // Potential workaround: https://github.com/modernweb-dev/web/issues/2588 concurrency: 1, - browserLogs: false, + concurrentBrowsers: 3, nodeResolve: true, rootDir: join(import.meta.dirname, '../..'), plugins: [ diff --git a/packages/@lwc/integration-not-karma/configs/shared/browsers.js b/packages/@lwc/integration-not-karma/configs/shared/browsers.js new file mode 100644 index 0000000000..220c458f42 --- /dev/null +++ b/packages/@lwc/integration-not-karma/configs/shared/browsers.js @@ -0,0 +1,56 @@ +import { playwrightLauncher } from '@web/test-runner-playwright'; +import { createSauceLabsLauncher } from '@web/test-runner-saucelabs'; + +/** @type {(options: typeof import('../../helpers/options.js')) => import("@web/test-runner").BrowserLauncher[]} */ +export function getBrowsers(options) { + if (options.IS_CI) { + if (!options.SAUCE_USERNAME || !options.SAUCE_ACCESS_KEY || !options.SAUCE_TUNNEL_ID) { + throw new Error( + `SAUCE_USERNAME, SAUCE_ACCESS_KEY, and SAUCE_TUNNEL_ID must be configured in CI` + ); + } + const sauceLabsLauncher = createSauceLabsLauncher( + { + user: options.SAUCE_USERNAME, + key: options.SAUCE_ACCESS_KEY, + }, + { + tunnelName: options.SAUCE_TUNNEL_ID, + } + ); + return [ + sauceLabsLauncher({ + browserName: 'chrome', + browserVersion: 'latest', + }), + sauceLabsLauncher({ + browserName: 'firefox', + browserVersion: 'latest', + }), + sauceLabsLauncher({ + browserName: 'safari', + browserVersion: 'latest', + platformName: 'macOS 15', // Update this with new Mac releases + }), + ...(options.LEGACY_BROWSERS + ? [ + sauceLabsLauncher({ + browserName: 'chrome', + browserVersion: 'latest-2', + }), + sauceLabsLauncher({ + browserName: 'safari', + browserVersion: 'latest-2', + platformName: 'macOS 13', // Should be 2 behind latest + }), + ] + : []), + ]; + } else { + return [ + playwrightLauncher({ product: 'chromium' }), + playwrightLauncher({ product: 'firefox' }), + playwrightLauncher({ product: 'webkit' }), + ]; + } +} diff --git a/packages/@lwc/integration-not-karma/package.json b/packages/@lwc/integration-not-karma/package.json index 3242986035..faf7b45140 100644 --- a/packages/@lwc/integration-not-karma/package.json +++ b/packages/@lwc/integration-not-karma/package.json @@ -21,7 +21,10 @@ "@web/dev-server-import-maps": "^0.2.1", "@web/dev-server-rollup": "^0.6.4", "@web/test-runner": "^0.20.2", - "chai": "^6.2.0" + "@web/test-runner-playwright": "^0.11.1", + "@web/test-runner-saucelabs": "^0.13.0", + "chai": "^6.2.0", + "playwright": "^1.56.0" }, "volta": { "extends": "../../../package.json" diff --git a/packages/@lwc/integration-not-karma/test/api/CustomElementConstructor-getter/index.spec.js b/packages/@lwc/integration-not-karma/test/api/CustomElementConstructor-getter/index.spec.js index 6850011af9..4eb8cc217d 100644 --- a/packages/@lwc/integration-not-karma/test/api/CustomElementConstructor-getter/index.spec.js +++ b/packages/@lwc/integration-not-karma/test/api/CustomElementConstructor-getter/index.spec.js @@ -34,7 +34,9 @@ it('CustomElementConstructor cannot be `new`ed before being defined', () => { new UndefinedComponent.CustomElementConstructor(); }; expect(func).toThrowError(TypeError); - expect(func).toThrowError(/(Illegal constructor|does not define a custom element)/); + expect(func).toThrowError( + /(Illegal constructor|does not define a custom element|is not a valid custom element constructor)/ + ); }); it('CustomElementConstructor can be `new`ed after being defined', () => { diff --git a/yarn.lock b/yarn.lock index e6f7debd0b..eb790c5312 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2091,9 +2091,11 @@ "@lwc/eslint-plugin-lwc-internal@link:./scripts/eslint-plugin": version "0.0.0" + uid "" "@lwc/test-utils-lwc-internals@link:./scripts/test-utils": version "0.0.0" + uid "" "@napi-rs/wasm-runtime@0.2.4": version "0.2.4" @@ -4026,6 +4028,35 @@ dependencies: "@web/test-runner-core" "^0.13.0" +"@web/test-runner-playwright@^0.11.1": + version "0.11.1" + resolved "https://registry.yarnpkg.com/@web/test-runner-playwright/-/test-runner-playwright-0.11.1.tgz#d993112ae2126eb74c1c5a171d6ea44c2dd24b4e" + integrity sha512-l9tmX0LtBqMaKAApS4WshpB87A/M8sOHZyfCobSGuYqnREgz5rqQpX314yx+4fwHXLLTa5N64mTrawsYkLjliw== + dependencies: + "@web/test-runner-core" "^0.13.0" + "@web/test-runner-coverage-v8" "^0.8.0" + playwright "^1.53.0" + +"@web/test-runner-saucelabs@^0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@web/test-runner-saucelabs/-/test-runner-saucelabs-0.13.0.tgz#66b50d4cf6ca29163e8c67e0d6a0b5863ac69172" + integrity sha512-RHVDIFVaiOoxydigx1S4wrA20wjjLF9IAxlT7HxYHxO1qx1UIuWLabd6jEGlxluC0xFhuBJLm+zFj8zMEXJNyg== + dependencies: + "@web/test-runner-webdriver" "^0.9.0" + internal-ip "^6.2.0" + nanoid "^3.1.25" + saucelabs "^9.0.0" + webdriver "^9.0.0" + webdriverio "^9.0.0" + +"@web/test-runner-webdriver@^0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@web/test-runner-webdriver/-/test-runner-webdriver-0.9.0.tgz#18fb3299ddc258a2782028de19f21ee4c27895c5" + integrity sha512-G2io6ph0v/sX0U/DEgh/EUHsLsq8/Gs/uUw8N7rcUaXSdIFCUbxlwzx/qZv2ZKY52q84oYUyeOhViNZ2OqYl6Q== + dependencies: + "@web/test-runner-core" "^0.13.0" + webdriverio "^9.0.0" + "@web/test-runner@^0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@web/test-runner/-/test-runner-0.20.2.tgz#3045de8f14eb9f9b8aa51aa7fd9849dd95bb0a93" @@ -7605,6 +7636,11 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== +fsevents@2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + fsevents@~2.3.2, fsevents@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" @@ -11279,6 +11315,20 @@ pkg-up@^4.0.0: dependencies: find-up "^6.2.0" +playwright-core@1.56.0: + version "1.56.0" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.56.0.tgz#14b40ea436551b0bcefe19c5bfb8d1804c83739c" + integrity sha512-1SXl7pMfemAMSDn5rkPeZljxOCYAmQnYLBTExuh6E8USHXGSX3dx6lYZN/xPpTz1vimXmPA9CDnILvmJaB8aSQ== + +playwright@^1.53.0, playwright@^1.56.0: + version "1.56.0" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.56.0.tgz#71c533c61da33e95812f8c6fa53960e073548d9a" + integrity sha512-X5Q1b8lOdWIE4KAoHpW3SE8HvUB+ZZsUoN64ZhjnN8dOb1UpujxBtENGiZFE+9F/yhzJwYa+ca3u43FeLbboHA== + dependencies: + playwright-core "1.56.0" + optionalDependencies: + fsevents "2.3.2" + portfinder@^1.0.32: version "1.0.37" resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.37.tgz#92b754ef89a11801c8efe4b0e5cd845b0064c212" @@ -12132,7 +12182,7 @@ saucelabs@6.2.2: tunnel "0.0.6" yargs "^17.0.1" -saucelabs@^9.0.1: +saucelabs@^9.0.0, saucelabs@^9.0.1: version "9.0.2" resolved "https://registry.yarnpkg.com/saucelabs/-/saucelabs-9.0.2.tgz#99f6170f3d789fcb0be2f270f7d37a9d7cdf5187" integrity sha512-37QGEOgp9BP1re6S06qpNcBZ0Hw+ZSkZkDepbXHT9VjYoRQwRzUoLtKqE4yyVeK7dzcQXQapmTGF1kp1jO2VDw== @@ -13856,7 +13906,7 @@ webdriver@7.19.5: ky "^0.30.0" lodash.merge "^4.6.1" -webdriver@9.20.0: +webdriver@9.20.0, webdriver@^9.0.0: version "9.20.0" resolved "https://registry.yarnpkg.com/webdriver/-/webdriver-9.20.0.tgz#518fa61abd0b0435509548ef54fb0824f0fa04fd" integrity sha512-Kk+AGV1xWLNHVpzUynQJDULMzbcO3IjXo3s0BzfC30OpGxhpaNmoazMQodhtv0Lp242Mb1VYXD89dCb4oAHc4w== @@ -13906,7 +13956,7 @@ webdriverio@7.19.5: serialize-error "^8.0.0" webdriver "7.19.5" -webdriverio@9.20.0, webdriverio@^9.19.2: +webdriverio@9.20.0, webdriverio@^9.0.0, webdriverio@^9.19.2: version "9.20.0" resolved "https://registry.yarnpkg.com/webdriverio/-/webdriverio-9.20.0.tgz#46f45268f2c4021a18045a7e7dfd738225514ece" integrity sha512-cqaXfahTzCFaQLlk++feZaze6tAsW8OSdaVRgmOGJRII1z2A4uh4YGHtusTpqOiZAST7OBPqycOwfh01G/Ktbg== From af60a96bdde9cf5792cf8099b7c858bfe91e00be Mon Sep 17 00:00:00 2001 From: Will Harney Date: Tue, 7 Oct 2025 14:58:56 -0400 Subject: [PATCH 06/31] test(wtr): use build script to install playwright I'm not convinced this is the right place to do it --- packages/@lwc/integration-not-karma/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/@lwc/integration-not-karma/package.json b/packages/@lwc/integration-not-karma/package.json index faf7b45140..f5d51ab307 100644 --- a/packages/@lwc/integration-not-karma/package.json +++ b/packages/@lwc/integration-not-karma/package.json @@ -4,6 +4,7 @@ "version": "8.22.4", "type": "module", "scripts": { + "build": "playwright install", "start": "web-test-runner --manual", "test": "web-test-runner --config configs/integration.js", "test:hydration": "web-test-runner --config configs/hydration.js" From 41676b562cb3ab9b3fb00dcb7574ea0b9105095d Mon Sep 17 00:00:00 2001 From: Will Harney Date: Tue, 7 Oct 2025 15:06:29 -0400 Subject: [PATCH 07/31] chore: bundlesize FAIL: packages/@lwc/engine-dom/dist/index.js: 24.79KB > 24.79KB RUDE --- scripts/bundlesize/bundlesize.config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/bundlesize/bundlesize.config.json b/scripts/bundlesize/bundlesize.config.json index 085eddc8d4..b457893ec8 100644 --- a/scripts/bundlesize/bundlesize.config.json +++ b/scripts/bundlesize/bundlesize.config.json @@ -2,7 +2,7 @@ "files": [ { "path": "packages/@lwc/engine-dom/dist/index.js", - "maxSize": "24.79KB" + "maxSize": "25KB" }, { "path": "packages/@lwc/synthetic-shadow/dist/index.js", From 1b44785e5787898b9441f02517335553ac8f6c8f Mon Sep 17 00:00:00 2001 From: Will Harney Date: Tue, 7 Oct 2025 15:31:29 -0400 Subject: [PATCH 08/31] test(wtr): add type for param --- .../@lwc/integration-not-karma/configs/shared/base-config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@lwc/integration-not-karma/configs/shared/base-config.js b/packages/@lwc/integration-not-karma/configs/shared/base-config.js index 72c84ce27a..a269499a85 100644 --- a/packages/@lwc/integration-not-karma/configs/shared/base-config.js +++ b/packages/@lwc/integration-not-karma/configs/shared/base-config.js @@ -19,7 +19,7 @@ const envify = (obj) => { const pluck = (obj, keys) => Object.fromEntries(keys.map((k) => [k, obj[k]])); const maybeImport = (file, condition) => (condition ? `await import('${file}');` : ''); -/** @type {() => import("@web/test-runner").TestRunnerConfig} */ +/** @type {(options: typeof import('../../helpers/options.js')) => import("@web/test-runner").TestRunnerConfig} */ export default (options) => { /** `process.env` to inject into test environment. */ const env = envify({ From 2072694e7ebfa60305bb9f3e34ce4e127db1d88a Mon Sep 17 00:00:00 2001 From: Will Harney Date: Tue, 7 Oct 2025 15:32:04 -0400 Subject: [PATCH 09/31] test(wtr): use sauce helper in CI --- .github/workflows/web-test-runner.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/web-test-runner.yml b/.github/workflows/web-test-runner.yml index 425bc13d69..42881a69b0 100644 --- a/.github/workflows/web-test-runner.yml +++ b/.github/workflows/web-test-runner.yml @@ -19,7 +19,6 @@ env: jobs: # TODO: upload result artifacts - # TODO: make it saucy 🥫 integration-tests: name: Integration tests (${{ matrix.shadow_mode }} shadow) strategy: @@ -90,12 +89,12 @@ jobs: run: yarn install --frozen-lockfile working-directory: ./ - # - uses: saucelabs/sauce-connect-action@v3.0.0 - # with: - # username: ${{ secrets.SAUCE_USERNAME }} - # accessKey: ${{ secrets.SAUCE_ACCESS_KEY }} - # tunnelName: ${{ env.SAUCE_TUNNEL_ID }} - # region: us + - uses: saucelabs/sauce-connect-action@v3.0.0 + with: + username: ${{ secrets.SAUCE_USERNAME }} + accessKey: ${{ secrets.SAUCE_ACCESS_KEY }} + tunnelName: ${{ env.SAUCE_TUNNEL_ID }} + region: us # Synthetic shadow only - run: LEGACY_BROWSERS=1 yarn test || true From 423c051fbf38cef093e92f5d7e089d23218615ad Mon Sep 17 00:00:00 2001 From: Will Harney Date: Tue, 7 Oct 2025 15:42:01 -0400 Subject: [PATCH 10/31] test(wtr): add install to playwright setup --- packages/@lwc/integration-not-karma/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@lwc/integration-not-karma/package.json b/packages/@lwc/integration-not-karma/package.json index f5d51ab307..cd11a5dfbd 100644 --- a/packages/@lwc/integration-not-karma/package.json +++ b/packages/@lwc/integration-not-karma/package.json @@ -4,7 +4,7 @@ "version": "8.22.4", "type": "module", "scripts": { - "build": "playwright install", + "build": "playwright install-deps chromium firefox webkit", "start": "web-test-runner --manual", "test": "web-test-runner --config configs/integration.js", "test:hydration": "web-test-runner --config configs/hydration.js" From 7841184091f369ed89c7d55fc354026f834a0eab Mon Sep 17 00:00:00 2001 From: Will Harney Date: Tue, 7 Oct 2025 15:46:45 -0400 Subject: [PATCH 11/31] test(wtr): enable saucelabs in all runs --- .github/workflows/web-test-runner.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/web-test-runner.yml b/.github/workflows/web-test-runner.yml index 42881a69b0..793dd5193d 100644 --- a/.github/workflows/web-test-runner.yml +++ b/.github/workflows/web-test-runner.yml @@ -46,12 +46,12 @@ jobs: run: yarn install --frozen-lockfile working-directory: ./ - # - uses: saucelabs/sauce-connect-action@v3.0.0 - # with: - # username: ${{ secrets.SAUCE_USERNAME }} - # accessKey: ${{ secrets.SAUCE_ACCESS_KEY }} - # tunnelName: ${{ env.SAUCE_TUNNEL_ID }} - # region: us + - uses: saucelabs/sauce-connect-action@v3.0.0 + with: + username: ${{ secrets.SAUCE_USERNAME }} + accessKey: ${{ secrets.SAUCE_ACCESS_KEY }} + tunnelName: ${{ env.SAUCE_TUNNEL_ID }} + region: us - run: yarn test - run: API_VERSION=58 yarn test @@ -127,12 +127,12 @@ jobs: run: yarn install --frozen-lockfile working-directory: ./ - # - uses: saucelabs/sauce-connect-action@v3.0.0 - # with: - # username: ${{ secrets.SAUCE_USERNAME }} - # accessKey: ${{ secrets.SAUCE_ACCESS_KEY }} - # tunnelName: ${{ env.SAUCE_TUNNEL_ID }} - # region: us + - uses: saucelabs/sauce-connect-action@v3.0.0 + with: + username: ${{ secrets.SAUCE_USERNAME }} + accessKey: ${{ secrets.SAUCE_ACCESS_KEY }} + tunnelName: ${{ env.SAUCE_TUNNEL_ID }} + region: us - run: ENGINE_SERVER=1 yarn test:hydration - run: ENGINE_SERVER=1 SHADOW_MODE_OVERRIDE=synthetic yarn test:hydration - run: ENGINE_SERVER=1 NODE_ENV_FOR_TEST=production yarn test:hydration From 52915ff5ef5c659cc2c1ffa3db8f7a3fa77fa065 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Tue, 7 Oct 2025 15:51:10 -0400 Subject: [PATCH 12/31] test(wtr): kerjigger playwright again --- packages/@lwc/integration-not-karma/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@lwc/integration-not-karma/package.json b/packages/@lwc/integration-not-karma/package.json index cd11a5dfbd..6ee92c7785 100644 --- a/packages/@lwc/integration-not-karma/package.json +++ b/packages/@lwc/integration-not-karma/package.json @@ -4,7 +4,7 @@ "version": "8.22.4", "type": "module", "scripts": { - "build": "playwright install-deps chromium firefox webkit", + "build": "playwright install && playwright install-deps chromium firefox webkit", "start": "web-test-runner --manual", "test": "web-test-runner --config configs/integration.js", "test:hydration": "web-test-runner --config configs/hydration.js" From f17448b0a71a4d2570db192d9a44647f4faa8ad3 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Tue, 7 Oct 2025 16:01:03 -0400 Subject: [PATCH 13/31] test(wtr): rekerjigger playwright again --- packages/@lwc/integration-not-karma/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@lwc/integration-not-karma/package.json b/packages/@lwc/integration-not-karma/package.json index 6ee92c7785..f5d51ab307 100644 --- a/packages/@lwc/integration-not-karma/package.json +++ b/packages/@lwc/integration-not-karma/package.json @@ -4,7 +4,7 @@ "version": "8.22.4", "type": "module", "scripts": { - "build": "playwright install && playwright install-deps chromium firefox webkit", + "build": "playwright install", "start": "web-test-runner --manual", "test": "web-test-runner --config configs/integration.js", "test:hydration": "web-test-runner --config configs/hydration.js" From 64126464361ae9730b33524ec13c71f083f17e79 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Tue, 7 Oct 2025 16:08:38 -0400 Subject: [PATCH 14/31] test(wtr): make fake SSR file more clear --- .../integration-not-karma/configs/plugins/serve-hydration.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@lwc/integration-not-karma/configs/plugins/serve-hydration.js b/packages/@lwc/integration-not-karma/configs/plugins/serve-hydration.js index 62bfa0a2d0..da07194acc 100644 --- a/packages/@lwc/integration-not-karma/configs/plugins/serve-hydration.js +++ b/packages/@lwc/integration-not-karma/configs/plugins/serve-hydration.js @@ -87,7 +87,7 @@ async function getSsrMarkup(componentEntrypoint, configPath) { ); })()`, { - filename: `[SSR] ${configPath}`, + filename: `(virtual SSR file for) ${configPath}`, importModuleDynamically: vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER, } ); From e4092b4c8cfd8cbe8e72460b93a47c49d83e4f69 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Tue, 7 Oct 2025 16:10:45 -0400 Subject: [PATCH 15/31] test(wtr): install playwright deps in WTR CI installing in package break nucleus --- .github/workflows/web-test-runner.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/web-test-runner.yml b/.github/workflows/web-test-runner.yml index 793dd5193d..3cdf0b4697 100644 --- a/.github/workflows/web-test-runner.yml +++ b/.github/workflows/web-test-runner.yml @@ -53,6 +53,7 @@ jobs: tunnelName: ${{ env.SAUCE_TUNNEL_ID }} region: us + - run: yarn exec -- playwright install-deps chromium firefox webkit - run: yarn test - run: API_VERSION=58 yarn test - run: API_VERSION=59 yarn test @@ -96,6 +97,7 @@ jobs: tunnelName: ${{ env.SAUCE_TUNNEL_ID }} region: us + - run: yarn exec -- playwright install-deps chromium firefox webkit # Synthetic shadow only - run: LEGACY_BROWSERS=1 yarn test || true - run: FORCE_NATIVE_SHADOW_MODE_FOR_TEST=1 yarn test @@ -133,6 +135,8 @@ jobs: accessKey: ${{ secrets.SAUCE_ACCESS_KEY }} tunnelName: ${{ env.SAUCE_TUNNEL_ID }} region: us + + - run: yarn exec -- playwright install-deps chromium firefox webkit - run: ENGINE_SERVER=1 yarn test:hydration - run: ENGINE_SERVER=1 SHADOW_MODE_OVERRIDE=synthetic yarn test:hydration - run: ENGINE_SERVER=1 NODE_ENV_FOR_TEST=production yarn test:hydration From 5357cd7203e06c543233dd0725b68790aa39002b Mon Sep 17 00:00:00 2001 From: Will Harney Date: Tue, 7 Oct 2025 16:27:27 -0400 Subject: [PATCH 16/31] test(wtr): and much rekerjiggering there was --- .github/workflows/web-test-runner.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/web-test-runner.yml b/.github/workflows/web-test-runner.yml index 3cdf0b4697..3773362b64 100644 --- a/.github/workflows/web-test-runner.yml +++ b/.github/workflows/web-test-runner.yml @@ -53,7 +53,7 @@ jobs: tunnelName: ${{ env.SAUCE_TUNNEL_ID }} region: us - - run: yarn exec -- playwright install-deps chromium firefox webkit + - run: yarn exec -- playwright install chrome firefox webkit --with-deps - run: yarn test - run: API_VERSION=58 yarn test - run: API_VERSION=59 yarn test @@ -97,7 +97,7 @@ jobs: tunnelName: ${{ env.SAUCE_TUNNEL_ID }} region: us - - run: yarn exec -- playwright install-deps chromium firefox webkit + - run: yarn exec -- playwright install chrome firefox webkit --with-deps # Synthetic shadow only - run: LEGACY_BROWSERS=1 yarn test || true - run: FORCE_NATIVE_SHADOW_MODE_FOR_TEST=1 yarn test @@ -136,7 +136,7 @@ jobs: tunnelName: ${{ env.SAUCE_TUNNEL_ID }} region: us - - run: yarn exec -- playwright install-deps chromium firefox webkit + - run: yarn exec -- playwright install chrome firefox webkit --with-deps - run: ENGINE_SERVER=1 yarn test:hydration - run: ENGINE_SERVER=1 SHADOW_MODE_OVERRIDE=synthetic yarn test:hydration - run: ENGINE_SERVER=1 NODE_ENV_FOR_TEST=production yarn test:hydration From 3fade975957fa079120ed5eb0fb0891b5fdf10df Mon Sep 17 00:00:00 2001 From: Will Harney Date: Thu, 9 Oct 2025 11:57:02 -0400 Subject: [PATCH 17/31] test(wtr): isolate server-side LWC --- .../configs/plugins/serve-hydration.js | 81 +++++++++---------- 1 file changed, 38 insertions(+), 43 deletions(-) diff --git a/packages/@lwc/integration-not-karma/configs/plugins/serve-hydration.js b/packages/@lwc/integration-not-karma/configs/plugins/serve-hydration.js index da07194acc..0a30fa9019 100644 --- a/packages/@lwc/integration-not-karma/configs/plugins/serve-hydration.js +++ b/packages/@lwc/integration-not-karma/configs/plugins/serve-hydration.js @@ -1,20 +1,16 @@ import path from 'node:path'; import vm from 'node:vm'; import { fileURLToPath } from 'node:url'; +import { readFileSync } from 'node:fs'; import { rollup } from 'rollup'; import lwcRollupPlugin from '@lwc/rollup-plugin'; import { DISABLE_STATIC_CONTENT_OPTIMIZATION, ENGINE_SERVER } from '../../helpers/options.js'; -/** LWC SSR module to use when server-side rendering components. */ -const lwcSsr = await (ENGINE_SERVER - ? // Using import('literal') rather than import(variable) so static analysis tools work - import('@lwc/engine-server') - : import('@lwc/ssr-runtime')); -lwcSsr.setHooks({ - sanitizeHtmlContent(content) { - return content; - }, -}); +/** Code for the LWC SSR module. */ +const LWC_SSR = readFileSync( + new URL(import.meta.resolve(ENGINE_SERVER ? '@lwc/engine-server' : '@lwc/ssr-runtime')), + 'utf8' +); const ROOT_DIR = path.join(import.meta.dirname, '../..'); const COMPONENT_NAME = 'x-main'; @@ -68,16 +64,27 @@ async function compileModule(input, targetSSR, format) { */ async function getSsrMarkup(componentEntrypoint, configPath) { const componentIife = await compileModule(componentEntrypoint, !ENGINE_SERVER, 'iife'); - // To minimize the amount of code in the generated script, ideally we'd do `import Component` - // and delegate the bundling to the loader. However, that's complicated to configure and using - // imports with vm.Script/vm.Module is still experimental, so we use an IIFE for simplicity. - // Additionally, we could import LWC, but the framework requires configuration before each test - // (setHooks/setFeatureFlagForTest), so instead we configure it once in the top-level context - // and inject it as a global variable. + // Ideally, we'd be able to do `import Component` and delegate bundling to the loader. We also + // need each import of LWC to be isolated, but by all server-side imports share a global state. + // We could solve this with the right `vm.Script`/`vm.Module` setup, but that's complicated and + // still experimental. Therefore, we just inline everything. const script = new vm.Script( `(async () => { - const {default: config} = await import('./${configPath}'); - ${componentIife /* var Component = ... */} + // node.js / CommonJS setup + const process = { env: ${JSON.stringify(process.env)} }; + const exports = Object.create(null); + const LWC = exports; + + // LWC / test setup + ${LWC_SSR}; + LWC.setHooks({ sanitizeHtmlContent: (v) => v }); + const { default: config } = await import('./${configPath}'); + config.requiredFeatureFlags?.forEach(ff => { + LWC.setFeatureFlagForTest(ff, true); + }); + + // Component code + ${componentIife}; return LWC.renderComponent( '${COMPONENT_NAME}', Component, @@ -92,7 +99,7 @@ async function getSsrMarkup(componentEntrypoint, configPath) { } ); - return await script.runInContext(vm.createContext({ LWC: lwcSsr })); + return await script.runInNewContext(); } /** @@ -100,31 +107,19 @@ async function getSsrMarkup(componentEntrypoint, configPath) { * This function wraps those configs in the test code to be executed. */ async function wrapHydrationTest(configPath) { - const { default: config } = await import(path.join(ROOT_DIR, configPath)); + const suiteDir = path.dirname(configPath); + const componentEntrypoint = path.join(suiteDir, COMPONENT_ENTRYPOINT); + const ssrOutput = await getSsrMarkup(componentEntrypoint, configPath); - try { - config.requiredFeatureFlags?.forEach((featureFlag) => { - lwcSsr.setFeatureFlagForTest(featureFlag, true); - }); - - const suiteDir = path.dirname(configPath); - const componentEntrypoint = path.join(suiteDir, COMPONENT_ENTRYPOINT); - const ssrOutput = await getSsrMarkup(componentEntrypoint, configPath); - - return ` - import * as LWC from 'lwc'; - import { runTest } from '/configs/plugins/test-hydration.js'; - runTest( - '/${configPath}?original=1', - '/${componentEntrypoint}', - ${JSON.stringify(ssrOutput) /* escape quotes */} - ); - `; - } finally { - config.requiredFeatureFlags?.forEach((featureFlag) => { - lwcSsr.setFeatureFlagForTest(featureFlag, false); - }); - } + return ` + import * as LWC from 'lwc'; + import { runTest } from '/configs/plugins/test-hydration.js'; + runTest( + '/${configPath}?original=1', + '/${componentEntrypoint}', + ${JSON.stringify(ssrOutput) /* escape quotes */} + ); + `; } /** @type {import('@web/dev-server-core').Plugin} */ From 9e4ac3eee66d79a4c27eeb1f4980ae1182a79752 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Thu, 9 Oct 2025 12:04:47 -0400 Subject: [PATCH 18/31] test(wtr): hack for nucleus --- packages/@lwc/integration-not-karma/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@lwc/integration-not-karma/package.json b/packages/@lwc/integration-not-karma/package.json index f5d51ab307..5e3cafd744 100644 --- a/packages/@lwc/integration-not-karma/package.json +++ b/packages/@lwc/integration-not-karma/package.json @@ -4,7 +4,7 @@ "version": "8.22.4", "type": "module", "scripts": { - "build": "playwright install", + "build": "playwright install || true", "start": "web-test-runner --manual", "test": "web-test-runner --config configs/integration.js", "test:hydration": "web-test-runner --config configs/hydration.js" From 465dd72d6548cbd0fd995109cc70f609f22ff148 Mon Sep 17 00:00:00 2001 From: Will Harney <62956339+wjhsf@users.noreply.github.com> Date: Tue, 14 Oct 2025 15:32:53 +0000 Subject: [PATCH 19/31] test(wtr): re-enable CTE tests @W-19098211 (#5535) * test(wtr): change from filename-based config to magic directive * test(wtr): actually use JSON * test(wtr): let spec file set config for whole dir * test(wtr): fix CTE tests --- .../configs/integration.js | 7 +--- .../configs/plugins/serve-integration.js | 40 +++++++++++-------- .../x/useApiVersion60/useApiVersion60.js | 3 +- .../x/light/chic.native-only.css | 2 + .../x/light/snazzy.native-only.scoped.css | 2 + .../x/shadow/chic.native-only.css | 2 + .../x/shadow/snazzy.native-only.scoped.css | 2 + .../x/styleLibrary/foo.native-only.css | 2 + .../template-expressions/errors/index.spec.js | 9 ++++- .../smoke-test/index.spec.js | 7 +++- 10 files changed, 49 insertions(+), 27 deletions(-) diff --git a/packages/@lwc/integration-not-karma/configs/integration.js b/packages/@lwc/integration-not-karma/configs/integration.js index 0ce6a84d5b..e0bbc1a342 100644 --- a/packages/@lwc/integration-not-karma/configs/integration.js +++ b/packages/@lwc/integration-not-karma/configs/integration.js @@ -13,12 +13,7 @@ const baseConfig = createConfig({ /** @type {import("@web/test-runner").TestRunnerConfig} */ export default { ...baseConfig, - files: [ - 'test/**/*.spec.js', - // Make John fix this after his PR is merged - '!test/template-expressions/errors/index.spec.js', - '!test/template-expressions/smoke-test/index.spec.js', - ], + files: ['test/**/*.spec.js'], plugins: [ ...baseConfig.plugins, importMapsPlugin({ inject: { importMap: { imports: { lwc: './mocks/lwc.js' } } } }), diff --git a/packages/@lwc/integration-not-karma/configs/plugins/serve-integration.js b/packages/@lwc/integration-not-karma/configs/plugins/serve-integration.js index 491b2fe688..91d7e8c240 100644 --- a/packages/@lwc/integration-not-karma/configs/plugins/serve-integration.js +++ b/packages/@lwc/integration-not-karma/configs/plugins/serve-integration.js @@ -40,30 +40,35 @@ const createRollupPlugin = (input, options) => { const transform = async (ctx) => { const input = ctx.path.slice(1); // strip leading / from URL path to get relative file path - const defaultRollupPlugin = createRollupPlugin(input); + // Override the LWC rollup plugin config on a per-file basis by searching for a comment + // directive /*!WTR {...}*/ and parsing the content as JSON. The spec file acts as a default + // location to update the config for every component file. + let rootConfig = {}; + const configDirective = /(?:\/\*|)/s; + const parseConfig = (src, id) => { + const configStr = src.match(configDirective)?.[1]; + if (!configStr) { + return rootConfig; // default config if no overrides found + } + const config = JSON.parse(configStr); + // id is full file path, input is relative to the package dir + if (id.endsWith(`/${input}`)) { + // this is the test entrypoint + rootConfig = config; + } + return config; + }; + const customLwcRollupPlugin = { ...defaultRollupPlugin, transform(src, id) { - let transform; + const { apiVersion, nativeOnly } = parseConfig(src, id); - // Override the LWC Rollup plugin to specify different options based on file name patterns. - // This allows us to alter the API version or other compiler props on a filename-only basis. - const apiVersion = id.match(/useApiVersion(\d+)/)?.[1]; - const nativeOnly = /\.native-only\./.test(id); + let transform; if (apiVersion) { - // The original Karma tests only ever had filename-based config for API version 60. - // Filename-based config is a pattern we want to move away from, so this transform - // only works for that version, so that we could simplify the logic here. - if (apiVersion !== '60') { - throw new Error( - 'TODO: fully implement or remove support for filename-based API version' - ); - } - transform = createRollupPlugin(input, { - apiVersion: 60, - }).transform; + transform = createRollupPlugin(input, { apiVersion }).transform; } else if (nativeOnly) { transform = createRollupPlugin(input, { disableSyntheticShadowSupport: true, @@ -71,6 +76,7 @@ const transform = async (ctx) => { } else { transform = defaultRollupPlugin.transform; } + return transform.call(this, src, id); }, }; diff --git a/packages/@lwc/integration-not-karma/test/mixed-api-version/x/useApiVersion60/useApiVersion60.js b/packages/@lwc/integration-not-karma/test/mixed-api-version/x/useApiVersion60/useApiVersion60.js index 9e2ab67e8f..0fd2bb4b23 100644 --- a/packages/@lwc/integration-not-karma/test/mixed-api-version/x/useApiVersion60/useApiVersion60.js +++ b/packages/@lwc/integration-not-karma/test/mixed-api-version/x/useApiVersion60/useApiVersion60.js @@ -1,4 +1,5 @@ +// Per-file compiler config, used in configs/plugins/serve-integration.js +/*!WTR {"apiVersion": 60}*/ import { LightningElement } from 'lwc'; -// By naming this component `useApiVersion60` we tell Karma's LWC Rollup plugin to compile it with API version 60 export default class extends LightningElement {} diff --git a/packages/@lwc/integration-not-karma/test/rendering/native-only-css/x/light/chic.native-only.css b/packages/@lwc/integration-not-karma/test/rendering/native-only-css/x/light/chic.native-only.css index 3f7b51fab0..c22f3baea4 100644 --- a/packages/@lwc/integration-not-karma/test/rendering/native-only-css/x/light/chic.native-only.css +++ b/packages/@lwc/integration-not-karma/test/rendering/native-only-css/x/light/chic.native-only.css @@ -1,3 +1,5 @@ +/* Per-file compiler config, used in configs/plugins/serve-integration.js */ +/*!WTR {"nativeOnly": true}*/ div { --chic: 'native'; } diff --git a/packages/@lwc/integration-not-karma/test/rendering/native-only-css/x/light/snazzy.native-only.scoped.css b/packages/@lwc/integration-not-karma/test/rendering/native-only-css/x/light/snazzy.native-only.scoped.css index 20e1bf49d9..13c0165120 100644 --- a/packages/@lwc/integration-not-karma/test/rendering/native-only-css/x/light/snazzy.native-only.scoped.css +++ b/packages/@lwc/integration-not-karma/test/rendering/native-only-css/x/light/snazzy.native-only.scoped.css @@ -1,3 +1,5 @@ +/* Per-file compiler config, used in configs/plugins/serve-integration.js */ +/*!WTR {"nativeOnly": true}*/ div { --snazzy: 'native'; } diff --git a/packages/@lwc/integration-not-karma/test/rendering/native-only-css/x/shadow/chic.native-only.css b/packages/@lwc/integration-not-karma/test/rendering/native-only-css/x/shadow/chic.native-only.css index 3f7b51fab0..c22f3baea4 100644 --- a/packages/@lwc/integration-not-karma/test/rendering/native-only-css/x/shadow/chic.native-only.css +++ b/packages/@lwc/integration-not-karma/test/rendering/native-only-css/x/shadow/chic.native-only.css @@ -1,3 +1,5 @@ +/* Per-file compiler config, used in configs/plugins/serve-integration.js */ +/*!WTR {"nativeOnly": true}*/ div { --chic: 'native'; } diff --git a/packages/@lwc/integration-not-karma/test/rendering/native-only-css/x/shadow/snazzy.native-only.scoped.css b/packages/@lwc/integration-not-karma/test/rendering/native-only-css/x/shadow/snazzy.native-only.scoped.css index 20e1bf49d9..13c0165120 100644 --- a/packages/@lwc/integration-not-karma/test/rendering/native-only-css/x/shadow/snazzy.native-only.scoped.css +++ b/packages/@lwc/integration-not-karma/test/rendering/native-only-css/x/shadow/snazzy.native-only.scoped.css @@ -1,3 +1,5 @@ +/* Per-file compiler config, used in configs/plugins/serve-integration.js */ +/*!WTR {"nativeOnly": true}*/ div { --snazzy: 'native'; } diff --git a/packages/@lwc/integration-not-karma/test/rendering/native-only-css/x/styleLibrary/foo.native-only.css b/packages/@lwc/integration-not-karma/test/rendering/native-only-css/x/styleLibrary/foo.native-only.css index f7ae70e9e7..a9700555b7 100644 --- a/packages/@lwc/integration-not-karma/test/rendering/native-only-css/x/styleLibrary/foo.native-only.css +++ b/packages/@lwc/integration-not-karma/test/rendering/native-only-css/x/styleLibrary/foo.native-only.css @@ -1,3 +1,5 @@ +/* Per-file compiler config, used in configs/plugins/serve-integration.js */ +/*!WTR {"nativeOnly": true}*/ div { --foo: 'native'; } diff --git a/packages/@lwc/integration-not-karma/test/template-expressions/errors/index.spec.js b/packages/@lwc/integration-not-karma/test/template-expressions/errors/index.spec.js index 77903150f0..ca2123e3ec 100644 --- a/packages/@lwc/integration-not-karma/test/template-expressions/errors/index.spec.js +++ b/packages/@lwc/integration-not-karma/test/template-expressions/errors/index.spec.js @@ -1,15 +1,20 @@ +// Per-file compiler config, used in configs/plugins/serve-integration.js +/*!WTR {"apiVersion": 66}*/ import { createElement } from 'lwc'; import UndefinedMemberExpressionObjParent from 'x/undefinedMemberExpressionObjParent'; import ThrowDuringCallParent from 'x/throwDuringCallParent'; +import { API_VERSION } from '../../../helpers/options'; -it(`should handle member expression with undefined object`, () => { +const cteEnabled = API_VERSION >= 66; + +it.runIf(cteEnabled)(`should handle member expression with undefined object`, () => { const parent = createElement('x-parent', { is: UndefinedMemberExpressionObjParent }); document.body.appendChild(parent); expect(parent.caughtError).toContain('undefined'); }); -it(`should handle errors thrown during call expression`, () => { +it.runIf(cteEnabled)(`should handle errors thrown during call expression`, () => { const parent = createElement('x-parent', { is: ThrowDuringCallParent }); document.body.appendChild(parent); expect(parent.caughtError).toContain("I'm the Gingerbread man!"); diff --git a/packages/@lwc/integration-not-karma/test/template-expressions/smoke-test/index.spec.js b/packages/@lwc/integration-not-karma/test/template-expressions/smoke-test/index.spec.js index 1c1d44a939..f03bea6cf2 100644 --- a/packages/@lwc/integration-not-karma/test/template-expressions/smoke-test/index.spec.js +++ b/packages/@lwc/integration-not-karma/test/template-expressions/smoke-test/index.spec.js @@ -1,8 +1,13 @@ +// Per-file compiler config, used in configs/plugins/serve-integration.js +/*!WTR {"apiVersion": 66}*/ import { createElement } from 'lwc'; import Test from 'x/test'; +import { API_VERSION } from '../../../helpers/options'; -it(`should support call expressions`, () => { +const cteEnabled = API_VERSION >= 66; + +it.runIf(cteEnabled)(`should support call expressions`, () => { const elm = createElement('x-test', { is: Test }); document.body.appendChild(elm); From 5c81592caebe46cbfa1ba0566fbffb105ba6c71b Mon Sep 17 00:00:00 2001 From: Will Harney Date: Wed, 15 Oct 2025 15:03:46 -0400 Subject: [PATCH 20/31] chore(ci): split hydration tests into engine-server and ssr-v2 --- .github/workflows/web-test-runner.yml | 134 ++++++++++++++++++++++++-- 1 file changed, 126 insertions(+), 8 deletions(-) diff --git a/.github/workflows/web-test-runner.yml b/.github/workflows/web-test-runner.yml index 3773362b64..9f310f73cd 100644 --- a/.github/workflows/web-test-runner.yml +++ b/.github/workflows/web-test-runner.yml @@ -42,6 +42,27 @@ jobs: node-version: ${{ env.NODE_VERSION }} cache: 'yarn' + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT + + - name: Cache yarn dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: Cache LWC build + uses: actions/cache@v4 + with: + key: ${{ runner.os }}-${{ github.sha }} + path: | + .nx-cache + packages/@lwc/*/dist + playground/dist + - name: Install dependencies run: yarn install --frozen-lockfile working-directory: ./ @@ -86,6 +107,27 @@ jobs: node-version: ${{ env.NODE_VERSION }} cache: 'yarn' + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT + + - name: Cache yarn dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: Cache LWC build + uses: actions/cache@v4 + with: + key: ${{ runner.os }}-${{ github.sha }} + path: | + .nx-cache + packages/@lwc/*/dist + playground/dist + - name: Install dependencies run: yarn install --frozen-lockfile working-directory: ./ @@ -108,10 +150,69 @@ jobs: - run: SHADOW_MODE_OVERRIDE=native DISABLE_SYNTHETIC_SHADOW_SUPPORT_IN_COMPILER=1 yarn test - run: SHADOW_MODE_OVERRIDE=native DISABLE_SYNTHETIC_SHADOW_SUPPORT_IN_COMPILER=1 DISABLE_STATIC_CONTENT_OPTIMIZATION=1 yarn test - hydration-tests: + hydration-tests-ssr-v2: + name: Hydration tests (SSR v2) + runs-on: ubuntu-22.04 + env: + SAUCE_TUNNEL_ID: github-action-tunnel-wtr-${{github.run_id}}-group-1 + defaults: + run: + working-directory: ./packages/@lwc/integration-not-karma + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: 'yarn' + + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT + + - name: Cache yarn dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: Cache LWC build + uses: actions/cache@v4 + with: + key: ${{ runner.os }}-${{ github.sha }} + path: | + .nx-cache + packages/@lwc/*/dist + playground/dist + + - name: Install dependencies + run: yarn install --frozen-lockfile + working-directory: ./ + + - uses: saucelabs/sauce-connect-action@v3.0.0 + with: + username: ${{ secrets.SAUCE_USERNAME }} + accessKey: ${{ secrets.SAUCE_ACCESS_KEY }} + tunnelName: ${{ env.SAUCE_TUNNEL_ID }} + region: us + + - run: yarn exec -- playwright install chrome firefox webkit --with-deps + - run: yarn test:hydration + - run: SHADOW_MODE_OVERRIDE=synthetic yarn test:hydration + - run: NODE_ENV_FOR_TEST=production yarn test:hydration + - run: DISABLE_NATIVE_CUSTOM_ELEMENT_LIFECYCLE=1 yarn test:hydration + - run: DISABLE_STATIC_CONTENT_OPTIMIZATION=1 yarn test:hydration + + hydration-tests-engine-server: + name: Hydration tests (engine-server) runs-on: ubuntu-22.04 env: SAUCE_TUNNEL_ID: github-action-tunnel-wtr-${{github.run_id}}-group-1 + ENGINE_SERVER: 1 defaults: run: working-directory: ./packages/@lwc/integration-not-karma @@ -125,6 +226,27 @@ jobs: node-version: ${{ env.NODE_VERSION }} cache: 'yarn' + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT + + - name: Cache yarn dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: Cache LWC build + uses: actions/cache@v4 + with: + key: ${{ runner.os }}-${{ github.sha }} + path: | + .nx-cache + packages/@lwc/*/dist + playground/dist + - name: Install dependencies run: yarn install --frozen-lockfile working-directory: ./ @@ -137,15 +259,11 @@ jobs: region: us - run: yarn exec -- playwright install chrome firefox webkit --with-deps - - run: ENGINE_SERVER=1 yarn test:hydration - - run: ENGINE_SERVER=1 SHADOW_MODE_OVERRIDE=synthetic yarn test:hydration - - run: ENGINE_SERVER=1 NODE_ENV_FOR_TEST=production yarn test:hydration - - run: ENGINE_SERVER=1 DISABLE_NATIVE_CUSTOM_ELEMENT_LIFECYCLE=1 yarn test:hydration - - run: ENGINE_SERVER=1 DISABLE_STATIC_CONTENT_OPTIMIZATION=1 yarn test:hydration - - run: ENGINE_SERVER=1 DISABLE_DETACHED_REHYDRATION=1 yarn test:hydration - - run: ENGINE_SERVER=1 DISABLE_NATIVE_CUSTOM_ELEMENT_LIFECYCLE=1 DISABLE_DETACHED_REHYDRATION=1 yarn test:hydration + # NOTE: All tests have ENGINE_SERVER=1 already set - run: yarn test:hydration - run: SHADOW_MODE_OVERRIDE=synthetic yarn test:hydration - run: NODE_ENV_FOR_TEST=production yarn test:hydration - run: DISABLE_NATIVE_CUSTOM_ELEMENT_LIFECYCLE=1 yarn test:hydration - run: DISABLE_STATIC_CONTENT_OPTIMIZATION=1 yarn test:hydration + - run: DISABLE_DETACHED_REHYDRATION=1 yarn test:hydration + - run: DISABLE_NATIVE_CUSTOM_ELEMENT_LIFECYCLE=1 DISABLE_DETACHED_REHYDRATION=1 yarn test:hydration From e92801797e96922811effca1b590c6d0695dd951 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Wed, 15 Oct 2025 15:10:58 -0400 Subject: [PATCH 21/31] chore(ci): split integration tests into two groups --- .github/workflows/web-test-runner.yml | 68 +++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/.github/workflows/web-test-runner.yml b/.github/workflows/web-test-runner.yml index 9f310f73cd..49c28ce256 100644 --- a/.github/workflows/web-test-runner.yml +++ b/.github/workflows/web-test-runner.yml @@ -18,6 +18,9 @@ env: NODE_VERSION: '20.19.4' jobs: + # We run tests in parallel to speed up CI, with an arbitrary goal of ~20 minutes per job. + # Test grouping is also somewhat arbitrary. + # TODO: upload result artifacts integration-tests: name: Integration tests (${{ matrix.shadow_mode }} shadow) @@ -76,16 +79,73 @@ jobs: - run: yarn exec -- playwright install chrome firefox webkit --with-deps - run: yarn test + - run: DISABLE_NATIVE_CUSTOM_ELEMENT_LIFECYCLE=1 yarn test || true + - run: DISABLE_STATIC_CONTENT_OPTIMIZATION=1 yarn test + - run: ENABLE_ARIA_REFLECTION_GLOBAL_POLYFILL=1 yarn test + - run: NODE_ENV_FOR_TEST=production yarn test + + integration-tests-api-versions: + name: Integration tests (${{ matrix.shadow_mode }} shadow) - API versions + strategy: + matrix: + shadow_mode: [native, synthetic] + + runs-on: ubuntu-22.04 + env: + SAUCE_TUNNEL_ID: github-action-tunnel-wtr-${{github.run_id}}-group-1 + SHADOW_MODE_OVERRIDE: ${{ matrix.shadow_mode }} + defaults: + run: + working-directory: ./packages/@lwc/integration-not-karma + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: 'yarn' + + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT + + - name: Cache yarn dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: Cache LWC build + uses: actions/cache@v4 + with: + key: ${{ runner.os }}-${{ github.sha }} + path: | + .nx-cache + packages/@lwc/*/dist + playground/dist + + - name: Install dependencies + run: yarn install --frozen-lockfile + working-directory: ./ + + - uses: saucelabs/sauce-connect-action@v3.0.0 + with: + username: ${{ secrets.SAUCE_USERNAME }} + accessKey: ${{ secrets.SAUCE_ACCESS_KEY }} + tunnelName: ${{ env.SAUCE_TUNNEL_ID }} + region: us + + - run: yarn exec -- playwright install chrome firefox webkit --with-deps - run: API_VERSION=58 yarn test - run: API_VERSION=59 yarn test - run: API_VERSION=60 yarn test - run: API_VERSION=61 yarn test - run: API_VERSION=62 yarn test - run: API_VERSION=66 yarn test - - run: DISABLE_NATIVE_CUSTOM_ELEMENT_LIFECYCLE=1 yarn test || true - - run: DISABLE_STATIC_CONTENT_OPTIMIZATION=1 yarn test - - run: ENABLE_ARIA_REFLECTION_GLOBAL_POLYFILL=1 yarn test - - run: NODE_ENV_FOR_TEST=production yarn test integration-tests-not-both-modes: # Tests that should run in only synthetic or native shadow, not both From f6ea8dea222d5170e0125874adb6b4c0ea3cf914 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Wed, 15 Oct 2025 16:49:32 -0400 Subject: [PATCH 22/31] chore(ci): build first and cache result so parallel jobs are faster --- .github/workflows/web-test-runner.yml | 64 ++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 11 deletions(-) diff --git a/.github/workflows/web-test-runner.yml b/.github/workflows/web-test-runner.yml index 49c28ce256..12d17f0009 100644 --- a/.github/workflows/web-test-runner.yml +++ b/.github/workflows/web-test-runner.yml @@ -20,10 +20,48 @@ env: jobs: # We run tests in parallel to speed up CI, with an arbitrary goal of ~20 minutes per job. # Test grouping is also somewhat arbitrary. - # TODO: upload result artifacts + + install-and-build: + runs-on: ubuntu-22.04 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: 'yarn' + + - name: Install dependencies + run: yarn install --frozen-lockfile + working-directory: ./ + + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT + + - name: Cache yarn dependencies + uses: actions/cache/save@v4 + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: Cache LWC build + uses: actions/cache/save@v4 + with: + key: ${{ runner.os }}-${{ github.sha }} + path: | + .nx-cache + packages/@lwc/*/dist + playground/dist + integration-tests: name: Integration tests (${{ matrix.shadow_mode }} shadow) + needs: install-and-build strategy: matrix: shadow_mode: [native, synthetic] @@ -50,7 +88,7 @@ jobs: run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT - name: Cache yarn dependencies - uses: actions/cache@v4 + uses: actions/cache/restore@v4 with: path: ${{ steps.yarn-cache-dir-path.outputs.dir }} key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} @@ -58,7 +96,7 @@ jobs: ${{ runner.os }}-yarn- - name: Cache LWC build - uses: actions/cache@v4 + uses: actions/cache/restore@v4 with: key: ${{ runner.os }}-${{ github.sha }} path: | @@ -86,6 +124,7 @@ jobs: integration-tests-api-versions: name: Integration tests (${{ matrix.shadow_mode }} shadow) - API versions + needs: install-and-build strategy: matrix: shadow_mode: [native, synthetic] @@ -112,7 +151,7 @@ jobs: run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT - name: Cache yarn dependencies - uses: actions/cache@v4 + uses: actions/cache/restore@v4 with: path: ${{ steps.yarn-cache-dir-path.outputs.dir }} key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} @@ -120,7 +159,7 @@ jobs: ${{ runner.os }}-yarn- - name: Cache LWC build - uses: actions/cache@v4 + uses: actions/cache/restore@v4 with: key: ${{ runner.os }}-${{ github.sha }} path: | @@ -150,6 +189,7 @@ jobs: integration-tests-not-both-modes: # Tests that should run in only synthetic or native shadow, not both name: Integration tests (singleton batch) + needs: install-and-build runs-on: ubuntu-22.04 env: SAUCE_TUNNEL_ID: github-action-tunnel-wtr-${{github.run_id}}-group-1 @@ -172,7 +212,7 @@ jobs: run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT - name: Cache yarn dependencies - uses: actions/cache@v4 + uses: actions/cache/restore@v4 with: path: ${{ steps.yarn-cache-dir-path.outputs.dir }} key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} @@ -180,7 +220,7 @@ jobs: ${{ runner.os }}-yarn- - name: Cache LWC build - uses: actions/cache@v4 + uses: actions/cache/restore@v4 with: key: ${{ runner.os }}-${{ github.sha }} path: | @@ -212,6 +252,7 @@ jobs: hydration-tests-ssr-v2: name: Hydration tests (SSR v2) + needs: install-and-build runs-on: ubuntu-22.04 env: SAUCE_TUNNEL_ID: github-action-tunnel-wtr-${{github.run_id}}-group-1 @@ -233,7 +274,7 @@ jobs: run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT - name: Cache yarn dependencies - uses: actions/cache@v4 + uses: actions/cache/restore@v4 with: path: ${{ steps.yarn-cache-dir-path.outputs.dir }} key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} @@ -241,7 +282,7 @@ jobs: ${{ runner.os }}-yarn- - name: Cache LWC build - uses: actions/cache@v4 + uses: actions/cache/restore@v4 with: key: ${{ runner.os }}-${{ github.sha }} path: | @@ -269,6 +310,7 @@ jobs: hydration-tests-engine-server: name: Hydration tests (engine-server) + needs: install-and-build runs-on: ubuntu-22.04 env: SAUCE_TUNNEL_ID: github-action-tunnel-wtr-${{github.run_id}}-group-1 @@ -291,7 +333,7 @@ jobs: run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT - name: Cache yarn dependencies - uses: actions/cache@v4 + uses: actions/cache/restore@v4 with: path: ${{ steps.yarn-cache-dir-path.outputs.dir }} key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} @@ -299,7 +341,7 @@ jobs: ${{ runner.os }}-yarn- - name: Cache LWC build - uses: actions/cache@v4 + uses: actions/cache/restore@v4 with: key: ${{ runner.os }}-${{ github.sha }} path: | From e83ec4e1bf00b9b368fb2f59d9d549786e6e9445 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Wed, 15 Oct 2025 17:07:03 -0400 Subject: [PATCH 23/31] test(wtr): check correct CI env var --- packages/@lwc/integration-not-karma/configs/shared/browsers.js | 2 +- packages/@lwc/integration-not-karma/helpers/options.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@lwc/integration-not-karma/configs/shared/browsers.js b/packages/@lwc/integration-not-karma/configs/shared/browsers.js index 220c458f42..c644cf91d7 100644 --- a/packages/@lwc/integration-not-karma/configs/shared/browsers.js +++ b/packages/@lwc/integration-not-karma/configs/shared/browsers.js @@ -3,7 +3,7 @@ import { createSauceLabsLauncher } from '@web/test-runner-saucelabs'; /** @type {(options: typeof import('../../helpers/options.js')) => import("@web/test-runner").BrowserLauncher[]} */ export function getBrowsers(options) { - if (options.IS_CI) { + if (options.CI) { if (!options.SAUCE_USERNAME || !options.SAUCE_ACCESS_KEY || !options.SAUCE_TUNNEL_ID) { throw new Error( `SAUCE_USERNAME, SAUCE_ACCESS_KEY, and SAUCE_TUNNEL_ID must be configured in CI` diff --git a/packages/@lwc/integration-not-karma/helpers/options.js b/packages/@lwc/integration-not-karma/helpers/options.js index 51a9dd99f8..0c687eb834 100644 --- a/packages/@lwc/integration-not-karma/helpers/options.js +++ b/packages/@lwc/integration-not-karma/helpers/options.js @@ -73,5 +73,5 @@ export const COVERAGE = Boolean(process.env.COVERAGE); export const SAUCE_USERNAME = process.env.SAUCE_USERNAME; export const SAUCE_ACCESS_KEY = process.env.SAUCE_ACCESS_KEY || process.env.SAUCE_KEY; export const SAUCE_TUNNEL_ID = process.env.SAUCE_TUNNEL_ID; -export const IS_CI = Boolean(process.env.IS_CI); +export const CI = Boolean(process.env.CI); export const GITHUB_RUN_ID = process.env.GITHUB_RUN_ID; From 02c820694e60c4100413c8ca1f7b33f05ff63cf9 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Wed, 15 Oct 2025 17:07:55 -0400 Subject: [PATCH 24/31] test(wtr): use concurrency in CI hopefully it doesn't break --- .../@lwc/integration-not-karma/configs/shared/base-config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@lwc/integration-not-karma/configs/shared/base-config.js b/packages/@lwc/integration-not-karma/configs/shared/base-config.js index a269499a85..b57ba602b5 100644 --- a/packages/@lwc/integration-not-karma/configs/shared/base-config.js +++ b/packages/@lwc/integration-not-karma/configs/shared/base-config.js @@ -43,7 +43,7 @@ export default (options) => { // FIXME: Parallelism breaks tests that rely on focus/requestAnimationFrame, because they often // time out before they receive focus. But it also makes the full suite take 3x longer to run... // Potential workaround: https://github.com/modernweb-dev/web/issues/2588 - concurrency: 1, + concurrency: options.CI ? 6 : 1, concurrentBrowsers: 3, nodeResolve: true, rootDir: join(import.meta.dirname, '../..'), From 8564becd764275c49776c852c3650b73dab32108 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Wed, 15 Oct 2025 17:09:02 -0400 Subject: [PATCH 25/31] test(wtr): always run browsers concurrently --- .../integration-not-karma/configs/shared/base-config.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/@lwc/integration-not-karma/configs/shared/base-config.js b/packages/@lwc/integration-not-karma/configs/shared/base-config.js index b57ba602b5..a0104a6ef2 100644 --- a/packages/@lwc/integration-not-karma/configs/shared/base-config.js +++ b/packages/@lwc/integration-not-karma/configs/shared/base-config.js @@ -37,14 +37,16 @@ export default (options) => { NODE_ENV: options.NODE_ENV_FOR_TEST, }); + const browsers = getBrowsers(options); + return { - browsers: getBrowsers(options), + browsers, browserLogs: false, // FIXME: Parallelism breaks tests that rely on focus/requestAnimationFrame, because they often // time out before they receive focus. But it also makes the full suite take 3x longer to run... // Potential workaround: https://github.com/modernweb-dev/web/issues/2588 concurrency: options.CI ? 6 : 1, - concurrentBrowsers: 3, + concurrentBrowsers: browsers.length, nodeResolve: true, rootDir: join(import.meta.dirname, '../..'), plugins: [ From e1288ce587b6197f098610323314d4d976ee6751 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Wed, 15 Oct 2025 17:28:29 -0400 Subject: [PATCH 26/31] chore(ci): give up on caching (for now?) not working as intended; may fix later --- .github/workflows/web-test-runner.yml | 142 -------------------------- 1 file changed, 142 deletions(-) diff --git a/.github/workflows/web-test-runner.yml b/.github/workflows/web-test-runner.yml index 12d17f0009..3ef3bffd0b 100644 --- a/.github/workflows/web-test-runner.yml +++ b/.github/workflows/web-test-runner.yml @@ -22,43 +22,6 @@ jobs: # Test grouping is also somewhat arbitrary. # TODO: upload result artifacts - install-and-build: - runs-on: ubuntu-22.04 - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup Node - uses: actions/setup-node@v4 - with: - node-version: ${{ env.NODE_VERSION }} - cache: 'yarn' - - - name: Install dependencies - run: yarn install --frozen-lockfile - working-directory: ./ - - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT - - - name: Cache yarn dependencies - uses: actions/cache/save@v4 - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - - - name: Cache LWC build - uses: actions/cache/save@v4 - with: - key: ${{ runner.os }}-${{ github.sha }} - path: | - .nx-cache - packages/@lwc/*/dist - playground/dist - integration-tests: name: Integration tests (${{ matrix.shadow_mode }} shadow) needs: install-and-build @@ -83,27 +46,6 @@ jobs: node-version: ${{ env.NODE_VERSION }} cache: 'yarn' - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT - - - name: Cache yarn dependencies - uses: actions/cache/restore@v4 - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - - - name: Cache LWC build - uses: actions/cache/restore@v4 - with: - key: ${{ runner.os }}-${{ github.sha }} - path: | - .nx-cache - packages/@lwc/*/dist - playground/dist - - name: Install dependencies run: yarn install --frozen-lockfile working-directory: ./ @@ -146,27 +88,6 @@ jobs: node-version: ${{ env.NODE_VERSION }} cache: 'yarn' - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT - - - name: Cache yarn dependencies - uses: actions/cache/restore@v4 - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - - - name: Cache LWC build - uses: actions/cache/restore@v4 - with: - key: ${{ runner.os }}-${{ github.sha }} - path: | - .nx-cache - packages/@lwc/*/dist - playground/dist - - name: Install dependencies run: yarn install --frozen-lockfile working-directory: ./ @@ -207,27 +128,6 @@ jobs: node-version: ${{ env.NODE_VERSION }} cache: 'yarn' - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT - - - name: Cache yarn dependencies - uses: actions/cache/restore@v4 - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - - - name: Cache LWC build - uses: actions/cache/restore@v4 - with: - key: ${{ runner.os }}-${{ github.sha }} - path: | - .nx-cache - packages/@lwc/*/dist - playground/dist - - name: Install dependencies run: yarn install --frozen-lockfile working-directory: ./ @@ -269,27 +169,6 @@ jobs: node-version: ${{ env.NODE_VERSION }} cache: 'yarn' - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT - - - name: Cache yarn dependencies - uses: actions/cache/restore@v4 - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - - - name: Cache LWC build - uses: actions/cache/restore@v4 - with: - key: ${{ runner.os }}-${{ github.sha }} - path: | - .nx-cache - packages/@lwc/*/dist - playground/dist - - name: Install dependencies run: yarn install --frozen-lockfile working-directory: ./ @@ -328,27 +207,6 @@ jobs: node-version: ${{ env.NODE_VERSION }} cache: 'yarn' - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT - - - name: Cache yarn dependencies - uses: actions/cache/restore@v4 - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - - - name: Cache LWC build - uses: actions/cache/restore@v4 - with: - key: ${{ runner.os }}-${{ github.sha }} - path: | - .nx-cache - packages/@lwc/*/dist - playground/dist - - name: Install dependencies run: yarn install --frozen-lockfile working-directory: ./ From b1fef23f0bbc3fe11e77dc456bc7fc6524573361 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Wed, 15 Oct 2025 17:50:45 -0400 Subject: [PATCH 27/31] test(wtr): try difference sauce config --- packages/@lwc/integration-not-karma/configs/shared/browsers.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/@lwc/integration-not-karma/configs/shared/browsers.js b/packages/@lwc/integration-not-karma/configs/shared/browsers.js index c644cf91d7..99792e853b 100644 --- a/packages/@lwc/integration-not-karma/configs/shared/browsers.js +++ b/packages/@lwc/integration-not-karma/configs/shared/browsers.js @@ -30,7 +30,6 @@ export function getBrowsers(options) { sauceLabsLauncher({ browserName: 'safari', browserVersion: 'latest', - platformName: 'macOS 15', // Update this with new Mac releases }), ...(options.LEGACY_BROWSERS ? [ @@ -41,7 +40,7 @@ export function getBrowsers(options) { sauceLabsLauncher({ browserName: 'safari', browserVersion: 'latest-2', - platformName: 'macOS 13', // Should be 2 behind latest + platformName: 'Mac 13', // update with new releases }), ] : []), From 2aa45e1c40b9839e66b489927f2a1a6e5e3e67b5 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Wed, 15 Oct 2025 17:55:06 -0400 Subject: [PATCH 28/31] chore(ci): don't needs: install-and-build it got deleted oops --- .github/workflows/web-test-runner.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/web-test-runner.yml b/.github/workflows/web-test-runner.yml index 3ef3bffd0b..8cc7740d0f 100644 --- a/.github/workflows/web-test-runner.yml +++ b/.github/workflows/web-test-runner.yml @@ -24,7 +24,6 @@ jobs: integration-tests: name: Integration tests (${{ matrix.shadow_mode }} shadow) - needs: install-and-build strategy: matrix: shadow_mode: [native, synthetic] @@ -66,7 +65,6 @@ jobs: integration-tests-api-versions: name: Integration tests (${{ matrix.shadow_mode }} shadow) - API versions - needs: install-and-build strategy: matrix: shadow_mode: [native, synthetic] @@ -110,7 +108,6 @@ jobs: integration-tests-not-both-modes: # Tests that should run in only synthetic or native shadow, not both name: Integration tests (singleton batch) - needs: install-and-build runs-on: ubuntu-22.04 env: SAUCE_TUNNEL_ID: github-action-tunnel-wtr-${{github.run_id}}-group-1 @@ -152,7 +149,6 @@ jobs: hydration-tests-ssr-v2: name: Hydration tests (SSR v2) - needs: install-and-build runs-on: ubuntu-22.04 env: SAUCE_TUNNEL_ID: github-action-tunnel-wtr-${{github.run_id}}-group-1 @@ -189,7 +185,6 @@ jobs: hydration-tests-engine-server: name: Hydration tests (engine-server) - needs: install-and-build runs-on: ubuntu-22.04 env: SAUCE_TUNNEL_ID: github-action-tunnel-wtr-${{github.run_id}}-group-1 From 9d59c9a584e873f88452d65b87c5f88fe371e2c8 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Thu, 16 Oct 2025 12:58:11 -0400 Subject: [PATCH 29/31] chore(ci): use distinct tunnel IDs for SauceLabs --- .github/workflows/web-test-runner.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/web-test-runner.yml b/.github/workflows/web-test-runner.yml index 8cc7740d0f..7c6eb8186a 100644 --- a/.github/workflows/web-test-runner.yml +++ b/.github/workflows/web-test-runner.yml @@ -30,7 +30,7 @@ jobs: runs-on: ubuntu-22.04 env: - SAUCE_TUNNEL_ID: github-action-tunnel-wtr-${{github.run_id}}-group-1 + SAUCE_TUNNEL_ID: github-actions-wtr-${{github.run_id}}-integration-1 SHADOW_MODE_OVERRIDE: ${{ matrix.shadow_mode }} defaults: run: @@ -71,7 +71,7 @@ jobs: runs-on: ubuntu-22.04 env: - SAUCE_TUNNEL_ID: github-action-tunnel-wtr-${{github.run_id}}-group-1 + SAUCE_TUNNEL_ID: github-actions-wtr-${{github.run_id}}-integration-2 SHADOW_MODE_OVERRIDE: ${{ matrix.shadow_mode }} defaults: run: @@ -110,7 +110,7 @@ jobs: name: Integration tests (singleton batch) runs-on: ubuntu-22.04 env: - SAUCE_TUNNEL_ID: github-action-tunnel-wtr-${{github.run_id}}-group-1 + SAUCE_TUNNEL_ID: github-actions-wtr-${{github.run_id}}-integration-3 SHADOW_MODE_OVERRIDE: ${{ matrix.shadow_mode }} defaults: run: @@ -151,7 +151,7 @@ jobs: name: Hydration tests (SSR v2) runs-on: ubuntu-22.04 env: - SAUCE_TUNNEL_ID: github-action-tunnel-wtr-${{github.run_id}}-group-1 + SAUCE_TUNNEL_ID: github-actions-wtr-${{github.run_id}}-hydration-1 defaults: run: working-directory: ./packages/@lwc/integration-not-karma @@ -187,7 +187,7 @@ jobs: name: Hydration tests (engine-server) runs-on: ubuntu-22.04 env: - SAUCE_TUNNEL_ID: github-action-tunnel-wtr-${{github.run_id}}-group-1 + SAUCE_TUNNEL_ID: github-actions-wtr-${{github.run_id}}-hydration-2 ENGINE_SERVER: 1 defaults: run: From 45d38dad6c9c82154adbdd5b30f9e46e11f7a5f4 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Thu, 16 Oct 2025 13:18:16 -0400 Subject: [PATCH 30/31] test(wtr): revert concurrency in CI --- .../@lwc/integration-not-karma/configs/shared/base-config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@lwc/integration-not-karma/configs/shared/base-config.js b/packages/@lwc/integration-not-karma/configs/shared/base-config.js index a0104a6ef2..e8b546490a 100644 --- a/packages/@lwc/integration-not-karma/configs/shared/base-config.js +++ b/packages/@lwc/integration-not-karma/configs/shared/base-config.js @@ -45,7 +45,7 @@ export default (options) => { // FIXME: Parallelism breaks tests that rely on focus/requestAnimationFrame, because they often // time out before they receive focus. But it also makes the full suite take 3x longer to run... // Potential workaround: https://github.com/modernweb-dev/web/issues/2588 - concurrency: options.CI ? 6 : 1, + concurrency: 1, concurrentBrowsers: browsers.length, nodeResolve: true, rootDir: join(import.meta.dirname, '../..'), From 199412f5ae323115461b7cd87d00f0135bbb5243 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Thu, 16 Oct 2025 13:49:37 -0400 Subject: [PATCH 31/31] test(wtr): disable tests that sauce doesn't like --- .github/workflows/web-test-runner.yml | 2 +- packages/@lwc/integration-not-karma/configs/hydration.js | 2 +- packages/@lwc/integration-not-karma/configs/integration.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/web-test-runner.yml b/.github/workflows/web-test-runner.yml index 7c6eb8186a..74a5866ba1 100644 --- a/.github/workflows/web-test-runner.yml +++ b/.github/workflows/web-test-runner.yml @@ -1,4 +1,4 @@ -name: Run Web Test Runner integration tests +name: Web Test Runner on: push: diff --git a/packages/@lwc/integration-not-karma/configs/hydration.js b/packages/@lwc/integration-not-karma/configs/hydration.js index a03f370cf4..38aa6effe9 100644 --- a/packages/@lwc/integration-not-karma/configs/hydration.js +++ b/packages/@lwc/integration-not-karma/configs/hydration.js @@ -12,6 +12,6 @@ const baseConfig = createConfig({ /** @type {import("@web/test-runner").TestRunnerConfig} */ export default { ...baseConfig, - files: ['test-hydration/**/*.spec.js'], + files: ['test-hydration/**/*.spec.js', '!test-hydration/synthetic-shadow/index.spec.js'], plugins: [...baseConfig.plugins, hydrationTestPlugin], }; diff --git a/packages/@lwc/integration-not-karma/configs/integration.js b/packages/@lwc/integration-not-karma/configs/integration.js index e0bbc1a342..162e19cbcc 100644 --- a/packages/@lwc/integration-not-karma/configs/integration.js +++ b/packages/@lwc/integration-not-karma/configs/integration.js @@ -13,7 +13,7 @@ const baseConfig = createConfig({ /** @type {import("@web/test-runner").TestRunnerConfig} */ export default { ...baseConfig, - files: ['test/**/*.spec.js'], + files: ['test/**/*.spec.js', '!test/custom-elements/index.spec.js'], plugins: [ ...baseConfig.plugins, importMapsPlugin({ inject: { importMap: { imports: { lwc: './mocks/lwc.js' } } } }),