feat(ct): svelte rerender (#17940)

This commit is contained in:
sand4rt 2022-10-10 21:45:48 +02:00 committed by GitHub
parent 0f820aa7f3
commit 3a281364d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 118 additions and 7 deletions

View File

@ -42,22 +42,23 @@ type JsonObject = { [Key in string]?: JsonValue };
type Slot = string | string[];
export interface MountOptions<Component extends SvelteComponent> {
export interface MountOptions<Component extends SvelteComponent = SvelteComponent> {
props?: ComponentProps<Component>;
slots?: Record<string, Slot> & { default?: Slot };
on?: Record<string, Function>;
hooksConfig?: JsonObject;
}
interface MountResult extends Locator {
interface MountResult<Component extends SvelteComponent> extends Locator {
unmount(): Promise<void>;
rerender(options: Omit<MountOptions<Component>, 'hooksConfig'|'slots'>): Promise<void>
}
interface ComponentFixtures {
mount<Component extends SvelteComponent>(
component: new (...args: any[]) => Component,
options?: MountOptions<Component>
): Promise<MountResult>;
): Promise<MountResult<Component>>;
}
export const test: TestType<

View File

@ -66,6 +66,8 @@ function createSlots(slots) {
return svelteSlots;
}
const svelteComponentKey = Symbol('svelteComponent');
window.playwrightMount = async (component, rootElement, hooksConfig) => {
let componentCtor = registry.get(component.type);
if (!componentCtor) {
@ -98,11 +100,11 @@ window.playwrightMount = async (component, rootElement, hooksConfig) => {
}));
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 || {}))
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 => {
@ -112,4 +114,14 @@ window.playwrightUnmount = async rootElement => {
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);
};

View 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>

View File

@ -0,0 +1,4 @@
export let remountCount = 0;
export function update() {
remountCount++;
}

View File

@ -16,6 +16,7 @@
import { test, expect } from '@playwright/experimental-ct-svelte';
import Button from './components/Button.svelte';
import Counter from './components/Counter.svelte';
import DefaultSlot from './components/DefaultSlot.svelte';
import NamedSlots from './components/NamedSlots.svelte';
import MultiRoot from './components/MultiRoot.svelte';
@ -32,6 +33,36 @@ test('render props', async ({ mount }) => {
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 }) => {
const messages = []
const component = await mount(Button, {

View 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>

View File

@ -0,0 +1,4 @@
export let remountCount = 0;
export function update() {
remountCount++;
}

View File

@ -16,6 +16,7 @@
import { test, expect } from '@playwright/experimental-ct-svelte';
import Button from './components/Button.svelte';
import Counter from './components/Counter.svelte';
import Component from './components/Component.svelte';
import DefaultSlot from './components/DefaultSlot.svelte';
import NamedSlots from './components/NamedSlots.svelte'
@ -33,6 +34,36 @@ test('render props', async ({ mount }) => {
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 }) => {
const messages = []
const component = await mount(Button, {