feat(ct): allow unmounting components (#15974)
This commit is contained in:
parent
607910f6aa
commit
2eff208e54
8
package-lock.json
generated
8
package-lock.json
generated
|
|
@ -5770,7 +5770,6 @@
|
|||
"version": "3.49.0",
|
||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.49.0.tgz",
|
||||
"integrity": "sha512-+lmjic1pApJWDfPCpUUTc1m8azDqYCG1JN9YEngrx/hUyIcFJo6VZhj0A1Ai0wqoHcEIuQy+e9tk+4uDgdtsFA==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
|
|
@ -6490,6 +6489,9 @@
|
|||
"@sveltejs/vite-plugin-svelte": "^1.0.1",
|
||||
"vite": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"svelte": "^3.49.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
|
|
@ -7485,6 +7487,7 @@
|
|||
"requires": {
|
||||
"@playwright/test": "1.25.0-next",
|
||||
"@sveltejs/vite-plugin-svelte": "^1.0.1",
|
||||
"svelte": "*",
|
||||
"vite": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
@ -10959,8 +10962,7 @@
|
|||
"svelte": {
|
||||
"version": "3.49.0",
|
||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.49.0.tgz",
|
||||
"integrity": "sha512-+lmjic1pApJWDfPCpUUTc1m8azDqYCG1JN9YEngrx/hUyIcFJo6VZhj0A1Ai0wqoHcEIuQy+e9tk+4uDgdtsFA==",
|
||||
"peer": true
|
||||
"integrity": "sha512-+lmjic1pApJWDfPCpUUTc1m8azDqYCG1JN9YEngrx/hUyIcFJo6VZhj0A1Ai0wqoHcEIuQy+e9tk+4uDgdtsFA=="
|
||||
},
|
||||
"svelte-hmr": {
|
||||
"version": "0.14.12",
|
||||
|
|
|
|||
1
packages/playwright-ct-react/index.d.ts
vendored
1
packages/playwright-ct-react/index.d.ts
vendored
|
|
@ -36,6 +36,7 @@ export type PlaywrightTestConfig = Omit<BasePlaywrightTestConfig, 'use'> & {
|
|||
|
||||
export interface ComponentFixtures {
|
||||
mount(component: JSX.Element, options?: { hooksConfig?: any }): Promise<Locator>;
|
||||
unmount(component: Locator): Promise<void>;
|
||||
}
|
||||
|
||||
export const test: TestType<
|
||||
|
|
|
|||
|
|
@ -77,3 +77,8 @@ window.playwrightMount = async (component, rootElement, hooksConfig) => {
|
|||
for (const hook of /** @type {any} */(window).__pw_hooks_after_mount || [])
|
||||
await hook({ hooksConfig });
|
||||
};
|
||||
|
||||
window.playwrightUnmount = async (element, rootElement) => {
|
||||
if (!ReactDOM.unmountComponentAtNode(rootElement))
|
||||
throw new Error('Component was not mounted');
|
||||
};
|
||||
|
|
|
|||
4
packages/playwright-ct-svelte/hooks.d.ts
vendored
4
packages/playwright-ct-svelte/hooks.d.ts
vendored
|
|
@ -14,5 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { SvelteComponent } from "svelte";
|
||||
|
||||
export declare function beforeMount(callback: (params: { hooksConfig: any }) => Promise<void>): void;
|
||||
export declare function afterMount(callback: (params: { hooksConfig: any }) => Promise<void>): void;
|
||||
export declare function afterMount(callback: (params: { hooksConfig: any, svelteComponent: SvelteComponent }) => Promise<void>): void;
|
||||
|
|
|
|||
1
packages/playwright-ct-svelte/index.d.ts
vendored
1
packages/playwright-ct-svelte/index.d.ts
vendored
|
|
@ -47,6 +47,7 @@ interface ComponentFixtures {
|
|||
on?: { [key: string]: Function },
|
||||
hooksConfig?: any,
|
||||
}): Promise<Locator>;
|
||||
unmount(component: Locator): Promise<void>;
|
||||
}
|
||||
|
||||
export const test: TestType<
|
||||
|
|
|
|||
|
|
@ -26,8 +26,11 @@
|
|||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^1.0.1",
|
||||
"@playwright/test": "1.25.0-next",
|
||||
"@sveltejs/vite-plugin-svelte": "^1.0.1",
|
||||
"vite": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"svelte": "^3.49.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
/** @typedef {import('../playwright-test/types/component').Component} Component */
|
||||
/** @typedef {any} FrameworkComponent */
|
||||
/** @typedef {import('svelte').SvelteComponent} SvelteComponent */
|
||||
|
||||
/** @type {Map<string, FrameworkComponent>} */
|
||||
const registry = new Map();
|
||||
|
|
@ -54,14 +55,24 @@ window.playwrightMount = async (component, rootElement, hooksConfig) => {
|
|||
for (const hook of /** @type {any} */(window).__pw_hooks_before_mount || [])
|
||||
await hook({ hooksConfig });
|
||||
|
||||
const wrapper = new componentCtor({
|
||||
const svelteComponent = /** @type {SvelteComponent} */ (new componentCtor({
|
||||
target: rootElement,
|
||||
props: component.options?.props,
|
||||
});
|
||||
}));
|
||||
rootElement[svelteComponentKey] = svelteComponent;
|
||||
|
||||
for (const hook of /** @type {any} */(window).__pw_hooks_after_mount || [])
|
||||
await hook({ hooksConfig });
|
||||
await hook({ hooksConfig, svelteComponent });
|
||||
|
||||
for (const [key, listener] of Object.entries(component.options?.on || {}))
|
||||
wrapper.$on(key, event => listener(event.detail));
|
||||
svelteComponent.$on(key, event => listener(event.detail));
|
||||
};
|
||||
|
||||
window.playwrightUnmount = async (element, rootElement) => {
|
||||
const svelteComponent = /** @type {SvelteComponent} */ (rootElement[svelteComponentKey]);
|
||||
if (!svelteComponent)
|
||||
throw new Error('Component was not mounted');
|
||||
svelteComponent.$destroy();
|
||||
};
|
||||
|
||||
const svelteComponentKey = Symbol('svelteComponent');
|
||||
|
|
|
|||
1
packages/playwright-ct-vue/index.d.ts
vendored
1
packages/playwright-ct-vue/index.d.ts
vendored
|
|
@ -48,6 +48,7 @@ export interface ComponentFixtures {
|
|||
on?: { [key: string]: Function },
|
||||
hooksConfig?: any,
|
||||
}): Promise<Locator>;
|
||||
unmount(locator: Locator): Promise<void>;
|
||||
}
|
||||
|
||||
export const test: TestType<
|
||||
|
|
|
|||
|
|
@ -164,6 +164,16 @@ window.playwrightMount = async (component, rootElement, hooksConfig) => {
|
|||
for (const hook of /** @type {any} */(window).__pw_hooks_before_mount || [])
|
||||
await hook({ app, hooksConfig });
|
||||
const instance = app.mount(rootElement);
|
||||
instance.$el[appKey] = app;
|
||||
for (const hook of /** @type {any} */(window).__pw_hooks_after_mount || [])
|
||||
await hook({ app, hooksConfig, instance });
|
||||
};
|
||||
|
||||
window.playwrightUnmount = async element => {
|
||||
const app = /** @type {import('vue').App} */ (element[appKey]);
|
||||
if (!app)
|
||||
throw new Error('Component was not mounted');
|
||||
app.unmount();
|
||||
};
|
||||
|
||||
const appKey = Symbol('appKey');
|
||||
|
|
|
|||
1
packages/playwright-ct-vue2/index.d.ts
vendored
1
packages/playwright-ct-vue2/index.d.ts
vendored
|
|
@ -48,6 +48,7 @@ export interface ComponentFixtures {
|
|||
on?: { [key: string]: Function },
|
||||
hooksConfig?: any,
|
||||
}): Promise<Locator>;
|
||||
unmount(locator: Locator): Promise<void>;
|
||||
}
|
||||
|
||||
export const test: TestType<
|
||||
|
|
|
|||
|
|
@ -135,8 +135,6 @@ function render(component, h) {
|
|||
}
|
||||
|
||||
window.playwrightMount = async (component, rootElement, hooksConfig) => {
|
||||
const config = hooksConfig || /** @type {any} */(component).options?.hooksConfig;
|
||||
|
||||
for (const hook of /** @type {any} */(window).__pw_hooks_before_mount || [])
|
||||
await hook({ hooksConfig });
|
||||
|
||||
|
|
@ -144,7 +142,18 @@ window.playwrightMount = async (component, rootElement, hooksConfig) => {
|
|||
render: h => render(component, h),
|
||||
}).$mount();
|
||||
rootElement.appendChild(instance.$el);
|
||||
/** @type {any} */ (instance.$el)[instanceKey] = instance;
|
||||
|
||||
for (const hook of /** @type {any} */(window).__pw_hooks_after_mount || [])
|
||||
await hook({ hooksConfig, instance });
|
||||
};
|
||||
|
||||
window.playwrightUnmount = async element => {
|
||||
const component = /** @type {any} */(element)[instanceKey];
|
||||
if (!component)
|
||||
throw new Error('Component was not mounted');
|
||||
component.$destroy();
|
||||
element.remove();
|
||||
};
|
||||
|
||||
const instanceKey = Symbol('instanceKey');
|
||||
|
|
|
|||
|
|
@ -20,7 +20,10 @@ import type { Component, JsxComponent, ObjectComponentOptions } from '../types/c
|
|||
let boundCallbacksForMount: Function[] = [];
|
||||
|
||||
export const fixtures: Fixtures<
|
||||
PlaywrightTestArgs & PlaywrightTestOptions & { mount: (component: any, options: any) => Promise<Locator> },
|
||||
PlaywrightTestArgs & PlaywrightTestOptions & {
|
||||
mount: (component: any, options: any) => Promise<Locator>;
|
||||
unmount: (locator: Locator) => Promise<void>;
|
||||
},
|
||||
PlaywrightWorkerArgs & PlaywrightWorkerOptions & { _ctWorker: { context: BrowserContext | undefined, hash: string } },
|
||||
{ _contextFactory: (options?: BrowserContextOptions) => Promise<BrowserContext>, _contextReuseEnabled: boolean }> = {
|
||||
|
||||
|
|
@ -49,6 +52,15 @@ export const fixtures: Fixtures<
|
|||
});
|
||||
boundCallbacksForMount = [];
|
||||
},
|
||||
|
||||
unmount: async ({}, use) => {
|
||||
await use(async (locator: Locator) => {
|
||||
await locator.evaluate(async element => {
|
||||
const rootElement = document.getElementById('root')!;
|
||||
await window.playwrightUnmount(element, rootElement);
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
async function innerMount(page: Page, jsxOrType: JsxComponent | string, options: ObjectComponentOptions = {}): Promise<string> {
|
||||
|
|
|
|||
|
|
@ -39,5 +39,6 @@ export type Component = JsxComponent | ObjectComponent;
|
|||
declare global {
|
||||
interface Window {
|
||||
playwrightMount(component: Component, rootElement: Element, hooksConfig: any): Promise<void>;
|
||||
playwrightUnmount(element: Element, rootElement: Element): Promise<void>;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,3 +18,10 @@ test('should configure app', async ({ page, mount }) => {
|
|||
});
|
||||
expect(messages).toEqual(['Before mount: {\"route\":\"A\"}', 'After mount']);
|
||||
});
|
||||
|
||||
test('should unmount', async ({ page, mount, unmount }) => {
|
||||
const component = await mount(<App></App>);
|
||||
await expect(page.locator('#root')).toContainText('Hello Vite + React!');
|
||||
await unmount(component);
|
||||
await expect(page.locator('#root')).not.toContainText('Hello Vite + React!');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
"devDependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^1.0.1",
|
||||
"@tsconfig/svelte": "^2.0.1",
|
||||
"svelte": "^3.44.0",
|
||||
"svelte": "^3.49.0",
|
||||
"svelte-check": "^2.2.7",
|
||||
"svelte-preprocess": "^4.9.8",
|
||||
"tslib": "^2.3.1",
|
||||
|
|
|
|||
|
|
@ -47,3 +47,14 @@ test('should configure app', async ({ page, mount }) => {
|
|||
});
|
||||
expect(messages).toEqual(['Before mount: {\"route\":\"A\"}', 'After mount']);
|
||||
});
|
||||
|
||||
test('should unmount', async ({ page, mount, unmount }) => {
|
||||
const component = await mount(Counter, {
|
||||
props: {
|
||||
suffix: 'my suffix',
|
||||
},
|
||||
});
|
||||
await expect(page.locator('#root')).toContainText('my suffix')
|
||||
await unmount(component);
|
||||
await expect(page.locator('#root')).not.toContainText('my suffix');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -78,3 +78,14 @@ test('should run hooks', async ({ page, mount }) => {
|
|||
})
|
||||
expect(messages).toEqual(['Before mount: {\"route\":\"A\"}, app: true', 'After mount el: HTMLButtonElement'])
|
||||
})
|
||||
|
||||
test('should unmount', async ({ page, mount, unmount }) => {
|
||||
const component = await mount(Button, {
|
||||
props: {
|
||||
title: 'Submit'
|
||||
}
|
||||
})
|
||||
await expect(page.locator('#root')).toContainText('Submit')
|
||||
await unmount(component);
|
||||
await expect(page.locator('#root')).not.toContainText('Submit');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -72,3 +72,14 @@ test('should run hooks', async ({ page, mount }) => {
|
|||
})
|
||||
expect(messages).toEqual(['Before mount: {\"route\":\"A\"}', 'After mount el: HTMLButtonElement'])
|
||||
})
|
||||
|
||||
test('should unmount', async ({ page, mount, unmount }) => {
|
||||
const component = await mount(Button, {
|
||||
props: {
|
||||
title: 'Submit'
|
||||
}
|
||||
})
|
||||
await expect(page.locator('#root')).toContainText('Submit')
|
||||
await unmount(component);
|
||||
await expect(page.locator('#root')).not.toContainText('Submit');
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue