Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/src/test-typescript-js.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ npx tsc -p tsconfig.json --noEmit -w

## tsconfig.json

Playwright will pick up `tsconfig.json` for each source file it loads. Note that Playwright **only supports** the following tsconfig options: `allowJs`, `baseUrl`, `paths` and `references`.
Playwright will pick up `tsconfig.json` for each source file it loads. Note that Playwright **only supports** the following tsconfig options: `allowJs`, `baseUrl`, `paths`, `references` and `extends`.

We recommend setting up a separate `tsconfig.json` in the tests directory so that you can change some preferences specifically for the tests. Here is an example directory structure.

Expand Down
9 changes: 6 additions & 3 deletions packages/playwright/src/transform/tsconfig-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,17 @@ export function loadTsConfig(configPath: string): LoadedTsConfig[] {
}
}

function resolveConfigFile(baseConfigFile: string, referencedConfigFile: string) {
function resolveConfigFile(baseConfigFile: string, referencedConfigFile: string, kind: 'extends' | 'references') {
const originalReferencedConfigFile = referencedConfigFile;
if (!referencedConfigFile.endsWith('.json'))
referencedConfigFile += '.json';
const currentDir = path.dirname(baseConfigFile);
let resolvedConfigFile = path.resolve(currentDir, referencedConfigFile);
// TODO: I don't see how this makes sense, delete in the next minor release.
if (referencedConfigFile.includes('/') && referencedConfigFile.includes('.') && !fs.existsSync(resolvedConfigFile))
resolvedConfigFile = path.join(currentDir, 'node_modules', referencedConfigFile);
if (!fs.existsSync(resolvedConfigFile))
throw new Error(`Failed to resolve "${kind}" path "${originalReferencedConfigFile}" referenced from ${baseConfigFile}`);
return resolvedConfigFile;
}

Expand All @@ -95,7 +98,7 @@ function innerLoadTsConfig(

const extendsArray = Array.isArray(parsedConfig.extends) ? parsedConfig.extends : (parsedConfig.extends ? [parsedConfig.extends] : []);
for (const extendedConfig of extendsArray) {
const extendedConfigPath = resolveConfigFile(configFilePath, extendedConfig);
const extendedConfigPath = resolveConfigFile(configFilePath, extendedConfig, 'extends');
const base = innerLoadTsConfig(extendedConfigPath, references, visited);
// Retain result instance, so that caching works.
Object.assign(result, base, { tsConfigPath: configFilePath });
Expand All @@ -120,7 +123,7 @@ function innerLoadTsConfig(
}

for (const ref of parsedConfig.references || [])
references.push(innerLoadTsConfig(resolveConfigFile(configFilePath, ref.path), references, visited));
references.push(innerLoadTsConfig(resolveConfigFile(configFilePath, ref.path, 'references'), references, visited));

if (path.basename(configFilePath) === 'jsconfig.json' && result.allowJs === undefined)
result.allowJs = true;
Expand Down
40 changes: 40 additions & 0 deletions tests/playwright-test/resolver.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,43 @@ test('should resolve paths relative to the originating config when extending and
expect(result.exitCode).toBe(0);
});

test('should fail loudly when extends path cannot be resolved', async ({ runInlineTest }) => {
test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/41543' });

const result = await runInlineTest({
'tsconfig.json': `{
"extends": "./tsconfig.bas.json",
}`,
'a.test.ts': `
import { test, expect } from '@playwright/test';
test('test', () => {});
`,
});

expect(result.exitCode).toBe(1);
expect(result.output).toContain('Failed to resolve "extends" path "./tsconfig.bas.json"');
});

test('should fail loudly when references path cannot be resolved', async ({ runInlineTest }) => {
test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/41543' });

const result = await runInlineTest({
'tsconfig.json': `{
"files": [],
"references": [
{ "path": "./tsconfig.doesnotexist.json" }
]
}`,
'a.test.ts': `
import { test, expect } from '@playwright/test';
test('test', () => {});
`,
});

expect(result.exitCode).toBe(1);
expect(result.output).toContain('Failed to resolve "references" path "./tsconfig.doesnotexist.json"');
});

test('should respect tsconfig project references', async ({ runInlineTest }) => {
test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/29256' });

Expand All @@ -599,6 +636,9 @@ test('should respect tsconfig project references', async ({ runInlineTest }) =>
{ "path": "./tsconfig.test.json" }
]
}`,
'tsconfig.app.json': `{
"compilerOptions": {},
}`,
'tsconfig.test.json': `{
"compilerOptions": {
"baseUrl": ".",
Expand Down
Loading