mirror of
				https://github.com/microsoft/playwright.git
				synced 2025-06-26 21:40:17 +00:00 
			
		
		
		
	feat(ct-react): Support React 18 only (#19814)
BREAKING CHANGE: Drop support for React 17 and earlier Support for React 17 an earlier is provided by `@playwright/experimental-ct-react-17` Closes #19923
This commit is contained in:
		
							parent
							
								
									be259dac7c
								
							
						
					
					
						commit
						fbaf56a13f
					
				
							
								
								
									
										28
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										28
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -1297,6 +1297,10 @@ | ||||
|       "resolved": "packages/playwright-ct-react", | ||||
|       "link": true | ||||
|     }, | ||||
|     "node_modules/@playwright/experimental-ct-react17": { | ||||
|       "resolved": "packages/playwright-ct-react17", | ||||
|       "link": true | ||||
|     }, | ||||
|     "node_modules/@playwright/experimental-ct-solid": { | ||||
|       "resolved": "packages/playwright-ct-solid", | ||||
|       "link": true | ||||
| @ -5990,6 +5994,22 @@ | ||||
|         "node": ">=14" | ||||
|       } | ||||
|     }, | ||||
|     "packages/playwright-ct-react17": { | ||||
|       "name": "@playwright/experimental-ct-react17", | ||||
|       "version": "1.32.0-next", | ||||
|       "license": "Apache-2.0", | ||||
|       "dependencies": { | ||||
|         "@playwright/test": "1.32.0-next", | ||||
|         "@vitejs/plugin-react": "^3.1.0", | ||||
|         "vite": "^4.1.1" | ||||
|       }, | ||||
|       "bin": { | ||||
|         "playwright": "cli.js" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=14" | ||||
|       } | ||||
|     }, | ||||
|     "packages/playwright-ct-solid": { | ||||
|       "name": "@playwright/experimental-ct-solid", | ||||
|       "version": "1.32.0-next", | ||||
| @ -6908,6 +6928,14 @@ | ||||
|         "vite": "^4.1.1" | ||||
|       } | ||||
|     }, | ||||
|     "@playwright/experimental-ct-react17": { | ||||
|       "version": "file:packages/playwright-ct-react17", | ||||
|       "requires": { | ||||
|         "@playwright/test": "1.32.0-next", | ||||
|         "@vitejs/plugin-react": "^3.1.0", | ||||
|         "vite": "^4.1.1" | ||||
|       } | ||||
|     }, | ||||
|     "@playwright/experimental-ct-solid": { | ||||
|       "version": "file:packages/playwright-ct-solid", | ||||
|       "requires": { | ||||
|  | ||||
| @ -84,6 +84,8 @@ test('should show the project names', async ({ mount }) => { | ||||
|     > | ||||
|     </HeaderView>); | ||||
|     await expect(component.getByText('Project: my-project')).toBeVisible(); | ||||
| 
 | ||||
|     await component.unmount(); | ||||
|   }); | ||||
|   await test.step('with 1 project and empty projectName', async () => { | ||||
|     const component = await mount(<HeaderView | ||||
| @ -94,6 +96,8 @@ test('should show the project names', async ({ mount }) => { | ||||
|     > | ||||
|     </HeaderView>); | ||||
|     await expect(component.getByText('Project:')).toBeHidden(); | ||||
| 
 | ||||
|     await component.unmount(); | ||||
|   }); | ||||
|   await test.step('with more than 1 project', async () => { | ||||
|     const component = await mount(<HeaderView | ||||
| @ -105,5 +109,7 @@ test('should show the project names', async ({ mount }) => { | ||||
|     </HeaderView>); | ||||
|     await expect(component.getByText('my-project')).toBeHidden(); | ||||
|     await expect(component.getByText('great-project')).toBeHidden(); | ||||
| 
 | ||||
|     await component.unmount(); | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| @ -17,14 +17,16 @@ | ||||
| // @ts-check
 | ||||
| // This file is injected into the registry as text, no dependencies are allowed.
 | ||||
| 
 | ||||
| import React from 'react'; | ||||
| import ReactDOM from 'react-dom'; | ||||
| import * as React from 'react'; | ||||
| import { createRoot } from 'react-dom/client'; | ||||
| 
 | ||||
| /** @typedef {import('../playwright-test/types/component').Component} Component */ | ||||
| /** @typedef {import('react').FunctionComponent} FrameworkComponent */ | ||||
| 
 | ||||
| /** @type {Map<string, FrameworkComponent>} */ | ||||
| const registry = new Map(); | ||||
| /** @type {Map<Element, import('react-dom/client').Root>>} */ | ||||
| const rootRegistry = new Map(); | ||||
| 
 | ||||
| /** | ||||
|  * @param {{[key: string]: FrameworkComponent}} components | ||||
| @ -79,17 +81,33 @@ window.playwrightMount = async (component, rootElement, hooksConfig) => { | ||||
|       App = () => wrapper; | ||||
|   } | ||||
| 
 | ||||
|   ReactDOM.render(App(), rootElement); | ||||
|   if (rootRegistry.has(rootElement)) { | ||||
|     throw new Error( | ||||
|         'Attempting to mount a component into an container that already has a React root' | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   const root = createRoot(rootElement); | ||||
|   rootRegistry.set(rootElement, root); | ||||
|   root.render(App()); | ||||
| 
 | ||||
|   for (const hook of window.__pw_hooks_after_mount || []) | ||||
|     await hook({ hooksConfig }); | ||||
| }; | ||||
| 
 | ||||
| window.playwrightUnmount = async rootElement => { | ||||
|   if (!ReactDOM.unmountComponentAtNode(rootElement)) | ||||
|   const root = rootRegistry.get(rootElement); | ||||
|   if (root === undefined) | ||||
|     throw new Error('Component was not mounted'); | ||||
| 
 | ||||
|   root.unmount(); | ||||
|   rootRegistry.delete(rootElement); | ||||
| }; | ||||
| 
 | ||||
| window.playwrightUpdate = async (rootElement, component) => { | ||||
|   ReactDOM.render(render(/** @type {Component} */(component)), rootElement); | ||||
|   const root = rootRegistry.get(rootElement); | ||||
|   if (root === undefined) | ||||
|     throw new Error('Component was not mounted'); | ||||
| 
 | ||||
|   root.render(render(/** @type {Component} */ (component))); | ||||
| }; | ||||
|  | ||||
							
								
								
									
										12
									
								
								packages/playwright-ct-react17/.npmignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								packages/playwright-ct-react17/.npmignore
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| **/* | ||||
| 
 | ||||
| !README.md | ||||
| !LICENSE | ||||
| !cli.js | ||||
| !register.d.ts | ||||
| !register.mjs | ||||
| !registerSource.mjs | ||||
| !index.d.ts | ||||
| !index.js | ||||
| !hooks.d.ts | ||||
| !hooks.mjs | ||||
							
								
								
									
										3
									
								
								packages/playwright-ct-react17/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								packages/playwright-ct-react17/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| > **BEWARE** This package is EXPERIMENTAL and does not respect semver. | ||||
| 
 | ||||
| Read more at https://playwright.dev/docs/test-components | ||||
							
								
								
									
										17
									
								
								packages/playwright-ct-react17/cli.js
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										17
									
								
								packages/playwright-ct-react17/cli.js
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,17 @@ | ||||
| #!/usr/bin/env node
 | ||||
| /** | ||||
|  * Copyright (c) Microsoft Corporation. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| module.exports = require('playwright-core/cli'); | ||||
							
								
								
									
										26
									
								
								packages/playwright-ct-react17/hooks.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								packages/playwright-ct-react17/hooks.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | ||||
| /** | ||||
|  * Copyright (c) Microsoft Corporation. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| type JsonPrimitive = string | number | boolean | null; | ||||
| type JsonValue = JsonPrimitive | JsonObject | JsonArray; | ||||
| type JsonArray = JsonValue[]; | ||||
| type JsonObject = { [Key in string]?: JsonValue }; | ||||
| export declare function beforeMount<HooksConfig extends JsonObject>( | ||||
|   callback: (params: { hooksConfig: HooksConfig; App: () => JSX.Element }) => Promise<void | JSX.Element> | ||||
| ): void; | ||||
| export declare function afterMount<HooksConfig extends JsonObject>( | ||||
|   callback: (params: { hooksConfig: HooksConfig }) => Promise<void> | ||||
| ): void; | ||||
							
								
								
									
										29
									
								
								packages/playwright-ct-react17/hooks.mjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								packages/playwright-ct-react17/hooks.mjs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| /** | ||||
|  * Copyright (c) Microsoft Corporation. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| const __pw_hooks_before_mount = []; | ||||
| const __pw_hooks_after_mount = []; | ||||
| 
 | ||||
| window.__pw_hooks_before_mount = __pw_hooks_before_mount; | ||||
| window.__pw_hooks_after_mount = __pw_hooks_after_mount; | ||||
| 
 | ||||
| export const beforeMount = callback => { | ||||
|   __pw_hooks_before_mount.push(callback); | ||||
| }; | ||||
| 
 | ||||
| export const afterMount = callback => { | ||||
|   __pw_hooks_after_mount.push(callback); | ||||
| }; | ||||
							
								
								
									
										70
									
								
								packages/playwright-ct-react17/index.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								packages/playwright-ct-react17/index.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,70 @@ | ||||
| /** | ||||
|  * Copyright (c) Microsoft Corporation. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| import type { | ||||
|   TestType, | ||||
|   PlaywrightTestArgs, | ||||
|   PlaywrightTestConfig as BasePlaywrightTestConfig, | ||||
|   PlaywrightTestOptions, | ||||
|   PlaywrightWorkerArgs, | ||||
|   PlaywrightWorkerOptions, | ||||
|   Locator, | ||||
| } from '@playwright/test'; | ||||
| import type { InlineConfig } from 'vite'; | ||||
| 
 | ||||
| export type PlaywrightTestConfig<T = {}, W = {}> = Omit<BasePlaywrightTestConfig<T, W>, 'use'> & { | ||||
|   use?: BasePlaywrightTestConfig<T, W>['use'] & { | ||||
|     ctPort?: number; | ||||
|     ctTemplateDir?: string; | ||||
|     ctCacheDir?: string; | ||||
|     ctViteConfig?: InlineConfig | (() => Promise<InlineConfig>); | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| type JsonPrimitive = string | number | boolean | null; | ||||
| type JsonValue = JsonPrimitive | JsonObject | JsonArray; | ||||
| type JsonArray = JsonValue[]; | ||||
| type JsonObject = { [Key in string]?: JsonValue }; | ||||
| 
 | ||||
| export interface MountOptions<HooksConfig extends JsonObject> { | ||||
|   hooksConfig?: HooksConfig; | ||||
| } | ||||
| 
 | ||||
| interface MountResult extends Locator { | ||||
|   unmount(): Promise<void>; | ||||
|   update(component: JSX.Element): Promise<void>; | ||||
| } | ||||
| 
 | ||||
| export interface ComponentFixtures { | ||||
|   mount<HooksConfig extends JsonObject>( | ||||
|     component: JSX.Element, | ||||
|     options?: MountOptions<HooksConfig> | ||||
|   ): Promise<MountResult>; | ||||
| } | ||||
| 
 | ||||
| export const test: TestType< | ||||
|   PlaywrightTestArgs & PlaywrightTestOptions & ComponentFixtures, | ||||
|   PlaywrightWorkerArgs & PlaywrightWorkerOptions | ||||
| >; | ||||
| 
 | ||||
| /** | ||||
|  * Defines Playwright config | ||||
|  */ | ||||
| export function defineConfig(config: PlaywrightTestConfig): PlaywrightTestConfig; | ||||
| export function defineConfig<T>(config: PlaywrightTestConfig<T>): PlaywrightTestConfig<T>; | ||||
| export function defineConfig<T, W>(config: PlaywrightTestConfig<T, W>): PlaywrightTestConfig<T, W>; | ||||
| 
 | ||||
| export { expect, devices } from '@playwright/test'; | ||||
							
								
								
									
										31
									
								
								packages/playwright-ct-react17/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								packages/playwright-ct-react17/index.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| /** | ||||
|  * Copyright (c) Microsoft Corporation. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| const { test: baseTest, expect, devices, defineConfig: originalDefineConfig } = require('@playwright/test'); | ||||
| const { fixtures } = require('@playwright/test/lib/mount'); | ||||
| const path = require('path'); | ||||
| 
 | ||||
| const plugin = () => { | ||||
|   // Only fetch upon request to avoid resolution in workers.
 | ||||
|   const { createPlugin } = require('@playwright/test/lib/plugins/vitePlugin'); | ||||
|   return createPlugin( | ||||
|     path.join(__dirname, 'registerSource.mjs'), | ||||
|     () => import('@vitejs/plugin-react').then(plugin => plugin.default())); | ||||
| }; | ||||
| const defineConfig = config => originalDefineConfig({ ...config, _plugins: [plugin] }); | ||||
| const test = baseTest.extend(fixtures); | ||||
| 
 | ||||
| module.exports = { test, expect, devices, defineConfig }; | ||||
							
								
								
									
										36
									
								
								packages/playwright-ct-react17/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								packages/playwright-ct-react17/package.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | ||||
| { | ||||
|   "name": "@playwright/experimental-ct-react17", | ||||
|   "version": "1.32.0-next", | ||||
|   "description": "Playwright Component Testing for React", | ||||
|   "repository": "github:Microsoft/playwright", | ||||
|   "homepage": "https://playwright.dev", | ||||
|   "engines": { | ||||
|     "node": ">=14" | ||||
|   }, | ||||
|   "author": { | ||||
|     "name": "Microsoft Corporation" | ||||
|   }, | ||||
|   "license": "Apache-2.0", | ||||
|   "exports": { | ||||
|     ".": { | ||||
|       "types": "./index.d.ts", | ||||
|       "default": "./index.js" | ||||
|     }, | ||||
|     "./register": { | ||||
|       "types": "./register.d.ts", | ||||
|       "default": "./register.mjs" | ||||
|     }, | ||||
|     "./hooks": { | ||||
|       "types": "./hooks.d.ts", | ||||
|       "default": "./hooks.mjs" | ||||
|     } | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@vitejs/plugin-react": "^3.1.0", | ||||
|     "@playwright/test": "1.32.0-next", | ||||
|     "vite": "^4.1.1" | ||||
|   }, | ||||
|   "bin": { | ||||
|     "playwright": "./cli.js" | ||||
|   } | ||||
| } | ||||
							
								
								
									
										19
									
								
								packages/playwright-ct-react17/register.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								packages/playwright-ct-react17/register.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| /** | ||||
|  * Copyright (c) Microsoft Corporation. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| export default function register( | ||||
|   components: { [key: string]: any }, | ||||
| ): void | ||||
							
								
								
									
										21
									
								
								packages/playwright-ct-react17/register.mjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								packages/playwright-ct-react17/register.mjs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| /** | ||||
|  * Copyright (c) Microsoft Corporation. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| import { register } from './registerSource.mjs'; | ||||
| 
 | ||||
| export default components => { | ||||
|   register(components); | ||||
| }; | ||||
							
								
								
									
										93
									
								
								packages/playwright-ct-react17/registerSource.mjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								packages/playwright-ct-react17/registerSource.mjs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,93 @@ | ||||
| /** | ||||
|  * Copyright (c) Microsoft Corporation. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| // @ts-check
 | ||||
| // This file is injected into the registry as text, no dependencies are allowed.
 | ||||
| 
 | ||||
| import React from 'react'; | ||||
| import ReactDOM from 'react-dom'; | ||||
| 
 | ||||
| /** @typedef {import('../playwright-test/types/component').Component} Component */ | ||||
| /** @typedef {import('react').FunctionComponent} FrameworkComponent */ | ||||
| 
 | ||||
| /** @type {Map<string, FrameworkComponent>} */ | ||||
| const registry = new Map(); | ||||
| 
 | ||||
| /** | ||||
|  * @param {{[key: string]: FrameworkComponent}} components | ||||
|  */ | ||||
| export function register(components) { | ||||
|   for (const [name, value] of Object.entries(components)) | ||||
|     registry.set(name, value); | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * @param {Component} component | ||||
|  * @returns {JSX.Element} | ||||
|  */ | ||||
| function render(component) { | ||||
|   let componentFunc = registry.get(component.type); | ||||
|   if (!componentFunc) { | ||||
|     // Lookup by shorthand.
 | ||||
|     for (const [name, value] of registry) { | ||||
|       if (component.type.endsWith(`_${name}`)) { | ||||
|         componentFunc = value; | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   if (!componentFunc && component.type[0].toUpperCase() === component.type[0]) | ||||
|     throw new Error(`Unregistered component: ${component.type}. Following components are registered: ${[...registry.keys()]}`); | ||||
| 
 | ||||
|   const componentFuncOrString = componentFunc || component.type; | ||||
| 
 | ||||
|   if (component.kind !== 'jsx') | ||||
|     throw new Error('Object mount notation is not supported'); | ||||
| 
 | ||||
|   return React.createElement(componentFuncOrString, component.props, ...component.children.map(child => { | ||||
|     if (typeof child === 'string') | ||||
|       return child; | ||||
|     return render(child); | ||||
|   }).filter(child => { | ||||
|     if (typeof child === 'string') | ||||
|       return !!child.trim(); | ||||
|     return true; | ||||
|   })); | ||||
| } | ||||
| 
 | ||||
| window.playwrightMount = async (component, rootElement, hooksConfig) => { | ||||
|   let App = () => render(component); | ||||
|   for (const hook of window.__pw_hooks_before_mount || []) { | ||||
|     const wrapper = await hook({ App, hooksConfig }); | ||||
|     if (wrapper) | ||||
|       App = () => wrapper; | ||||
|   } | ||||
| 
 | ||||
|   ReactDOM.render(App(), rootElement); | ||||
| 
 | ||||
|   for (const hook of window.__pw_hooks_after_mount || []) | ||||
|     await hook({ hooksConfig }); | ||||
| }; | ||||
| 
 | ||||
| window.playwrightUnmount = async rootElement => { | ||||
|   if (!ReactDOM.unmountComponentAtNode(rootElement)) | ||||
|     throw new Error('Component was not mounted'); | ||||
| }; | ||||
| 
 | ||||
| window.playwrightUpdate = async (rootElement, component) => { | ||||
|   ReactDOM.render(render(/** @type {Component} */(component)), rootElement); | ||||
| }; | ||||
| @ -9,19 +9,19 @@ | ||||
|     "typecheck": "tsc --noEmit" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "react": "^17.0.2", | ||||
|     "react-dom": "^17.0.2", | ||||
|     "react-router-dom": "^6.4.2" | ||||
|     "react": "^18.2.0", | ||||
|     "react-dom": "^18.2.0", | ||||
|     "react-router-dom": "^6.6.1" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@types/react": "^17.0.33", | ||||
|     "@types/react-dom": "^17.0.10", | ||||
|     "@types/react": "^18.0.26", | ||||
|     "@types/react-dom": "^18.0.10", | ||||
|     "@vitejs/plugin-react": "^3.0.0", | ||||
|     "typescript": "^4.5.4", | ||||
|     "vite": "^4.1.1" | ||||
|   }, | ||||
|   "@standaloneDevDependencies": { | ||||
|     "@playwright/experimental-ct-react": "^1.22.2", | ||||
|     "@playwright/experimental-ct-react": "^1.22.0", | ||||
|     "@playwright/test": "^1.22.2" | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| import { useRef } from "react" | ||||
| import { useLayoutEffect, useRef, useState } from "react" | ||||
| 
 | ||||
|  type CounterProps = { | ||||
|    count?: number; | ||||
| @ -9,11 +9,17 @@ import { useRef } from "react" | ||||
|  let _remountCount = 1; | ||||
| 
 | ||||
|  export default function Counter(props: CounterProps) { | ||||
|    const remountCount = useRef(_remountCount++); | ||||
|    const [remountCount] = useState(_remountCount); | ||||
|    const didMountRef = useRef(false) | ||||
|    useLayoutEffect(() => { | ||||
|      if (!didMountRef.current) { | ||||
|        didMountRef.current = true; | ||||
|        _remountCount++; | ||||
|      } | ||||
|    }, []) | ||||
|    return <div onClick={() => props.onClick?.('hello')}> | ||||
|      <div id="props">{ props.count }</div> | ||||
|      <div id="remount-count">{ remountCount.current }</div> | ||||
|      <div id="remount-count">{ remountCount }</div> | ||||
|      { props.children } | ||||
|    </div> | ||||
|  } | ||||
|   | ||||
| @ -1,12 +1,13 @@ | ||||
| import React from 'react'; | ||||
| import ReactDOM from 'react-dom'; | ||||
| import * as React from 'react'; | ||||
| import { createRoot } from 'react-dom/client'; | ||||
| import { BrowserRouter } from 'react-router-dom'; | ||||
| import App from './App'; | ||||
| import './assets/index.css'; | ||||
| 
 | ||||
| ReactDOM.render( | ||||
| createRoot(document.getElementById("root")!).render( | ||||
|   <React.StrictMode> | ||||
|     <BrowserRouter><App /></BrowserRouter> | ||||
|   </React.StrictMode>, | ||||
|   document.getElementById('root') | ||||
| ) | ||||
|     <BrowserRouter> | ||||
|       <App /> | ||||
|     </BrowserRouter> | ||||
|   </React.StrictMode> | ||||
| ); | ||||
|  | ||||
| @ -3,19 +3,19 @@ | ||||
|   "version": "0.1.0", | ||||
|   "private": true, | ||||
|   "dependencies": { | ||||
|     "react": "^17.0.2", | ||||
|     "react-dom": "^17.0.2", | ||||
|     "react-router-dom": "^6.4.2"     | ||||
|     "react": "^18.2.0", | ||||
|     "react-dom": "^18.2.0", | ||||
|     "react-router-dom": "^6.6.1" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@types/node": "^16.11.26", | ||||
|     "@types/react": "^17.0.39", | ||||
|     "@types/react-dom": "^17.0.13", | ||||
|     "@types/react": "^18.0.26", | ||||
|     "@types/react-dom": "^18.0.10", | ||||
|     "react-scripts": "5.0.0", | ||||
|     "typescript": "^4.6.2" | ||||
|   }, | ||||
|   "@standaloneDevDependencies": { | ||||
|     "@playwright/experimental-ct-react": "^1.22.2", | ||||
|     "@playwright/experimental-ct-react": "^1.2.2", | ||||
|     "@playwright/test": "^1.22.2" | ||||
|   }, | ||||
|   "scripts": { | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| import { useRef } from "react" | ||||
| import { useLayoutEffect, useRef, useState } from "react" | ||||
| 
 | ||||
|  type CounterProps = { | ||||
|    count?: number; | ||||
| @ -9,11 +9,17 @@ import { useRef } from "react" | ||||
|  let _remountCount = 1; | ||||
| 
 | ||||
|  export default function Counter(props: CounterProps) { | ||||
|    const remountCount = useRef(_remountCount++); | ||||
|    const [remountCount] = useState(_remountCount); | ||||
|    const didMountRef = useRef(false) | ||||
|    useLayoutEffect(() => { | ||||
|      if (!didMountRef.current) { | ||||
|        didMountRef.current = true; | ||||
|        _remountCount++; | ||||
|      } | ||||
|    }, []) | ||||
|    return <div onClick={() => props.onClick?.('hello')}> | ||||
|      <div id="props">{ props.count }</div> | ||||
|      <div id="remount-count">{ remountCount.current }</div> | ||||
|      <div id="remount-count">{ remountCount }</div> | ||||
|      { props.children } | ||||
|    </div> | ||||
|  } | ||||
|   | ||||
| @ -1,12 +1,13 @@ | ||||
| import React from 'react'; | ||||
| import ReactDOM from 'react-dom'; | ||||
| import * as React from 'react'; | ||||
| import { createRoot } from 'react-dom/client'; | ||||
| import { BrowserRouter } from 'react-router-dom'; | ||||
| import App from './App'; | ||||
| import './assets/index.css'; | ||||
| 
 | ||||
| ReactDOM.render( | ||||
| createRoot(document.getElementById("root")).render( | ||||
|   <React.StrictMode> | ||||
|     <BrowserRouter><App /></BrowserRouter> | ||||
|   </React.StrictMode>, | ||||
|   document.getElementById('root') | ||||
|     <BrowserRouter> | ||||
|       <App /> | ||||
|     </BrowserRouter> | ||||
|   </React.StrictMode> | ||||
| ); | ||||
|  | ||||
| @ -45,7 +45,7 @@ test('should work with the empty component list', async ({ runInlineTest }, test | ||||
|   expect(metainfo.version).toEqual(require('playwright-core/package.json').version); | ||||
|   expect(metainfo.viteVersion).toEqual(require('vite/package.json').version); | ||||
|   expect(Object.entries(metainfo.tests)).toHaveLength(1); | ||||
|   expect(Object.entries(metainfo.sources)).toHaveLength(8); | ||||
|   expect(Object.entries(metainfo.sources)).toHaveLength(9); | ||||
| }); | ||||
| 
 | ||||
| test('should extract component list', async ({ runInlineTest }, testInfo) => { | ||||
|  | ||||
| @ -34,6 +34,7 @@ | ||||
|     "packages/*/lib", | ||||
|     "packages/html-reporter", | ||||
|     "packages/playwright-ct-react", | ||||
|     "packages/playwright-ct-react17", | ||||
|     "packages/playwright-ct-solid", | ||||
|     "packages/playwright-ct-svelte", | ||||
|     "packages/playwright-ct-vue", | ||||
|  | ||||
| @ -178,6 +178,11 @@ const workspace = new Workspace(ROOT_PATH, [ | ||||
|     path: path.join(ROOT_PATH, 'packages', 'playwright-ct-react'), | ||||
|     files: ['LICENSE'], | ||||
|   }), | ||||
|   new PWPackage({ | ||||
|     name: '@playwright/experimental-ct-react17', | ||||
|     path: path.join(ROOT_PATH, 'packages', 'playwright-ct-react17'), | ||||
|     files: ['LICENSE'], | ||||
|   }), | ||||
|   new PWPackage({ | ||||
|     name: '@playwright/experimental-ct-solid', | ||||
|     path: path.join(ROOT_PATH, 'packages', 'playwright-ct-solid'), | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Sebastian Silbermann
						Sebastian Silbermann