From dcb83d9db057ab907aa26b458705929fb2620385 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Thu, 21 Jul 2022 00:57:09 +0200 Subject: [PATCH] docs: new Python onboarding story (#15782) --- docs/src/api-testing-python.md | 2 +- docs/src/intro-csharp.md | 68 ++++----- docs/src/intro-python.md | 254 +++++++------------------------ docs/src/library-python.md | 206 +++++++++++++++++++++++++ docs/src/running-tests-python.md | 56 +++++++ docs/src/test-runners-python.md | 34 +---- docs/src/writing-tests-csharp.md | 6 +- docs/src/writing-tests-js.md | 4 +- docs/src/writing-tests-python.md | 109 +++++++++++++ 9 files changed, 465 insertions(+), 274 deletions(-) create mode 100644 docs/src/library-python.md create mode 100644 docs/src/running-tests-python.md create mode 100644 docs/src/writing-tests-python.md diff --git a/docs/src/api-testing-python.md b/docs/src/api-testing-python.md index af29aac2bf..d6a69ddaf4 100644 --- a/docs/src/api-testing-python.md +++ b/docs/src/api-testing-python.md @@ -114,7 +114,7 @@ def test_should_create_feature_request(api_request_context: APIRequestContext) - ### Setup and teardown -These tests assume that repository exists. You probably want to create a new one before running tests and delete it afterwards. Use a [session fixture](https://docs.pytest.org/en/6.2.x/fixture.html#fixture-scopes) for that. The part before `yield` is the before all and after is the after all. +These tests assume that repository exists. You probably want to create a new one before running tests and delete it afterwards. Use a [session fixture](https://docs.pytest.org/en/stable/fixture.html#fixture-scopes) for that. The part before `yield` is the before all and after is the after all. ```python # ... diff --git a/docs/src/intro-csharp.md b/docs/src/intro-csharp.md index 30daefbd41..8b8e0af744 100644 --- a/docs/src/intro-csharp.md +++ b/docs/src/intro-csharp.md @@ -5,9 +5,9 @@ title: "Installation" Playwright was created specifically to accommodate the needs of end-to-end testing. Playwright supports all modern rendering engines including Chromium, WebKit, and Firefox. Test on Windows, Linux, and macOS, locally or on CI, headless or headed with native mobile emulation. -You can choose to use [NUnit base classes](./test-runners.md#nunit) or [MSTest base classes](./test-runners.md#nunit) that Playwright provides to write end-to-end tests. These classes support running tests on multiple browser engines, parallelizing tests, adjusting launch/context options and getting a [Page]/[BrowserContext] instance per test out of the box. +You can choose to use [NUnit base classes](./test-runners.md#nunit) or [MSTest base classes](./test-runners.md#nunit) that Playwright provides to write end-to-end tests. These classes support running tests on multiple browser engines, parallelizing tests, adjusting launch/context options and getting a [Page]/[BrowserContext] instance per test out of the box. Alternatively you can use the [library](./library.md) to manually write the testing infrastructure. -Start by creating a new project with `dotnet new`. This will create the `PlaywrightTests` directory which includes a `UnitTest1.cs` file: +1. Start by creating a new project with `dotnet new`. This will create the `PlaywrightTests` directory which includes a `UnitTest1.cs` file: -Install the necessary Playwright dependencies: +2. Install the necessary Playwright dependencies: -Build the project so the `playwright.ps1` is available inside the `bin` directory: +3. Build the project so the `playwright.ps1` is available inside the `bin` directory: ```bash dotnet build ``` -Install required browsers by replacing `netX` with the actual output folder name, e.g. `net6.0`: +4. Install required browsers by replacing `netX` with the actual output folder name, e.g. `net6.0`: ```bash pwsh bin\Debug\netX\playwright.ps1 install @@ -95,25 +95,24 @@ namespace PlaywrightTests; public class Tests : PageTest { [Test] - async public Task ShouldHaveTheCorrectSlogan() + async public Task HomepageHasPlaywrightInTitleAndGetStartedLinkLinkingtoTheIntroPage() { await Page.GotoAsync("https://playwright.dev"); - await Expect(Page.Locator("text=enables reliable end-to-end testing for modern web apps")).ToBeVisibleAsync(); - } - [Test] - public async Task ShouldHaveTheCorrectTitle() - { - await Page.GotoAsync("https://playwright.dev"); - var title = Page.Locator(".navbar__inner .navbar__title"); - await Expect(title).ToHaveTextAsync("Playwright"); - } + // Expect a title "to contain" a substring. + await Expect(Page).ToHaveTitleAsync(new Regex("Playwright")); - [Test] - public async Task ShouldAdd() - { - var result = await Page.EvaluateAsync("() => 7 + 3"); - Assert.AreEqual(10, result); + // create a locator + var getStarted = Page.Locator("text=Get Started"); + + // Expect an attribute "to be strictly equal" to the value. + await Expect(getStarted).ToHaveAttributeAsync("href", "/docs/intro"); + + // Click the get started link. + await getStarted.ClickAsync(); + + // Expects the URL to contain intro. + await Expect(Page).ToHaveURLAsync(new Regex(".*intro")); } } ``` @@ -129,25 +128,24 @@ namespace PlaywrightTests; public class UnitTest1 : PageTest { [TestMethod] - async public Task ShouldHaveTheCorrectSlogan() + async public Task HomepageHasPlaywrightInTitleAndGetStartedLinkLinkingtoTheIntroPage() { await Page.GotoAsync("https://playwright.dev"); - await Expect(Page.Locator("text=enables reliable end-to-end testing for modern web apps")).ToBeVisibleAsync(); - } - [TestMethod] - public async Task ShouldHaveTheCorrectTitle() - { - await Page.GotoAsync("https://playwright.dev"); - var title = Page.Locator(".navbar__inner .navbar__title"); - await Expect(title).ToHaveTextAsync("Playwright"); - } + // Expect a title "to contain" a substring. + await Expect(Page).ToHaveTitleAsync(new Regex("Playwright")); - [TestMethod] - public async Task ShouldAdd() - { - var result = await Page.EvaluateAsync("() => 7 + 3"); - Assert.AreEqual(10, result); + // create a locator + var getStarted = Page.Locator("text=Get Started"); + + // Expect an attribute "to be strictly equal" to the value. + await Expect(getStarted).ToHaveAttributeAsync("href", "/docs/intro"); + + // Click the get started link. + await getStarted.ClickAsync(); + + // Expects the URL to contain intro. + await Expect(Page).ToHaveURLAsync(new Regex(".*intro")); } } ``` diff --git a/docs/src/intro-python.md b/docs/src/intro-python.md index 576703abd1..354e9e7a69 100644 --- a/docs/src/intro-python.md +++ b/docs/src/intro-python.md @@ -1,222 +1,70 @@ --- id: intro -title: "Getting started" +title: "Installation" --- - +Playwright was created specifically to accommodate the needs of end-to-end testing. Playwright supports all modern rendering engines including Chromium, WebKit, and Firefox. Test on Windows, Linux, and macOS, locally or on CI, headless or headed with native mobile emulation. -- [Release notes](./release-notes.md) +Playwright recommends using the official [Playwright Pytest plugin](./test-runners.md) to write end-to-end tests. It provides context isolation, running it on multiple browser configurations out of the box. Alternatively you can use the [library](./library.md) to manually write the testing infrastructure with your preferred test-runner. The Pytest plugin utilizes the sync version of Playwright, there is also an async version accessible via the library. -## Installation +Get started by installing Playwright and running the example test to see it in action. -See [system requirements](#system-requirements). - -### Pip - -[![PyPI version](https://badge.fury.io/py/playwright.svg)](https://pypi.python.org/pypi/playwright/) +Install the [Pytest plugin](https://pypi.org/project/pytest-playwright/): + +```bash +pip install pytest-playwright +``` + +Install the required browsers: ```bash -pip install --upgrade pip -pip install playwright playwright install ``` -### Conda +## Add Example Test -[![Anaconda version](https://img.shields.io/conda/v/microsoft/playwright)](https://anaconda.org/Microsoft/playwright) +Create a `test_my_application.py` file inside the current working directory or in a sub-directory with the code below: + +```py +import re +from playwright.sync_api import Page, expect + + +def test_homepage_has_Playwright_in_title_and_get_started_link_linking_to_the_intro_page( + page: Page, foo +): + page.goto("https://playwright.dev/") + + # Expect a title "to contain" a substring. + expect(page).to_have_title(re.compile("Playwright")) + + # create a locator + get_started = page.locator("text=Get Started") + + # Expect an attribute "to be strictly equal" to the value. + expect(get_started).to_have_attribute("href", "/docs/intro") + + # Click the get started link. + get_started.click() + + # Expects the URL to contain intro. + expect(page).to_have_url(re.compile(".*intro")) +``` + +## Running the Example Test + +By default tests will be run on chromium. This can be configured via the CLI options. Tests are run in headless mode meaning no browser UI will open up when running the tests. Results of the tests and test logs will be shown in the terminal. ```bash -conda config --add channels conda-forge -conda config --add channels microsoft -conda install playwright -playwright install +pytest ``` -These commands download the Playwright package and install browser binaries for Chromium, Firefox and WebKit. To modify this behavior see [installation parameters](./browsers.md#installing-browsers). +See our doc on [Running Tests](./running-tests.md) to learn more about running tests in headed mode, running multiple tests, running specific tests etc. -## Usage +## What's next -Once installed, you can `import` Playwright in a Python script, and launch any of the 3 browsers (`chromium`, `firefox` and `webkit`). - -```py -from playwright.sync_api import sync_playwright - -with sync_playwright() as p: - browser = p.chromium.launch() - page = browser.new_page() - page.goto("http://playwright.dev") - print(page.title()) - browser.close() -``` - -Playwright supports two variations of the API: synchronous and asynchronous. If your modern project uses [asyncio](https://docs.python.org/3/library/asyncio.html), you should use async API: - -```py -import asyncio -from playwright.async_api import async_playwright - -async def main(): - async with async_playwright() as p: - browser = await p.chromium.launch() - page = await browser.new_page() - await page.goto("http://playwright.dev") - print(await page.title()) - await browser.close() - -asyncio.run(main()) -``` - -## First script - -In our first script, we will navigate to `whatsmyuseragent.org` and take a screenshot in WebKit. - -```py -from playwright.sync_api import sync_playwright - -with sync_playwright() as p: - browser = p.webkit.launch() - page = browser.new_page() - page.goto("http://whatsmyuseragent.org/") - page.screenshot(path="example.png") - browser.close() -``` - -By default, Playwright runs the browsers in headless mode. To see the browser UI, pass the `headless=False` flag while launching the browser. You can also use [`option: slowMo`] to slow down execution. Learn more in the debugging tools [section](./debug.md). - -```py -firefox.launch(headless=False, slow_mo=50) -``` - -## Record scripts - -[Command line tools](./cli.md) can be used to record user interactions and generate Python code. - -```bash -playwright codegen wikipedia.org -``` - -## With Pytest - -See [here](./test-runners.md) for Pytest instructions and examples. - -## Interactive mode (REPL) - -Blocking REPL, as in CLI via Python directly: - -```bash -python -``` - -```py ->>> from playwright.sync_api import sync_playwright ->>> playwright = sync_playwright().start() -# Use playwright.chromium, playwright.firefox or playwright.webkit -# Pass headless=False to launch() to see the browser UI ->>> browser = playwright.chromium.launch() ->>> page = browser.new_page() ->>> page.goto("http://whatsmyuseragent.org/") ->>> page.screenshot(path="example.png") ->>> browser.close() ->>> playwright.stop() -``` - -Async REPL such as `asyncio` REPL: - -```bash -python -m asyncio -``` - -```py ->>> from playwright.async_api import async_playwright ->>> playwright = await async_playwright().start() ->>> browser = await playwright.chromium.launch() ->>> page = await browser.new_page() ->>> await page.goto("http://whatsmyuseragent.org/") ->>> await page.screenshot(path="example.png") ->>> await browser.close() ->>> await playwright.stop() -``` - -## Pyinstaller - -You can use Playwright with [Pyinstaller](https://www.pyinstaller.org/) to create standalone executables. - -```py -# main.py -from playwright.sync_api import sync_playwright - -with sync_playwright() as p: - browser = p.chromium.launch() - page = browser.new_page() - page.goto("http://whatsmyuseragent.org/") - page.screenshot(path="example.png") - browser.close() -``` - -If you want to bundle browsers with the executables: - -```bash tab=bash-bash -PLAYWRIGHT_BROWSERS_PATH=0 playwright install chromium -pyinstaller -F main.py -``` - -```batch tab=bash-batch -set PLAYWRIGHT_BROWSERS_PATH=0 -playwright install chromium -pyinstaller -F main.py -``` - -```powershell tab=bash-powershell -$env:PLAYWRIGHT_BROWSERS_PATH="0" -playwright install chromium -pyinstaller -F main.py -``` - -:::note -Bundling the browsers with the executables will generate bigger binaries. -It is recommended to only bundle the browsers you use. -::: - -## Known issues - -### `time.sleep()` leads to outdated state - -You should use `page.wait_for_timeout(5000)` instead of `time.sleep(5)` and it is better to not wait for a timeout at all, but sometimes it is useful for debugging. In these cases, use our wait method instead of the `time` module. This is because we internally rely on asynchronous operations and when using `time.sleep(5)` they can't get processed correctly. - - -### incompatible with `SelectorEventLoop` of `asyncio` on Windows - -Playwright runs the driver in a subprocess, so it requires `ProactorEventLoop` of `asyncio` on Windows because `SelectorEventLoop` does not supports async subprocesses. - -On Windows Python 3.7, Playwright sets the default event loop to `ProactorEventLoop` as it is default on Python 3.8+. - -### Threading - -Playwright's API is not thread-safe. If you are using Playwright in a multi-threaded environment, you should create a playwright instance per thread. See [threading issue](https://github.com/microsoft/playwright-python/issues/623) for more details. - - -## System requirements - -Playwright requires Python 3.7 or above. The browser binaries for Chromium, -Firefox and WebKit work across the 3 platforms (Windows, macOS, Linux): - -### Windows - -Works with Windows and Windows Subsystem for Linux (WSL). - -### macOS - -Requires 11 (Big Sur) or above. - -### Linux - -Depending on your Linux distribution, you might need to install additional -dependencies to run the browsers. - -:::note -Only Ubuntu 18.04, 20.04, and 22.04 are officially supported. -::: - -See also in the [Command line tools](./cli.md#install-system-dependencies) -which has a command to install all necessary dependencies automatically for Ubuntu -LTS releases. +- [Write tests using web first assertions, page fixtures and locators](./writing-tests.md) +- [Run single tests, multiple tests, headed mode](./running-tests.md) +- [Debug tests with the Playwright Debugger](./debug.md) +- [Generate tests with Codegen](./codegen.md) +- [See a trace of your tests](./trace-viewer.md) diff --git a/docs/src/library-python.md b/docs/src/library-python.md new file mode 100644 index 0000000000..00ee682a07 --- /dev/null +++ b/docs/src/library-python.md @@ -0,0 +1,206 @@ +--- +id: library +title: "Library" +--- + +## Installation + +### Pip + +[![PyPI version](https://badge.fury.io/py/playwright.svg)](https://pypi.python.org/pypi/playwright/) + +```bash +pip install --upgrade pip +pip install playwright +playwright install +``` + +### Conda + +[![Anaconda version](https://img.shields.io/conda/v/microsoft/playwright)](https://anaconda.org/Microsoft/playwright) + +```bash +conda config --add channels conda-forge +conda config --add channels microsoft +conda install playwright +playwright install +``` + +These commands download the Playwright package and install browser binaries for Chromium, Firefox and WebKit. To modify this behavior see [installation parameters](./browsers.md#installing-browsers). + +## Usage + +Once installed, you can `import` Playwright in a Python script, and launch any of the 3 browsers (`chromium`, `firefox` and `webkit`). + +```py +from playwright.sync_api import sync_playwright + +with sync_playwright() as p: + browser = p.chromium.launch() + page = browser.new_page() + page.goto("http://playwright.dev") + print(page.title()) + browser.close() +``` + +Playwright supports two variations of the API: synchronous and asynchronous. If your modern project uses [asyncio](https://docs.python.org/3/library/asyncio.html), you should use async API: + +```py +import asyncio +from playwright.async_api import async_playwright + +async def main(): + async with async_playwright() as p: + browser = await p.chromium.launch() + page = await browser.new_page() + await page.goto("http://playwright.dev") + print(await page.title()) + await browser.close() + +asyncio.run(main()) +``` + +## First script + +In our first script, we will navigate to `whatsmyuseragent.org` and take a screenshot in WebKit. + +```py +from playwright.sync_api import sync_playwright + +with sync_playwright() as p: + browser = p.webkit.launch() + page = browser.new_page() + page.goto("http://whatsmyuseragent.org/") + page.screenshot(path="example.png") + browser.close() +``` + +By default, Playwright runs the browsers in headless mode. To see the browser UI, pass the `headless=False` flag while launching the browser. You can also use [`option: slowMo`] to slow down execution. Learn more in the debugging tools [section](./debug.md). + +```py +firefox.launch(headless=False, slow_mo=50) +``` + +## Interactive mode (REPL) + +You can launch the interactive python REPL: + +```bash +python +``` + +and then launch Playwright within it for quick experimentation: + +```py +>>> from playwright.sync_api import sync_playwright +>>> playwright = sync_playwright().start() +# Use playwright.chromium, playwright.firefox or playwright.webkit +# Pass headless=False to launch() to see the browser UI +>>> browser = playwright.chromium.launch() +>>> page = browser.new_page() +>>> page.goto("http://whatsmyuseragent.org/") +>>> page.screenshot(path="example.png") +>>> browser.close() +>>> playwright.stop() +``` + +Async REPL such as `asyncio` REPL: + +```bash +python -m asyncio +``` + +```py +>>> from playwright.async_api import async_playwright +>>> playwright = await async_playwright().start() +>>> browser = await playwright.chromium.launch() +>>> page = await browser.new_page() +>>> await page.goto("http://whatsmyuseragent.org/") +>>> await page.screenshot(path="example.png") +>>> await browser.close() +>>> await playwright.stop() +``` + +## Pyinstaller + +You can use Playwright with [Pyinstaller](https://www.pyinstaller.org/) to create standalone executables. + +```py +# main.py +from playwright.sync_api import sync_playwright + +with sync_playwright() as p: + browser = p.chromium.launch() + page = browser.new_page() + page.goto("http://whatsmyuseragent.org/") + page.screenshot(path="example.png") + browser.close() +``` + +If you want to bundle browsers with the executables: + +```bash tab=bash-bash +PLAYWRIGHT_BROWSERS_PATH=0 playwright install chromium +pyinstaller -F main.py +``` + +```batch tab=bash-batch +set PLAYWRIGHT_BROWSERS_PATH=0 +playwright install chromium +pyinstaller -F main.py +``` + +```powershell tab=bash-powershell +$env:PLAYWRIGHT_BROWSERS_PATH="0" +playwright install chromium +pyinstaller -F main.py +``` + +:::note +Bundling the browsers with the executables will generate bigger binaries. +It is recommended to only bundle the browsers you use. +::: + +## Known issues + +### `time.sleep()` leads to outdated state + +Most likely you don't need to wait manually, since Playwright has [auto-waiting](./actionability.md). If you still rely on it, you should use `page.wait_for_timeout(5000)` instead of `time.sleep(5)` and it is better to not wait for a timeout at all, but sometimes it is useful for debugging. In these cases, use our wait (`wait_for_timeout`) method instead of the `time` module. This is because we internally rely on asynchronous operations and when using `time.sleep(5)` they can't get processed correctly. + + +### incompatible with `SelectorEventLoop` of `asyncio` on Windows + +Playwright runs the driver in a subprocess, so it requires `ProactorEventLoop` of `asyncio` on Windows because `SelectorEventLoop` does not supports async subprocesses. + +On Windows Python 3.7, Playwright sets the default event loop to `ProactorEventLoop` as it is default on Python 3.8+. + +### Threading + +Playwright's API is not thread-safe. If you are using Playwright in a multi-threaded environment, you should create a playwright instance per thread. See [threading issue](https://github.com/microsoft/playwright-python/issues/623) for more details. + + +## System requirements + +Playwright requires Python 3.7 or above. The browser binaries for Chromium, +Firefox and WebKit work across the 3 platforms (Windows, macOS, Linux): + +### Windows + +Works with Windows and Windows Subsystem for Linux (WSL). + +### macOS + +Requires 11 (Big Sur) or above. + +### Linux + +Depending on your Linux distribution, you might need to install additional +dependencies to run the browsers. + +:::note +Only Ubuntu 18.04, 20.04, and 22.04 are officially supported. +::: + +See also in the [Command line tools](./cli.md#install-system-dependencies) +which has a command to install all necessary dependencies automatically for Ubuntu +LTS releases. diff --git a/docs/src/running-tests-python.md b/docs/src/running-tests-python.md new file mode 100644 index 0000000000..6429135434 --- /dev/null +++ b/docs/src/running-tests-python.md @@ -0,0 +1,56 @@ +--- +id: running-tests +title: "Running Tests" +--- + +You can run a single test, a set of tests or all tests. Tests can be run on one browser or multiple browsers. By default tests are run in a headless manner meaning no browser window will be opened while running the tests and results will be seen in the terminal. If you prefer you can run your tests in headed mode by using the `--headed` flag. + +- Running tests on Chromium + + ```bash + pytest + ``` + +- Running a single test file + + ```bash + pytest test_login.py + ``` + +- Run a set of test files + + ```bash + pytest tests/todo-page/ tests/landing-page/ + ``` + +- Run the test with the function name + + ```bash + pytest -k "test_add_a_todo_item" + ``` + +- Running tests in headed mode + + ```bash + pytest --headed test_login.py + ``` + +- Running Tests on specific browsers + + ```bash + pytest test_login.py --browser webkit + ``` + +- Running Tests on multiple browsers + + ```bash + pytest test_login.py --browser webkit --browser firefox + ``` + +For more information see [Playwright Pytest usage](./test-runners.md) or the Pytest documentation for [general CLI usage](https://docs.pytest.org/en/stable/usage.html). + +## What's Next + +- [Debug tests with the Playwright Debugger](./debug.md) +- [Generate tests with Codegen](./codegen.md) +- [See a trace of your tests](./trace-viewer.md) \ No newline at end of file diff --git a/docs/src/test-runners-python.md b/docs/src/test-runners-python.md index d417d06f78..c912e8d8fe 100644 --- a/docs/src/test-runners-python.md +++ b/docs/src/test-runners-python.md @@ -1,42 +1,16 @@ --- id: test-runners -title: "Pytest plugin" +title: "Pytest Plugin Reference" --- -Write end-to-end tests for your web apps with [Pytest](https://docs.pytest.org/en/stable/). - - +Playwright provides a [Pytest](https://docs.pytest.org/en/stable/) plugin to write end-to-end tests. To get started with it, refer to the [getting started guide](./intro.md). ## Usage -```bash -pip install pytest-playwright -``` - -Use the `page` fixture to write a basic test. See [more examples](#examples). - -```py -# test_my_application.py -def test_example_is_working(page): - page.goto("https://example.com") - assert page.inner_text('h1') == 'Example Domain' - page.locator("text=More information").click() -``` - -To run your tests, use pytest CLI. +To run your tests, use [Pytest](https://docs.pytest.org/en/stable/) CLI. ```bash -# Run tests (Chromium and headless by default) -pytest - -# Run tests in headed mode -pytest --headed - -# Run tests in a different browser (chromium, firefox, webkit) -pytest --browser firefox - -# Run tests in multiple browsers -pytest --browser chromium --browser webkit +pytest --browser webkit --headedd ``` If you want to add the CLI arguments automatically without specifying them, you can use the [pytest.ini](https://docs.pytest.org/en/stable/reference.html#ini-options-ref) file: diff --git a/docs/src/writing-tests-csharp.md b/docs/src/writing-tests-csharp.md index 9f76fd5c03..0acf259b66 100644 --- a/docs/src/writing-tests-csharp.md +++ b/docs/src/writing-tests-csharp.md @@ -3,9 +3,9 @@ id: writing-tests title: "Writing Tests" --- -Playwright assertions are created specifically for the dynamic web. Checks are automatically retried until the necessary conditions are met. Playwright comes with auto-wait built in meaning it waits for elements to be actionable prior to performing actions. Playwright provides the [Expect](./test-assertions) function to write assertions. +Playwright assertions are created specifically for the dynamic web. Checks are automatically retried until the necessary conditions are met. Playwright comes with [auto-wait](./actionability.md) built in meaning it waits for elements to be actionable prior to performing actions. Playwright provides the [Expect](./test-assertions) function to write assertions. -Take a look at the example test to see how to write a test using web first assertions, locators and selectors. +Take a look at the example test below to see how to write a test using web first assertions, locators and selectors.