diff --git a/packages/core/lib/v3/handlers/actHandler.ts b/packages/core/lib/v3/handlers/actHandler.ts index a965d9cc9..4df420b83 100644 --- a/packages/core/lib/v3/handlers/actHandler.ts +++ b/packages/core/lib/v3/handlers/actHandler.ts @@ -303,6 +303,12 @@ export class ActHandler { try { ensureTimeRemaining?.(); + logPlaywrightAction({ + selector: action.selector, + description: action.description || `action (${method})`, + method, + arguments: placeholderArgs, + }); await performUnderstudyMethod( page, page.mainFrame(), @@ -395,6 +401,12 @@ export class ActHandler { } ensureTimeRemaining?.(); + logPlaywrightAction({ + selector: newSelector, + description: action.description || `action (${method})`, + method, + arguments: placeholderArgs, + }); await performUnderstudyMethod( page, page.mainFrame(), @@ -442,6 +454,23 @@ export class ActHandler { } } +function logPlaywrightAction(action: Action): void { + v3Logger({ + category: "action", + message: "executing playwright action", + level: 1, + auxiliary: { + selector: { value: action.selector, type: "string" }, + description: { value: action.description, type: "string" }, + method: { value: action.method ?? "", type: "string" }, + arguments: { + value: JSON.stringify(action.arguments ?? []), + type: "object", + }, + }, + }); +} + function normalizeActInferenceElement( element: ActInferenceElement | undefined, xpathMap: Record, diff --git a/packages/core/tests/unit/timeout-handlers.test.ts b/packages/core/tests/unit/timeout-handlers.test.ts index d524dd935..1dcc8780d 100644 --- a/packages/core/tests/unit/timeout-handlers.test.ts +++ b/packages/core/tests/unit/timeout-handlers.test.ts @@ -6,7 +6,10 @@ import type { Page } from "../../lib/v3/understudy/page.js"; import type { ClientOptions } from "../../lib/v3/types/public/model.js"; import type { LLMClient } from "../../lib/v3/llm/LLMClient.js"; import { createTimeoutGuard } from "../../lib/v3/handlers/handlerUtils/timeoutGuard.js"; -import { waitForDomNetworkQuiet } from "../../lib/v3/handlers/handlerUtils/actHandlerUtils.js"; +import { + performUnderstudyMethod, + waitForDomNetworkQuiet, +} from "../../lib/v3/handlers/handlerUtils/actHandlerUtils.js"; import { captureHybridSnapshot } from "../../lib/v3/understudy/a11y/snapshot/index.js"; import { ActTimeoutError, @@ -20,6 +23,12 @@ import { observe as observeInference, } from "../../lib/inference.js"; import { V3FunctionName } from "../../lib/v3/types/public/methods.js"; +import { + bindInstanceLogger, + unbindInstanceLogger, + withInstanceLogContext, +} from "../../lib/v3/logger.js"; +import type { LogLine } from "../../lib/v3/types/public/logs.js"; vi.mock("../../lib/v3/handlers/handlerUtils/timeoutGuard", () => ({ createTimeoutGuard: vi.fn(), @@ -1237,6 +1246,50 @@ describe("No-timeout success paths", () => { expect(result.success).toBe(true); }); + + it("logs the generated Playwright action before executing it", async () => { + vi.mocked(performUnderstudyMethod).mockResolvedValue(undefined); + const logs: LogLine[] = []; + const instanceId = "act-action-visibility"; + + bindInstanceLogger(instanceId, (line) => logs.push(line)); + + try { + const handler = buildActHandler(); + const fakePage = { + mainFrame: vi.fn().mockReturnValue({}), + } as unknown as Page; + + await withInstanceLogContext(instanceId, () => + handler.takeDeterministicAction( + { + selector: "xpath=/html/body/button", + description: "click the submit button", + method: "click", + arguments: ["left"], + }, + fakePage, + ), + ); + + expect(logs).toContainEqual( + expect.objectContaining({ + category: "action", + message: "executing playwright action", + auxiliary: expect.objectContaining({ + selector: { + value: "xpath=/html/body/button", + type: "string", + }, + method: { value: "click", type: "string" }, + arguments: { value: '["left"]', type: "object" }, + }), + }), + ); + } finally { + unbindInstanceLogger(instanceId); + } + }); }); interface BuildActHandlerOptions {