feat(ct): svelte rerender (#17940)
This commit is contained in:
parent
0f820aa7f3
commit
3a281364d8
7
packages/playwright-ct-svelte/index.d.ts
vendored
7
packages/playwright-ct-svelte/index.d.ts
vendored
|
|
@ -42,22 +42,23 @@ type JsonObject = { [Key in string]?: JsonValue };
|
||||||
|
|
||||||
type Slot = string | string[];
|
type Slot = string | string[];
|
||||||
|
|
||||||
export interface MountOptions<Component extends SvelteComponent> {
|
export interface MountOptions<Component extends SvelteComponent = SvelteComponent> {
|
||||||
props?: ComponentProps<Component>;
|
props?: ComponentProps<Component>;
|
||||||
slots?: Record<string, Slot> & { default?: Slot };
|
slots?: Record<string, Slot> & { default?: Slot };
|
||||||
on?: Record<string, Function>;
|
on?: Record<string, Function>;
|
||||||
hooksConfig?: JsonObject;
|
hooksConfig?: JsonObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MountResult extends Locator {
|
interface MountResult<Component extends SvelteComponent> extends Locator {
|
||||||
unmount(): Promise<void>;
|
unmount(): Promise<void>;
|
||||||
|
rerender(options: Omit<MountOptions<Component>, 'hooksConfig'|'slots'>): Promise<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ComponentFixtures {
|
interface ComponentFixtures {
|
||||||
mount<Component extends SvelteComponent>(
|
mount<Component extends SvelteComponent>(
|
||||||
component: new (...args: any[]) => Component,
|
component: new (...args: any[]) => Component,
|
||||||
options?: MountOptions<Component>
|
options?: MountOptions<Component>
|
||||||
): Promise<MountResult>;
|
): Promise<MountResult<Component>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const test: TestType<
|
export const test: TestType<
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,8 @@ function createSlots(slots) {
|
||||||
return svelteSlots;
|
return svelteSlots;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const svelteComponentKey = Symbol('svelteComponent');
|
||||||
|
|
||||||
window.playwrightMount = async (component, rootElement, hooksConfig) => {
|
window.playwrightMount = async (component, rootElement, hooksConfig) => {
|
||||||
let componentCtor = registry.get(component.type);
|
let componentCtor = registry.get(component.type);
|
||||||
if (!componentCtor) {
|
if (!componentCtor) {
|
||||||
|
|
@ -98,11 +100,11 @@ window.playwrightMount = async (component, rootElement, hooksConfig) => {
|
||||||
}));
|
}));
|
||||||
rootElement[svelteComponentKey] = svelteComponent;
|
rootElement[svelteComponentKey] = svelteComponent;
|
||||||
|
|
||||||
for (const hook of /** @type {any} */(window).__pw_hooks_after_mount || [])
|
|
||||||
await hook({ hooksConfig, 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));
|
||||||
|
|
||||||
|
for (const hook of /** @type {any} */(window).__pw_hooks_after_mount || [])
|
||||||
|
await hook({ hooksConfig, svelteComponent });
|
||||||
};
|
};
|
||||||
|
|
||||||
window.playwrightUnmount = async rootElement => {
|
window.playwrightUnmount = async rootElement => {
|
||||||
|
|
@ -112,4 +114,14 @@ window.playwrightUnmount = async rootElement => {
|
||||||
svelteComponent.$destroy();
|
svelteComponent.$destroy();
|
||||||
};
|
};
|
||||||
|
|
||||||
const svelteComponentKey = Symbol('svelteComponent');
|
window.playwrightRerender = async (rootElement, component) => {
|
||||||
|
const svelteComponent = /** @type {SvelteComponent} */ (rootElement[svelteComponentKey]);
|
||||||
|
if (!svelteComponent)
|
||||||
|
throw new Error('Component was not mounted');
|
||||||
|
|
||||||
|
for (const [key, listener] of Object.entries(component.options?.on || {}))
|
||||||
|
svelteComponent.$on(key, event => listener(event.detail));
|
||||||
|
|
||||||
|
if (component.options?.props)
|
||||||
|
svelteComponent.$set(component.options.props);
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { update, remountCount } from '../store'
|
||||||
|
import { createEventDispatcher } from "svelte";
|
||||||
|
export let count;
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
update();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div on:click={() => dispatch('submit', 'hello')}>
|
||||||
|
<div id="props">{count}</div>
|
||||||
|
<div id="remount-count">{remountCount}</div>
|
||||||
|
<slot name="main" />
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
4
tests/components/ct-svelte-vite/src/store/index.ts
Normal file
4
tests/components/ct-svelte-vite/src/store/index.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
export let remountCount = 0;
|
||||||
|
export function update() {
|
||||||
|
remountCount++;
|
||||||
|
}
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
import { test, expect } from '@playwright/experimental-ct-svelte';
|
import { test, expect } from '@playwright/experimental-ct-svelte';
|
||||||
import Button from './components/Button.svelte';
|
import Button from './components/Button.svelte';
|
||||||
|
import Counter from './components/Counter.svelte';
|
||||||
import DefaultSlot from './components/DefaultSlot.svelte';
|
import DefaultSlot from './components/DefaultSlot.svelte';
|
||||||
import NamedSlots from './components/NamedSlots.svelte';
|
import NamedSlots from './components/NamedSlots.svelte';
|
||||||
import MultiRoot from './components/MultiRoot.svelte';
|
import MultiRoot from './components/MultiRoot.svelte';
|
||||||
|
|
@ -32,6 +33,36 @@ test('render props', async ({ mount }) => {
|
||||||
await expect(component).toContainText('Submit')
|
await expect(component).toContainText('Submit')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('renderer updates props without remounting', async ({ mount }) => {
|
||||||
|
const component = await mount(Counter, {
|
||||||
|
props: { count: 9001 }
|
||||||
|
})
|
||||||
|
await expect(component.locator('#props')).toContainText('9001')
|
||||||
|
|
||||||
|
await component.rerender({
|
||||||
|
props: { count: 1337 }
|
||||||
|
})
|
||||||
|
await expect(component).not.toContainText('9001')
|
||||||
|
await expect(component.locator('#props')).toContainText('1337')
|
||||||
|
|
||||||
|
await expect(component.locator('#remount-count')).toContainText('1')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('renderer updates event listeners without remounting', async ({ mount }) => {
|
||||||
|
const component = await mount(Counter)
|
||||||
|
|
||||||
|
const messages: string[] = []
|
||||||
|
await component.rerender({
|
||||||
|
on: {
|
||||||
|
submit: (data: string) => messages.push(data)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await component.click();
|
||||||
|
expect(messages).toEqual(['hello'])
|
||||||
|
|
||||||
|
await expect(component.locator('#remount-count')).toContainText('1')
|
||||||
|
})
|
||||||
|
|
||||||
test('emit an submit event when the button is clicked', async ({ mount }) => {
|
test('emit an submit event when the button is clicked', async ({ mount }) => {
|
||||||
const messages = []
|
const messages = []
|
||||||
const component = await mount(Button, {
|
const component = await mount(Button, {
|
||||||
|
|
|
||||||
14
tests/components/ct-svelte/src/components/Counter.svelte
Normal file
14
tests/components/ct-svelte/src/components/Counter.svelte
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { update, remountCount } from '../store'
|
||||||
|
import { createEventDispatcher } from "svelte";
|
||||||
|
export let count;
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
update();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div on:click={() => dispatch('submit', 'hello')}>
|
||||||
|
<div id="props">{count}</div>
|
||||||
|
<div id="remount-count">{remountCount}</div>
|
||||||
|
<slot name="main" />
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
4
tests/components/ct-svelte/src/store/index.ts
Normal file
4
tests/components/ct-svelte/src/store/index.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
export let remountCount = 0;
|
||||||
|
export function update() {
|
||||||
|
remountCount++;
|
||||||
|
}
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
import { test, expect } from '@playwright/experimental-ct-svelte';
|
import { test, expect } from '@playwright/experimental-ct-svelte';
|
||||||
import Button from './components/Button.svelte';
|
import Button from './components/Button.svelte';
|
||||||
|
import Counter from './components/Counter.svelte';
|
||||||
import Component from './components/Component.svelte';
|
import Component from './components/Component.svelte';
|
||||||
import DefaultSlot from './components/DefaultSlot.svelte';
|
import DefaultSlot from './components/DefaultSlot.svelte';
|
||||||
import NamedSlots from './components/NamedSlots.svelte'
|
import NamedSlots from './components/NamedSlots.svelte'
|
||||||
|
|
@ -33,6 +34,36 @@ test('render props', async ({ mount }) => {
|
||||||
await expect(component).toContainText('Submit')
|
await expect(component).toContainText('Submit')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('renderer updates props without remounting', async ({ mount }) => {
|
||||||
|
const component = await mount(Counter, {
|
||||||
|
props: { count: 9001 }
|
||||||
|
})
|
||||||
|
await expect(component.locator('#props')).toContainText('9001')
|
||||||
|
|
||||||
|
await component.rerender({
|
||||||
|
props: { count: 1337 }
|
||||||
|
})
|
||||||
|
await expect(component).not.toContainText('9001')
|
||||||
|
await expect(component.locator('#props')).toContainText('1337')
|
||||||
|
|
||||||
|
await expect(component.locator('#remount-count')).toContainText('1')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('renderer updates event listeners without remounting', async ({ mount }) => {
|
||||||
|
const component = await mount(Counter)
|
||||||
|
|
||||||
|
const messages: string[] = []
|
||||||
|
await component.rerender({
|
||||||
|
on: {
|
||||||
|
submit: (data: string) => messages.push(data)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await component.click();
|
||||||
|
expect(messages).toEqual(['hello'])
|
||||||
|
|
||||||
|
await expect(component.locator('#remount-count')).toContainText('1')
|
||||||
|
})
|
||||||
|
|
||||||
test('emit an submit event when the button is clicked', async ({ mount }) => {
|
test('emit an submit event when the button is clicked', async ({ mount }) => {
|
||||||
const messages = []
|
const messages = []
|
||||||
const component = await mount(Button, {
|
const component = await mount(Button, {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue