feat: config.build.tsconfig (#33026)

Allows to specify `tsconfig` in the configuration file, which applies to
test files but not the config file itself.

Fixes #32808.
This commit is contained in:
Dmitry Gozman 2024-10-10 01:37:46 -07:00 committed by GitHub
parent 8f3353865d
commit 25dd9b5cd4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 109 additions and 0 deletions

View file

@ -552,6 +552,22 @@ export default defineConfig({
}); });
``` ```
## property: TestConfig.tsconfig
* since: v1.49
- type: ?<[string]>
Path to a single `tsconfig` applicable to all imported files. By default, `tsconfig` for each imported file is looked up separately. Note that `tsconfig` property has no effect while the configuration file or any of its dependencies are loaded. Ignored when `--tsconfig` command line option is specified.
**Usage**
```js title="playwright.config.ts"
import { defineConfig } from '@playwright/test';
export default defineConfig({
tsconfig: './tsconfig.test.json',
});
```
## property: TestConfig.updateSnapshots ## property: TestConfig.updateSnapshots
* since: v1.10 * since: v1.10
- type: ?<[UpdateSnapshots]<"all"|"none"|"missing">> - type: ?<[UpdateSnapshots]<"all"|"none"|"missing">>

View file

@ -90,6 +90,16 @@ Alternatively, you can specify a single tsconfig file to use in the command line
npx playwright test --tsconfig=tsconfig.test.json npx playwright test --tsconfig=tsconfig.test.json
``` ```
You can specify a single tsconfig file in the config file, that will be used for loading test files, reporters, etc. However, it will not be used while loading the playwright config itself or any files imported from it.
```js title="playwright.config.ts"
import { defineConfig } from '@playwright/test';
export default defineConfig({
tsconfig: './tsconfig.test.json',
});
```
## Manually compile tests with TypeScript ## Manually compile tests with TypeScript
Sometimes, Playwright Test will not be able to transform your TypeScript code correctly, for example when you are using experimental or very recent features of TypeScript, usually configured in `tsconfig.json`. Sometimes, Playwright Test will not be able to transform your TypeScript code correctly, for example when you are using experimental or very recent features of TypeScript, usually configured in `tsconfig.json`.

View file

@ -45,6 +45,7 @@ export class FullConfigInternal {
readonly webServers: NonNullable<FullConfig['webServer']>[]; readonly webServers: NonNullable<FullConfig['webServer']>[];
readonly plugins: TestRunnerPluginRegistration[]; readonly plugins: TestRunnerPluginRegistration[];
readonly projects: FullProjectInternal[] = []; readonly projects: FullProjectInternal[] = [];
readonly singleTSConfigPath?: string;
cliArgs: string[] = []; cliArgs: string[] = [];
cliGrep: string | undefined; cliGrep: string | undefined;
cliGrepInvert: string | undefined; cliGrepInvert: string | undefined;
@ -69,6 +70,7 @@ export class FullConfigInternal {
this.configCLIOverrides = configCLIOverrides; this.configCLIOverrides = configCLIOverrides;
const privateConfiguration = (userConfig as any)['@playwright/test']; const privateConfiguration = (userConfig as any)['@playwright/test'];
this.plugins = (privateConfiguration?.plugins || []).map((p: any) => ({ factory: p })); this.plugins = (privateConfiguration?.plugins || []).map((p: any) => ({ factory: p }));
this.singleTSConfigPath = pathResolve(configDir, userConfig.tsconfig);
this.config = { this.config = {
configFile: resolvedConfigFile, configFile: resolvedConfigFile,

View file

@ -118,6 +118,8 @@ export async function loadConfig(location: ConfigLocation, overrides?: ConfigCLI
const babelPlugins = (userConfig as any)['@playwright/test']?.babelPlugins || []; const babelPlugins = (userConfig as any)['@playwright/test']?.babelPlugins || [];
const external = userConfig.build?.external || []; const external = userConfig.build?.external || [];
setTransformConfig({ babelPlugins, external }); setTransformConfig({ babelPlugins, external });
if (!overrides?.tsconfig)
setSingleTSConfig(fullConfig?.singleTSConfigPath);
// 4. Send transform options to ESM loader. // 4. Send transform options to ESM loader.
await configureESMLoaderTransformConfig(); await configureESMLoaderTransformConfig();

View file

@ -77,5 +77,6 @@ export async function configureESMLoader() {
export async function configureESMLoaderTransformConfig() { export async function configureESMLoaderTransformConfig() {
if (!loaderChannel) if (!loaderChannel)
return; return;
await loaderChannel.send('setSingleTSConfig', { tsconfig: singleTSConfig() });
await loaderChannel.send('setTransformConfig', { config: transformConfig() }); await loaderChannel.send('setTransformConfig', { config: transformConfig() });
} }

View file

@ -1642,6 +1642,25 @@ interface TestConfig<TestArgs = {}, WorkerArgs = {}> {
*/ */
timeout?: number; timeout?: number;
/**
* Path to a single `tsconfig` applicable to all imported files. By default, `tsconfig` for each imported file is
* looked up separately. Note that `tsconfig` property has no effect while the configuration file or any of its
* dependencies are loaded. Ignored when `--tsconfig` command line option is specified.
*
* **Usage**
*
* ```js
* // playwright.config.ts
* import { defineConfig } from '@playwright/test';
*
* export default defineConfig({
* tsconfig: './tsconfig.test.json',
* });
* ```
*
*/
tsconfig?: string;
/** /**
* Whether to update expected snapshots with the actual results produced by the test run. Defaults to `'missing'`. * Whether to update expected snapshots with the actual results produced by the test run. Defaults to `'missing'`.
* - `'all'` - All tests that are executed will update snapshots that did not match. Matching snapshots will not be * - `'all'` - All tests that are executed will update snapshots that did not match. Matching snapshots will not be

View file

@ -675,6 +675,65 @@ test('should respect --tsconfig option', async ({ runInlineTest }) => {
expect(result.output).not.toContain(`Could not`); expect(result.output).not.toContain(`Could not`);
}); });
test('should respect config.tsconfig option', async ({ runInlineTest }) => {
const result = await runInlineTest({
'playwright.config.ts': `
export { configFoo } from '~/foo';
export default {
testDir: './tests',
tsconfig: './tsconfig.tests.json',
};
`,
'tsconfig.json': `{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"~/*": ["./mapped-from-config/*"],
},
},
}`,
'mapped-from-config/foo.ts': `
export const configFoo = 17;
`,
'tsconfig.tests.json': `{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"~/*": ["./mapped-from-tests/*"],
},
},
}`,
'mapped-from-tests/foo.ts': `
export const testFoo = 42;
`,
'tests/tsconfig.json': `{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"~/*": ["../should-be-ignored/*"],
},
},
}`,
'tests/a.test.ts': `
import { testFoo } from '~/foo';
import { configFoo } from '../playwright.config';
import { test, expect } from '@playwright/test';
test('test', ({}) => {
expect(testFoo).toBe(42);
expect(configFoo).toBe(17);
});
`,
'should-be-ignored/foo.ts': `
export const testFoo = 43;
export const configFoo = 18;
`,
});
expect(result.passed).toBe(1);
expect(result.exitCode).toBe(0);
expect(result.output).not.toContain(`Could not`);
});
test.describe('directory imports', () => { test.describe('directory imports', () => {
test('should resolve index.js without path mapping in CJS', async ({ runInlineTest, runTSC }) => { test('should resolve index.js without path mapping in CJS', async ({ runInlineTest, runTSC }) => {
const files = { const files = {