This guide describes the day-to-day development workflow for automation engineers working on Dexter.
| Branch | Purpose |
|---|---|
main |
Stable, always passing CI |
feature/<short-description> |
New features or tests |
fix/<short-description> |
Bug fixes |
chore/<short-description> |
Maintenance (deps, docs, config) |
Workflow:
# 1. Pull latest main
git checkout main && git pull
# 2. Create a feature branch
git checkout -b feature/add-order-sorting-tests
# 3. Make changes, commit often
git add .
git commit -m "test(api): add sorting validation for /api/orders"
# 4. Push and open a PR
git push -u origin feature/add-order-sorting-tests
Always run tests before pushing. Make sure your virtual environment is activated.
# All tests
pytest
# Only API tests
pytest -m api
# Only UI tests
pytest -m ui
# A single test file
pytest tests/api/test_orders_api.py
# A specific test by name
pytest -k "test_create_order"
# With coverage report
pytest --cov=src --cov-report=term-missing
Tip: Run
pytest -xto stop on the first failure — useful during active development.
This project uses black for code formatting and follows PEP 8.
# Check formatting (dry-run)
black --check .
# Apply formatting
black .
Run formatting before every commit to keep diffs clean.
API tests live in tests/api/ and use the Flask test client (no live server needed).
Pattern:
def test_create_order(client):
payload = {"item": "Widget", "price": 9.99, "qty": 2}
response = client.post("/api/orders", json=payload)
assert response.status_code == 201
data = response.get_json()
assert data["item"] == "Widget"
Guidelines:
client fixture from tests/conftest.py.UI tests live in tests/ui/ and use Selenium with headless Chrome.
Pattern:
def test_create_order_ui(browser, live_server):
browser.get(live_server + "/")
browser.find_element(By.ID, "item").send_keys("Widget")
browser.find_element(By.ID, "submit-btn").click()
assert "Widget" in browser.find_element(By.ID, "order-list").text
Guidelines:
WebDriverWait + expected_conditions). Never use time.sleep.By.ID or By.CSS_SELECTOR — avoid fragile XPath selectors.tests/api/.client fixture.test_<behaviour>.@pytest.mark.api so it can be run selectively.import pytest
@pytest.mark.api
def test_delete_nonexistent_order(client):
response = client.delete("/api/orders/does-not-exist")
assert response.status_code == 404
tests/ui/.browser and live_server fixtures.@pytest.mark.ui.| Issue | What to do |
|---|---|
Test fails with ConnectionRefusedError |
The Flask app is not running; use the client fixture instead of a live server for API tests |
Selenium NoSuchElementException |
The element may not be loaded yet; add WebDriverWait |
Selenium SessionNotCreatedException |
ChromeDriver version mismatch; update to match your Chrome version |
ModuleNotFoundError |
Virtual environment may not be activated; run source .venv/bin/activate |
AssertionError on status code |
Print response.data to see the actual response body |
Print debugging in tests:
def test_something(client):
response = client.get("/api/orders")
print(response.get_json()) # visible with pytest -s
assert response.status_code == 200
Run pytest -s to see print output during test execution.