Skip to content
Merged

uv #196

Show file tree
Hide file tree
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
4 changes: 1 addition & 3 deletions .github/workflows/devRun.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: psf/black@stable
- uses: isort/isort-action@v1
- name: Set up Python
uses: actions/setup-python@v5
with:
Expand All @@ -23,7 +21,7 @@ jobs:
- name: Create venv & install dependencies
run: |
uv venv
uv pip sync uv.lock
uv sync --all-extras --dev
- name: Install Playwright Browsers
run: |
PLAYWRIGHT_VERSION=$(grep -E '^playwright = "[^"]*"' pyproject.toml | sed -E 's/playwright = "([^"]*)".*$/\1/')
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
- name: Create venv & install dependencies
run: |
uv venv
uv pip sync uv.lock
uv sync --all-extras --dev
- name: Install Playwright Browsers
run: |
PLAYWRIGHT_VERSION=$(grep -E '^playwright = "[^"]*"' pyproject.toml | sed -E 's/playwright = "([^"]*)".*$/\1/')
Expand Down
40 changes: 10 additions & 30 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,33 +35,14 @@ repos:
- id: conventional-pre-commit
stages: [commit-msg]
args: []
- repo: https://github.com/psf/black
rev: 25.1.0
hooks:
- id: black
language_version: python3
args: [ '--config', 'pyproject.toml' ]
- repo: https://github.com/PyCQA/autoflake
rev: v2.3.1
hooks:
- id: autoflake
args:
[
'--in-place',
'--remove-unused-variable',
'--remove-all-unused-imports',
'--expand-star-imports',
'--ignore-init-module-imports',
]
- repo: https://github.com/PyCQA/isort
rev: 6.0.1
hooks:
- id: isort
args: [ '--settings-file', 'pyproject.toml' ]
- repo: https://github.com/asottile/pyupgrade
rev: v3.19.1
hooks:
- id: pyupgrade
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.4
hooks:
- id: ruff
args: [ --fix ]
continue_on_error: true
- id: ruff-format
continue_on_error: true
- repo: https://github.com/codespell-project/codespell
rev: v2.4.1
hooks:
Expand All @@ -72,11 +53,10 @@ repos:
rev: v0.24.1
hooks:
- id: validate-pyproject
# Optional extra validations from SchemaStore:
additional_dependencies: [ "validate-pyproject-schema-store[all]" ]
additional_dependencies: ["validate-pyproject-schema-store[all]"]
- repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks
rev: v2.14.0
hooks:
- id: pretty-format-toml
exclude: poetry.lock
args: [ --autofix ]
args: [--autofix]
10 changes: 5 additions & 5 deletions .github/README.md → README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
![YouTube Channel](https://img.shields.io/youtube/channel/subscribers/UCQjS-eoKl0a1nuP_dvpLsjQ?label=YouTube%20Channel)
![dev run](https://github.com/nirtal85/Playwright-Python-Example/actions/workflows/devRun.yml/badge.svg)
![nightly](https://github.com/nirtal85/Playwright-Python-Example/actions/workflows/nightly.yml/badge.svg)
[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)

## 📃 Articles written about this project

Expand Down Expand Up @@ -50,15 +50,15 @@ cd playwright-python
pip install uv
uv venv
.\env\Scripts\activate
uv pip sync uv.lock
uv sync --all-extras --dev
```

#### For Mac:
```bash
python3 -m pip install uv
uv venv
source .venv/bin/activate
uv pip sync uv.lock
source .venv/bin/activate
uv sync --all-extras --dev
```

### Install playwright
Expand Down
76 changes: 45 additions & 31 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,48 +1,47 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "playwright-python"
version = "0.1.0"
description = "Playwright Python example project with pytest and Allure report"
authors = [{ name = "nirtal85", email = "nirt236@gmail.com" }]
requires-python = "~=3.11"
readme = "README.md"
keywords = [
"playwright",
"automation",
"testing",
"web",
]
dependencies = [
"allure-pytest==2.13.5",
"axe-playwright-python==0.1.4",
"playwright==1.51.0",
"pytest==8.3.5",
"pytest-base-url==2.1.0",
"pytest-playwright==0.7.0",
"pytest-split==0.10.0",
"requests==2.32.3",
]
requires = ["hatchling"]

[dependency-groups]
dev = [
"black==25.1.0",
"isort==6.0.1",
"pre-commit==4.2.0",
"ruff==0.11.4",
"pre-commit==4.2.0"
]

[tool.isort]
profile = "black"
skip = ["env", "venv"]
[project]
authors = [{name = "nirtal85", email = "nirt236@gmail.com"}]
dependencies = [
"allure-pytest==2.13.5",
"axe-playwright-python==0.1.4",
"playwright==1.51.0",
"pytest==8.3.5",
"pytest-base-url==2.1.0",
"pytest-playwright==0.7.0",
"pytest-split==0.10.0",
"requests==2.32.3"
]
description = "Playwright Python example project with pytest and Allure report"
keywords = [
"playwright",
"automation",
"testing",
"web"
]
name = "playwright-python"
readme = "README.md"
requires-python = "~=3.11"
version = "0.1.0"

[tool.hatch.build.targets.sdist]
include = ["playwright_python"]

[tool.hatch.build.targets.wheel]
include = ["playwright_python"]

[tool.isort]
profile = "black"
skip = ["env", "venv"]

[tool.pytest.ini_options]
addopts = [
"--clean-alluredir",
Expand All @@ -68,3 +67,18 @@ log_cli_level = "INFO"
markers = [
"devRun: marks tests that run before merge to the main branch"
]

[tool.ruff]
exclude = [".venv", "env"]
ignore = [
"D203", # One blank line required before class docstring (conflicts with D211)
"D213", # Multi-line docstring summary should start at the second line
"COM812"
]
line-length = 100
select = ["ALL"]
target-version = "py311"

[tool.ruff.format]
docstring-code-format = true
quote-style = "double"
1 change: 0 additions & 1 deletion tests/accesability_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@


class TestAccessibility:

@allure.title("Test Accessibility with Default Counts")
def test_accessibility_default_counts(self, axe_playwright, page):
axe_playwright.check_accessibility(page)
Expand Down
5 changes: 1 addition & 4 deletions tests/checkout_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@


class TestCheckout:

@pytest.mark.parametrize(
"browser_context_args", [User.STANDARD_USER], indirect=True
)
@pytest.mark.parametrize("browser_context_args", [User.STANDARD_USER], indirect=True)
def test_checkout_counter(self, browser_context_args, page: Page):
page.evaluate("localStorage.setItem('cart-contents', '[4,0]');")
page.reload()
Expand Down
19 changes: 12 additions & 7 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from typing import Dict

import allure
import pytest
import requests
Expand Down Expand Up @@ -27,6 +25,7 @@ def goto(page: Page, request: SubRequest):

Example:
@pytest.mark.parametrize('browser_context_args', ["standard_user"], indirect=True)

"""
if request.getfixturevalue("browser_context_args").get("storage_state"):
page.goto("/inventory.html")
Expand All @@ -43,27 +42,29 @@ def axe_playwright():

Returns:
AxeHelper: An instance of AxeHelper with Axe initialized.

"""
yield AxeHelper(Axe())
return AxeHelper(Axe())


@pytest.fixture(scope="function")
def browser_context_args(
browser_context_args: Dict, base_url: str, request: SubRequest
):
def browser_context_args(browser_context_args: dict, base_url: str, request: SubRequest) -> dict:
"""This fixture allows setting browser context arguments for Playwright.

Args:
browser_context_args (dict): Base browser context arguments.
request (SubRequest): Pytest request object to get the 'browser_context_args' fixture value.
base_url (str): The base URL for the application under test.

Returns:
dict: Updated browser context arguments.

See Also:
https://playwright.dev/python/docs/api/class-browser#browser-new-contex

Returns:
dict: Updated browser context arguments.

"""
context_args = {
**browser_context_args,
Expand All @@ -85,7 +86,7 @@ def browser_context_args(


@pytest.fixture(scope="session")
def browser_type_launch_args(browser_type_launch_args: Dict, playwright: Playwright):
def browser_type_launch_args(browser_type_launch_args: dict, playwright: Playwright) -> dict:
"""Fixture to set browser launch arguments.

This fixture updates the browser launch arguments to start the browser maximized
Expand All @@ -103,6 +104,7 @@ def browser_type_launch_args(browser_type_launch_args: Dict, playwright: Playwri

See Also:
https://playwright.dev/python/docs/api/class-browsertype#browser-type-launch

"""
playwright.selectors.set_test_id_attribute("data-test")
return {**browser_type_launch_args, "args": ["--start-maximized"]}
Expand All @@ -113,6 +115,7 @@ def get_public_ip() -> str:

Returns:
str: Public IP address.

"""
return requests.get(
"http://checkip.amazonaws.com",
Expand All @@ -129,6 +132,7 @@ def attach_playwright_results(page: Page, request: FixtureRequest):
Args:
page (Page): Playwright page object.
request: Pytest request object.

"""
yield
if request.node.rep_call.failed:
Expand Down Expand Up @@ -158,6 +162,7 @@ def pytest_runtest_makereport(item: Item):

Yields:
Outcome of the test execution.

"""
outcome = yield
rep = outcome.get_result()
Expand Down
5 changes: 1 addition & 4 deletions tests/inventory_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@


class TestInventory:

@pytest.mark.parametrize(
"browser_context_args", [User.STANDARD_USER], indirect=True
)
@pytest.mark.parametrize("browser_context_args", [User.STANDARD_USER], indirect=True)
def test_inventory_page(self, browser_context_args, page: Page):
expect(page.get_by_test_id("title")).to_have_text("Products")
4 changes: 1 addition & 3 deletions tests/login_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ def test_valid_login(self, base_url, page: Page):
ids=["invalid_password", "locked_user"],
)
@allure.title("Login with invalid credentials test")
def test_login_error(
self, page: Page, username: str, password: str, expected_error: str
):
def test_login_error(self, page: Page, username: str, password: str, expected_error: str):
self.login_page.login(username, password)
expect(self.login_page.error_message).to_have_text(expected_error)
11 changes: 3 additions & 8 deletions utilities/axe_helper.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
import json
from collections import Counter
from typing import Dict

import allure
from axe_playwright_python.sync_playwright import Axe
from playwright.sync_api import Page


class AxeHelper:

def __init__(self, axe: Axe):
self.axe = axe

def check_accessibility(
self, page: Page, maximum_allowed_violations_by_impact: Dict[str, int] = None
self, page: Page, maximum_allowed_violations_by_impact: dict[str, int] = None
Comment on lines 13 to +14
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improved type hinting with modern syntax

The change from Dict[str, int] to dict[str, int] is appropriate and follows modern Python typing practices (Python 3.9+) where built-in container types can be used directly as type annotations.

However, there's a static analysis issue to fix:

- def check_accessibility(
-     self, page: Page, maximum_allowed_violations_by_impact: dict[str, int] = None
+ def check_accessibility(
+     self, page: Page, maximum_allowed_violations_by_impact: dict[str, int] | None = None

This change addresses the warning about implicit Optional types and makes the parameter typing more explicit.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def check_accessibility(
self, page: Page, maximum_allowed_violations_by_impact: Dict[str, int] = None
self, page: Page, maximum_allowed_violations_by_impact: dict[str, int] = None
def check_accessibility(
self, page: Page, maximum_allowed_violations_by_impact: dict[str, int] | None = None
🧰 Tools
🪛 Ruff (0.8.2)

14-14: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)

) -> None:
"""Checks accessibility of the page using playwright axe.

Expand All @@ -33,15 +31,12 @@ def check_accessibility(
}
results = self.axe.run(page)
violations_count = dict(
Counter(
[violation["impact"] for violation in results.response["violations"]]
)
Counter([violation["impact"] for violation in results.response["violations"]])
)
if violations_exceeded := {
impact_level: violation_count
for impact_level, violation_count in violations_count.items()
if violation_count
> maximum_allowed_violations_by_impact.get(impact_level, 0)
if violation_count > maximum_allowed_violations_by_impact.get(impact_level, 0)
}:
allure.attach(
body=json.dumps(results.response["violations"], indent=4),
Expand Down
Loading