refactor: make all components svelte5 compliant and update tests
This commit is contained in:
parent
3e0a19230d
commit
53d6d57854
3
packages/playwright-ct-svelte/index.d.ts
vendored
3
packages/playwright-ct-svelte/index.d.ts
vendored
|
|
@ -14,6 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import type { Snippet } from "svelte"
|
||||||
import type {
|
import type {
|
||||||
SvelteComponent as V4Component,
|
SvelteComponent as V4Component,
|
||||||
Component as V5Component,
|
Component as V5Component,
|
||||||
|
|
@ -21,7 +22,7 @@ import type {
|
||||||
} from 'svelte/types/runtime';
|
} 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 = Snippet | 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>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,10 @@
|
||||||
// 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 { asClassComponent } from 'svelte/legacy';
|
import { asClassComponent } from 'svelte/legacy';
|
||||||
|
import { createRawSnippet } from "svelte";
|
||||||
|
|
||||||
/** @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 {import('svelte').SvelteComponent} SvelteComponent */
|
/** @typedef {import('svelte').SvelteComponent} SvelteComponent */
|
||||||
/** @typedef {import('svelte').ComponentType} ComponentType */
|
/** @typedef {import('svelte').ComponentType} ComponentType */
|
||||||
|
|
||||||
|
|
@ -38,6 +38,30 @@ function isObjectComponent(component) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @type {( component: ObjectComponent ) => Record<string, any>} */
|
||||||
|
function extractParams(component) {
|
||||||
|
let {props, slots, on} = component;
|
||||||
|
|
||||||
|
slots = Object.fromEntries(
|
||||||
|
Object.entries(slots ?? {}).map(([key, snippet]) => {
|
||||||
|
if(typeof snippet === "string") {
|
||||||
|
console.log("ugraded", key);
|
||||||
|
return [key, createRawSnippet(() => ({render: () => snippet}))];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [key, snippet]
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
on = Object.fromEntries(
|
||||||
|
Object.entries(on ?? {}).map(([key, fn]) => {
|
||||||
|
return [`on${key}`, fn]
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return {props, slots, on};
|
||||||
|
}
|
||||||
|
|
||||||
const __pwSvelteComponentKey = Symbol('svelteComponent');
|
const __pwSvelteComponentKey = Symbol('svelteComponent');
|
||||||
|
|
||||||
window.playwrightMount = async (component, rootElement, hooksConfig) => {
|
window.playwrightMount = async (component, rootElement, hooksConfig) => {
|
||||||
|
|
@ -45,17 +69,20 @@ 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;
|
||||||
component.type = component.type;
|
|
||||||
|
|
||||||
/** @type {ComponentType} */
|
|
||||||
const componentCtor = asClassComponent(component.type);
|
const componentCtor = asClassComponent(component.type);
|
||||||
class App extends componentCtor {
|
class App extends componentCtor {
|
||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
|
if (!isObjectComponent(component))
|
||||||
|
throw new Error('JSX mount notation is not supported');
|
||||||
|
|
||||||
|
let {props, slots, on} = extractParams(component);
|
||||||
|
|
||||||
super({
|
super({
|
||||||
target: rootElement,
|
target: rootElement,
|
||||||
props: {
|
props: {
|
||||||
...objectComponent.props,
|
...props,
|
||||||
$$scope: {}
|
...slots,
|
||||||
|
...on,
|
||||||
},
|
},
|
||||||
...options
|
...options
|
||||||
});
|
});
|
||||||
|
|
@ -63,9 +90,7 @@ window.playwrightMount = async (component, rootElement, hooksConfig) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @type {SvelteComponent | undefined} */
|
/** @type {SvelteComponent | undefined} */
|
||||||
|
|
||||||
let svelteComponent;
|
let svelteComponent;
|
||||||
|
|
||||||
for (const hook of window.__pw_hooks_before_mount || []) {
|
for (const hook of window.__pw_hooks_before_mount || []) {
|
||||||
svelteComponent = await hook({ hooksConfig, App });
|
svelteComponent = await hook({ hooksConfig, App });
|
||||||
}
|
}
|
||||||
|
|
@ -76,9 +101,6 @@ window.playwrightMount = async (component, rootElement, hooksConfig) => {
|
||||||
|
|
||||||
rootElement[__pwSvelteComponentKey] = svelteComponent;
|
rootElement[__pwSvelteComponentKey] = svelteComponent;
|
||||||
|
|
||||||
for (const [key, listener] of Object.entries(objectComponent.on || {}))
|
|
||||||
svelteComponent.$on(key, event => listener(event.detail));
|
|
||||||
|
|
||||||
for (const hook of window.__pw_hooks_after_mount || [])
|
for (const hook of window.__pw_hooks_after_mount || [])
|
||||||
await hook({ hooksConfig, svelteComponent });
|
await hook({ hooksConfig, svelteComponent });
|
||||||
};
|
};
|
||||||
|
|
@ -101,8 +123,11 @@ window.playwrightUpdate = async (rootElement, component) => {
|
||||||
);
|
);
|
||||||
if (!svelteComponent) 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 || {}))
|
let {props, slots, on} = extractParams(component);
|
||||||
svelteComponent.$on(key, event => listener(event.detail));
|
|
||||||
|
|
||||||
if (component.props) svelteComponent.$set(component.props);
|
svelteComponent.$set({
|
||||||
|
...props,
|
||||||
|
...slots,
|
||||||
|
...on,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { createEventDispatcher } from "svelte";
|
const { title, onsubmit } = $props();
|
||||||
export let title;
|
|
||||||
const dispatch = createEventDispatcher();
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<button on:click={() => dispatch('submit', 'hello')}>{title}</button>
|
<button onclick={() => onsubmit('hello')}>{title}</button>
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,12 @@
|
||||||
<script>
|
<script>
|
||||||
import { update, remountCount } from '../store'
|
import { update, remountCount } from '../store'
|
||||||
import { createEventDispatcher } from "svelte";
|
const { count, onsubmit, main, children } = $props()
|
||||||
export let count;
|
|
||||||
const dispatch = createEventDispatcher();
|
|
||||||
update();
|
update();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<button on:click={() => dispatch('submit', 'hello')}>
|
<button onclick={() => onsubmit?.('hello')}>
|
||||||
<span data-testid="props">{count}</span>
|
<span data-testid="props">{count}</span>
|
||||||
<span data-testid="remount-count">{remountCount}</span>
|
<span data-testid="remount-count">{remountCount}</span>
|
||||||
<slot name="main" />
|
{@render main?.()}
|
||||||
<slot />
|
{@render children?.()}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
|
<script>
|
||||||
|
const {children} = $props()
|
||||||
|
</script>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h1>Welcome!</h1>
|
<h1>Welcome!</h1>
|
||||||
<main>
|
<main>
|
||||||
<slot />
|
{@render children?.()}
|
||||||
</main>
|
</main>
|
||||||
<footer>
|
<footer>
|
||||||
Thanks for visiting.
|
Thanks for visiting.
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,17 @@
|
||||||
|
<script>
|
||||||
|
const {header, main, footer} = $props()
|
||||||
|
|
||||||
|
console.log({header, main, footer});
|
||||||
|
</script>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<header>
|
<header>
|
||||||
<slot name="header" />
|
{@render header?.()}
|
||||||
</header>
|
</header>
|
||||||
<main>
|
<main>
|
||||||
<slot name="main" />
|
{@render main?.()}
|
||||||
</main>
|
</main>
|
||||||
<footer>
|
<footer>
|
||||||
<slot name="footer" />
|
{@render footer?.()}
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import NamedSlots from '@/components/NamedSlots.svelte';
|
||||||
test('render a default slot', async ({ mount }) => {
|
test('render a default slot', async ({ mount }) => {
|
||||||
const component = await mount(DefaultSlot, {
|
const component = await mount(DefaultSlot, {
|
||||||
slots: {
|
slots: {
|
||||||
default: 'Main Content',
|
children: 'Main Content',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
await expect(component).toContainText('Main Content');
|
await expect(component).toContainText('Main Content');
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue