Skip to content

Commit d020dcb

Browse files
committed
Initial commit.
0 parents  commit d020dcb

27 files changed

+590
-0
lines changed

.github/workflows/ui-tests.yml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: UI Tests
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- initial
8+
pull_request:
9+
workflow_dispatch: # Manual trigger
10+
11+
jobs:
12+
ui-tests:
13+
runs-on: ubuntu-latest
14+
services:
15+
headless:
16+
image: browserless/chrome:latest
17+
options: >-
18+
--memory=2048m
19+
env:
20+
CONNECTION_TIMEOUT: "900000" # 15 minutes
21+
ports:
22+
# Opens tcp port 6379 on the host and service container
23+
- 3000:3000
24+
25+
steps:
26+
# Checkout the repository
27+
- name: Checkout code
28+
uses: actions/checkout@v3
29+
30+
# Set up Python environment
31+
- name: Set up Python
32+
uses: actions/setup-python@v4
33+
with:
34+
python-version: 3.12
35+
36+
# Install dependencies
37+
- name: Install dependencies
38+
run: pip install -r requirements.txt
39+
40+
# Set environment variables
41+
- name: Set environment variables
42+
run: |
43+
echo "SELENIUM_DRIVER_KIND=remote" >> $GITHUB_ENV
44+
echo "REMOTE_DRIVER_URL=http://127.0.0.1:3000" >> $GITHUB_ENV
45+
46+
# Run tests
47+
- name: Run UI tests
48+
run: pytest tests --html=test-reports/report.html --self-contained-html -vvv --junitxml=test-reports/report.xml
49+
env:
50+
FRONTEND_URL: ${{ vars.FRONTEND_URL }}
51+
52+
# Upload test reports
53+
- name: Upload test reports
54+
uses: actions/upload-artifact@v3
55+
with:
56+
name: test-reports
57+
path: test-reports/**

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.idea
2+
test-reports/
3+
__pycache__
4+
.DS_Store

Dockerfile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
FROM python:3.12-slim
2+
WORKDIR /app
3+
COPY requirements.txt .
4+
RUN pip install -r requirements.txt
5+
COPY . .
6+
CMD ["pytest", "tests", "--html=test-reports/report.html", "--self-contained-html", "-vvv"]

LICENSE

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Copyright 2024 Volodymyr Obrizan
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4+
5+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6+
7+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# Selenium + Python Template Project
2+
3+
Welcome to the Selenium + Python Template Project! This repository provides a well-structured, scalable framework for test automation using Selenium WebDriver and Python. It's designed to help you get started quickly and maintain your test automation efforts efficiently.
4+
5+
---
6+
7+
## 📋 Features
8+
9+
- **Modular Design**: Organized structure with reusable components like PageObjects and Test Data Factories.
10+
- **Scalability**: Easy to extend for larger projects.
11+
- **Integration-Ready**: Built-in support for integrating with APIs, CI/CD pipelines, and reporting tools.
12+
- **Cross-Browser Support**: Pre-configured WebDriver factory for managing multiple browsers.
13+
14+
---
15+
16+
## 🏗️ Project Structure
17+
18+
```plaintext
19+
selenium_python_template/
20+
├── .github/workflows/ui-tests.yml # GitHub Workflow
21+
├── pages/ # PageObject classes
22+
├── tests/ # Test scripts
23+
├── utils/ # Utility functions (e.g. text processing)
24+
├── data/ # Test data files (coming soon)
25+
├── test-reports/ # Test execution reports
26+
├── drivers/ # WebDriver binaries (optional)
27+
├── config/ # Configuration files (coming soon)
28+
├── requirements.txt # Python dependencies
29+
├── bitbucket-pipelines.yml # BitBucket Pipelines configuration
30+
└── conftest.py # Global fixtures
31+
```
32+
33+
## 🚀 Getting Started
34+
35+
### Prerequisites
36+
37+
* Python 3.9+
38+
* Google Chrome or Firefox or Safari to run & debug tests locally
39+
* pip (Python package installer)
40+
41+
### Installation
42+
43+
Clone the repository:
44+
45+
```bash
46+
git clone https://github.com/obrizan/selenium_python_template.git
47+
cd selenium_python_template
48+
```
49+
50+
51+
Create and activate virutal environment (optional, but recommended):
52+
53+
```bash
54+
python -m venv .venv
55+
56+
# On Windows:
57+
.venv\Scripts\activate
58+
59+
# On macOS/Linux:
60+
source .venv/bin/activate
61+
```
62+
63+
Install dependencies:
64+
65+
```bash
66+
pip install -r requirements.txt
67+
```
68+
69+
Set up WebDriver (optionally):
70+
71+
Download the appropriate WebDriver for your browser (ChromeDriver, GeckoDriver, etc.)
72+
Place it in the drivers/ directory or update your system PATH.
73+
74+
## ⚙️Configuration
75+
76+
Set environment variables:
77+
78+
| Variable | Description | Default |
79+
|----------------------|-----------------------------------------------------------------------|--------------------|
80+
| `SELENIUM_DRIVER_KIND` | Options: `remote`, `chrome`, `safari`, `firefox`. | `chrome` |
81+
| `REMOTE_DRIVER_URL` | Used when `SELENIUM_DRIVER_KIND=remote`. | `http://localhost:3000` |
82+
| `WINDOW_RESOLUTION` | Browser window resolution. Values are defined in `webdriver_factory.py` | `DESKTOP_1280X720` |
83+
84+
## 🧪 Running Tests
85+
Run all tests using pytest:
86+
87+
```bash
88+
pytest --html=test-reports/report.html --self-contained-html
89+
```
90+
91+
Specify a particular test file or function:
92+
93+
```bash
94+
pytest tests/test_example.py
95+
```
96+
97+
## 🛠️ Customization
98+
99+
* **Adding Pages:** Create new classes in pages/ to represent additional pages or components.
100+
* **Adding Tests:** Write test scripts in tests/ and use the pytest framework for execution.
101+
* **Configuration:** Update config/ files to customize browser, test data paths, and other settings.
102+
103+
## 📄 License
104+
This project is licensed under the MIT License. See the LICENSE file for details.
105+
106+
## 🙌 Contributing
107+
Contributions are welcome! If you'd like to improve this project, feel free to fork the repository and submit a pull request.
108+
109+
## 📞 Contact
110+
Have questions or suggestions? Reach out:
111+
112+
**Author:** Volodymyr Obrizan
113+
114+
**Email:** volodymyr.obrizan@gmail.com
115+
116+
Happy Testing! 🚀

bitbucket-pipelines.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
image: python:3.12-slim
2+
3+
definitions:
4+
services:
5+
headless:
6+
image: browserless/chrome:latest
7+
variables:
8+
# Connection timeout is a parameter that sets how long any session can run for.
9+
# This is in place to prevent scripts that don't clean up properly, or run into
10+
# errors that cause them to the app froze. The value of which can be set in milliseconds,
11+
# and defaults to 30000, or 30 seconds.
12+
# https://docs.browserless.io/docs/docker.html#connection-timeout
13+
CONNECTION_TIMEOUT: "900000"
14+
memory: 2048
15+
16+
pipelines:
17+
default:
18+
- step:
19+
name: UI Tests
20+
services:
21+
- headless
22+
caches:
23+
- pip
24+
script:
25+
- pip install -r requirements.txt
26+
- export SELENIUM_DRIVER_KIND=remote
27+
- export REMOTE_DRIVER_URL=http://localhost:3000
28+
- pytest tests --html=test-reports/report.html --self-contained-html -vvv --junitxml=test-reports/report.xml
29+
artifacts:
30+
- test-reports/**

conftest.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from typing import Generator
2+
3+
import pytest
4+
from selenium.webdriver.remote.webdriver import WebDriver
5+
6+
from webdriver_factory import get_driver
7+
8+
9+
@pytest.fixture(scope="module")
10+
def driver() -> Generator[WebDriver, None, None]:
11+
"""Returns initialized WedDriver instance."""
12+
drv = get_driver()
13+
yield drv
14+
drv.quit()

docker-compose.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
services:
2+
tests:
3+
build:
4+
context: .
5+
environment:
6+
SELENIUM_DRIVER_KIND: "remote"
7+
FRONTEND_URL: ${FRONTEND_URL}
8+
REMOTE_DRIVER_URL: "http://remote_driver:3000"
9+
# Adjust TZ to your timezone to get correct date/time in test reports.
10+
TZ: Europe/Kiev
11+
depends_on:
12+
- remote_driver
13+
networks:
14+
- selenium_template_python_network
15+
volumes:
16+
- test-reports:/app/test-reports
17+
18+
remote_driver:
19+
image: browserless/chrome:latest
20+
environment:
21+
CONNECTION_TIMEOUT: "900000"
22+
ports:
23+
- "3000:3000"
24+
networks:
25+
- selenium_template_python_network
26+
27+
28+
networks:
29+
selenium_template_python_network:
30+
driver: bridge
31+
32+
volumes:
33+
test-reports:
34+
driver: local
35+
driver_opts:
36+
type: none
37+
o: bind
38+
device: ./test-reports

pages/__init__.py

Whitespace-only changes.

pages/base_page.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import os
2+
from abc import abstractmethod, ABC
3+
4+
from selenium.webdriver.remote.webdriver import WebDriver
5+
6+
7+
class BasePage(ABC):
8+
def __init__(self, driver: WebDriver):
9+
self.driver = driver
10+
11+
@abstractmethod
12+
def wait_page_is_present(self) -> None:
13+
"""Implement in all children classes with an algorithm how to wait for complete page is loaded."""
14+
...
15+
16+
@abstractmethod
17+
def get_relative_url(self) -> str:
18+
"""Returns relative URL of the current page."""
19+
...
20+
21+
def open(self) -> None:
22+
self.driver.get(os.environ["FRONTEND_URL"] + self.get_relative_url())

0 commit comments

Comments
 (0)