Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 64 additions & 20 deletions docs/6-software-development-practices/6.5.2-functional-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,45 +29,89 @@ Functional tests are written from a user’s perspective. That is, you should be

## Example

One popular tool for functional testing website and web applications is Selenium. Selenium is a portable framework for browser automation. Selenium allows you to write declarative tests that programmatically interact with a website, checking functionality. This can be extremely helpful automating tests, allowing the same tests to be performed using all popular browsers.
One popular tool for functional testing of websites and web applications is Playwright. Playwright is an open-source framework for browser automation. It allows you to write tests that programmatically interact with a website, checking functionality. This is extremely helpful in automating tests, as the same tests can be performed across all major browsers.

An example of a use-case for Selenium would be testing a web application’s login form. Where a unit test might check that the email field only accepts valid email addresses, a functional test using Selenium might check that logging in with a valid email and password results in the user being logged in.
An example use case of Playwright is testing a web application’s login form. While a unit test might check that the email field only accepts valid email addresses, a functional test using Playwright could verify that logging in with a valid email and password successfully logs the user in.

## Exercise 1:

We will use Selenium and Python to run a couple functional tests on the bootcamp website.
We'll use Playwright and pytest to run functional tests. This approach is popular for its modern features, speed, and reliability. We'll manage our project's dependencies with uv.We're going to take this opportunity to introduce you to `uv` [\(docs\)](https://docs.astral.sh/uv/), a python tool somewhat similar to `npm` in the JavaScript ecosystem.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like there's a space missing between "uv." and "We're going to take..."

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
We'll use Playwright and pytest to run functional tests. This approach is popular for its modern features, speed, and reliability. We'll manage our project's dependencies with uv.We're going to take this opportunity to introduce you to `uv` [\(docs\)](https://docs.astral.sh/uv/), a python tool somewhat similar to `npm` in the JavaScript ecosystem.
We'll use Playwright and pytest to run functional tests. This approach is popular for its modern features, speed, and reliability. We'll manage our project's dependencies with `uv`. We're going to take this opportunity to introduce you to `uv` [\(docs\)](https://docs.astral.sh/uv/), a python tool somewhat similar to `npm` in the JavaScript ecosystem.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
We'll use Playwright and pytest to run functional tests. This approach is popular for its modern features, speed, and reliability. We'll manage our project's dependencies with uv.We're going to take this opportunity to introduce you to `uv` [\(docs\)](https://docs.astral.sh/uv/), a python tool somewhat similar to `npm` in the JavaScript ecosystem.
We'll use Playwright and pytest to run functional tests. This approach is popular for its modern features, speed, and reliability. We'll also take this opportunity to introduce you to `uv` [\(docs\)](https://docs.astral.sh/uv/), a python tool for managing dependencies, somewhat similar to `npm` in the JavaScript ecosystem.


1. Install a Selenium WebDriver of your choice
* Firefox - `brew install geckodriver`
* Chrome - `brew install chromedriver --cask`
* Safari - built in
2. Install the [Selenium Python bindings](https://pypi.org/project/selenium/)
`uv` allows you to manage a python projects dependencies in a declarative manner (like `pip`), set up virtual python environments, declare required python versions, and more.

1. Set up Your Project
First, install uv (a fast Python package manager).

`brew install uv`

Next, create a project directory and initialize a virtual environment with uv.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Next, create a project directory and initialize a virtual environment with uv.
Next, create a project directory and initialize a virtual environment with `uv`.


Read through the [Selenium Getting Started page](https://selenium-python.readthedocs.io/getting-started.html) to get a brief introduction on how to use Selenium.
`mkdir playwright-tests`

?> If you are getting an error when trying to install the Selenium Python bindings, look into [installing the packages in a virtual environment](https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/).
`cd playwright-tests`

3. Use the starter code provided to test
`uv init`

2. Add Dependencies
Use uv to add Playwright and its pytest plugin to your project.
`uv add playwright pytest-playwright`

3. Install Browser Drivers
Playwright requires its own browser binaries. Install them by running:
`uv run playwright install`

4. Use the starter code provided to test
* The link in the bottom right corner of the homepage takes you to [the bootcamp introduction](https://devops-bootcamp.liatr.io/#/1-introduction/1.0-overview)
* The sidebar toggle button properly hides the sidebar

?> Note: the starter code has Firefox selected as the driver. Make sure to either change it or install geckodriver.
```python
import re
from playwright.sync_api import Page, expect

BASE_URL = "https://devops-bootcamp.liatr.io"

[document](https://raw.githubusercontent.com/PaulDHenson/devops-bootcamp/master/examples/codeQuality/selenium-frame.py ':include :type=code python')
def test_bootcamp_link(page: Page):
"""Tests that the 'Introduction to DevOps' link navigates correctly."""
# go to the bootcamp site
page.goto(BASE_URL)

# check we get expected page title
expect(page).to_have_title(re.compile("Welcome"))

# find the link to Introduction to DevOps section
page.get_by_role("link", name=re.compile("Introduction to DevOps")).first.click()

# check that we get the expected url
expect(page).to_have_url(re.compile(".*/1-introduction/.*"))

def test_bootcamp_sidebar(page: Page):
"""Tests that the sidebar toggle button works correctly."""
# go to the bootcamp site
page.goto(BASE_URL)

# check that the sidebar is shown (HINT: check html body attributes)
body = page.locator("body")
expect(body).not_to_have_attribute("class", re.compile("close"))

# find the sidebar toggle and toggle it
toggle_button = page.locator(".sidebar-toggle").first
toggle_button.click()

# after toggling sidebar, check that it is closed
expect(body).to_have_attribute("class", re.compile("close"))
```
Comment on lines +67 to +102
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```python
import re
from playwright.sync_api import Page, expect
BASE_URL = "https://devops-bootcamp.liatr.io"
[document](https://raw.githubusercontent.com/PaulDHenson/devops-bootcamp/master/examples/codeQuality/selenium-frame.py ':include :type=code python')
def test_bootcamp_link(page: Page):
"""Tests that the 'Introduction to DevOps' link navigates correctly."""
# go to the bootcamp site
page.goto(BASE_URL)
# check we get expected page title
expect(page).to_have_title(re.compile("Welcome"))
# find the link to Introduction to DevOps section
page.get_by_role("link", name=re.compile("Introduction to DevOps")).first.click()
# check that we get the expected url
expect(page).to_have_url(re.compile(".*/1-introduction/.*"))
def test_bootcamp_sidebar(page: Page):
"""Tests that the sidebar toggle button works correctly."""
# go to the bootcamp site
page.goto(BASE_URL)
# check that the sidebar is shown (HINT: check html body attributes)
body = page.locator("body")
expect(body).not_to_have_attribute("class", re.compile("close"))
# find the sidebar toggle and toggle it
toggle_button = page.locator(".sidebar-toggle").first
toggle_button.click()
# after toggling sidebar, check that it is closed
expect(body).to_have_attribute("class", re.compile("close"))
```
~~~python
import re
from playwright.sync_api import Page, expect
BASE_URL = "https://devops-bootcamp.liatr.io"
def test_bootcamp_link(page: Page):
"""Tests that the 'Introduction to DevOps' link navigates correctly."""
# go to the bootcamp site
page.goto(BASE_URL)
# check we get expected page title
expect(page).to_have_title(re.compile("Welcome"))
# IMPLEMENT find the link to Introduction to DevOps section
# IMPLEMENT check that we get the expected url
~~~
5. With just the starter code verify you can run the tests
6. Now we want to add another tests that verifies that the sidebar toggle works to toggle the visibility of the sidebar. Make sure you are writing good assertions to actually verify the behavior you are testing.
>? Playwright runs in headless mode by default. This is great for performance but can be challenging when developing. Explore the options `--headed` and `--slowmo`
**Challenge:** Modify your tests so that on any failure you capture a screenshot

Updates the fence to ~~~ b/c github suggestions uses ``` and things were messing up.

Good changes in general I just want this to be a little more hands on


While these are fairly trivial functional tests, they serve to show in general how they differ from unit tests.

## Exercise 2:

While Selenium is still in common use, [Playwright](https://playwright.dev/) is becoming more popular due to its ease of use. Furthermore, we're going to take this opportunity to introduce you to `uv` [\(docs\)](https://docs.astral.sh/uv/), a python tool somewhat similar to `npm` in the JavaScript ecosystem.
While [Playwright](https://playwright.dev/) is becoming more popular due to its ease of use,[Selenium](https://www.selenium.dev/) is still in common use.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
While [Playwright](https://playwright.dev/) is becoming more popular due to its ease of use,[Selenium](https://www.selenium.dev/) is still in common use.
While [Playwright](https://playwright.dev/) is becoming more popular due to its speed and ease of use, [Selenium](https://www.selenium.dev/) is still very common due to its large community, robust tool support and being established in this problem space. Both serve as functional testing frameworks though not unit testing frameworks.


`uv` allows you to manage a python projects dependencies in a declarative manner (like `pip`), set up virtual python environments, declare required python versions, and more.
1. Install a Selenium WebDriver of your choice.(`brew install geckodriver` for firefox.)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
1. Install a Selenium WebDriver of your choice.(`brew install geckodriver` for firefox.)
1. Install a Selenium WebDriver of your choice. (`brew install geckodriver` for firefox.)

2. Install the Selenium Python bindings.(`pip install selenium`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
2. Install the Selenium Python bindings.(`pip install selenium`)
2. Install the Selenium Python bindings. (`pip install selenium`)

3. Write the same tests from Exercise 1, but this time using Selenium.

1. Install uv (`brew install uv`)
2. Create a new directory, and run `uv init`
3. Add Playwright's [python library](https://playwright.dev/python/docs/intro) with `uv add playwright pytest-playwright`
4. As mentioned in Playwright's docs, you will need to install some playwright specific browser drivers. To do so with `uv`, instead of installing playwright globally, you can do `uv run playwright install`
5. Write the same tests from Exercise 1, but this time using playwright. You can run the tests with `uv run pytest`, and `uv` will automatically run the process in a context that has all of the needed dependencies.
?>While Selenium is more established,the tests you write with it serve the same role:functional testing,not unit testing.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
?>While Selenium is more established,the tests you write with it serve the same role:functional testing,not unit testing.

Consolidated the information in this tip with the opening paragraph.


# Deliverables

Expand Down