Skip to content
Merged
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
2 changes: 0 additions & 2 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 Down
49 changes: 11 additions & 38 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,14 @@ repos:
- id: check-xml
- id: end-of-file-fixer
- id: trailing-whitespace
- id: check-docstring-first
- id: name-tests-test
- id: file-contents-sorter
- id: pretty-format-json
args: [ --autofix ]
- id: check-ast
- id: check-builtin-literals
- id: check-case-conflict
- id: check-executables-have-shebangs
- id: check-merge-conflict
- id: check-shebang-scripts-are-executable
- id: debug-statements
- id: detect-private-key
- id: no-commit-to-branch
args: [ '--branch', 'main' ]
args: ['--branch', 'main']
- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.32.1
hooks:
Expand All @@ -35,33 +28,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 +46,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]
8 changes: 4 additions & 4 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/Selenium-Python-Example/actions/workflows/devRun.yml/badge.svg)
![nightly](https://github.com/nirtal85/Selenium-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)

<img height="100" width="100" src="https://cdn.simpleicons.org/selenium"/>

Expand Down Expand Up @@ -58,7 +58,7 @@ git clone https://github.com/nirtal85/Selenium-Python-Example.git
cd selenium-python-example
```

### Create and activate a virtual environment then Install project dependencies
### Create and activate a virtual environment then Install project dependencies

#### For Windows:
```bash
Expand All @@ -72,7 +72,7 @@ uv pip sync uv.lock
```bash
python3 -m pip install uv
uv venv
source .venv/bin/activate
source .venv/bin/activate
uv pip sync uv.lock
```

Expand Down
6 changes: 2 additions & 4 deletions pages/about_page.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from typing import Tuple

import allure
from selenium.webdriver.common.by import By

Expand All @@ -9,8 +7,8 @@
class AboutPage(BasePage):
"""About page - The first page that appears when navigating to base URL"""

LOGIN_LINK: Tuple[str, str] = (By.CSS_SELECTOR, ".login")
REGISTER_LINK: Tuple[str, str] = (By.CSS_SELECTOR, ".register")
LOGIN_LINK: tuple[str, str] = (By.CSS_SELECTOR, ".login")
REGISTER_LINK: tuple[str, str] = (By.CSS_SELECTOR, ".register")

def __init__(self, driver, wait):
super().__init__(driver, wait)
Expand Down
39 changes: 15 additions & 24 deletions pages/base_page.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
from typing import Tuple, Union

from deprecated import deprecated
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver import ActionChains, Chrome, Edge, Firefox
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.expected_conditions import (
StaleElementReferenceException,
)
from selenium.webdriver.support.expected_conditions import StaleElementReferenceException
from selenium.webdriver.support.wait import WebDriverWait


class BasePage:
"""Wrapper for selenium operations."""

def __init__(self, driver: Union[Chrome, Firefox, Edge], wait: WebDriverWait):
def __init__(self, driver: Chrome | Firefox | Edge, wait: WebDriverWait):
self.driver = driver
self.wait = wait

Expand All @@ -39,42 +35,39 @@ def set_geo_location(self, latitude: float, longitude: float) -> None:
"""Sets the geolocation for the web browser using the Chrome DevTools
Protocol (CDP).

Parameters:
Parameters
----------
- latitude (float): The latitude of the desired geolocation.
- longitude (float): The longitude of the desired geolocation.

Returns:
Returns
-------
None

Note:
This method uses the Chrome DevTools Protocol (CDP) to override the geolocation
in the web browser, allowing simulation of a specific geographic location for testing purposes.
The accuracy is set to 1 for simplicity in this method.

"""
self.driver.execute_cdp_cmd(
"Emulation.setGeolocationOverride",
{"latitude": latitude, "longitude": longitude, "accuracy": 1},
)

def click(self, locator: Tuple[str, str]) -> None:
el: WebElement = self.wait.until(
expected_conditions.element_to_be_clickable(locator)
)
def click(self, locator: tuple[str, str]) -> None:
el: WebElement = self.wait.until(expected_conditions.element_to_be_clickable(locator))
self._highlight_element(el, "green")
el.click()

def fill_text(self, locator: Tuple[str, str], txt: str) -> None:
el: WebElement = self.wait.until(
expected_conditions.element_to_be_clickable(locator)
)
def fill_text(self, locator: tuple[str, str], txt: str) -> None:
el: WebElement = self.wait.until(expected_conditions.element_to_be_clickable(locator))
el.clear()
self._highlight_element(el, "green")
el.send_keys(txt)

def clear_text(self, locator: Tuple[str, str]) -> None:
el: WebElement = self.wait.until(
expected_conditions.element_to_be_clickable(locator)
)
def clear_text(self, locator: tuple[str, str]) -> None:
el: WebElement = self.wait.until(expected_conditions.element_to_be_clickable(locator))
el.clear()

def scroll_to_bottom(self) -> None:
Expand All @@ -84,10 +77,8 @@ def submit(self, webelement: WebElement) -> None:
self._highlight_element(webelement, "green")
webelement.submit()

def get_text(self, locator: Tuple[str, str]) -> str:
el: WebElement = self.wait.until(
expected_conditions.visibility_of_element_located(locator)
)
def get_text(self, locator: tuple[str, str]) -> str:
el: WebElement = self.wait.until(expected_conditions.visibility_of_element_located(locator))
self._highlight_element(el, "green")
return el.text

Expand Down
12 changes: 5 additions & 7 deletions pages/forgot_password_page.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
from typing import Tuple

import allure
from selenium.webdriver.common.by import By

from pages.base_page import BasePage


class ForgotPasswordPage(BasePage):
EMAIL_FIELD: Tuple[str, str] = (By.CSS_SELECTOR, "[name=email]")
SEND_PASSWORD_RESET_LINK_BUTTON: Tuple[str, str] = (
EMAIL_FIELD: tuple[str, str] = (By.CSS_SELECTOR, "[name=email]")
SEND_PASSWORD_RESET_LINK_BUTTON: tuple[str, str] = (
By.CSS_SELECTOR,
"[type=submit]",
)
ERROR_MSG: Tuple[str, str] = (By.CSS_SELECTOR, ".alert-danger")
SUCCESS_MSG: Tuple[str, str] = (By.CSS_SELECTOR, ".alert-success")
PAGE_TITLE: Tuple[str, str] = (By.CSS_SELECTOR, ".e-form-heading")
ERROR_MSG: tuple[str, str] = (By.CSS_SELECTOR, ".alert-danger")
SUCCESS_MSG: tuple[str, str] = (By.CSS_SELECTOR, ".alert-success")
PAGE_TITLE: tuple[str, str] = (By.CSS_SELECTOR, ".e-form-heading")

def __init__(self, driver, wait):
super().__init__(driver, wait)
Expand Down
14 changes: 6 additions & 8 deletions pages/login_page.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from typing import Tuple

import allure
from selenium.webdriver.common.by import By

Expand All @@ -9,12 +7,12 @@
class LoginPage(TopMenuBar):
"""Login Page."""

USERNAME_FIELD: Tuple[str, str] = (By.CSS_SELECTOR, "input[type=email]")
PASSWORD_FIELD: Tuple[str, str] = (By.CSS_SELECTOR, "input[type=password]")
LOGIN_BUTTON: Tuple[str, str] = (By.CSS_SELECTOR, "button[type=submit]")
LOGIN_ERROR_MESSAGE: Tuple[str, str] = (By.CSS_SELECTOR, "div.alert-danger")
PAGE_TITLE: Tuple[str, str] = (By.CSS_SELECTOR, ".e-form-heading")
FORGOT_PASSWORD_LINK: Tuple[str, str] = (
USERNAME_FIELD: tuple[str, str] = (By.CSS_SELECTOR, "input[type=email]")
PASSWORD_FIELD: tuple[str, str] = (By.CSS_SELECTOR, "input[type=password]")
LOGIN_BUTTON: tuple[str, str] = (By.CSS_SELECTOR, "button[type=submit]")
LOGIN_ERROR_MESSAGE: tuple[str, str] = (By.CSS_SELECTOR, "div.alert-danger")
PAGE_TITLE: tuple[str, str] = (By.CSS_SELECTOR, ".e-form-heading")
FORGOT_PASSWORD_LINK: tuple[str, str] = (
By.CSS_SELECTOR,
"[href='https://app.involve.me/password/reset']",
)
Expand Down
12 changes: 5 additions & 7 deletions pages/project_edit_page.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from typing import Tuple

import allure
from selenium.webdriver.common.by import By

Expand All @@ -9,20 +7,20 @@
class ProjectEditPage(BasePage):
"""Project Edit page - the page where adding to and editing projects is done"""

_PROJECT_NAME_FIELD: Tuple[str, str] = (By.CSS_SELECTOR, "input#project-name")
_THANK_YOU_PAGE_TYPE_BUTTON: Tuple[str, str] = (
_PROJECT_NAME_FIELD: tuple[str, str] = (By.CSS_SELECTOR, "input#project-name")
_THANK_YOU_PAGE_TYPE_BUTTON: tuple[str, str] = (
By.CSS_SELECTOR,
"[for=select-single-outcome]",
)
_OUTCOME_PAGES_TYPE_BUTTON: Tuple[str, str] = (
_OUTCOME_PAGES_TYPE_BUTTON: tuple[str, str] = (
By.CSS_SELECTOR,
"[for=select-outcomes]",
)
_START_EDITING_BUTTON: Tuple[str, str] = (
_START_EDITING_BUTTON: tuple[str, str] = (
By.CSS_SELECTOR,
".swal-button.swal-button--confirm",
)
_SAVE_AND_EXIT_BUTTON: Tuple[str, str] = (By.CSS_SELECTOR, ".e-close.nav-link")
_SAVE_AND_EXIT_BUTTON: tuple[str, str] = (By.CSS_SELECTOR, ".e-close.nav-link")

def __init__(self, driver, wait):
super().__init__(driver, wait)
Expand Down
6 changes: 2 additions & 4 deletions pages/project_type_page.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from typing import Tuple

import allure
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
Expand All @@ -10,8 +8,8 @@
class ProjectTypePage(TopNavigateBar):
"""Project Type page - where one can choose which kind of templates to work with"""

_START_FROM_SCRATCH_BUTTON: Tuple[str, str] = (By.CSS_SELECTOR, ".blank div.icon")
_PROJECTS_BLOCK: Tuple[str, str] = (
_START_FROM_SCRATCH_BUTTON: tuple[str, str] = (By.CSS_SELECTOR, ".blank div.icon")
_PROJECTS_BLOCK: tuple[str, str] = (
By.CSS_SELECTOR,
"#app-layout div:nth-child(3) .title",
)
Expand Down
Loading