






















@@ -1,10 +1,8 @@
11import { EventEmitter } from "node:events";
22import { PassThrough, Writable } from "node:stream";
33import { Command } from "commander";
4-import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry";
54import type { RealtimeVoiceProviderPlugin } from "openclaw/plugin-sdk/realtime-voice";
65import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
7-import { createTestPluginApi } from "../../test/helpers/plugins/plugin-api.ts";
86import plugin from "./index.js";
97import { registerGoogleMeetCli } from "./src/cli.js";
108import { resolveGoogleMeetConfig, resolveGoogleMeetConfigWithEnv } from "./src/config.js";
@@ -23,6 +21,11 @@ import { startNodeRealtimeAudioBridge } from "./src/realtime-node.js";
2321import { startCommandRealtimeAudioBridge } from "./src/realtime.js";
2422import { normalizeMeetUrl } from "./src/runtime.js";
2523import type { GoogleMeetRuntime } from "./src/runtime.js";
24+import {
25+captureStdout,
26+noopLogger,
27+setupGoogleMeetPlugin,
28+} from "./src/test-support/plugin-harness.js";
2629import { buildMeetDtmfSequence, normalizeDialInNumber } from "./src/transports/twilio.js";
27302831const voiceCallMocks = vi.hoisted(() => ({
@@ -54,23 +57,11 @@ vi.mock("./src/voice-call-gateway.js", () => ({
5457endMeetVoiceCallGatewayCall: voiceCallMocks.endMeetVoiceCallGatewayCall,
5558}));
565957-const noopLogger = {
58-info: vi.fn(),
59-warn: vi.fn(),
60-error: vi.fn(),
61-debug: vi.fn(),
62-};
63-64-function captureStdout() {
65-let output = "";
66-const writeSpy = vi.spyOn(process.stdout, "write").mockImplementation(((chunk: unknown) => {
67-output += String(chunk);
68-return true;
69-}) as typeof process.stdout.write);
70-return {
71-output: () => output,
72-restore: () => writeSpy.mockRestore(),
73-};
60+function setup(
61+config?: Parameters<typeof setupGoogleMeetPlugin>[1],
62+options?: Parameters<typeof setupGoogleMeetPlugin>[2],
63+) {
64+return setupGoogleMeetPlugin(plugin, config, options);
7465}
75667667type TestBridgeProcess = {
@@ -82,134 +73,6 @@ type TestBridgeProcess = {
8273on: EventEmitter["on"];
8374};
847585-type NodeListResult = {
86-nodes: Array<{
87-nodeId: string;
88-displayName?: string;
89-connected?: boolean;
90-commands?: string[];
91-caps?: string[];
92-remoteIp?: string;
93-}>;
94-};
95-96-function setup(
97-config: Record<string, unknown> = {},
98-options: {
99-fullConfig?: Record<string, unknown>;
100-nodesListResult?: NodeListResult;
101-nodesInvokeResult?: unknown;
102-browserActResult?: Record<string, unknown>;
103-nodesInvokeHandler?: (params: {
104-nodeId: string;
105-command: string;
106-params?: unknown;
107-timeoutMs?: number;
108-}) => Promise<unknown>;
109-} = {},
110-) {
111-const methods = new Map<string, unknown>();
112-const tools: unknown[] = [];
113-const cliRegistrations: unknown[] = [];
114-const nodeHostCommands: unknown[] = [];
115-const nodesList = vi.fn(
116-async () =>
117-options.nodesListResult ?? {
118-nodes: [
119-{
120-nodeId: "node-1",
121-displayName: "parallels-macos",
122-connected: true,
123-caps: ["browser"],
124-commands: ["browser.proxy", "googlemeet.chrome"],
125-},
126-],
127-},
128-);
129-const nodesInvoke = vi.fn(async (params) => {
130-if (options.nodesInvokeHandler) {
131-return options.nodesInvokeHandler(params);
132-}
133-if (params.command === "browser.proxy") {
134-const proxy = params.params as { path?: string; body?: { url?: string; targetId?: string } };
135-if (proxy.path === "/tabs") {
136-return { payload: { result: { running: true, tabs: [] } } };
137-}
138-if (proxy.path === "/tabs/open") {
139-return {
140-payload: {
141-result: {
142-targetId: "tab-1",
143-title: "Meet",
144-url: proxy.body?.url ?? "https://meet.google.com/abc-defg-hij",
145-},
146-},
147-};
148-}
149-if (proxy.path === "/act") {
150-return {
151-payload: {
152-result: {
153-ok: true,
154-targetId: proxy.body?.targetId ?? "tab-1",
155-result: JSON.stringify(
156-options.browserActResult ?? {
157-inCall: true,
158-micMuted: false,
159-title: "Meet call",
160-url: "https://meet.google.com/abc-defg-hij",
161-},
162-),
163-},
164-},
165-};
166-}
167-return { payload: { result: { ok: true } } };
168-}
169-return options.nodesInvokeResult ?? { launched: true };
170-});
171-const runCommandWithTimeout = vi.fn(async (argv: string[]) => {
172-if (argv[0] === "/usr/sbin/system_profiler") {
173-return { code: 0, stdout: "BlackHole 2ch", stderr: "" };
174-}
175-return { code: 0, stdout: "", stderr: "" };
176-});
177-const api = createTestPluginApi({
178-id: "google-meet",
179-name: "Google Meet",
180-description: "test",
181-version: "0",
182-source: "test",
183-config: options.fullConfig ?? {},
184-pluginConfig: config,
185-runtime: {
186-system: {
187- runCommandWithTimeout,
188-formatNativeDependencyHint: vi.fn(() => "Install with brew install blackhole-2ch."),
189-},
190-nodes: {
191-list: nodesList,
192-invoke: nodesInvoke,
193-},
194-} as unknown as OpenClawPluginApi["runtime"],
195-logger: noopLogger,
196-registerGatewayMethod: (method: string, handler: unknown) => methods.set(method, handler),
197-registerTool: (tool: unknown) => tools.push(tool),
198-registerCli: (_registrar: unknown, opts: unknown) => cliRegistrations.push(opts),
199-registerNodeHostCommand: (command: unknown) => nodeHostCommands.push(command),
200-});
201-plugin.register(api);
202-return {
203- cliRegistrations,
204- methods,
205- tools,
206- runCommandWithTimeout,
207- nodesList,
208- nodesInvoke,
209- nodeHostCommands,
210-};
211-}
212-21376describe("google-meet plugin", () => {
21477beforeEach(() => {
21578vi.clearAllMocks();
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。