Files
paseo/packages/app/e2e/support/helpers/daemon-client-loader.ts
T
Mohamed BoudraandGitHub 5a30affd7f Skip unrelated required checks without losing their names (#2542)
* fix(ci): skip unrelated required checks cleanly

Matrix jobs had to start no-op runners to preserve interpolated required-check names. Static named jobs let GitHub report genuine skipped conclusions while keeping those names stable.

* fix(ci): gate changes to install patching script

* fix(ci): route cross-package test contracts narrowly

* fix(ci): keep routed contracts merge-blocking

* fix(server): exclude nested test utilities from builds

* fix(ci): cover app-owned native and browser domains

* refactor(ci): align tests with runtime domains

Own browser specs, desktop specs, and Electron-only app code by stable directories so PR routing does not depend on filename conventions. Keep desktop integration coverage inside the required desktop check.

* fix(ci): keep routing and desktop suites isolated

The routing regression must run before dependency installation, and desktop Vitest must not collect Playwright-owned specs.

* fix(ci): isolate desktop e2e runtime

* perf(test): isolate Playwright workers

* perf(test): parallelize Playwright within specs

* fix(test): keep Playwright file scheduling

* fix(test): share dynamic Metro fixture

* fix(test): preserve own-host restart fixtures

* fix(ci): preserve routed contracts after rebase

* Stabilize Playwright wheel-scroll assertions
2026-08-02 00:56:05 +08:00

67 lines
2.3 KiB
TypeScript

import { randomUUID } from "node:crypto";
import { readFileSync } from "node:fs";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { getE2EDaemonPort } from "./daemon-port";
import { createNodeWebSocketFactory, type NodeWebSocketFactory } from "./node-ws-factory";
export async function loadDaemonClientConstructor<ClientConfig, ClientInstance>(): Promise<
new (config: ClientConfig) => ClientInstance
> {
const repoRoot = path.resolve(__dirname, "../../../../../");
const moduleUrl = pathToFileURL(
path.join(repoRoot, "packages/client/dist/daemon-client.js"),
).href;
const mod = (await import(moduleUrl)) as {
DaemonClient: new (config: ClientConfig) => ClientInstance;
};
return mod.DaemonClient;
}
interface E2EDaemonClientConfig {
url: string;
clientId: string;
clientType: "cli";
appVersion?: string;
webSocketFactory?: NodeWebSocketFactory;
}
function resolveDaemonWsUrl(port?: number): string {
return `ws://127.0.0.1:${port ?? getE2EDaemonPort()}/ws`;
}
export interface ConnectDaemonClientOptions {
clientIdPrefix: string;
appVersion?: string;
port?: number;
}
/**
* Connects an in-test daemon client over the isolated E2E daemon's WebSocket.
* The port-6767 guard keeps tests off the developer daemon. Each helper passes
* its own typed client interface as the generic.
*/
export async function connectDaemonClient<ClientInstance extends { connect(): Promise<void> }>(
options: ConnectDaemonClientOptions,
): Promise<ClientInstance> {
const DaemonClient = await loadDaemonClientConstructor<E2EDaemonClientConfig, ClientInstance>();
const client = new DaemonClient({
url: resolveDaemonWsUrl(options.port),
clientId: `${options.clientIdPrefix}-${randomUUID()}`,
clientType: "cli",
appVersion: options.appVersion ?? loadAppVersion(),
webSocketFactory: createNodeWebSocketFactory(),
});
await client.connect();
return client;
}
function loadAppVersion(): string {
const packageJsonPath = path.resolve(__dirname, "../../../package.json");
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8")) as { version?: unknown };
if (typeof packageJson.version !== "string" || packageJson.version.length === 0) {
throw new Error(`Missing app version in ${packageJsonPath}`);
}
return packageJson.version;
}