Skip to content

Commit

Permalink
chore: move dev server to config-based framework extensibility (#30234)
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelfeldman committed Apr 5, 2024
1 parent e18a358 commit 5043bd5
Show file tree
Hide file tree
Showing 16 changed files with 104 additions and 50 deletions.
3 changes: 0 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 0 additions & 19 deletions packages/playwright-ct-core/cli.js

This file was deleted.

3 changes: 2 additions & 1 deletion packages/playwright-ct-core/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

const { test: baseTest, expect, devices, defineConfig: originalDefineConfig } = require('playwright/test');
const { fixtures } = require('./lib/mount');
const { clearCacheCommand, findRelatedTestFilesCommand } = require('./lib/cliOverrides');
const { clearCacheCommand, runDevServerCommand, findRelatedTestFilesCommand } = require('./lib/cliOverrides');
const { createPlugin } = require('./lib/vitePlugin');

const defineConfig = (...configs) => {
Expand All @@ -31,6 +31,7 @@ const defineConfig = (...configs) => {
],
cli: {
'clear-cache': clearCacheCommand,
'dev-server': runDevServerCommand,
'find-related-test-files': findRelatedTestFilesCommand,
},
}
Expand Down
3 changes: 0 additions & 3 deletions packages/playwright-ct-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,5 @@
"playwright-core": "1.44.0-next",
"vite": "^5.0.13",
"playwright": "1.44.0-next"
},
"bin": {
"playwright": "cli.js"
}
}
6 changes: 6 additions & 0 deletions packages/playwright-ct-core/src/cliOverrides.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import { affectedTestFiles, cacheDir } from 'playwright/lib/transform/compilatio
import { buildBundle } from './vitePlugin';
import { resolveDirs } from './viteUtils';
import type { FullConfig, Suite } from 'playwright/types/testReporter';
import { runDevServer } from './devServer';
import type { FullConfigInternal } from 'playwright/lib/common/config';

