chore: allow marking scripts as external for transform (#23449)
Fixes https://github.com/microsoft/playwright/issues/22874
This commit is contained in:
parent
14a1eaa474
commit
96b2247e28
|
|
@ -17,6 +17,25 @@ export default defineConfig({
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## property: TestConfig.build
|
||||||
|
* since: v1.35
|
||||||
|
- type: ?<[Object]>
|
||||||
|
- `external` ?<[Array]<[string]>> Paths to exclude from the transpilation expressed as glob patterns. Typically heavy JS bundles your tests reference.
|
||||||
|
|
||||||
|
Transpiler configuration.
|
||||||
|
|
||||||
|
**Usage**
|
||||||
|
|
||||||
|
```js title="playwright.config.ts"
|
||||||
|
import { defineConfig } from '@playwright/test';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
build: {
|
||||||
|
external: '**/*bundle.js',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
## property: TestConfig.expect
|
## property: TestConfig.expect
|
||||||
* since: v1.10
|
* since: v1.10
|
||||||
- type: ?<[Object]>
|
- type: ?<[Object]>
|
||||||
|
|
|
||||||
66
packages/playwright-ct-core/index.d.ts
vendored
Normal file
66
packages/playwright-ct-core/index.d.ts
vendored
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Microsoft Corporation.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type {
|
||||||
|
TestType,
|
||||||
|
PlaywrightTestArgs,
|
||||||
|
PlaywrightTestConfig as BasePlaywrightTestConfig,
|
||||||
|
PlaywrightTestOptions,
|
||||||
|
PlaywrightWorkerArgs,
|
||||||
|
PlaywrightWorkerOptions,
|
||||||
|
Locator,
|
||||||
|
} from '@playwright/test';
|
||||||
|
import type { JsonObject } from '@playwright/experimental-ct-core/types/component';
|
||||||
|
import type { InlineConfig } from 'vite';
|
||||||
|
|
||||||
|
export type PlaywrightTestConfig<T = {}, W = {}> = Omit<BasePlaywrightTestConfig<T, W>, 'use'> & {
|
||||||
|
use?: BasePlaywrightTestConfig<T, W>['use'] & {
|
||||||
|
ctPort?: number;
|
||||||
|
ctTemplateDir?: string;
|
||||||
|
ctCacheDir?: string;
|
||||||
|
ctViteConfig?: InlineConfig | (() => Promise<InlineConfig>);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface MountOptions<HooksConfig extends JsonObject> {
|
||||||
|
hooksConfig?: HooksConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MountResult extends Locator {
|
||||||
|
unmount(): Promise<void>;
|
||||||
|
update(component: JSX.Element): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ComponentFixtures {
|
||||||
|
mount<HooksConfig extends JsonObject>(
|
||||||
|
component: JSX.Element,
|
||||||
|
options?: MountOptions<HooksConfig>
|
||||||
|
): Promise<MountResult>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const test: TestType<
|
||||||
|
PlaywrightTestArgs & PlaywrightTestOptions & ComponentFixtures,
|
||||||
|
PlaywrightWorkerArgs & PlaywrightWorkerOptions
|
||||||
|
>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines Playwright config
|
||||||
|
*/
|
||||||
|
export function defineConfig(config: PlaywrightTestConfig): PlaywrightTestConfig;
|
||||||
|
export function defineConfig<T>(config: PlaywrightTestConfig<T>): PlaywrightTestConfig<T>;
|
||||||
|
export function defineConfig<T, W>(config: PlaywrightTestConfig<T, W>): PlaywrightTestConfig<T, W>;
|
||||||
|
|
||||||
|
export { expect, devices } from '@playwright/test';
|
||||||
32
packages/playwright-ct-core/index.js
Normal file
32
packages/playwright-ct-core/index.js
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Microsoft Corporation.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const { test: baseTest, expect, devices, defineConfig: originalDefineConfig } = require('@playwright/test');
|
||||||
|
const { fixtures } = require('./lib/mount');
|
||||||
|
|
||||||
|
const defineConfig = config => originalDefineConfig({
|
||||||
|
...config,
|
||||||
|
build: {
|
||||||
|
...config.build,
|
||||||
|
babelPlugins: [
|
||||||
|
[require.resolve('./lib/tsxTransform')]
|
||||||
|
],
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const test = baseTest.extend(fixtures);
|
||||||
|
|
||||||
|
module.exports = { test, expect, devices, defineConfig };
|
||||||
|
|
@ -12,6 +12,10 @@
|
||||||
},
|
},
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"types": "./index.d.ts",
|
||||||
|
"default": "./index.js"
|
||||||
|
},
|
||||||
"./cli": "./cli.js",
|
"./cli": "./cli.js",
|
||||||
"./lib/mount": "./lib/mount.js",
|
"./lib/mount": "./lib/mount.js",
|
||||||
"./lib/vitePlugin": "./lib/vitePlugin.js"
|
"./lib/vitePlugin": "./lib/vitePlugin.js"
|
||||||
|
|
|
||||||
|
|
@ -58,10 +58,6 @@ export function createPlugin(
|
||||||
configDir = configDirectory;
|
configDir = configDirectory;
|
||||||
},
|
},
|
||||||
|
|
||||||
babelPlugins: async () => [
|
|
||||||
[require.resolve('./tsxTransform')]
|
|
||||||
],
|
|
||||||
|
|
||||||
begin: async (suite: Suite) => {
|
begin: async (suite: Suite) => {
|
||||||
const use = config.projects[0].use as CtConfig;
|
const use = config.projects[0].use as CtConfig;
|
||||||
const port = use.ctPort || 3100;
|
const port = use.ctPort || 3100;
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const { test: baseTest, expect, devices, defineConfig: originalDefineConfig } = require('@playwright/test');
|
const { test, expect, devices, defineConfig: originalDefineConfig } = require('@playwright/experimental-ct-core');
|
||||||
const { fixtures } = require('@playwright/experimental-ct-core/lib/mount');
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const plugin = () => {
|
const plugin = () => {
|
||||||
|
|
@ -26,6 +25,5 @@ const plugin = () => {
|
||||||
() => import('@vitejs/plugin-react').then(plugin => plugin.default()));
|
() => import('@vitejs/plugin-react').then(plugin => plugin.default()));
|
||||||
};
|
};
|
||||||
const defineConfig = config => originalDefineConfig({ ...config, _plugins: [plugin] });
|
const defineConfig = config => originalDefineConfig({ ...config, _plugins: [plugin] });
|
||||||
const test = baseTest.extend(fixtures);
|
|
||||||
|
|
||||||
module.exports = { test, expect, devices, defineConfig };
|
module.exports = { test, expect, devices, defineConfig };
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const { test: baseTest, expect, devices, defineConfig: originalDefineConfig } = require('@playwright/test');
|
const { test, expect, devices, defineConfig: originalDefineConfig } = require('@playwright/experimental-ct-core');
|
||||||
const { fixtures } = require('@playwright/experimental-ct-core/lib/mount');
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const plugin = () => {
|
const plugin = () => {
|
||||||
|
|
@ -26,6 +25,5 @@ const plugin = () => {
|
||||||
() => import('@vitejs/plugin-react').then(plugin => plugin.default()));
|
() => import('@vitejs/plugin-react').then(plugin => plugin.default()));
|
||||||
};
|
};
|
||||||
const defineConfig = config => originalDefineConfig({ ...config, _plugins: [plugin] });
|
const defineConfig = config => originalDefineConfig({ ...config, _plugins: [plugin] });
|
||||||
const test = baseTest.extend(fixtures);
|
|
||||||
|
|
||||||
module.exports = { test, expect, devices, defineConfig };
|
module.exports = { test, expect, devices, defineConfig };
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const { test: baseTest, expect, devices, defineConfig: originalDefineConfig } = require('@playwright/test');
|
const { test, expect, devices, defineConfig: originalDefineConfig } = require('@playwright/experimental-ct-core');
|
||||||
const { fixtures } = require('@playwright/experimental-ct-core/lib/mount');
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const plugin = () => {
|
const plugin = () => {
|
||||||
|
|
@ -26,6 +25,5 @@ const plugin = () => {
|
||||||
() => import('vite-plugin-solid').then(plugin => plugin.default()));
|
() => import('vite-plugin-solid').then(plugin => plugin.default()));
|
||||||
};
|
};
|
||||||
const defineConfig = config => originalDefineConfig({ ...config, _plugins: [plugin] });
|
const defineConfig = config => originalDefineConfig({ ...config, _plugins: [plugin] });
|
||||||
const test = baseTest.extend(fixtures);
|
|
||||||
|
|
||||||
module.exports = { test, expect, devices, defineConfig };
|
module.exports = { test, expect, devices, defineConfig };
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const { test: baseTest, expect, devices, defineConfig: originalDefineConfig } = require('@playwright/test');
|
const { test, expect, devices, defineConfig: originalDefineConfig } = require('@playwright/experimental-ct-core');
|
||||||
const { fixtures } = require('@playwright/experimental-ct-core/lib/mount');
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const plugin = () => {
|
const plugin = () => {
|
||||||
|
|
@ -26,6 +25,5 @@ const plugin = () => {
|
||||||
() => import('@sveltejs/vite-plugin-svelte').then(plugin => plugin.svelte()));
|
() => import('@sveltejs/vite-plugin-svelte').then(plugin => plugin.svelte()));
|
||||||
};
|
};
|
||||||
const defineConfig = config => originalDefineConfig({ ...config, _plugins: [plugin] });
|
const defineConfig = config => originalDefineConfig({ ...config, _plugins: [plugin] });
|
||||||
const test = baseTest.extend(fixtures);
|
|
||||||
|
|
||||||
module.exports = { test, expect, devices, defineConfig };
|
module.exports = { test, expect, devices, defineConfig };
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const { test: baseTest, expect, devices, defineConfig: originalDefineConfig } = require('@playwright/test');
|
const { test, expect, devices, defineConfig: originalDefineConfig } = require('@playwright/experimental-ct-core');
|
||||||
const { fixtures } = require('@playwright/experimental-ct-core/lib/mount');
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const plugin = () => {
|
const plugin = () => {
|
||||||
|
|
@ -26,6 +25,5 @@ const plugin = () => {
|
||||||
() => import('@vitejs/plugin-vue').then(plugin => plugin.default()));
|
() => import('@vitejs/plugin-vue').then(plugin => plugin.default()));
|
||||||
}
|
}
|
||||||
const defineConfig = config => originalDefineConfig({ ...config, _plugins: [plugin] });
|
const defineConfig = config => originalDefineConfig({ ...config, _plugins: [plugin] });
|
||||||
const test = baseTest.extend(fixtures);
|
|
||||||
|
|
||||||
module.exports = { test, expect, devices, defineConfig };
|
module.exports = { test, expect, devices, defineConfig };
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const { test: baseTest, expect, devices, defineConfig: originalDefineConfig } = require('@playwright/test');
|
const { test, expect, devices, defineConfig: originalDefineConfig } = require('@playwright/experimental-ct-core');
|
||||||
const { fixtures } = require('@playwright/experimental-ct-core/lib/mount');
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const plugin = () => {
|
const plugin = () => {
|
||||||
|
|
@ -26,6 +25,5 @@ const plugin = () => {
|
||||||
() => import('@vitejs/plugin-vue2').then(plugin => plugin.default()));
|
() => import('@vitejs/plugin-vue2').then(plugin => plugin.default()));
|
||||||
};
|
};
|
||||||
const defineConfig = config => originalDefineConfig({ ...config, _plugins: [plugin] });
|
const defineConfig = config => originalDefineConfig({ ...config, _plugins: [plugin] });
|
||||||
const test = baseTest.extend(fixtures);
|
|
||||||
|
|
||||||
module.exports = { test, expect, devices, defineConfig };
|
module.exports = { test, expect, devices, defineConfig };
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import { getPackageJsonPath, mergeObjects } from '../util';
|
||||||
import type { Matcher } from '../util';
|
import type { Matcher } from '../util';
|
||||||
import type { ConfigCLIOverrides } from './ipc';
|
import type { ConfigCLIOverrides } from './ipc';
|
||||||
import type { FullConfig, FullProject } from '../../types/test';
|
import type { FullConfig, FullProject } from '../../types/test';
|
||||||
|
import { setTransformConfig } from '../transform/transform';
|
||||||
|
|
||||||
export type FixturesWithLocation = {
|
export type FixturesWithLocation = {
|
||||||
fixtures: Fixtures;
|
fixtures: Fixtures;
|
||||||
|
|
@ -124,6 +125,10 @@ export class FullConfigInternal {
|
||||||
this.projects = projectConfigs.map(p => new FullProjectInternal(configDir, config, this, p, this.configCLIOverrides, throwawayArtifactsPath));
|
this.projects = projectConfigs.map(p => new FullProjectInternal(configDir, config, this, p, this.configCLIOverrides, throwawayArtifactsPath));
|
||||||
resolveProjectDependencies(this.projects);
|
resolveProjectDependencies(this.projects);
|
||||||
this._assignUniqueProjectIds(this.projects);
|
this._assignUniqueProjectIds(this.projects);
|
||||||
|
setTransformConfig({
|
||||||
|
babelPlugins: (config as any).build?.babelPlugins || [],
|
||||||
|
external: config.build?.external || [],
|
||||||
|
});
|
||||||
this.config.projects = this.projects.map(p => p.project);
|
this.config.projects = this.projects.map(p => p.project);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { isRegExp } from 'playwright-core/lib/utils';
|
import { isRegExp } from 'playwright-core/lib/utils';
|
||||||
import type { ConfigCLIOverrides, SerializedConfig } from './ipc';
|
import type { ConfigCLIOverrides, SerializedConfig } from './ipc';
|
||||||
import { requireOrImport, setBabelPlugins } from '../transform/transform';
|
import { requireOrImport } from '../transform/transform';
|
||||||
import type { Config, Project } from '../../types/test';
|
import type { Config, Project } from '../../types/test';
|
||||||
import { errorWithFile } from '../util';
|
import { errorWithFile } from '../util';
|
||||||
import { setCurrentConfig } from './globals';
|
import { setCurrentConfig } from './globals';
|
||||||
|
|
@ -41,15 +41,12 @@ export class ConfigLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
static async deserialize(data: SerializedConfig): Promise<FullConfigInternal> {
|
static async deserialize(data: SerializedConfig): Promise<FullConfigInternal> {
|
||||||
setBabelPlugins(data.babelTransformPlugins);
|
|
||||||
addToCompilationCache(data.compilationCache);
|
addToCompilationCache(data.compilationCache);
|
||||||
await initializeEsmLoader();
|
|
||||||
|
|
||||||
const loader = new ConfigLoader(data.configCLIOverrides);
|
const loader = new ConfigLoader(data.configCLIOverrides);
|
||||||
|
const config = data.configFile ? await loader.loadConfigFile(data.configFile) : await loader.loadEmptyConfig(data.configDir);
|
||||||
if (data.configFile)
|
await initializeEsmLoader();
|
||||||
return await loader.loadConfigFile(data.configFile);
|
return config;
|
||||||
return await loader.loadEmptyConfig(data.configDir);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadConfigFile(file: string, ignoreProjectDependencies = false): Promise<FullConfigInternal> {
|
async loadConfigFile(file: string, ignoreProjectDependencies = false): Promise<FullConfigInternal> {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { addToCompilationCache, serializeCompilationCache } from '../transform/compilationCache';
|
import { addToCompilationCache, serializeCompilationCache } from '../transform/compilationCache';
|
||||||
import { getBabelPlugins } from '../transform/transform';
|
import { transformConfig } from '../transform/transform';
|
||||||
import { PortTransport } from '../transform/portTransport';
|
import { PortTransport } from '../transform/portTransport';
|
||||||
|
|
||||||
const port = (globalThis as any).__esmLoaderPort;
|
const port = (globalThis as any).__esmLoaderPort;
|
||||||
|
|
@ -47,6 +47,6 @@ export async function incorporateCompilationCache() {
|
||||||
export async function initializeEsmLoader() {
|
export async function initializeEsmLoader() {
|
||||||
if (!loaderChannel)
|
if (!loaderChannel)
|
||||||
return;
|
return;
|
||||||
await loaderChannel.send('setBabelPlugins', { plugins: getBabelPlugins() });
|
await loaderChannel.send('setTransformConfig', { config: transformConfig() });
|
||||||
await loaderChannel.send('addToCompilationCache', { cache: serializeCompilationCache() });
|
await loaderChannel.send('addToCompilationCache', { cache: serializeCompilationCache() });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,6 @@ export type SerializedConfig = {
|
||||||
configDir: string;
|
configDir: string;
|
||||||
configCLIOverrides: ConfigCLIOverrides;
|
configCLIOverrides: ConfigCLIOverrides;
|
||||||
compilationCache: any;
|
compilationCache: any;
|
||||||
babelTransformPlugins: [string, any?][];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TtyParams = {
|
export type TtyParams = {
|
||||||
|
|
@ -126,15 +125,11 @@ export type TeardownErrorsPayload = {
|
||||||
export type EnvProducedPayload = [string, string | null][];
|
export type EnvProducedPayload = [string, string | null][];
|
||||||
|
|
||||||
export function serializeConfig(config: FullConfigInternal): SerializedConfig {
|
export function serializeConfig(config: FullConfigInternal): SerializedConfig {
|
||||||
const babelTransformPlugins: [string, any?][] = [];
|
|
||||||
for (const plugin of config.plugins)
|
|
||||||
babelTransformPlugins.push(...plugin.babelPlugins || []);
|
|
||||||
const result: SerializedConfig = {
|
const result: SerializedConfig = {
|
||||||
configFile: config.config.configFile,
|
configFile: config.config.configFile,
|
||||||
configDir: config.configDir,
|
configDir: config.configDir,
|
||||||
configCLIOverrides: config.configCLIOverrides,
|
configCLIOverrides: config.configCLIOverrides,
|
||||||
compilationCache: serializeCompilationCache(),
|
compilationCache: serializeCompilationCache(),
|
||||||
babelTransformPlugins,
|
|
||||||
};
|
};
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ import type { InternalReporter } from '../reporters/internalReporter';
|
||||||
export interface TestRunnerPlugin {
|
export interface TestRunnerPlugin {
|
||||||
name: string;
|
name: string;
|
||||||
setup?(config: FullConfig, configDir: string, reporter: InternalReporter): Promise<void>;
|
setup?(config: FullConfig, configDir: string, reporter: InternalReporter): Promise<void>;
|
||||||
babelPlugins?(): Promise<[string, any?][]>;
|
|
||||||
begin?(suite: Suite): Promise<void>;
|
begin?(suite: Suite): Promise<void>;
|
||||||
end?(): Promise<void>;
|
end?(): Promise<void>;
|
||||||
teardown?(): Promise<void>;
|
teardown?(): Promise<void>;
|
||||||
|
|
@ -29,7 +28,6 @@ export interface TestRunnerPlugin {
|
||||||
export type TestRunnerPluginRegistration = {
|
export type TestRunnerPluginRegistration = {
|
||||||
factory: TestRunnerPlugin | (() => TestRunnerPlugin | Promise<TestRunnerPlugin>);
|
factory: TestRunnerPlugin | (() => TestRunnerPlugin | Promise<TestRunnerPlugin>);
|
||||||
instance?: TestRunnerPlugin;
|
instance?: TestRunnerPlugin;
|
||||||
babelPlugins?: [string, any?][];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export { webServer } from './webServerPlugin';
|
export { webServer } from './webServerPlugin';
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ import { loadTestFile } from '../common/testLoader';
|
||||||
import type { FullConfigInternal } from '../common/config';
|
import type { FullConfigInternal } from '../common/config';
|
||||||
import { PoolBuilder } from '../common/poolBuilder';
|
import { PoolBuilder } from '../common/poolBuilder';
|
||||||
import { addToCompilationCache } from '../transform/compilationCache';
|
import { addToCompilationCache } from '../transform/compilationCache';
|
||||||
import { setBabelPlugins } from '../transform/transform';
|
|
||||||
import { incorporateCompilationCache, initializeEsmLoader } from '../common/esmLoaderHost';
|
import { incorporateCompilationCache, initializeEsmLoader } from '../common/esmLoaderHost';
|
||||||
|
|
||||||
export class InProcessLoaderHost {
|
export class InProcessLoaderHost {
|
||||||
|
|
@ -35,10 +34,6 @@ export class InProcessLoaderHost {
|
||||||
}
|
}
|
||||||
|
|
||||||
async start() {
|
async start() {
|
||||||
const babelTransformPlugins: [string, any?][] = [];
|
|
||||||
for (const plugin of this._config.plugins)
|
|
||||||
babelTransformPlugins.push(...plugin.babelPlugins || []);
|
|
||||||
setBabelPlugins(babelTransformPlugins);
|
|
||||||
await initializeEsmLoader();
|
await initializeEsmLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,6 @@ function createPluginSetupTask(plugin: TestRunnerPluginRegistration): Task<TestR
|
||||||
else
|
else
|
||||||
plugin.instance = plugin.factory;
|
plugin.instance = plugin.factory;
|
||||||
await plugin.instance?.setup?.(config.config, config.configDir, reporter);
|
await plugin.instance?.setup?.(config.config, config.configDir, reporter);
|
||||||
plugin.babelPlugins = await plugin.instance?.babelPlugins?.() || [];
|
|
||||||
return () => plugin.instance?.teardown?.();
|
return () => plugin.instance?.teardown?.();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@
|
||||||
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import url from 'url';
|
import url from 'url';
|
||||||
import { addToCompilationCache, belongsToNodeModules, currentFileDepsCollector, serializeCompilationCache, startCollectingFileDeps, stopCollectingFileDeps } from './compilationCache';
|
import { addToCompilationCache, currentFileDepsCollector, serializeCompilationCache, startCollectingFileDeps, stopCollectingFileDeps } from './compilationCache';
|
||||||
import { transformHook, resolveHook, setBabelPlugins } from './transform';
|
import { transformHook, resolveHook, setTransformConfig, shouldTransform } from './transform';
|
||||||
import { PortTransport } from './portTransport';
|
import { PortTransport } from './portTransport';
|
||||||
|
|
||||||
// Node < 18.6: defaultResolve takes 3 arguments.
|
// Node < 18.6: defaultResolve takes 3 arguments.
|
||||||
|
|
@ -50,7 +50,7 @@ async function load(moduleUrl: string, context: { format?: string }, defaultLoad
|
||||||
|
|
||||||
const filename = url.fileURLToPath(moduleUrl);
|
const filename = url.fileURLToPath(moduleUrl);
|
||||||
// Bail for node_modules.
|
// Bail for node_modules.
|
||||||
if (belongsToNodeModules(filename))
|
if (!shouldTransform(filename))
|
||||||
return defaultLoad(moduleUrl, context, defaultLoad);
|
return defaultLoad(moduleUrl, context, defaultLoad);
|
||||||
|
|
||||||
const code = fs.readFileSync(filename, 'utf-8');
|
const code = fs.readFileSync(filename, 'utf-8');
|
||||||
|
|
@ -68,8 +68,8 @@ let transport: PortTransport | undefined;
|
||||||
|
|
||||||
function globalPreload(context: { port: MessagePort }) {
|
function globalPreload(context: { port: MessagePort }) {
|
||||||
transport = new PortTransport(context.port, async (method, params) => {
|
transport = new PortTransport(context.port, async (method, params) => {
|
||||||
if (method === 'setBabelPlugins') {
|
if (method === 'setTransformConfig') {
|
||||||
setBabelPlugins(params.plugins);
|
setTransformConfig(params.config);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,8 @@ import type { TsConfigLoaderResult } from '../third_party/tsconfig-loader';
|
||||||
import { tsConfigLoader } from '../third_party/tsconfig-loader';
|
import { tsConfigLoader } from '../third_party/tsconfig-loader';
|
||||||
import Module from 'module';
|
import Module from 'module';
|
||||||
import type { BabelPlugin, BabelTransformFunction } from './babelBundle';
|
import type { BabelPlugin, BabelTransformFunction } from './babelBundle';
|
||||||
import { fileIsModule, resolveImportSpecifierExtension } from '../util';
|
import { createFileMatcher, fileIsModule, resolveImportSpecifierExtension } from '../util';
|
||||||
|
import type { Matcher } from '../util';
|
||||||
import { getFromCompilationCache, currentFileDepsCollector, belongsToNodeModules } from './compilationCache';
|
import { getFromCompilationCache, currentFileDepsCollector, belongsToNodeModules } from './compilationCache';
|
||||||
|
|
||||||
const version = require('../../package.json').version;
|
const version = require('../../package.json').version;
|
||||||
|
|
@ -35,14 +36,25 @@ type ParsedTsConfigData = {
|
||||||
};
|
};
|
||||||
const cachedTSConfigs = new Map<string, ParsedTsConfigData | undefined>();
|
const cachedTSConfigs = new Map<string, ParsedTsConfigData | undefined>();
|
||||||
|
|
||||||
let babelPlugins: BabelPlugin[] = [];
|
export type TransformConfig = {
|
||||||
|
babelPlugins: [string, any?][];
|
||||||
|
external: string[];
|
||||||
|
};
|
||||||
|
|
||||||
export function setBabelPlugins(plugins: BabelPlugin[]) {
|
let _transformConfig: TransformConfig = {
|
||||||
babelPlugins = plugins;
|
babelPlugins: [],
|
||||||
|
external: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
let _externalMatcher: Matcher = () => false;
|
||||||
|
|
||||||
|
export function setTransformConfig(config: TransformConfig) {
|
||||||
|
_transformConfig = config;
|
||||||
|
_externalMatcher = createFileMatcher(_transformConfig.external);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getBabelPlugins(): BabelPlugin[] {
|
export function transformConfig(): TransformConfig {
|
||||||
return babelPlugins;
|
return _transformConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateTsConfig(tsconfig: TsConfigLoaderResult): ParsedTsConfigData | undefined {
|
function validateTsConfig(tsconfig: TsConfigLoaderResult): ParsedTsConfigData | undefined {
|
||||||
|
|
@ -75,7 +87,7 @@ const builtins = new Set(Module.builtinModules);
|
||||||
export function resolveHook(filename: string, specifier: string): string | undefined {
|
export function resolveHook(filename: string, specifier: string): string | undefined {
|
||||||
if (specifier.startsWith('node:') || builtins.has(specifier))
|
if (specifier.startsWith('node:') || builtins.has(specifier))
|
||||||
return;
|
return;
|
||||||
if (belongsToNodeModules(filename))
|
if (!shouldTransform(filename))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (isRelativeSpecifier(specifier))
|
if (isRelativeSpecifier(specifier))
|
||||||
|
|
@ -138,13 +150,19 @@ export function resolveHook(filename: string, specifier: string): string | undef
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function shouldTransform(filename: string): boolean {
|
||||||
|
if (_externalMatcher(filename))
|
||||||
|
return false;
|
||||||
|
return !belongsToNodeModules(filename);
|
||||||
|
}
|
||||||
|
|
||||||
export function transformHook(originalCode: string, filename: string, moduleUrl?: string): string {
|
export function transformHook(originalCode: string, filename: string, moduleUrl?: string): string {
|
||||||
const isTypeScript = filename.endsWith('.ts') || filename.endsWith('.tsx') || filename.endsWith('.mts') || filename.endsWith('.cts');
|
const isTypeScript = filename.endsWith('.ts') || filename.endsWith('.tsx') || filename.endsWith('.mts') || filename.endsWith('.cts');
|
||||||
const hasPreprocessor =
|
const hasPreprocessor =
|
||||||
process.env.PW_TEST_SOURCE_TRANSFORM &&
|
process.env.PW_TEST_SOURCE_TRANSFORM &&
|
||||||
process.env.PW_TEST_SOURCE_TRANSFORM_SCOPE &&
|
process.env.PW_TEST_SOURCE_TRANSFORM_SCOPE &&
|
||||||
process.env.PW_TEST_SOURCE_TRANSFORM_SCOPE.split(pathSeparator).some(f => filename.startsWith(f));
|
process.env.PW_TEST_SOURCE_TRANSFORM_SCOPE.split(pathSeparator).some(f => filename.startsWith(f));
|
||||||
const pluginsPrologue = babelPlugins;
|
const pluginsPrologue = _transformConfig.babelPlugins;
|
||||||
const pluginsEpilogue = hasPreprocessor ? [[process.env.PW_TEST_SOURCE_TRANSFORM!]] as BabelPlugin[] : [];
|
const pluginsEpilogue = hasPreprocessor ? [[process.env.PW_TEST_SOURCE_TRANSFORM!]] as BabelPlugin[] : [];
|
||||||
const hash = calculateHash(originalCode, filename, !!moduleUrl, pluginsPrologue, pluginsEpilogue);
|
const hash = calculateHash(originalCode, filename, !!moduleUrl, pluginsPrologue, pluginsEpilogue);
|
||||||
const { cachedCode, addToCache } = getFromCompilationCache(filename, hash, moduleUrl);
|
const { cachedCode, addToCache } = getFromCompilationCache(filename, hash, moduleUrl);
|
||||||
|
|
@ -209,7 +227,7 @@ function installTransform(): () => void {
|
||||||
(Module as any)._resolveFilename = resolveFilename;
|
(Module as any)._resolveFilename = resolveFilename;
|
||||||
|
|
||||||
const revertPirates = pirates.addHook((code: string, filename: string) => {
|
const revertPirates = pirates.addHook((code: string, filename: string) => {
|
||||||
if (belongsToNodeModules(filename))
|
if (!shouldTransform(filename))
|
||||||
return code;
|
return code;
|
||||||
return transformHook(code, filename);
|
return transformHook(code, filename);
|
||||||
}, { exts: ['.ts', '.tsx', '.js', '.jsx', '.mjs'] });
|
}, { exts: ['.ts', '.tsx', '.js', '.jsx', '.mjs'] });
|
||||||
|
|
|
||||||
25
packages/playwright-test/types/test.d.ts
vendored
25
packages/playwright-test/types/test.d.ts
vendored
|
|
@ -569,6 +569,31 @@ interface TestConfig {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
webServer?: TestConfigWebServer | TestConfigWebServer[];
|
webServer?: TestConfigWebServer | TestConfigWebServer[];
|
||||||
|
/**
|
||||||
|
* Transpiler configuration.
|
||||||
|
*
|
||||||
|
* **Usage**
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* // playwright.config.ts
|
||||||
|
* import { defineConfig } from '@playwright/test';
|
||||||
|
*
|
||||||
|
* export default defineConfig({
|
||||||
|
* build: {
|
||||||
|
* external: '**\/*bundle.js',
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
build?: {
|
||||||
|
/**
|
||||||
|
* Paths to exclude from the transpilation expressed as glob patterns. Typically heavy JS bundles your tests
|
||||||
|
* reference.
|
||||||
|
*/
|
||||||
|
external?: Array<string>;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration for the `expect` assertion library. Learn more about [various timeouts](https://playwright.dev/docs/test-timeouts).
|
* Configuration for the `expect` assertion library. Learn more about [various timeouts](https://playwright.dev/docs/test-timeouts).
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -131,3 +131,22 @@ test('should not read browserslist file', async ({ runInlineTest }) => {
|
||||||
expect(result.passed).toBe(1);
|
expect(result.passed).toBe(1);
|
||||||
expect(result.failed).toBe(0);
|
expect(result.failed).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should not transform external', async ({ runInlineTest }) => {
|
||||||
|
const result = await runInlineTest({
|
||||||
|
'playwright.config.ts': `
|
||||||
|
import { defineConfig } from '@playwright/test';
|
||||||
|
export default defineConfig({
|
||||||
|
build: {
|
||||||
|
external: ['**/a.spec.ts']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
'a.spec.ts': `
|
||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
test('succeeds', () => {});
|
||||||
|
`
|
||||||
|
});
|
||||||
|
expect(result.exitCode).toBe(1);
|
||||||
|
expect(result.output).toContain('Cannot use import statement outside a module');
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue