diff --git a/.github/workflows/verify_api.yml b/.github/workflows/verify_api.yml new file mode 100644 index 00000000..22414c9e --- /dev/null +++ b/.github/workflows/verify_api.yml @@ -0,0 +1,43 @@ +name: Verify API +on: + push: + branches: [ master ] + paths: + - 'scripts/*' + - 'api-generator/*' + pull_request: + branches: [ master ] + paths: + - 'scripts/**' + - 'api-generator/**' +jobs: + verify: + timeout-minutes: 30 + strategy: + fail-fast: true + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Cache Maven packages + uses: actions/cache@v2 + with: + path: ~/.m2 + key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} + restore-keys: ${{ runner.os }}-m2 + - name: Cache Downloaded Drivers + uses: actions/cache@v2 + with: + path: driver-bundle/src/main/resources/driver + key: ${{ runner.os }}-drivers-${{ hashFiles('scripts/*') }} + restore-keys: ${{ runner.os }}-drivers + - name: Download drivers + run: scripts/download_driver_for_all_platforms.sh + - name: Regenerate APIs + run: scripts/generate_api.sh + - name: Verify API is up to date + run: | + if [[ -n $(git status -s) ]]; then + echo "ERROR: generated interfaces differ from the current sources:" + git diff + exit 1 + fi diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7126b13b..ee555d14 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,7 +28,13 @@ mvn test ### Generating API -Public Java API is generated from [api.json](https://github.com/microsoft/playwright-java/blob/master/api-generator/src/main/resources/api.json) which in turn is created by `playwright-cli print-api-json`. +Public Java API is generated from api.json which is produced by `playwright-cli print-api-json`. To regenerate +Java interfaces for the current driver run the following commands: + +```bash +./scripts/download_driver_for_all_platforms.sh +./scripts/generate_api.sh +``` ### Code Style diff --git a/api-generator/src/main/resources/.gitignore b/api-generator/src/main/resources/.gitignore new file mode 100644 index 00000000..1a11577d --- /dev/null +++ b/api-generator/src/main/resources/.gitignore @@ -0,0 +1 @@ +api.json diff --git a/api-generator/src/main/resources/api.json b/api-generator/src/main/resources/api.json deleted file mode 100644 index 52d42d64..00000000 --- a/api-generator/src/main/resources/api.json +++ /dev/null @@ -1 +0,0 @@ -{"Browser":{"name":"Browser","extends":"EventEmitter","comment":"A Browser is created when Playwright connects to a browser instance, either through browserType.launch([options]) or\nbrowserType.connect(params).\nAn example of using a Browser to create a Page:\n```js\nconst { firefox } = require('playwright'); // Or 'chromium' or 'webkit'.\n\n(async () => {\n const browser = await firefox.launch();\n const page = await browser.newPage();\n await page.goto('https://example.com');\n await browser.close();\n})();\n```\nSee ChromiumBrowser, FirefoxBrowser and WebKitBrowser for browser-specific features. Note that\nbrowserType.connect(params) and browserType.launch([options]) always return a specific browser instance, based on the browser\nbeing connected to or launched.","methods":{"close":{"name":"close","type":{"name":"Promise"},"comment":"In case this browser is obtained using browserType.launch([options]), closes the browser and all of its pages (if any were\nopened).\nIn case this browser is obtained using browserType.connect(params), clears all created contexts belonging to this browser\nand disconnects from the browser server.\nThe Browser object itself is considered to be disposed and cannot be used anymore.","required":true,"args":{}},"contexts":{"name":"contexts","type":{"name":"Array"},"comment":"Returns an array of all open browser contexts. In a newly created browser, this will return zero browser contexts.\n```js\nconst browser = await pw.webkit.launch();\nconsole.log(browser.contexts().length); // prints `0`\n\nconst context = await browser.newContext();\nconsole.log(browser.contexts().length); // prints `1`\n```","required":true,"args":{}},"isConnected":{"name":"isConnected","type":{"name":"boolean"},"comment":"Indicates that the browser is connected.","required":true,"args":{}},"newContext":{"name":"newContext","type":{"name":"Promise"},"comment":"Creates a new browser context. It won't share cookies/cache with other browser contexts.\n```js\n(async () => {\n const browser = await playwright.firefox.launch(); // Or 'chromium' or 'webkit'.\n // Create a new incognito browser context.\n const context = await browser.newContext();\n // Create a new page in a pristine context.\n const page = await context.newPage();\n await page.goto('https://example.com');\n})();\n```","required":true,"args":{"options":{"name":"options","type":{"name":"Object","properties":{"acceptDownloads":{"name":"acceptDownloads","type":{"name":"boolean"},"comment":"Whether to automatically download all the attachments. Defaults to `false` where all the downloads are canceled.","required":false},"ignoreHTTPSErrors":{"name":"ignoreHTTPSErrors","type":{"name":"boolean"},"comment":"Whether to ignore HTTPS errors during navigation. Defaults to `false`.","required":false},"bypassCSP":{"name":"bypassCSP","type":{"name":"boolean"},"comment":"Toggles bypassing page's Content-Security-Policy.","required":false},"viewport":{"name":"viewport","type":{"name":"null|Object","properties":{"width":{"name":"width","type":{"name":"number"},"comment":"page width in pixels.","required":true},"height":{"name":"height","type":{"name":"number"},"comment":"page height in pixels.","required":true}}},"comment":"Sets a consistent viewport for each page. Defaults to an 1280x720 viewport. `null` disables the default viewport.","required":false},"userAgent":{"name":"userAgent","type":{"name":"string"},"comment":"Specific user agent to use in this context.","required":false},"deviceScaleFactor":{"name":"deviceScaleFactor","type":{"name":"number"},"comment":"Specify device scale factor (can be thought of as dpr). Defaults to `1`.","required":false},"isMobile":{"name":"isMobile","type":{"name":"boolean"},"comment":"Whether the `meta viewport` tag is taken into account and touch events are enabled. Defaults to `false`. Not supported in Firefox.","required":false},"hasTouch":{"name":"hasTouch","type":{"name":"boolean"},"comment":"Specifies if viewport supports touch events. Defaults to false.","required":false},"javaScriptEnabled":{"name":"javaScriptEnabled","type":{"name":"boolean"},"comment":"Whether or not to enable JavaScript in the context. Defaults to `true`.","required":false},"timezoneId":{"name":"timezoneId","type":{"name":"string"},"comment":"Changes the timezone of the context. See ICU’s `metaZones.txt` for a list of supported timezone IDs.","required":false},"geolocation":{"name":"geolocation","type":{"name":"Object","properties":{"latitude":{"name":"latitude","type":{"name":"number"},"comment":"Latitude between -90 and 90.","required":true},"longitude":{"name":"longitude","type":{"name":"number"},"comment":"Longitude between -180 and 180.","required":true},"accuracy":{"name":"accuracy","type":{"name":"number"},"comment":"Non-negative accuracy value. Defaults to `0`.","required":false}}},"required":false},"locale":{"name":"locale","type":{"name":"string"},"comment":"Specify user locale, for example `en-GB`, `de-DE`, etc. Locale will affect `navigator.language` value, `Accept-Language` request header value as well as number and date formatting rules.","required":false},"permissions":{"name":"permissions","type":{"name":"Array"},"comment":"A list of permissions to grant to all pages in this context. See browserContext.grantPermissions(permissions[, options]) for more details.","required":false},"extraHTTPHeaders":{"name":"extraHTTPHeaders","type":{"name":"Object"},"comment":"An object containing additional HTTP headers to be sent with every request. All header values must be strings.","required":false},"offline":{"name":"offline","type":{"name":"boolean"},"comment":"Whether to emulate network being offline. Defaults to `false`.","required":false},"httpCredentials":{"name":"httpCredentials","type":{"name":"Object","properties":{"username":{"name":"username","type":{"name":"string"},"required":true},"password":{"name":"password","type":{"name":"string"},"required":true}}},"comment":"Credentials for HTTP authentication.","required":false},"colorScheme":{"name":"colorScheme","type":{"name":"\"dark\"|\"light\"|\"no-preference\""},"comment":"Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See page.emulateMedia(params) for more details. Defaults to '`light`'.","required":false},"logger":{"name":"logger","type":{"name":"Logger"},"comment":"Logger sink for Playwright logging.","required":false},"videosPath":{"name":"videosPath","type":{"name":"string"},"comment":"**NOTE** Use `recordVideo` instead, it takes precedence over `videosPath`. Enables video recording for all pages to `videosPath` directory. If not specified, videos are not recorded. Make sure to await browserContext.close() for videos to be saved.","required":false},"videoSize":{"name":"videoSize","type":{"name":"Object","properties":{"width":{"name":"width","type":{"name":"number"},"comment":"Video frame width.","required":true},"height":{"name":"height","type":{"name":"number"},"comment":"Video frame height.","required":true}}},"comment":"**NOTE** Use `recordVideo` instead, it takes precedence over `videoSize`. Specifies dimensions of the automatically recorded video. Can only be used if `videosPath` is set. If not specified the size will be equal to `viewport`. If `viewport` is not configured explicitly the video size defaults to 1280x720. Actual picture of the page will be scaled down if necessary to fit specified size.","required":false},"recordHar":{"name":"recordHar","type":{"name":"Object","properties":{"omitContent":{"name":"omitContent","type":{"name":"boolean"},"comment":"Optional setting to control whether to omit request content from the HAR. Defaults to `false`.","required":false},"path":{"name":"path","type":{"name":"string"},"comment":"Path on the filesystem to write the HAR file to.","required":true}}},"comment":"Enables HAR recording for all pages into `recordHar.path` file. If not specified, the HAR is not recorded. Make sure to await browserContext.close() for the HAR to be saved.","required":false},"recordVideo":{"name":"recordVideo","type":{"name":"Object","properties":{"dir":{"name":"dir","type":{"name":"string"},"comment":"Path to the directory to put videos into.","required":true},"size":{"name":"size","type":{"name":"Object","properties":{"width":{"name":"width","type":{"name":"number"},"comment":"Video frame width.","required":true},"height":{"name":"height","type":{"name":"number"},"comment":"Video frame height.","required":true}}},"comment":"Optional dimensions of the recorded videos. If not specified the size will be equal to `viewport`. If `viewport` is not configured explicitly the video size defaults to 1280x720. Actual picture of each page will be scaled down if necessary to fit the specified size.","required":false}}},"comment":"Enables video recording for all pages into `recordVideo.dir` directory. If not specified videos are not recorded. Make sure to await browserContext.close() for videos to be saved.","required":false},"proxy":{"name":"proxy","type":{"name":"Object","properties":{"server":{"name":"server","type":{"name":"string"},"comment":"Proxy to be used for all requests. HTTP and SOCKS proxies are supported, for example `http://myproxy.com:3128` or `socks5://myproxy.com:3128`. Short form `myproxy.com:3128` is considered an HTTP proxy.","required":true},"bypass":{"name":"bypass","type":{"name":"string"},"comment":"Optional coma-separated domains to bypass proxy, for example `\".com, chromium.org, .domain.com\"`.","required":false},"username":{"name":"username","type":{"name":"string"},"comment":"Optional username to use if HTTP proxy requires authentication.","required":false},"password":{"name":"password","type":{"name":"string"},"comment":"Optional password to use if HTTP proxy requires authentication.","required":false}}},"comment":"Network proxy settings to use with this context. Note that browser needs to be launched with the global proxy for this option to work. If all contexts override the proxy, global proxy will be never used and can be any string, for example `launch({ proxy: { server: 'per-context' } })`.","required":false},"storageState":{"name":"storageState","type":{"name":"Object","properties":{"cookies":{"name":"cookies","type":{"name":"Array","properties":{"name":{"name":"name","type":{"name":"string"},"comment":"**required**","required":true},"value":{"name":"value","type":{"name":"string"},"comment":"**required**","required":true},"url":{"name":"url","type":{"name":"string"},"comment":"Optional either url or domain / path are required","required":false},"domain":{"name":"domain","type":{"name":"string"},"comment":"Optional either url or domain / path are required","required":false},"path":{"name":"path","type":{"name":"string"},"comment":"Optional either url or domain / path are required","required":false},"expires":{"name":"expires","type":{"name":"number"},"comment":"Optional Unix time in seconds.","required":false},"httpOnly":{"name":"httpOnly","type":{"name":"boolean"},"comment":"Optional httpOnly flag","required":false},"secure":{"name":"secure","type":{"name":"boolean"},"comment":"Optional secure flag","required":false},"sameSite":{"name":"sameSite","type":{"name":"\"Lax\"|\"None\"|\"Strict\""},"comment":"Optional sameSite flag","required":false}}},"comment":"Optional cookies to set for context","required":false},"origins":{"name":"origins","type":{"name":"Array","properties":{"origin":{"name":"origin","type":{"name":"string"},"required":true},"localStorage":{"name":"localStorage","type":{"name":"Array","properties":{"name":{"name":"name","type":{"name":"string"},"required":true},"value":{"name":"value","type":{"name":"string"},"required":true}}},"required":true}}},"comment":"Optional localStorage to set for context","required":false}}},"comment":"Populates context with given storage state. This method can be used to initialize context with logged-in information obtained via browserContext.storageState().","required":false}}},"required":false}}},"newPage":{"name":"newPage","type":{"name":"Promise"},"comment":"Creates a new page in a new browser context. Closing this page will close the context as well.\nThis is a convenience API that should only be used for the single-page scenarios and short snippets. Production code and\ntesting frameworks should explicitly create browser.newContext([options]) followed by the browserContext.newPage() to\ncontrol their exact life times.","required":true,"args":{"options":{"name":"options","type":{"name":"Object","properties":{"acceptDownloads":{"name":"acceptDownloads","type":{"name":"boolean"},"comment":"Whether to automatically download all the attachments. Defaults to `false` where all the downloads are canceled.","required":false},"ignoreHTTPSErrors":{"name":"ignoreHTTPSErrors","type":{"name":"boolean"},"comment":"Whether to ignore HTTPS errors during navigation. Defaults to `false`.","required":false},"bypassCSP":{"name":"bypassCSP","type":{"name":"boolean"},"comment":"Toggles bypassing page's Content-Security-Policy.","required":false},"viewport":{"name":"viewport","type":{"name":"null|Object","properties":{"width":{"name":"width","type":{"name":"number"},"comment":"page width in pixels.","required":true},"height":{"name":"height","type":{"name":"number"},"comment":"page height in pixels.","required":true}}},"comment":"Sets a consistent viewport for each page. Defaults to an 1280x720 viewport. `null` disables the default viewport.","required":false},"userAgent":{"name":"userAgent","type":{"name":"string"},"comment":"Specific user agent to use in this context.","required":false},"deviceScaleFactor":{"name":"deviceScaleFactor","type":{"name":"number"},"comment":"Specify device scale factor (can be thought of as dpr). Defaults to `1`.","required":false},"isMobile":{"name":"isMobile","type":{"name":"boolean"},"comment":"Whether the `meta viewport` tag is taken into account and touch events are enabled. Defaults to `false`. Not supported in Firefox.","required":false},"hasTouch":{"name":"hasTouch","type":{"name":"boolean"},"comment":"Specifies if viewport supports touch events. Defaults to false.","required":false},"javaScriptEnabled":{"name":"javaScriptEnabled","type":{"name":"boolean"},"comment":"Whether or not to enable JavaScript in the context. Defaults to `true`.","required":false},"timezoneId":{"name":"timezoneId","type":{"name":"string"},"comment":"Changes the timezone of the context. See ICU’s `metaZones.txt` for a list of supported timezone IDs.","required":false},"geolocation":{"name":"geolocation","type":{"name":"Object","properties":{"latitude":{"name":"latitude","type":{"name":"number"},"comment":"Latitude between -90 and 90.","required":true},"longitude":{"name":"longitude","type":{"name":"number"},"comment":"Longitude between -180 and 180.","required":true},"accuracy":{"name":"accuracy","type":{"name":"number"},"comment":"Non-negative accuracy value. Defaults to `0`.","required":false}}},"required":false},"locale":{"name":"locale","type":{"name":"string"},"comment":"Specify user locale, for example `en-GB`, `de-DE`, etc. Locale will affect `navigator.language` value, `Accept-Language` request header value as well as number and date formatting rules.","required":false},"permissions":{"name":"permissions","type":{"name":"Array"},"comment":"A list of permissions to grant to all pages in this context. See browserContext.grantPermissions(permissions[, options]) for more details.","required":false},"extraHTTPHeaders":{"name":"extraHTTPHeaders","type":{"name":"Object"},"comment":"An object containing additional HTTP headers to be sent with every request. All header values must be strings.","required":false},"offline":{"name":"offline","type":{"name":"boolean"},"comment":"Whether to emulate network being offline. Defaults to `false`.","required":false},"httpCredentials":{"name":"httpCredentials","type":{"name":"Object","properties":{"username":{"name":"username","type":{"name":"string"},"required":true},"password":{"name":"password","type":{"name":"string"},"required":true}}},"comment":"Credentials for HTTP authentication.","required":false},"colorScheme":{"name":"colorScheme","type":{"name":"\"dark\"|\"light\"|\"no-preference\""},"comment":"Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See page.emulateMedia(params) for more details. Defaults to '`light`'.","required":false},"logger":{"name":"logger","type":{"name":"Logger"},"comment":"Logger sink for Playwright logging.","required":false},"videosPath":{"name":"videosPath","type":{"name":"string"},"comment":"**NOTE** Use `recordVideo` instead, it takes precedence over `videosPath`. Enables video recording for all pages to `videosPath` directory. If not specified, videos are not recorded. Make sure to await browserContext.close() for videos to be saved.","required":false},"videoSize":{"name":"videoSize","type":{"name":"Object","properties":{"width":{"name":"width","type":{"name":"number"},"comment":"Video frame width.","required":true},"height":{"name":"height","type":{"name":"number"},"comment":"Video frame height.","required":true}}},"comment":"**NOTE** Use `recordVideo` instead, it takes precedence over `videoSize`. Specifies dimensions of the automatically recorded video. Can only be used if `videosPath` is set. If not specified the size will be equal to `viewport`. If `viewport` is not configured explicitly the video size defaults to 1280x720. Actual picture of the page will be scaled down if necessary to fit specified size.","required":false},"recordHar":{"name":"recordHar","type":{"name":"Object","properties":{"omitContent":{"name":"omitContent","type":{"name":"boolean"},"comment":"Optional setting to control whether to omit request content from the HAR. Defaults to `false`.","required":false},"path":{"name":"path","type":{"name":"string"},"comment":"Path on the filesystem to write the HAR file to.","required":true}}},"comment":"Enables HAR recording for all pages into `recordHar.path` file. If not specified, the HAR is not recorded. Make sure to await browserContext.close() for the HAR to be saved.","required":false},"recordVideo":{"name":"recordVideo","type":{"name":"Object","properties":{"dir":{"name":"dir","type":{"name":"string"},"comment":"Path to the directory to put videos into.","required":true},"size":{"name":"size","type":{"name":"Object","properties":{"width":{"name":"width","type":{"name":"number"},"comment":"Video frame width.","required":true},"height":{"name":"height","type":{"name":"number"},"comment":"Video frame height.","required":true}}},"comment":"Optional dimensions of the recorded videos. If not specified the size will be equal to `viewport`. If `viewport` is not configured explicitly the video size defaults to 1280x720. Actual picture of each page will be scaled down if necessary to fit the specified size.","required":false}}},"comment":"Enables video recording for all pages into `recordVideo.dir` directory. If not specified videos are not recorded. Make sure to await browserContext.close() for videos to be saved.","required":false},"proxy":{"name":"proxy","type":{"name":"Object","properties":{"server":{"name":"server","type":{"name":"string"},"comment":"Proxy to be used for all requests. HTTP and SOCKS proxies are supported, for example `http://myproxy.com:3128` or `socks5://myproxy.com:3128`. Short form `myproxy.com:3128` is considered an HTTP proxy.","required":true},"bypass":{"name":"bypass","type":{"name":"string"},"comment":"Optional coma-separated domains to bypass proxy, for example `\".com, chromium.org, .domain.com\"`.","required":false},"username":{"name":"username","type":{"name":"string"},"comment":"Optional username to use if HTTP proxy requires authentication.","required":false},"password":{"name":"password","type":{"name":"string"},"comment":"Optional password to use if HTTP proxy requires authentication.","required":false}}},"comment":"Network proxy settings to use with this context. Note that browser needs to be launched with the global proxy for this option to work. If all contexts override the proxy, global proxy will be never used and can be any string, for example `launch({ proxy: { server: 'per-context' } })`.","required":false},"storageState":{"name":"storageState","type":{"name":"Object","properties":{"cookies":{"name":"cookies","type":{"name":"Array","properties":{"name":{"name":"name","type":{"name":"string"},"comment":"**required**","required":true},"value":{"name":"value","type":{"name":"string"},"comment":"**required**","required":true},"url":{"name":"url","type":{"name":"string"},"comment":"Optional either url or domain / path are required","required":false},"domain":{"name":"domain","type":{"name":"string"},"comment":"Optional either url or domain / path are required","required":false},"path":{"name":"path","type":{"name":"string"},"comment":"Optional either url or domain / path are required","required":false},"expires":{"name":"expires","type":{"name":"number"},"comment":"Optional Unix time in seconds.","required":false},"httpOnly":{"name":"httpOnly","type":{"name":"boolean"},"comment":"Optional httpOnly flag","required":false},"secure":{"name":"secure","type":{"name":"boolean"},"comment":"Optional secure flag","required":false},"sameSite":{"name":"sameSite","type":{"name":"\"Lax\"|\"None\"|\"Strict\""},"comment":"Optional sameSite flag","required":false}}},"comment":"Optional cookies to set for context","required":false},"origins":{"name":"origins","type":{"name":"Array","properties":{"origin":{"name":"origin","type":{"name":"string"},"required":true},"localStorage":{"name":"localStorage","type":{"name":"Array","properties":{"name":{"name":"name","type":{"name":"string"},"required":true},"value":{"name":"value","type":{"name":"string"},"required":true}}},"required":true}}},"comment":"Optional localStorage to set for context","required":false}}},"comment":"Populates context with given storage state. This method can be used to initialize context with logged-in information obtained via browserContext.storageState().","required":false}}},"required":false}}},"version":{"name":"version","type":{"name":"string"},"comment":"Returns the browser version.","required":true,"args":{}}},"events":{"disconnected":{"name":"disconnected","type":null,"required":true,"args":{}}},"properties":{}},"BrowserContext":{"name":"BrowserContext","extends":"EventEmitter","comment":"BrowserContexts provide a way to operate multiple independent browser sessions.\nIf a page opens another page, e.g. with a `window.open` call, the popup will belong to the parent page's browser\ncontext.\nPlaywright allows creation of \"incognito\" browser contexts with `browser.newContext()` method. \"Incognito\" browser\ncontexts don't write any browsing data to disk.\n```js\n// Create a new incognito browser context\nconst context = await browser.newContext();\n// Create a new page inside context.\nconst page = await context.newPage();\nawait page.goto('https://example.com');\n// Dispose context once it's no longer needed.\nawait context.close();\n```","methods":{"addCookies":{"name":"addCookies","type":{"name":"Promise"},"comment":"Adds cookies into this browser context. All pages within this context will have these cookies installed. Cookies can be\nobtained via browserContext.cookies([urls]).\n```js\nawait browserContext.addCookies([cookieObject1, cookieObject2]);\n```","required":true,"args":{"cookies":{"name":"cookies","type":{"name":"Array","properties":{"name":{"name":"name","type":{"name":"string"},"comment":"**required**","required":true},"value":{"name":"value","type":{"name":"string"},"comment":"**required**","required":true},"url":{"name":"url","type":{"name":"string"},"comment":"either url or domain / path are required","required":false},"domain":{"name":"domain","type":{"name":"string"},"comment":"either url or domain / path are required","required":false},"path":{"name":"path","type":{"name":"string"},"comment":"either url or domain / path are required","required":false},"expires":{"name":"expires","type":{"name":"number"},"comment":"Unix time in seconds.","required":false},"httpOnly":{"name":"httpOnly","type":{"name":"boolean"},"required":false},"secure":{"name":"secure","type":{"name":"boolean"},"required":false},"sameSite":{"name":"sameSite","type":{"name":"\"Lax\"|\"None\"|\"Strict\""},"required":false}}},"required":true}}},"addInitScript":{"name":"addInitScript","type":{"name":"Promise"},"comment":"Adds a script which would be evaluated in one of the following scenarios:\n\nWhenever a page is created in the browser context or is navigated.\nWhenever a child frame is attached or navigated in any page in the browser context. In this case, the script is evaluated in the context of the newly attached frame.\n\nThe script is evaluated after the document was created but before any of its scripts were run. This is useful to amend\nthe JavaScript environment, e.g. to seed `Math.random`.\nAn example of overriding `Math.random` before the page loads:\n```js\n// preload.js\nMath.random = () => 42;\n```\n```js\n// In your playwright script, assuming the preload.js file is in same directory.\nawait browserContext.addInitScript({\n path: 'preload.js'\n});\n```\n\n**NOTE** The order of evaluation of multiple scripts installed via browserContext.addInitScript(script[, arg]) and\npage.addInitScript(script[, arg]) is not defined.","required":true,"args":{"script":{"name":"script","type":{"name":"function|string|Object","properties":{"path":{"name":"path","type":{"name":"string"},"comment":"Path to the JavaScript file. If `path` is a relative path, then it is resolved relative to current working directory.","required":false},"content":{"name":"content","type":{"name":"string"},"comment":"Raw script content.","required":false}}},"comment":"Script to be evaluated in all pages in the browser context.","required":true},"arg":{"name":"arg","type":{"name":"Serializable"},"comment":"Optional argument to pass to `script` (only supported when passing a function).","required":false}}},"browser":{"name":"browser","type":{"name":"null|Browser"},"comment":"Returns the browser instance of the context. If it was launched as a persistent context null gets returned.","required":true,"args":{}},"clearCookies":{"name":"clearCookies","type":{"name":"Promise"},"comment":"Clears context cookies.","required":true,"args":{}},"clearPermissions":{"name":"clearPermissions","type":{"name":"Promise"},"comment":"Clears all permission overrides for the browser context.\n```js\nconst context = await browser.newContext();\nawait context.grantPermissions(['clipboard-read']);\n// do stuff ..\ncontext.clearPermissions();\n```","required":true,"args":{}},"close":{"name":"close","type":{"name":"Promise"},"comment":"Closes the browser context. All the pages that belong to the browser context will be closed.\n\n**NOTE** the default browser context cannot be closed.","required":true,"args":{}},"cookies":{"name":"cookies","type":{"name":"Promise>","properties":{"name":{"name":"name","type":{"name":"string"},"required":true},"value":{"name":"value","type":{"name":"string"},"required":true},"domain":{"name":"domain","type":{"name":"string"},"required":true},"path":{"name":"path","type":{"name":"string"},"required":true},"expires":{"name":"expires","type":{"name":"number"},"comment":"Unix time in seconds.","required":true},"httpOnly":{"name":"httpOnly","type":{"name":"boolean"},"required":true},"secure":{"name":"secure","type":{"name":"boolean"},"required":true},"sameSite":{"name":"sameSite","type":{"name":"\"Lax\"|\"None\"|\"Strict\""},"required":true}}},"comment":"If no URLs are specified, this method returns all cookies. If URLs are specified, only cookies that affect those URLs\nare returned.","required":true,"args":{"urls":{"name":"urls","type":{"name":"string|Array"},"comment":"Optional list of URLs.","required":false}}},"exposeBinding":{"name":"exposeBinding","type":{"name":"Promise"},"comment":"The method adds a function called `name` on the `window` object of every frame in every page in the context. When\ncalled, the function executes `playwrightBinding` in Node.js and returns a Promise which resolves to the return value\nof `playwrightBinding`. If the `playwrightBinding` returns a Promise, it will be awaited.\nThe first argument of the `playwrightBinding` function contains information about the caller: `{ browserContext: BrowserContext, page: Page, frame: Frame }`.\nSee page.exposeBinding(name, playwrightBinding[, options]) for page-only version.\nAn example of exposing page URL to all frames in all pages in the context:\n```js\nconst { webkit } = require('playwright'); // Or 'chromium' or 'firefox'.\n\n(async () => {\n const browser = await webkit.launch({ headless: false });\n const context = await browser.newContext();\n await context.exposeBinding('pageURL', ({ page }) => page.url());\n const page = await context.newPage();\n await page.setContent(`\n \n \n
\n `);\n await page.click('button');\n})();\n```\nAn example of passing an element handle:\n```js\nawait context.exposeBinding('clicked', async (source, element) => {\n console.log(await element.textContent());\n}, { handle: true });\nawait page.setContent(`\n \n
Click me
\n
Or click me
\n`);\n```","required":true,"args":{"name":{"name":"name","type":{"name":"string"},"comment":"Name of the function on the window object.","required":true},"playwrightBinding":{"name":"playwrightBinding","type":{"name":"function"},"comment":"Callback function that will be called in the Playwright's context.","required":true},"options":{"name":"options","type":{"name":"Object","properties":{"handle":{"name":"handle","type":{"name":"boolean"},"comment":"Whether to pass the argument as a handle, instead of passing by value. When passing a handle, only one argument is supported. When passing by value, multiple arguments are supported.","required":false}}},"required":false}}},"exposeFunction":{"name":"exposeFunction","type":{"name":"Promise"},"comment":"The method adds a function called `name` on the `window` object of every frame in every page in the context. When\ncalled, the function executes `playwrightFunction` in Node.js and returns a Promise which resolves to the return value\nof `playwrightFunction`.\nIf the `playwrightFunction` returns a Promise, it will be awaited.\nSee page.exposeFunction(name, playwrightFunction) for page-only version.\nAn example of adding an `md5` function to all pages in the context:\n```js\nconst { webkit } = require('playwright'); // Or 'chromium' or 'firefox'.\nconst crypto = require('crypto');\n\n(async () => {\n const browser = await webkit.launch({ headless: false });\n const context = await browser.newContext();\n await context.exposeFunction('md5', text => crypto.createHash('md5').update(text).digest('hex'));\n const page = await context.newPage();\n await page.setContent(`\n \n \n
\n `);\n await page.click('button');\n})();\n```","required":true,"args":{"name":{"name":"name","type":{"name":"string"},"comment":"Name of the function on the window object.","required":true},"playwrightFunction":{"name":"playwrightFunction","type":{"name":"function"},"comment":"Callback function that will be called in the Playwright's context.","required":true}}},"grantPermissions":{"name":"grantPermissions","type":{"name":"Promise"},"comment":"Grants specified permissions to the browser context. Only grants corresponding permissions to the given origin if\nspecified.","required":true,"args":{"permissions":{"name":"permissions","type":{"name":"Array"},"comment":"A permission or an array of permissions to grant. Permissions can be one of the following values:\n - `'geolocation'`\n - `'midi'`\n - `'midi-sysex'` (system-exclusive midi)\n - `'notifications'`\n - `'push'`\n - `'camera'`\n - `'microphone'`\n - `'background-sync'`\n - `'ambient-light-sensor'`\n - `'accelerometer'`\n - `'gyroscope'`\n - `'magnetometer'`\n - `'accessibility-events'`\n - `'clipboard-read'`\n - `'clipboard-write'`\n - `'payment-handler'`","required":true},"options":{"name":"options","type":{"name":"Object","properties":{"origin":{"name":"origin","type":{"name":"string"},"comment":"The origin to grant permissions to, e.g. \"https://example.com\".","required":false}}},"required":false}}},"newPage":{"name":"newPage","type":{"name":"Promise"},"comment":"Creates a new page in the browser context.","required":true,"args":{}},"pages":{"name":"pages","type":{"name":"Array"},"comment":"Returns all open pages in the context. Non visible pages, such as `\"background_page\"`, will not be listed here. You can\nfind them using chromiumBrowserContext.backgroundPages().","required":true,"args":{}},"route":{"name":"route","type":{"name":"Promise"},"comment":"Routing provides the capability to modify network requests that are made by any page in the browser context. Once route\nis enabled, every request matching the url pattern will stall unless it's continued, fulfilled or aborted.\nAn example of a naïve handler that aborts all image requests:\n```js\nconst context = await browser.newContext();\nawait context.route('**/*.{png,jpg,jpeg}', route => route.abort());\nconst page = await context.newPage();\nawait page.goto('https://example.com');\nawait browser.close();\n```\nor the same snippet using a regex pattern instead:\n```js\nconst context = await browser.newContext();\nawait context.route(/(\\.png$)|(\\.jpg$)/, route => route.abort());\nconst page = await context.newPage();\nawait page.goto('https://example.com');\nawait browser.close();\n```\nPage routes (set up with page.route(url, handler)) take precedence over browser context routes when request matches both\nhandlers.\n\n**NOTE** Enabling routing disables http cache.","required":true,"args":{"url":{"name":"url","type":{"name":"string|RegExp|function(URL):boolean"},"comment":"A glob pattern, regex pattern or predicate receiving URL to match while routing.","required":true},"handler":{"name":"handler","type":{"name":"function(Route, Request)"},"comment":"handler function to route the request.","required":true}}},"setDefaultNavigationTimeout":{"name":"setDefaultNavigationTimeout","type":null,"comment":"This setting will change the default maximum navigation time for the following methods and related shortcuts:\n\npage.goBack([options])\npage.goForward([options])\npage.goto(url[, options])\npage.reload([options])\npage.setContent(html[, options])\npage.waitForNavigation([options])\n\n\n**NOTE** page.setDefaultNavigationTimeout(timeout) and page.setDefaultTimeout(timeout) take priority over\nbrowserContext.setDefaultNavigationTimeout(timeout).","required":true,"args":{"timeout":{"name":"timeout","type":{"name":"number"},"comment":"Maximum navigation time in milliseconds","required":true}}},"setDefaultTimeout":{"name":"setDefaultTimeout","type":null,"comment":"This setting will change the default maximum time for all the methods accepting `timeout` option.\n\n**NOTE** page.setDefaultNavigationTimeout(timeout), page.setDefaultTimeout(timeout) and\nbrowserContext.setDefaultNavigationTimeout(timeout) take priority over browserContext.setDefaultTimeout(timeout).","required":true,"args":{"timeout":{"name":"timeout","type":{"name":"number"},"comment":"Maximum time in milliseconds","required":true}}},"setExtraHTTPHeaders":{"name":"setExtraHTTPHeaders","type":{"name":"Promise"},"comment":"The extra HTTP headers will be sent with every request initiated by any page in the context. These headers are merged\nwith page-specific extra HTTP headers set with page.setExtraHTTPHeaders(headers). If page overrides a particular header,\npage-specific header value will be used instead of the browser context header value.\n\n**NOTE** `browserContext.setExtraHTTPHeaders` does not guarantee the order of headers in the outgoing requests.","required":true,"args":{"headers":{"name":"headers","type":{"name":"Object"},"comment":"An object containing additional HTTP headers to be sent with every request. All header values must be strings.","required":true}}},"setGeolocation":{"name":"setGeolocation","type":{"name":"Promise"},"comment":"Sets the context's geolocation. Passing `null` or `undefined` emulates position unavailable.\n```js\nawait browserContext.setGeolocation({latitude: 59.95, longitude: 30.31667});\n```\n\n**NOTE** Consider using browserContext.grantPermissions(permissions[, options]) to grant permissions for the browser context pages to\nread its geolocation.","required":true,"args":{"geolocation":{"name":"geolocation","type":{"name":"null|Object","properties":{"latitude":{"name":"latitude","type":{"name":"number"},"comment":"Latitude between -90 and 90. **required**","required":true},"longitude":{"name":"longitude","type":{"name":"number"},"comment":"Longitude between -180 and 180. **required**","required":true},"accuracy":{"name":"accuracy","type":{"name":"number"},"comment":"Non-negative accuracy value. Defaults to `0`.","required":false}}},"required":true}}},"setHTTPCredentials":{"name":"setHTTPCredentials","type":{"name":"Promise"},"comment":"Provide credentials for HTTP authentication.\n\n**NOTE** Browsers may cache credentials after successful authentication. Passing different credentials or passing\n`null` to disable authentication will be unreliable. To remove or replace credentials, create a new browser context\ninstead.","required":true,"args":{"httpCredentials":{"name":"httpCredentials","type":{"name":"null|Object","properties":{"username":{"name":"username","type":{"name":"string"},"comment":"**required**","required":true},"password":{"name":"password","type":{"name":"string"},"comment":"**required**","required":true}}},"required":true}}},"setOffline":{"name":"setOffline","type":{"name":"Promise"},"required":true,"args":{"offline":{"name":"offline","type":{"name":"boolean"},"comment":"Whether to emulate network being offline for the browser context.","required":true}}},"storageState":{"name":"storageState","type":{"name":"Promise","properties":{"cookies":{"name":"cookies","type":{"name":"Array","properties":{"name":{"name":"name","type":{"name":"string"},"required":true},"value":{"name":"value","type":{"name":"string"},"required":true},"domain":{"name":"domain","type":{"name":"string"},"required":true},"path":{"name":"path","type":{"name":"string"},"required":true},"expires":{"name":"expires","type":{"name":"number"},"comment":"Unix time in seconds.","required":true},"httpOnly":{"name":"httpOnly","type":{"name":"boolean"},"required":true},"secure":{"name":"secure","type":{"name":"boolean"},"required":true},"sameSite":{"name":"sameSite","type":{"name":"\"Lax\"|\"None\"|\"Strict\""},"required":true}}},"required":true},"origins":{"name":"origins","type":{"name":"Array","properties":{"origin":{"name":"origin","type":{"name":"string"},"required":true},"localStorage":{"name":"localStorage","type":{"name":"Array","properties":{"name":{"name":"name","type":{"name":"string"},"required":true},"value":{"name":"value","type":{"name":"string"},"required":true}}},"required":true}}},"required":true}}},"comment":"Returns storage state for this browser context, contains current cookies and local storage snapshot.","required":true,"args":{}},"unroute":{"name":"unroute","type":{"name":"Promise"},"comment":"Removes a route created with browserContext.route(url, handler). When `handler` is not specified, removes all routes for the\n`url`.","required":true,"args":{"url":{"name":"url","type":{"name":"string|RegExp|function(URL):boolean"},"comment":"A glob pattern, regex pattern or predicate receiving URL used to register a routing with browserContext.route(url, handler).","required":true},"handler":{"name":"handler","type":{"name":"function(Route, Request)"},"comment":"Optional handler function used to register a routing with browserContext.route(url, handler).","required":false}}},"waitForEvent":{"name":"waitForEvent","type":{"name":"Promise"},"comment":"Waits for event to fire and passes its value into the predicate function. Resolves when the predicate returns truthy\nvalue. Will throw an error if the context closes before the event is fired. Returns the event data value.\n```js\nconst context = await browser.newContext();\nawait context.grantPermissions(['geolocation']);\n```","required":true,"args":{"event":{"name":"event","type":{"name":"string"},"comment":"Event name, same one would pass into `browserContext.on(event)`.","required":true},"optionsOrPredicate":{"name":"optionsOrPredicate","type":{"name":"Function|Object","properties":{"predicate":{"name":"predicate","type":{"name":"Function"},"comment":"receives the event data and resolves to truthy value when the waiting should resolve.","required":false},"timeout":{"name":"timeout","type":{"name":"number"},"comment":"maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can be changed by using the browserContext.setDefaultTimeout(timeout).","required":false}}},"comment":"Either a predicate that receives an event or an options object. Optional.","required":false}}}},"events":{"close":{"name":"close","type":null,"required":true,"args":{}},"page":{"name":"page","type":{"name":"Page"},"comment":"The event is emitted when a new Page is created in the BrowserContext. The page may still be loading. The event will\nalso fire for popup pages. See also page.on('popup') to receive events about popups relevant to a specific page.\nThe earliest moment that page is available is when it has navigated to the initial url. For example, when opening a\npopup with `window.open('http://example.com')`, this event will fire when the network request to \"http://example.com\" is\ndone and its response has started loading in the popup.\n```js\nconst [page] = await Promise.all([\n context.waitForEvent('page'),\n page.click('a[target=_blank]'),\n]);\nconsole.log(await page.evaluate('location.href'));\n```\n\n**NOTE** Use page.waitForLoadState([state, options]) to wait until the page gets to a particular state (you should not need it in\nmost cases).","required":true,"args":{}}},"properties":{}},"Page":{"name":"Page","extends":"EventEmitter","comment":"Page provides methods to interact with a single tab in a Browser, or an extension background\npage in Chromium. One Browser instance might have multiple\nPage instances.\nThis example creates a page, navigates it to a URL, and then saves a screenshot:\n```js\nconst { webkit } = require('playwright'); // Or 'chromium' or 'firefox'.\n\n(async () => {\n const browser = await webkit.launch();\n const context = await browser.newContext();\n const page = await context.newPage();\n await page.goto('https://example.com');\n await page.screenshot({path: 'screenshot.png'});\n await browser.close();\n})();\n```\nThe Page class emits various events (described below) which can be handled using any of Node's native\n`EventEmitter` methods, such as `on`, `once` or\n`removeListener`.\nThis example logs a message for a single page `load` event:\n```js\npage.once('load', () => console.log('Page loaded!'));\n```\nTo unsubscribe from events use the `removeListener` method:\n```js\nfunction logRequest(interceptedRequest) {\n console.log('A request was made:', interceptedRequest.url());\n}\npage.on('request', logRequest);\n// Sometime later...\npage.removeListener('request', logRequest);\n```","methods":{"$":{"name":"$","type":{"name":"Promise"},"comment":"The method finds an element matching the specified selector within the page. If no elements match the selector, the\nreturn value resolves to `null`.\nShortcut for main frame's frame.$(selector).","required":true,"args":{"selector":{"name":"selector","type":{"name":"string"},"comment":"A selector to query for. See working with selectors for more details.","required":true}}},"$$":{"name":"$$","type":{"name":"Promise>"},"comment":"The method finds all elements matching the specified selector within the page. If no elements match the selector, the\nreturn value resolves to `[]`.\nShortcut for main frame's frame.$$(selector).","required":true,"args":{"selector":{"name":"selector","type":{"name":"string"},"comment":"A selector to query for. See working with selectors for more details.","required":true}}},"$eval":{"name":"$eval","type":{"name":"Promise"},"comment":"The method finds an element matching the specified selector within the page and passes it as a first argument to\n`pageFunction`. If no elements match the selector, the method throws an error. Returns the value of `pageFunction`.\nIf `pageFunction` returns a Promise, then `page.$eval` would wait for the promise to resolve and return its value.\nExamples:\n```js\nconst searchValue = await page.$eval('#search', el => el.value);\nconst preloadHref = await page.$eval('link[rel=preload]', el => el.href);\nconst html = await page.$eval('.main-container', (e, suffix) => e.outerHTML + suffix, 'hello');\n```\nShortcut for main frame's frame.$eval(selector, pageFunction[, arg]).","required":true,"args":{"selector":{"name":"selector","type":{"name":"string"},"comment":"A selector to query for. See working with selectors for more details.","required":true},"pageFunction":{"name":"pageFunction","type":{"name":"function(Element)"},"comment":"Function to be evaluated in browser context","required":true},"arg":{"name":"arg","type":{"name":"EvaluationArgument"},"comment":"Optional argument to pass to `pageFunction`","required":false}}},"$$eval":{"name":"$$eval","type":{"name":"Promise"},"comment":"The method finds all elements matching the specified selector within the page and passes an array of matched elements as\na first argument to `pageFunction`. Returns the result of `pageFunction` invocation.\nIf `pageFunction` returns a Promise, then `page.$$eval` would wait for the promise to resolve and return its value.\nExamples:\n```js\nconst divsCounts = await page.$$eval('div', (divs, min) => divs.length >= min, 10);\n```","required":true,"args":{"selector":{"name":"selector","type":{"name":"string"},"comment":"A selector to query for. See working with selectors for more details.","required":true},"pageFunction":{"name":"pageFunction","type":{"name":"function(Array)"},"comment":"Function to be evaluated in browser context","required":true},"arg":{"name":"arg","type":{"name":"EvaluationArgument"},"comment":"Optional argument to pass to `pageFunction`","required":false}}},"addInitScript":{"name":"addInitScript","type":{"name":"Promise"},"comment":"Adds a script which would be evaluated in one of the following scenarios:\n\nWhenever the page is navigated.\nWhenever the child frame is attached or navigated. In this case, the script is evaluated in the context of the newly attached frame.\n\nThe script is evaluated after the document was created but before any of its scripts were run. This is useful to amend\nthe JavaScript environment, e.g. to seed `Math.random`.\nAn example of overriding `Math.random` before the page loads:\n```js\n// preload.js\nMath.random = () => 42;\n\n// In your playwright script, assuming the preload.js file is in same directory\nconst preloadFile = fs.readFileSync('./preload.js', 'utf8');\nawait page.addInitScript(preloadFile);\n```\n\n**NOTE** The order of evaluation of multiple scripts installed via browserContext.addInitScript(script[, arg]) and\npage.addInitScript(script[, arg]) is not defined.","required":true,"args":{"script":{"name":"script","type":{"name":"function|string|Object","properties":{"path":{"name":"path","type":{"name":"string"},"comment":"Path to the JavaScript file. If `path` is a relative path, then it is resolved relative to current working directory.","required":false},"content":{"name":"content","type":{"name":"string"},"comment":"Raw script content.","required":false}}},"comment":"Script to be evaluated in the page.","required":true},"arg":{"name":"arg","type":{"name":"Serializable"},"comment":"Optional argument to pass to `script` (only supported when passing a function).","required":false}}},"addScriptTag":{"name":"addScriptTag","type":{"name":"Promise"},"comment":"Adds a `\n \n
\n `);\n await page.click('button');\n})();\n```\nAn example of passing an element handle:\n```js\nawait page.exposeBinding('clicked', async (source, element) => {\n console.log(await element.textContent());\n}, { handle: true });\nawait page.setContent(`\n \n
Click me
\n
Or click me
\n`);\n```","required":true,"args":{"name":{"name":"name","type":{"name":"string"},"comment":"Name of the function on the window object.","required":true},"playwrightBinding":{"name":"playwrightBinding","type":{"name":"function"},"comment":"Callback function that will be called in the Playwright's context.","required":true},"options":{"name":"options","type":{"name":"Object","properties":{"handle":{"name":"handle","type":{"name":"boolean"},"comment":"Whether to pass the argument as a handle, instead of passing by value. When passing a handle, only one argument is supported. When passing by value, multiple arguments are supported.","required":false}}},"required":false}}},"exposeFunction":{"name":"exposeFunction","type":{"name":"Promise"},"comment":"The method adds a function called `name` on the `window` object of every frame in the page. When called, the function\nexecutes `playwrightFunction` in Node.js and returns a Promise which resolves to the return value of\n`playwrightFunction`.\nIf the `playwrightFunction` returns a Promise, it will be awaited.\nSee browserContext.exposeFunction(name, playwrightFunction) for context-wide exposed function.\n\n**NOTE** Functions installed via `page.exposeFunction` survive navigations.\n\nAn example of adding an `md5` function to the page:\n```js\nconst { webkit } = require('playwright'); // Or 'chromium' or 'firefox'.\nconst crypto = require('crypto');\n\n(async () => {\n const browser = await webkit.launch({ headless: false });\n const page = await browser.newPage();\n await page.exposeFunction('md5', text => crypto.createHash('md5').update(text).digest('hex'));\n await page.setContent(`\n \n \n
\n `);\n await page.click('button');\n})();\n```\nAn example of adding a `window.readfile` function to the page:\n```js\nconst { chromium } = require('playwright'); // Or 'firefox' or 'webkit'.\nconst fs = require('fs');\n\n(async () => {\n const browser = await chromium.launch();\n const page = await browser.newPage();\n page.on('console', msg => console.log(msg.text()));\n await page.exposeFunction('readfile', async filePath => {\n return new Promise((resolve, reject) => {\n fs.readFile(filePath, 'utf8', (err, text) => {\n if (err)\n reject(err);\n else\n resolve(text);\n });\n });\n });\n await page.evaluate(async () => {\n // use window.readfile to read contents of a file\n const content = await window.readfile('/etc/hosts');\n console.log(content);\n });\n await browser.close();\n})();\n```","required":true,"args":{"name":{"name":"name","type":{"name":"string"},"comment":"Name of the function on the window object","required":true},"playwrightFunction":{"name":"playwrightFunction","type":{"name":"function"},"comment":"Callback function which will be called in Playwright's context.","required":true}}},"fill":{"name":"fill","type":{"name":"Promise"},"comment":"This method waits for an element matching `selector`, waits for actionability checks, focuses the\nelement, fills it and triggers an `input` event after filling. If the element matching `selector` is not an ``,\n`