feat(ct): code split for better performance and isolation (#22494)

This commit is contained in:
Sander 2023-04-26 03:08:34 +02:00 committed by GitHub
parent d34c4e99f5
commit 44e56d2404
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 283 additions and 117 deletions

View file

@ -322,9 +322,9 @@ function vitePlugin(registerSource: string, relativeTemplateDir: string, buildIn
for (const [alias, value] of componentRegistry) { for (const [alias, value] of componentRegistry) {
const importPath = value.isModuleOrAlias ? value.importPath : './' + path.relative(folder, value.importPath).replace(/\\/g, '/'); const importPath = value.isModuleOrAlias ? value.importPath : './' + path.relative(folder, value.importPath).replace(/\\/g, '/');
if (value.importedName) if (value.importedName)
lines.push(`import { ${value.importedName} as ${alias} } from '${importPath}';`); lines.push(`const ${alias} = () => import('${importPath}').then((mod) => mod.${value.importedName});`);
else else
lines.push(`import ${alias} from '${importPath}';`); lines.push(`const ${alias} = () => import('${importPath}').then((mod) => mod.default);`);
} }
lines.push(`pwRegister({ ${[...componentRegistry.keys()].join(',\n ')} });`); lines.push(`pwRegister({ ${[...componentRegistry.keys()].join(',\n ')} });`);

View file

@ -21,48 +21,74 @@ import * as __pwReact from 'react';
import { createRoot as __pwCreateRoot } from 'react-dom/client'; import { createRoot as __pwCreateRoot } from 'react-dom/client';
/** @typedef {import('../playwright-ct-core/types/component').Component} Component */ /** @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 {import('react').FunctionComponent} FrameworkComponent */ /** @typedef {import('react').FunctionComponent} FrameworkComponent */
/** @type {Map<string, () => Promise<FrameworkComponent>>} */
const __pwLoaderRegistry = new Map();
/** @type {Map<string, FrameworkComponent>} */ /** @type {Map<string, FrameworkComponent>} */
const __pwRegistry = new Map(); const __pwRegistry = new Map();
/** @type {Map<Element, import('react-dom/client').Root>} */ /** @type {Map<Element, import('react-dom/client').Root>} */
const __pwRootRegistry = new Map(); const __pwRootRegistry = new Map();
/** /**
* @param {{[key: string]: FrameworkComponent}} components * @param {{[key: string]: () => Promise<FrameworkComponent>}} components
*/ */
export function pwRegister(components) { export function pwRegister(components) {
for (const [name, value] of Object.entries(components)) for (const [name, value] of Object.entries(components))
__pwRegistry.set(name, value); __pwLoaderRegistry.set(name, value);
}
/**
* @param {Component} component
* @returns {component is JsxComponent | ObjectComponent}
*/
function isComponent(component) {
return !(typeof component !== 'object' || Array.isArray(component));
}
/**
* @param {Component} component
*/
async function __pwResolveComponent(component) {
if (!isComponent(component))
return
let componentFactory = __pwLoaderRegistry.get(component.type);
if (!componentFactory) {
// Lookup by shorthand.
for (const [name, value] of __pwLoaderRegistry) {
if (component.type.endsWith(`_${name}`)) {
componentFactory = value;
break;
}
}
}
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 ('children' in component)
await Promise.all(component.children.map(child => __pwResolveComponent(child)))
} }
/** /**
* @param {Component} component * @param {Component} component
*/ */
function __pwRender(component) { function __pwRender(component) {
if (typeof component !== 'object' || Array.isArray(component)) if (!isComponent(component))
return component; return component;
let componentFunc = __pwRegistry.get(component.type); const componentFunc = __pwRegistry.get(component.type);
if (!componentFunc) {
// Lookup by shorthand.
for (const [name, value] of __pwRegistry) {
if (component.type.endsWith(`_${name}`)) {
componentFunc = value;
break;
}
}
}
if (!componentFunc && component.type[0].toUpperCase() === component.type[0])
throw new Error(`Unregistered component: ${component.type}. Following components are registered: ${[...__pwRegistry.keys()]}`);
const componentFuncOrString = componentFunc || component.type;
if (component.kind !== 'jsx') if (component.kind !== 'jsx')
throw new Error('Object mount notation is not supported'); throw new Error('Object mount notation is not supported');
return __pwReact.createElement(componentFuncOrString, component.props, ...component.children.map(child => { return __pwReact.createElement(componentFunc || component.type, component.props, ...component.children.map(child => {
if (typeof child === 'string') if (typeof child === 'string')
return child; return child;
return __pwRender(child); return __pwRender(child);
@ -74,6 +100,7 @@ function __pwRender(component) {
} }
window.playwrightMount = async (component, rootElement, hooksConfig) => { window.playwrightMount = async (component, rootElement, hooksConfig) => {
await __pwResolveComponent(component);
let App = () => __pwRender(component); let App = () => __pwRender(component);
for (const hook of window.__pw_hooks_before_mount || []) { for (const hook of window.__pw_hooks_before_mount || []) {
const wrapper = await hook({ App, hooksConfig }); const wrapper = await hook({ App, hooksConfig });
@ -105,6 +132,7 @@ window.playwrightUnmount = async rootElement => {
}; };
window.playwrightUpdate = async (rootElement, component) => { window.playwrightUpdate = async (rootElement, component) => {
await __pwResolveComponent(component);
const root = __pwRootRegistry.get(rootElement); const root = __pwRootRegistry.get(rootElement);
if (root === undefined) if (root === undefined)
throw new Error('Component was not mounted'); throw new Error('Component was not mounted');

View file

@ -22,46 +22,72 @@ import __pwReact from 'react';
import __pwReactDOM from 'react-dom'; import __pwReactDOM from 'react-dom';
/** @typedef {import('../playwright-ct-core/types/component').Component} Component */ /** @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 {import('react').FunctionComponent} FrameworkComponent */ /** @typedef {import('react').FunctionComponent} FrameworkComponent */
/** @type {Map<string, FrameworkComponent>} */ /** @type {Map<string, () => Promise<FrameworkComponent>>} */
const __pwLoaderRegistry = new Map();
/** @type {Map<string, FrameworkComponent} */
const __pwRegistry = new Map(); const __pwRegistry = new Map();
/** /**
* @param {{[key: string]: FrameworkComponent}} components * @param {{[key: string]: () => Promise<FrameworkComponent>}} components
*/ */
export function pwRegister(components) { export function pwRegister(components) {
for (const [name, value] of Object.entries(components)) for (const [name, value] of Object.entries(components))
__pwRegistry.set(name, value); __pwLoaderRegistry.set(name, value);
}
/**
* @param {Component} component
* @returns {component is JsxComponent | ObjectComponent}
*/
function isComponent(component) {
return !(typeof component !== 'object' || Array.isArray(component));
}
/**
* @param {Component} component
*/
async function __pwResolveComponent(component) {
if (!isComponent(component))
return
let componentFactory = __pwLoaderRegistry.get(component.type);
if (!componentFactory) {
// Lookup by shorthand.
for (const [name, value] of __pwLoaderRegistry) {
if (component.type.endsWith(`_${name}`)) {
componentFactory = value;
break;
}
}
}
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 ('children' in component)
await Promise.all(component.children.map(child => __pwResolveComponent(child)))
} }
/** /**
* @param {Component} component * @param {Component} component
*/ */
function __pwRender(component) { function __pwRender(component) {
if (typeof component !== 'object' || Array.isArray(component)) if (!isComponent(component))
return component; return component;
let componentFunc = __pwRegistry.get(component.type); const componentFunc = __pwRegistry.get(component.type);
if (!componentFunc) {
// Lookup by shorthand.
for (const [name, value] of __pwRegistry) {
if (component.type.endsWith(`_${name}`)) {
componentFunc = value;
break;
}
}
}
if (!componentFunc && component.type[0].toUpperCase() === component.type[0])
throw new Error(`Unregistered component: ${component.type}. Following components are registered: ${[...__pwRegistry.keys()]}`);
const componentFuncOrString = componentFunc || component.type;
if (component.kind !== 'jsx') if (component.kind !== 'jsx')
throw new Error('Object mount notation is not supported'); throw new Error('Object mount notation is not supported');
return __pwReact.createElement(componentFuncOrString, component.props, ...component.children.map(child => { return __pwReact.createElement(componentFunc || component.type, component.props, ...component.children.map(child => {
if (typeof child === 'string') if (typeof child === 'string')
return child; return child;
return __pwRender(child); return __pwRender(child);
@ -73,6 +99,7 @@ function __pwRender(component) {
} }
window.playwrightMount = async (component, rootElement, hooksConfig) => { window.playwrightMount = async (component, rootElement, hooksConfig) => {
await __pwResolveComponent(component);
let App = () => __pwRender(component); let App = () => __pwRender(component);
for (const hook of window.__pw_hooks_before_mount || []) { for (const hook of window.__pw_hooks_before_mount || []) {
const wrapper = await hook({ App, hooksConfig }); const wrapper = await hook({ App, hooksConfig });
@ -92,5 +119,6 @@ window.playwrightUnmount = async rootElement => {
}; };
window.playwrightUpdate = async (rootElement, component) => { window.playwrightUpdate = async (rootElement, component) => {
await __pwResolveComponent(component);
__pwReactDOM.render(__pwRender(/** @type {Component} */(component)), rootElement); __pwReactDOM.render(__pwRender(/** @type {Component} */(component)), rootElement);
}; };

View file

@ -21,17 +21,57 @@ import { render as __pwSolidRender, createComponent as __pwSolidCreateComponent
import __pwH from 'solid-js/h'; import __pwH from 'solid-js/h';
/** @typedef {import('../playwright-ct-core/types/component').Component} Component */ /** @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 {() => import('solid-js').JSX.Element} FrameworkComponent */ /** @typedef {() => import('solid-js').JSX.Element} FrameworkComponent */
/** @type {Map<string, () => Promise<FrameworkComponent>>} */
const __pwLoaderRegistry = new Map();
/** @type {Map<string, FrameworkComponent>} */ /** @type {Map<string, FrameworkComponent>} */
const __pwRegistry = new Map(); const __pwRegistry = new Map();
/** /**
* @param {{[key: string]: FrameworkComponent}} components * @param {{[key: string]: () => Promise<FrameworkComponent>}} components
*/ */
export function pwRegister(components) { export function pwRegister(components) {
for (const [name, value] of Object.entries(components)) for (const [name, value] of Object.entries(components))
__pwRegistry.set(name, value); __pwLoaderRegistry.set(name, value);
}
/**
* @param {Component} component
* @returns {component is JsxComponent | ObjectComponent}
*/
function isComponent(component) {
return !(typeof component !== 'object' || Array.isArray(component));
}
/**
* @param {Component} component
*/
async function __pwResolveComponent(component) {
if (!isComponent(component))
return
let componentFactory = __pwLoaderRegistry.get(component.type);
if (!componentFactory) {
// Lookup by shorthand.
for (const [name, value] of __pwLoaderRegistry) {
if (component.type.endsWith(`_${name}`)) {
componentFactory = value;
break;
}
}
}
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 ('children' in component)
await Promise.all(component.children.map(child => __pwResolveComponent(child)))
} }
function __pwCreateChild(child) { function __pwCreateChild(child) {
@ -45,19 +85,7 @@ function __pwCreateComponent(component) {
if (typeof component !== 'object' || Array.isArray(component)) if (typeof component !== 'object' || Array.isArray(component))
return component; return component;
let Component = __pwRegistry.get(component.type); const componentFunc = __pwRegistry.get(component.type);
if (!Component) {
// Lookup by shorthand.
for (const [name, value] of __pwRegistry) {
if (component.type.endsWith(`_${name}`)) {
Component = value;
break;
}
}
}
if (!Component && component.type[0].toUpperCase() === component.type[0])
throw new Error(`Unregistered component: ${component.type}. Following components are registered: ${[...__pwRegistry.keys()]}`);
if (component.kind !== 'jsx') if (component.kind !== 'jsx')
throw new Error('Object mount notation is not supported'); throw new Error('Object mount notation is not supported');
@ -69,15 +97,16 @@ function __pwCreateComponent(component) {
return children; return children;
}, []); }, []);
if (!Component) if (!componentFunc)
return __pwH(component.type, component.props, children); return __pwH(component.type, component.props, children);
return __pwSolidCreateComponent(Component, { ...component.props, children }); return __pwSolidCreateComponent(componentFunc, { ...component.props, children });
} }
const __pwUnmountKey = Symbol('unmountKey'); const __pwUnmountKey = Symbol('unmountKey');
window.playwrightMount = async (component, rootElement, hooksConfig) => { window.playwrightMount = async (component, rootElement, hooksConfig) => {
await __pwResolveComponent(component);
let App = () => __pwCreateComponent(component); let App = () => __pwCreateComponent(component);
for (const hook of window.__pw_hooks_before_mount || []) { for (const hook of window.__pw_hooks_before_mount || []) {
const wrapper = await hook({ App, hooksConfig }); const wrapper = await hook({ App, hooksConfig });

View file

@ -21,18 +21,58 @@
import { detach as __pwDetach, insert as __pwInsert, noop as __pwNoop } from 'svelte/internal'; 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').Component} Component */
/** @typedef {import('../playwright-ct-core/types/component').JsxComponent} JsxComponent */
/** @typedef {import('../playwright-ct-core/types/component').ObjectComponent} ObjectComponent */
/** @typedef {any} FrameworkComponent */ /** @typedef {any} FrameworkComponent */
/** @typedef {import('svelte').SvelteComponent} SvelteComponent */ /** @typedef {import('svelte').SvelteComponent} SvelteComponent */
/** @type {Map<string, () => Promise<FrameworkComponent>>} */
const __pwLoaderRegistry = new Map();
/** @type {Map<string, FrameworkComponent>} */ /** @type {Map<string, FrameworkComponent>} */
const __pwRegistry = new Map(); const __pwRegistry = new Map();
/** /**
* @param {{[key: string]: FrameworkComponent}} components * @param {{[key: string]: () => Promise<FrameworkComponent>}} components
*/ */
export function pwRegister(components) { export function pwRegister(components) {
for (const [name, value] of Object.entries(components)) for (const [name, value] of Object.entries(components))
__pwRegistry.set(name, value); __pwLoaderRegistry.set(name, value);
}
/**
* @param {Component} component
* @returns {component is JsxComponent | ObjectComponent}
*/
function isComponent(component) {
return !(typeof component !== 'object' || Array.isArray(component));
}
/**
* @param {Component} component
*/
async function __pwResolveComponent(component) {
if (!isComponent(component))
return
let componentFactory = __pwLoaderRegistry.get(component.type);
if (!componentFactory) {
// Lookup by shorthand.
for (const [name, value] of __pwLoaderRegistry) {
if (component.type.endsWith(`_${name}_svelte`)) {
componentFactory = value;
break;
}
}
}
if (!componentFactory)
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)))
} }
/** /**
@ -69,19 +109,8 @@ function __pwCreateSlots(slots) {
const __pwSvelteComponentKey = Symbol('svelteComponent'); const __pwSvelteComponentKey = Symbol('svelteComponent');
window.playwrightMount = async (component, rootElement, hooksConfig) => { window.playwrightMount = async (component, rootElement, hooksConfig) => {
let componentCtor = __pwRegistry.get(component.type); await __pwResolveComponent(component);
if (!componentCtor) { const componentCtor = __pwRegistry.get(component.type);
// Lookup by shorthand.
for (const [name, value] of __pwRegistry) {
if (component.type.endsWith(`_${name}_svelte`)) {
componentCtor = value;
break;
}
}
}
if (!componentCtor)
throw new Error(`Unregistered component: ${component.type}. Following components are registered: ${[...__pwRegistry.keys()]}`);
if (component.kind !== 'object') if (component.kind !== 'object')
throw new Error('JSX mount notation is not supported'); throw new Error('JSX mount notation is not supported');
@ -115,6 +144,7 @@ window.playwrightUnmount = async rootElement => {
}; };
window.playwrightUpdate = async (rootElement, component) => { window.playwrightUpdate = async (rootElement, component) => {
await __pwResolveComponent(component);
const svelteComponent = /** @type {SvelteComponent} */ (rootElement[__pwSvelteComponentKey]); const svelteComponent = /** @type {SvelteComponent} */ (rootElement[__pwSvelteComponentKey]);
if (!svelteComponent) if (!svelteComponent)
throw new Error('Component was not mounted'); throw new Error('Component was not mounted');

View file

@ -21,18 +21,58 @@ import { createApp as __pwCreateApp, setDevtoolsHook as __pwSetDevtoolsHook, h a
import { compile as __pwCompile } from '@vue/compiler-dom'; import { compile as __pwCompile } from '@vue/compiler-dom';
import * as __pwVue from 'vue'; import * as __pwVue from 'vue';
/** @typedef {import('@playwright/test/types/experimentalComponent').Component} Component */ /** @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 {import('vue').Component} FrameworkComponent */ /** @typedef {import('vue').Component} FrameworkComponent */
/** @type {Map<string, () => Promise<FrameworkComponent>>} */
const __pwLoaderRegistry = new Map();
/** @type {Map<string, FrameworkComponent>} */ /** @type {Map<string, FrameworkComponent>} */
const __pwRegistry = new Map(); const __pwRegistry = new Map();
/** /**
* @param {{[key: string]: FrameworkComponent}} components * @param {{[key: string]: () => Promise<FrameworkComponent>}} components
*/ */
export function pwRegister(components) { export function pwRegister(components) {
for (const [name, value] of Object.entries(components)) for (const [name, value] of Object.entries(components))
__pwRegistry.set(name, value); __pwLoaderRegistry.set(name, value);
}
/**
* @param {Component} component
* @returns {component is JsxComponent | ObjectComponent}
*/
function isComponent(component) {
return !(typeof component !== 'object' || Array.isArray(component));
}
/**
* @param {Component} component
*/
async function __pwResolveComponent(component) {
if (!isComponent(component))
return
let componentFactory = __pwLoaderRegistry.get(component.type);
if (!componentFactory) {
// Lookup by shorthand.
for (const [name, value] of __pwLoaderRegistry) {
if (component.type.endsWith(`_${name}_vue`)) {
componentFactory = value;
break;
}
}
}
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 ('children' in component)
await Promise.all(component.children.map(child => __pwResolveComponent(child)))
} }
const __pwAllListeners = new Map(); const __pwAllListeners = new Map();
@ -95,23 +135,7 @@ function __pwCreateComponent(component) {
if (typeof component === 'string') if (typeof component === 'string')
return component; return component;
/**
* @type {import('vue').Component | string | undefined}
*/
let componentFunc = __pwRegistry.get(component.type); let componentFunc = __pwRegistry.get(component.type);
if (!componentFunc) {
// Lookup by shorthand.
for (const [name, value] of __pwRegistry) {
if (component.type.endsWith(`_${name}_vue`)) {
componentFunc = value;
break;
}
}
}
if (!componentFunc && component.type[0].toUpperCase() === component.type[0])
throw new Error(`Unregistered component: ${component.type}. Following components are registered: ${[...__pwRegistry.keys()]}`);
componentFunc = componentFunc || component.type; componentFunc = componentFunc || component.type;
const isVueComponent = componentFunc !== component.type; const isVueComponent = componentFunc !== component.type;
@ -223,6 +247,7 @@ const __pwAppKey = Symbol('appKey');
const __pwWrapperKey = Symbol('wrapperKey'); const __pwWrapperKey = Symbol('wrapperKey');
window.playwrightMount = async (component, rootElement, hooksConfig) => { window.playwrightMount = async (component, rootElement, hooksConfig) => {
await __pwResolveComponent(component);
const app = __pwCreateApp({ const app = __pwCreateApp({
render: () => { render: () => {
const wrapper = __pwCreateWrapper(component); const wrapper = __pwCreateWrapper(component);
@ -248,7 +273,8 @@ window.playwrightUnmount = async rootElement => {
app.unmount(); app.unmount();
}; };
window.playwrightUpdate = async (rootElement, options) => { window.playwrightUpdate = async (rootElement, component) => {
await __pwResolveComponent(component);
const wrapper = rootElement[__pwWrapperKey]; const wrapper = rootElement[__pwWrapperKey];
if (!wrapper) if (!wrapper)
throw new Error('Component was not mounted'); throw new Error('Component was not mounted');
@ -256,7 +282,7 @@ window.playwrightUpdate = async (rootElement, options) => {
if (!wrapper.component) if (!wrapper.component)
throw new Error('Updating a native HTML element is not supported'); throw new Error('Updating a native HTML element is not supported');
const { slots, listeners, props } = __pwCreateComponent(options); const { slots, listeners, props } = __pwCreateComponent(component);
wrapper.component.slots = __pwWrapFunctions(slots); wrapper.component.slots = __pwWrapFunctions(slots);
__pwAllListeners.set(wrapper, listeners); __pwAllListeners.set(wrapper, listeners);

View file

@ -21,17 +21,57 @@
import __pwVue, { h as __pwH } from 'vue'; import __pwVue, { h as __pwH } from 'vue';
/** @typedef {import('../playwright-ct-core/types/component').Component} Component */ /** @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 {import('vue').Component} FrameworkComponent */ /** @typedef {import('vue').Component} FrameworkComponent */
/** @type {Map<string, () => Promise<FrameworkComponent>>} */
const __pwLoaderRegistry = new Map();
/** @type {Map<string, FrameworkComponent>} */ /** @type {Map<string, FrameworkComponent>} */
const __pwRegistry = new Map(); const __pwRegistry = new Map();
/** /**
* @param {{[key: string]: FrameworkComponent}} components * @param {{[key: string]: () => Promise<FrameworkComponent>}} components
*/ */
export function pwRegister(components) { export function pwRegister(components) {
for (const [name, value] of Object.entries(components)) for (const [name, value] of Object.entries(components))
__pwRegistry.set(name, value); __pwLoaderRegistry.set(name, value);
}
/**
* @param {Component} component
* @returns {component is JsxComponent | ObjectComponent}
*/
function isComponent(component) {
return !(typeof component !== 'object' || Array.isArray(component));
}
/**
* @param {Component} component
*/
async function __pwResolveComponent(component) {
if (!isComponent(component))
return
let componentFactory = __pwLoaderRegistry.get(component.type);
if (!componentFactory) {
// Lookup by shorthand.
for (const [name, value] of __pwLoaderRegistry) {
if (component.type.endsWith(`_${name}_vue`)) {
componentFactory = value;
break;
}
}
}
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 ('children' in component)
await Promise.all(component.children.map(child => __pwResolveComponent(child)))
} }
/** /**
@ -59,25 +99,7 @@ function __pwComponentHasKeyInProps(Component, key) {
* @param {Component} component * @param {Component} component
*/ */
function __pwCreateComponent(component) { function __pwCreateComponent(component) {
/** const componentFunc = __pwRegistry.get(component.type) || component.type;
* @type {import('vue').Component | string | undefined}
*/
let componentFunc = __pwRegistry.get(component.type);
if (!componentFunc) {
// Lookup by shorthand.
for (const [name, value] of __pwRegistry) {
if (component.type.endsWith(`_${name}_vue`)) {
componentFunc = value;
break;
}
}
}
if (!componentFunc && component.type[0].toUpperCase() === component.type[0])
throw new Error(`Unregistered component: ${component.type}. Following components are registered: ${[...__pwRegistry.keys()]}`);
componentFunc = componentFunc || component.type;
const isVueComponent = componentFunc !== component.type; const isVueComponent = componentFunc !== component.type;
/** /**
@ -157,6 +179,7 @@ const instanceKey = Symbol('instanceKey');
const wrapperKey = Symbol('wrapperKey'); const wrapperKey = Symbol('wrapperKey');
window.playwrightMount = async (component, rootElement, hooksConfig) => { window.playwrightMount = async (component, rootElement, hooksConfig) => {
await __pwResolveComponent(component);
let options = {}; let options = {};
for (const hook of window.__pw_hooks_before_mount || []) for (const hook of window.__pw_hooks_before_mount || [])
options = await hook({ hooksConfig, Vue: __pwVue }); options = await hook({ hooksConfig, Vue: __pwVue });
@ -185,6 +208,7 @@ window.playwrightUnmount = async rootElement => {
}; };
window.playwrightUpdate = async (element, options) => { window.playwrightUpdate = async (element, options) => {
await __pwResolveComponent(options);
const wrapper = /** @type {any} */(element)[wrapperKey]; const wrapper = /** @type {any} */(element)[wrapperKey];
if (!wrapper) if (!wrapper)
throw new Error('Component was not mounted'); throw new Error('Component was not mounted');

View file

@ -17,3 +17,4 @@
import '../src/common.css'; import '../src/common.css';
import '../src/theme.ts'; import '../src/theme.ts';
import '../src/third_party/vscode/codicon.css'; import '../src/third_party/vscode/codicon.css';
import '../src/third_party/vscode/colors.css';