diff --git a/packages/playwright-test/src/transform.ts b/packages/playwright-test/src/transform.ts index a6e4ffe5c6..ad19c2d6c9 100644 --- a/packages/playwright-test/src/transform.ts +++ b/packages/playwright-test/src/transform.ts @@ -26,7 +26,7 @@ import { tsConfigLoader } from './third_party/tsconfig-loader'; import Module from 'module'; import type { BabelTransformFunction } from './babelBundle'; -const version = 10; +const version = 11; const cacheDir = process.env.PWTEST_CACHE_DIR || path.join(os.tmpdir(), 'playwright-transform-cache'); const sourceMaps: Map = new Map(); diff --git a/packages/playwright-test/src/tsxTransform.ts b/packages/playwright-test/src/tsxTransform.ts index 77a48f1353..728d7205ea 100644 --- a/packages/playwright-test/src/tsxTransform.ts +++ b/packages/playwright-test/src/tsxTransform.ts @@ -124,21 +124,38 @@ export default declare((api: BabelAPI) => { }); export function collectComponentUsages(node: T.Node) { + const importedLocalNames = new Set(); const names = new Set(); const identifiers = new Set(); traverse(node, { enter: p => { + + // First look at all the imports. + if (t.isImportDeclaration(p.node)) { + const importNode = p.node; + if (!t.isStringLiteral(importNode.source)) + return; + + for (const specifier of importNode.specifiers) { + if (t.isImportNamespaceSpecifier(specifier)) + continue; + importedLocalNames.add(specifier.local.name); + } + } + // Treat JSX-everything as component usages. if (t.isJSXElement(p.node) && t.isJSXIdentifier(p.node.openingElement.name)) names.add(p.node.openingElement.name.name); - // Treat mount(identifier, ...) as component usage. + // Treat mount(identifier, ...) as component usage if it is in the importedLocalNames list. if (t.isAwaitExpression(p.node) && t.isCallExpression(p.node.argument) && t.isIdentifier(p.node.argument.callee) && p.node.argument.callee.name === 'mount') { const callExpression = p.node.argument; - if (t.isIdentifier(callExpression.arguments[0])) { - names.add(callExpression.arguments[0].name); - identifiers.add(callExpression.arguments[0]); - } + const arg = callExpression.arguments[0]; + if (!t.isIdentifier(arg) || !importedLocalNames.has(arg.name)) + return; + + names.add(arg.name); + identifiers.add(arg); } } }); diff --git a/tests/playwright-test/playwright.ct-react.spec.ts b/tests/playwright-test/playwright.ct-react.spec.ts index 5b16f91cb5..9252c4e97b 100644 --- a/tests/playwright-test/playwright.ct-react.spec.ts +++ b/tests/playwright-test/playwright.ct-react.spec.ts @@ -240,3 +240,33 @@ test.fixme('should work with stray JS import', async ({ runInlineTest }) => { expect(result.exitCode).toBe(0); expect(result.passed).toBe(1); }); + +test('should work with JSX in variable', async ({ runInlineTest }) => { + const result = await runInlineTest({ + 'playwright/index.html': ``, + 'playwright/index.js': ` + //@no-header + `, + + 'src/button.jsx': ` + //@no-header + export const Button = () => ; + `, + + 'src/button.test.jsx': ` + //@no-header + import { test, expect } from '@playwright/experimental-ct-react'; + import { Button } from './button'; + + const button = ; + + test('pass button', async ({ mount }) => { + const component = await mount(button); + await expect(component).toHaveText('Button'); + }); + `, + }, { workers: 1 }); + + expect(result.exitCode).toBe(0); + expect(result.passed).toBe(1); +});