diff --git a/packages/core/lib/v3/understudy/page.ts b/packages/core/lib/v3/understudy/page.ts index a34d363a9..e8f636629 100644 --- a/packages/core/lib/v3/understudy/page.ts +++ b/packages/core/lib/v3/understudy/page.ts @@ -1209,6 +1209,7 @@ export class Page { * Supports iframe hop notation with '>>' (e.g., 'iframe#checkout >> .submit-btn'). * * @param selector CSS selector to wait for (supports '>>' for iframe hops) + * @param options * @param options.state Element state to wait for: 'attached' | 'detached' | 'visible' | 'hidden' (default: 'visible') * @param options.timeout Maximum time to wait in milliseconds (default: 30000) * @param options.pierceShadow Whether to search inside shadow DOM (default: true) diff --git a/packages/docs/v3/references/page.mdx b/packages/docs/v3/references/page.mdx index 856360728..0ef874657 100644 --- a/packages/docs/v3/references/page.mdx +++ b/packages/docs/v3/references/page.mdx @@ -564,6 +564,58 @@ await page.waitForLoadState(state: LoadState, timeoutMs?: number): Promise **Default:** `15000` +### waitForSelector() + +Wait for an element matching the selector to reach a specific state in the DOM. Uses a MutationObserver for efficiency, pierces shadow DOM by default, and supports iframe hops when needed. + +```typescript +await page.waitForSelector( + selector: string, + options?: { + state?: "attached" | "detached" | "visible" | "hidden"; + timeout?: number; + pierceShadow?: boolean; + } +): Promise +``` + + + CSS selector or XPath expression to wait for. Supports iframe hops (e.g., `/html/div/iframe/html/div/button`). + + + + Optional wait configuration. + + + + Element state to wait for. + + **Options:** + - `"attached"` - Element is present in DOM (even if hidden) + - `"detached"` - Element is removed from DOM + - `"visible"` - Element is visible + - `"hidden"` - Element is hidden + + **Default:** `"visible"` + + + + Maximum time to wait in milliseconds before timing out. + + **Default:** `30000` + + + + Whether to search inside open and closed shadow DOM boundaries. + + **Default:** `true` + + + + +**Returns:** `true` when the condition is met. + +**Throws:** Error if timeout is reached before the condition is met. ## Events @@ -743,6 +795,41 @@ await page.goto("https://spa-app.com", { await page.waitForLoadState("domcontentloaded"); ``` + + + +```typescript +// Wait for element to be visible (default) +await page.waitForSelector("#submit-btn"); + +// Wait for element to appear with custom timeout +await page.waitForSelector(".loading-spinner", { + state: "visible", + timeout: 10000 +}); + +// Wait for element to be removed from DOM +await page.waitForSelector(".loading-spinner", { + state: "detached" +}); + +// Wait for element to become hidden +await page.waitForSelector(".modal", { + state: "hidden" +}); + +// Wait for element inside an iframe +await page.waitForSelector("iframe#checkout >> .pay-button"); + +// Wait for element in shadow DOM (enabled by default) +await page.waitForSelector("#shadow-button", { + pierceShadow: true +}); + +// Wait for element with XPath +await page.waitForSelector("/html/div/button"); +``` + diff --git a/packages/server/src/types/model.ts b/packages/server/src/types/model.ts index 74cc988e7..e07130afb 100644 --- a/packages/server/src/types/model.ts +++ b/packages/server/src/types/model.ts @@ -12,7 +12,7 @@ export const AISDK_PROVIDERS = [ "perplexity", "ollama", "vertex", - "bedrock" + "bedrock", ] as const; export type AISDKProvider = (typeof AISDK_PROVIDERS)[number];