diff --git a/packages/playwright/src/transform/babelBundle.ts b/packages/playwright/src/transform/babelBundle.ts index 20f75bdabd60d..6503009c16820 100644 --- a/packages/playwright/src/transform/babelBundle.ts +++ b/packages/playwright/src/transform/babelBundle.ts @@ -41,6 +41,24 @@ function babelTransformOptions(isTypeScript: boolean, isModule: boolean, plugins if (isTypeScript) { plugins.push( + // Strip "declare" class fields before these plugins run: + // - plugin-proposal-decorators + // - plugin-transform-class-properties + // - plugin-transform-private-methods + // See https://github.com/microsoft/playwright/issues/38586 + [ + (): PluginObj => ({ + name: 'strip-declare-class-fields', + visitor: { + Class(path) { + for (const member of path.get('body.body')) { + if (member.isClassProperty() && member.node.declare) + member.remove(); + } + } + } + }) + ], [require('@babel/plugin-proposal-decorators'), { version: '2023-05' }], [require('@babel/plugin-transform-class-properties')], [require('@babel/plugin-transform-class-static-block')], diff --git a/tests/playwright-test/babel.spec.ts b/tests/playwright-test/babel.spec.ts index 0d7572de5ba1a..5843ab7384f7f 100644 --- a/tests/playwright-test/babel.spec.ts +++ b/tests/playwright-test/babel.spec.ts @@ -37,6 +37,37 @@ test('should succeed', async ({ runInlineTest }) => { expect(result.failed).toBe(0); }); +test('should support declare class fields', { + annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/38586' }, +}, async ({ runInlineTest }) => { + const result = await runInlineTest({ + 'one-success.spec.ts': ` + import { test, expect } from '@playwright/test'; + + class Base { + constructor(p1, p2) { + this.p1 = p1; + this.p2 = p2; + } + } + + class Derived extends Base { + p1: string; + declare p2: string; + } + + test('works', () => { + const d = new Derived('value1', 'value2'); + expect(d.p1).toBe(undefined); + expect(d.p2).toBe('value2'); + }) + ` + }); + expect(result.exitCode).toBe(0); + expect(result.passed).toBe(1); + expect(result.failed).toBe(0); +}); + test('should treat enums equally', async ({ runInlineTest }) => { const result = await runInlineTest({ 'component.tsx': `