From 8e9564a2404e9cf3eddbe5618c1c2c1df4621d6c Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Sun, 19 May 2024 11:32:45 +0300 Subject: [PATCH 01/83] fix(core)!: remove side effects from core import Removes `window.PfeConfig` and auto-reveal features Adds server checks to `createContextWithRoot` --- core/pfe-core/core.ts | 62 ------------------------------ core/pfe-core/decorators/time.ts | 15 +++----- core/pfe-core/functions/context.ts | 5 ++- 3 files changed, 9 insertions(+), 73 deletions(-) diff --git a/core/pfe-core/core.ts b/core/pfe-core/core.ts index 55519b5c93..21a3da623a 100644 --- a/core/pfe-core/core.ts +++ b/core/pfe-core/core.ts @@ -1,38 +1,9 @@ import type { ComplexAttributeConverter } from 'lit'; -/** PatternFly Elements global config object */ -export interface PfeConfig { - /** Set to false to disable client-side page load performance tracking */ - trackPerformance?: boolean; - /** Set to false to disable various debug logs */ - log?: boolean; - /** Set to false to disable automatically removing `unresolved` attr from body */ - autoReveal?: boolean; -} - export type RequireProps = T & { [P in Ps]-?: T[P]; }; -const noPref = Symbol(); - -/** Retrieve an HTML metadata item */ -function getMeta(name: string): string | undefined { - return document.head.querySelector(`meta[name="${name}"]`)?.content; -} - -/** - * A boolean value that indicates if the performance should be tracked. - * For use in a JS file or script tag; can also be added in the constructor of a component during development. - * @example trackPerformance(true); - */ -export function trackPerformance(preference: boolean | typeof noPref = noPref) { - if (preference !== noPref) { - window.PfeConfig.trackPerformance = !!preference; - } - return window.PfeConfig.trackPerformance; -} - function makeConverter( f: (x: string, type?: unknown) => T, ): ComplexAttributeConverter { @@ -78,36 +49,3 @@ export class ComposedEvent extends Event { } } -// 👇 SIDE EFFECTS 👇 - -declare global { - interface Window { - /** Global configuration settings for PatternFly Elements */ - PfeConfig: PfeConfig; - } -} - -const bodyNoAutoReveal = document.body.hasAttribute('no-auto-reveal'); - -/** Global patternfly elements config */ -window.PfeConfig = Object.assign(window.PfeConfig ?? {}, { - trackPerformance: window.PfeConfig?.trackPerformance - ?? getMeta('pf-track-performance') === 'true', - // if the body tag has `no-auto-reveal` attribute, reveal immediately - // if `` exists, and it's `content` is 'true', - // then auto-reveal the body - autoReveal: window.PfeConfig?.autoReveal ?? ( - bodyNoAutoReveal ? !bodyNoAutoReveal - : getMeta('pf-auto-reveal') === 'true' - ), - get log() { - return !!localStorage.pfeLog; - }, - set log(v: boolean) { - if (v) { - localStorage.setItem('pfeLog', `${true}`); - } else { - localStorage.removeItem('pfeLog'); - } - }, -}); diff --git a/core/pfe-core/decorators/time.ts b/core/pfe-core/decorators/time.ts index dca0b4ae31..aa0f964a8f 100644 --- a/core/pfe-core/decorators/time.ts +++ b/core/pfe-core/decorators/time.ts @@ -1,5 +1,6 @@ /** * Tracks the time a method takes to complete using the [performance API](https://developer.mozilla.org/en-US/docs/Web/API/Performance) + * @param tag - short string to identify the method name */ export function time(tag?: string) { return function(_: unknown, key: string, descriptor: PropertyDescriptor) { @@ -14,19 +15,15 @@ export function time(tag?: string) { const START_TAG = `start-${TAG}`; const END_TAG = `end-${TAG}`; - if (window.PfeConfig.trackPerformance) { - performance.mark(START_TAG); - } + performance.mark(START_TAG); const x = f.call(this, ...args); const ret = () => { - if (window.PfeConfig.trackPerformance) { - performance.mark(END_TAG); - performance.measure(TAG, START_TAG, END_TAG); - // eslint-disable-next-line no-console - console.log(Array.from(performance.getEntriesByName(TAG)).pop()); - } + performance.mark(END_TAG); + performance.measure(TAG, START_TAG, END_TAG); + // eslint-disable-next-line no-console + console.log(Array.from(performance.getEntriesByName(TAG)).pop()); return x; }; diff --git a/core/pfe-core/functions/context.ts b/core/pfe-core/functions/context.ts index ec97e4bcfb..baa8a1aeee 100644 --- a/core/pfe-core/functions/context.ts +++ b/core/pfe-core/functions/context.ts @@ -1,10 +1,11 @@ import { ContextRoot, createContext } from '@lit/context'; +import { isServer } from 'lit'; let root: ContextRoot; function makeContextRoot() { - root = new ContextRoot(); - root.attach(document.body); + const root = new ContextRoot(); + !isServer && root.attach(document.body); return root; } From 79fa98793ea849f900c6c33ffbe1dfa806059976 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Sun, 19 May 2024 16:01:41 +0300 Subject: [PATCH 02/83] feat(tools): ssr test page --- package-lock.json | 178 ++++++++++++++++++++- playwright.ssr.config.ts | 12 ++ tools/pfe-tools/package.json | 2 + tools/pfe-tools/test/playwright/SSRPage.ts | 60 +++++++ tools/pfe-tools/test/ssr/global.ts | 10 ++ tools/pfe-tools/test/ssr/shims.ts | 30 ++++ tools/pfe-tools/test/ssr/ssr.ts | 10 ++ 7 files changed, 299 insertions(+), 3 deletions(-) create mode 100644 playwright.ssr.config.ts create mode 100644 tools/pfe-tools/test/playwright/SSRPage.ts create mode 100644 tools/pfe-tools/test/ssr/global.ts create mode 100644 tools/pfe-tools/test/ssr/shims.ts create mode 100644 tools/pfe-tools/test/ssr/ssr.ts diff --git a/package-lock.json b/package-lock.json index aad4a80bde..d442002077 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2403,11 +2403,58 @@ "node": ">= 12" } }, + "node_modules/@lit-labs/ssr": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr/-/ssr-3.2.2.tgz", + "integrity": "sha512-He5TzeNPM9ECmVpgXRYmVlz0UA5YnzHlT43kyLi2Lu6mUidskqJVonk9W5K699+2DKhoXp8Ra4EJmHR6KrcW1Q==", + "dependencies": { + "@lit-labs/ssr-client": "^1.1.7", + "@lit-labs/ssr-dom-shim": "^1.2.0", + "@lit/reactive-element": "^2.0.4", + "@parse5/tools": "^0.3.0", + "@types/node": "^16.0.0", + "enhanced-resolve": "^5.10.0", + "lit": "^3.1.2", + "lit-element": "^4.0.4", + "lit-html": "^3.1.2", + "node-fetch": "^3.2.8", + "parse5": "^7.1.1" + }, + "engines": { + "node": ">=13.9.0" + } + }, + "node_modules/@lit-labs/ssr-client": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-client/-/ssr-client-1.1.7.tgz", + "integrity": "sha512-VvqhY/iif3FHrlhkzEPsuX/7h/NqnfxLwVf0p8ghNIlKegRyRqgeaJevZ57s/u/LiFyKgqksRP5n+LmNvpxN+A==", + "dependencies": { + "@lit/reactive-element": "^2.0.4", + "lit": "^3.1.2", + "lit-html": "^3.1.2" + } + }, "node_modules/@lit-labs/ssr-dom-shim": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.2.0.tgz", "integrity": "sha512-yWJKmpGE6lUURKAaIltoPIE/wrbY3TEkqQt+X0m+7fQNnAv0keydnYvbiJFP1PnMhizmIWRWOG5KLhYyc/xl+g==" }, + "node_modules/@lit-labs/ssr/node_modules/@types/node": { + "version": "16.18.97", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.97.tgz", + "integrity": "sha512-4muilE1Lbfn57unR+/nT9AFjWk0MtWi5muwCEJqnOvfRQDbSfLCUdN7vCIg8TYuaANfhLOV85ve+FNpiUsbSRg==" + }, + "node_modules/@lit-labs/ssr/node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/@lit/context": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@lit/context/-/context-1.1.0.tgz", @@ -2774,6 +2821,25 @@ "lit-html": "^2.0.0 || ^3.0.0" } }, + "node_modules/@parse5/tools": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@parse5/tools/-/tools-0.3.0.tgz", + "integrity": "sha512-zxRyTHkqb7WQMV8kTNBKWb1BeOFUKXBXTBWuxg9H9hfvQB3IwP6Iw2U75Ia5eyRxPNltmY7E8YAlz6zWwUnjKg==", + "dependencies": { + "parse5": "^7.0.0" + } + }, + "node_modules/@parse5/tools/node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/@patternfly/create-element": { "resolved": "tools/create-element", "link": true @@ -7216,6 +7282,18 @@ "once": "^1.4.0" } }, + "node_modules/enhanced-resolve": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.1.tgz", + "integrity": "sha512-4U5pNsuDl0EhuZpq46M5xPslstkviJuhrdobaRDBk2Jy2KO37FDAJl4lb2KlNabxT0m4MTK2UHNrsAcphE8nyw==", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/enquirer": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", @@ -8415,6 +8493,28 @@ "pend": "~1.2.0" } }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -8587,6 +8687,17 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -10445,9 +10556,9 @@ "dev": true }, "node_modules/koa": { - "version": "2.15.2", - "resolved": "https://registry.npmjs.org/koa/-/koa-2.15.2.tgz", - "integrity": "sha512-MXTeZH3M6AJ8ukW2QZ8wqO3Dcdfh2WRRmjCBkEP+NhKNCiqlO5RDqHmSnsyNrbRJrdjyvIGSJho4vQiWgQJSVA==", + "version": "2.15.3", + "resolved": "https://registry.npmjs.org/koa/-/koa-2.15.3.tgz", + "integrity": "sha512-j/8tY9j5t+GVMLeioLaxweJiKUayFhlGqNTzf2ZGwL0ZCQijd2RLHK0SLW5Tsko8YyyqCZC2cojIb0/s62qTAg==", "dependencies": { "accepts": "^1.3.5", "cache-content-type": "^1.0.0", @@ -11861,6 +11972,49 @@ "lower-case": "^1.1.1" } }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/node-fetch/node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "engines": { + "node": ">= 12" + } + }, "node_modules/node-releases": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", @@ -15937,6 +16091,14 @@ "node": ">=8" } }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "engines": { + "node": ">=6" + } + }, "node_modules/tar": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", @@ -16808,6 +16970,14 @@ "@rollup/pluginutils": "^5.1.0" } }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "engines": { + "node": ">= 8" + } + }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -17291,6 +17461,7 @@ "@custom-elements-manifest/analyzer": "^0.5.7", "@jspm/generator": "^2.0.1", "@koa/router": "^12.0.1", + "@lit-labs/ssr": "^3.2.2", "@open-wc/testing": "^4.0.0", "@playwright/test": "^1.43.0", "@rollup/plugin-replace": "^5.0.5", @@ -17330,6 +17501,7 @@ "execa": "^8.0.1", "glob": "^10.3.12", "html-include-element": "^0.3.0", + "koa": "^2.15.3", "koa-send": "^5.0.1", "lit": "^3.1.2", "markdown-it-anchor": "^8.6.7", diff --git a/playwright.ssr.config.ts b/playwright.ssr.config.ts new file mode 100644 index 0000000000..4bd3092f34 --- /dev/null +++ b/playwright.ssr.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from '@playwright/test'; + +export default defineConfig({ + testMatch: '**/test/*.ssr.ts', + testIgnore: /node_modules|_site|create-element\/templates/, + timeout: 120 * 1000, + workers: process.env.CI ? 2 : 8, + use: { + viewport: { width: 1920, height: 1080 }, + }, +}); + diff --git a/tools/pfe-tools/package.json b/tools/pfe-tools/package.json index 35474b8b04..6e70a1928d 100644 --- a/tools/pfe-tools/package.json +++ b/tools/pfe-tools/package.json @@ -66,6 +66,7 @@ "@custom-elements-manifest/analyzer": "^0.5.7", "@jspm/generator": "^2.0.1", "@koa/router": "^12.0.1", + "@lit-labs/ssr": "^3.2.2", "@open-wc/testing": "^4.0.0", "@playwright/test": "^1.43.0", "@rollup/plugin-replace": "^5.0.5", @@ -105,6 +106,7 @@ "execa": "^8.0.1", "glob": "^10.3.12", "html-include-element": "^0.3.0", + "koa": "^2.15.3", "koa-send": "^5.0.1", "lit": "^3.1.2", "markdown-it-anchor": "^8.6.7", diff --git a/tools/pfe-tools/test/playwright/SSRPage.ts b/tools/pfe-tools/test/playwright/SSRPage.ts new file mode 100644 index 0000000000..2ca4cc8d7c --- /dev/null +++ b/tools/pfe-tools/test/playwright/SSRPage.ts @@ -0,0 +1,60 @@ +import { expect } from '@playwright/test'; +import { readFile } from 'node:fs/promises'; +import { renderGlobal } from '../ssr/global.js'; + +import Koa from 'koa'; + +import type { Page } from '@playwright/test'; +import type { Server } from 'node:http'; +import type { AddressInfo } from 'node:net'; + +interface SSRDemoConfig { + demoURL: URL; + importSpecifiers: string[]; +} + +export class SSRPage { + private app: Koa; + private server!: Server; + private host!: string; + + constructor( + public tagName: string, + public page: Page, + private config: SSRDemoConfig, + ) { + this.app = new Koa(); + } + + private async serve() { + const html = await readFile(this.config.demoURL, 'utf-8'); + this.app.use(async ctx => { + ctx.type = 'text/html'; + ctx.response.body = await renderGlobal(html, this.config.importSpecifiers); + }); + this.server = this.app.listen(0); + while (!this.server.listening) { + await new Promise(r => setTimeout(r)); + } + const { address = 'localhost', port = 0 } = this.server.address() as AddressInfo; + this.host = `http://${address.replace('::', 'localhost')}:${port}/`; + } + + private async close() { + await new Promise((res, rej) => + !this.server ? rej('no server') : this.server?.close(e => e ? rej(e) : res())); + } + + /** Take a snapshot and save it to disk */ + async snapshot() { + try { + await this.serve(); + const path = new URL(new URL(this.config.demoURL).pathname, this.host); + const response = await this.page.goto(path.toString(), { waitUntil: 'load' }); + expect(response?.status(), { message: response?.statusText() }).toEqual(200); + expect(await this.page.screenshot({ fullPage: true })).toMatchSnapshot(`${this.tagName}.png`); + } finally { + await this.close(); + } + } +} diff --git a/tools/pfe-tools/test/ssr/global.ts b/tools/pfe-tools/test/ssr/global.ts new file mode 100644 index 0000000000..6166aaff1f --- /dev/null +++ b/tools/pfe-tools/test/ssr/global.ts @@ -0,0 +1,10 @@ +export async function renderGlobal( + html: string, + importSpecifiers: string[], +) { + await import('./shims.js'); + const { ssr } = await import('./ssr.js'); + await Promise.all(importSpecifiers.map(x => import(x))); + return ssr(html); +} + diff --git a/tools/pfe-tools/test/ssr/shims.ts b/tools/pfe-tools/test/ssr/shims.ts new file mode 100644 index 0000000000..b9baad8bb8 --- /dev/null +++ b/tools/pfe-tools/test/ssr/shims.ts @@ -0,0 +1,30 @@ +class ObserverShim { + observe() { + void 0; + } + + disconnect() { + void 0; + } +} + +// @ts-expect-error: i'm shimmin' here! +globalThis.window ??= globalThis; +// @ts-expect-error: i'm shimmin' here! +globalThis.ErrorEvent ??= Event; +// @ts-expect-error: i'm shimmin' here! +globalThis.IntersectionObserver ??= ObserverShim; +// @ts-expect-error: i'm shimmin' here! +globalThis.MutationObserver ??= ObserverShim; +// @ts-expect-error: i'm shimmin' here! +globalThis.getComputedStyle ??= function() { + return { + getPropertyPriority() { + return ''; + }, + getPropertyValue() { + return ''; + }, + }; +}; + diff --git a/tools/pfe-tools/test/ssr/ssr.ts b/tools/pfe-tools/test/ssr/ssr.ts new file mode 100644 index 0000000000..27c613dc5a --- /dev/null +++ b/tools/pfe-tools/test/ssr/ssr.ts @@ -0,0 +1,10 @@ +import { render } from '@lit-labs/ssr'; +import { collectResult } from '@lit-labs/ssr/lib/render-result.js'; +import { html } from 'lit'; +import { unsafeHTML } from 'lit/directives/unsafe-html.js'; + +export async function ssr(input: string) { + return collectResult(render(html`${unsafeHTML(input)}`)); +} + + From 3850511ded894a78ec293216c3ebbefeb28cba6f Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Sun, 19 May 2024 16:01:54 +0300 Subject: [PATCH 03/83] test(accordion): ssr tests --- elements/pf-accordion/test/pf-accordion.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-accordion/test/pf-accordion.e2e.ts b/elements/pf-accordion/test/pf-accordion.e2e.ts index 1fcec84cf6..82f3720c13 100644 --- a/elements/pf-accordion/test/pf-accordion.e2e.ts +++ b/elements/pf-accordion/test/pf-accordion.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-accordion'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From 06d61d7dc7993b1a6efe76a71697abfb2f9b65b8 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Sun, 19 May 2024 16:03:57 +0300 Subject: [PATCH 04/83] test(avatar): ssr tests --- elements/pf-avatar/test/pf-avatar.e2e.ts | 13 +++++++++++++ elements/pf-avatar/test/pf-avatar.ssr.ts | 16 ++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 elements/pf-avatar/test/pf-avatar.ssr.ts diff --git a/elements/pf-avatar/test/pf-avatar.e2e.ts b/elements/pf-avatar/test/pf-avatar.e2e.ts index 17c15158a4..9ab4c74237 100644 --- a/elements/pf-avatar/test/pf-avatar.e2e.ts +++ b/elements/pf-avatar/test/pf-avatar.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-avatar'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); diff --git a/elements/pf-avatar/test/pf-avatar.ssr.ts b/elements/pf-avatar/test/pf-avatar.ssr.ts new file mode 100644 index 0000000000..1327655c9f --- /dev/null +++ b/elements/pf-avatar/test/pf-avatar.ssr.ts @@ -0,0 +1,16 @@ +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; +import { test } from '@playwright/test'; + +const tagName = 'pf-avatar'; + +test.describe(tagName, () => { + test('ssr', async ({ page }) => { + const fixture = new SSRPage(tagName, page, { + demoURL: new URL('../demo/ssr.html', import.meta.url), + importSpecifiers: [ + '@patternfly/elements/pf-avatar/pf-avatar.js', + ], + }); + await fixture.snapshot(); + }); +}); From 9a001c633dc0e66c1572821531dae361158d40d4 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Sun, 19 May 2024 16:05:00 +0300 Subject: [PATCH 05/83] test(back-to-top): ssr --- elements/pf-back-to-top/test/pf-back-to-top.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-back-to-top/test/pf-back-to-top.e2e.ts b/elements/pf-back-to-top/test/pf-back-to-top.e2e.ts index 708611d7a3..f1c0a0ddde 100644 --- a/elements/pf-back-to-top/test/pf-back-to-top.e2e.ts +++ b/elements/pf-back-to-top/test/pf-back-to-top.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-back-to-top'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From acf3b384df5729358b8633fecf072e40055cea1b Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Sun, 19 May 2024 16:05:13 +0300 Subject: [PATCH 06/83] test(background-image): ssr --- .../test/pf-background-image.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-background-image/test/pf-background-image.e2e.ts b/elements/pf-background-image/test/pf-background-image.e2e.ts index 591f19a641..c6b83ffb54 100644 --- a/elements/pf-background-image/test/pf-background-image.e2e.ts +++ b/elements/pf-background-image/test/pf-background-image.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-background-image'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From c931c5a4a93e45ebb0ef15996f3e10d18426732d Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Sun, 19 May 2024 16:05:23 +0300 Subject: [PATCH 07/83] test(badge): ssr --- elements/pf-badge/test/pf-badge.e2e.ts | 13 +++++++++++++ elements/pf-badge/test/pf-badge.ssr.ts | 16 ++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 elements/pf-badge/test/pf-badge.ssr.ts diff --git a/elements/pf-badge/test/pf-badge.e2e.ts b/elements/pf-badge/test/pf-badge.e2e.ts index 4a2d5498f2..d2723a0326 100644 --- a/elements/pf-badge/test/pf-badge.e2e.ts +++ b/elements/pf-badge/test/pf-badge.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-badge'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); diff --git a/elements/pf-badge/test/pf-badge.ssr.ts b/elements/pf-badge/test/pf-badge.ssr.ts new file mode 100644 index 0000000000..4a60971e8b --- /dev/null +++ b/elements/pf-badge/test/pf-badge.ssr.ts @@ -0,0 +1,16 @@ +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; +import { test } from '@playwright/test'; + +const tagName = 'pf-badge'; + +test.describe(tagName, () => { + test('ssr', async ({ page }) => { + const fixture = new SSRPage(tagName, page, { + demoURL: new URL('../demo/ssr.html', import.meta.url), + importSpecifiers: [ + '@patternfly/elements/pf-badge/pf-badge.js', + ], + }); + await fixture.snapshot(); + }); +}); From fd37c48395e4df69a0b21d3daf766779f7b614f5 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:12:57 +0300 Subject: [PATCH 08/83] test(banner): ssr --- elements/pf-banner/test/pf-banner.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-banner/test/pf-banner.e2e.ts b/elements/pf-banner/test/pf-banner.e2e.ts index 03506dda94..e45c6deb82 100644 --- a/elements/pf-banner/test/pf-banner.e2e.ts +++ b/elements/pf-banner/test/pf-banner.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-banner'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From 303768717399ecd748a03d9713206e97f85b0064 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:13:09 +0300 Subject: [PATCH 09/83] test(button): ssr --- elements/pf-button/test/pf-button.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-button/test/pf-button.e2e.ts b/elements/pf-button/test/pf-button.e2e.ts index d139085abd..5072a7e6d7 100644 --- a/elements/pf-button/test/pf-button.e2e.ts +++ b/elements/pf-button/test/pf-button.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-button'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From 58389ffb9ea2ef782cc74772911673374d34f72b Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:13:19 +0300 Subject: [PATCH 10/83] test(card): ssr --- elements/pf-card/test/pf-card.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-card/test/pf-card.e2e.ts b/elements/pf-card/test/pf-card.e2e.ts index 0138284760..0d4aac7d7f 100644 --- a/elements/pf-card/test/pf-card.e2e.ts +++ b/elements/pf-card/test/pf-card.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-card'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From 3f7eec15616e3853d50b55ad0b73e07144438337 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:13:34 +0300 Subject: [PATCH 11/83] test(chip): ssr --- elements/pf-chip/test/pf-chip.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-chip/test/pf-chip.e2e.ts b/elements/pf-chip/test/pf-chip.e2e.ts index fb26e51cc2..77e5e203e5 100644 --- a/elements/pf-chip/test/pf-chip.e2e.ts +++ b/elements/pf-chip/test/pf-chip.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-chip'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From d292433f2070e77ed54d07cdb8f200099ee502a5 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:13:45 +0300 Subject: [PATCH 12/83] test(clipboard-copy): ssr --- .../pf-clipboard-copy/test/pf-clipboard-copy.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-clipboard-copy/test/pf-clipboard-copy.e2e.ts b/elements/pf-clipboard-copy/test/pf-clipboard-copy.e2e.ts index d7e145eab2..0d2f1f8da4 100644 --- a/elements/pf-clipboard-copy/test/pf-clipboard-copy.e2e.ts +++ b/elements/pf-clipboard-copy/test/pf-clipboard-copy.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-clipboard-copy'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From 3359f45437799d4550df25e4d1d4552a38e1b11a Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:13:57 +0300 Subject: [PATCH 13/83] test(code-block): ssr --- elements/pf-code-block/test/pf-code-block.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-code-block/test/pf-code-block.e2e.ts b/elements/pf-code-block/test/pf-code-block.e2e.ts index 692e8f317c..5df986cfe4 100644 --- a/elements/pf-code-block/test/pf-code-block.e2e.ts +++ b/elements/pf-code-block/test/pf-code-block.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-code-block'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From 56b08585b2753f54227386c68bb9b108a014aeeb Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:14:08 +0300 Subject: [PATCH 14/83] test(dropdown): ssr --- elements/pf-dropdown/test/pf-dropdown.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-dropdown/test/pf-dropdown.e2e.ts b/elements/pf-dropdown/test/pf-dropdown.e2e.ts index 0bd90ef8b7..97435b0d68 100644 --- a/elements/pf-dropdown/test/pf-dropdown.e2e.ts +++ b/elements/pf-dropdown/test/pf-dropdown.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-dropdown'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From a8efb0576e7803b39a198275fe402b9222204b17 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:14:19 +0300 Subject: [PATCH 15/83] test(icon): ssr --- elements/pf-icon/test/pf-icon.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-icon/test/pf-icon.e2e.ts b/elements/pf-icon/test/pf-icon.e2e.ts index 3a8111887e..54a8cca6c8 100644 --- a/elements/pf-icon/test/pf-icon.e2e.ts +++ b/elements/pf-icon/test/pf-icon.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-icon'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From 696a86599e0ccfc9234ab0467d4a2fae7baecc87 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:14:31 +0300 Subject: [PATCH 16/83] test(jump-links): ssr --- elements/pf-jump-links/test/pf-jump-links.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-jump-links/test/pf-jump-links.e2e.ts b/elements/pf-jump-links/test/pf-jump-links.e2e.ts index 4b25956d0c..739c64c4e8 100644 --- a/elements/pf-jump-links/test/pf-jump-links.e2e.ts +++ b/elements/pf-jump-links/test/pf-jump-links.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-jump-links'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate({ selector: 'pf-jump-links-nav' }); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From 240c7e76772c03332dd2a717c2bc2254d20cac4c Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:14:41 +0300 Subject: [PATCH 17/83] test(label): ssr --- elements/pf-label/test/pf-label.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-label/test/pf-label.e2e.ts b/elements/pf-label/test/pf-label.e2e.ts index 0e9c8fd44a..b0e512b6dd 100644 --- a/elements/pf-label/test/pf-label.e2e.ts +++ b/elements/pf-label/test/pf-label.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-label'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From 0ca0ea5af815264461ae5cd7d20368416dd5ef37 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:16:03 +0300 Subject: [PATCH 18/83] test(modal): ssr --- elements/pf-modal/test/pf-modal.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-modal/test/pf-modal.e2e.ts b/elements/pf-modal/test/pf-modal.e2e.ts index 715f5097cc..391383f3cf 100644 --- a/elements/pf-modal/test/pf-modal.e2e.ts +++ b/elements/pf-modal/test/pf-modal.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-modal'; @@ -13,4 +14,16 @@ test.describe(tagName, () => { await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From 6b0f40a9ac8a60732bab34e916f6b3fa15df18eb Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:16:13 +0300 Subject: [PATCH 19/83] test(panel): ssr --- elements/pf-panel/test/pf-panel.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-panel/test/pf-panel.e2e.ts b/elements/pf-panel/test/pf-panel.e2e.ts index 3d15e31a82..3b1afc3428 100644 --- a/elements/pf-panel/test/pf-panel.e2e.ts +++ b/elements/pf-panel/test/pf-panel.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-panel'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From b4d9c11b3bdb2a49108dcabfb328791d5e87a9c5 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:17:23 +0300 Subject: [PATCH 20/83] test(popover): ssr --- elements/pf-popover/test/pf-popover.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-popover/test/pf-popover.e2e.ts b/elements/pf-popover/test/pf-popover.e2e.ts index 1c1c65c44b..78709c9997 100644 --- a/elements/pf-popover/test/pf-popover.e2e.ts +++ b/elements/pf-popover/test/pf-popover.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-popover'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From 80e12276f5593fa3658b79847ccb05ca77149f26 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:18:16 +0300 Subject: [PATCH 21/83] test(progress): ssr --- elements/pf-progress/test/pf-progress.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-progress/test/pf-progress.e2e.ts b/elements/pf-progress/test/pf-progress.e2e.ts index e19cba99d9..2da4cdda68 100644 --- a/elements/pf-progress/test/pf-progress.e2e.ts +++ b/elements/pf-progress/test/pf-progress.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-progress'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From 70d464f5c206aaf2b261247d1cce307b4c49df67 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:20:32 +0300 Subject: [PATCH 22/83] test(progress-stepper): ssr --- .../test/pf-progress-stepper.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-progress-stepper/test/pf-progress-stepper.e2e.ts b/elements/pf-progress-stepper/test/pf-progress-stepper.e2e.ts index baebac6716..c218f62249 100644 --- a/elements/pf-progress-stepper/test/pf-progress-stepper.e2e.ts +++ b/elements/pf-progress-stepper/test/pf-progress-stepper.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-progress-stepper'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From 18f9f8585049ba8d90b0d3d271a9dca1d7e93809 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:20:43 +0300 Subject: [PATCH 23/83] test(select): ssr --- elements/pf-select/test/pf-select.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-select/test/pf-select.e2e.ts b/elements/pf-select/test/pf-select.e2e.ts index 4bbc30693f..b537e0eff7 100644 --- a/elements/pf-select/test/pf-select.e2e.ts +++ b/elements/pf-select/test/pf-select.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-select'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From 5f9f52791702243d2d8de72682b02b65f2e3190f Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:20:54 +0300 Subject: [PATCH 24/83] test(spinner): ssr --- elements/pf-spinner/test/pf-spinner.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-spinner/test/pf-spinner.e2e.ts b/elements/pf-spinner/test/pf-spinner.e2e.ts index 6dcfc50a34..e034c6cc06 100644 --- a/elements/pf-spinner/test/pf-spinner.e2e.ts +++ b/elements/pf-spinner/test/pf-spinner.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-spinner'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From 4b71fe5e88d60286f2f3136e7d598e246ffd46d2 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:21:04 +0300 Subject: [PATCH 25/83] test(switch): ssr --- elements/pf-switch/test/pf-switch.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-switch/test/pf-switch.e2e.ts b/elements/pf-switch/test/pf-switch.e2e.ts index b62ba1c65c..e06cc70125 100644 --- a/elements/pf-switch/test/pf-switch.e2e.ts +++ b/elements/pf-switch/test/pf-switch.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-switch'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From 11294cd96daa074cae9ed4f1a23d8c1d4f147afa Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:21:15 +0300 Subject: [PATCH 26/83] test(table): ssr --- elements/pf-table/test/pf-table.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-table/test/pf-table.e2e.ts b/elements/pf-table/test/pf-table.e2e.ts index e516a155ef..9d23b76cd7 100644 --- a/elements/pf-table/test/pf-table.e2e.ts +++ b/elements/pf-table/test/pf-table.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-table'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From eba47b9a2845ba52d7fe4080cbc7126aa316a36d Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:21:28 +0300 Subject: [PATCH 27/83] test(tabs): ssr --- elements/pf-tabs/test/pf-tabs.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-tabs/test/pf-tabs.e2e.ts b/elements/pf-tabs/test/pf-tabs.e2e.ts index 27b9224c52..1f37415eb2 100644 --- a/elements/pf-tabs/test/pf-tabs.e2e.ts +++ b/elements/pf-tabs/test/pf-tabs.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-tabs'; @@ -11,4 +12,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From 74eef92fdedce84eb9f3a9d4e723d5fc75772f35 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:21:47 +0300 Subject: [PATCH 28/83] test(text-area): ssr --- elements/pf-text-area/test/pf-text-area.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-text-area/test/pf-text-area.e2e.ts b/elements/pf-text-area/test/pf-text-area.e2e.ts index 4d4ecb8c43..ea473cf51a 100644 --- a/elements/pf-text-area/test/pf-text-area.e2e.ts +++ b/elements/pf-text-area/test/pf-text-area.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-text-area'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From 06ec5b97bd20fa7e6c61e7e558aa49d690fc739f Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:22:14 +0300 Subject: [PATCH 29/83] test(text-area): ssr --- elements/pf-text-input/test/pf-text-input.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-text-input/test/pf-text-input.e2e.ts b/elements/pf-text-input/test/pf-text-input.e2e.ts index 47745e9e16..32fa19cd09 100644 --- a/elements/pf-text-input/test/pf-text-input.e2e.ts +++ b/elements/pf-text-input/test/pf-text-input.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-text-input'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From 9ddecdd145211de977b4a3f6f8a05e31d180ab66 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:22:23 +0300 Subject: [PATCH 30/83] test(tile): ssr --- elements/pf-tile/test/pf-tile.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-tile/test/pf-tile.e2e.ts b/elements/pf-tile/test/pf-tile.e2e.ts index ed15c452e4..705b5fd500 100644 --- a/elements/pf-tile/test/pf-tile.e2e.ts +++ b/elements/pf-tile/test/pf-tile.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-tile'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From 725623d9700f2d85960a6b28916175ca2c8b335d Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:22:34 +0300 Subject: [PATCH 31/83] test(timestamp): ssr --- elements/pf-timestamp/test/pf-timestamp.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-timestamp/test/pf-timestamp.e2e.ts b/elements/pf-timestamp/test/pf-timestamp.e2e.ts index 9db32b9b47..52b290c6d2 100644 --- a/elements/pf-timestamp/test/pf-timestamp.e2e.ts +++ b/elements/pf-timestamp/test/pf-timestamp.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-timestamp'; @@ -10,4 +11,16 @@ test.describe(tagName, () => { await page.$eval('#realtime', el => el.closest('section')?.remove()); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From 57e381d35c12bf9609a27ba0b37feec7d6832566 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:22:46 +0300 Subject: [PATCH 32/83] test(tooltip): ssr --- elements/pf-tooltip/test/pf-tooltip.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elements/pf-tooltip/test/pf-tooltip.e2e.ts b/elements/pf-tooltip/test/pf-tooltip.e2e.ts index 446e9ec558..0c645f9bba 100644 --- a/elements/pf-tooltip/test/pf-tooltip.e2e.ts +++ b/elements/pf-tooltip/test/pf-tooltip.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = 'pf-tooltip'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From bac43ed77f9a405201a99adde19f2760e65290b4 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:23:20 +0300 Subject: [PATCH 33/83] feat(create-element): ssr tests --- .../templates/element/test/element.e2e.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tools/create-element/templates/element/test/element.e2e.ts b/tools/create-element/templates/element/test/element.e2e.ts index 85a1f24623..40fb5ca6f0 100644 --- a/tools/create-element/templates/element/test/element.e2e.ts +++ b/tools/create-element/templates/element/test/element.e2e.ts @@ -1,5 +1,6 @@ import { test } from '@playwright/test'; import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; +import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; const tagName = '<%= tagName %>'; @@ -9,4 +10,16 @@ test.describe(tagName, () => { await componentPage.navigate(); await componentPage.snapshot(); }); + + test('ssr', async ({ browser }) => { + const fixture = new SSRPage({ + tagName, + browser, + demoDir: new URL('../demo/', import.meta.url), + importSpecifiers: [ + `@patternfly/elements/${tagName}/${tagName}.js`, + ], + }); + await fixture.snapshots(); + }); }); From 34d1c1860b2169f2d78d0b11fb0a15a9ee47a572 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:23:35 +0300 Subject: [PATCH 34/83] feat(tools): automatic ssr demos --- tools/pfe-tools/test/playwright/SSRPage.ts | 65 +++++++++++++++------- 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/tools/pfe-tools/test/playwright/SSRPage.ts b/tools/pfe-tools/test/playwright/SSRPage.ts index 2ca4cc8d7c..c5eeb7e63b 100644 --- a/tools/pfe-tools/test/playwright/SSRPage.ts +++ b/tools/pfe-tools/test/playwright/SSRPage.ts @@ -1,60 +1,85 @@ import { expect } from '@playwright/test'; -import { readFile } from 'node:fs/promises'; +import { readFile, readdir } from 'node:fs/promises'; +import { fileURLToPath, resolve } from 'node:url'; +import { basename } from 'node:path'; import { renderGlobal } from '../ssr/global.js'; import Koa from 'koa'; -import type { Page } from '@playwright/test'; +import type { Browser, Page } from '@playwright/test'; import type { Server } from 'node:http'; import type { AddressInfo } from 'node:net'; interface SSRDemoConfig { - demoURL: URL; + demoDir: URL; importSpecifiers: string[]; + tagName: string; + browser: Browser; } + export class SSRPage { private app: Koa; private server!: Server; private host!: string; + private page!: Page; + private demoPaths!: string[]; constructor( - public tagName: string, - public page: Page, private config: SSRDemoConfig, ) { this.app = new Koa(); - } - - private async serve() { - const html = await readFile(this.config.demoURL, 'utf-8'); this.app.use(async ctx => { ctx.type = 'text/html'; - ctx.response.body = await renderGlobal(html, this.config.importSpecifiers); + const origPath = ctx.request.path.replace(/^\//, ''); + const demoDir = config.demoDir.href; + const fileUrl = resolve(demoDir, origPath); + ctx.response.body = await renderGlobal( + await readFile(fileURLToPath(fileUrl), 'utf-8'), + this.config.importSpecifiers, + ); }); - this.server = this.app.listen(0); + } + + private async initPage() { + this.page ??= await (await this.config.browser.newContext({ javaScriptEnabled: false })) + .newPage(); + } + + private async initServer() { + this.server ??= this.app.listen(0); while (!this.server.listening) { await new Promise(r => setTimeout(r)); } const { address = 'localhost', port = 0 } = this.server.address() as AddressInfo; - this.host = `http://${address.replace('::', 'localhost')}:${port}/`; + this.host ??= `http://${address.replace('::', 'localhost')}:${port}/`; + this.demoPaths ??= (await readdir(this.config.demoDir)).map(x => new URL(x, this.host).href); } private async close() { - await new Promise((res, rej) => + await new Promise((res, rej) => !this.server ? rej('no server') : this.server?.close(e => e ? rej(e) : res())); } - /** Take a snapshot and save it to disk */ - async snapshot() { + async snapshots() { try { - await this.serve(); - const path = new URL(new URL(this.config.demoURL).pathname, this.host); - const response = await this.page.goto(path.toString(), { waitUntil: 'load' }); - expect(response?.status(), { message: response?.statusText() }).toEqual(200); - expect(await this.page.screenshot({ fullPage: true })).toMatchSnapshot(`${this.tagName}.png`); + await Promise.all([ + this.initServer(), + this.initPage(), + ]); + for (const path of this.demoPaths) { + await this.snapshot(path); + } } finally { await this.close(); } } + + /** Take a snapshot and save it to disk */ + private async snapshot(url: string) { + const response = await this.page.goto(url, { waitUntil: 'load' }); + expect(response?.status(), { message: response?.statusText() }).toEqual(200); + const snapshot = await this.page.screenshot({ fullPage: true }); + expect(snapshot).toMatchSnapshot(`${this.config.tagName}-${basename(url)}.png`); + } } From f774e40aee4f7dcbeca002aa702b8522e6226f22 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:33:55 +0300 Subject: [PATCH 35/83] fix(tools): shim module --- tools/pfe-tools/test/ssr/shims.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pfe-tools/test/ssr/shims.ts b/tools/pfe-tools/test/ssr/shims.ts index b9baad8bb8..959e91c9f0 100644 --- a/tools/pfe-tools/test/ssr/shims.ts +++ b/tools/pfe-tools/test/ssr/shims.ts @@ -1,4 +1,4 @@ -class ObserverShim { +export class ObserverShim { observe() { void 0; } From a9e84f7b24242ae8e48e9adfbdbec7441d3d4787 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:37:20 +0300 Subject: [PATCH 36/83] docs: changesets --- .changeset/few-lands-feel.md | 4 ++++ .changeset/mean-tires-ask.md | 4 ++++ .changeset/polite-rules-dress.md | 4 ++++ .changeset/public-yaks-tickle.md | 4 ++++ .changeset/thirty-hounds-know.md | 4 ++++ 5 files changed, 20 insertions(+) create mode 100644 .changeset/few-lands-feel.md create mode 100644 .changeset/mean-tires-ask.md create mode 100644 .changeset/polite-rules-dress.md create mode 100644 .changeset/public-yaks-tickle.md create mode 100644 .changeset/thirty-hounds-know.md diff --git a/.changeset/few-lands-feel.md b/.changeset/few-lands-feel.md new file mode 100644 index 0000000000..b0a82b285f --- /dev/null +++ b/.changeset/few-lands-feel.md @@ -0,0 +1,4 @@ +--- +"@patternfly/pfe-core": major +--- +Removed global `pfeLog` feature diff --git a/.changeset/mean-tires-ask.md b/.changeset/mean-tires-ask.md new file mode 100644 index 0000000000..cc3f34b6cb --- /dev/null +++ b/.changeset/mean-tires-ask.md @@ -0,0 +1,4 @@ +--- +"@patternfly/pfe-core": major +--- +Removed `window.PfeConfig` global config object diff --git a/.changeset/polite-rules-dress.md b/.changeset/polite-rules-dress.md new file mode 100644 index 0000000000..a2bfedd823 --- /dev/null +++ b/.changeset/polite-rules-dress.md @@ -0,0 +1,4 @@ +--- +"@patternfly/pfe-core": major +--- +Removed global `auto-reveal` feature diff --git a/.changeset/public-yaks-tickle.md b/.changeset/public-yaks-tickle.md new file mode 100644 index 0000000000..b500155e41 --- /dev/null +++ b/.changeset/public-yaks-tickle.md @@ -0,0 +1,4 @@ +--- +"@patternfly/pfe-core": patch +--- +Context: `makeContextRoot` no longer crashes SSR processes diff --git a/.changeset/thirty-hounds-know.md b/.changeset/thirty-hounds-know.md new file mode 100644 index 0000000000..37cfb7eb81 --- /dev/null +++ b/.changeset/thirty-hounds-know.md @@ -0,0 +1,4 @@ +--- +"@patternfly/pfe-core": major +--- +Removed global `trackPerformance` feature From 39cfe7a3a767798d7d8899d1638130bbba6b11d2 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 09:38:20 +0300 Subject: [PATCH 37/83] test: remove cruft --- elements/pf-avatar/test/pf-avatar.ssr.ts | 16 ---------------- elements/pf-badge/test/pf-badge.ssr.ts | 16 ---------------- playwright.ssr.config.ts | 12 ------------ 3 files changed, 44 deletions(-) delete mode 100644 elements/pf-avatar/test/pf-avatar.ssr.ts delete mode 100644 elements/pf-badge/test/pf-badge.ssr.ts delete mode 100644 playwright.ssr.config.ts diff --git a/elements/pf-avatar/test/pf-avatar.ssr.ts b/elements/pf-avatar/test/pf-avatar.ssr.ts deleted file mode 100644 index 1327655c9f..0000000000 --- a/elements/pf-avatar/test/pf-avatar.ssr.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; -import { test } from '@playwright/test'; - -const tagName = 'pf-avatar'; - -test.describe(tagName, () => { - test('ssr', async ({ page }) => { - const fixture = new SSRPage(tagName, page, { - demoURL: new URL('../demo/ssr.html', import.meta.url), - importSpecifiers: [ - '@patternfly/elements/pf-avatar/pf-avatar.js', - ], - }); - await fixture.snapshot(); - }); -}); diff --git a/elements/pf-badge/test/pf-badge.ssr.ts b/elements/pf-badge/test/pf-badge.ssr.ts deleted file mode 100644 index 4a60971e8b..0000000000 --- a/elements/pf-badge/test/pf-badge.ssr.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; -import { test } from '@playwright/test'; - -const tagName = 'pf-badge'; - -test.describe(tagName, () => { - test('ssr', async ({ page }) => { - const fixture = new SSRPage(tagName, page, { - demoURL: new URL('../demo/ssr.html', import.meta.url), - importSpecifiers: [ - '@patternfly/elements/pf-badge/pf-badge.js', - ], - }); - await fixture.snapshot(); - }); -}); diff --git a/playwright.ssr.config.ts b/playwright.ssr.config.ts deleted file mode 100644 index 4bd3092f34..0000000000 --- a/playwright.ssr.config.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineConfig } from '@playwright/test'; - -export default defineConfig({ - testMatch: '**/test/*.ssr.ts', - testIgnore: /node_modules|_site|create-element\/templates/, - timeout: 120 * 1000, - workers: process.env.CI ? 2 : 8, - use: { - viewport: { width: 1920, height: 1080 }, - }, -}); - From 0e21463e60d47bfa2f15ab0b6273a07ccb10fbf7 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 10:29:55 +0300 Subject: [PATCH 38/83] fix(tools): ssr error reports --- tools/pfe-tools/test/playwright/SSRPage.ts | 14 +++++++++----- tools/pfe-tools/test/ssr/ssr.ts | 2 -- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/tools/pfe-tools/test/playwright/SSRPage.ts b/tools/pfe-tools/test/playwright/SSRPage.ts index c5eeb7e63b..0c74b32fb3 100644 --- a/tools/pfe-tools/test/playwright/SSRPage.ts +++ b/tools/pfe-tools/test/playwright/SSRPage.ts @@ -34,10 +34,14 @@ export class SSRPage { const origPath = ctx.request.path.replace(/^\//, ''); const demoDir = config.demoDir.href; const fileUrl = resolve(demoDir, origPath); - ctx.response.body = await renderGlobal( - await readFile(fileURLToPath(fileUrl), 'utf-8'), - this.config.importSpecifiers, - ); + try { + const content = await readFile(fileURLToPath(fileUrl), 'utf-8'); + ctx.response.body = await renderGlobal(content, this.config.importSpecifiers); + } catch (e) { + ctx.response.status = 500; + ctx.response.message = (e as Error).message; + ctx.response.body = (e as Error).stack; + } }); } @@ -78,7 +82,7 @@ export class SSRPage { /** Take a snapshot and save it to disk */ private async snapshot(url: string) { const response = await this.page.goto(url, { waitUntil: 'load' }); - expect(response?.status(), { message: response?.statusText() }).toEqual(200); + expect(response?.status(), { message: await response?.text() }).toEqual(200); const snapshot = await this.page.screenshot({ fullPage: true }); expect(snapshot).toMatchSnapshot(`${this.config.tagName}-${basename(url)}.png`); } diff --git a/tools/pfe-tools/test/ssr/ssr.ts b/tools/pfe-tools/test/ssr/ssr.ts index 27c613dc5a..a9b58de85e 100644 --- a/tools/pfe-tools/test/ssr/ssr.ts +++ b/tools/pfe-tools/test/ssr/ssr.ts @@ -6,5 +6,3 @@ import { unsafeHTML } from 'lit/directives/unsafe-html.js'; export async function ssr(input: string) { return collectResult(render(html`${unsafeHTML(input)}`)); } - - From db7a59341f184ae48b2ea58edfcde9ea8c238cb2 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 10:30:10 +0300 Subject: [PATCH 39/83] test: playwright config for ssr --- playwright.config.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/playwright.config.ts b/playwright.config.ts index 7e46cf07e9..f491fb93d2 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,10 +1,11 @@ -import type { PlaywrightTestConfig } from '@playwright/test'; +import { defineConfig } from '@playwright/test'; -const config: PlaywrightTestConfig = { - testMatch: '**/*.e2e.ts', - testIgnore: /node_modules|_site|create-element\/templates/, +export default defineConfig({ + testMatch: 'elements/**/*.e2e.ts', timeout: 120 * 1000, + workers: process.env.CI ? 2 : 8, + webServer: process.env.CI ? undefined : { command: 'npx @web/dev-server --config ./docs/demo/web-dev-server.demo.config.js', port: 8080, @@ -19,6 +20,9 @@ const config: PlaywrightTestConfig = { expect: { toMatchSnapshot: { threshold: 0.2 }, }, -}; -export default config; + reporter: process.env.CI ? 'github' : [['html', { + open: 'never', + outputFolder: 'test-report', + }]], +}); From 600ae91a10ebbfdd08a08e33110442d8aa1ac243 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 10:31:56 +0300 Subject: [PATCH 40/83] chore: ssr test workflow --- .github/workflows/tests.yml | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d00b424a18..1e7385db59 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -61,7 +61,6 @@ jobs: id: lint run: npm run lint - test: name: Run test suite (Web Test Runner) runs-on: ubuntu-latest @@ -91,6 +90,28 @@ jobs: report_paths: test-results/test-results.xml fail_on_failure: true # fail the actions run if the tests failed + ssr: + name: Run SSR Tests (Playwright) + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Configures the node version used on GitHub-hosted runners + - name: Configure node version + uses: actions/setup-node@v3 + with: + node-version: '20' + cache: npm + + - name: Install dependencies + run: | + npm ci --prefer-offline + npx playwright install + + - name: Run tests + run: npx playwright test -g ssr + build: name: Compile project runs-on: ubuntu-latest From 09dc36896da30509d786ebd98718d1a39488593e Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 10:35:00 +0300 Subject: [PATCH 41/83] fix(tools): ssr error status message --- tools/pfe-tools/test/playwright/SSRPage.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/pfe-tools/test/playwright/SSRPage.ts b/tools/pfe-tools/test/playwright/SSRPage.ts index 0c74b32fb3..557515a029 100644 --- a/tools/pfe-tools/test/playwright/SSRPage.ts +++ b/tools/pfe-tools/test/playwright/SSRPage.ts @@ -39,7 +39,6 @@ export class SSRPage { ctx.response.body = await renderGlobal(content, this.config.importSpecifiers); } catch (e) { ctx.response.status = 500; - ctx.response.message = (e as Error).message; ctx.response.body = (e as Error).stack; } }); From 663f414d502a49f5a4932cdd21747446a94c21f6 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 10:38:38 +0300 Subject: [PATCH 42/83] chore: ssr test workflow --- .github/workflows/tests.yml | 46 +++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1e7385db59..94905c9022 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -90,28 +90,6 @@ jobs: report_paths: test-results/test-results.xml fail_on_failure: true # fail the actions run if the tests failed - ssr: - name: Run SSR Tests (Playwright) - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - # Configures the node version used on GitHub-hosted runners - - name: Configure node version - uses: actions/setup-node@v3 - with: - node-version: '20' - cache: npm - - - name: Install dependencies - run: | - npm ci --prefer-offline - npx playwright install - - - name: Run tests - run: npx playwright test -g ssr - build: name: Compile project runs-on: ubuntu-latest @@ -159,6 +137,30 @@ jobs: id: release-dry run: npm run prepublishOnly -ws --if-present + ssr: + name: Run SSR Tests (Playwright) + needs: + - build + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Configures the node version used on GitHub-hosted runners + - name: Configure node version + uses: actions/setup-node@v3 + with: + node-version: '20' + cache: npm + + - name: Install dependencies + run: | + npm ci --prefer-offline + npx playwright install + + - name: Run tests + run: npx playwright test -g ssr + # Validate the build to main was successful; open an issue if not validate: name: Validate successful build on main From 9c92325962c1c90b84bf5acebda029f04d5bab5f Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 10:43:58 +0300 Subject: [PATCH 43/83] chore: ssr test workflow --- .github/workflows/tests.yml | 49 ++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 94905c9022..053d6a51ba 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -90,6 +90,30 @@ jobs: report_paths: test-results/test-results.xml fail_on_failure: true # fail the actions run if the tests failed + ssr: + name: Run SSR Tests (Playwright) + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Configures the node version used on GitHub-hosted runners + - name: Configure node version + uses: actions/setup-node@v3 + with: + node-version: '20' + cache: npm + + - name: Install dependencies + run: | + npm ci --prefer-offline + npx playwright install + npm run build + + - name: Run tests + run: npx playwright test -g ssr + + # Validate the build to main was successful; open an issue if not build: name: Compile project runs-on: ubuntu-latest @@ -137,31 +161,6 @@ jobs: id: release-dry run: npm run prepublishOnly -ws --if-present - ssr: - name: Run SSR Tests (Playwright) - needs: - - build - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - # Configures the node version used on GitHub-hosted runners - - name: Configure node version - uses: actions/setup-node@v3 - with: - node-version: '20' - cache: npm - - - name: Install dependencies - run: | - npm ci --prefer-offline - npx playwright install - - - name: Run tests - run: npx playwright test -g ssr - - # Validate the build to main was successful; open an issue if not validate: name: Validate successful build on main needs: From d6f9acfae2d5e879c41027abc32e0b0aad1db771 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 13:57:02 +0300 Subject: [PATCH 44/83] chore: ignore reports --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a0146b7ebc..6f6ad9dc21 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ pfe.min.js **/*.LEGAL.txt *.tsbuildinfo test-results +test-report /elements/react From a485351254fa1b6e71b29de1b98c27a33610cb9c Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 13:57:14 +0300 Subject: [PATCH 45/83] fix(accordion): ssrability --- elements/pf-accordion/BaseAccordion.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/elements/pf-accordion/BaseAccordion.ts b/elements/pf-accordion/BaseAccordion.ts index a79afd49a3..062ef9afef 100644 --- a/elements/pf-accordion/BaseAccordion.ts +++ b/elements/pf-accordion/BaseAccordion.ts @@ -212,11 +212,11 @@ export abstract class BaseAccordion extends LitElement { } #allHeaders(accordion: BaseAccordion = this): BaseAccordionHeader[] { - return Array.from(accordion.children).filter(BaseAccordion.isHeader); + return Array.from(accordion.children ?? []).filter(BaseAccordion.isHeader); } #allPanels(accordion: BaseAccordion = this): BaseAccordionPanel[] { - return Array.from(accordion.children).filter(BaseAccordion.isPanel); + return Array.from(accordion.children ?? []).filter(BaseAccordion.isPanel); } #getIndex(el: Element | null) { From a7cad9d2f10c8bc909c9ad8220fce3e0f5d25a76 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 13:57:29 +0300 Subject: [PATCH 46/83] fix(back-to-top): ssrability --- elements/pf-back-to-top/pf-back-to-top.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/elements/pf-back-to-top/pf-back-to-top.ts b/elements/pf-back-to-top/pf-back-to-top.ts index e45e0f6e8b..b436bfd7e6 100644 --- a/elements/pf-back-to-top/pf-back-to-top.ts +++ b/elements/pf-back-to-top/pf-back-to-top.ts @@ -1,4 +1,4 @@ -import { LitElement, html, type PropertyValues } from 'lit'; +import { LitElement, html, isServer, type PropertyValues } from 'lit'; import { customElement } from 'lit/decorators/custom-element.js'; import { property } from 'lit/decorators/property.js'; import { ifDefined } from 'lit/directives/if-defined.js'; @@ -66,9 +66,11 @@ export class PfBackToTop extends LitElement { #logger = new Logger(this); - get #rootNode(): Document | ShadowRoot { - const root = this.getRootNode(); - if (root instanceof Document || root instanceof ShadowRoot) { + get #rootNode(): Document | ShadowRoot | null { + let root = null; + if (isServer) { + return null; + } else if ((root = this.getRootNode()) instanceof Document || root instanceof ShadowRoot) { return root; } else { return document; @@ -157,7 +159,7 @@ export class PfBackToTop extends LitElement { this.#scrollSpy = !!this.scrollableSelector; if (this.#scrollSpy && this.scrollableSelector) { - const scrollableElement = this.#rootNode.querySelector(this.scrollableSelector); + const scrollableElement = this.#rootNode?.querySelector?.(this.scrollableSelector); if (!scrollableElement) { this.#logger.error(`unable to find element with selector ${this.scrollableSelector}`); return; From 96c9a45a13b377ac6b5fdb6805a0e1b3427a9fd2 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 16:10:27 +0300 Subject: [PATCH 47/83] docs: jsdoc for ssr tests --- tools/pfe-tools/test/playwright/SSRPage.ts | 37 +++++++++++++++------- tools/pfe-tools/test/ssr/global.ts | 6 ++++ 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/tools/pfe-tools/test/playwright/SSRPage.ts b/tools/pfe-tools/test/playwright/SSRPage.ts index 557515a029..c6d19652c3 100644 --- a/tools/pfe-tools/test/playwright/SSRPage.ts +++ b/tools/pfe-tools/test/playwright/SSRPage.ts @@ -18,6 +18,10 @@ interface SSRDemoConfig { } +/** + * Creates a server which server-renders each html file in the `demoDir` directory, + * given a list of importSpecifiers. + */ export class SSRPage { private app: Koa; private server!: Server; @@ -29,17 +33,20 @@ export class SSRPage { private config: SSRDemoConfig, ) { this.app = new Koa(); - this.app.use(async ctx => { - ctx.type = 'text/html'; - const origPath = ctx.request.path.replace(/^\//, ''); - const demoDir = config.demoDir.href; - const fileUrl = resolve(demoDir, origPath); - try { - const content = await readFile(fileURLToPath(fileUrl), 'utf-8'); - ctx.response.body = await renderGlobal(content, this.config.importSpecifiers); - } catch (e) { - ctx.response.status = 500; - ctx.response.body = (e as Error).stack; + this.app.use(async (ctx, next) => { + if (ctx.method === 'GET' && ctx.request.path.endsWith('.html')) { + const origPath = ctx.request.path.replace(/^\//, ''); + const demoDir = config.demoDir.href; + const fileUrl = resolve(demoDir, origPath); + try { + const content = await readFile(fileURLToPath(fileUrl), 'utf-8'); + ctx.response.body = await renderGlobal(content, this.config.importSpecifiers); + } catch (e) { + ctx.response.status = 500; + ctx.response.body = (e as Error).stack; + } + } else { + return next(); } }); } @@ -64,6 +71,9 @@ export class SSRPage { !this.server ? rej('no server') : this.server?.close(e => e ? rej(e) : res())); } + /** + * Creates visual regression snapshots for each demo in the server's `demoDir` + */ async snapshots() { try { await Promise.all([ @@ -78,7 +88,10 @@ export class SSRPage { } } - /** Take a snapshot and save it to disk */ + /** + * Take a visual regression snapshot and save it to disk + * @param url url to the demo file + */ private async snapshot(url: string) { const response = await this.page.goto(url, { waitUntil: 'load' }); expect(response?.status(), { message: await response?.text() }).toEqual(200); diff --git a/tools/pfe-tools/test/ssr/global.ts b/tools/pfe-tools/test/ssr/global.ts index 6166aaff1f..269bd92dbb 100644 --- a/tools/pfe-tools/test/ssr/global.ts +++ b/tools/pfe-tools/test/ssr/global.ts @@ -1,3 +1,9 @@ +/** + * Renders a string of HTML, + * first importing the provided component defintions into nodejs' global scope. + * @param html string to render + * @param importSpecifiers list of web component definition module import specifiers + */ export async function renderGlobal( html: string, importSpecifiers: string[], From e5fcc99fc1dc7feea781183cfcdfbb91121d336f Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 18:33:14 +0300 Subject: [PATCH 48/83] chore: test workflow in ci --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 053d6a51ba..abab38e48a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -111,7 +111,7 @@ jobs: npm run build - name: Run tests - run: npx playwright test -g ssr + run: npx playwright test -g ssr --update-snapshots # Validate the build to main was successful; open an issue if not build: From f0c857c72a126dd63fd63b4b730be6a7067ea18b Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 20 May 2024 18:48:36 +0300 Subject: [PATCH 49/83] fix(core): fix Logger for ssr --- core/pfe-core/controllers/logger.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/pfe-core/controllers/logger.ts b/core/pfe-core/controllers/logger.ts index ec3f313a96..4c4cb7bfd3 100644 --- a/core/pfe-core/controllers/logger.ts +++ b/core/pfe-core/controllers/logger.ts @@ -1,4 +1,4 @@ -import type { ReactiveController, ReactiveControllerHost } from 'lit'; +import { isServer, type ReactiveController, type ReactiveControllerHost } from 'lit'; export class Logger implements ReactiveController { private static logDebug: boolean; @@ -6,7 +6,7 @@ export class Logger implements ReactiveController { private static instances = new WeakMap(); private get prefix() { - if (this.host instanceof HTMLElement) { + if (!isServer && this.host instanceof HTMLElement) { return `[${this.host.localName}${this.host.id ? `#${this.host.id}` : ''}]`; } else { return `[${this.host.constructor.name}]`; From 5e5859d685b61e12e7aebf7006898bdd360ceb10 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 21 May 2024 08:13:37 +0300 Subject: [PATCH 50/83] style: whitespace --- tools/pfe-tools/test/playwright/SSRPage.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/pfe-tools/test/playwright/SSRPage.ts b/tools/pfe-tools/test/playwright/SSRPage.ts index c6d19652c3..6dfb61d5aa 100644 --- a/tools/pfe-tools/test/playwright/SSRPage.ts +++ b/tools/pfe-tools/test/playwright/SSRPage.ts @@ -17,7 +17,6 @@ interface SSRDemoConfig { browser: Browser; } - /** * Creates a server which server-renders each html file in the `demoDir` directory, * given a list of importSpecifiers. @@ -52,7 +51,9 @@ export class SSRPage { } private async initPage() { - this.page ??= await (await this.config.browser.newContext({ javaScriptEnabled: false })) + this.page ??= await (await this.config.browser.newContext({ + javaScriptEnabled: false, + })) .newPage(); } From 6d409908c55e5fd1ffd73afd657dc23277044b8d Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 21 May 2024 08:13:49 +0300 Subject: [PATCH 51/83] chore: better elements build --- elements/tsconfig.build.json | 14 ++++++++++++++ package.json | 15 +++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 elements/tsconfig.build.json diff --git a/elements/tsconfig.build.json b/elements/tsconfig.build.json new file mode 100644 index 0000000000..483ddcae4e --- /dev/null +++ b/elements/tsconfig.build.json @@ -0,0 +1,14 @@ +{ + "extends": "./tsconfig.json", + "exclude": [ + "./*/test/*.ts" + ], + "references": [ + { + "path": "../core/pfe-core" + }, + { + "path": "../tools/pfe-tools" + } + ] +} diff --git a/package.json b/package.json index afebb397dc..cd4ad3e58b 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "🧪-TEST": "❓ Test packages", "test": "wireit", "test:ci": "wireit", + "test:ssr": "wireit", "test:watch": "wtr --watch", "e2e": "wireit", "e2e:update": "wireit", @@ -31,7 +32,8 @@ "leftover-check": "bash scripts/leftover-check.sh", "⚙️--UTIL": "❓ Manages the repo", "postinstall": "wireit", - "clean": "git clean -dfX -e node_modules -e .husky", + "clean": "git clean -dfx -e node_modules -e .husky -e .wireit", + "nuke": "git clean -dfx", "lint": "eslint", "patch": "patch-package", "husky": "husky" @@ -88,7 +90,7 @@ ] }, "build:elements": { - "command": "tspc --build elements --pretty", + "command": "tspc --build elements/tsconfig.build.json --pretty", "dependencies": [ "build:core" ], @@ -257,6 +259,15 @@ "build:core" ] }, + "test:ssr": { + "command": "npx playwright test -g ssr --update-snapshots", + "dependencies": [ + "clean", + "build:tools", + "build:core", + "build:elements" + ] + }, "e2e": { "command": "PW_EXPERIMENTAL_TS_ESM=1 playwright test", "dependencies": [ From 45db0997ab7aa16fd93853bb422570b0fdd97220 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 21 May 2024 08:32:06 +0300 Subject: [PATCH 52/83] fix(core): more ssr-able controllers --- .../controllers/internals-controller.ts | 21 ++++++++++++++++--- .../controllers/overflow-controller.ts | 2 +- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/core/pfe-core/controllers/internals-controller.ts b/core/pfe-core/controllers/internals-controller.ts index 3ebdbd842a..6e72138a3a 100644 --- a/core/pfe-core/controllers/internals-controller.ts +++ b/core/pfe-core/controllers/internals-controller.ts @@ -1,4 +1,9 @@ -import type { ReactiveController, ReactiveControllerHost } from 'lit'; +import { + isServer, + type ReactiveController, + type ReactiveControllerHost, + type LitElement, +} from 'lit'; function isARIAMixinProp(key: string): key is keyof ARIAMixin { return key === 'role' || key.startsWith('aria'); @@ -146,7 +151,11 @@ export class InternalsController implements ReactiveController, ARIAMixin { /** True when the control is disabled via it's containing fieldset element */ get formDisabled() { - return this.element?.matches(':disabled') || this._formDisabled; + if (isServer) { + return this._formDisabled; + } else { + return this.element?.matches(':disabled') || this._formDisabled; + } } get labels() { @@ -166,7 +175,13 @@ export class InternalsController implements ReactiveController, ARIAMixin { } private get element() { - return this.host instanceof HTMLElement ? this.host : this.options?.getHTMLElement?.(); + if (isServer) { + // FIXME(bennyp): a little white lie, which may break + // when the controller is applied to non-lit frameworks. + return this.host as LitElement; + } else { + return this.host instanceof HTMLElement ? this.host : this.options?.getHTMLElement?.(); + } } private internals!: ElementInternals; diff --git a/core/pfe-core/controllers/overflow-controller.ts b/core/pfe-core/controllers/overflow-controller.ts index 5d4b888497..1b9e1d49e8 100644 --- a/core/pfe-core/controllers/overflow-controller.ts +++ b/core/pfe-core/controllers/overflow-controller.ts @@ -18,7 +18,7 @@ export class OverflowController implements ReactiveController { static { // on resize check for overflows to add or remove scroll buttons - window.addEventListener('resize', () => { + globalThis.addEventListener?.('resize', () => { for (const instance of this.#instances) { instance.onScroll(); } From 17841e82537b5f452c98c5b021c7fba94175e8d4 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 21 May 2024 08:32:29 +0300 Subject: [PATCH 53/83] test(back-to-top): ssrable demos --- .../pf-back-to-top/demo/always-visible.html | 20 +++++++++++-- .../pf-back-to-top/demo/button-no-text.html | 25 ++++++++++++++-- elements/pf-back-to-top/demo/button.html | 29 +++++++++++++++++-- elements/pf-back-to-top/demo/demo.css | 25 ---------------- elements/pf-back-to-top/demo/label.html | 29 +++++++++++++++++-- elements/pf-back-to-top/demo/no-text.html | 29 +++++++++++++++++-- .../pf-back-to-top/demo/pf-back-to-top.html | 29 +++++++++++++++++-- .../pf-back-to-top/demo/scroll-distance.html | 29 +++++++++++++++++-- 8 files changed, 176 insertions(+), 39 deletions(-) delete mode 100644 elements/pf-back-to-top/demo/demo.css diff --git a/elements/pf-back-to-top/demo/always-visible.html b/elements/pf-back-to-top/demo/always-visible.html index 427492d97f..a607050b23 100644 --- a/elements/pf-back-to-top/demo/always-visible.html +++ b/elements/pf-back-to-top/demo/always-visible.html @@ -1,5 +1,3 @@ - -

