diff --git a/packages/playwright-ct-core/src/tsxTransform.ts b/packages/playwright-ct-core/src/tsxTransform.ts index 1ad02c51a1..de15d3912a 100644 --- a/packages/playwright-ct-core/src/tsxTransform.ts +++ b/packages/playwright-ct-core/src/tsxTransform.ts @@ -121,12 +121,15 @@ export default declare((api: BabelAPI) => { children.push(t.spreadElement(child.expression)); } - path.replaceWith(t.objectExpression([ + const component = [ t.objectProperty(t.identifier('kind'), t.stringLiteral('jsx')), t.objectProperty(t.identifier('type'), t.stringLiteral(componentName)), t.objectProperty(t.identifier('props'), t.objectExpression(props)), - t.objectProperty(t.identifier('children'), t.arrayExpression(children)), - ])); + ]; + if (children.length) + component.push(t.objectProperty(t.identifier('children'), t.arrayExpression(children))); + + path.replaceWith(t.objectExpression(component)); } } }; diff --git a/packages/playwright-ct-core/types/component.d.ts b/packages/playwright-ct-core/types/component.d.ts index dc3ec2beaf..ddac25ab32 100644 --- a/packages/playwright-ct-core/types/component.d.ts +++ b/packages/playwright-ct-core/types/component.d.ts @@ -25,7 +25,7 @@ export type JsxComponent = { kind: 'jsx', type: string, props: Record, - children: JsxComponentChild[], + children?: JsxComponentChild[], }; export type MountOptions = { diff --git a/packages/playwright-ct-react/registerSource.mjs b/packages/playwright-ct-react/registerSource.mjs index 6231dae353..6ac6b8372d 100644 --- a/packages/playwright-ct-react/registerSource.mjs +++ b/packages/playwright-ct-react/registerSource.mjs @@ -71,7 +71,7 @@ async function __pwResolveComponent(component) { if (componentFactory) __pwRegistry.set(component.type, await componentFactory()); - if ('children' in component) + if (component.children?.length) await Promise.all(component.children.map(child => __pwResolveComponent(child))); } @@ -91,7 +91,7 @@ function __renderChild(child) { */ function __pwRender(component) { const componentFunc = __pwRegistry.get(component.type); - const children = component.children.map(child => __renderChild(child)).filter(child => { + const children = component.children?.map(child => __renderChild(child)).filter(child => { if (typeof child === 'string') return !!child.trim(); return true; diff --git a/packages/playwright-ct-react17/registerSource.mjs b/packages/playwright-ct-react17/registerSource.mjs index b50168ed0e..e6f89db935 100644 --- a/packages/playwright-ct-react17/registerSource.mjs +++ b/packages/playwright-ct-react17/registerSource.mjs @@ -70,7 +70,7 @@ async function __pwResolveComponent(component) { if (componentFactory) __pwRegistry.set(component.type, await componentFactory()); - if ('children' in component) + if (component.children?.length) await Promise.all(component.children.map(child => __pwResolveComponent(child))); } @@ -90,7 +90,7 @@ function __renderChild(child) { */ function __pwRender(component) { const componentFunc = __pwRegistry.get(component.type); - const children = component.children.map(child => __renderChild(child)).filter(child => { + const children = component.children?.map(child => __renderChild(child)).filter(child => { if (typeof child === 'string') return !!child.trim(); return true; diff --git a/packages/playwright-ct-solid/registerSource.mjs b/packages/playwright-ct-solid/registerSource.mjs index fed1b46540..1704a4ba9a 100644 --- a/packages/playwright-ct-solid/registerSource.mjs +++ b/packages/playwright-ct-solid/registerSource.mjs @@ -69,7 +69,7 @@ async function __pwResolveComponent(component) { if (componentFactory) __pwRegistry.set(component.type, await componentFactory()); - if ('children' in component) + if (component.children?.length) await Promise.all(component.children.map(child => __pwResolveComponent(child))); } @@ -89,7 +89,7 @@ function __pwCreateChild(child) { */ function __pwCreateComponent(component) { const componentFunc = __pwRegistry.get(component.type); - const children = component.children.map(child => __pwCreateChild(child)).filter(child => { + const children = component.children?.map(child => __pwCreateChild(child)).filter(child => { if (typeof child === 'string') return !!child.trim(); return true; diff --git a/packages/playwright-ct-vue/registerSource.mjs b/packages/playwright-ct-vue/registerSource.mjs index c78b3f6ac2..8ee030daf7 100644 --- a/packages/playwright-ct-vue/registerSource.mjs +++ b/packages/playwright-ct-vue/registerSource.mjs @@ -72,7 +72,7 @@ async function __pwResolveComponent(component) { if (componentFactory) __pwRegistry.set(component.type, await componentFactory()); - if ('children' in component) + if ('children' in component && component.children?.length) await Promise.all(component.children.map(child => __pwResolveComponent(child))); } @@ -156,7 +156,7 @@ function __pwCreateComponent(component) { if (typeof child !== 'string' && child.type === 'template' && child.kind === 'jsx') { const slotProperty = Object.keys(child.props).find(k => k.startsWith('v-slot:')); const slot = slotProperty ? slotProperty.substring('v-slot:'.length) : 'default'; - slots[slot] = child.children.map(__pwCreateChild); + slots[slot] = child.children?.map(__pwCreateChild); } else { children.push(__pwCreateChild(child)); } diff --git a/packages/playwright-ct-vue2/registerSource.mjs b/packages/playwright-ct-vue2/registerSource.mjs index e67a22dd2b..043c680229 100644 --- a/packages/playwright-ct-vue2/registerSource.mjs +++ b/packages/playwright-ct-vue2/registerSource.mjs @@ -71,7 +71,7 @@ async function __pwResolveComponent(component) { if (componentFactory) __pwRegistry.set(component.type, await componentFactory()); - if ('children' in component) + if ('children' in component && component.children?.length) await Promise.all(component.children.map(child => __pwResolveComponent(child))); } @@ -124,7 +124,7 @@ function __pwCreateComponent(component) { if (typeof child !== 'string' && child.type === 'template' && child.kind === 'jsx') { const slotProperty = Object.keys(child.props).find(k => k.startsWith('v-slot:')); const slot = slotProperty ? slotProperty.substring('v-slot:'.length) : 'default'; - nodeData.scopedSlots[slot] = () => child.children.map(c => __pwCreateChild(c)); + nodeData.scopedSlots[slot] = () => child.children?.map(c => __pwCreateChild(c)); } else { children.push(__pwCreateChild(child)); } diff --git a/tests/components/ct-react-vite/src/components/EmptyFragment.tsx b/tests/components/ct-react-vite/src/components/EmptyFragment.tsx index 64cb1177a3..b424841462 100644 --- a/tests/components/ct-react-vite/src/components/EmptyFragment.tsx +++ b/tests/components/ct-react-vite/src/components/EmptyFragment.tsx @@ -1,3 +1,4 @@ -export default function EmptyFragment() { +export default function EmptyFragment(props: unknown) { + Object.assign(window, { props }); return <>{[]}; } diff --git a/tests/components/ct-react-vite/tests/render.spec.tsx b/tests/components/ct-react-vite/tests/render.spec.tsx index f8ab02e819..107a18bf65 100644 --- a/tests/components/ct-react-vite/tests/render.spec.tsx +++ b/tests/components/ct-react-vite/tests/render.spec.tsx @@ -12,8 +12,9 @@ test('render attributes', async ({ mount }) => { await expect(component).toHaveClass('primary'); }); -test('get textContent of the empty fragment', async ({ mount }) => { +test('render an empty component', async ({ mount, page }) => { const component = await mount(); + expect(await page.evaluate(() => 'props' in window && window.props)).toEqual({}); expect(await component.allTextContents()).toEqual(['']); expect(await component.textContent()).toBe(''); await expect(component).toHaveText(''); diff --git a/tests/components/ct-react17/src/components/EmptyFragment.tsx b/tests/components/ct-react17/src/components/EmptyFragment.tsx index 64cb1177a3..b424841462 100644 --- a/tests/components/ct-react17/src/components/EmptyFragment.tsx +++ b/tests/components/ct-react17/src/components/EmptyFragment.tsx @@ -1,3 +1,4 @@ -export default function EmptyFragment() { +export default function EmptyFragment(props: unknown) { + Object.assign(window, { props }); return <>{[]}; } diff --git a/tests/components/ct-react17/tests/render.spec.tsx b/tests/components/ct-react17/tests/render.spec.tsx index 9795e753a9..ec9405c82f 100644 --- a/tests/components/ct-react17/tests/render.spec.tsx +++ b/tests/components/ct-react17/tests/render.spec.tsx @@ -20,8 +20,9 @@ test('render delayed data', async ({ mount }) => { await expect(component).toHaveText('complete'); }); -test('get textContent of the empty fragment', async ({ mount }) => { +test('render an empty component', async ({ mount, page }) => { const component = await mount(); + expect(await page.evaluate(() => 'props' in window && window.props)).toEqual({}); expect(await component.allTextContents()).toEqual(['']); expect(await component.textContent()).toBe(''); await expect(component).toHaveText(''); diff --git a/tests/components/ct-solid/src/components/EmptyFragment.tsx b/tests/components/ct-solid/src/components/EmptyFragment.tsx index 64cb1177a3..b424841462 100644 --- a/tests/components/ct-solid/src/components/EmptyFragment.tsx +++ b/tests/components/ct-solid/src/components/EmptyFragment.tsx @@ -1,3 +1,4 @@ -export default function EmptyFragment() { +export default function EmptyFragment(props: unknown) { + Object.assign(window, { props }); return <>{[]}; } diff --git a/tests/components/ct-solid/tests/render.spec.tsx b/tests/components/ct-solid/tests/render.spec.tsx index 70e5082bc2..199e5f4f03 100644 --- a/tests/components/ct-solid/tests/render.spec.tsx +++ b/tests/components/ct-solid/tests/render.spec.tsx @@ -12,8 +12,9 @@ test('render attributes', async ({ mount }) => { await expect(component).toHaveClass('primary'); }); -test('get textContent of the empty fragment', async ({ mount }) => { +test('render an empty component', async ({ mount, page }) => { const component = await mount(); + expect(await page.evaluate(() => 'props' in window && window.props)).toEqual({}); expect(await component.allTextContents()).toEqual(['']); expect(await component.textContent()).toBe(''); await expect(component).toHaveText(''); diff --git a/tests/components/ct-vue-cli/src/components/EmptyTemplate.vue b/tests/components/ct-vue-cli/src/components/EmptyTemplate.vue index ba5341392f..9b4c59695e 100644 --- a/tests/components/ct-vue-cli/src/components/EmptyTemplate.vue +++ b/tests/components/ct-vue-cli/src/components/EmptyTemplate.vue @@ -1,2 +1,8 @@ + \ No newline at end of file + + diff --git a/tests/components/ct-vue-cli/tests/render/render.spec.tsx b/tests/components/ct-vue-cli/tests/render/render.spec.tsx index 1fb6964fb3..c051422fdd 100644 --- a/tests/components/ct-vue-cli/tests/render/render.spec.tsx +++ b/tests/components/ct-vue-cli/tests/render/render.spec.tsx @@ -7,8 +7,9 @@ test('render props', async ({ mount }) => { await expect(component).toContainText('Submit'); }); -test('get textContent of the empty template', async ({ mount }) => { +test('render an empty component', async ({ page, mount }) => { const component = await mount(); + expect(await page.evaluate(() => 'slots' in window && window.slots)).toEqual({}); expect(await component.allTextContents()).toEqual(['']); expect(await component.textContent()).toBe(''); await expect(component).toHaveText(''); diff --git a/tests/components/ct-vue-vite/src/components/EmptyTemplate.vue b/tests/components/ct-vue-vite/src/components/EmptyTemplate.vue index ba5341392f..0c47e38098 100644 --- a/tests/components/ct-vue-vite/src/components/EmptyTemplate.vue +++ b/tests/components/ct-vue-vite/src/components/EmptyTemplate.vue @@ -1,2 +1,7 @@ + \ No newline at end of file + diff --git a/tests/components/ct-vue-vite/tests/render/render.spec.tsx b/tests/components/ct-vue-vite/tests/render/render.spec.tsx index 918f0e0113..e4cf96ec8f 100644 --- a/tests/components/ct-vue-vite/tests/render/render.spec.tsx +++ b/tests/components/ct-vue-vite/tests/render/render.spec.tsx @@ -12,8 +12,9 @@ test('render attributes', async ({ mount }) => { await expect(component).toHaveClass('primary'); }); -test('get textContent of the empty template', async ({ mount }) => { +test('render an empty component', async ({ page, mount }) => { const component = await mount(); + expect(await page.evaluate(() => 'slots' in window && window.slots)).toEqual({}); expect(await component.allTextContents()).toEqual(['']); expect(await component.textContent()).toBe(''); await expect(component).toHaveText(''); diff --git a/tests/components/ct-vue2-cli/src/components/EmptyTemplate.vue b/tests/components/ct-vue2-cli/src/components/EmptyTemplate.vue index ba5341392f..9b4c59695e 100644 --- a/tests/components/ct-vue2-cli/src/components/EmptyTemplate.vue +++ b/tests/components/ct-vue2-cli/src/components/EmptyTemplate.vue @@ -1,2 +1,8 @@ + \ No newline at end of file + + diff --git a/tests/components/ct-vue2-cli/tests/render/render.spec.tsx b/tests/components/ct-vue2-cli/tests/render/render.spec.tsx index 42307ff8f6..699269545d 100644 --- a/tests/components/ct-vue2-cli/tests/render/render.spec.tsx +++ b/tests/components/ct-vue2-cli/tests/render/render.spec.tsx @@ -12,8 +12,9 @@ test('render attributes', async ({ mount }) => { await expect(component).toHaveClass('primary'); }); -test('get textContent of the empty template', async ({ mount }) => { +test('render an empty component', async ({ page, mount }) => { const component = await mount(); + expect(await page.evaluate(() => 'slots' in window && window.slots)).toEqual({}); expect(await component.allTextContents()).toEqual(['']); expect(await component.textContent()).toBe(''); await expect(component).toHaveText('');