From 54ebee79f7ab81c25f834f3fb1a7915f64a6294c Mon Sep 17 00:00:00 2001 From: Sander Date: Thu, 26 Oct 2023 23:57:49 +0200 Subject: [PATCH] chore(ct): resolve internal type errors (#26779) --- .../playwright-ct-core/types/component.d.ts | 8 +++--- .../playwright-ct-react/registerSource.mjs | 22 ++++++++------- .../playwright-ct-react17/registerSource.mjs | 24 +++++++++-------- .../playwright-ct-solid/registerSource.mjs | 27 ++++++++++--------- .../playwright-ct-svelte/registerSource.mjs | 21 +++++++-------- packages/playwright-ct-vue/registerSource.mjs | 9 ++++--- .../playwright-ct-vue2/registerSource.mjs | 17 ++++++------ 7 files changed, 69 insertions(+), 59 deletions(-) diff --git a/packages/playwright-ct-core/types/component.d.ts b/packages/playwright-ct-core/types/component.d.ts index b4f1f7ecc5258..dc3ec2beaffd0 100644 --- a/packages/playwright-ct-core/types/component.d.ts +++ b/packages/playwright-ct-core/types/component.d.ts @@ -19,16 +19,18 @@ type JsonValue = JsonPrimitive | JsonObject | JsonArray; type JsonArray = JsonValue[]; export type JsonObject = { [Key in string]?: JsonValue }; +// JsxComponentChild can be anything, consider cases like: <>{1}, <>{null} +export type JsxComponentChild = JsxComponent | string | number | boolean | null; export type JsxComponent = { kind: 'jsx', type: string, props: Record, - children: (Component | string)[], + children: JsxComponentChild[], }; export type MountOptions = { props?: Record, - slots?: Record, + slots?: Record, on?: Record, hooksConfig?: any, }; @@ -39,7 +41,7 @@ export type ObjectComponent = { options?: MountOptions }; -export type Component = JsxComponent | ObjectComponent | number | string | Array; +export type Component = JsxComponent | ObjectComponent; declare global { interface Window { diff --git a/packages/playwright-ct-react/registerSource.mjs b/packages/playwright-ct-react/registerSource.mjs index e6380757a1418..76918b34fbc8c 100644 --- a/packages/playwright-ct-react/registerSource.mjs +++ b/packages/playwright-ct-react/registerSource.mjs @@ -20,9 +20,8 @@ import * as __pwReact from 'react'; import { createRoot as __pwCreateRoot } from 'react-dom/client'; -/** @typedef {import('../playwright-ct-core/types/component').Component} Component */ +/** @typedef {import('../playwright-ct-core/types/component').JsxComponentChild} JsxComponentChild */ /** @typedef {import('../playwright-ct-core/types/component').JsxComponent} JsxComponent */ -/** @typedef {import('../playwright-ct-core/types/component').ObjectComponent} ObjectComponent */ /** @typedef {import('react').FunctionComponent} FrameworkComponent */ /** @type {Map Promise>} */ @@ -41,15 +40,15 @@ export function pwRegister(components) { } /** - * @param {Component} component - * @returns {component is JsxComponent | ObjectComponent} + * @param {any} component + * @returns {component is JsxComponent} */ function isComponent(component) { return !(typeof component !== 'object' || Array.isArray(component)); } /** - * @param {Component} component + * @param {JsxComponent | JsxComponentChild} component */ async function __pwResolveComponent(component) { if (!isComponent(component)) @@ -77,7 +76,7 @@ async function __pwResolveComponent(component) { } /** - * @param {Component} component + * @param {JsxComponent | JsxComponentChild} component */ function __pwRender(component) { if (!isComponent(component)) @@ -85,9 +84,6 @@ function __pwRender(component) { const componentFunc = __pwRegistry.get(component.type); - if (component.kind !== 'jsx') - throw new Error('Object mount notation is not supported'); - return __pwReact.createElement(componentFunc || component.type, component.props, ...component.children.map(child => { if (typeof child === 'string') return child; @@ -100,6 +96,9 @@ function __pwRender(component) { } window.playwrightMount = async (component, rootElement, hooksConfig) => { + if (component.kind !== 'jsx') + throw new Error('Object mount notation is not supported'); + await __pwResolveComponent(component); let App = () => __pwRender(component); for (const hook of window.__pw_hooks_before_mount || []) { @@ -132,10 +131,13 @@ window.playwrightUnmount = async rootElement => { }; window.playwrightUpdate = async (rootElement, component) => { + if (component.kind !== 'jsx') + throw new Error('Object mount notation is not supported'); + await __pwResolveComponent(component); const root = __pwRootRegistry.get(rootElement); if (root === undefined) throw new Error('Component was not mounted'); - root.render(__pwRender(/** @type {Component} */ (component))); + root.render(__pwRender(component)); }; diff --git a/packages/playwright-ct-react17/registerSource.mjs b/packages/playwright-ct-react17/registerSource.mjs index 0a3bef1b5b663..076b3ad194a17 100644 --- a/packages/playwright-ct-react17/registerSource.mjs +++ b/packages/playwright-ct-react17/registerSource.mjs @@ -21,14 +21,13 @@ import __pwReact from 'react'; import __pwReactDOM from 'react-dom'; -/** @typedef {import('../playwright-ct-core/types/component').Component} Component */ +/** @typedef {import('../playwright-ct-core/types/component').JsxComponentChild} JsxComponentChild */ /** @typedef {import('../playwright-ct-core/types/component').JsxComponent} JsxComponent */ -/** @typedef {import('../playwright-ct-core/types/component').ObjectComponent} ObjectComponent */ /** @typedef {import('react').FunctionComponent} FrameworkComponent */ /** @type {Map Promise>} */ const __pwLoaderRegistry = new Map(); -/** @type {Map} */ const __pwRegistry = new Map(); /** @@ -40,15 +39,15 @@ export function pwRegister(components) { } /** - * @param {Component} component - * @returns {component is JsxComponent | ObjectComponent} + * @param {any} component + * @returns {component is JsxComponent} */ function isComponent(component) { return !(typeof component !== 'object' || Array.isArray(component)); } /** - * @param {Component} component + * @param {JsxComponent | JsxComponentChild} component */ async function __pwResolveComponent(component) { if (!isComponent(component)) @@ -76,7 +75,7 @@ async function __pwResolveComponent(component) { } /** - * @param {Component} component + * @param {JsxComponent | JsxComponentChild} component */ function __pwRender(component) { if (!isComponent(component)) @@ -84,9 +83,6 @@ function __pwRender(component) { const componentFunc = __pwRegistry.get(component.type); - if (component.kind !== 'jsx') - throw new Error('Object mount notation is not supported'); - return __pwReact.createElement(componentFunc || component.type, component.props, ...component.children.map(child => { if (typeof child === 'string') return child; @@ -99,6 +95,9 @@ function __pwRender(component) { } window.playwrightMount = async (component, rootElement, hooksConfig) => { + if (component.kind !== 'jsx') + throw new Error('Object mount notation is not supported'); + await __pwResolveComponent(component); let App = () => __pwRender(component); for (const hook of window.__pw_hooks_before_mount || []) { @@ -119,6 +118,9 @@ window.playwrightUnmount = async rootElement => { }; window.playwrightUpdate = async (rootElement, component) => { + if (component.kind !== 'jsx') + throw new Error('Object mount notation is not supported'); + await __pwResolveComponent(component); - __pwReactDOM.render(__pwRender(/** @type {Component} */(component)), rootElement); + __pwReactDOM.render(__pwRender(component), rootElement); }; diff --git a/packages/playwright-ct-solid/registerSource.mjs b/packages/playwright-ct-solid/registerSource.mjs index 04efe4b59e55b..a04d65c40494e 100644 --- a/packages/playwright-ct-solid/registerSource.mjs +++ b/packages/playwright-ct-solid/registerSource.mjs @@ -20,9 +20,8 @@ import { render as __pwSolidRender, createComponent as __pwSolidCreateComponent } from 'solid-js/web'; import __pwH from 'solid-js/h'; -/** @typedef {import('../playwright-ct-core/types/component').Component} Component */ +/** @typedef {import('../playwright-ct-core/types/component').JsxComponentChild} JsxComponentChild */ /** @typedef {import('../playwright-ct-core/types/component').JsxComponent} JsxComponent */ -/** @typedef {import('../playwright-ct-core/types/component').ObjectComponent} ObjectComponent */ /** @typedef {() => import('solid-js').JSX.Element} FrameworkComponent */ /** @type {Map Promise>} */ @@ -39,19 +38,19 @@ export function pwRegister(components) { } /** - * @param {Component} component - * @returns {component is JsxComponent | ObjectComponent} + * @param {any} component + * @returns {component is JsxComponent} */ function isComponent(component) { return !(typeof component !== 'object' || Array.isArray(component)); } /** - * @param {Component} component + * @param {JsxComponent | JsxComponentChild} component */ async function __pwResolveComponent(component) { if (!isComponent(component)) - return + return; let componentFactory = __pwLoaderRegistry.get(component.type); if (!componentFactory) { @@ -67,11 +66,11 @@ async function __pwResolveComponent(component) { if (!componentFactory && component.type[0].toUpperCase() === component.type[0]) throw new Error(`Unregistered component: ${component.type}. Following components are registered: ${[...__pwRegistry.keys()]}`); - if(componentFactory) - __pwRegistry.set(component.type, await componentFactory()) + if (componentFactory) + __pwRegistry.set(component.type, await componentFactory()); if ('children' in component) - await Promise.all(component.children.map(child => __pwResolveComponent(child))) + await Promise.all(component.children.map(child => __pwResolveComponent(child))); } function __pwCreateChild(child) { @@ -79,7 +78,7 @@ function __pwCreateChild(child) { } /** - * @param {Component} component + * @param {JsxComponent} component */ function __pwCreateComponent(component) { if (typeof component !== 'object' || Array.isArray(component)) @@ -87,8 +86,6 @@ function __pwCreateComponent(component) { const componentFunc = __pwRegistry.get(component.type); - if (component.kind !== 'jsx') - throw new Error('Object mount notation is not supported'); const children = component.children.reduce((/** @type {any[]} */ children, current) => { const child = __pwCreateChild(current); @@ -108,6 +105,9 @@ function __pwCreateComponent(component) { const __pwUnmountKey = Symbol('unmountKey'); window.playwrightMount = async (component, rootElement, hooksConfig) => { + if (component.kind !== 'jsx') + throw new Error('Object mount notation is not supported'); + await __pwResolveComponent(component); let App = () => __pwCreateComponent(component); for (const hook of window.__pw_hooks_before_mount || []) { @@ -132,6 +132,9 @@ window.playwrightUnmount = async rootElement => { }; window.playwrightUpdate = async (rootElement, component) => { + if (component.kind !== 'jsx') + throw new Error('Object mount notation is not supported'); + window.playwrightUnmount(rootElement); window.playwrightMount(component, rootElement, {}); }; diff --git a/packages/playwright-ct-svelte/registerSource.mjs b/packages/playwright-ct-svelte/registerSource.mjs index 10fd56f465e12..8cdd3e43ee54d 100644 --- a/packages/playwright-ct-svelte/registerSource.mjs +++ b/packages/playwright-ct-svelte/registerSource.mjs @@ -21,7 +21,6 @@ import { detach as __pwDetach, insert as __pwInsert, noop as __pwNoop } from 'svelte/internal'; /** @typedef {import('../playwright-ct-core/types/component').Component} Component */ -/** @typedef {import('../playwright-ct-core/types/component').JsxComponent} JsxComponent */ /** @typedef {import('../playwright-ct-core/types/component').ObjectComponent} ObjectComponent */ /** @typedef {any} FrameworkComponent */ /** @typedef {import('svelte').SvelteComponent} SvelteComponent */ @@ -40,15 +39,15 @@ export function pwRegister(components) { } /** - * @param {Component} component - * @returns {component is JsxComponent | ObjectComponent} + * @param {any} component + * @returns {component is ObjectComponent} */ function isComponent(component) { return !(typeof component !== 'object' || Array.isArray(component)); } /** - * @param {Component} component + * @param {ObjectComponent} component */ async function __pwResolveComponent(component) { if (!isComponent(component)) @@ -69,10 +68,7 @@ async function __pwResolveComponent(component) { throw new Error(`Unregistered component: ${component.type}. Following components are registered: ${[...__pwRegistry.keys()]}`); if (componentFactory) - __pwRegistry.set(component.type, await componentFactory()) - - if ('children' in component) - await Promise.all(component.children.map(child => __pwResolveComponent(child))) + __pwRegistry.set(component.type, await componentFactory()); } /** @@ -109,12 +105,12 @@ function __pwCreateSlots(slots) { const __pwSvelteComponentKey = Symbol('svelteComponent'); window.playwrightMount = async (component, rootElement, hooksConfig) => { - await __pwResolveComponent(component); - const componentCtor = __pwRegistry.get(component.type); - if (component.kind !== 'object') throw new Error('JSX mount notation is not supported'); + await __pwResolveComponent(component); + const componentCtor = __pwRegistry.get(component.type); + class App extends componentCtor { constructor(options = {}) { super({ @@ -153,6 +149,9 @@ window.playwrightUnmount = async rootElement => { }; window.playwrightUpdate = async (rootElement, component) => { + if (component.kind !== 'object') + throw new Error('JSX mount notation is not supported'); + await __pwResolveComponent(component); const svelteComponent = /** @type {SvelteComponent} */ (rootElement[__pwSvelteComponentKey]); if (!svelteComponent) diff --git a/packages/playwright-ct-vue/registerSource.mjs b/packages/playwright-ct-vue/registerSource.mjs index 4bd9c2b67d6bc..407ee9ed5a495 100644 --- a/packages/playwright-ct-vue/registerSource.mjs +++ b/packages/playwright-ct-vue/registerSource.mjs @@ -22,6 +22,7 @@ import { compile as __pwCompile } from '@vue/compiler-dom'; import * as __pwVue from 'vue'; /** @typedef {import('../playwright-ct-core/types/component').Component} Component */ +/** @typedef {import('../playwright-ct-core/types/component').JsxComponentChild} JsxComponentChild */ /** @typedef {import('../playwright-ct-core/types/component').JsxComponent} JsxComponent */ /** @typedef {import('../playwright-ct-core/types/component').ObjectComponent} ObjectComponent */ /** @typedef {import('vue').Component} FrameworkComponent */ @@ -40,15 +41,15 @@ export function pwRegister(components) { } /** - * @param {Component} component - * @returns {component is JsxComponent | ObjectComponent} + * @param {any} component + * @returns {component is Component} */ function isComponent(component) { return !(typeof component !== 'object' || Array.isArray(component)); } /** - * @param {Component} component + * @param {Component | JsxComponentChild} component */ async function __pwResolveComponent(component) { if (!isComponent(component)) @@ -78,7 +79,7 @@ async function __pwResolveComponent(component) { const __pwAllListeners = new Map(); /** - * @param {Component | string} child + * @param {JsxComponentChild} child * @returns {import('vue').VNode | string} */ function __pwCreateChild(child) { diff --git a/packages/playwright-ct-vue2/registerSource.mjs b/packages/playwright-ct-vue2/registerSource.mjs index 4c2741907c855..f6985fc97ffd3 100644 --- a/packages/playwright-ct-vue2/registerSource.mjs +++ b/packages/playwright-ct-vue2/registerSource.mjs @@ -21,6 +21,7 @@ import __pwVue, { h as __pwH } from 'vue'; /** @typedef {import('../playwright-ct-core/types/component').Component} Component */ +/** @typedef {import('../playwright-ct-core/types/component').JsxComponentChild} JsxComponentChild */ /** @typedef {import('../playwright-ct-core/types/component').JsxComponent} JsxComponent */ /** @typedef {import('../playwright-ct-core/types/component').ObjectComponent} ObjectComponent */ /** @typedef {import('vue').Component} FrameworkComponent */ @@ -39,19 +40,19 @@ export function pwRegister(components) { } /** - * @param {Component} component - * @returns {component is JsxComponent | ObjectComponent} + * @param {any} component + * @returns {component is Component} */ function isComponent(component) { return !(typeof component !== 'object' || Array.isArray(component)); } /** - * @param {Component} component + * @param {Component | JsxComponentChild} component */ async function __pwResolveComponent(component) { if (!isComponent(component)) - return + return; let componentFactory = __pwLoaderRegistry.get(component.type); if (!componentFactory) { @@ -67,15 +68,15 @@ async function __pwResolveComponent(component) { if (!componentFactory && component.type[0].toUpperCase() === component.type[0]) throw new Error(`Unregistered component: ${component.type}. Following components are registered: ${[...__pwRegistry.keys()]}`); - if(componentFactory) - __pwRegistry.set(component.type, await componentFactory()) + if (componentFactory) + __pwRegistry.set(component.type, await componentFactory()); if ('children' in component) - await Promise.all(component.children.map(child => __pwResolveComponent(child))) + await Promise.all(component.children.map(child => __pwResolveComponent(child))); } /** - * @param {Component | string} child + * @param {Component | JsxComponentChild} child */ function __pwCreateChild(child) { return typeof child === 'string' ? child : __pwCreateWrapper(child);