chore(ct): do not clash internals with userland (#21774)

This commit is contained in:
Pavel Feldman 2023-03-17 18:08:28 -07:00 committed by GitHub
parent 36a1055524
commit d806c98009
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 156 additions and 154 deletions

View File

@ -14,6 +14,6 @@
* limitations under the License. * limitations under the License.
*/ */
export default function register( export default function pwRegister(
components: { [key: string]: any }, components: { [key: string]: any },
): void ): void

View File

@ -14,8 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
import { register } from './registerSource.mjs'; import { pwRegister } from './registerSource.mjs';
export default components => { export default components => {
register(components); pwRegister(components);
}; };

View File

@ -17,36 +17,36 @@
// @ts-check // @ts-check
// This file is injected into the registry as text, no dependencies are allowed. // This file is injected into the registry as text, no dependencies are allowed.
import * as React from 'react'; import * as __pwReact from 'react';
import { createRoot } from 'react-dom/client'; import { createRoot as __pwCreateRoot } from 'react-dom/client';
/** @typedef {import('../playwright-test/types/component').Component} Component */ /** @typedef {import('../playwright-test/types/component').Component} Component */
/** @typedef {import('react').FunctionComponent} FrameworkComponent */ /** @typedef {import('react').FunctionComponent} FrameworkComponent */
/** @type {Map<string, FrameworkComponent>} */ /** @type {Map<string, FrameworkComponent>} */
const registry = new Map(); const __pwRegistry = new Map();
/** @type {Map<Element, import('react-dom/client').Root>} */ /** @type {Map<Element, import('react-dom/client').Root>} */
const rootRegistry = new Map(); const __pwRootRegistry = new Map();
/** /**
* @param {{[key: string]: FrameworkComponent}} components * @param {{[key: string]: FrameworkComponent}} components
*/ */
export function register(components) { export function pwRegister(components) {
for (const [name, value] of Object.entries(components)) for (const [name, value] of Object.entries(components))
registry.set(name, value); __pwRegistry.set(name, value);
} }
/** /**
* @param {Component} component * @param {Component} component
*/ */
function render(component) { function __pwRender(component) {
if (typeof component !== 'object' || Array.isArray(component)) if (typeof component !== 'object' || Array.isArray(component))
return component; return component;
let componentFunc = registry.get(component.type); let componentFunc = __pwRegistry.get(component.type);
if (!componentFunc) { if (!componentFunc) {
// Lookup by shorthand. // Lookup by shorthand.
for (const [name, value] of registry) { for (const [name, value] of __pwRegistry) {
if (component.type.endsWith(`_${name}`)) { if (component.type.endsWith(`_${name}`)) {
componentFunc = value; componentFunc = value;
break; break;
@ -55,17 +55,17 @@ function render(component) {
} }
if (!componentFunc && component.type[0].toUpperCase() === component.type[0]) if (!componentFunc && component.type[0].toUpperCase() === component.type[0])
throw new Error(`Unregistered component: ${component.type}. Following components are registered: ${[...registry.keys()]}`); throw new Error(`Unregistered component: ${component.type}. Following components are registered: ${[...__pwRegistry.keys()]}`);
const componentFuncOrString = componentFunc || component.type; 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 React.createElement(componentFuncOrString, component.props, ...component.children.map(child => { return __pwReact.createElement(componentFuncOrString, component.props, ...component.children.map(child => {
if (typeof child === 'string') if (typeof child === 'string')
return child; return child;
return render(child); return __pwRender(child);
}).filter(child => { }).filter(child => {
if (typeof child === 'string') if (typeof child === 'string')
return !!child.trim(); return !!child.trim();
@ -74,21 +74,21 @@ function render(component) {
} }
window.playwrightMount = async (component, rootElement, hooksConfig) => { window.playwrightMount = async (component, rootElement, hooksConfig) => {
let App = () => render(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 });
if (wrapper) if (wrapper)
App = () => wrapper; App = () => wrapper;
} }
if (rootRegistry.has(rootElement)) { if (__pwRootRegistry.has(rootElement)) {
throw new Error( throw new Error(
'Attempting to mount a component into an container that already has a React root' 'Attempting to mount a component into an container that already has a React root'
); );
} }
const root = createRoot(rootElement); const root = __pwCreateRoot(rootElement);
rootRegistry.set(rootElement, root); __pwRootRegistry.set(rootElement, root);
root.render(App()); root.render(App());
for (const hook of window.__pw_hooks_after_mount || []) for (const hook of window.__pw_hooks_after_mount || [])
@ -96,18 +96,18 @@ window.playwrightMount = async (component, rootElement, hooksConfig) => {
}; };
window.playwrightUnmount = async rootElement => { window.playwrightUnmount = async rootElement => {
const root = rootRegistry.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');
root.unmount(); root.unmount();
rootRegistry.delete(rootElement); __pwRootRegistry.delete(rootElement);
}; };
window.playwrightUpdate = async (rootElement, component) => { window.playwrightUpdate = async (rootElement, component) => {
const root = rootRegistry.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');
root.render(render(/** @type {Component} */ (component))); root.render(__pwRender(/** @type {Component} */ (component)));
}; };

View File

@ -14,6 +14,6 @@
* limitations under the License. * limitations under the License.
*/ */
export default function register( export default function pwRegister(
components: { [key: string]: any }, components: { [key: string]: any },
): void ): void

View File

@ -14,8 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
import { register } from './registerSource.mjs'; import { pwRegister } from './registerSource.mjs';
export default components => { export default components => {
register(components); pwRegister(components);
}; };

View File

@ -17,34 +17,35 @@
// @ts-check // @ts-check
// This file is injected into the registry as text, no dependencies are allowed. // This file is injected into the registry as text, no dependencies are allowed.
import React from 'react'; // Don't clash with the user land.
import ReactDOM from 'react-dom'; import __pwReact from 'react';
import __pwReactDOM from 'react-dom';
/** @typedef {import('../playwright-test/types/component').Component} Component */ /** @typedef {import('../playwright-test/types/component').Component} Component */
/** @typedef {import('react').FunctionComponent} FrameworkComponent */ /** @typedef {import('react').FunctionComponent} FrameworkComponent */
/** @type {Map<string, FrameworkComponent>} */ /** @type {Map<string, FrameworkComponent>} */
const registry = new Map(); const __pwRegistry = new Map();
/** /**
* @param {{[key: string]: FrameworkComponent}} components * @param {{[key: string]: FrameworkComponent}} components
*/ */
export function register(components) { export function pwRegister(components) {
for (const [name, value] of Object.entries(components)) for (const [name, value] of Object.entries(components))
registry.set(name, value); __pwRegistry.set(name, value);
} }
/** /**
* @param {Component} component * @param {Component} component
*/ */
function render(component) { function __pwRender(component) {
if (typeof component !== 'object' || Array.isArray(component)) if (typeof component !== 'object' || Array.isArray(component))
return component; return component;
let componentFunc = registry.get(component.type); let componentFunc = __pwRegistry.get(component.type);
if (!componentFunc) { if (!componentFunc) {
// Lookup by shorthand. // Lookup by shorthand.
for (const [name, value] of registry) { for (const [name, value] of __pwRegistry) {
if (component.type.endsWith(`_${name}`)) { if (component.type.endsWith(`_${name}`)) {
componentFunc = value; componentFunc = value;
break; break;
@ -53,17 +54,17 @@ function render(component) {
} }
if (!componentFunc && component.type[0].toUpperCase() === component.type[0]) if (!componentFunc && component.type[0].toUpperCase() === component.type[0])
throw new Error(`Unregistered component: ${component.type}. Following components are registered: ${[...registry.keys()]}`); throw new Error(`Unregistered component: ${component.type}. Following components are registered: ${[...__pwRegistry.keys()]}`);
const componentFuncOrString = componentFunc || component.type; 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 React.createElement(componentFuncOrString, component.props, ...component.children.map(child => { return __pwReact.createElement(componentFuncOrString, component.props, ...component.children.map(child => {
if (typeof child === 'string') if (typeof child === 'string')
return child; return child;
return render(child); return __pwRender(child);
}).filter(child => { }).filter(child => {
if (typeof child === 'string') if (typeof child === 'string')
return !!child.trim(); return !!child.trim();
@ -72,24 +73,24 @@ function render(component) {
} }
window.playwrightMount = async (component, rootElement, hooksConfig) => { window.playwrightMount = async (component, rootElement, hooksConfig) => {
let App = () => render(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 });
if (wrapper) if (wrapper)
App = () => wrapper; App = () => wrapper;
} }
ReactDOM.render(App(), rootElement); __pwReactDOM.render(App(), rootElement);
for (const hook of window.__pw_hooks_after_mount || []) for (const hook of window.__pw_hooks_after_mount || [])
await hook({ hooksConfig }); await hook({ hooksConfig });
}; };
window.playwrightUnmount = async rootElement => { window.playwrightUnmount = async rootElement => {
if (!ReactDOM.unmountComponentAtNode(rootElement)) if (!__pwReactDOM.unmountComponentAtNode(rootElement))
throw new Error('Component was not mounted'); throw new Error('Component was not mounted');
}; };
window.playwrightUpdate = async (rootElement, component) => { window.playwrightUpdate = async (rootElement, component) => {
ReactDOM.render(render(/** @type {Component} */(component)), rootElement); __pwReactDOM.render(__pwRender(/** @type {Component} */(component)), rootElement);
}; };

View File

@ -14,6 +14,6 @@
* limitations under the License. * limitations under the License.
*/ */
export default function register( export default function pwRegister(
components: { [key: string]: any }, components: { [key: string]: any },
): void ): void

View File

@ -14,8 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
import { register } from './registerSource.mjs'; import { pwRegister } from './registerSource.mjs';
export default components => { export default components => {
register(components); pwRegister(components);
}; };

View File

@ -17,38 +17,38 @@
// @ts-check // @ts-check
// This file is injected into the registry as text, no dependencies are allowed. // This file is injected into the registry as text, no dependencies are allowed.
import { render as solidRender, createComponent as solidCreateComponent } from 'solid-js/web'; import { render as __pwSolidRender, createComponent as __pwSolidCreateComponent } from 'solid-js/web';
import h from 'solid-js/h'; import __pwH from 'solid-js/h';
/** @typedef {import('../playwright-test/types/component').Component} Component */ /** @typedef {import('../playwright-test/types/component').Component} Component */
/** @typedef {() => import('solid-js').JSX.Element} FrameworkComponent */ /** @typedef {() => import('solid-js').JSX.Element} FrameworkComponent */
/** @type {Map<string, FrameworkComponent>} */ /** @type {Map<string, FrameworkComponent>} */
const registry = new Map(); const __pwRegistry = new Map();
/** /**
* @param {{[key: string]: FrameworkComponent}} components * @param {{[key: string]: FrameworkComponent}} components
*/ */
export function register(components) { export function pwRegister(components) {
for (const [name, value] of Object.entries(components)) for (const [name, value] of Object.entries(components))
registry.set(name, value); __pwRegistry.set(name, value);
} }
function createChild(child) { function __pwCreateChild(child) {
return typeof child === 'string' ? child : createComponent(child); return typeof child === 'string' ? child : __pwCreateComponent(child);
} }
/** /**
* @param {Component} component * @param {Component} component
*/ */
function createComponent(component) { function __pwCreateComponent(component) {
if (typeof component !== 'object' || Array.isArray(component)) if (typeof component !== 'object' || Array.isArray(component))
return component; return component;
let Component = registry.get(component.type); let Component = __pwRegistry.get(component.type);
if (!Component) { if (!Component) {
// Lookup by shorthand. // Lookup by shorthand.
for (const [name, value] of registry) { for (const [name, value] of __pwRegistry) {
if (component.type.endsWith(`_${name}`)) { if (component.type.endsWith(`_${name}`)) {
Component = value; Component = value;
break; break;
@ -57,43 +57,43 @@ function createComponent(component) {
} }
if (!Component && component.type[0].toUpperCase() === component.type[0]) if (!Component && component.type[0].toUpperCase() === component.type[0])
throw new Error(`Unregistered component: ${component.type}. Following components are registered: ${[...registry.keys()]}`); 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');
const children = component.children.reduce((/** @type {any[]} */ children, current) => { const children = component.children.reduce((/** @type {any[]} */ children, current) => {
const child = createChild(current); const child = __pwCreateChild(current);
if (typeof child !== 'string' || !!child.trim()) if (typeof child !== 'string' || !!child.trim())
children.push(child); children.push(child);
return children; return children;
}, []); }, []);
if (!Component) if (!Component)
return h(component.type, component.props, children); return __pwH(component.type, component.props, children);
return solidCreateComponent(Component, { ...component.props, children }); return __pwSolidCreateComponent(Component, { ...component.props, children });
} }
const unmountKey = Symbol('unmountKey'); const __pwUnmountKey = Symbol('unmountKey');
window.playwrightMount = async (component, rootElement, hooksConfig) => { window.playwrightMount = async (component, rootElement, hooksConfig) => {
let App = () => createComponent(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 });
if (wrapper) if (wrapper)
App = () => wrapper; App = () => wrapper;
} }
const unmount = solidRender(App, rootElement); const unmount = __pwSolidRender(App, rootElement);
rootElement[unmountKey] = unmount; rootElement[__pwUnmountKey] = unmount;
for (const hook of window.__pw_hooks_after_mount || []) for (const hook of window.__pw_hooks_after_mount || [])
await hook({ hooksConfig }); await hook({ hooksConfig });
}; };
window.playwrightUnmount = async rootElement => { window.playwrightUnmount = async rootElement => {
const unmount = rootElement[unmountKey]; const unmount = rootElement[__pwUnmountKey];
if (!unmount) if (!unmount)
throw new Error('Component was not mounted'); throw new Error('Component was not mounted');

View File

@ -14,8 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
import { register } from './registerSource.mjs'; import { pwRegister } from './registerSource.mjs';
export default components => { export default components => {
register(components); pwRegister(components);
}; };

View File

@ -18,28 +18,28 @@
// This file is injected into the registry as text, no dependencies are allowed. // This file is injected into the registry as text, no dependencies are allowed.
import { detach, insert, noop } from 'svelte/internal'; import { detach as __pwDetach, insert as __pwInsert, noop as __pwNoop } from 'svelte/internal';
/** @typedef {import('../playwright-test/types/component').Component} Component */ /** @typedef {import('../playwright-test/types/component').Component} Component */
/** @typedef {any} FrameworkComponent */ /** @typedef {any} FrameworkComponent */
/** @typedef {import('svelte').SvelteComponent} SvelteComponent */ /** @typedef {import('svelte').SvelteComponent} SvelteComponent */
/** @type {Map<string, FrameworkComponent>} */ /** @type {Map<string, FrameworkComponent>} */
const registry = new Map(); const __pwRegistry = new Map();
/** /**
* @param {{[key: string]: FrameworkComponent}} components * @param {{[key: string]: FrameworkComponent}} components
*/ */
export function register(components) { export function pwRegister(components) {
for (const [name, value] of Object.entries(components)) for (const [name, value] of Object.entries(components))
registry.set(name, value); __pwRegistry.set(name, value);
} }
/** /**
* TODO: remove this function when the following issue is fixed: * TODO: remove this function when the following issue is fixed:
* https://github.com/sveltejs/svelte/issues/2588 * https://github.com/sveltejs/svelte/issues/2588
*/ */
function createSlots(slots) { function __pwCreateSlots(slots) {
const svelteSlots = {}; const svelteSlots = {};
for (const slotName in slots) { for (const slotName in slots) {
@ -52,27 +52,27 @@ function createSlots(slots) {
function createSlotFn(element) { function createSlotFn(element) {
return function() { return function() {
return { return {
c: noop, c: __pwNoop,
m: function mount(target, anchor) { m: function mount(target, anchor) {
insert(target, element, anchor); __pwInsert(target, element, anchor);
}, },
d: function destroy(detaching) { d: function destroy(detaching) {
if (detaching) detach(element); if (detaching) __pwDetach(element);
}, },
l: noop, l: __pwNoop,
}; };
}; };
} }
return svelteSlots; return svelteSlots;
} }
const svelteComponentKey = Symbol('svelteComponent'); const __pwSvelteComponentKey = Symbol('svelteComponent');
window.playwrightMount = async (component, rootElement, hooksConfig) => { window.playwrightMount = async (component, rootElement, hooksConfig) => {
let componentCtor = registry.get(component.type); let componentCtor = __pwRegistry.get(component.type);
if (!componentCtor) { if (!componentCtor) {
// Lookup by shorthand. // Lookup by shorthand.
for (const [name, value] of registry) { for (const [name, value] of __pwRegistry) {
if (component.type.endsWith(`_${name}_svelte`)) { if (component.type.endsWith(`_${name}_svelte`)) {
componentCtor = value; componentCtor = value;
break; break;
@ -81,7 +81,7 @@ window.playwrightMount = async (component, rootElement, hooksConfig) => {
} }
if (!componentCtor) if (!componentCtor)
throw new Error(`Unregistered component: ${component.type}. Following components are registered: ${[...registry.keys()]}`); 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');
@ -94,11 +94,11 @@ window.playwrightMount = async (component, rootElement, hooksConfig) => {
target: rootElement, target: rootElement,
props: { props: {
...component.options?.props, ...component.options?.props,
$$slots: createSlots(component.options?.slots), $$slots: __pwCreateSlots(component.options?.slots),
$$scope: {}, $$scope: {},
} }
})); }));
rootElement[svelteComponentKey] = svelteComponent; rootElement[__pwSvelteComponentKey] = svelteComponent;
for (const [key, listener] of Object.entries(component.options?.on || {})) for (const [key, listener] of Object.entries(component.options?.on || {}))
svelteComponent.$on(key, event => listener(event.detail)); svelteComponent.$on(key, event => listener(event.detail));
@ -108,14 +108,14 @@ window.playwrightMount = async (component, rootElement, hooksConfig) => {
}; };
window.playwrightUnmount = async rootElement => { window.playwrightUnmount = async rootElement => {
const svelteComponent = /** @type {SvelteComponent} */ (rootElement[svelteComponentKey]); const svelteComponent = /** @type {SvelteComponent} */ (rootElement[__pwSvelteComponentKey]);
if (!svelteComponent) if (!svelteComponent)
throw new Error('Component was not mounted'); throw new Error('Component was not mounted');
svelteComponent.$destroy(); svelteComponent.$destroy();
}; };
window.playwrightUpdate = async (rootElement, component) => { window.playwrightUpdate = async (rootElement, component) => {
const svelteComponent = /** @type {SvelteComponent} */ (rootElement[svelteComponentKey]); 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

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
export default function register( export default function pwRegister(
components: { [key: string]: any }, components: { [key: string]: any },
options?: { options?: {
createApp: any, createApp: any,

View File

@ -14,8 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
import { register } from './registerSource.mjs'; import { pwRegister } from './registerSource.mjs';
export default components => { export default components => {
register(components); pwRegister(components);
}; };

View File

@ -17,32 +17,32 @@
// This file is injected into the registry as text, no dependencies are allowed. // This file is injected into the registry as text, no dependencies are allowed.
import { createApp, setDevtoolsHook, h } from 'vue'; import { createApp as __pwCreateApp, setDevtoolsHook as __pwSetDevtoolsHook, h as __pwH } from 'vue';
import { compile } from '@vue/compiler-dom'; import { compile as __pwCompile } from '@vue/compiler-dom';
import * as Vue from 'vue'; import * as __pwVue from 'vue';
/** @typedef {import('@playwright/test/types/component').Component} Component */ /** @typedef {import('@playwright/test/types/component').Component} Component */
/** @typedef {import('vue').Component} FrameworkComponent */ /** @typedef {import('vue').Component} FrameworkComponent */
/** @type {Map<string, FrameworkComponent>} */ /** @type {Map<string, FrameworkComponent>} */
const registry = new Map(); const __pwRegistry = new Map();
/** /**
* @param {{[key: string]: FrameworkComponent}} components * @param {{[key: string]: FrameworkComponent}} components
*/ */
export function register(components) { export function pwRegister(components) {
for (const [name, value] of Object.entries(components)) for (const [name, value] of Object.entries(components))
registry.set(name, value); __pwRegistry.set(name, value);
} }
const allListeners = new Map(); const __pwAllListeners = new Map();
/** /**
* @param {Component | string} child * @param {Component | string} child
* @returns {import('vue').VNode | string} * @returns {import('vue').VNode | string}
*/ */
function createChild(child) { function __pwCreateChild(child) {
return typeof child === 'string' ? child : createWrapper(child); return typeof child === 'string' ? child : __pwCreateWrapper(child);
} }
/** /**
@ -57,7 +57,7 @@ function createChild(child) {
* *
* @param {string} html * @param {string} html
*/ */
function createSlot(html) { function __pwCreateSlot(html) {
let template = html.trim(); let template = html.trim();
const hasWrappingTemplate = template && template.startsWith('<template'); const hasWrappingTemplate = template && template.startsWith('<template');
@ -65,12 +65,12 @@ function createSlot(html) {
if (!hasWrappingTemplate) if (!hasWrappingTemplate)
template = `<template #default="params">${template}</template>`; template = `<template #default="params">${template}</template>`;
const { code } = compile(`<transition>${template}</transition>`, { const { code } = __pwCompile(`<transition>${template}</transition>`, {
mode: 'function', mode: 'function',
prefixIdentifiers: false prefixIdentifiers: false
}); });
const createRenderFunction = new Function('Vue', code); const createRenderFunction = new Function('Vue', code);
const renderFn = createRenderFunction(Vue); const renderFn = createRenderFunction(__pwVue);
return (ctx = {}) => { return (ctx = {}) => {
const result = renderFn(ctx); const result = renderFn(ctx);
const slotName = Object.keys(result.children)[0]; const slotName = Object.keys(result.children)[0];
@ -78,12 +78,12 @@ function createSlot(html) {
}; };
} }
function slotToFunction(slot) { function __pwSlotToFunction(slot) {
if (typeof slot === 'string') if (typeof slot === 'string')
return createSlot(slot)(); return __pwCreateSlot(slot)();
if (Array.isArray(slot)) if (Array.isArray(slot))
return slot.map(slot => createSlot(slot)()); return slot.map(slot => __pwCreateSlot(slot)());
throw Error(`Invalid slot received.`); throw Error(`Invalid slot received.`);
} }
@ -91,17 +91,17 @@ function slotToFunction(slot) {
/** /**
* @param {Component} component * @param {Component} component
*/ */
function createComponent(component) { function __pwCreateComponent(component) {
if (typeof component === 'string') if (typeof component === 'string')
return component; return component;
/** /**
* @type {import('vue').Component | string | undefined} * @type {import('vue').Component | string | undefined}
*/ */
let componentFunc = registry.get(component.type); let componentFunc = __pwRegistry.get(component.type);
if (!componentFunc) { if (!componentFunc) {
// Lookup by shorthand. // Lookup by shorthand.
for (const [name, value] of registry) { for (const [name, value] of __pwRegistry) {
if (component.type.endsWith(`_${name}_vue`)) { if (component.type.endsWith(`_${name}_vue`)) {
componentFunc = value; componentFunc = value;
break; break;
@ -110,7 +110,7 @@ function createComponent(component) {
} }
if (!componentFunc && component.type[0].toUpperCase() === component.type[0]) if (!componentFunc && component.type[0].toUpperCase() === component.type[0])
throw new Error(`Unregistered component: ${component.type}. Following components are registered: ${[...registry.keys()]}`); throw new Error(`Unregistered component: ${component.type}. Following components are registered: ${[...__pwRegistry.keys()]}`);
componentFunc = componentFunc || component.type; componentFunc = componentFunc || component.type;
@ -131,9 +131,9 @@ function createComponent(component) {
if (typeof child !== 'string' && child.type === 'template' && child.kind === 'jsx') { if (typeof child !== 'string' && child.type === 'template' && child.kind === 'jsx') {
const slotProperty = Object.keys(child.props).find(k => k.startsWith('v-slot:')); const slotProperty = Object.keys(child.props).find(k => k.startsWith('v-slot:'));
const slot = slotProperty ? slotProperty.substring('v-slot:'.length) : 'default'; const slot = slotProperty ? slotProperty.substring('v-slot:'.length) : 'default';
slots[slot] = child.children.map(createChild); slots[slot] = child.children.map(__pwCreateChild);
} else { } else {
children.push(createChild(child)); children.push(__pwCreateChild(child));
} }
} }
@ -154,9 +154,9 @@ function createComponent(component) {
// Vue test util syntax. // Vue test util syntax.
for (const [key, value] of Object.entries(component.options?.slots || {})) { for (const [key, value] of Object.entries(component.options?.slots || {})) {
if (key === 'default') if (key === 'default')
children.push(slotToFunction(value)); children.push(__pwSlotToFunction(value));
else else
slots[key] = slotToFunction(value); slots[key] = __pwSlotToFunction(value);
} }
props = component.options?.props || {}; props = component.options?.props || {};
for (const [key, value] of Object.entries(component.options?.on || {})) for (const [key, value] of Object.entries(component.options?.on || {}))
@ -175,7 +175,7 @@ function createComponent(component) {
return { Component: componentFunc, props, slots: lastArg, listeners }; return { Component: componentFunc, props, slots: lastArg, listeners };
} }
function wrapFunctions(slots) { function __pwWrapFunctions(slots) {
const slotsWithRenderFunctions = {}; const slotsWithRenderFunctions = {};
if (!Array.isArray(slots)) { if (!Array.isArray(slots)) {
for (const [key, value] of Object.entries(slots || {})) for (const [key, value] of Object.entries(slots || {}))
@ -190,23 +190,23 @@ function wrapFunctions(slots) {
* @param {Component} component * @param {Component} component
* @returns {import('vue').VNode | string} * @returns {import('vue').VNode | string}
*/ */
function createWrapper(component) { function __pwCreateWrapper(component) {
const { Component, props, slots, listeners } = createComponent(component); const { Component, props, slots, listeners } = __pwCreateComponent(component);
// @ts-ignore // @ts-ignore
const wrapper = h(Component, props, slots); const wrapper = __pwH(Component, props, slots);
allListeners.set(wrapper, listeners); __pwAllListeners.set(wrapper, listeners);
return wrapper; return wrapper;
} }
/** /**
* @returns {any} * @returns {any}
*/ */
function createDevTools() { function __pwCreateDevTools() {
return { return {
emit(eventType, ...payload) { emit(eventType, ...payload) {
if (eventType === 'component:emit') { if (eventType === 'component:emit') {
const [, componentVM, event, eventArgs] = payload; const [, componentVM, event, eventArgs] = payload;
for (const [wrapper, listeners] of allListeners) { for (const [wrapper, listeners] of __pwAllListeners) {
if (wrapper.component !== componentVM) if (wrapper.component !== componentVM)
continue; continue;
const listener = listeners[event]; const listener = listeners[event];
@ -219,44 +219,44 @@ function createDevTools() {
}; };
} }
const appKey = Symbol('appKey'); const __pwAppKey = Symbol('appKey');
const wrapperKey = Symbol('wrapperKey'); const __pwWrapperKey = Symbol('wrapperKey');
window.playwrightMount = async (component, rootElement, hooksConfig) => { window.playwrightMount = async (component, rootElement, hooksConfig) => {
const app = createApp({ const app = __pwCreateApp({
render: () => { render: () => {
const wrapper = createWrapper(component); const wrapper = __pwCreateWrapper(component);
rootElement[wrapperKey] = wrapper; rootElement[__pwWrapperKey] = wrapper;
return wrapper; return wrapper;
} }
}); });
setDevtoolsHook(createDevTools(), {}); __pwSetDevtoolsHook(__pwCreateDevTools(), {});
for (const hook of window.__pw_hooks_before_mount || []) for (const hook of window.__pw_hooks_before_mount || [])
await hook({ app, hooksConfig }); await hook({ app, hooksConfig });
const instance = app.mount(rootElement); const instance = app.mount(rootElement);
rootElement[appKey] = app; rootElement[__pwAppKey] = app;
for (const hook of window.__pw_hooks_after_mount || []) for (const hook of window.__pw_hooks_after_mount || [])
await hook({ app, hooksConfig, instance }); await hook({ app, hooksConfig, instance });
}; };
window.playwrightUnmount = async rootElement => { window.playwrightUnmount = async rootElement => {
const app = /** @type {import('vue').App} */ (rootElement[appKey]); const app = /** @type {import('vue').App} */ (rootElement[__pwAppKey]);
if (!app) if (!app)
throw new Error('Component was not mounted'); throw new Error('Component was not mounted');
app.unmount(); app.unmount();
}; };
window.playwrightUpdate = async (rootElement, options) => { window.playwrightUpdate = async (rootElement, options) => {
const wrapper = rootElement[wrapperKey]; const wrapper = rootElement[__pwWrapperKey];
if (!wrapper) if (!wrapper)
throw new Error('Component was not mounted'); throw new Error('Component was not mounted');
const { slots, listeners, props } = createComponent(options); const { slots, listeners, props } = __pwCreateComponent(options);
wrapper.component.slots = wrapFunctions(slots); wrapper.component.slots = __pwWrapFunctions(slots);
allListeners.set(wrapper, listeners); __pwAllListeners.set(wrapper, listeners);
for (const [key, value] of Object.entries(props)) for (const [key, value] of Object.entries(props))
wrapper.component.props[key] = value; wrapper.component.props[key] = value;

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
export default function register( export default function pwRegister(
components: { [key: string]: any }, components: { [key: string]: any },
options?: { options?: {
createApp: any, createApp: any,

View File

@ -14,8 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
import { register } from './registerSource.mjs'; import { pwRegister } from './registerSource.mjs';
export default components => { export default components => {
register(components); pwRegister(components);
}; };

View File

@ -18,27 +18,27 @@
// This file is injected into the registry as text, no dependencies are allowed. // This file is injected into the registry as text, no dependencies are allowed.
import Vue, { h } from 'vue'; import __pwVue, { h as __pwH } from 'vue';
/** @typedef {import('../playwright-test/types/component').Component} Component */ /** @typedef {import('../playwright-test/types/component').Component} Component */
/** @typedef {import('vue').Component} FrameworkComponent */ /** @typedef {import('vue').Component} FrameworkComponent */
/** @type {Map<string, FrameworkComponent>} */ /** @type {Map<string, FrameworkComponent>} */
const registry = new Map(); const __pwRegistry = new Map();
/** /**
* @param {{[key: string]: FrameworkComponent}} components * @param {{[key: string]: FrameworkComponent}} components
*/ */
export function register(components) { export function pwRegister(components) {
for (const [name, value] of Object.entries(components)) for (const [name, value] of Object.entries(components))
registry.set(name, value); __pwRegistry.set(name, value);
} }
/** /**
* @param {Component | string} child * @param {Component | string} child
*/ */
function createChild(child) { function __pwCreateChild(child) {
return typeof child === 'string' ? child : createWrapper(child); return typeof child === 'string' ? child : __pwCreateWrapper(child);
} }
/** /**
@ -48,7 +48,7 @@ function createChild(child) {
* @param {string} key * @param {string} key
* @return {boolean} * @return {boolean}
*/ */
function componentHasKeyInProps(Component, key) { function __pwComponentHasKeyInProps(Component, key) {
if (Array.isArray(Component.props)) if (Array.isArray(Component.props))
return Component.props.includes(key); return Component.props.includes(key);
@ -58,14 +58,14 @@ function componentHasKeyInProps(Component, key) {
/** /**
* @param {Component} component * @param {Component} component
*/ */
function createComponent(component) { function __pwCreateComponent(component) {
/** /**
* @type {import('vue').Component | string | undefined} * @type {import('vue').Component | string | undefined}
*/ */
let componentFunc = registry.get(component.type); let componentFunc = __pwRegistry.get(component.type);
if (!componentFunc) { if (!componentFunc) {
// Lookup by shorthand. // Lookup by shorthand.
for (const [name, value] of registry) { for (const [name, value] of __pwRegistry) {
if (component.type.endsWith(`_${name}_vue`)) { if (component.type.endsWith(`_${name}_vue`)) {
componentFunc = value; componentFunc = value;
break; break;
@ -74,7 +74,7 @@ function createComponent(component) {
} }
if (!componentFunc && component.type[0].toUpperCase() === component.type[0]) if (!componentFunc && component.type[0].toUpperCase() === component.type[0])
throw new Error(`Unregistered component: ${component.type}. Following components are registered: ${[...registry.keys()]}`); throw new Error(`Unregistered component: ${component.type}. Following components are registered: ${[...__pwRegistry.keys()]}`);
componentFunc = componentFunc || component.type; componentFunc = componentFunc || component.type;
@ -97,9 +97,9 @@ function createComponent(component) {
if (typeof child !== 'string' && child.type === 'template' && child.kind === 'jsx') { if (typeof child !== 'string' && child.type === 'template' && child.kind === 'jsx') {
const slotProperty = Object.keys(child.props).find(k => k.startsWith('v-slot:')); const slotProperty = Object.keys(child.props).find(k => k.startsWith('v-slot:'));
const slot = slotProperty ? slotProperty.substring('v-slot:'.length) : 'default'; const slot = slotProperty ? slotProperty.substring('v-slot:'.length) : 'default';
nodeData.scopedSlots[slot] = () => child.children.map(c => createChild(c)); nodeData.scopedSlots[slot] = () => child.children.map(c => __pwCreateChild(c));
} else { } else {
children.push(createChild(child)); children.push(__pwCreateChild(child));
} }
} }
@ -108,7 +108,7 @@ function createComponent(component) {
const event = key.substring('v-on:'.length); const event = key.substring('v-on:'.length);
nodeData.on[event] = value; nodeData.on[event] = value;
} else { } else {
if (isVueComponent && componentHasKeyInProps(componentFunc, key)) if (isVueComponent && __pwComponentHasKeyInProps(componentFunc, key))
nodeData.props[key] = value; nodeData.props[key] = value;
else else
nodeData.attrs[key] = value; nodeData.attrs[key] = value;
@ -120,7 +120,7 @@ function createComponent(component) {
// Vue test util syntax. // Vue test util syntax.
const options = component.options || {}; const options = component.options || {};
for (const [key, value] of Object.entries(options.slots || {})) { for (const [key, value] of Object.entries(options.slots || {})) {
const list = (Array.isArray(value) ? value : [value]).map(v => createChild(v)); const list = (Array.isArray(value) ? value : [value]).map(v => __pwCreateChild(v));
if (key === 'default') if (key === 'default')
children.push(...list); children.push(...list);
else else
@ -147,9 +147,9 @@ function createComponent(component) {
* @param {Component} component * @param {Component} component
* @returns {import('vue').VNode} * @returns {import('vue').VNode}
*/ */
function createWrapper(component) { function __pwCreateWrapper(component) {
const { Component, nodeData, slots } = createComponent(component); const { Component, nodeData, slots } = __pwCreateComponent(component);
const wrapper = h(Component, nodeData, slots); const wrapper = __pwH(Component, nodeData, slots);
return wrapper; return wrapper;
} }
@ -159,12 +159,12 @@ const wrapperKey = Symbol('wrapperKey');
window.playwrightMount = async (component, rootElement, hooksConfig) => { window.playwrightMount = async (component, rootElement, hooksConfig) => {
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 }); options = await hook({ hooksConfig, Vue: __pwVue });
const instance = new Vue({ const instance = new __pwVue({
...options, ...options,
render: () => { render: () => {
const wrapper = createWrapper(component); const wrapper = __pwCreateWrapper(component);
/** @type {any} */ (rootElement)[wrapperKey] = wrapper; /** @type {any} */ (rootElement)[wrapperKey] = wrapper;
return wrapper; return wrapper;
}, },
@ -190,7 +190,7 @@ window.playwrightUpdate = async (element, options) => {
throw new Error('Component was not mounted'); throw new Error('Component was not mounted');
const component = wrapper.componentInstance; const component = wrapper.componentInstance;
const { nodeData, slots } = createComponent(options); const { nodeData, slots } = __pwCreateComponent(options);
for (const [name, value] of Object.entries(nodeData.on || {})) { for (const [name, value] of Object.entries(nodeData.on || {})) {
component.$on(name, value); component.$on(name, value);

View File

@ -307,8 +307,9 @@ function vitePlugin(registerSource: string, relativeTemplateDir: string, buildIn
const indexTs = path.join(relativeTemplateDir, 'index.ts'); const indexTs = path.join(relativeTemplateDir, 'index.ts');
const indexTsx = path.join(relativeTemplateDir, 'index.tsx'); const indexTsx = path.join(relativeTemplateDir, 'index.tsx');
const indexJs = path.join(relativeTemplateDir, 'index.js'); const indexJs = path.join(relativeTemplateDir, 'index.js');
const indexJsx = path.join(relativeTemplateDir, 'index.jsx');
const idResolved = path.resolve(id); const idResolved = path.resolve(id);
if (!idResolved.endsWith(indexTs) && !idResolved.endsWith(indexTsx) && !idResolved.endsWith(indexJs)) if (!idResolved.endsWith(indexTs) && !idResolved.endsWith(indexTsx) && !idResolved.endsWith(indexJs) && !idResolved.endsWith(indexJsx))
return; return;
const folder = path.dirname(id); const folder = path.dirname(id);
@ -323,7 +324,7 @@ function vitePlugin(registerSource: string, relativeTemplateDir: string, buildIn
lines.push(`import ${alias} from '${importPath}';`); lines.push(`import ${alias} from '${importPath}';`);
} }
lines.push(`register({ ${[...componentRegistry.keys()].join(',\n ')} });`); lines.push(`pwRegister({ ${[...componentRegistry.keys()].join(',\n ')} });`);
return { return {
code: lines.join('\n'), code: lines.join('\n'),
map: { mappings: '' } map: { mappings: '' }