feat(svelte): add support for svelte5
This commit is contained in:
parent
0bb5925d0d
commit
b1659fb42c
4262
package-lock.json
generated
4262
package-lock.json
generated
File diff suppressed because it is too large
Load diff
35
packages/playwright-ct-svelte/index.d.ts
vendored
35
packages/playwright-ct-svelte/index.d.ts
vendored
|
|
@ -14,33 +14,50 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { SvelteComponent, ComponentProps } from 'svelte/types/runtime';
|
import type {
|
||||||
|
SvelteComponent as V4Component,
|
||||||
|
Component as V5Component,
|
||||||
|
ComponentProps
|
||||||
|
} from 'svelte/types/runtime';
|
||||||
import type { TestType, Locator } from '@playwright/experimental-ct-core';
|
import type { TestType, Locator } from '@playwright/experimental-ct-core';
|
||||||
|
|
||||||
type ComponentSlot = string | string[];
|
type ComponentSlot = string | string[];
|
||||||
type ComponentSlots = Record<string, ComponentSlot> & { default?: ComponentSlot };
|
type ComponentSlots = Record<string, ComponentSlot> & { default?: ComponentSlot };
|
||||||
type ComponentEvents = Record<string, Function>;
|
type ComponentEvents = Record<string, Function>;
|
||||||
|
|
||||||
export interface MountOptions<HooksConfig, Component extends SvelteComponent> {
|
export interface MountOptions<
|
||||||
props?: ComponentProps<Component>;
|
HooksConfig,
|
||||||
|
Component extends (new (...args: any[]) => V4Component) | V5Component
|
||||||
|
> {
|
||||||
|
props?: ComponentProps<InstanceType<Component>>;
|
||||||
slots?: ComponentSlots;
|
slots?: ComponentSlots;
|
||||||
on?: ComponentEvents;
|
on?: ComponentEvents;
|
||||||
hooksConfig?: HooksConfig;
|
hooksConfig?: HooksConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MountResult<Component extends SvelteComponent> extends Locator {
|
export interface MountResult<
|
||||||
|
Component extends (new (...args: any[]) => V4Component) | V5Component
|
||||||
|
> extends Locator {
|
||||||
unmount(): Promise<void>;
|
unmount(): Promise<void>;
|
||||||
update(options: {
|
update(options: {
|
||||||
props?: Partial<ComponentProps<Component>>;
|
props?: Partial<ComponentProps<InstanceType<Component>>>;
|
||||||
on?: Partial<ComponentEvents>;
|
on?: Partial<ComponentEvents>;
|
||||||
}): Promise<void>;
|
}): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const test: TestType<{
|
export const test: TestType<{
|
||||||
mount<HooksConfig, Component extends SvelteComponent = SvelteComponent>(
|
mount<
|
||||||
component: new (...args: any[]) => Component,
|
HooksConfig,
|
||||||
options?: MountOptions<HooksConfig, Component>
|
Component extends (new (...args: any[]) => V4Component) | V5Component
|
||||||
|
>(
|
||||||
|
component: Component,
|
||||||
|
options?: MountOptions<HooksConfig, InstanceType<Component>>
|
||||||
): Promise<MountResult<Component>>;
|
): Promise<MountResult<Component>>;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export { defineConfig, PlaywrightTestConfig, expect, devices } from '@playwright/experimental-ct-core';
|
export {
|
||||||
|
defineConfig,
|
||||||
|
PlaywrightTestConfig,
|
||||||
|
expect,
|
||||||
|
devices
|
||||||
|
} from '@playwright/experimental-ct-core';
|
||||||
|
|
|
||||||
|
|
@ -31,10 +31,10 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@playwright/experimental-ct-core": "1.51.0-next",
|
"@playwright/experimental-ct-core": "1.51.0-next",
|
||||||
"@sveltejs/vite-plugin-svelte": "^3.0.1"
|
"@sveltejs/vite-plugin-svelte": "^5.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"svelte": "^4.2.19"
|
"svelte": "^5.19.9"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"playwright": "cli.js"
|
"playwright": "cli.js"
|
||||||
|
|
|
||||||
|
|
@ -18,51 +18,24 @@
|
||||||
|
|
||||||
// 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 as __pwDetach, insert as __pwInsert, noop as __pwNoop } from 'svelte/internal';
|
import { asClassComponent } from 'svelte/legacy';
|
||||||
|
|
||||||
/** @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').ObjectComponent} ObjectComponent */
|
/** @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 */
|
||||||
|
/** @typedef {import('svelte').ComponentType} ComponentType */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {any} component
|
* @param {any} component
|
||||||
* @returns {component is ObjectComponent}
|
* @returns {component is ObjectComponent}
|
||||||
*/
|
*/
|
||||||
function isObjectComponent(component) {
|
function isObjectComponent(component) {
|
||||||
return typeof component === 'object' && component && component.__pw_type === 'object-component';
|
return (
|
||||||
}
|
typeof component === 'object' &&
|
||||||
|
component &&
|
||||||
/**
|
component.__pw_type === 'object-component'
|
||||||
* TODO: remove this function when the following issue is fixed:
|
);
|
||||||
* https://github.com/sveltejs/svelte/issues/2588
|
|
||||||
*/
|
|
||||||
function __pwCreateSlots(slots) {
|
|
||||||
const svelteSlots = {};
|
|
||||||
|
|
||||||
for (const slotName in slots) {
|
|
||||||
const template = document
|
|
||||||
.createRange()
|
|
||||||
.createContextualFragment(slots[slotName]);
|
|
||||||
svelteSlots[slotName] = [createSlotFn(template)];
|
|
||||||
}
|
|
||||||
|
|
||||||
function createSlotFn(element) {
|
|
||||||
return function() {
|
|
||||||
return {
|
|
||||||
c: __pwNoop,
|
|
||||||
m: function mount(target, anchor) {
|
|
||||||
__pwInsert(target, element, anchor);
|
|
||||||
},
|
|
||||||
d: function destroy(detaching) {
|
|
||||||
if (detaching)
|
|
||||||
__pwDetach(element);
|
|
||||||
},
|
|
||||||
l: __pwNoop,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return svelteSlots;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const __pwSvelteComponentKey = Symbol('svelteComponent');
|
const __pwSvelteComponentKey = Symbol('svelteComponent');
|
||||||
|
|
@ -72,28 +45,34 @@ window.playwrightMount = async (component, rootElement, hooksConfig) => {
|
||||||
throw new Error('JSX mount notation is not supported');
|
throw new Error('JSX mount notation is not supported');
|
||||||
|
|
||||||
const objectComponent = component;
|
const objectComponent = component;
|
||||||
const componentCtor = component.type;
|
component.type = component.type;
|
||||||
|
|
||||||
|
/** @type {ComponentType} */
|
||||||
|
const componentCtor = asClassComponent(component.type);
|
||||||
class App extends componentCtor {
|
class App extends componentCtor {
|
||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
super({
|
super({
|
||||||
target: rootElement,
|
target: rootElement,
|
||||||
props: {
|
props: {
|
||||||
...objectComponent.props,
|
...objectComponent.props,
|
||||||
$$slots: __pwCreateSlots(objectComponent.slots),
|
$$scope: {}
|
||||||
$$scope: {},
|
|
||||||
},
|
},
|
||||||
...options
|
...options
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let svelteComponent;
|
/** @type {SvelteComponent | undefined} */
|
||||||
for (const hook of window.__pw_hooks_before_mount || [])
|
|
||||||
svelteComponent = await hook({ hooksConfig, App });
|
|
||||||
|
|
||||||
if (!svelteComponent)
|
let svelteComponent;
|
||||||
|
|
||||||
|
for (const hook of window.__pw_hooks_before_mount || []) {
|
||||||
|
svelteComponent = await hook({ hooksConfig, App });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!svelteComponent) {
|
||||||
svelteComponent = new App();
|
svelteComponent = new App();
|
||||||
|
}
|
||||||
|
|
||||||
rootElement[__pwSvelteComponentKey] = svelteComponent;
|
rootElement[__pwSvelteComponentKey] = svelteComponent;
|
||||||
|
|
||||||
|
|
@ -105,9 +84,10 @@ window.playwrightMount = async (component, rootElement, hooksConfig) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
window.playwrightUnmount = async rootElement => {
|
window.playwrightUnmount = async rootElement => {
|
||||||
const svelteComponent = /** @type {SvelteComponent} */ (rootElement[__pwSvelteComponentKey]);
|
const svelteComponent = /** @type {SvelteComponent} */ (
|
||||||
if (!svelteComponent)
|
rootElement[__pwSvelteComponentKey]
|
||||||
throw new Error('Component was not mounted');
|
);
|
||||||
|
if (!svelteComponent) throw new Error('Component was not mounted');
|
||||||
svelteComponent.$destroy();
|
svelteComponent.$destroy();
|
||||||
delete rootElement[__pwSvelteComponentKey];
|
delete rootElement[__pwSvelteComponentKey];
|
||||||
};
|
};
|
||||||
|
|
@ -116,13 +96,13 @@ window.playwrightUpdate = async (rootElement, component) => {
|
||||||
if (!isObjectComponent(component))
|
if (!isObjectComponent(component))
|
||||||
throw new Error('JSX mount notation is not supported');
|
throw new Error('JSX mount notation is not supported');
|
||||||
|
|
||||||
const svelteComponent = /** @type {SvelteComponent} */ (rootElement[__pwSvelteComponentKey]);
|
const svelteComponent = /** @type {SvelteComponent} */ (
|
||||||
if (!svelteComponent)
|
rootElement[__pwSvelteComponentKey]
|
||||||
throw new Error('Component was not mounted');
|
);
|
||||||
|
if (!svelteComponent) throw new Error('Component was not mounted');
|
||||||
|
|
||||||
for (const [key, listener] of Object.entries(component.on || {}))
|
for (const [key, listener] of Object.entries(component.on || {}))
|
||||||
svelteComponent.$on(key, event => listener(event.detail));
|
svelteComponent.$on(key, event => listener(event.detail));
|
||||||
|
|
||||||
if (component.props)
|
if (component.props) svelteComponent.$set(component.props);
|
||||||
svelteComponent.$set(component.props);
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue