Skip to content

Commit

Permalink
Revert "Merge branch 'main' of https://github.com/microsoft/playwright"
Browse files Browse the repository at this point in the history
This reverts commit c9e0c77, reversing
changes made to 26dc2aa.
  • Loading branch information
sand4rt committed Jan 25, 2024
1 parent c9e0c77 commit 1876c8c
Show file tree
Hide file tree
Showing 140 changed files with 2,030 additions and 3,383 deletions.
2 changes: 1 addition & 1 deletion .github/actions/upload-blob-report/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ runs:
uses: actions/upload-artifact@v4
with:
name: blob-report-${{ inputs.job_name }}
path: ${{ inputs.report_dir }}/**
path: ${{ inputs.report_dir }}
retention-days: 7
- name: Write triggering pull request number in a file
if: always() && github.event_name == 'pull_request'
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# 🎭 Playwright

[![npm version](https://img.shields.io/npm/v/playwright.svg)](https://www.npmjs.com/package/playwright) <!-- GEN:chromium-version-badge -->[![Chromium version](https://img.shields.io/badge/chromium-122.0.6261.6-blue.svg?logo=google-chrome)](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[![Firefox version](https://img.shields.io/badge/firefox-121.0-blue.svg?logo=firefoxbrowser)](https://www.mozilla.org/en-US/firefox/new/)<!-- GEN:stop --> <!-- GEN:webkit-version-badge -->[![WebKit version](https://img.shields.io/badge/webkit-17.4-blue.svg?logo=safari)](https://webkit.org/)<!-- GEN:stop -->
[![npm version](https://img.shields.io/npm/v/playwright.svg)](https://www.npmjs.com/package/playwright) <!-- GEN:chromium-version-badge -->[![Chromium version](https://img.shields.io/badge/chromium-121.0.6167.57-blue.svg?logo=google-chrome)](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[![Firefox version](https://img.shields.io/badge/firefox-121.0-blue.svg?logo=firefoxbrowser)](https://www.mozilla.org/en-US/firefox/new/)<!-- GEN:stop --> <!-- GEN:webkit-version-badge -->[![WebKit version](https://img.shields.io/badge/webkit-17.4-blue.svg?logo=safari)](https://webkit.org/)<!-- GEN:stop -->

## [Documentation](https://playwright.dev) | [API reference](https://playwright.dev/docs/api/class-playwright)

Playwright is a framework for Web Testing and Automation. It allows testing [Chromium](https://www.chromium.org/Home), [Firefox](https://www.mozilla.org/en-US/firefox/new/) and [WebKit](https://webkit.org/) with a single API. Playwright is built to enable cross-browser web automation that is **ever-green**, **capable**, **reliable** and **fast**.

| | Linux | macOS | Windows |
| :--- | :---: | :---: | :---: |
| Chromium <!-- GEN:chromium-version -->122.0.6261.6<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Chromium <!-- GEN:chromium-version -->121.0.6167.57<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| WebKit <!-- GEN:webkit-version -->17.4<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Firefox <!-- GEN:firefox-version -->121.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |

Expand Down
6 changes: 6 additions & 0 deletions docs/src/api/class-android.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ const { _android: android } = require('playwright');
})();
```

Note that since you don't need Playwright to install web browsers when testing Android, you can omit browser download via setting the following environment variable when installing Playwright:

```bash js
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm i -D playwright
```

## async method: Android.connect
* since: v1.28
- returns: <[AndroidDevice]>
Expand Down
6 changes: 6 additions & 0 deletions docs/src/api/class-electron.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ const { _electron: electron } = require('playwright');
})();
```

Note that since you don't need Playwright to install web browsers when testing Electron, you can omit browser download via setting the following environment variable when installing Playwright:

```bash js
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm i -D playwright
```

**Supported Electron versions are:**
* v12.2.0+
* v13.4.0+
Expand Down
196 changes: 0 additions & 196 deletions docs/src/api/class-page.md
Original file line number Diff line number Diff line change
Expand Up @@ -3130,202 +3130,6 @@ return value resolves to `[]`.
### param: Page.querySelectorAll.selector = %%-query-selector-%%
* since: v1.9


## async method: Page.handleLocator
* since: v1.42

Registers a handler for an element that might block certain actions like click. The handler should get rid of the blocking element so that an action may proceed. This is useful for nondeterministic interstitial pages or dialogs, like a cookie consent dialog.

The handler will be executed before [actionability checks](../actionability.md) for each action, and also before each attempt of the [web assertions](../test-assertions.md). When no actions or assertions are executed, the handler will not be run at all, even if the interstitial element appears on the page.

Note that execution time of the handler counts towards the timeout of the action/assertion that executed the handler.

**Usage**

An example that closes a cookie dialog when it appears:

```js
// Setup the handler.
await page.handleLocator(page.getByRole('button', { name: 'Accept all cookies' }), async () => {
await page.getByRole('button', { name: 'Reject all cookies' }).click();
});

// Write the test as usual.
await page.goto('https://example.com');
await page.getByRole('button', { name: 'Start here' }).click();
```

```java
// Setup the handler.
page.handleLocator(page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Accept all cookies")), () => {
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Reject all cookies")).click();
});

// Write the test as usual.
page.goto("https://example.com");
page.getByRole("button", Page.GetByRoleOptions().setName("Start here")).click();
```

```python sync
# Setup the handler.
def handler():
page.get_by_role("button", name="Reject all cookies").click()
page.handle_locator(page.get_by_role("button", name="Accept all cookies"), handler)

# Write the test as usual.
page.goto("https://example.com")
page.get_by_role("button", name="Start here").click()
```

```python async
# Setup the handler.
def handler():
await page.get_by_role("button", name="Reject all cookies").click()
await page.handle_locator(page.get_by_role("button", name="Accept all cookies"), handler)

# Write the test as usual.
await page.goto("https://example.com")
await page.get_by_role("button", name="Start here").click()
```

```csharp
// Setup the handler.
await page.HandleLocatorAsync(page.GetByRole(AriaRole.Button, new() { Name = "Accept all cookies" }), async () => {
await page.GetByRole(AriaRole.Button, new() { Name = "Reject all cookies" }).ClickAsync();
});

// Write the test as usual.
await page.GotoAsync("https://example.com");
await page.GetByRole("button", new() { Name = "Start here" }).ClickAsync();
```

An example that skips the "Confirm your security details" page when it is shown:

```js
// Setup the handler.
await page.handleLocator(page.getByText('Confirm your security details'), async () => {
await page.getByRole('button', 'Remind me later').click();
});

// Write the test as usual.
await page.goto('https://example.com');
await page.getByRole('button', { name: 'Start here' }).click();
```

```java
// Setup the handler.
page.handleLocator(page.getByText("Confirm your security details")), () => {
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Remind me later")).click();
});

// Write the test as usual.
page.goto("https://example.com");
page.getByRole("button", Page.GetByRoleOptions().setName("Start here")).click();
```

```python sync
# Setup the handler.
def handler():
page.get_by_role("button", name="Remind me later").click()
page.handle_locator(page.get_by_text("Confirm your security details"), handler)

# Write the test as usual.
page.goto("https://example.com")
page.get_by_role("button", name="Start here").click()
```

```python async
# Setup the handler.
def handler():
await page.get_by_role("button", name="Remind me later").click()
await page.handle_locator(page.get_by_text("Confirm your security details"), handler)

# Write the test as usual.
await page.goto("https://example.com")
await page.get_by_role("button", name="Start here").click()
```

```csharp
// Setup the handler.
await page.HandleLocatorAsync(page.GetByText("Confirm your security details"), async () => {
await page.GetByRole(AriaRole.Button, new() { Name = "Remind me later" }).ClickAsync();
});

// Write the test as usual.
await page.GotoAsync("https://example.com");
await page.GetByRole("button", new() { Name = "Start here" }).ClickAsync();
```

An example with a custom callback on every actionability check. It uses a `<body>` locator that is always visible, so the handler is called before every actionability check:

```js
// Setup the handler.
await page.handleLocator(page.locator('body'), async () => {
await page.evaluate(() => window.removeObstructionsForTestIfNeeded());
});

// Write the test as usual.
await page.goto('https://example.com');
await page.getByRole('button', { name: 'Start here' }).click();
```

```java
// Setup the handler.
page.handleLocator(page.locator("body")), () => {
page.evaluate("window.removeObstructionsForTestIfNeeded()");
});

// Write the test as usual.
page.goto("https://example.com");
page.getByRole("button", Page.GetByRoleOptions().setName("Start here")).click();
```

```python sync
# Setup the handler.
def handler():
page.evaluate("window.removeObstructionsForTestIfNeeded()")
page.handle_locator(page.locator("body"), handler)

# Write the test as usual.
page.goto("https://example.com")
page.get_by_role("button", name="Start here").click()
```

```python async
# Setup the handler.
def handler():
await page.evaluate("window.removeObstructionsForTestIfNeeded()")
await page.handle_locator(page.locator("body"), handler)

# Write the test as usual.
await page.goto("https://example.com")
await page.get_by_role("button", name="Start here").click()
```

```csharp
// Setup the handler.
await page.HandleLocatorAsync(page.Locator("body"), async () => {
await page.EvaluateAsync("window.removeObstructionsForTestIfNeeded()");
});

// Write the test as usual.
await page.GotoAsync("https://example.com");
await page.GetByRole("button", new() { Name = "Start here" }).ClickAsync();
```

### param: Page.handleLocator.locator
* since: v1.42
- `locator` <[Locator]>

Locator that triggers the handler.

### param: Page.handleLocator.handler
* since: v1.42
- `handler` <[function]>

Function that should be run once [`param: locator`] appears. This function should get rid of the element that blocks actions like click.


## async method: Page.reload
* since: v1.8
- returns: <[null]|[Response]>
Expand Down
4 changes: 1 addition & 3 deletions docs/src/intro-js.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,6 @@ To update Playwright to the latest version run the following command:

```bash
npm install -D @playwright/test@latest
# Also download new browser binaries and their dependencies:
npx playwright install --with-deps
```
You can always check which version of Playwright you have by running the following command:

Expand All @@ -126,7 +124,7 @@ npx playwright --version

## System requirements

- Node.js 18+
- Node.js 16+
- Windows 10+, Windows Server 2016+ or Windows Subsystem for Linux (WSL).
- MacOS 12 Monterey, MacOS 13 Ventura, or MacOS 14 Sonoma.
- Debian 11, Debian 12, Ubuntu 20.04 or Ubuntu 22.04, with x86-64 or arm64 architecture.
Expand Down
26 changes: 13 additions & 13 deletions docs/src/mock.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ test('gets the json from api and adds a new fruit', async ({ page }) => {
await page.route('*/**/api/v1/fruits', async route => {
const response = await route.fetch();
const json = await response.json();
json.push({ name: 'Loquat', id: 100 });
json.push({ name: 'Playwright', id: 100 });
// Fulfill using the original response, while patching the response body
// with the given JSON object.
await route.fulfill({ response, json });
Expand All @@ -128,7 +128,7 @@ test('gets the json from api and adds a new fruit', async ({ page }) => {
await page.goto('https://demo.playwright.dev/api-mocking');

// Assert that the new fruit is visible
await expect(page.getByText('Loquat', { exact: true })).toBeVisible();
await expect(page.getByText('Playwright', { exact: true })).toBeVisible();
});
```

Expand All @@ -137,7 +137,7 @@ async def test_gets_the_json_from_api_and_adds_a_new_fruit(page: Page):
async def handle(route: Route):
response = await route.fetch()
json = await response.json()
json.append({ "name": "Loquat", "id": 100})
json.append({ "name": "Playwright", "id": 100})
# Fulfill using the original response, while patching the response body
# with the given JSON object.
await route.fulfill(response=response, json=json)
Expand All @@ -148,15 +148,15 @@ async def test_gets_the_json_from_api_and_adds_a_new_fruit(page: Page):
await page.goto("https://demo.playwright.dev/api-mocking")

# Assert that the new fruit is visible
await page.get_by_text("Loquat", exact=True).to_be_visible()
await page.get_by_text("Playwright", exact=True).to_be_visible()
```

```python sync
def test_gets_the_json_from_api_and_adds_a_new_fruit(page: Page):
def handle(route: Route):
response = route.fetch()
json = response.json()
json.append({ "name": "Loquat", "id": 100})
json.append({ "name": "Playwright", "id": 100})
# Fulfill using the original response, while patching the response body
# with the given JSON object.
route.fulfill(response=response, json=json)
Expand All @@ -167,36 +167,36 @@ def test_gets_the_json_from_api_and_adds_a_new_fruit(page: Page):
page.goto("https://demo.playwright.dev/api-mocking")

# Assert that the new fruit is visible
page.get_by_text("Loquat", exact=True).to_be_visible()
page.get_by_text("Playwright", exact=True).to_be_visible()
```

```csharp
await page.RouteAsync("*/**/api/v1/fruits", async (route) => {
var response = await route.FetchAsync();
var fruits = await response.JsonAsync<Fruit[]>();
fruits.Add(new Fruit() { Name = "Loquat", Id = 100 });
fruits.Add(new Fruit() { Name = "Playwright", Id = 100 });
// Fulfill using the original response, while patching the response body
// with the given JSON object.
await route.FulfillAsync(new ()
{
Response = response,
Json = fruits
Json = json
});
}
);
// Go to the page
await page.GotoAsync("https://demo.playwright.dev/api-mocking");

// Assert that the Loquat fruit is visible
await Expect(page.GetByTextAsync("Loquat", new () { Exact = true })).ToBeVisibleAsync();
// Assert that the Strawberry fruit is visible
await Expect(page.GetByTextAsync("Playwright", new () { Exact = true })).ToBeVisibleAsync();
```

```java
page.route("*/**/api/v1/fruits", route -> {
Response response = route.fetch();
byte[] json = response.body();
parsed = new Gson().fromJson(json, JsonObject.class)
parsed.add(new JsonObject().add("name", "Loquat").add("id", 100));
parsed.add(new JsonObject().add("name", "Playwright").add("id", 100));
// Fulfill using the original response, while patching the response body
// with the given JSON object.
route.fulfill(new Route.FulfillOptions().setResponse(response).setBody(json.toString()));
Expand All @@ -205,8 +205,8 @@ page.route("*/**/api/v1/fruits", route -> {
// Go to the page
page.goto("https://demo.playwright.dev/api-mocking");

// Assert that the Loquat fruit is visible
assertThat(page.getByText("Loquat", new Page.GetByTextOptions().setExact(true))).isVisible();
// Assert that the Strawberry fruit is visible
assertThat(page.getByText("Playwright", new Page.GetByTextOptions().setExact(true))).isVisible();
```

In the trace of our test we can see that the API was called and the response was modified.
Expand Down
Loading

0 comments on commit 1876c8c

Please sign in to comment.