diff --git a/docs/src/api/class-accessibility.md b/docs/src/api/class-accessibility.md index 491d7a9c38cf6..19d3d1258dd7b 100644 --- a/docs/src/api/class-accessibility.md +++ b/docs/src/api/class-accessibility.md @@ -1,4 +1,5 @@ # class: Accessibility +* langs: csharp, js, python The Accessibility class provides methods for inspecting Chromium's accessibility tree. The accessibility tree is used by assistive technology such as [screen readers](https://en.wikipedia.org/wiki/Screen_reader) or @@ -58,6 +59,11 @@ const snapshot = await page.accessibility.snapshot(); console.log(snapshot); ``` +```java +String snapshot = page.accessibility().snapshot(); +System.out.println(snapshot); +``` + ```python async snapshot = await page.accessibility.snapshot() print(snapshot) @@ -86,6 +92,11 @@ function findFocusedNode(node) { } ``` +```java +// FIXME +String snapshot = page.accessibility().snapshot(); +``` + ```python async def find_focused_node(node): if (node.get("focused")) @@ -128,4 +139,4 @@ Prune uninteresting nodes from the tree. Defaults to `true`. ### option: Accessibility.snapshot.root - `root` <[ElementHandle]> -The root DOM element for the snapshot. Defaults to the whole page. +The root DOM element for the snapshot. Defaults to the whole page. \ No newline at end of file diff --git a/docs/src/api/class-browser.md b/docs/src/api/class-browser.md index 1a3128c62e726..b58a831a9c338 100644 --- a/docs/src/api/class-browser.md +++ b/docs/src/api/class-browser.md @@ -14,6 +14,22 @@ const { firefox } = require('playwright'); // Or 'chromium' or 'webkit'. })(); ``` +```java +import com.microsoft.playwright.*; + +public class Example { + public static void main(String[] args) { + try (Playwright playwright = Playwright.create()) { + BrowserType firefox = playwright.firefox() + Browser browser = firefox.launch(); + Page page = browser.newPage(); + page.navigate('https://example.com'); + browser.close(); + } + } +} +``` + ```python async import asyncio from playwright.async_api import async_playwright @@ -75,6 +91,13 @@ const context = await browser.newContext(); console.log(browser.contexts().length); // prints `1` ``` +```java +Browser browser = pw.webkit().launch(); +System.out.println(browser.contexts().size()); // prints "0" +BrowserContext context = browser.newContext(); +System.out.println(browser.contexts().size()); // prints "1" +``` + ```python async browser = await pw.webkit.launch() print(len(browser.contexts())) # prints `0` @@ -110,6 +133,15 @@ Creates a new browser context. It won't share cookies/cache with other browser c })(); ``` +```java +Browser browser = playwright.firefox().launch(); // Or 'chromium' or 'webkit'. +// Create a new incognito browser context. +BrowserContext context = browser.newContext(); +// Create a new page in a pristine context. +Page page = context.newPage(); +page.navigate('https://example.com'); +``` + ```python async browser = await playwright.firefox.launch() # or "chromium" or "webkit". # create a new incognito browser context. diff --git a/docs/src/api/class-browsercontext.md b/docs/src/api/class-browsercontext.md index 6b68f0429fab3..5a3bd6ef7662d 100644 --- a/docs/src/api/class-browsercontext.md +++ b/docs/src/api/class-browsercontext.md @@ -19,6 +19,16 @@ await page.goto('https://example.com'); await context.close(); ``` +```java +// Create a new incognito browser context +BrowserContext context = browser.newContext(); +// Create a new page inside context. +Page page = context.newPage(); +page.navigate("https://example.com"); +// Dispose context once it"s no longer needed. +context.close(); +``` + ```python async # create a new incognito browser context context = await browser.new_context() @@ -58,11 +68,18 @@ popup with `window.open('http://example.com')`, this event will fire when the ne done and its response has started loading in the popup. ```js -const [page] = await Promise.all([ +const [newPage] = await Promise.all([ context.waitForEvent('page'), page.click('a[target=_blank]'), ]); -console.log(await page.evaluate('location.href')); +console.log(await newPage.evaluate('location.href')); +``` + +```java +Page newPage = context.waitForPage(() -> { + page.click("a[target=_blank]"); +}); +System.out.println(newPage.evaluate("location.href")); ``` ```python async @@ -93,6 +110,10 @@ obtained via [`method: BrowserContext.cookies`]. await browserContext.addCookies([cookieObject1, cookieObject2]); ``` +```java +browserContext.addCookies(Arrays.asList(cookieObject1, cookieObject2)); +``` + ```python async await browser_context.add_cookies([cookie_object1, cookie_object2]) ``` @@ -137,6 +158,11 @@ await browserContext.addInitScript({ }); ``` +```java +// In your playwright script, assuming the preload.js file is in same directory. +browserContext.addInitScript(Paths.get("preload.js")); +``` + ```python async # in your playwright script, assuming the preload.js file is in same directory. await browser_context.add_init_script(path="preload.js") @@ -193,6 +219,13 @@ await context.grantPermissions(['clipboard-read']); context.clearPermissions(); ``` +```java +BrowserContext context = browser.newContext(); +context.grantPermissions(Arrays.asList("clipboard-read")); +// do stuff .. +context.clearPermissions(); +``` + ```python async context = await browser.new_context() await context.grant_permissions(["clipboard-read"]) @@ -268,6 +301,30 @@ const { webkit } = require('playwright'); // Or 'chromium' or 'firefox'. })(); ``` +```java +import com.microsoft.playwright.*; + +public class Example { + public static void main(String[] args) { + try (Playwright playwright = Playwright.create()) { + BrowserType webkit = playwright.webkit() + Browser browser = webkit.launch(new BrowserType.LaunchOptions().setHeadless(false)); + BrowserContext context = browser.newContext(); + context.exposeBinding("pageURL", (source, args) -> source.page().url()); + Page page = context.newPage(); + page.setContent("\n" + + "\n" + + "
"); + page.click("button"); + } + } +} +``` + ```python async import asyncio from playwright.async_api import async_playwright @@ -334,6 +391,20 @@ await page.setContent(` `); ``` +```java +context.exposeBinding("clicked", (source, args) -> { + ElementHandle element = (ElementHandle) args[0]; + System.out.println(element.textContent()); + return null; +}, new BrowserContext.ExposeBindingOptions().setHandle(true)); +page.setContent("" + + "\n" + + "
Click me
\n" + + "
Or click me
\n"); +``` + ```python async async def print(source, element): print(await element.text_content()) @@ -412,6 +483,44 @@ const crypto = require('crypto'); })(); ``` +```java +import com.microsoft.playwright.*; + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; + +public class Example { + public static void main(String[] args) { + try (Playwright playwright = Playwright.create()) { + BrowserType webkit = playwright.webkit() + Browser browser = webkit.launch(new BrowserType.LaunchOptions().setHeadless(false)); + context.exposeFunction("sha1", args -> { + String text = (String) args[0]; + MessageDigest crypto; + try { + crypto = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException e) { + return null; + } + byte[] token = crypto.digest(text.getBytes(StandardCharsets.UTF_8)); + return Base64.getEncoder().encodeToString(token); + }); + Page page = context.newPage(); + page.setContent("\n" + + "\n" + + "
\n"); + page.click("button"); + } + } +} +``` + ```python async import asyncio import hashlib @@ -544,6 +653,14 @@ await page.goto('https://example.com'); await browser.close(); ``` +```java +BrowserContext context = browser.newContext(); +context.route("**/*.{png,jpg,jpeg}", route -> route.abort()); +Page page = context.newPage(); +page.navigate("https://example.com"); +browser.close(); +``` + ```python async context = await browser.new_context() page = await context.new_page() @@ -570,6 +687,14 @@ await page.goto('https://example.com'); await browser.close(); ``` +```java +BrowserContext context = browser.newContext(); +context.route(Pattern.compile("(\\.png$)|(\\.jpg$)"), route -> route.abort()); +Page page = context.newPage(); +page.navigate("https://example.com"); +browser.close(); +``` + ```python async context = await browser.new_context() page = await context.new_page() @@ -670,6 +795,10 @@ Sets the context's geolocation. Passing `null` or `undefined` emulates position await browserContext.setGeolocation({latitude: 59.95, longitude: 30.31667}); ``` +```java +browserContext.setGeolocation(new Geolocation(59.95, 30.31667)); +``` + ```python async await browser_context.set_geolocation({"latitude": 59.95, "longitude": 30.31667}) ``` @@ -774,6 +903,10 @@ const [page, _] = await Promise.all([ ]); ``` +```java +Page newPage = context.waitForPage(() -> page.click("button")); +``` + ```python async async with context.expect_event("page") as event_info: await page.click("button") diff --git a/docs/src/api/class-browsertype.md b/docs/src/api/class-browsertype.md index 54ae53f454bf5..8459833dc6f51 100644 --- a/docs/src/api/class-browsertype.md +++ b/docs/src/api/class-browsertype.md @@ -15,6 +15,23 @@ const { chromium } = require('playwright'); // Or 'firefox' or 'webkit'. })(); ``` +```java +import com.microsoft.playwright.*; + +public class Example { + public static void main(String[] args) { + try (Playwright playwright = Playwright.create()) { + BrowserType chromium = playwright.chromium(); + Browser browser = chromium.launch(); + Page page = browser.newPage(); + page.navigate("https://example.com"); + // other actions... + browser.close(); + } + } +} +``` + ```python async import asyncio from playwright.async_api import async_playwright @@ -49,12 +66,13 @@ with sync_playwright() as playwright: ``` ## async method: BrowserType.connect -* langs: js +* langs: js, java - returns: <[Browser]> This methods attaches Playwright to an existing browser instance. ### param: BrowserType.connect.params +* langs: js - `params` <[Object]> - `wsEndpoint` <[string]> A browser websocket endpoint to connect to. - `slowMo` <[float]> Slows down Playwright operations by the specified amount of milliseconds. Useful so that you @@ -63,6 +81,26 @@ This methods attaches Playwright to an existing browser instance. - `timeout` <[float]> Maximum time in milliseconds to wait for the connection to be established. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. +### param: BrowserType.connect.wsEndpoint +* langs: java +- `wsEndpoint` <[string]> + +A browser websocket endpoint to connect to. + +### option: BrowserType.connect.slowMo +* langs: java +- `slowMo` <[float]> + +Slows down Playwright operations by the specified amount of milliseconds. Useful so that you +can see what is going on. Defaults to 0. + +### option: BrowserType.connect.timeout +* langs: java +- `timeout` <[float]> + +Maximum time in milliseconds to wait for the connection to be established. Defaults to +`30000` (30 seconds). Pass `0` to disable timeout. + ## async method: BrowserType.connectOverCDP * langs: js - returns: <[Browser]> @@ -102,6 +140,12 @@ const browser = await chromium.launch({ // Or 'firefox' or 'webkit'. }); ``` +```java +// Or "firefox" or "webkit". +Browser browser = chromium.launch(new BrowserType.LaunchOptions() + .setIgnoreDefaultArgs(Arrays.asList("--mute-audio"))); +``` + ```python async browser = await playwright.chromium.launch( # or "firefox" or "webkit". ignore_default_args=["--mute-audio"] diff --git a/docs/src/api/class-dialog.md b/docs/src/api/class-dialog.md index b2951d6748e73..5224c46818c26 100644 --- a/docs/src/api/class-dialog.md +++ b/docs/src/api/class-dialog.md @@ -13,12 +13,32 @@ const { chromium } = require('playwright'); // Or 'firefox' or 'webkit'. page.on('dialog', async dialog => { console.log(dialog.message()); await dialog.dismiss(); - await browser.close(); }); - page.evaluate(() => alert('1')); + await page.evaluate(() => alert('1')); + await browser.close(); })(); ``` +```java +import com.microsoft.playwright.*; + +public class Example { + public static void main(String[] args) { + try (Playwright playwright = Playwright.create()) { + BrowserType chromium = playwright.chromium(); + Browser browser = chromium.launch(); + Page page = browser.newPage(); + page.onDialog(dialog -> { + System.out.println(dialog.message()); + dialog.dismiss(); + }); + page.evaluate("alert('1')"); + browser.close(); + } + } +} +``` + ```python async import asyncio from playwright.async_api import async_playwright diff --git a/docs/src/api/class-download.md b/docs/src/api/class-download.md index c7e45ac292885..0142ca9ed6992 100644 --- a/docs/src/api/class-download.md +++ b/docs/src/api/class-download.md @@ -16,6 +16,22 @@ const [ download ] = await Promise.all([ const path = await download.path(); ``` +```java +// wait for download to start +Download download = page.waitForDownload(() -> page.click("a")); +// wait for download to complete +Path path = download.path(); +``` + +```java +// wait for download to start +Download download = page.waitForDownload(() -> { + page.click("a"); +}); +// wait for download to complete +Path path = download.path(); +``` + ```python async async with page.expect_download() as download_info: await page.click("a") @@ -78,4 +94,4 @@ browsers can use different logic for computing it. ## method: Download.url - returns: <[string]> -Returns downloaded url. +Returns downloaded url. \ No newline at end of file diff --git a/docs/src/api/class-elementhandle.md b/docs/src/api/class-elementhandle.md index 9ab821d0087d0..3a39f591aca73 100644 --- a/docs/src/api/class-elementhandle.md +++ b/docs/src/api/class-elementhandle.md @@ -16,6 +16,24 @@ const { chromium } = require('playwright'); // Or 'firefox' or 'webkit'. })(); ``` +```java +import com.microsoft.playwright.*; + +public class Example { + public static void main(String[] args) { + try (Playwright playwright = Playwright.create()) { + BrowserType chromium = playwright.chromium(); + Browser browser = chromium.launch(); + Page page = browser.newPage(); + page.navigate("https://example.com"); + ElementHandle hrefElement = page.querySelector("a"); + hrefElement.click(); + // ... + } + } +} +``` + ```python async import asyncio from playwright.async_api import async_playwright @@ -81,6 +99,11 @@ const box = await elementHandle.boundingBox(); await page.mouse.click(box.x + box.width / 2, box.y + box.height / 2); ``` +```java +BoundingBox box = elementHandle.boundingBox(); +page.mouse().click(box.x + box.width / 2, box.y + box.height / 2); +``` + ```python async box = await element_handle.bounding_box() await page.mouse.click(box["x"] + box["width"] / 2, box["y"] + box["height"] / 2) @@ -189,6 +212,10 @@ is dispatched. This is equivalend to calling await elementHandle.dispatchEvent('click'); ``` +```java +elementHandle.dispatchEvent("click"); +``` + ```python async await element_handle.dispatch_event("click") ``` @@ -219,6 +246,14 @@ const dataTransfer = await page.evaluateHandle(() => new DataTransfer()); await elementHandle.dispatchEvent('dragstart', { dataTransfer }); ``` +```java +// Note you can only create DataTransfer in Chromium and Firefox +JSHandle dataTransfer = page.evaluateHandle("() => new DataTransfer()"); +Map arg = new HashMap<>(); +arg.put("dataTransfer", dataTransfer); +elementHandle.dispatchEvent("dragstart", arg); +``` + ```python async # note you can only create data_transfer in chromium and firefox data_transfer = await page.evaluate_handle("new DataTransfer()") @@ -264,6 +299,12 @@ expect(await tweetHandle.$eval('.like', node => node.innerText)).toBe('100'); expect(await tweetHandle.$eval('.retweets', node => node.innerText)).toBe('10'); ``` +```java +ElementHandle tweetHandle = page.querySelector(".tweet"); +assertEquals("100", tweetHandle.evalOnSelector(".like", "node => node.innerText")); +assertEquals("10", tweetHandle.evalOnSelector(".retweets", "node => node.innerText")); +``` + ```python async tweet_handle = await page.query_selector(".tweet") assert await tweet_handle.eval_on_selector(".like", "node => node.innerText") == "100" @@ -314,6 +355,11 @@ const feedHandle = await page.$('.feed'); expect(await feedHandle.$$eval('.tweet', nodes => nodes.map(n => n.innerText))).toEqual(['Hello!', 'Hi!']); ``` +```java +ElementHandle feedHandle = page.querySelector(".feed"); +assertEquals(Arrays.asList("Hello!", "Hi!"), feedHandle.evalOnSelectorAll(".tweet", "nodes => nodes.map(n => n.innerText)")); +``` + ```python async feed_handle = await page.query_selector(".feed") assert await feed_handle.eval_on_selector_all(".tweet", "nodes => nodes.map(n => n.innerText)") == ["hello!", "hi!"] @@ -551,6 +597,15 @@ handle.selectOption({ label: 'Blue' }); handle.selectOption(['red', 'green', 'blue']); ``` +```java +// single selection matching the value +handle.selectOption("blue"); +// single selection matching the label +handle.selectOption(new SelectOption().setLabel("Blue")); +// multiple selection +handle.selectOption(new String[] {"red", "green", "blue"}); +``` + ```python async # single selection matching the value await handle.select_option("blue") @@ -650,6 +705,11 @@ await elementHandle.type('Hello'); // Types instantly await elementHandle.type('World', {delay: 100}); // Types slower, like a user ``` +```java +elementHandle.type("Hello"); // Types instantly +elementHandle.type("World", new ElementHandle.TypeOptions().setDelay(100)); // Types slower, like a user +``` + ```python async await element_handle.type("hello") # types instantly await element_handle.type("world", delay=100) # types slower, like a user @@ -668,6 +728,12 @@ await elementHandle.type('some text'); await elementHandle.press('Enter'); ``` +```java +ElementHandle elementHandle = page.querySelector("input"); +elementHandle.type("some text"); +elementHandle.press("Enter"); +``` + ```python async element_handle = await page.query_selector("input") await element_handle.type("some text") @@ -758,6 +824,14 @@ const div = await page.$('div'); const span = await div.waitForSelector('span', { state: 'attached' }); ``` +```java +page.setContent("
"); +ElementHandle div = page.querySelector("div"); +// Waiting for the "span" selector relative to the div. +ElementHandle span = div.waitForSelector("span", new ElementHandle.WaitForSelectorOptions() + .setState(WaitForSelectorState.ATTACHED)); +``` + ```python async await page.set_content("
") div = await page.query_selector("div") diff --git a/docs/src/api/class-filechooser.md b/docs/src/api/class-filechooser.md index e560a1a87ac66..2389db652f884 100644 --- a/docs/src/api/class-filechooser.md +++ b/docs/src/api/class-filechooser.md @@ -10,6 +10,11 @@ const [fileChooser] = await Promise.all([ await fileChooser.setFiles('myfile.pdf'); ``` +```java +FileChooser fileChooser = page.waitForFileChooser(() -> page.click("upload")); +fileChooser.setFiles(Paths.get("myfile.pdf")); +``` + ```python async async with page.expect_file_chooser() as fc_info: await page.click("upload") diff --git a/docs/src/api/class-frame.md b/docs/src/api/class-frame.md index 8a0174cdea8ad..edc798fa39f5e 100644 --- a/docs/src/api/class-frame.md +++ b/docs/src/api/class-frame.md @@ -31,6 +31,29 @@ const { firefox } = require('playwright'); // Or 'chromium' or 'webkit'. })(); ``` +```java +import com.microsoft.playwright.*; + +public class Example { + public static void main(String[] args) { + try (Playwright playwright = Playwright.create()) { + BrowserType firefox = playwright.firefox(); + Browser browser = firefox.launch(); + Page page = browser.newPage(); + page.navigate("https://www.google.com/chrome/browser/canary.html"); + dumpFrameTree(page.mainFrame(), ""); + browser.close(); + } + } + static void dumpFrameTree(Frame frame, String indent) { + System.out.println(indent + frame.url()); + for (Frame child : frame.childFrames()) { + dumpFrameTree(child, indent + " "); + } + } +} +``` + ```python async import asyncio from playwright.async_api import async_playwright @@ -237,6 +260,10 @@ is dispatched. This is equivalend to calling await frame.dispatchEvent('button#submit', 'click'); ``` +```java +frame.dispatchEvent("button#submit", "click"); +``` + ```python async await frame.dispatch_event("button#submit", "click") ``` @@ -267,6 +294,14 @@ const dataTransfer = await frame.evaluateHandle(() => new DataTransfer()); await frame.dispatchEvent('#source', 'dragstart', { dataTransfer }); ``` +```java +// Note you can only create DataTransfer in Chromium and Firefox +JSHandle dataTransfer = frame.evaluateHandle("() => new DataTransfer()"); +Map arg = new HashMap<>(); +arg.put("dataTransfer", dataTransfer); +frame.dispatchEvent("#source", "dragstart", arg); +``` + ```python async # note you can only create data_transfer in chromium and firefox data_transfer = await frame.evaluate_handle("new DataTransfer()") @@ -279,7 +314,6 @@ data_transfer = frame.evaluate_handle("new DataTransfer()") frame.dispatch_event("#source", "dragstart", { "dataTransfer": data_transfer }) ``` - ### param: Frame.dispatchEvent.selector = %%-input-selector-%% ### param: Frame.dispatchEvent.type @@ -317,6 +351,12 @@ const preloadHref = await frame.$eval('link[rel=preload]', el => el.href); const html = await frame.$eval('.main-container', (e, suffix) => e.outerHTML + suffix, 'hello'); ``` +```java +String searchValue = (String) frame.evalOnSelector("#search", "el => el.value"); +String preloadHref = (String) frame.evalOnSelector("link[rel=preload]", "el => el.href"); +String html = (String) frame.evalOnSelector(".main-container", "(e, suffix) => e.outerHTML + suffix", "hello"); +``` + ```python async search_value = await frame.eval_on_selector("#search", "el => el.value") preload_href = await frame.eval_on_selector("link[rel=preload]", "el => el.href") @@ -359,6 +399,10 @@ Examples: const divsCounts = await frame.$$eval('div', (divs, min) => divs.length >= min, 10); ``` +```java +boolean divsCounts = (boolean) page.evalOnSelectorAll("div", "(divs, min) => divs.length >= min", 10); +``` + ```python async divs_counts = await frame.eval_on_selector_all("div", "(divs, min) => divs.length >= min", 10) ``` @@ -395,6 +439,13 @@ const result = await frame.evaluate(([x, y]) => { console.log(result); // prints "56" ``` +```java +Object result = frame.evaluate("([x, y]) => {\n" + + " return Promise.resolve(x * y);\n" + + "}", Arrays.asList(7, 8)); +System.out.println(result); // prints "56" +``` + ```python async result = await frame.evaluate("([x, y]) => Promise.resolve(x * y)", [7, 8]) print(result) # prints "56" @@ -405,13 +456,16 @@ result = frame.evaluate("([x, y]) => Promise.resolve(x * y)", [7, 8]) print(result) # prints "56" ``` - A string can also be passed in instead of a function. ```js console.log(await frame.evaluate('1 + 2')); // prints "3" ``` +```java +System.out.println(frame.evaluate("1 + 2")); // prints "3" +``` + ```python async print(await frame.evaluate("1 + 2")) # prints "3" x = 10 @@ -424,7 +478,6 @@ x = 10 print(frame.evaluate(f"1 + {x}")) # prints "11" ``` - [ElementHandle] instances can be passed as an argument to the [`method: Frame.evaluate`]: ```js @@ -433,6 +486,12 @@ const html = await frame.evaluate(([body, suffix]) => body.innerHTML + suffix, [ await bodyHandle.dispose(); ``` +```java +ElementHandle bodyHandle = frame.querySelector("body"); +String html = (String) frame.evaluate("([body, suffix]) => body.innerHTML + suffix", Arrays.asList(bodyHandle, "hello")); +bodyHandle.dispose(); +``` + ```python async body_handle = await frame.query_selector("body") html = await frame.evaluate("([body, suffix]) => body.innerHTML + suffix", [body_handle, "hello"]) @@ -468,6 +527,11 @@ const aWindowHandle = await frame.evaluateHandle(() => Promise.resolve(window)); aWindowHandle; // Handle for the window object. ``` +```java +// Handle for the window object. +JSHandle aWindowHandle = frame.evaluateHandle("() => Promise.resolve(window)"); +``` + ```python async a_window_handle = await frame.evaluate_handle("Promise.resolve(window)") a_window_handle # handle for the window object. @@ -484,6 +548,10 @@ A string can also be passed in instead of a function. const aHandle = await frame.evaluateHandle('document'); // Handle for the 'document'. ``` +```java +JSHandle aHandle = frame.evaluateHandle("document"); // Handle for the "document". +``` + ```python async a_handle = await page.evaluate_handle("document") # handle for the "document" ``` @@ -501,6 +569,13 @@ console.log(await resultHandle.jsonValue()); await resultHandle.dispose(); ``` +```java +JSHandle aHandle = frame.evaluateHandle("() => document.body"); +JSHandle resultHandle = frame.evaluateHandle("([body, suffix]) => body.innerHTML + suffix", Arrays.asList(aHandle, "hello")); +System.out.println(resultHandle.jsonValue()); +resultHandle.dispose(); +``` + ```python async a_handle = await page.evaluate_handle("document.body") result_handle = await page.evaluate_handle("body => body.innerHTML", a_handle) @@ -567,6 +642,12 @@ const contentFrame = await frameElement.contentFrame(); console.log(frame === contentFrame); // -> true ``` +```java +ElementHandle frameElement = frame.frameElement(); +Frame contentFrame = frameElement.contentFrame(); +System.out.println(frame == contentFrame); // -> true +``` + ```python async frame_element = await frame.frame_element() content_frame = await frame_element.content_frame() @@ -844,6 +925,15 @@ frame.selectOption('select#colors', { label: 'Blue' }); frame.selectOption('select#colors', 'red', 'green', 'blue'); ``` +```java +// single selection matching the value +frame.selectOption("select#colors", "blue"); +// single selection matching both the value and the label +frame.selectOption("select#colors", new SelectOption().setLabel("Blue")); +// multiple selection +frame.selectOption("select#colors", new String[] {"red", "green", "blue"}); +``` + ```python async # single selection matching the value await frame.select_option("select#colors", "blue") @@ -953,6 +1043,13 @@ await frame.type('#mytextarea', 'Hello'); // Types instantly await frame.type('#mytextarea', 'World', {delay: 100}); // Types slower, like a user ``` +```java +// Types instantly +frame.type("#mytextarea", "Hello"); +// Types slower, like a user +frame.type("#mytextarea", "World", new Frame.TypeOptions().setDelay(100)); +``` + ```python async await frame.type("#mytextarea", "hello") # types instantly await frame.type("#mytextarea", "world", delay=100) # types slower, like a user @@ -1029,6 +1126,23 @@ const { firefox } = require('playwright'); // Or 'chromium' or 'webkit'. })(); ``` +```java +import com.microsoft.playwright.*; + +public class Example { + public static void main(String[] args) { + try (Playwright playwright = Playwright.create()) { + BrowserType firefox = playwright.firefox(); + Browser browser = firefox.launch(); + Page page = browser.newPage(); + page.setViewportSize(50, 50); + page.mainFrame().waitForFunction("window.innerWidth < 100"); + browser.close(); + } + } +} +``` + ```python async import asyncio from playwright.async_api import async_playwright @@ -1069,6 +1183,11 @@ const selector = '.foo'; await frame.waitForFunction(selector => !!document.querySelector(selector), selector); ``` +```java +String selector = ".foo"; +frame.waitForFunction("selector => !!document.querySelector(selector)", selector); +``` + ```python async selector = ".foo" await frame.wait_for_function("selector => !!document.querySelector(selector)", selector) @@ -1104,6 +1223,11 @@ await frame.click('button'); // Click triggers navigation. await frame.waitForLoadState(); // Waits for 'load' state by default. ``` +```java +frame.click("button"); // Click triggers navigation. +frame.waitForLoadState(); // Waits for "load" state by default. +``` + ```python async await frame.click("button") # click triggers navigation. await frame.wait_for_load_state() # the promise resolves after "load" event. @@ -1137,6 +1261,14 @@ const [response] = await Promise.all([ ]); ``` +```java +// The method returns after navigation has finished +Response response = frame.waitForNavigation(() -> { + // Clicking the link will indirectly cause a navigation + frame.click("a.delayed-navigation"); +}); +``` + ```python async async with frame.expect_navigation(): await frame.click("a.delayed-navigation") # clicking the link will indirectly cause a navigation @@ -1188,6 +1320,26 @@ const { chromium } = require('playwright'); // Or 'firefox' or 'webkit'. })(); ``` +```java +import com.microsoft.playwright.*; + +public class Example { + public static void main(String[] args) { + try (Playwright playwright = Playwright.create()) { + BrowserType chromium = playwright.chromium(); + Browser browser = chromium.launch(); + Page page = browser.newPage(); + for (String currentURL : Arrays.asList("https://google.com", "https://bbc.com")) { + page.navigate(currentURL); + ElementHandle element = page.mainFrame().waitForSelector("img"); + System.out.println("Loaded image: " + element.getAttribute("src")); + } + browser.close(); + } + } +} +``` + ```python async import asyncio from playwright.async_api import async_playwright diff --git a/docs/src/api/class-jshandle.md b/docs/src/api/class-jshandle.md index 62fb54224fe40..e9d078770e05f 100644 --- a/docs/src/api/class-jshandle.md +++ b/docs/src/api/class-jshandle.md @@ -8,6 +8,11 @@ const windowHandle = await page.evaluateHandle(() => window); // ... ``` +```java +JSHandle windowHandle = page.evaluateHandle("() => window"); +// ... +``` + ```python async window_handle = await page.evaluate_handle("window") # ... @@ -51,6 +56,11 @@ const tweetHandle = await page.$('.tweet .retweets'); expect(await tweetHandle.evaluate(node => node.innerText)).toBe('10 retweets'); ``` +```java +ElementHandle tweetHandle = page.querySelector(".tweet .retweets"); +assertEquals("10 retweets", tweetHandle.evaluate("node => node.innerText")); +``` + ```python async tweet_handle = await page.query_selector(".tweet .retweets") assert await tweet_handle.evaluate("node => node.innerText") == "10 retweets" @@ -102,6 +112,14 @@ const documentHandle = properties.get('document'); await handle.dispose(); ``` +```java +JSHandle handle = page.evaluateHandle("() => ({window, document}");); +Map properties = handle.getProperties(); +JSHandle windowHandle = properties.get("window"); +JSHandle documentHandle = properties.get("document"); +handle.dispose(); +``` + ```python async handle = await page.evaluate_handle("{window, document}") properties = await handle.get_properties() diff --git a/docs/src/api/class-keyboard.md b/docs/src/api/class-keyboard.md index 4431c1e14bbc2..47bec79adabbc 100644 --- a/docs/src/api/class-keyboard.md +++ b/docs/src/api/class-keyboard.md @@ -21,6 +21,17 @@ await page.keyboard.press('Backspace'); // Result text will end up saying 'Hello!' ``` +```java +page.keyboard().type("Hello World!"); +page.keyboard().press("ArrowLeft"); +page.keyboard().down("Shift"); +for (int i = 0; i < " World".length(); i++) + page.keyboard().press("ArrowLeft"); +page.keyboard().up("Shift"); +page.keyboard().press("Backspace"); +// Result text will end up saying "Hello!" +``` + ```python async await page.keyboard.type("Hello World!") await page.keyboard.press("ArrowLeft") @@ -51,6 +62,12 @@ await page.keyboard.press('Shift+KeyA'); await page.keyboard.press('Shift+A'); ``` +```java +page.keyboard().press("Shift+KeyA"); +// or +page.keyboard().press("Shift+A"); +``` + ```python async await page.keyboard.press("Shift+KeyA") # or @@ -72,6 +89,13 @@ await page.keyboard.press('Control+A'); await page.keyboard.press('Meta+A'); ``` +```java +// on Windows and Linux +page.keyboard().press("Control+A"); +// on macOS +page.keyboard().press("Meta+A"); +``` + ```python async # on windows and linux await page.keyboard.press("Control+A") @@ -129,6 +153,10 @@ Dispatches only `input` event, does not emit the `keydown`, `keyup` or `keypress page.keyboard.insertText('嗨'); ``` +```java +page.keyboard().insertText("嗨"); +``` + ```python async await page.keyboard.insert_text("嗨") ``` @@ -178,6 +206,18 @@ await page.screenshot({ path: 'O.png' }); await browser.close(); ``` +```java +Page page = browser.newPage(); +page.navigate("https://keycode.info"); +page.keyboard().press("A"); +page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("A.png")); +page.keyboard().press("ArrowLeft"); +page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("ArrowLeft.png"))); +page.keyboard().press("Shift+O"); +page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("O.png"))); +browser.close(); +``` + ```python async page = await browser.new_page() await page.goto("https://keycode.info") @@ -225,6 +265,13 @@ await page.keyboard.type('Hello'); // Types instantly await page.keyboard.type('World', {delay: 100}); // Types slower, like a user ``` +```java +// Types instantly +page.keyboard().type("Hello"); +// Types slower, like a user +page.keyboard().type("World", new Keyboard.TypeOptions().setDelay(100)); +``` + ```python async await page.keyboard.type("Hello") # types instantly await page.keyboard.type("World", delay=100) # types slower, like a user diff --git a/docs/src/api/class-mouse.md b/docs/src/api/class-mouse.md index d58ce793e3500..a6f01ea53be13 100644 --- a/docs/src/api/class-mouse.md +++ b/docs/src/api/class-mouse.md @@ -15,6 +15,17 @@ await page.mouse.move(0, 0); await page.mouse.up(); ``` +```java +// Using ‘page.mouse’ to trace a 100x100 square. +page.mouse().move(0, 0); +page.mouse().down(); +page.mouse().move(0, 100); +page.mouse().move(100, 100); +page.mouse().move(100, 0); +page.mouse().move(0, 0); +page.mouse().up(); +``` + ```python async # using ‘page.mouse’ to trace a 100x100 square. await page.mouse.move(0, 0) diff --git a/docs/src/api/class-page.md b/docs/src/api/class-page.md index 284e43834794e..74ef4edee689a 100644 --- a/docs/src/api/class-page.md +++ b/docs/src/api/class-page.md @@ -20,6 +20,24 @@ const { webkit } = require('playwright'); // Or 'chromium' or 'firefox'. })(); ``` +```java +import com.microsoft.playwright.*; + +public class Example { + public static void main(String[] args) { + try (Playwright playwright = Playwright.create()) { + BrowserType webkit = playwright.webkit(); + Browser browser = webkit.launch(); + BrowserContext context = browser.newContext(); + Page page = context.newPage(); + page.navigate("https://example.com"); + page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("screenshot.png"))); + browser.close(); + } + } +} +``` + ```python async import asyncio from playwright.async_api import async_playwright @@ -65,6 +83,10 @@ This example logs a message for a single page `load` event: page.once('load', () => console.log('Page loaded!')); ``` +```java +page.onLoad(p -> System.out.println("Page loaded!")); +``` + ```py page.once("load", lambda: print("page loaded!")) ``` @@ -80,6 +102,15 @@ page.on('request', logRequest); page.removeListener('request', logRequest); ``` +```java +Consumer logRequest = interceptedRequest -> { + System.out.println("A request was made: " + interceptedRequest.url()); +}; +page.onRequest(logRequest); +// Sometime later... +page.offRequest(logRequest); +``` + ```py def log_request(intercepted_request): print("a request was made:", intercepted_request.url) @@ -94,6 +125,8 @@ page.remove_listener("request", log_request) Emitted when the page closes. ## event: Page.console +* langs: + - alias-java: consoleMessage - type: <[ConsoleMessage]> Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`. Also @@ -111,6 +144,14 @@ page.on('console', msg => { page.evaluate(() => console.log('hello', 5, {foo: 'bar'})); ``` +```java +page.onConsole(msg -> { + for (int i = 0; i < msg.args().size(); ++i) + System.out.println(i + ": " + msg.args().get(i).jsonValue()); +}); +page.evaluate("() => console.log('hello', 5, {foo: 'bar'})"); +``` + ```python async async def print_args(msg): for arg in msg.args: @@ -148,6 +189,17 @@ try { } ``` +```java +try { + // Crash might happen during a click. + page.click("button"); + // Or while waiting for an event. + page.waitForPopup(() -> {}); +} catch (PlaywrightException e) { + // When the page crashes, exception message contains "crash". +} +``` + ```python async try: # crash might happen during a click. @@ -207,6 +259,12 @@ page.on('filechooser', async (fileChooser) => { }); ``` +```java +page.onFileChooser(fileChooser -> { + fileChooser.setFiles(Paths.get("/tmp/myfile.pdf")); +}); +``` + ```py page.on("filechooser", lambda file_chooser: file_chooser.set_files("/tmp/myfile.pdf")) ``` @@ -258,6 +316,13 @@ const [popup] = await Promise.all([ console.log(await popup.evaluate('location.href')); ``` +```java +Page popup = page.waitForPopup(() -> { + page.evaluate("() => window.open('https://example.com')"); +}); +System.out.println(popup.evaluate("location.href")); +``` + ```python async async with page.expect_event("popup") as page_info: page.evaluate("window.open('https://example.com')") @@ -317,6 +382,7 @@ Emitted when a dedicated [WebWorker](https://developer.mozilla.org/en-US/docs/We page. ## property: Page.accessibility +* langs: csharp, js, python - type: <[Accessibility]> ## async method: Page.addInitScript @@ -341,6 +407,11 @@ Math.random = () => 42; await page.addInitScript({ path: './preload.js' }); ``` +```java +// In your playwright script, assuming the preload.js file is in same directory +page.addInitScript(Paths.get("./preload.js")); +``` + ```python async # in your playwright script, assuming the preload.js file is in same directory await page.add_init_script(path="./preload.js") @@ -578,6 +649,10 @@ is dispatched. This is equivalend to calling await page.dispatchEvent('button#submit', 'click'); ``` +```java +page.dispatchEvent("button#submit", "click"); +``` + ```python async await page.dispatch_event("button#submit", "click") ``` @@ -608,6 +683,14 @@ const dataTransfer = await page.evaluateHandle(() => new DataTransfer()); await page.dispatchEvent('#source', 'dragstart', { dataTransfer }); ``` +```java +// Note you can only create DataTransfer in Chromium and Firefox +JSHandle dataTransfer = page.evaluateHandle("() => new DataTransfer()"); +Map arg = new HashMap<>(); +arg.put("dataTransfer", dataTransfer); +page.dispatchEvent("#source", "dragstart", arg); +``` + ```python async # note you can only create data_transfer in chromium and firefox data_transfer = await page.evaluate_handle("new DataTransfer()") @@ -655,6 +738,25 @@ await page.evaluate(() => matchMedia('print').matches); // → false ``` +```java +page.evaluate("() => matchMedia('screen').matches"); +// → true +page.evaluate("() => matchMedia('print').matches"); +// → false + +page.emulateMedia(new Page.EmulateMediaOptions().setMedia(Media.PRINT)); +page.evaluate("() => matchMedia('screen').matches"); +// → false +page.evaluate("() => matchMedia('print').matches"); +// → true + +page.emulateMedia(new Page.EmulateMediaOptions()); +page.evaluate("() => matchMedia('screen').matches"); +// → true +page.evaluate("() => matchMedia('print').matches"); +// → false +``` + ```python async await page.evaluate("matchMedia('screen').matches") # → True @@ -703,6 +805,16 @@ await page.evaluate(() => matchMedia('(prefers-color-scheme: no-preference)').ma // → false ``` +```java +page.emulateMedia(new Page.EmulateMediaOptions().setColorScheme(ColorScheme.DARK)); +page.evaluate("() => matchMedia('(prefers-color-scheme: dark)').matches"); +// → true +page.evaluate("() => matchMedia('(prefers-color-scheme: light)').matches"); +// → false +page.evaluate("() => matchMedia('(prefers-color-scheme: no-preference)').matches"); +// → false +``` + ```python async await page.emulate_media(color_scheme="dark") await page.evaluate("matchMedia('(prefers-color-scheme: dark)').matches") @@ -755,6 +867,12 @@ const preloadHref = await page.$eval('link[rel=preload]', el => el.href); const html = await page.$eval('.main-container', (e, suffix) => e.outerHTML + suffix, 'hello'); ``` +```java +String searchValue = (String) page.evalOnSelector("#search", "el => el.value"); +String preloadHref = (String) page.evalOnSelector("link[rel=preload]", "el => el.href"); +String html = (String) page.evalOnSelector(".main-container", "(e, suffix) => e.outerHTML + suffix", "hello"); +``` + ```python async search_value = await page.eval_on_selector("#search", "el => el.value") preload_href = await page.eval_on_selector("link[rel=preload]", "el => el.href") @@ -796,6 +914,10 @@ Examples: const divCounts = await page.$$eval('div', (divs, min) => divs.length >= min, 10); ``` +```java +boolean divCounts = (boolean) page.evalOnSelectorAll("div", "(divs, min) => divs.length >= min", 10); +``` + ```python async div_counts = await page.eval_on_selector_all("div", "(divs, min) => divs.length >= min", 10) ``` @@ -834,6 +956,13 @@ const result = await page.evaluate(([x, y]) => { console.log(result); // prints "56" ``` +```java +Object result = page.evaluate("([x, y]) => {\n" + + " return Promise.resolve(x * y);\n" + + "}", Arrays.asList(7, 8)); +System.out.println(result); // prints "56" +``` + ```python async result = await page.evaluate("([x, y]) => Promise.resolve(x * y)", [7, 8]) print(result) # prints "56" @@ -852,6 +981,10 @@ const x = 10; console.log(await page.evaluate(`1 + ${x}`)); // prints "11" ``` +```java +System.out.println(page.evaluate("1 + 2")); // prints "3" +``` + ```python async print(await page.evaluate("1 + 2")) # prints "3" x = 10 @@ -872,6 +1005,12 @@ const html = await page.evaluate(([body, suffix]) => body.innerHTML + suffix, [b await bodyHandle.dispose(); ``` +```java +ElementHandle bodyHandle = page.querySelector("body"); +String html = (String) page.evaluate("([body, suffix]) => body.innerHTML + suffix", Arrays.asList(bodyHandle, "hello")); +bodyHandle.dispose(); +``` + ```python async body_handle = await page.query_selector("body") html = await page.evaluate("([body, suffix]) => body.innerHTML + suffix", [body_handle, "hello"]) @@ -908,6 +1047,11 @@ const aWindowHandle = await page.evaluateHandle(() => Promise.resolve(window)); aWindowHandle; // Handle for the window object. ``` +```java +// Handle for the window object. +JSHandle aWindowHandle = page.evaluateHandle("() => Promise.resolve(window)"); +``` + ```python async a_window_handle = await page.evaluate_handle("Promise.resolve(window)") a_window_handle # handle for the window object. @@ -924,6 +1068,10 @@ A string can also be passed in instead of a function: const aHandle = await page.evaluateHandle('document'); // Handle for the 'document' ``` +```java +JSHandle aHandle = page.evaluateHandle("document"); // Handle for the "document". +``` + ```python async a_handle = await page.evaluate_handle("document") # handle for the "document" ``` @@ -941,6 +1089,13 @@ console.log(await resultHandle.jsonValue()); await resultHandle.dispose(); ``` +```java +JSHandle aHandle = page.evaluateHandle("() => document.body"); +JSHandle resultHandle = page.evaluateHandle("([body, suffix]) => body.innerHTML + suffix", Arrays.asList(aHandle, "hello")); +System.out.println(resultHandle.jsonValue()); +resultHandle.dispose(); +``` + ```python async a_handle = await page.evaluate_handle("document.body") result_handle = await page.evaluate_handle("body => body.innerHTML", a_handle) @@ -1000,6 +1155,30 @@ const { webkit } = require('playwright'); // Or 'chromium' or 'firefox'. })(); ``` +```java +import com.microsoft.playwright.*; + +public class Example { + public static void main(String[] args) { + try (Playwright playwright = Playwright.create()) { + BrowserType webkit = playwright.webkit(); + Browser browser = webkit.launch({ headless: false }); + BrowserContext context = browser.newContext(); + Page page = context.newPage(); + page.exposeBinding("pageURL", (source, args) -> source.page().url()); + page.setContent("\n" + + "\n" + + "
"); + page.click("button"); + } + } +} +``` + ```python async import asyncio from playwright.async_api import async_playwright @@ -1066,6 +1245,20 @@ await page.setContent(` `); ``` +```java +page.exposeBinding("clicked", (source, args) -> { + ElementHandle element = (ElementHandle) args[0]; + System.out.println(element.textContent()); + return null; +}, new Page.ExposeBindingOptions().setHandle(true)); +page.setContent("" + + "\n" + + "
Click me
\n" + + "
Or click me
\n"); +``` + ```python async async def print(source, element): print(await element.text_content()) @@ -1146,6 +1339,44 @@ const crypto = require('crypto'); })(); ``` +```java +import com.microsoft.playwright.*; + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; + +public class Example { + public static void main(String[] args) { + try (Playwright playwright = Playwright.create()) { + BrowserType webkit = playwright.webkit(); + Browser browser = webkit.launch({ headless: false }); + Page page = browser.newPage(); + page.exposeFunction("sha1", args -> { + String text = (String) args[0]; + MessageDigest crypto; + try { + crypto = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException e) { + return null; + } + byte[] token = crypto.digest(text.getBytes(StandardCharsets.UTF_8)); + return Base64.getEncoder().encodeToString(token); + }); + page.setContent("\n" + + "\n" + + "
\n"); + page.click("button"); + } + } +} +``` + ```python async import asyncio import hashlib @@ -1261,6 +1492,10 @@ Returns frame matching the specified criteria. Either `name` or `url` must be sp const frame = page.frame('frame-name'); ``` +```java +Frame frame = page.frame("frame-name"); +``` + ```py frame = page.frame(name="frame-name") ``` @@ -1269,6 +1504,10 @@ frame = page.frame(name="frame-name") const frame = page.frame({ url: /.*domain.*/ }); ``` +```java +Frame frame = page.frameByUrl(Pattern.compile(".*domain.*"); +``` + ```py frame = page.frame(url=r".*domain.*") ``` @@ -1545,6 +1784,12 @@ await page.emulateMedia({media: 'screen'}); await page.pdf({path: 'page.pdf'}); ``` +```java +// Generates a PDF with "screen" media type. +page.emulateMedia(new Page.EmulateMediaOptions().setMedia(Media.SCREEN)); +page.pdf(new Page.PdfOptions().setPath(Paths.get("page.pdf"))); +``` + ```python async # generates a pdf with "screen" media type. await page.emulate_media(media="screen") @@ -1726,6 +1971,17 @@ await page.screenshot({ path: 'O.png' }); await browser.close(); ``` +```java +Page page = browser.newPage(); +page.navigate("https://keycode.info"); +page.press("body", "A"); +page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("A.png"))); +page.press("body", "ArrowLeft"); +page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("ArrowLeft.png" ))); +page.press("body", "Shift+O"); +page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("O.png" ))); +``` + ```python async page = await browser.new_page() await page.goto("https://keycode.info") @@ -1821,6 +2077,13 @@ await page.goto('https://example.com'); await browser.close(); ``` +```java +Page page = browser.newPage(); +page.route("**/*.{png,jpg,jpeg}", route -> route.abort()); +page.navigate("https://example.com"); +browser.close(); +``` + ```python async page = await browser.new_page() await page.route("**/*.{png,jpg,jpeg}", lambda route: route.abort()) @@ -1844,6 +2107,13 @@ await page.goto('https://example.com'); await browser.close(); ``` +```java +Page page = browser.newPage(); +page.route(Pattern.compile("(\\.png$)|(\\.jpg$)"),route -> route.abort()); +page.navigate("https://example.com"); +browser.close(); +``` + ```python async page = await browser.new_page() await page.route(re.compile(r"(\.png$)|(\.jpg$)"), lambda route: route.abort()) @@ -1950,6 +2220,15 @@ page.selectOption('select#colors', ['red', 'green', 'blue']); ``` +```java +// single selection matching the value +page.selectOption("select#colors", "blue"); +// single selection matching both the value and the label +page.selectOption("select#colors", new SelectOption().setLabel("Blue")); +// multiple selection +page.selectOption("select#colors", new String[] {"red", "green", "blue"}); +``` + ```python async # single selection matching the value await page.select_option("select#colors", "blue") @@ -2068,6 +2347,12 @@ await page.setViewportSize({ await page.goto('https://example.com'); ``` +```java +Page page = browser.newPage(); +page.setViewportSize(640, 480); +page.navigate("https://example.com"); +``` + ```python async page = await browser.new_page() await page.set_viewport_size({"width": 640, "height": 480}) @@ -2081,10 +2366,19 @@ page.goto("https://example.com") ``` ### param: Page.setViewportSize.viewportSize +* langs: js, python - `viewportSize` <[Object]> - `width` <[int]> page width in pixels. - `height` <[int]> page height in pixels. +### param: Page.setViewportSize.width +* langs: csharp, java +- `width` <[int]> page width in pixels. + +### param: Page.setViewportSize.height +* langs: csharp, java +- `height` <[int]> page height in pixels. + ## async method: Page.tap This method taps an element matching [`param: selector`] by performing the following steps: @@ -2146,6 +2440,13 @@ await page.type('#mytextarea', 'Hello'); // Types instantly await page.type('#mytextarea', 'World', {delay: 100}); // Types slower, like a user ``` +```java +// Types instantly +page.type("#mytextarea", "Hello"); +// Types slower, like a user +page.type("#mytextarea", "World", new Page.TypeOptions().setDelay(100)); +``` + ```python async await page.type("#mytextarea", "hello") # types instantly await page.type("#mytextarea", "world", delay=100) # types slower, like a user @@ -2352,6 +2653,23 @@ const { webkit } = require('playwright'); // Or 'chromium' or 'firefox'. })(); ``` +```java +import com.microsoft.playwright.*; + +public class Example { + public static void main(String[] args) { + try (Playwright playwright = Playwright.create()) { + BrowserType webkit = playwright.webkit(); + Browser browser = webkit.launch(); + Page page = browser.newPage(); + page.setViewportSize(50, 50); + page.waitForFunction("() => window.innerWidth < 100"); + browser.close(); + } + } +} +``` + ```python async import asyncio from playwright.async_api import async_playwright @@ -2392,6 +2710,11 @@ const selector = '.foo'; await page.waitForFunction(selector => !!document.querySelector(selector), selector); ``` +```java +String selector = ".foo"; +page.waitForFunction("selector => !!document.querySelector(selector)", selector); +``` + ```python async selector = ".foo" await page.wait_for_function("selector => !!document.querySelector(selector)", selector) @@ -2429,6 +2752,11 @@ await page.click('button'); // Click triggers navigation. await page.waitForLoadState(); // The promise resolves after 'load' event. ``` +```java +page.click("button"); // Click triggers navigation. +page.waitForLoadState(); // The promise resolves after "load" event. +``` + ```python async await page.click("button") # click triggers navigation. await page.wait_for_load_state() # the promise resolves after "load" event. @@ -2448,6 +2776,14 @@ await popup.waitForLoadState('domcontentloaded'); // The promise resolves after console.log(await popup.title()); // Popup is ready to use. ``` +```java +Page popup = page.waitForPopup(() -> { + page.click("button"); // Click triggers a popup. +}); +popup.waitForLoadState(LoadState.DOMCONTENTLOADED); +System.out.println(popup.title()); // Popup is ready to use. +``` + ```python async async with page.expect_popup() as page_info: await page.click("button") # click triggers a popup. @@ -2492,6 +2828,13 @@ const [response] = await Promise.all([ ]); ``` +```java +// The method returns after navigation has finished +Response response = page.waitForNavigation(() -> { + page.click("a.delayed-navigation"); // Clicking the link will indirectly cause a navigation +}); +``` + ```python async async with page.expect_navigation(): await page.click("a.delayed-navigation") # clicking the link will indirectly cause a navigation @@ -2546,6 +2889,13 @@ const finalRequest = await page.waitForRequest(request => request.url() === 'htt return firstRequest.url(); ``` +```java +Request firstRequest = page.waitForRequest("http://example.com/resource"); +Object finalRequest = page.waitForRequest( + request -> "http://example.com".equals(request.url()) && "GET".equals(request.method()), () -> {}); +return firstRequest.url(); +``` + ```python async async with page.expect_request("http://example.com/resource") as first: await page.click('button') @@ -2594,6 +2944,12 @@ const finalResponse = await page.waitForResponse(response => response.url() === return finalResponse.ok(); ``` +```java +Response firstResponse = page.waitForResponse("https://example.com/resource", () -> {}); +Response finalResponse = page.waitForResponse(response -> "https://example.com".equals(response.url()) && response.status() == 200, () -> {}); +return finalResponse.ok(); +``` + ```python async first_response = await page.wait_for_response("https://example.com/resource") final_response = await page.wait_for_response(lambda response: response.url == "https://example.com" and response.status === 200) @@ -2645,6 +3001,26 @@ const { chromium } = require('playwright'); // Or 'firefox' or 'webkit'. })(); ``` +```java +import com.microsoft.playwright.*; + +public class Example { + public static void main(String[] args) { + try (Playwright playwright = Playwright.create()) { + BrowserType chromium = playwright.chromium(); + Browser browser = chromium.launch(); + Page page = browser.newPage(); + for (String currentURL : Arrays.asList("https://google.com", "https://bbc.com")) { + page.navigate(currentURL); + ElementHandle element = page.waitForSelector("img"); + System.out.println("Loaded image: " + element.getAttribute("src")); + } + browser.close(); + } + } +} +``` + ```python async import asyncio from playwright.async_api import async_playwright @@ -2700,6 +3076,11 @@ flaky. Use signals such as network events, selectors becoming visible and others await page.waitForTimeout(1000); ``` +```java +// wait for 1 second +page.waitForTimeout(1000); +``` + ```python async # wait for 1 second await page.wait_for_timeout(1000) diff --git a/docs/src/api/class-playwright.md b/docs/src/api/class-playwright.md index 51a28fb7fdd93..8ccf73968618c 100644 --- a/docs/src/api/class-playwright.md +++ b/docs/src/api/class-playwright.md @@ -15,6 +15,23 @@ const { chromium, firefox, webkit } = require('playwright'); })(); ``` +```java +import com.microsoft.playwright.*; + +public class Example { + public static void main(String[] args) { + try (Playwright playwright = Playwright.create()) { + BrowserType chromium = playwright.chromium(); + Browser browser = chromium.launch(); + Page page = browser.newPage(); + page.navigate("http://example.com"); + // other actions... + browser.close(); + } + } +} +``` + ```python async import asyncio from playwright.async_api import async_playwright diff --git a/docs/src/api/class-request.md b/docs/src/api/class-request.md index 264dd44518c2a..f9ed5b3fec2c8 100644 --- a/docs/src/api/class-request.md +++ b/docs/src/api/class-request.md @@ -29,6 +29,12 @@ page.on('requestfailed', request => { }); ``` +```java +page.onRequestFailed(request -> { + System.out.println(request.url() + " " + request.failure()); +}); +``` + ```py page.on("requestfailed", lambda request: print(request.url + " " + request.failure)) ``` @@ -88,6 +94,11 @@ const response = await page.goto('http://example.com'); console.log(response.request().redirectedFrom().url()); // 'http://example.com' ``` +```java +Response response = page.navigate("http://example.com"); +System.out.println(response.request().redirectedFrom().url()); // "http://example.com" +``` + ```python async response = await page.goto("http://example.com") print(response.request.redirected_from.url) # "http://example.com" @@ -105,6 +116,11 @@ const response = await page.goto('https://google.com'); console.log(response.request().redirectedFrom()); // null ``` +```java +Response response = page.navigate("https://google.com"); +System.out.println(response.request().redirectedFrom()); // null +``` + ```python async response = await page.goto("https://google.com") print(response.request.redirected_from) # None @@ -126,6 +142,10 @@ This method is the opposite of [`method: Request.redirectedFrom`]: console.log(request.redirectedFrom().redirectedTo() === request); // true ``` +```java +System.out.println(request.redirectedFrom().redirectedTo() == request); // true +``` + ```py assert request.redirected_from.redirected_to == request ``` @@ -175,6 +195,14 @@ const [request] = await Promise.all([ console.log(request.timing()); ``` +```java +page.onRequestFinished(request -> { + Timing timing = request.timing(); + System.out.println(timing.responseEnd - timing.startTime); +}); +page.navigate("http://example.com"); +``` + ```python async async with page.expect_event("requestfinished") as request_info: await page.goto("http://example.com") diff --git a/docs/src/api/class-route.md b/docs/src/api/class-route.md index 745d8876d6a72..de9fce64f0de5 100644 --- a/docs/src/api/class-route.md +++ b/docs/src/api/class-route.md @@ -48,6 +48,16 @@ await page.route('**/*', (route, request) => { }); ``` +```java +page.route("**/*", route -> { + // Override headers + Map headers = new HashMap<>(route.request().headers()); + headers.put("foo", "bar"); // set "foo" header + headers.remove("origin"); // remove "origin" header + route.resume(new Route.ResumeOptions().setHeaders(headers)); +}); +``` + ```python async async def handle(route, request): # override headers @@ -110,6 +120,15 @@ await page.route('**/*', route => { }); ``` +```java +page.route("**/*", route -> { + route.fulfill(new Route.FulfillOptions() + .setStatus(404) + .setContentType("text/plain") + .setBody("Not Found!")); +}); +``` + ```python async await page.route("**/*", lambda route: route.fulfill( status=404, @@ -130,6 +149,11 @@ An example of serving static file: await page.route('**/xhr_endpoint', route => route.fulfill({ path: 'mock_data.json' })); ``` +```java +page.route("**/xhr_endpoint", route -> route.fulfill( + new Route.FulfillOptions().setPath(Paths.get("mock_data.json"))); +``` + ```python async await page.route("**/xhr_endpoint", lambda route: route.fulfill(path="mock_data.json")) ``` diff --git a/docs/src/api/class-selectors.md b/docs/src/api/class-selectors.md index e62cd53a84882..659e86db77cfa 100644 --- a/docs/src/api/class-selectors.md +++ b/docs/src/api/class-selectors.md @@ -1,7 +1,7 @@ # class: Selectors -Selectors can be used to install custom selector engines. See -[Working with selectors](./selectors.md) for more information. +Selectors can be used to install custom selector engines. See [Working with selectors](./selectors.md) for more +information. ## async method: Selectors.register @@ -42,6 +42,32 @@ const { selectors, firefox } = require('playwright'); // Or 'chromium' or 'webk })(); ``` +```java +// Script that evaluates to a selector engine instance. +String createTagNameEngine = "{\n" + + " // Returns the first element matching given selector in the root's subtree.\n" + + " query(root, selector) {\n" + + " return root.querySelector(selector);\n" + + " },\n" + + " // Returns all elements matching given selector in the root's subtree.\n" + + " queryAll(root, selector) {\n" + + " return Array.from(root.querySelectorAll(selector));\n" + + " }\n" + + "}"; +// Register the engine. Selectors will be prefixed with "tag=". +playwright.selectors().register("tag", createTagNameEngine); +Browser browser = playwright.firefox().launch(); +Page page = browser.newPage(); +page.setContent("
"); +// Use the selector prefixed with its name. +ElementHandle button = page.querySelector("tag=button"); +// Combine it with other selector engines. +page.click("tag=div >> text=\"Click me\""); +// Can use it in any methods supporting selectors. +int buttonCount = (int) page.evalOnSelectorAll("tag=button", "buttons => buttons.length"); +browser.close(); +``` + ```python async # FIXME: add snippet ``` @@ -76,4 +102,4 @@ Script that evaluates to a selector engine instance. Whether to run this selector engine in isolated JavaScript environment. This environment has access to the same DOM, but not any JavaScript objects from the frame's scripts. Defaults to `false`. Note that running as a content script is not -guaranteed when this engine is used together with other registered engines. +guaranteed when this engine is used together with other registered engines. \ No newline at end of file diff --git a/docs/src/api/class-video.md b/docs/src/api/class-video.md index 89465ae85dca1..275e3b1c01539 100644 --- a/docs/src/api/class-video.md +++ b/docs/src/api/class-video.md @@ -6,6 +6,10 @@ When browser context is created with the `videosPath` option, each page has a vi console.log(await page.video().path()); ``` +```java +System.out.println(page.video().path()); +``` + ```python async print(await page.video.path()) ``` @@ -18,4 +22,4 @@ print(page.video.path()) - returns: <[path]> Returns the file system path this video will be recorded to. The video is guaranteed to be written to the filesystem -upon closing the browser context. +upon closing the browser context. \ No newline at end of file diff --git a/docs/src/api/class-worker.md b/docs/src/api/class-worker.md index 4c2997aa14cef..04bf4fbb86d5f 100644 --- a/docs/src/api/class-worker.md +++ b/docs/src/api/class-worker.md @@ -15,6 +15,16 @@ for (const worker of page.workers()) console.log(' ' + worker.url()); ``` +```java +page.onWorker(worker -> { + System.out.println("Worker created: " + worker.url()); + worker.onClose(worker1 -> System.out.println("Worker destroyed: " + worker1.url())); +}); +System.out.println("Current workers:"); +for (Worker worker : page.workers()) + System.out.println(" " + worker.url()); +``` + ```py def handle_worker(worker): print("worker created: " + worker.url) diff --git a/docs/src/api/java.md b/docs/src/api/java.md index 6daa1e384b5da..fba3bccf85d8f 100644 --- a/docs/src/api/java.md +++ b/docs/src/api/java.md @@ -1,8 +1,63 @@ +## method: Page.onceDialog +* langs: java + +Adds one-off [Dialog] handler. The handler will be removed immediately after next [Dialog] is created. +```java +page.onceDialog(dialog -> { + dialog.accept("foo"); +}); + +// prints 'foo' +System.out.println(page.evaluate("prompt('Enter string:')")); + +// prints 'null' as the dialog will be auto-dismissed because there are no handlers. +System.out.println(page.evaluate("prompt('Enter string:')")); +``` + +This code above is equivalent to: +```java +Consumer handler = new Consumer() { + @Override + public void accept(Dialog dialog) { + dialog.accept("foo"); + page.offDialog(this); + } +}; +page.onDialog(handler); + +// prints 'foo' +System.out.println(page.evaluate("prompt('Enter string:')")); + +// prints 'null' as the dialog will be auto-dismissed because there are no handlers. +System.out.println(page.evaluate("prompt('Enter string:')")); +``` + +### param: Page.onceDialog.handler +- `handler` <[function]\([Dialog]\)> + +Receives the [Dialog] object, it **must** either [`method: Dialog.accept`] or [`method: Dialog.dismiss`] the dialog - otherwise +the page will [freeze](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#never_blocking) waiting for the dialog, +and actions like click will never finish. + ## method: Playwright.close * langs: java Terminates this instance of Playwright, will also close all created browsers if they are still running. +## method: Playwright.create +* langs: java +- returns: <[Playwright]> + +Launches new Playwright driver process and connects to it. [`method: Playwright.close`] should be called when the instance is no longer needed. + +```java +Playwright playwright = Playwright.create()) { +Browser browser = playwright.webkit().launch(); +Page page = browser.newPage(); +page.navigate("https://www.w3.org/"); +playwright.close(); +``` + ### param: BrowserContext.waitForPage.callback = %%-java-wait-for-event-callback-%% ### param: Frame.waitForNavigation.callback = %%-java-wait-for-event-callback-%% diff --git a/docs/src/assertions.md b/docs/src/assertions.md index b41806b350d5a..5d04de2492dd6 100644 --- a/docs/src/assertions.md +++ b/docs/src/assertions.md @@ -8,7 +8,6 @@ text content of an element. These APIs can be used in your test assertions. - ## Text content ```js @@ -16,6 +15,11 @@ const content = await page.textContent('nav:first-child'); expect(content).toBe('home'); ``` +```java +String content = page.textContent("nav:first-child"); +assertEquals("home", content); +``` + ```python async content = await page.text_content("nav:first-child") assert content == "home" @@ -37,6 +41,11 @@ const text = await page.innerText('.selected'); expect(text).toBe('value'); ``` +```java +String text = page.innerText(".selected"); +assertEquals("value", text); +``` + ```python async text = await page.inner_text(".selected") assert text == "value" @@ -58,6 +67,11 @@ const alt = await page.getAttribute('input', 'alt'); expect(alt).toBe('Text'); ``` +```java +String alt = page.getAttribute("input", "alt"); +assertEquals("Text", alt); +``` + ```python async checked = await page.get_attribute("input", "alt") assert alt == "Text" @@ -75,6 +89,11 @@ const checked = await page.isChecked('input'); expect(checked).toBeTruthy(); ``` +```java +boolean checked = page.isChecked("input"); +assertTrue(checked); +``` + ```python async checked = await page.is_checked("input") assert checked @@ -96,6 +115,11 @@ const content = await page.$eval('nav:first-child', e => e.textContent); expect(content).toBe('home'); ``` +```java +Object content = page.evalOnSelector("nav:first-child", "e => e.textContent"); +assertEquals("home", content); +``` + ```python async content = await page.eval_on_selector("nav:first-child", "e => e.textContent") assert content == "home" @@ -117,6 +141,11 @@ const html = await page.innerHTML('div.result'); expect(html).toBe('

