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
20 changes: 20 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,23 @@ jobs:
done < <(find . -name '*.js' -not -path './.git/*' -not -path './node_modules/*' -print0)
[ "$found" = "1" ] || echo "No JS files found to check."
echo "Static app validated."

test:
name: playwright-tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest pytest-playwright
playwright install chromium --with-deps
- name: Run tests
run: |
python3 -m http.server 8000 &
sleep 3
pytest tests/test_app.py
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
__pycache__/
*.py[cod]
*$py.class
.pytest_cache/
.playwright/
ms-playwright/
74 changes: 74 additions & 0 deletions tests/test_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import pytest
import re
from playwright.sync_api import Page, expect

@pytest.fixture(autouse=True)
def setup(page: Page):
# Go to the app. We assume the server is running on localhost:8000
page.goto("http://localhost:8000/index.html?debug")
yield

def test_page_load(page: Page):
"""Verify that the page loads with the correct title and initial state."""
expect(page).to_have_title("StepView — Step, Distance & Calorie Counter")
expect(page.locator("#steps")).to_have_text("0")
expect(page.locator("#distance")).to_have_text("0.00")

def test_no_js_errors(page: Page):
"""Verify that there are no JavaScript errors on page load."""
errors = []
page.on("pageerror", lambda err: errors.append(err.message))
page.goto("http://localhost:8000/index.html?debug")
assert len(errors) == 0, f"JS errors found: {errors}"

def test_simulate_steps(page: Page):
"""Verify that simulating steps via debug hooks updates the UI."""
page.evaluate("window.__sv.simSteps(10)")
expect(page.locator("#steps")).to_have_text("10")
# 10 steps at 0.71m/stride = 7.1m = 0.01km (rounded)
expect(page.locator("#distance")).to_have_text("0.01")

def test_navigation(page: Page):
"""Verify navigation between Home and Settings."""
# Go to Settings
page.click("button[data-action='settings']")
expect(page.locator("#settings")).not_to_have_class(re.compile("hidden"))
expect(page.locator("#home")).to_have_class(re.compile("hidden"))

# Go back to Home
page.click("button[data-action='back']")
expect(page.locator("#home")).not_to_have_class(re.compile("hidden"))
expect(page.locator("#settings")).to_have_class(re.compile("hidden"))

def test_persistence(page: Page):
"""Verify that steps are persisted across reloads."""
page.evaluate("window.__sv.simSteps(50)")
expect(page.locator("#steps")).to_have_text("50")

# Reload the page
page.reload()
# Wait for the app to initialize
expect(page.locator("#steps")).to_have_text("50")

def test_settings_adjustment(page: Page):
"""Verify that settings can be adjusted and they update the UI."""
page.click("button[data-action='settings']")

# Increase weight
initial_weight = page.locator("#set-weight").inner_text()
page.click("button[data-action='weight-inc']")
expect(page.locator("#set-weight")).to_have_text(str(int(initial_weight) + 1))

# Go back and check if it's reflected in calories (if we have steps)
page.click("button[data-action='back']")
page.evaluate("window.__sv.simSteps(1000)") # Significant steps to see calorie change
calories_before = page.locator("#calories").inner_text()

page.click("button[data-action='settings']")
page.click("button[data-action='weight-inc']") # +1kg again
page.click("button[data-action='back']")

# Calories = distance_km * weight_kg * 0.9
# Increasing weight should increase calories
calories_after = page.locator("#calories").inner_text()
assert int(calories_after.replace(',', '')) > int(calories_before.replace(',', ''))
Loading