|
| 1 | +# Part 1: Getting started |
| 2 | + |
| 3 | +Part 1 of the workshop explains how to start testing with Playwright and pytest in Python. |
| 4 | + |
| 5 | + |
| 6 | +## What is Playwright? |
| 7 | + |
| 8 | +[Playwright](https://playwright.dev/python/) is a new library that can automate interactions with Chromium, Firefox, and WebKit browsers via a single API. |
| 9 | +It is an open source project developed by Microsoft. |
| 10 | + |
| 11 | +Playwright is a fantastic alternative to [Selenium WebDriver](https://www.selenium.dev/) for web UI testing. |
| 12 | +Like Selenium WebDriver, Playwright has language bindings in multiple languages: Python, .NET, Java, and JavaScript. |
| 13 | +Playwright also refines many of the pain points in Selenium WebDriver. |
| 14 | +Some examples include: |
| 15 | + |
| 16 | +* Playwright interactions automatically wait for elements to be ready. |
| 17 | +* Playwright can use one browser instance with multiple browser contexts for isolation instead of requiring multiple instances. |
| 18 | +* Playwright has device emulation for testing responsive web apps in mobile browsers. |
| 19 | + |
| 20 | +For a more thorough list of advantages, check out |
| 21 | +[Why Playwright?](https://playwright.dev/python/docs/why-playwright/) |
| 22 | +from the docs. |
| 23 | + |
| 24 | + |
| 25 | +## Our web search test |
| 26 | + |
| 27 | +For this workshop, we will walk through one test scenario for DuckDuckGo searching. |
| 28 | +[DuckDuckGo](https://duckduckgo.com/) is a search engine like Google or Yahoo. |
| 29 | + |
| 30 | +The steps for a basic DuckDuckGo search are: |
| 31 | + |
| 32 | +```gherkin |
| 33 | +Given the DuckDuckGo home page is displayed |
| 34 | +When the user searches for a phrase |
| 35 | +Then the search result query is the phrase |
| 36 | +And the search result links pertain to the phrase |
| 37 | +And the search result title contains the phrase |
| 38 | +``` |
| 39 | + |
| 40 | +Go to [duckduckgo.com](https://duckduckgo.com/) and give this a try. |
| 41 | +You can use any search phrase you like. |
| 42 | +It is important to write a test *case* before writing test *code*. |
| 43 | +It is also important to try a test manually before attempting to automate it. |
| 44 | + |
| 45 | + |
| 46 | +## Test project setup |
| 47 | + |
| 48 | +Let's set up the test project! |
| 49 | +For this workshop, we will build a new project from the ground up. |
| 50 | +The GitHub repository should be used exclusively as a reference for example code. |
| 51 | + |
| 52 | +Create a directory named `tau-playwright-workshop` for the project: |
| 53 | + |
| 54 | +```bash |
| 55 | +$ mkdir tau-playwright-workshop |
| 56 | +$ cd tau-playwright-workshop |
| 57 | +``` |
| 58 | + |
| 59 | +Inside this project, create a [Python virtual environment](https://docs.python.org/3/tutorial/venv.html) |
| 60 | +using the [venv](https://docs.python.org/3/library/venv.html) module |
| 61 | +to manage dependency packages locally: |
| 62 | + |
| 63 | +```bash |
| 64 | +$ python3 -m venv venv |
| 65 | +$ source venv/bin/activate |
| 66 | +``` |
| 67 | + |
| 68 | +Creating a new virtual environment for each Python project is a recommended practice. |
| 69 | +This command will create a subdirectory named `venv` that holds all virtual environment files, including dependency packages. |
| 70 | +After creating a virtual environment, you must "activate" it to use it using the `source` command shown above. |
| 71 | +You can tell if a virtual environment is active if its name appears in the bash prompt. |
| 72 | + |
| 73 | +*A note about Python commands:* |
| 74 | +Python has two incompatible major versions: 2 and 3. |
| 75 | +Although Python 2 end-of-life was January 1, 2020, many machines still run it. |
| 76 | +For example, macOS comes bundled with Python 2.7.18. |
| 77 | +Sometimes, the `python` executable may point to Python 2 instead of 3. |
| 78 | +To be precise about versions and executables, we will use the `python3` and `pip3` commands explicitly in this workshop. |
| 79 | + |
| 80 | +Let's add some Python packages to our new virtual environment: |
| 81 | + |
| 82 | +```bash |
| 83 | +$ pip3 install playwright |
| 84 | +$ pip3 install pytest |
| 85 | +$ pip3 install pytest-playwright |
| 86 | +``` |
| 87 | + |
| 88 | +By itself, Playwright is simply a library for browser automation. |
| 89 | +We need a test framework like pytest if we want to automate tests. |
| 90 | +The [`pytest-playwright`](https://playwright.dev/python/docs/test-runners) |
| 91 | +is a pytest plugin developed by the Playwright team that simplifies Playwright integration. |
| 92 | + |
| 93 | +You can check all installed packages using `pip3 freeze`. |
| 94 | +They should look something like this: |
| 95 | + |
| 96 | +```bash |
| 97 | +$ pip3 freeze |
| 98 | +attrs==21.2.0 |
| 99 | +certifi==2021.10.8 |
| 100 | +charset-normalizer==2.0.8 |
| 101 | +greenlet==1.1.2 |
| 102 | +idna==3.3 |
| 103 | +iniconfig==1.1.1 |
| 104 | +packaging==21.3 |
| 105 | +playwright==1.17.0 |
| 106 | +pluggy==1.0.0 |
| 107 | +py==1.11.0 |
| 108 | +pyee==8.2.2 |
| 109 | +pyparsing==3.0.6 |
| 110 | +pytest==6.2.5 |
| 111 | +pytest-base-url==1.4.2 |
| 112 | +pytest-playwright==0.2.2 |
| 113 | +python-slugify==5.0.2 |
| 114 | +requests==2.26.0 |
| 115 | +text-unidecode==1.3 |
| 116 | +toml==0.10.2 |
| 117 | +urllib3==1.26.7 |
| 118 | +websockets==10.1 |
| 119 | +``` |
| 120 | + |
| 121 | +Notice that pip fetches dependencies of dependencies. |
| 122 | +It is customary for Python projects to store this list of dependencies in a file named `requirements.txt`. |
| 123 | + |
| 124 | +After the Python packages are installed, we need to install the browsers for Playwright. |
| 125 | +The `playwright install` command installs the latest versions of the three browsers that Playwright supports: |
| 126 | +Chromium, Firefox, and WebKit: |
| 127 | + |
| 128 | +```bash |
| 129 | +$ playwright install |
| 130 | +``` |
| 131 | + |
| 132 | +By default, pytest with the Playwright plugin will run headless Chromium. |
| 133 | +We will show how to run against other browsers in Part 5. |
| 134 | + |
| 135 | +Finally, let's create a test function stub. |
| 136 | +By Python conventions, all tests should be located under a `tests` directory. |
| 137 | +Create a `tests` directory, and inside, create a file named `test_search.py`: |
| 138 | + |
| 139 | +```bash |
| 140 | +$ mkdir tests |
| 141 | +$ touch tests/test_search.py |
| 142 | +``` |
| 143 | + |
| 144 | +Add the following code to `tests/test_search.py`: |
| 145 | + |
| 146 | +```python |
| 147 | +def test_basic_duckduckgo_search(): |
| 148 | + # Given the DuckDuckGo home page is displayed |
| 149 | + # When the user searches for a phrase |
| 150 | + # Then the search result query is the phrase |
| 151 | + # And the search result links pertain to the phrase |
| 152 | + # And the search result title contains the phrase |
| 153 | + pass |
| 154 | +``` |
| 155 | + |
| 156 | +The `test_basic_duckduckgo_search` is merely a stub, but it establishes good practices: |
| 157 | + |
| 158 | +* It has a clear name. |
| 159 | +* It defines the behavior to test step-by-step in its comments. |
| 160 | +* It can be run immediately. |
| 161 | + |
| 162 | +The `pass` statement at the end is just a no-op. |
| 163 | + |
| 164 | +Remember, write test *cases* before you write test *code*. |
| 165 | + |
| 166 | +Before continuing, run this test to make sure everything is set up correctly: |
| 167 | + |
| 168 | +```bash |
| 169 | +$ python3 -m pytest tests |
| 170 | +``` |
| 171 | + |
| 172 | +pytest should discover, run, and pass the single test case under the `tests` directory. |
| 173 | + |
| 174 | +*A note about the pytest command:* |
| 175 | +Many online articles and examples use the `pytest` command directly to run tests, like this: `pytest tests`. |
| 176 | +Unfortunately, this version of the command does **not** add the current directory to the Python path. |
| 177 | +If your tests reference anything outside of their test modules, then the command will fail. |
| 178 | +Therefore, I always recommend running the full `python3 -m pytest tests` command. |
0 commit comments