export async function clearCacheCommand(config: FullConfig, configDir: string) {
const dirs = await resolveDirs(configDir, config);
Expand All @@ -32,3 +34,7 @@ export async function findRelatedTestFilesCommand(files: string[], config: Full
await buildBundle(config, configDir, suite);
return { testFiles: affectedTestFiles(files) };
}

export async function runDevServerCommand(config: FullConfigInternal) {
return await runDevServer(config);
}
13 changes: 5 additions & 8 deletions packages/playwright-ct-core/src/devServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,14 @@
import fs from 'fs';
import path from 'path';
import { Watcher } from 'playwright/lib/fsWatcher';
import { loadConfigFromFileRestartIfNeeded } from 'playwright/lib/common/configLoader';
import { Runner } from 'playwright/lib/runner/runner';
import type { PluginContext } from 'rollup';
import { source as injectedSource } from './generated/indexSource';
import { createConfig, populateComponentsFromTests, resolveDirs, transformIndexFile, frameworkConfig } from './viteUtils';
import type { ComponentRegistry } from './viteUtils';
import type { FullConfigInternal } from 'playwright/lib/common/config';

export async function runDevServer(configFile: string) {
const config = await loadConfigFromFileRestartIfNeeded(configFile);
if (!config)
return;

export async function runDevServer(config: FullConfigInternal): Promise<() => Promise<void>> {
const { registerSourceFile, frameworkPluginFactory } = frameworkConfig(config.config);
const runner = new Runner(config);
await runner.loadAllTests();
Expand All @@ -39,7 +35,7 @@ export async function runDevServer(configFile: string) {
if (!dirs) {
// eslint-disable-next-line no-console
console.log(`Template file playwright/index.html is missing.`);
return;
return async () => {};
}
const registerSource = injectedSource + '\n' + await fs.promises.readFile(registerSourceFile, 'utf-8');
const viteConfig = await createConfig(dirs, config.config, frameworkPluginFactory, false);
Expand All @@ -56,7 +52,7 @@ export async function runDevServer(configFile: string) {
await devServer.listen();
const protocol = viteConfig.server.https ? 'https:' : 'http:';
// eslint-disable-next-line no-console
console.log(`Test Server listening on ${protocol}//${viteConfig.server.host || 'localhost'}:${viteConfig.server.port}`);
console.log(`Dev Server listening on ${protocol}//${viteConfig.server.host || 'localhost'}:${viteConfig.server.port}`);

const projectDirs = new Set<string>();
const projectOutputs = new Set<string>();
Expand Down Expand Up @@ -85,4 +81,5 @@ export async function runDevServer(configFile: string) {
devServer.moduleGraph.onFileChange(rootModule.file!);
});
globalWatcher.update([...projectDirs], [...projectOutputs], false);
return () => Promise.all([devServer.close(), globalWatcher.close()]).then(() => {});
}
15 changes: 0 additions & 15 deletions packages/playwright-ct-core/src/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,4 @@
* limitations under the License.
*/

import type { Command } from 'playwright-core/lib/utilsBundle';

import { program } from 'playwright/lib/program';
import { runDevServer } from './devServer';
export { program } from 'playwright/lib/program';

function addDevServerCommand(program: Command) {
const command = program.command('dev-server', { hidden: true });
command.description('start dev server');
command.option('-c, --config <file>', `Configuration file, or a test directory with optional "playwright.config.{m,c}?{js,ts}"`);
command.action(options => {
runDevServer(options.config);
});
}

addDevServerCommand(program);
2 changes: 1 addition & 1 deletion packages/playwright-ct-core/src/vitePlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export async function buildBundle(config: FullConfig, configDir: string, suite:
const url = new URL(`${protocol}//${endpoint.host}:${endpoint.port}`);
if (await isURLAvailable(url, true)) {
// eslint-disable-next-line no-console
console.log(`Test Server is already running at ${url.toString()}, using it.\n`);
console.log(`Dev Server is already running at ${url.toString()}, using it.\n`);
process.env.PLAYWRIGHT_TEST_BASE_URL = url.toString();
return null;
}
Expand Down
4 changes: 4 additions & 0 deletions packages/playwright/src/fsWatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ export class Watcher {
});
}

async close() {
await this._fsWatcher?.close();
}

private _reportEventsIfAny() {
if (this._collector.length)
this._onChange(this._collector.slice());
Expand Down
2 changes: 2 additions & 0 deletions packages/playwright/src/isomorphic/teleReceiver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import type { Metadata } from '../../types/test';
import type * as reporterTypes from '../../types/testReporter';
import type { ReporterV2 } from '../reporters/reporterV2';

// -- Reuse boundary -- Everything below this line is reused in the vscode extension.

export type StringIntern = (s: string) => string;
export type JsonLocation = reporterTypes.Location;
export type JsonError = string;
Expand Down
10 changes: 10 additions & 0 deletions packages/playwright/src/isomorphic/testServerConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import type { TestServerInterface, TestServerInterfaceEvents } from '@testIsomorphic/testServerInterface';
import * as events from './events';

// -- Reuse boundary -- Everything below this line is reused in the vscode extension.

export class TestServerConnection implements TestServerInterface, TestServerInterfaceEvents {
readonly onClose: events.Event<void>;
readonly onReport: events.Event<any>;
Expand Down Expand Up @@ -155,6 +157,14 @@ export class TestServerConnection implements TestServerInterface, TestServerInte
return await this._sendMessage('runGlobalTeardown', params);
}

async startDevServer(params: Parameters<TestServerInterface['startDevServer']>[0]): ReturnType<TestServerInterface['startDevServer']> {
return await this._sendMessage('startDevServer', params);
}

async stopDevServer(params: Parameters<TestServerInterface['stopDevServer']>[0]): ReturnType<TestServerInterface['stopDevServer']> {
return await this._sendMessage('stopDevServer', params);
}

async listFiles(params: Parameters<TestServerInterface['listFiles']>[0]): ReturnType<TestServerInterface['listFiles']> {
return await this._sendMessage('listFiles', params);
}
Expand Down
12 changes: 12 additions & 0 deletions packages/playwright/src/isomorphic/testServerInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import type * as reporterTypes from '../../types/testReporter';
import type { Event } from './events';
import type { JsonEvent } from './teleReceiver';

// -- Reuse boundary -- Everything below this line is reused in the vscode extension.

export type ReportEntry = JsonEvent;

export interface TestServerInterface {
Expand Down Expand Up @@ -52,6 +54,16 @@ export interface TestServerInterface {
status: reporterTypes.FullResult['status']
}>;

startDevServer(params: {}): Promise<{
report: ReportEntry[];
status: reporterTypes.FullResult['status']
}>;

stopDevServer(params: {}): Promise<{
report: ReportEntry[];
status: reporterTypes.FullResult['status']
}>;

listFiles(params: {
projects?: string[];
}): Promise<{
Expand Down
2 changes: 2 additions & 0 deletions packages/playwright/src/isomorphic/testTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
export type TestItemStatus = 'none' | 'running' | 'scheduled' | 'passed' | 'failed' | 'skipped';
import type * as reporterTypes from '../../types/testReporter';

// -- Reuse boundary -- Everything below this line is reused in the vscode extension.

export type TreeItemBase = {
kind: 'root' | 'group' | 'case' | 'test',
id: string;
Expand Down
20 changes: 20 additions & 0 deletions packages/playwright/src/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,25 @@ function addFindRelatedTestFilesCommand(program: Command) {
});
}

function addDevServerCommand(program: Command) {
const command = program.command('dev-server', { hidden: true });
command.description('start dev server');
command.option('-c, --config <file>', `Configuration file, or a test directory with optional "playwright.config.{m,c}?{js,ts}"`);
command.action(async options => {
const configInternal = await loadConfigFromFileRestartIfNeeded(options.config);
if (!configInternal)
return;
const { config } = configInternal;
const implementation = (config as any)['@playwright/test']?.['cli']?.['dev-server'];
if (implementation) {
await implementation(configInternal);
} else {
console.log(`DevServer is not available in the package you are using. Did you mean to use component testing?`);
gracefullyProcessExitDoNotHang(1);
}
});
}

function addTestServerCommand(program: Command) {
const command = program.command('test-server', { hidden: true });
command.description('start test server');
Expand Down Expand Up @@ -362,4 +381,5 @@ addListFilesCommand(program);
addMergeReportsCommand(program);
addClearCacheCommand(program);
addFindRelatedTestFilesCommand(program);
addDevServerCommand(program);
addTestServerCommand(program);
2 changes: 2 additions & 0 deletions packages/playwright/src/reporters/teleEmitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import type * as teleReceiver from '../isomorphic/teleReceiver';
import { serializeRegexPatterns } from '../isomorphic/teleReceiver';
import type { ReporterV2 } from './reporterV2';

// -- Reuse boundary -- Everything below this line is reused in the vscode extension.

export type TeleReporterEmitterOptions = {
omitOutput?: boolean;
omitBuffers?: boolean;
Expand Down
38 changes: 38 additions & 0 deletions packages/playwright/src/runner/testServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class TestServerDispatcher implements TestServerInterface {
private _serializer = require.resolve('./uiModeReporter');
private _watchTestDirs = false;
private _closeOnDisconnect = false;
private _devServerHandle: (() => Promise<void>) | undefined;

constructor(configFile: string | undefined) {
this._configFile = configFile;
Expand Down Expand Up @@ -172,6 +173,43 @@ class TestServerDispatcher implements TestServerInterface {
return { status, report: globalSetup?.report || [] };
}

async startDevServer(params: Parameters<TestServerInterface['startDevServer']>[0]): ReturnType<TestServerInterface['startDevServer']> {
if (this._devServerHandle)
return { status: 'failed', report: [] };
const { reporter, report } = await this._collectingReporter();
const { config, error } = await this._loadConfig(this._configFile);
if (!config) {
reporter.onError(error!);
return { status: 'failed', report };
}
const devServerCommand = (config.config as any)['@playwright/test']?.['cli']?.['dev-server'];
if (!devServerCommand) {
reporter.onError({ message: 'No dev-server command found in the configuration' });
return { status: 'failed', report };
}
try {
this._devServerHandle = await devServerCommand(config);
return { status: 'passed', report };
} catch (e) {
reporter.onError(serializeError(e));
return { status: 'failed', report };
}
}

async stopDevServer(params: Parameters<TestServerInterface['stopDevServer']>[0]): ReturnType<TestServerInterface['stopDevServer']> {
if (!this._devServerHandle)
return { status: 'failed', report: [] };
try {
await this._devServerHandle();
this._devServerHandle = undefined;
return { status: 'passed', report: [] };
} catch (e) {
const { reporter, report } = await this._collectingReporter();
reporter.onError(serializeError(e));
return { status: 'failed', report };
}
}

async listFiles(params: Parameters<TestServerInterface['listFiles']>[0]): ReturnType<TestServerInterface['listFiles']> {
const { reporter, report } = await this._collectingReporter();
const { config, error } = await this._loadConfig(this._configFile);
Expand Down

0 comments on commit 5043bd5

Please sign in to comment.