diff --git a/packages/playwright/src/transform/transform.ts b/packages/playwright/src/transform/transform.ts index 076c3b59407ee..cf6a74d8aa4a0 100644 --- a/packages/playwright/src/transform/transform.ts +++ b/packages/playwright/src/transform/transform.ts @@ -215,7 +215,7 @@ export function transformHook(originalCode: string, filename: string, moduleUrl? process.env.PW_TEST_SOURCE_TRANSFORM_SCOPE && process.env.PW_TEST_SOURCE_TRANSFORM_SCOPE.split(pathSeparator).some(f => filename.startsWith(f)); const pluginsEpilogue = hasPreprocessor ? [[process.env.PW_TEST_SOURCE_TRANSFORM!]] as BabelPlugin[] : []; - const hash = calculateHash(originalCode, filename, !!moduleUrl, pluginsEpilogue); + const hash = calculateHash(originalCode, filename, !!moduleUrl, pluginsEpilogue, _transformConfig.jsxImportSource); const { cachedCode, addToCache, serializedCache } = cc.getFromCompilationCache(filename, hash, moduleUrl); if (cachedCode !== undefined) return { code: cachedCode, serializedCache }; @@ -233,13 +233,14 @@ export function transformHook(originalCode: string, filename: string, moduleUrl? return { code, serializedCache: added.serializedCache }; } -function calculateHash(content: string, filePath: string, isModule: boolean, pluginsEpilogue: BabelPlugin[]): string { +function calculateHash(content: string, filePath: string, isModule: boolean, pluginsEpilogue: BabelPlugin[], jsxImportSource: string | undefined): string { const hash = crypto.createHash('sha1') .update(isModule ? 'esm' : 'no_esm') .update(content) .update(filePath) .update(version) .update(pluginsEpilogue.map(p => p[0]).join(',')) + .update(jsxImportSource || '') .digest('hex'); return hash; } diff --git a/tests/playwright-test/cache.spec.ts b/tests/playwright-test/cache.spec.ts index 132cf8ca6ee68..307ab16c9dc31 100644 --- a/tests/playwright-test/cache.spec.ts +++ b/tests/playwright-test/cache.spec.ts @@ -101,3 +101,40 @@ test('should automatically clean cached versions of a changed file', async ({ ru expect(finalPathHash).toBe(firstPathHash); expect(finalTestHash).not.toBe(firstTestHash); }); + +test('should not reuse cached jsx transform after playwright moves', { + annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/42934' }, +}, async ({ runInlineTest, writeFiles, childProcess }) => { + const cacheDir = test.info().outputPath('playwright-test-cache'); + const files = { + 'playwright.config.ts': ` + import { defineConfig } from '@playwright/test'; + export default defineConfig({}); + `, + 'a.spec.tsx': ` + import { test, expect } from '@playwright/test'; + const element =
; + test('jsx', () => { expect(element).toBeTruthy(); }); + `, + }; + const baseDir = await writeFiles(files); + + // Resolve playwright through symlinks so that the cached transform references them. + const packagesDir = path.join(__dirname, '../../packages'); + const nodeModules = path.join(baseDir, 'node_modules'); + await fs.promises.mkdir(path.join(nodeModules, '@playwright'), { recursive: true }); + await fs.promises.symlink(path.join(packagesDir, 'playwright'), path.join(nodeModules, 'playwright'), 'dir'); + await fs.promises.symlink(path.join(packagesDir, 'playwright-test'), path.join(nodeModules, '@playwright', 'test'), 'dir'); + const first = childProcess({ + command: ['node', '--preserve-symlinks', '--preserve-symlinks-main', path.join(nodeModules, '@playwright', 'test', 'cli.js'), 'test', '--list'], + env: { PWTEST_CACHE_DIR: cacheDir, NODE_PRESERVE_SYMLINKS: '1' }, + cwd: baseDir, + }); + expect((await first.exited).exitCode).toBe(0); + expect(first.output).toContain('Total: 1 test in 1 file'); + + await fs.promises.rm(nodeModules, { recursive: true }); + const result = await runInlineTest(files, undefined, { PWTEST_CACHE_DIR: cacheDir }); + expect(result.exitCode).toBe(0); + expect(result.passed).toBe(1); +});