chore: use plugin story for components (#13717)

This commit is contained in:
Pavel Feldman 2022-04-25 09:40:58 -08:00 committed by GitHub
parent e69e836c40
commit 5e51c17d41
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 189 additions and 180 deletions

View file

@ -319,6 +319,9 @@ The directory for each test can be accessed by [`property: TestInfo.snapshotDir`
This path will serve as the base directory for each test file snapshot directory. Setting `snapshotDir` to `'snapshots'`, the [`property: TestInfo.snapshotDir`] would resolve to `snapshots/a.spec.js-snapshots`.
## property: TestConfig.plugins
- type: ?<[Array]<[TestPlugin]>>
## property: TestConfig.preserveOutput
- type: ?<[PreserveOutput]<"always"|"never"|"failures-only">>

View file

@ -0,0 +1,14 @@
# class: TestPlugin
* langs: js
## optional async method: TestPlugin.configure
### param: TestPlugin.configure.config
- `config` <[TestConfig]>
### param: TestPlugin.configure.configDir
- `configDir` <[string]>
## optional async method: TestPlugin.setup
## optional async method: TestPlugin.teardown

View file

@ -5,8 +5,6 @@
"scripts": {
"dev": "vite",
"build": "vite build && tsc",
"preview": "vite preview",
"playwright-build": "vite --config playwright.vite.config.ts build",
"playwright-dev": "vite --config playwright.vite.config.ts"
"preview": "vite preview"
}
}

View file

@ -17,6 +17,7 @@
import type { PlaywrightTestConfig } from '@playwright/test';
import path from 'path';
import { devices } from '@playwright/test';
import vite from '@playwright/experimental-ct-react/vitePlugin';
const config: PlaywrightTestConfig = {
testDir: 'src',
@ -27,14 +28,10 @@ const config: PlaywrightTestConfig = {
] : [
['html', { open: 'on-failure' }]
],
webServer: {
url: 'http://localhost:3101/playwright/index.html',
command: 'npm run playwright-dev',
cwd: __dirname,
reuseExistingServer: !process.env.CI,
},
plugins: [
vite({ port: 3101 })
],
use: {
baseURL: 'http://localhost:3101/playwright/index.html',
trace: 'on-first-retry',
},
projects: [ ],

View file

@ -1,37 +0,0 @@
/**
* 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 { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import playwright from '@playwright/experimental-ct-react/vitePlugin';
import path from 'path';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
react(),
playwright(),
],
resolve: {
alias: {
'@web': path.resolve(__dirname, '../web/src'),
'@playwright-core': path.resolve(__dirname, '../playwright-core/src'),
},
},
server: {
port: 3101,
},
});

View file

@ -14,4 +14,11 @@
* limitations under the License.
*/
export default function(options?: { include?: string }): any;
import { TestPlugin } from '@playwright/test';
import type { InlineConfig } from 'vite';
export default function(options?: {
config?: InlineConfig,
include?: string
port?: number,
}): TestPlugin;

View file

@ -14,5 +14,8 @@
* limitations under the License.
*/
const { createVitePlugin } = require('@playwright/test/lib/vitePlugin');
module.exports = createVitePlugin('@playwright/experimental-ct-react/register');
const { createPlugin } = require('@playwright/test/lib/plugins/vitePlugin');
module.exports = (options = {}) => {
return createPlugin('@playwright/experimental-ct-react/register', options);
};

View file

@ -14,4 +14,11 @@
* limitations under the License.
*/
export default function(options?: { include?: string }): any;
import { TestPlugin } from '@playwright/test';
import type { InlineConfig } from 'vite';
export default function(options?: {
config?: InlineConfig,
include?: string
port?: number,
}): TestPlugin;

View file

@ -14,5 +14,8 @@
* limitations under the License.
*/
const { createVitePlugin } = require('@playwright/test/lib/vitePlugin');
module.exports = createVitePlugin('@playwright/experimental-ct-svelte/register');
const { createPlugin } = require('@playwright/test/lib/plugins/vitePlugin');
module.exports = (options = {}) => {
return createPlugin('@playwright/experimental-ct-svelte/register', options);
};

View file

@ -14,4 +14,11 @@
* limitations under the License.
*/
export default function(options?: { include?: string }): any;
import { TestPlugin } from '@playwright/test';
import type { InlineConfig } from 'vite';
export default function(options?: {
config?: InlineConfig,
include?: string,
port?: number,
}): TestPlugin;

View file

@ -14,5 +14,8 @@
* limitations under the License.
*/
const { createVitePlugin } = require('@playwright/test/lib/vitePlugin');
module.exports = createVitePlugin('@playwright/experimental-ct-vue/register');
const { createPlugin } = require('@playwright/test/lib/plugins/vitePlugin');
module.exports = (options = {}) => {
return createPlugin('@playwright/experimental-ct-vue/register', options);
};

View file

@ -19,7 +19,7 @@
"./lib/cli": "./lib/cli.js",
"./lib/experimentalLoader": "./lib/experimentalLoader.js",
"./lib/mount": "./lib/mount.js",
"./lib/vitePlugin": "./lib/vitePlugin.js",
"./lib/plugins/vitePlugin": "./lib/plugins/vitePlugin.js",
"./reporter": "./reporter.js"
},
"bin": {

View file

@ -76,6 +76,9 @@ export class Loader {
}
private _processConfigObject(config: Config, configDir: string) {
for (const plugin of config.plugins || [])
plugin.configure?.(config, configDir);
this._configDir = configDir;
const packageJsonPath = getPackageJsonPath(configDir);
const packageJsonDir = packageJsonPath ? path.dirname(packageJsonPath) : undefined;
@ -121,6 +124,7 @@ export class Loader {
this._fullConfig.updateSnapshots = takeFirst(this._configOverrides.updateSnapshots, config.updateSnapshots, baseFullConfig.updateSnapshots);
this._fullConfig.workers = takeFirst(this._configOverrides.workers, config.workers, baseFullConfig.workers);
this._fullConfig.webServer = takeFirst(this._configOverrides.webServer, config.webServer, baseFullConfig.webServer);
this._fullConfig._plugins = takeFirst(this._configOverrides.plugins, config.plugins, baseFullConfig._plugins);
const projects: Project[] = ('projects' in config) && config.projects !== undefined ? config.projects : [config];
for (const project of projects)
@ -480,6 +484,7 @@ const baseFullConfig: FullConfigInternal = {
_globalOutputDir: path.resolve(process.cwd()),
_configDir: '',
_testGroupsCount: 0,
_plugins: [],
};
function resolveReporters(reporters: Config['reporter'], rootDir: string): ReporterDescription[]|undefined {

View file

@ -0,0 +1,2 @@
[*]
../

View file

@ -14,29 +14,63 @@
* limitations under the License.
*/
import type { PlaywrightTestConfig, TestPlugin } from '@playwright/test';
import fs from 'fs';
import path from 'path';
import { glob } from 'playwright-core/lib/utilsBundle';
import { parse, types as t, traverse } from './babelBundle';
import type { Plugin } from 'vite';
import { componentInfo, collectComponentUsages } from './tsxTransform';
import type { ComponentInfo } from './tsxTransform';
import type { InlineConfig, Plugin, ViteDevServer } from 'vite';
import { parse, traverse, types as t } from '../babelBundle';
import type { ComponentInfo } from '../tsxTransform';
import { collectComponentUsages, componentInfo } from '../tsxTransform';
const imports: Map<string, ComponentInfo> = new Map();
let viteDevServer: ViteDevServer;
export function createVitePlugin(registerFunction: string) {
return (options?: { include: string }) => {
return vitePlugin({ ...(options || {}), registerFunction });
export function createPlugin(
registerFunction: string,
options: {
include?: string,
port?: number,
config?: InlineConfig
} = {}): TestPlugin {
const viteConfig = options.config || {};
const port = options.port || 3100;
let configDir: string;
return {
configure: async (config: PlaywrightTestConfig, configDirectory: string) => {
configDir = configDirectory;
const url = `http://localhost:${port}/playwright/index.html`;
if (!config.use)
config.use = {};
config.use!.baseURL = url;
},
setup: async () => {
viteConfig.root = viteConfig.root || configDir;
viteConfig.plugins = viteConfig.plugins || [];
viteConfig.plugins.push(vitePlugin(registerFunction, options.include));
viteConfig.configFile = viteConfig.configFile || false;
viteConfig.server = viteConfig.server || {};
viteConfig.server.port = port;
const { createServer } = require('vite');
viteDevServer = await createServer(viteConfig);
await viteDevServer.listen(port);
},
teardown: async () => {
await viteDevServer.close();
},
};
}
function vitePlugin(options: { include?: string, registerFunction: string }): Plugin {
const imports: Map<string, ComponentInfo> = new Map();
function vitePlugin(registerFunction: string, include: string | undefined): Plugin {
return {
name: 'playwright-gallery',
name: 'playwright:component-index',
configResolved: async config => {
const files = await new Promise<string[]>((f, r) => {
glob(options.include || config.root + '/**/*.{test,spec}.[tj]s{x,}', {}, function(err, files) {
glob(include || config.root + '/**/*.{test,spec}.[tj]s{x,}', {}, function(err, files) {
if (err)
r(err);
else
@ -76,7 +110,7 @@ function vitePlugin(options: { include?: string, registerFunction: string }): Pl
const folder = path.dirname(id);
const lines = [content, ''];
lines.push(`import register from '${options.registerFunction}';`);
lines.push(`import register from '${registerFunction}';`);
for (const [alias, value] of imports) {
const importPath = value.isModuleOrAlias ? value.importPath : './' + path.relative(folder, value.importPath).replace(/\\/g, '/');

View file

@ -50,8 +50,6 @@ const readDirAsync = promisify(fs.readdir);
const readFileAsync = promisify(fs.readFile);
export const kDefaultConfigFiles = ['playwright.config.ts', 'playwright.config.js', 'playwright.config.mjs'];
type InternalGlobalSetupFunction = () => Promise<() => Promise<void>>;
type RunOptions = {
listOnly?: boolean;
filePatternFilter?: FilePatternFilter[];
@ -61,7 +59,6 @@ type RunOptions = {
export class Runner {
private _loader: Loader;
private _reporter!: Reporter;
private _internalGlobalSetups: Array<InternalGlobalSetupFunction> = [];
private _globalInfo: GlobalInfoImpl;
constructor(configOverrides: Config, options: { defaultConfig?: Config } = {}) {
@ -70,7 +67,7 @@ export class Runner {
}
async loadConfigFromResolvedFile(resolvedConfigFile: string): Promise<Config> {
return this._loader.loadConfigFile(resolvedConfigFile);
return await this._loader.loadConfigFile(resolvedConfigFile);
}
loadEmptyConfig(configFileOrDirectory: string): Config {
@ -148,10 +145,6 @@ export class Runner {
return new Multiplexer(reporters);
}
addInternalGlobalSetup(internalGlobalSetup: InternalGlobalSetupFunction) {
this._internalGlobalSetups.push(internalGlobalSetup);
}
async runAllTests(options: RunOptions = {}): Promise<FullResult> {
this._reporter = await this._createReporter(!!options.listOnly);
const config = this._loader.fullConfig();
@ -430,11 +423,12 @@ export class Runner {
private async _performGlobalSetup(config: FullConfigInternal): Promise<(() => Promise<void>) | undefined> {
const result: FullResult = { status: 'passed' };
const internalGlobalTeardowns: (() => Promise<void>)[] = [];
const pluginTeardowns: (() => Promise<void>)[] = [];
let globalSetupResult: any;
let webServer: WebServer | undefined;
const tearDown = async () => {
// Reverse to setup.
await this._runAndReportError(async () => {
if (globalSetupResult && typeof globalSetupResult === 'function')
await globalSetupResult(this._loader.fullConfig());
@ -449,16 +443,26 @@ export class Runner {
await webServer?.kill();
}, result);
await this._runAndReportError(async () => {
for (const internalGlobalTeardown of internalGlobalTeardowns)
await internalGlobalTeardown();
}, result);
for (const teardown of pluginTeardowns) {
await this._runAndReportError(async () => {
await teardown();
}, result);
}
};
await this._runAndReportError(async () => {
for (const internalGlobalSetup of this._internalGlobalSetups)
internalGlobalTeardowns.push(await internalGlobalSetup());
// First run the plugins, if plugin is a web server we want it to run before the
// config's global setup.
for (const plugin of config._plugins) {
await plugin.setup?.();
if (plugin.teardown)
pluginTeardowns.unshift(plugin.teardown);
}
// Then do legacy web server.
webServer = config.webServer ? await WebServer.create(config.webServer, this._reporter) : undefined;
// The do global setup.
if (config.globalSetup)
globalSetupResult = await (await this._loader.loadGlobalHook(config.globalSetup, 'globalSetup'))(this._loader.fullConfig(), this._globalInfo);
}, result);

View file

@ -14,7 +14,7 @@
* limitations under the License.
*/
import type { Fixtures, TestError, Project } from '../types/test';
import type { Fixtures, TestError, Project, TestPlugin } from '../types/test';
import type { Location } from '../types/testReporter';
import type { FullConfig as FullConfigPublic, FullProject as FullProjectPublic } from './types';
export * from '../types/test';
@ -48,6 +48,7 @@ export interface FullConfigInternal extends FullConfigPublic {
_globalOutputDir: string;
_configDir: string;
_testGroupsCount: number;
_plugins: TestPlugin[];
// Overrides the public field.
projects: FullProjectInternal[];

View file

@ -685,6 +685,8 @@ interface TestConfig {
*/
snapshotDir?: string;
plugins?: Array<TestPlugin>;
/**
* Whether to preserve test output in the
* [testConfig.outputDir](https://playwright.dev/docs/api/class-testconfig#test-config-output-dir). Defaults to `'always'`.
@ -3723,6 +3725,18 @@ export interface TestError {
value?: string;
}
export interface TestPlugin {
/**
* @param config
* @param configDir
*/
configure?(config: TestConfig, configDir: string): Promise<void>;
setup?(): Promise<void>;
teardown?(): Promise<void>;
}
/**
* Playwright Test supports running multiple test projects at the same time. This is useful for running tests in multiple
* configurations. For example, consider running tests against multiple browsers.

View file

@ -16,6 +16,7 @@
import type { PlaywrightTestConfig } from '@playwright/test';
import { devices } from '@playwright/test';
import vite from '@playwright/experimental-ct-react/vitePlugin';
const config: PlaywrightTestConfig = {
testDir: 'src',
@ -26,14 +27,10 @@ const config: PlaywrightTestConfig = {
] : [
['html', { open: 'on-failure' }]
],
webServer: {
url: 'http://localhost:3102/playwright/index.html',
command: 'npx vite --config playwright.vite.config.ts dev',
cwd: __dirname,
reuseExistingServer: !process.env.CI,
},
plugins: [
vite({ port: 3101 })
],
use: {
baseURL: 'http://localhost:3102/playwright/index.html',
trace: 'on-first-retry',
},
projects: [

View file

@ -1,30 +0,0 @@
/**
* 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 { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import playwright from '@playwright/experimental-ct-react/vitePlugin';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
react(),
playwright(),
],
server: {
port: 3102,
},
});

View file

@ -15,6 +15,7 @@
*/
import { PlaywrightTestConfig, devices } from '@playwright/test';
import vite from '@playwright/experimental-ct-react/vitePlugin';
const config: PlaywrightTestConfig = {
testDir: 'src',
@ -25,13 +26,10 @@ const config: PlaywrightTestConfig = {
] : [
['html', { open: 'on-failure' }]
],
webServer: {
url: 'http://localhost:3000/playwright/index.html',
command: 'npm run playwright-dev',
reuseExistingServer: !process.env.CI,
},
plugins: [
vite(),
],
use: {
baseURL: 'http://localhost:3000/playwright/index.html',
trace: 'on-first-retry',
},
projects: [

View file

@ -1,11 +0,0 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import playwright from '@playwright/experimental-ct-react/vitePlugin';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
react(),
playwright(),
]
});

View file

@ -1,3 +1,4 @@
import React from 'react'
import { useState } from 'react'
import logo from './logo.svg'
import './App.css'

View file

@ -16,6 +16,8 @@
import type { PlaywrightTestConfig } from '@playwright/test';
import { devices } from '@playwright/test';
import vite from '@playwright/experimental-ct-svelte/vitePlugin';
import { svelte } from '@sveltejs/vite-plugin-svelte';
const config: PlaywrightTestConfig = {
testDir: 'src',
@ -26,13 +28,12 @@ const config: PlaywrightTestConfig = {
] : [
['html', { open: 'on-failure' }]
],
webServer: {
url: 'http://localhost:3000/playwright/index.html',
command: 'npm run playwright-dev',
reuseExistingServer: !process.env.CI,
},
plugins: [
vite({
config: { plugins: [ svelte() ] }
}),
],
use: {
baseURL: 'http://localhost:3000/playwright/index.html',
trace: 'on-first-retry',
},
projects: [

View file

@ -1,11 +0,0 @@
import { defineConfig } from 'vite'
import { svelte } from '@sveltejs/vite-plugin-svelte'
import playwright from '@playwright/experimental-ct-svelte/vitePlugin';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
svelte(),
playwright(),
]
})

View file

@ -1,7 +0,0 @@
import { defineConfig } from 'vite'
import { svelte } from '@sveltejs/vite-plugin-svelte'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [svelte()]
})

View file

@ -15,6 +15,8 @@
*/
import { PlaywrightTestConfig, devices } from '@playwright/test';
import vite from '@playwright/experimental-ct-vue/vitePlugin';
import vue from '@vitejs/plugin-vue'
const config: PlaywrightTestConfig = {
testDir: 'src',
@ -25,13 +27,14 @@ const config: PlaywrightTestConfig = {
] : [
['html', { open: 'on-failure' }]
],
webServer: {
url: 'http://localhost:3000/playwright/index.html',
command: 'npm run playwright-dev',
reuseExistingServer: !process.env.CI,
},
plugins: [
vite({
config: {
plugins: [ vue() ]
}
}),
],
use: {
baseURL: 'http://localhost:3000/playwright/index.html',
trace: 'on-first-retry',
},
projects: [

View file

@ -1,11 +0,0 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import playwright from '@playwright/experimental-ct-vue/vitePlugin';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
playwright(),
]
})

View file

@ -16893,6 +16893,8 @@ interface TestConfig {
*/
snapshotDir?: string;
plugins?: Array<TestPlugin>;
/**
* Whether to preserve test output in the
* [testConfig.outputDir](https://playwright.dev/docs/api/class-testconfig#test-config-output-dir). Defaults to `'always'`.
@ -20155,6 +20157,18 @@ export interface TestError {
value?: string;
}
export interface TestPlugin {
/**
* @param config
* @param configDir
*/
configure?(config: TestConfig, configDir: string): Promise<void>;
setup?(): Promise<void>;
teardown?(): Promise<void>;
}
/**
* Playwright Test supports running multiple test projects at the same time. This is useful for running tests in multiple
* configurations. For example, consider running tests against multiple browsers.