diff --git a/packages/playwright-ct-react/hooks.d.ts b/packages/playwright-ct-react/hooks.d.ts index aa4680694a..bd84d3bcfe 100644 --- a/packages/playwright-ct-react/hooks.d.ts +++ b/packages/playwright-ct-react/hooks.d.ts @@ -19,7 +19,7 @@ type JsonValue = JsonPrimitive | JsonObject | JsonArray; type JsonArray = JsonValue[]; type JsonObject = { [Key in string]?: JsonValue }; export declare function beforeMount( - callback: (params: { hooksConfig: HooksConfig }) => Promise + callback: (params: { hooksConfig: HooksConfig; App: () => JSX.Element }) => Promise ): void; export declare function afterMount( callback: (params: { hooksConfig: HooksConfig }) => Promise diff --git a/packages/playwright-ct-react/registerSource.mjs b/packages/playwright-ct-react/registerSource.mjs index 6e79401cac..a89f05b48c 100644 --- a/packages/playwright-ct-react/registerSource.mjs +++ b/packages/playwright-ct-react/registerSource.mjs @@ -36,6 +36,7 @@ export function register(components) { /** * @param {Component} component + * @returns {JSX.Element} */ function render(component) { let componentFunc = registry.get(component.type); @@ -69,10 +70,14 @@ function render(component) { } window.playwrightMount = async (component, rootElement, hooksConfig) => { - for (const hook of /** @type {any} */(window).__pw_hooks_before_mount || []) - await hook({ hooksConfig }); + let App = () => render(component); + for (const hook of /** @type {any} */(window).__pw_hooks_before_mount || []) { + const wrapper = await hook({ App, hooksConfig }); + if (wrapper) + App = () => wrapper; + } - ReactDOM.render(render(component), rootElement); + ReactDOM.render(App(), rootElement); for (const hook of /** @type {any} */(window).__pw_hooks_after_mount || []) await hook({ hooksConfig }); diff --git a/packages/playwright-ct-solid/hooks.d.ts b/packages/playwright-ct-solid/hooks.d.ts index aa4680694a..e4aea76041 100644 --- a/packages/playwright-ct-solid/hooks.d.ts +++ b/packages/playwright-ct-solid/hooks.d.ts @@ -14,12 +14,14 @@ * limitations under the License. */ +import { JSXElement } from "solid-js"; + type JsonPrimitive = string | number | boolean | null; type JsonValue = JsonPrimitive | JsonObject | JsonArray; type JsonArray = JsonValue[]; type JsonObject = { [Key in string]?: JsonValue }; export declare function beforeMount( - callback: (params: { hooksConfig: HooksConfig }) => Promise + callback: (params: { hooksConfig: HooksConfig, App: () => JSXElement }) => Promise ): void; export declare function afterMount( callback: (params: { hooksConfig: HooksConfig }) => Promise diff --git a/packages/playwright-ct-solid/registerSource.mjs b/packages/playwright-ct-solid/registerSource.mjs index 4b9c44869f..7781807cd1 100644 --- a/packages/playwright-ct-solid/registerSource.mjs +++ b/packages/playwright-ct-solid/registerSource.mjs @@ -78,10 +78,14 @@ function createComponent(component) { const unmountKey = Symbol('unmountKey'); window.playwrightMount = async (component, rootElement, hooksConfig) => { - for (const hook of /** @type {any} */(window).__pw_hooks_before_mount || []) - await hook({ hooksConfig }); + let App = () => createComponent(component); + for (const hook of /** @type {any} */(window).__pw_hooks_before_mount || []) { + const wrapper = await hook({ App, hooksConfig }); + if (wrapper) + App = () => wrapper; + } - const unmount = solidRender(() => createComponent(component), rootElement); + const unmount = solidRender(App, rootElement); rootElement[unmountKey] = unmount; for (const hook of /** @type {any} */(window).__pw_hooks_after_mount || []) diff --git a/tests/components/ct-react-vite/playwright/index.html b/tests/components/ct-react-vite/playwright/index.html index 2b1557e4ef..f7b4577817 100644 --- a/tests/components/ct-react-vite/playwright/index.html +++ b/tests/components/ct-react-vite/playwright/index.html @@ -8,6 +8,6 @@
- + diff --git a/tests/components/ct-react-vite/playwright/index.ts b/tests/components/ct-react-vite/playwright/index.tsx similarity index 55% rename from tests/components/ct-react-vite/playwright/index.ts rename to tests/components/ct-react-vite/playwright/index.tsx index 956fc9625f..fa0563dbcd 100644 --- a/tests/components/ct-react-vite/playwright/index.ts +++ b/tests/components/ct-react-vite/playwright/index.tsx @@ -1,13 +1,17 @@ -//@ts-check -import '../src/assets/index.css'; import { beforeMount, afterMount } from '@playwright/experimental-ct-react/hooks'; +import { BrowserRouter } from 'react-router-dom'; +import '../src/assets/index.css'; export type HooksConfig = { - route: string; + route?: string; + routing?: boolean; } -beforeMount(async ({ hooksConfig }) => { +beforeMount(async ({ hooksConfig, App }) => { console.log(`Before mount: ${JSON.stringify(hooksConfig)}`); + + if (hooksConfig?.routing) + return ; }); afterMount(async () => { diff --git a/tests/components/ct-react-vite/src/tests.spec.tsx b/tests/components/ct-react-vite/src/tests.spec.tsx index d8c18554a8..da802c030d 100644 --- a/tests/components/ct-react-vite/src/tests.spec.tsx +++ b/tests/components/ct-react-vite/src/tests.spec.tsx @@ -1,5 +1,4 @@ import { test, expect } from '@playwright/experimental-ct-react'; -import { BrowserRouter } from 'react-router-dom'; import App from './App'; import Button from './components/Button'; import DefaultChildren from './components/DefaultChildren'; @@ -143,7 +142,9 @@ test('get textContent of the empty fragment', async ({ mount }) => { }); test('navigate to a page by clicking a link', async ({ page, mount }) => { - const component = await mount(); + const component = await mount(, { + hooksConfig: { routing: true } + }); await expect(component.getByRole('main')).toHaveText('Login'); await expect(page).toHaveURL('/'); await component.getByRole('link', { name: 'Dashboard' }).click(); diff --git a/tests/components/ct-react/playwright/index.html b/tests/components/ct-react/playwright/index.html index 280ca94d98..080e66f9b1 100644 --- a/tests/components/ct-react/playwright/index.html +++ b/tests/components/ct-react/playwright/index.html @@ -8,6 +8,6 @@
- + diff --git a/tests/components/ct-react/playwright/index.ts b/tests/components/ct-react/playwright/index.tsx similarity index 55% rename from tests/components/ct-react/playwright/index.ts rename to tests/components/ct-react/playwright/index.tsx index 7da5ae0387..fa0563dbcd 100644 --- a/tests/components/ct-react/playwright/index.ts +++ b/tests/components/ct-react/playwright/index.tsx @@ -1,12 +1,17 @@ -import '../src/assets/index.css'; import { beforeMount, afterMount } from '@playwright/experimental-ct-react/hooks'; +import { BrowserRouter } from 'react-router-dom'; +import '../src/assets/index.css'; export type HooksConfig = { - route: string; + route?: string; + routing?: boolean; } -beforeMount(async ({ hooksConfig }) => { +beforeMount(async ({ hooksConfig, App }) => { console.log(`Before mount: ${JSON.stringify(hooksConfig)}`); + + if (hooksConfig?.routing) + return ; }); afterMount(async () => { diff --git a/tests/components/ct-react/src/tests.spec.tsx b/tests/components/ct-react/src/tests.spec.tsx index 9d7c882269..d17b4d171b 100644 --- a/tests/components/ct-react/src/tests.spec.tsx +++ b/tests/components/ct-react/src/tests.spec.tsx @@ -1,6 +1,5 @@ import { test, expect } from '@playwright/experimental-ct-react'; const { serverFixtures } = require('../../../../tests/config/serverFixtures'); -import { BrowserRouter } from 'react-router-dom'; import App from './App'; import Fetch from './components/Fetch'; import DelayedData from './components/DelayedData'; @@ -151,7 +150,9 @@ test('get textContent of the empty fragment', async ({ mount }) => { }); test('navigate to a page by clicking a link', async ({ page, mount }) => { - const component = await mount(); + const component = await mount(, { + hooksConfig: { routing: true } + }); await expect(component.getByRole('main')).toHaveText('Login'); await expect(page).toHaveURL('/'); await component.getByRole('link', { name: 'Dashboard' }).click(); diff --git a/tests/components/ct-solid/package.json b/tests/components/ct-solid/package.json index 2e563e619a..4d12cb4774 100644 --- a/tests/components/ct-solid/package.json +++ b/tests/components/ct-solid/package.json @@ -10,14 +10,15 @@ "typecheck": "tsc --noEmit" }, "license": "MIT", + "dependencies": { + "@solidjs/router": "^0.5.0", + "solid-js": "^1.4.7" + }, "devDependencies": { "typescript": "^4.7.4", "vite": "^4.0.3", "vite-plugin-solid": "^2.5.0" }, - "dependencies": { - "solid-js": "^1.4.7" - }, "@standaloneDevDependencies": { "@playwright/experimental-ct-solid": "^1.22.2", "@playwright/test": "^1.22.2" diff --git a/tests/components/ct-solid/playwright/index.html b/tests/components/ct-solid/playwright/index.html index c04914b10d..1985b43bc1 100644 --- a/tests/components/ct-solid/playwright/index.html +++ b/tests/components/ct-solid/playwright/index.html @@ -8,6 +8,6 @@
- + diff --git a/tests/components/ct-solid/playwright/index.ts b/tests/components/ct-solid/playwright/index.tsx similarity index 58% rename from tests/components/ct-solid/playwright/index.ts rename to tests/components/ct-solid/playwright/index.tsx index 438b107ffa..de3eea3285 100644 --- a/tests/components/ct-solid/playwright/index.ts +++ b/tests/components/ct-solid/playwright/index.tsx @@ -1,12 +1,17 @@ -import '../src/assets/index.css'; import { beforeMount, afterMount } from '@playwright/experimental-ct-solid/hooks'; +import { Router } from "@solidjs/router"; +import '../src/assets/index.css'; export type HooksConfig = { - route: string; + route?: string; + routing?: boolean; } -beforeMount(async ({ hooksConfig }) => { +beforeMount(async ({ hooksConfig, App }) => { console.log(`Before mount: ${JSON.stringify(hooksConfig)}`); + + if (hooksConfig?.routing) + return ; }); afterMount(async () => { diff --git a/tests/components/ct-solid/src/App.module.css b/tests/components/ct-solid/src/App.module.css deleted file mode 100644 index 48308b24a8..0000000000 --- a/tests/components/ct-solid/src/App.module.css +++ /dev/null @@ -1,33 +0,0 @@ -.App { - text-align: center; -} - -.logo { - animation: logo-spin infinite 20s linear; - height: 40vmin; - pointer-events: none; -} - -.header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.link { - color: #b318f0; -} - -@keyframes logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} diff --git a/tests/components/ct-solid/src/App.tsx b/tests/components/ct-solid/src/App.tsx index 5810710a36..c57cd5642d 100644 --- a/tests/components/ct-solid/src/App.tsx +++ b/tests/components/ct-solid/src/App.tsx @@ -1,27 +1,20 @@ -import type { Component } from 'solid-js'; - +import { Routes, Route, A } from "@solidjs/router" import logo from './assets/logo.svg'; -import styles from './App.module.css'; +import LoginPage from './pages/LoginPage'; +import DashboardPage from './pages/DashboardPage'; -const App: Component = () => { - return ( -
-
- logo -

- Edit src/App.tsx and save to reload. -

- - Learn Solid - -
-
- ); +export default function App() { + return <> +
+ logo + Login + Dashboard +
+ + + + + + + }; - -export default App; diff --git a/tests/components/ct-solid/src/index.tsx b/tests/components/ct-solid/src/index.tsx index 9ad9412423..15976a07a6 100644 --- a/tests/components/ct-solid/src/index.tsx +++ b/tests/components/ct-solid/src/index.tsx @@ -1,6 +1,7 @@ /* @refresh reload */ import { render } from 'solid-js/web'; +import { Router } from "@solidjs/router"; import App from './App'; import './assets/index.css'; -render(() => , document.getElementById('root') as HTMLElement); +render(() => , document.getElementById('root')!); diff --git a/tests/components/ct-solid/src/pages/DashboardPage.tsx b/tests/components/ct-solid/src/pages/DashboardPage.tsx new file mode 100644 index 0000000000..64307e87f3 --- /dev/null +++ b/tests/components/ct-solid/src/pages/DashboardPage.tsx @@ -0,0 +1,3 @@ +export default function DashboardPage() { + return
Dashboard
+} diff --git a/tests/components/ct-solid/src/pages/LoginPage.tsx b/tests/components/ct-solid/src/pages/LoginPage.tsx new file mode 100644 index 0000000000..96adc431ed --- /dev/null +++ b/tests/components/ct-solid/src/pages/LoginPage.tsx @@ -0,0 +1,3 @@ +export default function LoginPage() { + return
Login
+} diff --git a/tests/components/ct-solid/src/tests.spec.tsx b/tests/components/ct-solid/src/tests.spec.tsx index 01cbc66a7a..b6876e7225 100644 --- a/tests/components/ct-solid/src/tests.spec.tsx +++ b/tests/components/ct-solid/src/tests.spec.tsx @@ -1,4 +1,5 @@ import { test, expect } from '@playwright/experimental-ct-solid'; +import App from './App'; import Button from './components/Button'; import Counter from './components/Counter'; import DefaultChildren from './components/DefaultChildren'; @@ -81,19 +82,15 @@ test('execute callback when the button is clicked', async ({ mount }) => { }); test('render a default child', async ({ mount }) => { - const component = await mount( - Main Content - ); + const component = await mount(Main Content); await expect(component).toContainText('Main Content'); }); test('render multiple children', async ({ mount }) => { - const component = await mount( - -
One
-
Two
-
- ); + const component = await mount( +
One
+
Two
+
); await expect(component.locator('#one')).toContainText('One'); await expect(component.locator('#two')).toContainText('Two'); }); @@ -107,13 +104,11 @@ test('render a component as slot', async ({ mount }) => { }); test('render named children', async ({ mount }) => { - const component = await mount( - -
Header
-
Main Content
-
Footer
-
- ); + const component = await mount( +
Header
+
Main Content
+
Footer
+
); await expect(component).toContainText('Header'); await expect(component).toContainText('Main Content'); await expect(component).toContainText('Footer'); @@ -121,11 +116,9 @@ test('render named children', async ({ mount }) => { test('execute callback when a child node is clicked', async ({ mount }) => { let clickFired = false; - const component = await mount( - - (clickFired = true)}>Main Content - - ); + const component = await mount( + (clickFired = true)}>Main Content + ); await component.locator('text=Main Content').click(); expect(clickFired).toBeTruthy(); }); @@ -163,3 +156,14 @@ test('get textContent of the empty fragment', async ({ mount }) => { expect(await component.textContent()).toBe(''); await expect(component).toHaveText(''); }); + +test('navigate to a page by clicking a link', async ({ page, mount }) => { + const component = await mount(, { + hooksConfig: { routing: true } + }); + await expect(component.getByRole('main')).toHaveText('Login'); + await expect(page).toHaveURL('/'); + await component.getByRole('link', { name: 'Dashboard' }).click(); + await expect(component.getByRole('main')).toHaveText('Dashboard'); + await expect(page).toHaveURL('/dashboard'); +}); diff --git a/tests/components/ct-vue-cli/playwright/index.ts b/tests/components/ct-vue-cli/playwright/index.ts index b87f588e10..2e32dc82f4 100644 --- a/tests/components/ct-vue-cli/playwright/index.ts +++ b/tests/components/ct-vue-cli/playwright/index.ts @@ -3,11 +3,13 @@ import { router } from '../src/router'; import '../src/assets/index.css'; export type HooksConfig = { - route: string; + route?: string; + routing?: boolean; } beforeMount(async ({ app, hooksConfig }) => { - app.use(router); + if (hooksConfig?.routing) + app.use(router); console.log(`Before mount: ${JSON.stringify(hooksConfig)}, app: ${!!app}`); }); diff --git a/tests/components/ct-vue-cli/src/notation-jsx.spec.tsx b/tests/components/ct-vue-cli/src/notation-jsx.spec.tsx index 258a1217fa..f9315a1954 100644 --- a/tests/components/ct-vue-cli/src/notation-jsx.spec.tsx +++ b/tests/components/ct-vue-cli/src/notation-jsx.spec.tsx @@ -122,7 +122,9 @@ test('get textContent of the empty template', async ({ mount }) => { }); test('navigate to a page by clicking a link', async ({ page, mount }) => { - const component = await mount(); + const component = await mount(, { + hooksConfig: { routing: true } + }); await expect(component.getByRole('main')).toHaveText('Login'); await expect(page).toHaveURL('/'); await component.getByRole('link', { name: 'Dashboard' }).click(); diff --git a/tests/components/ct-vue-cli/src/notation-vue.spec.ts b/tests/components/ct-vue-cli/src/notation-vue.spec.ts index 5e331e4be4..9a6c04714c 100644 --- a/tests/components/ct-vue-cli/src/notation-vue.spec.ts +++ b/tests/components/ct-vue-cli/src/notation-vue.spec.ts @@ -128,7 +128,9 @@ test('get textContent of the empty template', async ({ mount }) => { }); test('navigate to a page by clicking a link', async ({ page, mount }) => { - const component = await mount(App); + const component = await mount(App, { + hooksConfig: { routing: true } + }); await expect(component.getByRole('main')).toHaveText('Login'); await expect(page).toHaveURL('/'); await component.getByRole('link', { name: 'Dashboard' }).click(); diff --git a/tests/components/ct-vue-vite/playwright/index.ts b/tests/components/ct-vue-vite/playwright/index.ts index 2e548b550d..977ee33845 100644 --- a/tests/components/ct-vue-vite/playwright/index.ts +++ b/tests/components/ct-vue-vite/playwright/index.ts @@ -4,11 +4,13 @@ import Button from '../src/components/Button.vue'; import '../src/assets/index.css'; export type HooksConfig = { - route: string; + route?: string; + routing?: boolean; } beforeMount(async ({ app, hooksConfig }) => { - app.use(router as any); // TODO: remove any and fix the various installed conflicting Vue versions + if (hooksConfig?.routing) + app.use(router as any); // TODO: remove any and fix the various installed conflicting Vue versions app.component('Button', Button); console.log(`Before mount: ${JSON.stringify(hooksConfig)}, app: ${!!app}`); }); diff --git a/tests/components/ct-vue-vite/src/notation-jsx.spec.tsx b/tests/components/ct-vue-vite/src/notation-jsx.spec.tsx index b770739df8..1b38f83212 100644 --- a/tests/components/ct-vue-vite/src/notation-jsx.spec.tsx +++ b/tests/components/ct-vue-vite/src/notation-jsx.spec.tsx @@ -143,8 +143,10 @@ test('get textContent of the empty template', async ({ mount }) => { await expect(component).toHaveText(''); }); -test('render app and navigate to a page', async ({ page, mount }) => { - const component = await mount(App); +test('navigate to a page by clicking a link', async ({ page, mount }) => { + const component = await mount(, { + hooksConfig: { routing: true } + }); await expect(component.getByRole('main')).toHaveText('Login'); await expect(page).toHaveURL('/'); await component.getByRole('link', { name: 'Dashboard' }).click(); diff --git a/tests/components/ct-vue-vite/src/notation-vue.spec.js b/tests/components/ct-vue-vite/src/notation-vue.spec.js index 2e072c257c..a3c8e52d2f 100644 --- a/tests/components/ct-vue-vite/src/notation-vue.spec.js +++ b/tests/components/ct-vue-vite/src/notation-vue.spec.js @@ -159,8 +159,10 @@ test('get textContent of the empty template', async ({ mount }) => { await expect(component).toHaveText(''); }); -test('render app and navigate to a page', async ({ page, mount }) => { - const component = await mount(App); +test('navigate to a page by clicking a link', async ({ page, mount }) => { + const component = await mount(App, { + hooksConfig: { routing: true } + }); await expect(component.getByRole('main')).toHaveText('Login'); await expect(page).toHaveURL('/'); await component.getByRole('link', { name: 'Dashboard' }).click(); diff --git a/tests/components/ct-vue-vite/src/notation-vue.spec.ts b/tests/components/ct-vue-vite/src/notation-vue.spec.ts index 850ca45fd7..1070a5bd08 100644 --- a/tests/components/ct-vue-vite/src/notation-vue.spec.ts +++ b/tests/components/ct-vue-vite/src/notation-vue.spec.ts @@ -167,8 +167,10 @@ test('get textContent of the empty template', async ({ mount }) => { await expect(component).toHaveText(''); }); -test('render app and navigate to a page', async ({ page, mount }) => { - const component = await mount(App); +test('navigate to a page by clicking a link', async ({ page, mount }) => { + const component = await mount(App, { + hooksConfig: { routing: true } + }); await expect(component.getByRole('main')).toHaveText('Login'); await expect(page).toHaveURL('/'); await component.getByRole('link', { name: 'Dashboard' }).click(); diff --git a/tests/components/ct-vue2-cli/playwright/index.ts b/tests/components/ct-vue2-cli/playwright/index.ts index cc8c383b3d..d608a40218 100644 --- a/tests/components/ct-vue2-cli/playwright/index.ts +++ b/tests/components/ct-vue2-cli/playwright/index.ts @@ -4,13 +4,17 @@ import { router } from '../src/router'; import '../src/assets/index.css'; export type HooksConfig = { - route: string; + route?: string; + routing?: boolean; } beforeMount(async ({ Vue, hooksConfig }) => { console.log(`Before mount: ${JSON.stringify(hooksConfig)}`); - Vue.use(Router as any); // TODO: remove any and fix the various installed conflicting Vue versions - return { router } + + if (hooksConfig?.routing) { + Vue.use(Router as any); // TODO: remove any and fix the various installed conflicting Vue versions + return { router } + } }); afterMount(async ({ instance }) => { diff --git a/tests/components/ct-vue2-cli/src/notation-jsx.spec.tsx b/tests/components/ct-vue2-cli/src/notation-jsx.spec.tsx index 82bef40c8d..f023394b50 100644 --- a/tests/components/ct-vue2-cli/src/notation-jsx.spec.tsx +++ b/tests/components/ct-vue2-cli/src/notation-jsx.spec.tsx @@ -143,7 +143,9 @@ test('get textContent of the empty template', async ({ mount }) => { }); test('navigate to a page by clicking a link', async ({ page, mount }) => { - const component = await mount(); + const component = await mount(, { + hooksConfig: { routing: true } + }); await expect(component.getByRole('main')).toHaveText('Login'); await expect(page).toHaveURL('/'); await component.getByRole('link', { name: 'Dashboard' }).click(); diff --git a/tests/components/ct-vue2-cli/src/notation-vue.spec.ts b/tests/components/ct-vue2-cli/src/notation-vue.spec.ts index 3b182f5f05..dd09a152bb 100644 --- a/tests/components/ct-vue2-cli/src/notation-vue.spec.ts +++ b/tests/components/ct-vue2-cli/src/notation-vue.spec.ts @@ -152,7 +152,9 @@ test('get textContent of the empty template', async ({ mount }) => { }); test('navigate to a page by clicking a link', async ({ page, mount }) => { - const component = await mount(App); + const component = await mount(App, { + hooksConfig: { routing: true } + }); await expect(component.getByRole('main')).toHaveText('Login'); await expect(page).toHaveURL('/'); await component.getByRole('link', { name: 'Dashboard' }).click();