diff --git a/playwright/index.html b/playwright/index.html index 471b436..610ddf8 100644 --- a/playwright/index.html +++ b/playwright/index.html @@ -7,6 +7,6 @@
- + diff --git a/playwright/index.ts b/playwright/index.ts deleted file mode 100644 index e69de29..0000000 diff --git a/playwright/index.tsx b/playwright/index.tsx new file mode 100644 index 0000000..32977e4 --- /dev/null +++ b/playwright/index.tsx @@ -0,0 +1,15 @@ +import { beforeMount, afterMount } from '../src/hooks.mjs'; +import { ThemeContext } from '../tests/components/theme'; + +export type HooksConfig = { + theme: 'dark' | 'light'; +} + +beforeMount(async ({ hooksConfig, App }) => { + if (hooksConfig?.theme === 'dark') + return ; +}); + +afterMount(async () => { + console.log(`After mount`); +}); diff --git a/src/hooks.mts b/src/hooks.mts index b0ddefe..6ee667c 100644 --- a/src/hooks.mts +++ b/src/hooks.mts @@ -1,13 +1,20 @@ +import { JSX } from 'preact/jsx-runtime'; +import { JsonObject } from './jsonObject.js'; + const __pw_hooks_before_mount: any[] = []; const __pw_hooks_after_mount: any[] = []; window.__pw_hooks_before_mount = __pw_hooks_before_mount; window.__pw_hooks_after_mount = __pw_hooks_after_mount; -export const beforeMount = (callback: any) => { +export const beforeMount = ( + callback: (params: { hooksConfig: HooksConfig; App: () => JSX.Element }) => Promise +) => { __pw_hooks_before_mount.push(callback); }; -export const afterMount = (callback: any) => { +export const afterMount = ( + callback: (params: { hooksConfig: HooksConfig }) => Promise +) => { __pw_hooks_after_mount.push(callback); }; diff --git a/src/index.ts b/src/index.ts index 1278ed1..c1ac629 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,12 +5,15 @@ import { // @ts-ignore _addRunnerPlugin, PlaywrightTestConfig as BasePlaywrightTestConfig, + Locator, } from "@playwright/test"; // @ts-ignore import { fixtures } from "@playwright/test/lib/mount"; import path from "path"; +import { JSX } from 'preact/jsx-runtime'; // @ts-ignore import type { InlineConfig } from "vite"; +import { JsonObject } from './jsonObject'; export type PlaywrightTestConfig = Omit & { use?: BasePlaywrightTestConfig["use"] & { @@ -30,6 +33,22 @@ _addRunnerPlugin(() => { }); }); -const test = baseTest.extend(fixtures); +export interface MountOptions { + hooksConfig?: HooksConfig; +} + +interface MountResult extends Locator { + unmount(): Promise; + update(component: JSX.Element): Promise; +} + +interface ComponentFixtures { + mount( + component: JSX.Element, + options?: MountOptions + ): Promise; +} + +const test = baseTest.extend(fixtures); export { test, expect, devices }; diff --git a/src/jsonObject.ts b/src/jsonObject.ts new file mode 100644 index 0000000..5bd018c --- /dev/null +++ b/src/jsonObject.ts @@ -0,0 +1,4 @@ +type JsonPrimitive = string | number | boolean | null; +type JsonValue = JsonPrimitive | JsonObject | JsonArray; +type JsonArray = JsonValue[]; +export type JsonObject = { [Key in string]?: JsonValue }; \ No newline at end of file diff --git a/src/setup.mts b/src/setup.mts index 8c5e130..e3aa48c 100644 --- a/src/setup.mts +++ b/src/setup.mts @@ -1,4 +1,4 @@ -import { ComponentType, h, render, VNode } from "preact"; +import { ComponentType, h, JSX, render, VNode } from "preact"; type JsxComponent = { kind: "jsx"; @@ -22,20 +22,17 @@ type ObjectComponent = { type PwVNode = JsxComponent | ObjectComponent; -type HookConfig = any; -type Mounter = (config: HookConfig) => Promise; - declare global { interface Window { - playwrightMount( + playwrightMount( vnode: PwVNode, scratch: HTMLElement, - config: HookConfig + config: HooksConfig ): Promise; playwrightUnmount(scratch: HTMLElement): Promise; playwrightUpdate(scratch: HTMLElement, vnode: PwVNode): Promise; - __pw_hooks_before_mount: Mounter[]; - __pw_hooks_after_mount: Mounter[]; + __pw_hooks_before_mount: ((params: { hooksConfig: HooksConfig; App: () => any }) => Promise)[]; + __pw_hooks_after_mount: ((params: { hooksConfig: HooksConfig; }) => Promise)[]; } } @@ -58,11 +55,15 @@ function normalizeNode(node: PwVNode | string): string | VNode { } window.playwrightMount = async (vnode, scratch, hooksConfig) => { + let App = () => normalizeNode(vnode); for (const hook of window.__pw_hooks_before_mount || []) { - await hook({ hooksConfig }); + const wrapper = await hook({ App, hooksConfig }); + if (wrapper) { + App = () => wrapper; + } } - render(normalizeNode(vnode), scratch); + render(App(), scratch); for (const hook of window.__pw_hooks_after_mount || []) { await hook({ hooksConfig }); diff --git a/tests/App.tsx b/tests/App.tsx deleted file mode 100644 index cf617e7..0000000 --- a/tests/App.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export function App() { - return

foo

; -} diff --git a/tests/components/Theme.tsx b/tests/components/Theme.tsx new file mode 100644 index 0000000..dc95a74 --- /dev/null +++ b/tests/components/Theme.tsx @@ -0,0 +1,7 @@ +import { createContext } from 'preact'; + +export const ThemeContext = createContext('light'); + +export function Theme() { + return {theme => theme}; +} diff --git a/tests/preact.test.tsx b/tests/preact.test.tsx index 0d50dff..cd8f279 100644 --- a/tests/preact.test.tsx +++ b/tests/preact.test.tsx @@ -4,6 +4,8 @@ import { DefaultChildren } from './components/DefaultChildren'; import { MultiRoot } from './components/MultiRoot'; import { Counter } from './components/Counter'; import { EmptyFragment } from './components/EmptyFragment'; +import { Theme } from './components/theme'; +import type { HooksConfig } from '../playwright'; test('render props', async ({ mount }) => { const component = await mount(