Files
callstack__agent-device/test/integration/provider-scenarios/cloud-webdriver-test-server.ts
Michał Pierzchała a707348b9b feat: add hosted WebDriver provider support (#948)
* feat: add cloud webdriver artifacts

* fix: clean up local session after provider release failure

* fix: tag cloud webdriver provider requests

* feat: connect hosted webdriver providers

* docs: document hosted provider credentials

* refactor: tighten cloud webdriver provider internals

* refactor: consolidate cloud webdriver provider definitions

* refactor: collapse hosted webdriver runtime wrapper

* refactor: reduce cloud webdriver smell surface

* docs: clarify hosted provider interfaces

* fix: avoid regex slash trimming in webdriver urls

* docs: rename hosted providers to device clouds

* fix: align provider profile imports with remote modules

* fix: skip local android recovery for provider devices

* test: classify cloud provider integration flags

* fix: close active cloud connection session

* test: cover provider disconnect cli flow

* fix: make cloud webdriver sessions launchable

* fix: align cloud webdriver input gestures

* fix: avoid keyboard input during cloud scroll

* fix: constrain cloud webdriver scroll gestures

* refactor: isolate cloud webdriver scroll frame

* refactor: deduplicate cloud webdriver helpers

* refactor: tighten cloud webdriver action types

* fix: harden cloud webdriver release

* fix: polish provider disconnect diagnostics

* refactor: group connection profile helpers

* fix: repair rebased internal paths

* fix: satisfy cloud webdriver CI guards
2026-07-01 13:01:47 +02:00

96 lines
3.0 KiB
TypeScript

import assert from 'node:assert/strict';
import http, {
type IncomingHttpHeaders,
type IncomingMessage,
type ServerResponse,
} from 'node:http';
export type CloudWebDriverHttpCall = {
method: string;
path: string;
headers: IncomingHttpHeaders;
body?: unknown;
};
export abstract class CloudWebDriverTestServer {
readonly calls: CloudWebDriverHttpCall[] = [];
url = '';
constructor() {
const server = http.createServer();
server.on('request', async (req, res) => await this.handle(req, res));
cloudWebDriverHttpServers.set(this, server);
}
protected abstract respond(call: CloudWebDriverHttpCall, res: ServerResponse): void;
private async handle(req: IncomingMessage, res: ServerResponse): Promise<void> {
const body = await readRequestBody(req);
const call: CloudWebDriverHttpCall = {
method: req.method ?? 'GET',
path: req.url ?? '/',
headers: req.headers,
...(body === undefined ? {} : { body }),
};
this.calls.push(call);
this.respond(call, res);
}
}
const cloudWebDriverHttpServers = new WeakMap<CloudWebDriverTestServer, http.Server>();
export type StartedCloudWebDriverTestServer<T extends CloudWebDriverTestServer> = T & {
close(): Promise<void>;
};
export async function startCloudWebDriverTestServer<T extends CloudWebDriverTestServer>(
testServer: T,
): Promise<StartedCloudWebDriverTestServer<T>> {
const server = getCloudWebDriverHttpServer(testServer);
await new Promise<void>((resolve, reject) => {
server.once('error', reject);
server.listen(0, '127.0.0.1', resolve);
});
const address = server.address();
assert.ok(address && typeof address === 'object');
testServer.url = `http://127.0.0.1:${address.port}`;
return Object.assign(testServer, {
close: async () => await closeCloudWebDriverTestServer(testServer),
});
}
export function writeCloudWebDriverTestJson(
res: ServerResponse,
body: unknown,
status = 200,
): void {
res.writeHead(status, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(body));
}
async function readRequestBody(req: IncomingMessage): Promise<unknown> {
const chunks: Buffer[] = [];
for await (const chunk of req) {
chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk);
}
const buffer = Buffer.concat(chunks);
if (req.headers['content-type']?.startsWith('multipart/form-data') === true) {
return { multipartBytes: buffer.length };
}
const text = buffer.toString('utf8');
return text ? (JSON.parse(text) as unknown) : undefined;
}
function getCloudWebDriverHttpServer(testServer: CloudWebDriverTestServer): http.Server {
const server = cloudWebDriverHttpServers.get(testServer);
assert.ok(server);
return server;
}
async function closeCloudWebDriverTestServer(testServer: CloudWebDriverTestServer): Promise<void> {
const server = getCloudWebDriverHttpServer(testServer);
await new Promise<void>((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}