Result

'); ``` +```java +String html = page.innerHTML("div.result"); +assertEquals("

Result

", html); +``` + ```python async html = await page.inner_html("div.result") assert html == "

Result

" @@ -138,6 +167,11 @@ const visible = await page.isVisible('input'); expect(visible).toBeTruthy(); ``` +```java +boolean visible = page.isVisible("input"); +assertTrue(visible); +``` + ```python async visible = await page.is_visible("input") assert visible @@ -156,7 +190,12 @@ assert visible ```js const enabled = await page.isEnabled('input'); -expect(visible).toBeTruthy(); +expect(enabled).toBeTruthy(); +``` + +```java +boolean enabled = page.isEnabled("input"); +assertTrue(enabled); ``` ```python async @@ -198,6 +237,25 @@ const length = await page.$$eval('li.selected', (items) => items.length); expect(length === 3).toBeTruthy(); ``` +```java +// Assert local storage value +Object userId = page.evaluate("() => window.localStorage.getItem('userId')"); +assertNotNull(userId); + +// Assert value for input element +page.waitForSelector("#search"); +Object value = page.evalOnSelector("#search", "el => el.value"); +assertEquals("query", value); + +// Assert computed style +Object fontSize = page.evalOnSelector("div", "el => window.getComputedStyle(el).fontSize"); +assertEquals("16px", fontSize); + +// Assert list length +Object length = page.evalOnSelectorAll("li.selected", "items => items.length"); +assertEquals(3, length); +``` + ```python async # Assert local storage value user_id = page.evaluate("() => window.localStorage.getItem('user_id')") @@ -245,4 +303,4 @@ assert length == 3 - [`method: Frame.evalOnSelectorAll`] - [`method: ElementHandle.evalOnSelector`] - [`method: ElementHandle.evalOnSelectorAll`] -- [EvaluationArgument] +- [EvaluationArgument] \ No newline at end of file diff --git a/docs/src/auth.md b/docs/src/auth.md index 95b689ecefa27..87651699e4331 100644 --- a/docs/src/auth.md +++ b/docs/src/auth.md @@ -36,6 +36,17 @@ await page.click('text=Submit'); // Verify app is logged in ``` +```java +Page page = context.newPage(); +page.navigate("https://github.com/login"); +// Interact with login form +page.click("text=Login"); +page.fill("input[name='login']", USERNAME); +page.fill("input[name='password']", PASSWORD); +page.click("text=Submit"); +// Verify app is logged in +``` + ```python async page = await context.new_page() await page.goto('https://github.com/login') @@ -88,6 +99,16 @@ const storageState = JSON.parse(process.env.STORAGE); const context = await browser.newContext({ storageState }); ``` +```java +// Save storage state and store as an env variable +String storage = context.storageState(); +System.getenv().put("STORAGE", storage); + +// Create a new context with the saved storage state +BrowserContext context = browser.newContext( + new Browser.NewContextOptions().setStorageState(storage)); +``` + ```python async import json import os @@ -150,6 +171,23 @@ await context.addInitScript(storage => { }, sessionStorage); ``` +```java +// Get session storage and store as env variable +String sessionStorage = (String) page.evaluate("() => JSON.stringify(sessionStorage"); +System.getenv().put("SESSION_STORAGE", sessionStorage); + +// Set session storage in a new context +String sessionStorage = System.getenv("SESSION_STORAGE"); +context.addInitScript("(storage => {\n" + + " if (window.location.hostname === 'example.com') {\n" + + " const entries = JSON.parse(storage);\n" + + " Object.keys(entries).forEach(key => {\n" + + " window.sessionStorage.setItem(key, entries[key]);\n" + + " });\n" + + " }\n" + + "})(" + sessionStorage + ")"); +``` + ```python async import os # Get session storage and store as env variable @@ -199,8 +237,6 @@ manual intervention. Persistent authentication can be used to partially automate MFA scenarios. ### Persistent authentication -Web browsers use a directory on disk to store user history, cookies, IndexedDB -and other local state. This disk location is called the [User data directory](https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md). Note that persistent authentication is not suited for CI environments since it relies on a disk location. User data directories are specific to browser types @@ -216,6 +252,22 @@ const context = await chromium.launchPersistentContext(userDataDir, { headless: // Execute login steps manually in the browser window ``` +```java +import com.microsoft.playwright.*; + +public class Example { + public static void main(String[] args) { + try (Playwright playwright = Playwright.create()) { + BrowserType chromium = playwright.chromium(); + Path userDataDir = Paths.get("/path/to/directory"); + BrowserContext context = chromium.launchPersistentContext(userDataDir, + new BrowserType.LaunchPersistentContextOptions().setHeadless(false)); + // Execute login steps manually in the browser window + } + } +} +``` + ```python async import asyncio from playwright.async_api import async_playwright @@ -246,4 +298,4 @@ with sync_playwright() as p: ### API reference - [BrowserContext] -- [`method: BrowserType.launchPersistentContext`] +- [`method: BrowserType.launchPersistentContext`] \ No newline at end of file diff --git a/docs/src/ci.md b/docs/src/ci.md index 34cbd738c028a..34a2bb9e43528 100644 --- a/docs/src/ci.md +++ b/docs/src/ci.md @@ -83,6 +83,11 @@ Suggested configuration }); ``` + ```java + Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions() + .setArgs(Arrays.asList("--disable-dev-shm-usage"))); + ``` + ```python async browser = await playwright.chromium.launch( args=['--disable-dev-shm-usage'] @@ -233,6 +238,19 @@ const { chromium } = require('playwright'); const browser = await chromium.launch({ chromiumSandbox: false }); ``` +```java +import com.microsoft.playwright.*; + +public class Example { + public static void main(String[] args) { + try (Playwright playwright = Playwright.create()) { + BrowserType chromium = playwright.chromium(); + Browser browser = chromium.launch(new BrowserType.LaunchOptions().setChromiumSandbox(false)); + } + } +} +``` + ```python async browser = await playwright.chromium.launch(chromiumSandbox=False) ``` @@ -319,6 +337,20 @@ const { chromium } = require('playwright'); const browser = await chromium.launch({ headless: false }); ``` +```java +// Works across chromium, firefox and webkit +import com.microsoft.playwright.*; + +public class Example { + public static void main(String[] args) { + try (Playwright playwright = Playwright.create()) { + BrowserType chromium = playwright.chromium(); + Browser browser = chromium.launch(new BrowserType.LaunchOptions().setHeadless(false)); + } + } +} +``` + ```python async import asyncio from playwright.async_api import async_playwright diff --git a/docs/src/cli.md b/docs/src/cli.md index 2da5c5f529670..a1471a11df497 100644 --- a/docs/src/cli.md +++ b/docs/src/cli.md @@ -91,6 +91,27 @@ const { chromium } = require('playwright'); })(); ``` +```java +// FIXME +import com.microsoft.playwright.*; + +public class Example { + public static void main(String[] args) { + try (Playwright playwright = Playwright.create()) { + BrowserType chromium = playwright.chromium(); + // Make sure to run headed. + Browser browser = chromium.launch(new BrowserType.LaunchOptions().setHeadless(false)); + // Setup context however you like. + BrowserContext context = browser.newContext(/* pass any options */); + context.route("**/*", route -> route.resume()); + // Pause the page, and start recording manually. + Page page = context.newPage(); + page.pause(); + } + } +} +``` + ```python async import asyncio from playwright.async_api import async_playwright diff --git a/docs/src/core-concepts.md b/docs/src/core-concepts.md index cd0eaff7ca744..3ecdc522c6337 100644 --- a/docs/src/core-concepts.md +++ b/docs/src/core-concepts.md @@ -29,6 +29,20 @@ const browser = await chromium.launch({ headless: false }); await browser.close(); ``` +```java +import com.microsoft.playwright.*; + +public class Example { + public static void main(String[] args) { + try (Playwright playwright = Playwright.create()) { + BrowserType chromium = playwright.chromium(); + Browser browser = chromium.launch(new BrowserType.LaunchOptions().setHeadless(false)); + browser.close(); + } + } +} +``` + ```python async import asyncio from playwright.async_api import async_playwright @@ -69,6 +83,11 @@ const browser = await chromium.launch(); const context = await browser.newContext(); ``` +```java +Browser browser = chromium.launch(); +BrowserContext context = browser.newContext(); +``` + ```python async browser = await playwright.chromium.launch() context = await browser.new_context() @@ -95,6 +114,29 @@ const context = await browser.newContext({ }); ``` +```java +// FIXME +import com.microsoft.playwright.*; + +public class Example { + public static void main(String[] args) { + try (Playwright playwright = Playwright.create()) { + BrowserType devices = playwright.devices(); + BrowserContext context = browser.newContext(new Browser.NewContextOptions() + .setUserAgent("Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Mobile/15E148 Safari/604.1") + .setViewportSize(375, 812) + .setDeviceScaleFactor(3) + .setIsMobile(true) + .setHasTouch(true) + .setPermissions(Arrays.asList("geolocation")) + .setGeolocation(52.52, 13.39) + .setColorScheme(ColorScheme.DARK) + .setLocale("de-DE")); + } + } +} +``` + ```python async import asyncio from playwright.async_api import async_playwright @@ -161,6 +203,24 @@ console.log(page.url()); window.location.href = 'https://example.com'; ``` +```java +// Create a page. +Page page = context.newPage(); + +// Navigate explicitly, similar to entering a URL in the browser. +page.navigate("http://example.com"); +// Fill an input. +page.fill("#search", "query"); + +// Navigate implicitly by clicking a link. +page.click("#submit"); +// Expect a new url. +System.out.println(page.url()); + +// Page can navigate from the script - this will be picked up by Playwright. +// window.location.href = "https://example.com"; +``` + ```python async page = await context.new_page() @@ -219,6 +279,21 @@ const frame = await frameElementHandle.contentFrame(); await frame.fill('#username-input', 'John'); ``` +```java +// Get frame using the frame"s name attribute +Frame frame = page.frame("frame-login"); + +// Get frame using frame"s URL +Frame frame = page.frameByUrl(Pattern.compile(".*domain.*")); + +// Get frame using any other selector +ElementHandle frameElementHandle = page.querySelector(".frame-class"); +Frame frame = frameElementHandle.contentFrame(); + +// Interact with the frame +frame.fill("#username-input", "John"); +``` + ```python async # Get frame using the frame's name attribute frame = page.frame('frame-login') @@ -274,6 +349,11 @@ Some examples below: await page.click('data-test-id=foo'); ``` +```java +// Using data-test-id= selector engine +page.click("data-test-id=foo"); +``` + ```python async # Using data-test-id= selector engine await page.click('data-test-id=foo') @@ -290,6 +370,12 @@ await page.click('div'); await page.click('//html/body/div'); ``` +```java +// CSS and XPath selector engines are automatically detected +page.click("div"); +page.click("//html/body/div"); +``` + ```python async # CSS and XPath selector engines are automatically detected await page.click('div') @@ -307,6 +393,11 @@ page.click('//html/body/div') await page.click('text=Hello w'); ``` +```java +// Find node by text substring +page.click("text=Hello w"); +``` + ```python async # Find node by text substring await page.click('text=Hello w') @@ -323,6 +414,12 @@ await page.click('css=div'); await page.click('xpath=//html/body/div'); ``` +```java +// Explicit CSS and XPath notation +page.click("css=div"); +page.click("xpath=//html/body/div"); +``` + ```python async # Explicit CSS and XPath notation await page.click('css=div') @@ -340,6 +437,11 @@ page.click('xpath=//html/body/div') await page.click('css:light=div'); ``` +```java +// Only search light DOM, outside WebComponent shadow DOM: +page.click("css:light=div"); +``` + ```python async # Only search light DOM, outside WebComponent shadow DOM: await page.click('css:light=div') @@ -357,6 +459,11 @@ Selectors using the same or different engines can be combined using the `>>` sep await page.click('#free-month-promo >> text=Sign Up'); ``` +```java +// Click an element with text "Sign Up" inside of a #free-month-promo. +page.click("#free-month-promo >> text=Sign Up"); +``` + ```python async # Click an element with text 'Sign Up' inside of a #free-month-promo. await page.click('#free-month-promo >> text=Sign Up') @@ -372,6 +479,11 @@ page.click('#free-month-promo >> text=Sign Up') const sectionText = await page.$eval('*css=section >> text=Selectors', e => e.textContent); ``` +```java +// Capture textContent of a section that contains an element with text "Selectors". +String sectionText = (String) page.evalOnSelector("*css=section >> text=Selectors", "e => e.textContent"); +``` + ```python async # Capture textContent of a section that contains an element with text 'Selectors'. section_text = await page.eval_on_selector('*css=section >> text=Selectors', 'e => e.textContent') @@ -401,6 +513,11 @@ and [actionable](./actionability.md). For example, click will: await page.fill('#search', 'query'); ``` +```java +// Playwright waits for #search element to be in the DOM +page.fill("#search", "query"); +``` + ```python async # Playwright waits for #search element to be in the DOM await page.fill('#search', 'query') @@ -417,6 +534,12 @@ page.fill('#search', 'query') await page.click('#search'); ``` +```java +// Playwright waits for element to stop animating +// and accept clicks. +page.click("#search"); +``` + ```python async # Playwright waits for element to stop animating # and accept clicks. @@ -438,6 +561,14 @@ await page.waitForSelector('#search', { state: 'attached' }); await page.waitForSelector('#promo'); ``` +```java +// Wait for #search to appear in the DOM. +page.waitForSelector("#search", new Page.WaitForSelectorOptions() + .setState(WaitForSelectorState.ATTACHED)); +// Wait for #promo to become visible, for example with "visibility:visible". +page.waitForSelector("#promo"); +``` + ```python async # Wait for #search to appear in the DOM. await page.wait_for_selector('#search', state='attached') @@ -461,6 +592,15 @@ await page.waitForSelector('#details', { state: 'hidden' }); await page.waitForSelector('#promo', { state: 'detached' }); ``` +```java +// Wait for #details to become hidden, for example with "display:none". +page.waitForSelector("#details", new Page.WaitForSelectorOptions() + .setState(WaitForSelectorState.HIDDEN)); +// Wait for #promo to be removed from the DOM. +page.waitForSelector("#promo", new Page.WaitForSelectorOptions() + .setState(WaitForSelectorState.DETACHED)); +``` + ```python async # Wait for #details to become hidden, for example with `display:none`. await page.wait_for_selector('#details', state='hidden') @@ -495,6 +635,10 @@ of the web page and bring results back to the Playwright environment. Browser gl const href = await page.evaluate(() => document.location.href); ``` +```java +String href = (String) page.evaluate("document.location.href"); +``` + ```python async href = await page.evaluate('() => document.location.href') ``` @@ -512,6 +656,13 @@ const status = await page.evaluate(async () => { }); ``` +```java +int status = (int) page.evaluate("async () => {\n" + + " const response = await fetch(location.href);\n" + + " return response.status;\n" + + "}"); +``` + ```python async status = await page.evaluate("""async () => { response = await fetch(location.href) @@ -573,6 +724,57 @@ await page.evaluate( { button1, list: [button2], foo: null }); ``` +```java +// A primitive value. +page.evaluate("num => num", 42); + +// An array. +page.evaluate("array => array.length", Arrays.asList(1, 2, 3)); + +// An object. +Map obj = new HashMap<>(); +obj.put("foo", "bar"); +page.evaluate("object => object.foo", obj); + +// A single handle. +ElementHandle button = page.querySelector("button"); +page.evaluate("button => button.textContent", button); + +// Alternative notation using elementHandle.evaluate. +button.evaluate("(button, from) => button.textContent.substring(from)", 5); + +// Object with multiple handles. +ElementHandle button1 = page.querySelector(".button1"); +ElementHandle button2 = page.querySelector(".button2"); +Map arg = new HashMap<>(); +arg.put("button1", button1); +arg.put("button2", button2); +page.evaluate("o => o.button1.textContent + o.button2.textContent", arg); + +// Object destructuring works. Note that property names must match +// between the destructured object and the argument. +// Also note the required parenthesis. +Map arg = new HashMap<>(); +arg.put("button1", button1); +arg.put("button2", button2); +page.evaluate("({ button1, button2 }) => button1.textContent + button2.textContent", arg); + +// Array works as well. Arbitrary names can be used for destructuring. +// Note the required parenthesis. +page.evaluate( + "([b1, b2]) => b1.textContent + b2.textContent", + Arrays.asList(button1, button2)); + +// Any non-cyclic mix of serializables and handles works. +Map arg = new HashMap<>(); +arg.put("button1", button1); +arg.put("list", Arrays.asList(button2)); +arg.put("foo", 0); +page.evaluate( + "x => x.button1.textContent + x.list[0].textContent + String(x.foo)", + arg); +``` + ```python async # A primitive value. await page.evaluate('num => num', 42) @@ -668,6 +870,16 @@ const result = await page.evaluate(data => { }, data); ``` +```java +Map data = new HashMap<>(); +data.put("text", "some data"); +data.put("value", 1); +// Pass |data| as a parameter. +Object result = page.evaluate("data => {\n" + + " window.myApp.use(data);\n" + + "}", data); +``` + ```python async data = { 'text': 'some data', 'value': 1 } # Pass |data| as a parameter. @@ -694,6 +906,16 @@ const result = await page.evaluate(() => { }); ``` +```java +Map data = new HashMap<>(); +data.put("text", "some data"); +data.put("value", 1); +Object result = page.evaluate("() => {\n" + + " // There is no |data| in the web page.\n" + + " window.myApp.use(data);\n" + + "}"); +``` + ```python async data = { 'text': 'some data', 'value': 1 } result = await page.evaluate("""() => { diff --git a/docs/src/debug.md b/docs/src/debug.md index 5a7a968234c01..2bf158b0eefcf 100644 --- a/docs/src/debug.md +++ b/docs/src/debug.md @@ -26,6 +26,12 @@ to slow down execution and follow along while debugging. await chromium.launch({ headless: false, slowMo: 100 }); // or firefox, webkit ``` +```java +chromium.launch(new BrowserType.LaunchOptions() // or firefox, webkit + .setHeadless(false) + .setSlowMo(100)); +``` + ```python async await chromium.launch(headless=False, slow_mo=100) # or firefox, webkit @@ -75,6 +81,10 @@ In Chromium, you can also open developer tools through a launch option. await chromium.launch({ devtools: true }); ``` +```java +chromium.launch(new BrowserType.LaunchOptions().setDevtools(true)); +``` + ```python async await chromium.launch(devtools=True) @@ -98,6 +108,15 @@ $ set PWDEBUG=1 $ npm run test ``` +```sh java +# Linux/macOS +$ PWDEBUG=1 mvn test + +# Windows +$ set PWDEBUG=1 +$ mvn test +``` + ```sh python # Linux/macOS $ PWDEBUG=1 pytest -s @@ -152,6 +171,15 @@ $ set DEBUG=pw:api $ npm run test ``` +```sh java +# Linux/macOS +$ DEBUG=pw:api mvn test + +# Windows +$ set DEBUG=pw:api +$ mvn test +``` + ```sh python # Linux/macOS $ DEBUG=pw:api pytest -s diff --git a/docs/src/dialogs.md b/docs/src/dialogs.md index f85924aecdaf4..1fa32b3c44c38 100644 --- a/docs/src/dialogs.md +++ b/docs/src/dialogs.md @@ -16,6 +16,11 @@ page.on('dialog', dialog => dialog.accept()); await page.click('button'); ``` +```java +page.onDialog(dialog -> dialog.accept()); +page.click("button"); +``` + ```python async page.on("dialog", lambda dialog: dialog.accept()) await page.click("button") @@ -41,6 +46,11 @@ page.on('dialog', dialog => console.log(dialog.message())); await page.click('button'); // Will hang here ``` +```java +page.onDialog(dialog -> System.out.println(dialog.message())); +page.click("button"); // Will hang here +``` + ```python async page.on("dialog", lambda dialog: print(dialog.message)) await page.click("button") # Will hang here @@ -75,6 +85,14 @@ page.on('dialog', async dialog => { await page.close({runBeforeUnload: true}); ``` +```java +page.onDialog(dialog -> { + assertEquals("beforeunload", dialog.type()); + dialog.dismiss(); +}); +page.close(new Page.CloseOptions().setRunBeforeUnload(true)); +``` + ```python async async def handle_dialog(dialog): assert dialog.type == 'beforeunload' diff --git a/docs/src/downloads.md b/docs/src/downloads.md index 01bfe065f03ce..6bc2305bc1776 100644 --- a/docs/src/downloads.md +++ b/docs/src/downloads.md @@ -58,6 +58,10 @@ If you have no idea what initiates the download, you can still handle the event: page.on('download', download => download.path().then(console.log)); ``` +```java +page.onDownload(download -> System.out.println(download.path())); +``` + ```python async async def handle_download(download): print(await download.path()) diff --git a/docs/src/emulation.md b/docs/src/emulation.md index 18cc93756c036..909b41c568cbd 100644 --- a/docs/src/emulation.md +++ b/docs/src/emulation.md @@ -80,6 +80,11 @@ const context = await browser.newContext({ }); ``` +```java +BrowserContext context = browser.newContext(new Browser.NewContextOptions() + .setUserAgent("My user agent")); +``` + ```python async context = await browser.new_context( user_agent='My user agent' @@ -117,6 +122,20 @@ const context = await browser.newContext({ }); ``` +```java +// Create context with given viewport +BrowserContext context = browser.newContext(new Browser.NewContextOptions() + .setViewportSize(1280, 1024)); + +// Resize viewport for individual page +page.setViewportSize(1600, 1200); + +// Emulate high-DPI +BrowserContext context = browser.newContext(new Browser.NewContextOptions() + .setViewportSize(2560, 1440) + .setDeviceScaleFactor(2); +``` + ```python async # Create context with given viewport context = await browser.new_context( @@ -164,6 +183,13 @@ const context = await browser.newContext({ }); ``` +```java +// Emulate locale and time +BrowserContext context = browser.newContext(new Browser.NewContextOptions() + .setLocale("de-DE") + .setTimezoneId("Europe/Berlin")); +``` + ```python async # Emulate locale and time context = await browser.new_context( @@ -195,6 +221,11 @@ const context = await browser.newContext({ }); ``` +```java +BrowserContext context = browser.newContext(new Browser.NewContextOptions() + .setPermissions(Arrays.asList("notifications")); +``` + ```python async context = await browser.new_context( permissions=['notifications'], @@ -213,6 +244,10 @@ Grant all pages in the existing context access to current location: await context.grantPermissions(['geolocation']); ``` +```java +context.grantPermissions(Arrays.asList("geolocation")); +``` + ```python async await context.grant_permissions(['geolocation']) ``` @@ -227,6 +262,11 @@ Grant notifications access from a specific domain: await context.grantPermissions(['notifications'], {origin: 'https://skype.com'} ); ``` +```java +context.grantPermissions(Arrays.asList("notifications"), + new BrowserContext.GrantPermissionsOptions().setOrigin("https://skype.com")); +``` + ```python async await context.grant_permissions(['notifications'], origin='https://skype.com') ``` @@ -241,6 +281,10 @@ Revoke all permissions: await context.clearPermissions(); ``` +```java +context.clearPermissions(); +``` + ```python async await context.clear_permissions() ``` @@ -267,6 +311,12 @@ const context = await browser.newContext({ }); ``` +```java +BrowserContext context = browser.newContext(new Browser.NewContextOptions() + .setGeolocation(48.858455, 2.294474) + .setPermissions(Arrays.asList("geolocation"))); +``` + ```python async context = await browser.new_context( geolocation={"longitude": 48.858455, "latitude": 2.294474}, @@ -287,6 +337,10 @@ Change the location later: await context.setGeolocation({ longitude: 29.979097, latitude: 31.134256 }); ``` +```java +context.setGeolocation(new Geolocation(29.979097, 31.134256)); +``` + ```python async await context.set_geolocation({"longitude": 29.979097, "latitude": 31.134256}) ``` @@ -325,6 +379,22 @@ await page.emulateMedia({ colorScheme: 'dark' }); await page.emulateMedia({ media: 'print' }); ``` +```java +// Create context with dark mode +BrowserContext context = browser.newContext(new Browser.NewContextOptions() + .setColorScheme(ColorScheme.DARK)); // or "light" + +// Create page with dark mode +Page page = browser.newPage(new Browser.NewPageOptions() + .setColorScheme(ColorScheme.DARK)); // or "light" + +// Change color scheme for the page +page.emulateMedia(new Page.EmulateMediaOptions().setColorScheme(ColorScheme.DARK)); + +// Change media for page +page.emulateMedia(new Page.EmulateMediaOptions().setMedia(Media.PRINT)); +``` + ```python async # Create context with dark mode context = await browser.new_context( diff --git a/docs/src/extensibility.md b/docs/src/extensibility.md index 1963d17ed6f10..21510b50d3604 100644 --- a/docs/src/extensibility.md +++ b/docs/src/extensibility.md @@ -51,6 +51,33 @@ await page.click('tag=div >> span >> "Click me"'); const buttonCount = await page.$$eval('tag=button', buttons => buttons.length); ``` +```java +// Must be a script that evaluates to a selector engine instance. +String createTagNameEngine = "{\n" + + " // Returns the first element matching given selector in the root's subtree.\n" + + " query(root, selector) {\n" + + " return root.querySelector(selector);\n" + + " },\n" + + "\n" + + " // Returns all elements matching given selector in the root's subtree.\n" + + " queryAll(root, selector) {\n" + + " return Array.from(root.querySelectorAll(selector));\n" + + " }\n" + + "}"; + +// Register the engine. Selectors will be prefixed with "tag=". +playwright.selectors().register("tag", createTagNameEngine); + +// Now we can use "tag=" selectors. +ElementHandle button = page.querySelector("tag=button"); + +// We can combine it with other selector engines using ">>" combinator. +page.click("tag=div >> span >> \"Click me\""); + +// We can use it in any methods supporting selectors. +int buttonCount = (int) page.evalOnSelectorAll("tag=button", "buttons => buttons.length"); +``` + ```python async tag_selector = """ // Must evaluate to a selector engine instance. diff --git a/docs/src/handles.md b/docs/src/handles.md index 20532f2b2f097..c937e4ad866b0 100644 --- a/docs/src/handles.md +++ b/docs/src/handles.md @@ -28,6 +28,11 @@ const jsHandle = await page.evaluateHandle('window'); // Use jsHandle for evaluations. ``` +```java +JSHandle jsHandle = page.evaluateHandle("window"); +// Use jsHandle for evaluations. +``` + ```python async js_handle = await page.evaluate_handle('window') # Use jsHandle for evaluations. @@ -43,6 +48,11 @@ const ulElementHandle = await page.waitForSelector('ul'); // Use ulElementHandle for actions and evaluation. ``` +```java +ElementHandle ulElementHandle = page.waitForSelector("ul"); +// Use ulElementHandle for actions and evaluation. +``` + ```python async ul_element_handle = await page.wait_for_selector('ul') # Use ul_element_handle for actions and evaluation. @@ -76,6 +86,20 @@ const classNames = await elementHandle.getAttribute('class'); expect(classNames.includes('highlighted')).toBeTruthy(); ``` +```java +// Get the element handle +JSHandle jsHandle = page.waitForSelector("#box"); +ElementHandle elementHandle = jsHandle.asElement(); + +// Assert bounding box for the element +BoundingBox boundingBox = elementHandle.boundingBox(); +assertEquals(100, boundingBox.width); + +// Assert attribute for the element +String classNames = elementHandle.getAttribute("class"); +assertTrue(classNames.contains("highlighted")); +``` + ```python async # Get the element handle element_handle = page.wait_for_selector('#box') @@ -129,6 +153,26 @@ await page.evaluate(arg => arg.myArray.push(arg.newElement), { await myArrayHandle.dispose(); ``` +```java +// Create new array in page. +JSHandle myArrayHandle = page.evaluateHandle("() => {\n" + + " window.myArray = [1];\n" + + " return myArray;\n" + + "}"); + +// Get the length of the array. +int length = (int) page.evaluate("a => a.length", myArrayHandle); + +// Add one more element to the array using the handle +Map arg = new HashMap<>(); +arg.put("myArray", myArrayHandle); +arg.put("newElement", 2); +page.evaluate("arg => arg.myArray.add(arg.newElement)", arg); + +// Release the object when it"s no longer needed. +myArrayHandle.dispose(); +``` + ```python async # Create new array in page. my_array_handle = await page.evaluate_handle("""() => { diff --git a/docs/src/input.md b/docs/src/input.md index 3780df181cc44..1527c0ba7b270 100644 --- a/docs/src/input.md +++ b/docs/src/input.md @@ -26,6 +26,23 @@ await page.fill('#local', '2020-03-02T05:15'); await page.fill('text=First Name', 'Peter'); ``` +```java +// Text input +page.fill("#name", "Peter"); + +// Date input +page.fill("#date", "2020-02-02"); + +// Time input +page.fill("#time", "13-15"); + +// Local datetime input +page.fill("#local", "2020-03-02T05:15"); + +// Input through label +page.fill("text=First Name", "Peter"); +``` + ```python async # Text input await page.fill('#name', 'Peter') @@ -86,6 +103,20 @@ await page.uncheck('#subscribe-label'); await page.check('text=XL'); ``` +```java +// Check the checkbox +page.check("#agree"); + +// Assert the checked state +assertTrue(page.isChecked("#agree")); + +// Uncheck by input