test: slim browser and msteams imports

This commit is contained in:
Peter Steinberger
2026-04-24 13:33:48 +01:00
parent 60f7a59f5e
commit 8866544ffe
10 changed files with 45 additions and 36 deletions

View File

@@ -0,0 +1,5 @@
export type ChromeMcpModule = typeof import("./chrome-mcp.js");
export async function getChromeMcpModule(): Promise<ChromeMcpModule> {
return await import("./chrome-mcp.js");
}

View File

@@ -8,11 +8,7 @@ import {
resolveCdpReachabilityTimeouts,
} from "./cdp-timeouts.js";
import { redactCdpUrl } from "./cdp.helpers.js";
import {
closeChromeMcpSession,
ensureChromeMcpAvailable,
listChromeMcpTabs,
} from "./chrome-mcp.js";
import { getChromeMcpModule } from "./chrome-mcp.runtime.js";
import {
diagnoseChromeCdp,
formatChromeCdpDiagnostic,
@@ -78,6 +74,7 @@ export function createProfileAvailability({
const isReachable = async (timeoutMs?: number) => {
if (capabilities.usesChromeMcp) {
// listChromeMcpTabs creates the session if needed — no separate ensureChromeMcpAvailable call required
const { listChromeMcpTabs } = await getChromeMcpModule();
await listChromeMcpTabs(profile.name, profile.userDataDir);
return true;
}
@@ -155,6 +152,7 @@ export function createProfileAvailability({
setProfileRunning(null);
}
if (getBrowserProfileCapabilities(previousProfile).usesChromeMcp) {
const { closeChromeMcpSession } = await getChromeMcpModule();
await closeChromeMcpSession(previousProfile.name).catch(() => false);
}
await closePlaywrightBrowserConnectionForProfile(previousProfile.cdpUrl);
@@ -191,6 +189,7 @@ export function createProfileAvailability({
let lastError: unknown;
while (Date.now() < deadlineMs) {
try {
const { listChromeMcpTabs } = await getChromeMcpModule();
await listChromeMcpTabs(profile.name, profile.userDataDir);
return;
} catch (err) {
@@ -209,6 +208,7 @@ export function createProfileAvailability({
`Browser user data directory not found for profile "${profile.name}": ${profile.userDataDir}`,
);
}
const { ensureChromeMcpAvailable } = await getChromeMcpModule();
await ensureChromeMcpAvailable(profile.name, profile.userDataDir);
await waitForChromeMcpReadyAfterAttach();
return;
@@ -308,6 +308,7 @@ export function createProfileAvailability({
const stopRunningBrowser = async (): Promise<{ stopped: boolean }> => {
await reconcileProfileRuntime();
if (capabilities.usesChromeMcp) {
const { closeChromeMcpSession } = await getChromeMcpModule();
const stopped = await closeChromeMcpSession(profile.name);
return { stopped };
}

View File

@@ -2,7 +2,7 @@ import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
import type { SsrFPolicy } from "../infra/net/ssrf.js";
import { fetchOk, normalizeCdpHttpBaseForJsonEndpoints } from "./cdp.helpers.js";
import { appendCdpPath } from "./cdp.js";
import { closeChromeMcpTab, focusChromeMcpTab } from "./chrome-mcp.js";
import { getChromeMcpModule } from "./chrome-mcp.runtime.js";
import type { ResolvedBrowserProfile } from "./config.js";
import { BrowserTabNotFoundError, BrowserTargetAmbiguousError } from "./errors.js";
import { getBrowserProfileCapabilities } from "./profile-capabilities.js";
@@ -98,6 +98,7 @@ export function createProfileSelectionOps({
const resolvedTargetId = await resolveTargetIdOrThrow(targetId);
if (capabilities.usesChromeMcp) {
const { focusChromeMcpTab } = await getChromeMcpModule();
await focusChromeMcpTab(profile.name, resolvedTargetId, profile.userDataDir);
const profileState = getProfileState();
profileState.lastTargetId = resolvedTargetId;
@@ -134,6 +135,7 @@ export function createProfileSelectionOps({
const resolvedTargetId = await resolveTargetIdOrThrow(targetId);
if (capabilities.usesChromeMcp) {
const { closeChromeMcpTab } = await getChromeMcpModule();
await closeChromeMcpTab(profile.name, resolvedTargetId, profile.userDataDir);
return;
}

View File

@@ -7,7 +7,7 @@ import {
normalizeCdpHttpBaseForJsonEndpoints,
} from "./cdp.helpers.js";
import { appendCdpPath, createTargetViaCdp, normalizeCdpWsUrl } from "./cdp.js";
import { listChromeMcpTabs, openChromeMcpTab } from "./chrome-mcp.js";
import { getChromeMcpModule } from "./chrome-mcp.runtime.js";
import type { ResolvedBrowserProfile } from "./config.js";
import {
assertBrowserNavigationAllowed,
@@ -74,6 +74,7 @@ export function createProfileTabOps({
const listTabs = async (): Promise<BrowserTab[]> => {
if (capabilities.usesChromeMcp) {
const { listChromeMcpTabs } = await getChromeMcpModule();
return await listChromeMcpTabs(profile.name, profile.userDataDir);
}
@@ -155,6 +156,7 @@ export function createProfileTabOps({
if (capabilities.usesChromeMcp) {
await assertBrowserNavigationAllowed({ url, ...ssrfPolicyOpts });
const { openChromeMcpTab } = await getChromeMcpModule();
const page = await openChromeMcpTab(profile.name, url, profile.userDataDir);
const profileState = getProfileState();
profileState.lastTargetId = page.targetId;

View File

@@ -20,7 +20,7 @@ vi.mock("./shared.js", async (importOriginal) => {
};
});
vi.mock("../../runtime-api.js", () => ({
vi.mock("openclaw/plugin-sdk/ssrf-runtime", () => ({
fetchWithSsrFGuard: vi.fn(),
}));
@@ -48,7 +48,7 @@ vi.mock("./remote-media.js", () => ({
downloadAndStoreMSTeamsRemoteMedia: vi.fn(),
}));
import { fetchWithSsrFGuard } from "../../runtime-api.js";
import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
import { downloadMSTeamsGraphMedia } from "./graph.js";
import { downloadAndStoreMSTeamsRemoteMedia } from "./remote-media.js";
import { safeFetchWithPolicy } from "./shared.js";

View File

@@ -1,9 +1,9 @@
import { fetchWithSsrFGuard, type SsrFPolicy } from "openclaw/plugin-sdk/ssrf-runtime";
import {
normalizeLowercaseStringOrEmpty,
normalizeOptionalLowercaseString,
normalizeOptionalString,
} from "openclaw/plugin-sdk/text-runtime";
import { fetchWithSsrFGuard, type SsrFPolicy } from "../../runtime-api.js";
import { getMSTeamsRuntime } from "../runtime.js";
import { ensureUserAgentHeader } from "../user-agent.js";
import { downloadMSTeamsAttachments } from "./download.js";

View File

@@ -1,15 +1,15 @@
import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime";
import {
type ChunkMode,
isSilentReplyText,
loadWebMedia,
type MarkdownTableMode,
type MSTeamsReplyStyle,
type ReplyPayload,
resolveSendableOutboundReplyParts,
SILENT_REPLY_TOKEN,
sleep,
} from "../runtime-api.js";
type ChunkMode,
} from "openclaw/plugin-sdk/reply-chunking";
import {
resolveSendableOutboundReplyParts,
type ReplyPayload,
} from "openclaw/plugin-sdk/reply-payload";
import { normalizeOptionalLowercaseString, sleep } from "openclaw/plugin-sdk/text-runtime";
import { loadWebMedia } from "openclaw/plugin-sdk/web-media";
import type { MarkdownTableMode, MSTeamsReplyStyle } from "../runtime-api.js";
import type { MSTeamsAccessTokenProvider } from "./attachments/types.js";
import type { StoredConversationReference } from "./conversation-store.js";
import { classifyMSTeamsSendError } from "./errors.js";

View File

@@ -17,10 +17,8 @@ const runtimeApiMockState = vi.hoisted(() => ({
})),
}));
vi.mock("../runtime-api.js", async () => {
const actual = await vi.importActual<typeof import("../runtime-api.js")>("../runtime-api.js");
vi.mock("openclaw/plugin-sdk/inbound-reply-dispatch", () => {
return {
...actual,
dispatchReplyFromConfigWithSettledDispatcher:
runtimeApiMockState.dispatchReplyFromConfigWithSettledDispatcher,
};

View File

@@ -12,11 +12,8 @@ export function getRuntimeApiMockState() {
return runtimeApiMockState;
}
vi.mock("../../runtime-api.js", async () => {
const actual =
await vi.importActual<typeof import("../../runtime-api.js")>("../../runtime-api.js");
vi.mock("openclaw/plugin-sdk/inbound-reply-dispatch", () => {
return {
...actual,
dispatchReplyFromConfigWithSettledDispatcher:
runtimeApiMockState.dispatchReplyFromConfigWithSettledDispatcher,
};

View File

@@ -1,20 +1,24 @@
import { formatAllowlistMatchMeta } from "openclaw/plugin-sdk/allow-from";
import { resolveInboundMentionDecision } from "openclaw/plugin-sdk/channel-inbound";
import {
logInboundDrop,
resolveInboundSessionEnvelopeContext,
} from "openclaw/plugin-sdk/channel-inbound";
import { resolveDualTextControlCommandGate } from "openclaw/plugin-sdk/command-gating";
import {
filterSupplementalContextItems,
resolveChannelContextVisibilityMode,
shouldIncludeSupplementalContext,
} from "openclaw/plugin-sdk/context-visibility-runtime";
import { evaluateSenderGroupAccessForPolicy } from "openclaw/plugin-sdk/group-access";
import { dispatchReplyFromConfigWithSettledDispatcher } from "openclaw/plugin-sdk/inbound-reply-dispatch";
import {
buildPendingHistoryContextFromMap,
clearHistoryEntriesIfEnabled,
dispatchReplyFromConfigWithSettledDispatcher,
DEFAULT_GROUP_HISTORY_LIMIT,
logInboundDrop,
evaluateSenderGroupAccessForPolicy,
filterSupplementalContextItems,
recordPendingHistoryEntryIfEnabled,
resolveChannelContextVisibilityMode,
resolveDualTextControlCommandGate,
resolveInboundSessionEnvelopeContext,
shouldIncludeSupplementalContext,
formatAllowlistMatchMeta,
type HistoryEntry,
} from "../../runtime-api.js";
} from "openclaw/plugin-sdk/reply-history";
import {
buildMSTeamsAttachmentPlaceholder,
buildMSTeamsMediaPayload,