Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions apps/site/docs/en/automate-with-scripts-in-yaml.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,14 @@ web:
# Path to a JSON format browser cookie file, optional.
cookie: <path-to-cookie-file>

# The strategy for waiting for network idle, optional.
# The strategy for waiting for network idle in Puppeteer mode, optional.
# `timeout` applies to the initial opening of `web.url` defined in YAML and to later actions such as `aiTap` and `aiInput`.
# `continueOnNetworkIdleError` only applies to the initial opening of `web.url` defined in YAML.
waitForNetworkIdle:
# The timeout in milliseconds, optional, defaults to 2000ms.
# The timeout in milliseconds for each network idle wait, optional, defaults to 2000ms.
timeout: <ms>
# Whether to continue on timeout, optional, defaults to true.
# Whether to continue if the initial opening of `web.url` defined in YAML times out while waiting for network idle, optional, defaults to true.
# Later action-time waits always continue even if they time out.
continueOnNetworkIdleError: <boolean>

# The path to the JSON file for outputting aiQuery/aiAssert results, optional.
Expand Down
9 changes: 6 additions & 3 deletions apps/site/docs/zh/automate-with-scripts-in-yaml.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,14 @@ web:
# JSON 格式的浏览器 Cookie 文件路径,可选
cookie: <path-to-cookie-file>

# 等待网络空闲的策略,可选
# Puppeteer 模式下等待网络空闲的策略,可选
# `timeout` 会作用于初始打开 YAML 中的 `web.url`,以及后续 `aiTap`、`aiInput` 等操作后的等待
# `continueOnNetworkIdleError` 只作用于初始打开 YAML 中的 `web.url`
waitForNetworkIdle:
# 等待超时时间,可选,默认 2000ms
# 每次网络空闲等待的超时时间,可选,默认 2000ms
timeout: <ms>
# 是否在等待超时后继续,可选,默认 true
# 初始打开 YAML 中的 `web.url` 时,如果网络空闲等待超时,是否继续执行,可选,默认 true
# 后续脚本执行中的等待即使超时也总是继续执行
continueOnNetworkIdleError: <boolean>

# 输出 aiQuery/aiAssert 结果的 JSON 文件路径,可选
Expand Down
4 changes: 4 additions & 0 deletions packages/web-integration/src/puppeteer/agent-launcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,10 @@ export async function puppeteerAgentForTarget(
const agent = new PuppeteerAgent(page, {
...preferenceToUse,
aiActContext,
waitForNetworkIdleTimeout:
typeof target.waitForNetworkIdle?.timeout === 'number'
? target.waitForNetworkIdle.timeout
: undefined,
forceSameTabNavigation:
typeof target.forceSameTabNavigation !== 'undefined'
? target.forceSameTabNavigation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,28 @@ describe('Page - beforeInvokeAction and afterInvokeAction', () => {
expect(mockPage.waitForNetworkIdle).not.toHaveBeenCalled();
});

it('should use the configured network idle timeout', async () => {
const mockPage = {
url: () => 'http://example.com',
mouse: { move: vi.fn() },
keyboard: { down: vi.fn(), up: vi.fn(), press: vi.fn(), type: vi.fn() },
waitForSelector: vi.fn().mockResolvedValue(true),
waitForNetworkIdle: vi.fn().mockResolvedValue(true),
evaluate: vi.fn(),
} as any;

const page = new Page(mockPage, 'puppeteer', {
waitForNetworkIdleTimeout: 4321,
});
await page.afterInvokeAction('testAction', {});

expect(mockPage.waitForNetworkIdle).toHaveBeenCalledWith({
idleTime: 200,
concurrency: 2,
timeout: 4321,
});
});

it('should handle navigation timeout gracefully', async () => {
const consoleWarnSpy = vi
.spyOn(console, 'warn')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
defaultViewportHeight,
defaultViewportWidth,
launchPuppeteerPage,
puppeteerAgentForTarget,
} from '@/puppeteer/agent-launcher';
import { beforeEach, describe, expect, it, vi } from 'vitest';

Expand All @@ -21,6 +22,8 @@ const createPageMock = () => ({
setViewport: vi.fn().mockResolvedValue(undefined),
goto: vi.fn().mockResolvedValue(undefined),
waitForNetworkIdle: vi.fn().mockResolvedValue(undefined),
on: vi.fn(),
isClosed: vi.fn().mockReturnValue(false),
});

vi.mock('puppeteer', () => ({
Expand Down Expand Up @@ -67,4 +70,17 @@ describe('launchPuppeteerPage', () => {
expect.objectContaining({ defaultViewport: null }),
);
});

it('passes yaml waitForNetworkIdle settings to the agent for later actions', async () => {
const { agent } = await puppeteerAgentForTarget({
url: 'https://example.com',
forceSameTabNavigation: false,
waitForNetworkIdle: {
timeout: 4321,
continueOnNetworkIdleError: false,
},
});

expect((agent.page as any).waitForNetworkIdleTimeout).toBe(4321);
});
});
Loading