Always visible

Focusable element (top) @@ -10,3 +8,21 @@

Always visible

+ + diff --git a/elements/pf-back-to-top/demo/button-no-text.html b/elements/pf-back-to-top/demo/button-no-text.html index 09728fc299..0f6de199a2 100644 --- a/elements/pf-back-to-top/demo/button-no-text.html +++ b/elements/pf-back-to-top/demo/button-no-text.html @@ -1,5 +1,3 @@ - -

Button No Text

@@ -20,3 +18,26 @@

Button No Text

target.focus(); }); + + diff --git a/elements/pf-back-to-top/demo/button.html b/elements/pf-back-to-top/demo/button.html index a05dd33e70..3a2806507f 100644 --- a/elements/pf-back-to-top/demo/button.html +++ b/elements/pf-back-to-top/demo/button.html @@ -1,5 +1,3 @@ - - Accessibility Warning Using the Button/JS variant, implementation must apply click event and focus to the element that is scrolled to. @@ -25,3 +23,30 @@

Button

target.focus(); }); + + diff --git a/elements/pf-back-to-top/demo/demo.css b/elements/pf-back-to-top/demo/demo.css deleted file mode 100644 index 39ac723ffd..0000000000 --- a/elements/pf-back-to-top/demo/demo.css +++ /dev/null @@ -1,25 +0,0 @@ -:root { - --_scroll-distance: 400px; -} - -main { - scroll-behavior: smooth; -} - -.scroll-distance { - --_scroll-distance: 200px; -} - -.outer-container { - height: calc(100vh - var(--pf-demo-header-height) + var(--_scroll-distance)); -} - -.padded { - padding: var(--pf-global--spacer--md, 1rem); -} - -.scroll-indicator { - height: var(--_scroll-distance); - background-color: var(--pf-global--palette--cyan-50, #f2f9f9) !important; -} - diff --git a/elements/pf-back-to-top/demo/label.html b/elements/pf-back-to-top/demo/label.html index 51db65dd2f..0fa9c01840 100644 --- a/elements/pf-back-to-top/demo/label.html +++ b/elements/pf-back-to-top/demo/label.html @@ -1,5 +1,3 @@ - -

Default

@@ -14,3 +12,30 @@

Default

+ + diff --git a/elements/pf-back-to-top/demo/no-text.html b/elements/pf-back-to-top/demo/no-text.html index 66e8d4bbfa..c2a4ed1db3 100644 --- a/elements/pf-back-to-top/demo/no-text.html +++ b/elements/pf-back-to-top/demo/no-text.html @@ -1,5 +1,3 @@ - -

No Text

@@ -14,3 +12,30 @@

No Text

+ + diff --git a/elements/pf-back-to-top/demo/pf-back-to-top.html b/elements/pf-back-to-top/demo/pf-back-to-top.html index f22fb4277d..521bb16603 100644 --- a/elements/pf-back-to-top/demo/pf-back-to-top.html +++ b/elements/pf-back-to-top/demo/pf-back-to-top.html @@ -1,5 +1,3 @@ - -

Default

@@ -14,3 +12,30 @@

Default

+ + diff --git a/elements/pf-back-to-top/demo/scroll-distance.html b/elements/pf-back-to-top/demo/scroll-distance.html index b7d97a6015..15c65c6a99 100644 --- a/elements/pf-back-to-top/demo/scroll-distance.html +++ b/elements/pf-back-to-top/demo/scroll-distance.html @@ -1,5 +1,3 @@ - -

Default

@@ -14,3 +12,30 @@

Default

+ + From f9f8cd437b6c870da1fa98d8bed2330759ab9b30 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 21 May 2024 09:27:15 +0300 Subject: [PATCH 54/83] fix(tools): redirects for demos in dev server --- tools/pfe-tools/dev-server/plugins/pfe-dev-server.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/pfe-tools/dev-server/plugins/pfe-dev-server.ts b/tools/pfe-tools/dev-server/plugins/pfe-dev-server.ts index 34046e7be2..63ba2ee34e 100644 --- a/tools/pfe-tools/dev-server/plugins/pfe-dev-server.ts +++ b/tools/pfe-tools/dev-server/plugins/pfe-dev-server.ts @@ -118,11 +118,12 @@ function getRouter(options: PfeDevServerInternalConfig) { .get(`/${componentSubpath}/:element/demo/:splat*/:fileName.:ext`, async (ctx, next) => { const { element, splat, fileName, ext } = ctx.params; const prefixedElement = deslugify(element); + const demoName = ctx.request.get('Referer').match(/\/demo\/([\w-]+)\/$/)?.at(1) ?? ''; if (!element.includes(tagPrefix)) { if (splat) { - ctx.redirect(`/${elementsDir}/${prefixedElement}/demo/${splat}/${fileName}.${ext}`); + ctx.redirect(`/${elementsDir}/${prefixedElement}/demo/${splat}/${fileName}.${ext}`.replace(`/${demoName}`, '/')); } else { - ctx.redirect(`/${elementsDir}/${prefixedElement}/demo/${fileName}.${ext}`); + ctx.redirect(`/${elementsDir}/${prefixedElement}/demo/${fileName}.${ext}`.replace(`/${demoName}`, '/')); } } else { return next(); From 804842f1bded1f200028961d11a8d21bd4a53375 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 21 May 2024 09:28:02 +0300 Subject: [PATCH 55/83] fix(tools): ssr files --- tools/pfe-tools/{test => }/ssr/global.ts | 0 tools/pfe-tools/{test => }/ssr/shims.ts | 0 tools/pfe-tools/{test => }/ssr/ssr.ts | 0 tools/pfe-tools/test/playwright/SSRPage.ts | 37 +++++++++++++++------- 4 files changed, 26 insertions(+), 11 deletions(-) rename tools/pfe-tools/{test => }/ssr/global.ts (100%) rename tools/pfe-tools/{test => }/ssr/shims.ts (100%) rename tools/pfe-tools/{test => }/ssr/ssr.ts (100%) diff --git a/tools/pfe-tools/test/ssr/global.ts b/tools/pfe-tools/ssr/global.ts similarity index 100% rename from tools/pfe-tools/test/ssr/global.ts rename to tools/pfe-tools/ssr/global.ts diff --git a/tools/pfe-tools/test/ssr/shims.ts b/tools/pfe-tools/ssr/shims.ts similarity index 100% rename from tools/pfe-tools/test/ssr/shims.ts rename to tools/pfe-tools/ssr/shims.ts diff --git a/tools/pfe-tools/test/ssr/ssr.ts b/tools/pfe-tools/ssr/ssr.ts similarity index 100% rename from tools/pfe-tools/test/ssr/ssr.ts rename to tools/pfe-tools/ssr/ssr.ts diff --git a/tools/pfe-tools/test/playwright/SSRPage.ts b/tools/pfe-tools/test/playwright/SSRPage.ts index 6dfb61d5aa..25ac1714ce 100644 --- a/tools/pfe-tools/test/playwright/SSRPage.ts +++ b/tools/pfe-tools/test/playwright/SSRPage.ts @@ -2,7 +2,7 @@ import { expect } from '@playwright/test'; import { readFile, readdir } from 'node:fs/promises'; import { fileURLToPath, resolve } from 'node:url'; import { basename } from 'node:path'; -import { renderGlobal } from '../ssr/global.js'; +import { renderGlobal } from '@patternfly/pfe-tools/ssr/global.js'; import Koa from 'koa'; @@ -33,16 +33,24 @@ export class SSRPage { ) { this.app = new Koa(); this.app.use(async (ctx, next) => { - if (ctx.method === 'GET' && ctx.request.path.endsWith('.html')) { + if (ctx.method === 'GET') { const origPath = ctx.request.path.replace(/^\//, ''); const demoDir = config.demoDir.href; const fileUrl = resolve(demoDir, origPath); - try { - const content = await readFile(fileURLToPath(fileUrl), 'utf-8'); - ctx.response.body = await renderGlobal(content, this.config.importSpecifiers); - } catch (e) { - ctx.response.status = 500; - ctx.response.body = (e as Error).stack; + if (ctx.request.path.endsWith('.html')) { + try { + const content = await readFile(fileURLToPath(fileUrl), 'utf-8'); + ctx.response.body = await renderGlobal(content, this.config.importSpecifiers); + } catch (e) { + ctx.response.status = 500; + ctx.response.body = (e as Error).stack; + } + } else { + try { + ctx.response.body = await readFile(fileURLToPath(fileUrl)); + } catch (e) { + ctx.throw(500, e as Error); + } } } else { return next(); @@ -64,7 +72,9 @@ export class SSRPage { } const { address = 'localhost', port = 0 } = this.server.address() as AddressInfo; this.host ??= `http://${address.replace('::', 'localhost')}:${port}/`; - this.demoPaths ??= (await readdir(this.config.demoDir)).map(x => new URL(x, this.host).href); + this.demoPaths ??= (await readdir(this.config.demoDir)) + .filter(x => x.endsWith('.html')) + .map(x => new URL(x, this.host).href); } private async close() { @@ -95,8 +105,13 @@ export class SSRPage { */ private async snapshot(url: string) { const response = await this.page.goto(url, { waitUntil: 'load' }); - expect(response?.status(), { message: await response?.text() }).toEqual(200); + if (response?.status() === 404) { + throw new Error(`Not Found: ${url}`); + } + expect(response?.status(), await response?.text()) + .toEqual(200); const snapshot = await this.page.screenshot({ fullPage: true }); - expect(snapshot).toMatchSnapshot(`${this.config.tagName}-${basename(url)}.png`); + expect(snapshot, new URL(url).pathname) + .toMatchSnapshot(`${this.config.tagName}-${basename(url)}.png`); } } From 82b1e0211809a0a88bdf3438a29ddd29e7fbc126 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 21 May 2024 09:28:23 +0300 Subject: [PATCH 56/83] test(background-image): ssrable demos --- elements/pf-background-image/demo/filter-override.html | 10 +++++----- elements/pf-background-image/demo/sibling-content.html | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/elements/pf-background-image/demo/filter-override.html b/elements/pf-background-image/demo/filter-override.html index aec2f02c8c..5b874ccedd 100644 --- a/elements/pf-background-image/demo/filter-override.html +++ b/elements/pf-background-image/demo/filter-override.html @@ -1,9 +1,9 @@ + src="pfbg.jpg" + src-2x="pfbg_576.jpg" + src-sm="pfbg_768.jpg" + src-sm-2x="pfbg_768@2x.jpg" + src-lg="pfbg_1200.jpg"> diff --git a/elements/pf-background-image/demo/sibling-content.html b/elements/pf-background-image/demo/sibling-content.html index c27647c14b..0bfc15f2b5 100644 --- a/elements/pf-background-image/demo/sibling-content.html +++ b/elements/pf-background-image/demo/sibling-content.html @@ -1,10 +1,10 @@
From 35ba37126a4e2eab4c718040dfa118f7edd0e618 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 21 May 2024 09:30:43 +0300 Subject: [PATCH 57/83] fix(tools): 11ty demo images --- docs/components/demos.html | 2 +- tools/pfe-tools/11ty/plugins/custom-elements-manifest.cjs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/components/demos.html b/docs/components/demos.html index 1f39a4d2c5..0d17a73eec 100644 --- a/docs/components/demos.html +++ b/docs/components/demos.html @@ -6,7 +6,7 @@ data: 'demos', alias: 'demo', size: 1, - before: xs => xs.filter(x => x.permalink ), + before: xs => xs.filter(x => x.permalink), }, preloads: [ '@lit/reactive-element@1.0.2/development/css-tag.js', diff --git a/tools/pfe-tools/11ty/plugins/custom-elements-manifest.cjs b/tools/pfe-tools/11ty/plugins/custom-elements-manifest.cjs index ca5790d1c6..03b4fee93e 100644 --- a/tools/pfe-tools/11ty/plugins/custom-elements-manifest.cjs +++ b/tools/pfe-tools/11ty/plugins/custom-elements-manifest.cjs @@ -82,7 +82,7 @@ module.exports = function configFunction(eleventyConfig, pluginOpts = {}) { eleventyConfig.addTransform('reroute-special-demo-subresources', function(content) { if (this.inputPath.endsWith('/demos.html')) { const [, one, , three, four] = this.outputPath.split('/'); - if ( one === 'components' && three === 'demo' && four !== 'index.html') { + if (one === 'components' && three === 'demo' && four !== 'index.html') { const cheerio = require('cheerio'); const $ = cheerio.load(content); $('body link').each(function() { @@ -91,7 +91,7 @@ module.exports = function configFunction(eleventyConfig, pluginOpts = {}) { $(this).attr('href', join('..', href)); } }); - $('body script').each(function() { + $('body script, body img').each(function() { const src = $(this).attr('src'); if (src && !src.startsWith('http')) { $(this).attr('src', join('..', src)); From 674de7616ea2db8f5e95435ca79353c78a7dca6b Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 21 May 2024 11:01:10 +0300 Subject: [PATCH 58/83] fix(core): floating dom controller more ssrable --- core/pfe-core/controllers/floating-dom-controller.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/pfe-core/controllers/floating-dom-controller.ts b/core/pfe-core/controllers/floating-dom-controller.ts index be84b89fed..4522c0ec94 100644 --- a/core/pfe-core/controllers/floating-dom-controller.ts +++ b/core/pfe-core/controllers/floating-dom-controller.ts @@ -1,5 +1,5 @@ import type { Placement } from '@floating-ui/dom'; -import type { ReactiveController, ReactiveControllerHost } from 'lit'; +import type { LitElement, ReactiveController, ReactiveControllerHost } from 'lit'; import type { StyleInfo } from 'lit/directives/style-map.js'; import type { OffsetOptions as Offset } from '@floating-ui/core'; @@ -100,7 +100,7 @@ export class FloatingDOMController implements ReactiveController { ) { host.addController(this); this.#options = { - invoker: (host instanceof HTMLElement ? () => host : () => undefined), + invoker: (() => host as LitElement), shift: true, ...options, }; From 7ca39e58df40b0615a626c6fe53bc95ef3cd4f0f Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 21 May 2024 11:01:24 +0300 Subject: [PATCH 59/83] feat(tools): export ssr helpers --- tools/pfe-tools/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/pfe-tools/package.json b/tools/pfe-tools/package.json index 6e70a1928d..145bc6773f 100644 --- a/tools/pfe-tools/package.json +++ b/tools/pfe-tools/package.json @@ -32,6 +32,7 @@ "./11ty/plugins/table-of-contents.cjs": "./11ty/plugins/table-of-contents.cjs", "./11ty/plugins/todos.cjs": "./11ty/plugins/todos.cjs", "./react/generate-wrappers.js": "./react/generate-wrappers.js", + "./ssr/*": "./ssr/*", "./test/a11y-snapshot.js": "./test/a11y-snapshot.js", "./test/config.js": "./test/config.js", "./test/create-fixture.js": "./test/create-fixture.js", From 23340f2d24d514cf396a2470f927b8f77fe98b0d Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 21 May 2024 11:04:55 +0300 Subject: [PATCH 60/83] fix(code-block): ssrable --- elements/pf-code-block/pf-code-block.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/elements/pf-code-block/pf-code-block.ts b/elements/pf-code-block/pf-code-block.ts index 4f2d2482c8..d5e920e7eb 100644 --- a/elements/pf-code-block/pf-code-block.ts +++ b/elements/pf-code-block/pf-code-block.ts @@ -40,11 +40,11 @@ export class PfCodeBlock extends LitElement { @property({ type: Boolean, reflect: true }) expanded = false; get #expandedContent(): string { - return this.querySelector('script[data-expand]')?.textContent ?? ''; + return this.querySelector?.('script[data-expand]')?.textContent ?? ''; } get #content() { - const script = this.querySelector('script[type]'); + const script = this.querySelector?.('script[type]'); if (script?.type !== 'text/javascript-sample' && !!script?.type.match(/(j(ava)?|ecma|live)script/)) { return ''; From d9296ee4c78208388a9ffd537f1798324b56dd38 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 21 May 2024 11:09:14 +0300 Subject: [PATCH 61/83] fix(jump-links): ssrable --- elements/pf-jump-links/pf-jump-links.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/elements/pf-jump-links/pf-jump-links.ts b/elements/pf-jump-links/pf-jump-links.ts index 83725a956f..f352ff1031 100644 --- a/elements/pf-jump-links/pf-jump-links.ts +++ b/elements/pf-jump-links/pf-jump-links.ts @@ -75,7 +75,7 @@ export class PfJumpLinks extends LitElement { /** Label to add to nav element. */ @property() label?: string; - #kids = this.querySelectorAll(':is(pf-jump-links-item, pf-jump-links-list)'); + #kids = this.querySelectorAll?.(':is(pf-jump-links-item, pf-jump-links-list)'); #tabindex?: RovingTabindexController; @@ -101,13 +101,13 @@ export class PfJumpLinks extends LitElement { getItems: () => { const items = Array.from(this.#kids) .flatMap(i => [ - ...i.shadowRoot?.querySelectorAll('a') ?? [], - ...i.querySelectorAll('a') ?? [], + ...i.shadowRoot?.querySelectorAll?.('a') ?? [], + ...i.querySelectorAll?.('a') ?? [], ]); return items; }, }); - const active = this.querySelector('pf-jump-links-item[active]'); + const active = this.querySelector?.('pf-jump-links-item[active]'); if (active) { this.#setActiveItem(active); } @@ -150,7 +150,7 @@ export class PfJumpLinks extends LitElement { } #setActiveItem(item: PfJumpLinksItem) { - this.#tabindex?.setActiveItem(item.shadowRoot?.querySelector('a') ?? undefined); + this.#tabindex?.setActiveItem(item.shadowRoot?.querySelector?.('a') ?? undefined); this.#spy.setActive(item); } From d2493d748ec8804b396bd43d67634d34309adbc7 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 21 May 2024 11:13:03 +0300 Subject: [PATCH 62/83] fix(core): ssrable ScrollSpyController --- core/pfe-core/controllers/scroll-spy-controller.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/pfe-core/controllers/scroll-spy-controller.ts b/core/pfe-core/controllers/scroll-spy-controller.ts index 60c223d1ca..9468b3a547 100644 --- a/core/pfe-core/controllers/scroll-spy-controller.ts +++ b/core/pfe-core/controllers/scroll-spy-controller.ts @@ -44,7 +44,7 @@ export class ScrollSpyController implements ReactiveController { #rootMargin?: string; #threshold: number | number[]; - #rootNode: Node; + #getRootNode: () => Node; #getHash: (el: Element) => string | null; get #linkChildren(): Element[] { @@ -92,7 +92,7 @@ export class ScrollSpyController implements ReactiveController { this.#rootMargin = options.rootMargin; this.#activeAttribute = options.activeAttribute ?? 'active'; this.#threshold = options.threshold ?? 0.85; - this.#rootNode = options.rootNode ?? host.getRootNode(); + this.#getRootNode = () => options.rootNode ?? host.getRootNode(); this.#getHash = options?.getHash ?? ((el: Element) => el.getAttribute('href')); } @@ -101,7 +101,7 @@ export class ScrollSpyController implements ReactiveController { } #initIo() { - const rootNode = this.#rootNode; + const rootNode = this.#getRootNode(); if (rootNode instanceof Document || rootNode instanceof ShadowRoot) { const { rootMargin, threshold, root } = this; this.#io = new IntersectionObserver(r => this.#onIo(r), { root, rootMargin, threshold }); From 9ab5a8bed4b1e3715835d615959350cff5930fa4 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 21 May 2024 11:15:11 +0300 Subject: [PATCH 63/83] fix(progress-stepper): ssrable --- elements/pf-progress-stepper/pf-progress-step.ts | 3 +-- .../pf-progress-stepper/pf-progress-stepper.ts | 15 +++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/elements/pf-progress-stepper/pf-progress-step.ts b/elements/pf-progress-stepper/pf-progress-step.ts index d2c97189f6..c6cfc5f73e 100644 --- a/elements/pf-progress-stepper/pf-progress-step.ts +++ b/elements/pf-progress-stepper/pf-progress-step.ts @@ -57,7 +57,7 @@ export class PfProgressStep extends LitElement { const icon = this.icon ?? ICONS.get(this.variant ?? 'default')?.icon; const set = this.iconSet ?? ICONS.get(this.variant ?? 'default')?.set; const { parentTagName } = (this.constructor as typeof PfProgressStep); - const { compact = false } = this.closest(parentTagName) ?? {}; + const { compact = false } = this.closest?.(parentTagName) ?? {}; return html`
@@ -74,7 +74,6 @@ export class PfProgressStep extends LitElement { } updated(changed: PropertyValues) { - super.updated?.(changed); if (changed.has('current')) { this.#internals.ariaCurrent = String(!!this.current); } diff --git a/elements/pf-progress-stepper/pf-progress-stepper.ts b/elements/pf-progress-stepper/pf-progress-stepper.ts index 29331e5c12..8333d3a072 100644 --- a/elements/pf-progress-stepper/pf-progress-stepper.ts +++ b/elements/pf-progress-stepper/pf-progress-stepper.ts @@ -1,4 +1,4 @@ -import { LitElement, html } from 'lit'; +import { LitElement, html, type PropertyValues } from 'lit'; import { customElement } from 'lit/decorators/custom-element.js'; import { property } from 'lit/decorators/property.js'; import { observed } from '@patternfly/pfe-core/decorators/observed.js'; @@ -28,9 +28,6 @@ export class PfProgressStepper extends LitElement { @property({ type: Boolean, reflect: true }) center = false; /** Whether to use the compact layout */ - @observed(function(this: PfProgressStepper) { - this.querySelectorAll('pf-progress-step').forEach(step => step.requestUpdate()); - }) @property({ type: Boolean, reflect: true }) compact = false; #internals = InternalsController.of(this, { @@ -42,8 +39,8 @@ export class PfProgressStepper extends LitElement { get value() { const { childTagName } = (this.constructor as typeof PfProgressStepper); - const steps = this.querySelectorAll(childTagName); - const current = this.querySelector(`${childTagName}[current]`); + const steps = this.querySelectorAll?.(childTagName) ?? []; + const current = this.querySelector?.(`${childTagName}[current]`); const n = Array.from(steps).indexOf(current as PfProgressStep) + 1; return (n / steps.length) * 100; } @@ -62,6 +59,12 @@ export class PfProgressStepper extends LitElement { // eslint-disable-next-line lit-a11y/accessible-name return html`
`; } + + updated(changed: PropertyValues) { + if (changed.has('compact')) { + this.querySelectorAll?.('pf-progress-step').forEach(step => step.requestUpdate()); + } + } } declare global { From d49b640cf410de00efff910913fac4b80670d7c6 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 21 May 2024 11:59:37 +0300 Subject: [PATCH 64/83] fix(popover): ssrable --- elements/pf-popover/pf-popover.ts | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/elements/pf-popover/pf-popover.ts b/elements/pf-popover/pf-popover.ts index c739d4410b..0a1b22684d 100644 --- a/elements/pf-popover/pf-popover.ts +++ b/elements/pf-popover/pf-popover.ts @@ -1,4 +1,6 @@ -import { LitElement, nothing, html, type PropertyValues } from 'lit'; +import type { Placement } from '@patternfly/pfe-core/controllers/floating-dom-controller.js'; + +import { LitElement, nothing, html, type PropertyValues, isServer } from 'lit'; import { customElement } from 'lit/decorators/custom-element.js'; import { property } from 'lit/decorators/property.js'; import { query } from 'lit/decorators/query.js'; @@ -7,12 +9,13 @@ import { classMap } from 'lit/directives/class-map.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { FloatingDOMController } from '@patternfly/pfe-core/controllers/floating-dom-controller.js'; import { SlotController } from '@patternfly/pfe-core/controllers/slot-controller.js'; +import { deprecation } from '@patternfly/pfe-core/decorators/deprecation.js'; import { bound } from '@patternfly/pfe-core/decorators/bound.js'; import { ComposedEvent, StringListConverter } from '@patternfly/pfe-core/core.js'; -import type { Placement } from '@patternfly/pfe-core/controllers/floating-dom-controller.js'; + import '@patternfly/elements/pf-button/pf-button.js'; + import styles from './pf-popover.css'; -import { deprecation } from '@patternfly/pfe-core/decorators/deprecation.js'; const headingLevels = [2, 3, 4, 5, 6] as const; @@ -189,7 +192,7 @@ export class PfPopover extends LitElement { } satisfies Record) as [AlertSeverity, string][]); static { - document.addEventListener('click', function(event) { + !isServer && document.addEventListener('click', function(event) { for (const instance of PfPopover.instances) { if (!instance.noOutsideClick) { instance.#outsideClick(event); @@ -330,7 +333,7 @@ export class PfPopover extends LitElement { constructor() { super(); - this.addEventListener('keydown', this.#onKeydown); + !isServer && this.addEventListener('keydown', this.#onKeydown); } render() { @@ -412,8 +415,11 @@ export class PfPopover extends LitElement { } #getReferenceTrigger() { - const root = this.getRootNode() as Document | ShadowRoot; - return !this.trigger ? null : root.getElementById(this.trigger); + if (isServer || !this.trigger) { + return null; + } else { + return (this.getRootNode() as Document | ShadowRoot).getElementById(this.trigger); + } } #triggerChanged() { From 735b2f8c6dbdbc1c33214cac3beb1443992aa526 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 21 May 2024 14:12:35 +0300 Subject: [PATCH 65/83] fix(core): ssrable lbc --- core/pfe-core/controllers/listbox-controller.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/pfe-core/controllers/listbox-controller.ts b/core/pfe-core/controllers/listbox-controller.ts index 3dc85192f1..abcda1ec6f 100644 --- a/core/pfe-core/controllers/listbox-controller.ts +++ b/core/pfe-core/controllers/listbox-controller.ts @@ -1,4 +1,4 @@ -import type { ReactiveController, ReactiveControllerHost } from 'lit'; +import { isServer, type ReactiveController, type ReactiveControllerHost } from 'lit'; export interface ListboxAccessibilityController< Item extends HTMLElement @@ -56,7 +56,9 @@ export class ListboxController implements ReactiveCont if (!constructingAllowed) { throw new Error('ListboxController must be constructed with `ListboxController.of()`'); } - if (!(host instanceof HTMLElement) && typeof _options.getHTMLElement !== 'function') { + if (!isServer + && !(host instanceof HTMLElement) + && typeof _options.getHTMLElement !== 'function') { throw new Error( `ListboxController requires the host to be an HTMLElement, or for the initializer to include a \`getHTMLElement()\` function`, ); From 540b811b165a4fc15adb751e6a0026d0dcb25e97 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 21 May 2024 14:12:46 +0300 Subject: [PATCH 66/83] fix(icon): ssr --- elements/pf-icon/pf-icon.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/elements/pf-icon/pf-icon.ts b/elements/pf-icon/pf-icon.ts index 795865912c..1b6459217b 100644 --- a/elements/pf-icon/pf-icon.ts +++ b/elements/pf-icon/pf-icon.ts @@ -1,4 +1,4 @@ -import { LitElement, html, type PropertyValues } from 'lit'; +import { LitElement, html, isServer, type PropertyValues } from 'lit'; import { customElement } from 'lit/decorators/custom-element.js'; import { property } from 'lit/decorators/property.js'; import { state } from 'lit/decorators/state.js'; @@ -10,7 +10,10 @@ import style from './pf-icon.css'; export type URLGetter = (set: string, icon: string) => URL | string; /** requestIdleCallback when available, requestAnimationFrame when not */ -const ric = window.requestIdleCallback ?? window.requestAnimationFrame; +const ric: typeof globalThis.requestIdleCallback = + globalThis.requestIdleCallback + ?? globalThis.requestAnimationFrame + ?? (async (f: () => void) => Promise.resolve().then(f)); /** Fired when an icon fails to load */ class IconLoadError extends ErrorEvent { @@ -184,11 +187,11 @@ export class PfIcon extends LitElement { const mod = await import(spec); this.content = mod.default instanceof Node ? mod.default.cloneNode(true) : mod.default; await this.updateComplete; - this.dispatchEvent(new Event('load', { bubbles: true })); + isServer && this.dispatchEvent(new Event('load', { bubbles: true })); } catch (error: unknown) { const event = new IconLoadError(spec, error as Error); this.#logger.error((error as IconLoadError).message); - this.dispatchEvent(event); + isServer && this.dispatchEvent(event); } } } From 926987a66200579f4b280f6cadf89ddaefc40e83 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 21 May 2024 14:13:19 +0300 Subject: [PATCH 67/83] fix(select): ssrable --- elements/pf-select/pf-select.ts | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/elements/pf-select/pf-select.ts b/elements/pf-select/pf-select.ts index 8b1a265ab2..076a8e0df9 100644 --- a/elements/pf-select/pf-select.ts +++ b/elements/pf-select/pf-select.ts @@ -1,6 +1,6 @@ import type { PfChipRemoveEvent } from '@patternfly/elements/pf-chip/pf-chip.js'; -import { LitElement, html, type PropertyValues } from 'lit'; +import { LitElement, html, isServer, type PropertyValues } from 'lit'; import { customElement } from 'lit/decorators/custom-element.js'; import { property } from 'lit/decorators/property.js'; import { query } from 'lit/decorators/query.js'; @@ -144,12 +144,16 @@ export class PfSelect extends LitElement { * array of slotted options */ get options(): PfOption[] { - const opts = Array.from(this.querySelectorAll('pf-option')); - const placeholder = this.shadowRoot?.getElementById('placeholder') as PfOption | null; - if (placeholder) { - return [placeholder, ...opts]; + if (isServer) { + return []; // TODO: expose a DOM property to allow setting options in SSR scenarios } else { - return opts; + const opts = Array.from(this.querySelectorAll('pf-option')); + const placeholder = this.shadowRoot?.getElementById('placeholder') as PfOption | null; + if (placeholder) { + return [placeholder, ...opts]; + } else { + return opts; + } } } @@ -216,7 +220,7 @@ export class PfSelect extends LitElement { const { disabled, expanded, variant } = this; const { anchor = 'bottom', alignment = 'start', styles = {} } = this.#float; const { computedLabelText } = this.#internals; - const { height, width } = this.getBoundingClientRect() || {}; + const { height, width } = this.getBoundingClientRect?.() || {}; const buttonLabel = this.#buttonLabel; const hasBadge = this.#hasBadge; const selectedOptions = this.#listbox?.selectedOptions ?? []; @@ -458,7 +462,7 @@ export class PfSelect extends LitElement { #computePlaceholderText() { return this.placeholder - || this.querySelector('[slot=placeholder]') + || this.querySelector?.('[slot=placeholder]') ?.assignedNodes() ?.reduce((acc, node) => `${acc}${node.textContent}`, '')?.trim() || this.#listbox?.options From d18cd2f7f03f77e262016fed6f0c6b3513ec3433 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 21 May 2024 14:13:52 +0300 Subject: [PATCH 68/83] fix(table): ssrable --- elements/pf-table/pf-table.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/elements/pf-table/pf-table.ts b/elements/pf-table/pf-table.ts index 84be0cd5d1..0e07d9c47c 100644 --- a/elements/pf-table/pf-table.ts +++ b/elements/pf-table/pf-table.ts @@ -666,7 +666,7 @@ export class PfTable extends LitElement { static readonly styles = [styles]; get rows() { - return this.querySelectorAll(rowQuery); + return this.querySelectorAll?.(rowQuery); } @state() private columns = 0; @@ -678,7 +678,7 @@ export class PfTable extends LitElement { } render() { - const hasExpandableRow = !!this.querySelector('pf-tr[expandable]'); + const hasExpandableRow = !!this.querySelector?.('pf-tr[expandable]'); const coeffRows = hasExpandableRow ? '1' : '0'; return html` Date: Tue, 21 May 2024 14:14:06 +0300 Subject: [PATCH 69/83] fix(text-area): ssrable --- elements/pf-text-area/pf-text-area.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/elements/pf-text-area/pf-text-area.ts b/elements/pf-text-area/pf-text-area.ts index c39e160cb0..04dde1eb0b 100644 --- a/elements/pf-text-area/pf-text-area.ts +++ b/elements/pf-text-area/pf-text-area.ts @@ -1,4 +1,4 @@ -import { LitElement, html } from 'lit'; +import { LitElement, html, isServer } from 'lit'; import { customElement } from 'lit/decorators/custom-element.js'; import { property } from 'lit/decorators/property.js'; import { ifDefined } from 'lit/directives/if-defined.js'; @@ -186,6 +186,10 @@ export class PfTextArea extends LitElement { #derivedLabel = ''; + get #disabled() { + return (!isServer && this.matches(':disabled')) || this.disabled; + } + get #input() { return this.shadowRoot?.getElementById('textarea') as HTMLTextAreaElement ?? null; } @@ -201,7 +205,7 @@ export class PfTextArea extends LitElement {