diff --git a/packages/playwright-test/src/transform.ts b/packages/playwright-test/src/transform.ts index 3d31df012d..c9f6219564 100644 --- a/packages/playwright-test/src/transform.ts +++ b/packages/playwright-test/src/transform.ts @@ -189,27 +189,33 @@ export function transformHook(code: string, filename: string, isModule = false): if (hasPreprocessor) plugins.push([scriptPreprocessor]); - const result = babel.transformFileSync(filename, { - babelrc: false, - configFile: false, - assumptions: { - // Without this, babel defines a top level function that - // breaks playwright evaluates. - setPublicClassFields: true, - }, - presets: [ - [require.resolve('@babel/preset-typescript'), { onlyRemoveTypeImports: true }], - ], - plugins, - sourceMaps: 'both', - } as babel.TransformOptions)!; - if (result.code) { - fs.mkdirSync(path.dirname(cachePath), { recursive: true }); - if (result.map) - fs.writeFileSync(sourceMapPath, JSON.stringify(result.map), 'utf8'); - fs.writeFileSync(codePath, result.code, 'utf8'); + try { + const result = babel.transformFileSync(filename, { + babelrc: false, + configFile: false, + assumptions: { + // Without this, babel defines a top level function that + // breaks playwright evaluates. + setPublicClassFields: true, + }, + presets: [ + [require.resolve('@babel/preset-typescript'), { onlyRemoveTypeImports: true }], + ], + plugins, + sourceMaps: 'both', + } as babel.TransformOptions)!; + if (result.code) { + fs.mkdirSync(path.dirname(cachePath), { recursive: true }); + if (result.map) + fs.writeFileSync(sourceMapPath, JSON.stringify(result.map), 'utf8'); + fs.writeFileSync(codePath, result.code, 'utf8'); + } + return result.code || ''; + } catch (e) { + // Re-throw error with a playwright-test stack + // that could be filtered out. + throw new Error(e.message); } - return result.code || ''; } export function installTransform(): () => void { diff --git a/packages/playwright-test/src/util.ts b/packages/playwright-test/src/util.ts index 59ca3e03f0..28ac6a3b5a 100644 --- a/packages/playwright-test/src/util.ts +++ b/packages/playwright-test/src/util.ts @@ -47,7 +47,10 @@ function filterStackTrace(e: Error) { const functionName = callSite.getFunctionName() || undefined; if (!fileName) return true; - return !fileName.startsWith(PLAYWRIGHT_TEST_PATH) && !fileName.startsWith(PLAYWRIGHT_CORE_PATH) && !fileName.startsWith(EXPECT_PATH) && !isInternalFileName(fileName, functionName); + return !fileName.startsWith(PLAYWRIGHT_TEST_PATH) && + !fileName.startsWith(PLAYWRIGHT_CORE_PATH) && + !fileName.startsWith(EXPECT_PATH) && + !isInternalFileName(fileName, functionName); })); }; // eslint-disable-next-line diff --git a/tests/playwright-test/loader.spec.ts b/tests/playwright-test/loader.spec.ts index ad6a4f449f..5aba8151a5 100644 --- a/tests/playwright-test/loader.spec.ts +++ b/tests/playwright-test/loader.spec.ts @@ -314,6 +314,21 @@ test('should filter out event emitter from stack traces', async ({ runInlineTest expect(outputWithoutGoodStackFrames).not.toContain('EventEmitter.emit'); }); +test('should filter out syntax error stack traces', async ({ runInlineTest }, testInfo) => { + const result = await runInlineTest({ + 'expect-test.spec.ts': ` + const { test } = pwt; + test('should work', ({}) => { + // syntax error: cannot have await in non-async function + await Proimse.resolve(); + }); + ` + }); + expect(result.exitCode).toBe(1); + expect(stripAnsi(result.output)).not.toContain('babel'); + expect(stripAnsi(result.output)).not.toContain(' at '); +}); + test('should filter stack trace for raw errors', async ({ runInlineTest }) => { const result = await runInlineTest({ 'expect-test.spec.ts': `