feat(ct): svelte vite context (#26554)

This commit is contained in:
Sander 2023-08-20 01:26:06 +02:00 committed by GitHub
parent 192b697488
commit e2a11bed19
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 55 additions and 20 deletions

View file

@ -14,11 +14,14 @@
* limitations under the License. * limitations under the License.
*/ */
import type { SvelteComponent } from 'svelte'; import type { ComponentConstructorOptions, SvelteComponent } from 'svelte';
import type { JsonObject } from '@playwright/experimental-ct-core/types/component'; import type { JsonObject } from '@playwright/experimental-ct-core/types/component';
export declare function beforeMount<HooksConfig extends JsonObject>( export declare function beforeMount<HooksConfig extends JsonObject>(
callback: (params: { hooksConfig?: HooksConfig }) => Promise<void> callback: (params: {
hooksConfig?: HooksConfig,
App: new (options: Partial<ComponentConstructorOptions>) => SvelteComponent
}) => Promise<SvelteComponent | void>
): void; ): void;
export declare function afterMount<HooksConfig extends JsonObject>( export declare function afterMount<HooksConfig extends JsonObject>(
callback: (params: { callback: (params: {

View file

@ -52,7 +52,7 @@ function isComponent(component) {
*/ */
async function __pwResolveComponent(component) { async function __pwResolveComponent(component) {
if (!isComponent(component)) if (!isComponent(component))
return return;
let componentFactory = __pwLoaderRegistry.get(component.type); let componentFactory = __pwLoaderRegistry.get(component.type);
if (!componentFactory) { if (!componentFactory) {
@ -68,7 +68,7 @@ async function __pwResolveComponent(component) {
if (!componentFactory) if (!componentFactory)
throw new Error(`Unregistered component: ${component.type}. Following components are registered: ${[...__pwRegistry.keys()]}`); throw new Error(`Unregistered component: ${component.type}. Following components are registered: ${[...__pwRegistry.keys()]}`);
if(componentFactory) if (componentFactory)
__pwRegistry.set(component.type, await componentFactory()) __pwRegistry.set(component.type, await componentFactory())
if ('children' in component) if ('children' in component)
@ -84,8 +84,8 @@ function __pwCreateSlots(slots) {
for (const slotName in slots) { for (const slotName in slots) {
const template = document const template = document
.createRange() .createRange()
.createContextualFragment(slots[slotName]); .createContextualFragment(slots[slotName]);
svelteSlots[slotName] = [createSlotFn(template)]; svelteSlots[slotName] = [createSlotFn(template)];
} }
@ -111,22 +111,31 @@ const __pwSvelteComponentKey = Symbol('svelteComponent');
window.playwrightMount = async (component, rootElement, hooksConfig) => { window.playwrightMount = async (component, rootElement, hooksConfig) => {
await __pwResolveComponent(component); await __pwResolveComponent(component);
const componentCtor = __pwRegistry.get(component.type); const componentCtor = __pwRegistry.get(component.type);
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');
class App extends componentCtor {
for (const hook of window.__pw_hooks_before_mount || []) constructor(options = {}) {
await hook({ hooksConfig }); super({
target: rootElement,
const svelteComponent = /** @type {SvelteComponent} */ (new componentCtor({ props: {
target: rootElement, ...component.options?.props,
props: { $$slots: __pwCreateSlots(component.options?.slots),
...component.options?.props, $$scope: {},
$$slots: __pwCreateSlots(component.options?.slots), },
$$scope: {}, ...options
});
} }
})); }
let svelteComponent;
for (const hook of window.__pw_hooks_before_mount || [])
svelteComponent = await hook({ hooksConfig, App });
if (!svelteComponent)
svelteComponent = new App();
rootElement[__pwSvelteComponentKey] = svelteComponent; rootElement[__pwSvelteComponentKey] = svelteComponent;
for (const [key, listener] of Object.entries(component.options?.on || {})) for (const [key, listener] of Object.entries(component.options?.on || {}))

View file

@ -2,11 +2,17 @@ import '../src/assets/index.css';
import { beforeMount, afterMount } from '@playwright/experimental-ct-svelte/hooks'; import { beforeMount, afterMount } from '@playwright/experimental-ct-svelte/hooks';
export type HooksConfig = { export type HooksConfig = {
route: string; context?: string;
route?: string;
} }
beforeMount<HooksConfig>(async ({ hooksConfig }) => { beforeMount<HooksConfig>(async ({ hooksConfig, App }) => {
console.log(`Before mount: ${JSON.stringify(hooksConfig)}`); console.log(`Before mount: ${JSON.stringify(hooksConfig)}`);
return new App({
context: new Map([
['context-key', hooksConfig?.context]
]),
});
}); });
afterMount<HooksConfig>(async () => { afterMount<HooksConfig>(async () => {

View file

@ -0,0 +1,6 @@
<script lang="ts">
import { getContext } from 'svelte';
const contextValue = getContext('context-key');
</script>
<div>{contextValue}</div>

View file

@ -1,6 +1,8 @@
import { test, expect } from '@playwright/experimental-ct-svelte'; import { test, expect } from '@playwright/experimental-ct-svelte';
import type { HooksConfig } from 'playwright';
import Button from '@/components/Button.svelte'; import Button from '@/components/Button.svelte';
import Empty from '@/components/Empty.svelte'; import Empty from '@/components/Empty.svelte';
import Context from '@/components/Context.svelte';
test('render props', async ({ mount }) => { test('render props', async ({ mount }) => {
const component = await mount(Button, { const component = await mount(Button, {
@ -17,3 +19,12 @@ test('get textContent of the empty component', async ({ mount }) => {
expect(await component.textContent()).toBe(''); expect(await component.textContent()).toBe('');
await expect(component).toHaveText(''); await expect(component).toHaveText('');
}); });
test('render context', async ({ mount }) => {
const component = await mount<HooksConfig>(Context, {
hooksConfig: {
context: 'context-value',
}
});
await expect(component).toContainText('context-value');
});