diff --git a/packages/playwright-ct-react/registerSource.mjs b/packages/playwright-ct-react/registerSource.mjs index e5a14c3db6..4b233a8dec 100644 --- a/packages/playwright-ct-react/registerSource.mjs +++ b/packages/playwright-ct-react/registerSource.mjs @@ -33,12 +33,24 @@ function isJsxComponent(component) { } /** + * @param {any} type + * @returns {boolean} type is Playwright's mock JSX.Fragment + */ +function isJsxFragment(type) { + return typeof type === 'object' && type?.__pw_jsx_fragment; +} + +/** + * Turns the Playwright representation of JSX (see jsx-runtime.js) into React.createElement calls. * @param {any} value */ function __pwRender(value) { return window.__pwTransformObject(value, v => { if (isJsxComponent(v)) { const component = v; + let type = component.type; + if (isJsxFragment(type)) + type = __pwReact.Fragment; const props = component.props ? __pwRender(component.props) : {}; const key = component.key ? __pwRender(component.key) : undefined; const { children, ...propsWithoutChildren } = props; @@ -47,7 +59,7 @@ function __pwRender(value) { const createElementArguments = [propsWithoutChildren]; if (children) createElementArguments.push(children); - return { result: __pwReact.createElement(component.type, ...createElementArguments) }; + return { result: __pwReact.createElement(type, ...createElementArguments) }; } }); } diff --git a/packages/playwright/jsx-runtime.js b/packages/playwright/jsx-runtime.js index d35e5e6e8d..ff3d79e34e 100644 --- a/packages/playwright/jsx-runtime.js +++ b/packages/playwright/jsx-runtime.js @@ -32,7 +32,8 @@ function jsxs(type, props, key) { }; } -const Fragment = {}; +// this is used in <> notation +const Fragment = { __pw_jsx_fragment: true }; module.exports = { Fragment, diff --git a/tests/components/ct-react-vite/tests/render.spec.tsx b/tests/components/ct-react-vite/tests/render.spec.tsx index d00a313e9e..b7d0e61b29 100644 --- a/tests/components/ct-react-vite/tests/render.spec.tsx +++ b/tests/components/ct-react-vite/tests/render.spec.tsx @@ -46,3 +46,8 @@ test('render inline component with an error if its nested', async ({ mount }) => )).rejects.toThrow('Component "MyInlineComponent" cannot be mounted.'); }); + +test('render Fragment shorthand notation', { annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/32853' } }, async ({ mount }) => { + const component = await mount(<>Learn React); + await expect(component).toContainText('Learn React'); +});