trainUs/tests/test_step5_sessions.py
David 352a3d5e88
Some checks are pending
CI / Lint & Format (push) Waiting to run
CI / Build (push) Waiting to run
CI / Tests (${{ matrix.browser }}) (chromium) (push) Waiting to run
CI / Tests (${{ matrix.browser }}) (firefox) (push) Waiting to run
Initial commit
2026-06-18 13:06:57 +02:00

909 lines
32 KiB
Python

"""
Step 5 — Session Management Tests
- test_session_list_empty: Shows empty state when no sessions exist
- test_create_session_minimal: Create session with only required field (title)
- test_create_session_full: Create session with all fields including items
- test_session_appears_in_list: Created session appears in the list
- test_session_detail_view: Detail view shows all session data
- test_edit_session: Edit a session and verify changes
- test_delete_session: Delete a session with confirmation
- test_delete_session_cancel: Cancelling delete does not remove session
- test_search_sessions: Search filters sessions by title
- test_search_no_results: Search with no matches shows empty message
- test_search_clear_button: Clear button empties the search field and restores the full list
- test_validation_title_required: Empty title shows validation error
- test_duplicate_title_rejected: Creating session with duplicate title shows error
- test_reorder_items: Reorder items in session
- test_remove_item: Remove an item from session
- test_action_bar_buttons: New and Search buttons appear in action bar
- test_create_session_with_exercise_and_combo: Create session mixing exercises and combos
- test_create_session_with_reps_and_weight: Create session with reps/weight values
- test_edit_session_reps_and_weight: Edit session and change reps/weight values
- test_reps_weight_defaults: Reps default to 1 and weight defaults to 0
"""
from playwright.sync_api import Page, expect
def _wait_for_db(page: Page, app_url: str):
"""Navigate and wait for the database to be ready."""
page.goto(app_url)
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
def _go_to_sessions(page: Page, app_url: str):
"""Navigate to the sessions list and wait for it to load."""
_wait_for_db(page, app_url)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
def _clean_sessions(page: Page):
"""Remove all sessions via the repository."""
page.evaluate(
"""async () => {
const sessions = await window.__repos.sessions.getAll();
for (const s of sessions) {
await window.__repos.sessions.delete(s.id);
}
}"""
)
def _clean_exercises(page: Page):
"""Remove all exercises via the repository."""
page.evaluate(
"""async () => {
const exercises = await window.__repos.exercises.getAll();
for (const e of exercises) {
await window.__repos.exercises.delete(e.id);
}
}"""
)
def _clean_combos(page: Page):
"""Remove all combos via the repository."""
page.evaluate(
"""async () => {
const combos = await window.__repos.combos.getAll();
for (const c of combos) {
await window.__repos.combos.delete(c.id);
}
}"""
)
def _create_exercise_via_repo(page: Page, title):
"""Create an exercise via the repository and return its ID."""
return page.evaluate(
"""async (title) => {
const uuid = await window.__repos.settings.get('user_uuid');
return window.__repos.exercises.create({
title: title, description: '', asymmetric: false, alternate: false,
image_urls: [], video_urls: [], default_reps: 10, default_weight: 0,
created_by: uuid
});
}""",
title,
)
def _create_combo_via_repo(page: Page, title):
"""Create a combo via the repository and return its ID."""
return page.evaluate(
"""async (title) => {
const uuid = await window.__repos.settings.get('user_uuid');
return window.__repos.combos.create({
title: title, description: '', type: 'NONE',
timer_config: {}, created_by: uuid
});
}""",
title,
)
def test_session_list_empty(page: Page, app_url: str):
"""Empty state is shown when no sessions exist."""
_go_to_sessions(page, app_url)
_clean_sessions(page)
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
expect(page.locator('[data-testid="session-empty"]')).to_be_visible()
def test_create_session_minimal(page: Page, app_url: str):
"""Create a session with only the required title field."""
_go_to_sessions(page, app_url)
_clean_sessions(page)
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
page.click('[data-testid="session-new-btn"]')
page.wait_for_selector('[data-testid="session-title"]')
page.fill('[data-testid="session-title"]', "My First Session")
page.click('[data-testid="session-save"]')
page.wait_for_selector('[data-testid="session-detail-title"]', timeout=5000)
expect(page.locator('[data-testid="session-detail-title"]')).to_have_text("My First Session")
_clean_sessions(page)
def test_create_session_full(page: Page, app_url: str):
"""Create a session with all fields including items."""
_go_to_sessions(page, app_url)
_clean_sessions(page)
_clean_exercises(page)
_clean_combos(page)
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
# Create exercise and combo
ex_id = _create_exercise_via_repo(page, "Push-ups")
combo_id = _create_combo_via_repo(page, "Warm-up Combo")
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
# Create session
page.click('[data-testid="session-new-btn"]')
page.wait_for_selector('[data-testid="session-title"]')
page.fill('[data-testid="session-title"]', "Upper Body Day")
page.fill('[data-testid="session-description"]', "Focus on chest and shoulders")
# Add exercise
page.select_option('[data-testid="session-item-type-select"]', "exercise")
page.select_option('[data-testid="session-item-select"]', ex_id)
page.click('[data-testid="session-item-add"]')
# Add combo
page.select_option('[data-testid="session-item-type-select"]', "combo")
page.select_option('[data-testid="session-item-select"]', combo_id)
page.click('[data-testid="session-item-add"]')
page.click('[data-testid="session-save"]')
page.wait_for_selector('[data-testid="session-detail-title"]', timeout=5000)
expect(page.locator('[data-testid="session-detail-title"]')).to_have_text("Upper Body Day")
expect(page.locator('[data-testid="session-detail-description"]')).to_have_text(
"Focus on chest and shoulders"
)
expect(page.locator('[data-testid="session-detail-item-0"]')).to_contain_text("Push-ups")
expect(page.locator('[data-testid="session-detail-item-1"]')).to_contain_text("Warm-up Combo")
_clean_sessions(page)
_clean_exercises(page)
_clean_combos(page)
def test_session_appears_in_list(page: Page, app_url: str):
"""Created session appears in the list view."""
_go_to_sessions(page, app_url)
_clean_sessions(page)
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
page.click('[data-testid="session-new-btn"]')
page.wait_for_selector('[data-testid="session-title"]')
page.fill('[data-testid="session-title"]', "Test Session")
page.click('[data-testid="session-save"]')
page.wait_for_selector('[data-testid="session-detail-title"]', timeout=5000)
page.click('[data-testid="session-back-btn"]')
page.wait_for_timeout(500)
expect(page.locator('[data-testid="session-card-title"]')).to_have_text("Test Session")
_clean_sessions(page)
def test_session_detail_view(page: Page, app_url: str):
"""Detail view shows all session data correctly."""
_go_to_sessions(page, app_url)
_clean_sessions(page)
_clean_exercises(page)
ex_id = _create_exercise_via_repo(page, "Burpees")
# Create session via repo
session_id = page.evaluate(
"""async ({ exId }) => {
const uuid = await window.__repos.settings.get('user_uuid');
const id = await window.__repos.sessions.create({
title: 'HIIT Session',
description: 'High intensity interval training',
created_by: uuid
});
await window.__repos.sessions.setItems(id, [
{ item_id: exId, item_type: 'exercise', repetitions: 3, weight: 0.0 }
]);
return id;
}""",
{"exId": ex_id},
)
page.goto(f"{app_url}/#/sessions/{session_id}")
page.wait_for_selector('[data-testid="session-detail-title"]', timeout=5000)
expect(page.locator('[data-testid="session-detail-title"]')).to_have_text("HIIT Session")
expect(page.locator('[data-testid="session-detail-description"]')).to_have_text(
"High intensity interval training"
)
expect(page.locator('[data-testid="session-detail-item-0"]')).to_contain_text("Burpees")
_clean_sessions(page)
_clean_exercises(page)
def test_edit_session(page: Page, app_url: str):
"""Edit a session and verify changes are persisted."""
_go_to_sessions(page, app_url)
_clean_sessions(page)
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
page.click('[data-testid="session-new-btn"]')
page.wait_for_selector('[data-testid="session-title"]')
page.fill('[data-testid="session-title"]', "Original Session")
page.click('[data-testid="session-save"]')
page.wait_for_selector('[data-testid="session-detail-title"]', timeout=5000)
page.click('[data-testid="session-edit-btn"]')
page.wait_for_selector('[data-testid="session-title"]')
page.fill('[data-testid="session-title"]', "Updated Session")
page.fill('[data-testid="session-description"]', "Updated description")
page.click('[data-testid="session-save"]')
page.wait_for_selector('[data-testid="session-detail-title"]', timeout=5000)
expect(page.locator('[data-testid="session-detail-title"]')).to_have_text("Updated Session")
expect(page.locator('[data-testid="session-detail-description"]')).to_have_text(
"Updated description"
)
_clean_sessions(page)
def test_delete_session(page: Page, app_url: str):
"""Delete a session with confirmation dialog."""
_go_to_sessions(page, app_url)
_clean_sessions(page)
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
page.click('[data-testid="session-new-btn"]')
page.wait_for_selector('[data-testid="session-title"]')
page.fill('[data-testid="session-title"]', "To Delete")
page.click('[data-testid="session-save"]')
page.wait_for_selector('[data-testid="session-detail-title"]', timeout=5000)
page.on("dialog", lambda dialog: dialog.accept())
page.click('[data-testid="session-delete-btn"]')
page.wait_for_timeout(500)
expect(page.locator('[data-testid="session-empty"]')).to_be_visible()
def test_delete_session_cancel(page: Page, app_url: str):
"""Cancelling the delete dialog does not remove the session."""
_go_to_sessions(page, app_url)
_clean_sessions(page)
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
page.click('[data-testid="session-new-btn"]')
page.wait_for_selector('[data-testid="session-title"]')
page.fill('[data-testid="session-title"]', "Keep Me")
page.click('[data-testid="session-save"]')
page.wait_for_selector('[data-testid="session-detail-title"]', timeout=5000)
page.on("dialog", lambda dialog: dialog.dismiss())
page.click('[data-testid="session-delete-btn"]')
page.wait_for_timeout(500)
expect(page.locator('[data-testid="session-detail-title"]')).to_have_text("Keep Me")
_clean_sessions(page)
def test_search_sessions(page: Page, app_url: str):
"""Search filters sessions by title."""
_go_to_sessions(page, app_url)
_clean_sessions(page)
page.evaluate(
"""async () => {
const uuid = await window.__repos.settings.get('user_uuid');
await window.__repos.sessions.create({
title: 'Upper Body', description: '', created_by: uuid
});
await window.__repos.sessions.create({
title: 'Lower Body', description: '', created_by: uuid
});
await window.__repos.sessions.create({
title: 'Full Body', description: '', created_by: uuid
});
}"""
)
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
expect(page.locator('[data-testid="session-card-title"]')).to_have_count(3)
page.click('[data-testid="session-search-toggle"]')
page.wait_for_selector('[data-testid="session-search-input"]')
page.fill('[data-testid="session-search-input"]', "Upper")
page.wait_for_timeout(500)
expect(page.locator('[data-testid="session-card-title"]')).to_have_count(1)
expect(page.locator('[data-testid="session-card-title"]')).to_have_text("Upper Body")
_clean_sessions(page)
def test_search_no_results(page: Page, app_url: str):
"""Search with no matches shows no-results message."""
_go_to_sessions(page, app_url)
_clean_sessions(page)
page.evaluate(
"""async () => {
const uuid = await window.__repos.settings.get('user_uuid');
await window.__repos.sessions.create({
title: 'Upper Body', description: '', created_by: uuid
});
}"""
)
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
page.click('[data-testid="session-search-toggle"]')
page.fill('[data-testid="session-search-input"]', "zzzznotfound")
page.wait_for_timeout(500)
expect(page.locator('[data-testid="session-no-results"]')).to_be_visible()
_clean_sessions(page)
def test_search_clear_button(page: Page, app_url: str):
"""Clear button empties the search field and restores the full list."""
_go_to_sessions(page, app_url)
_clean_sessions(page)
page.evaluate(
"""async () => {
const uuid = await window.__repos.settings.get('user_uuid');
await window.__repos.sessions.create({
title: 'Upper Body', description: '', created_by: uuid
});
await window.__repos.sessions.create({
title: 'Lower Body', description: '', created_by: uuid
});
}"""
)
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
page.click('[data-testid="session-search-toggle"]')
expect(page.locator('[data-testid="session-search-clear"]')).not_to_be_visible()
page.fill('[data-testid="session-search-input"]', "Upper")
page.wait_for_timeout(500)
expect(page.locator('[data-testid="session-card-title"]')).to_have_count(1)
page.click('[data-testid="session-search-clear"]')
expect(page.locator('[data-testid="session-search-input"]')).to_have_value("")
page.wait_for_timeout(500)
expect(page.locator('[data-testid="session-card-title"]')).to_have_count(2)
expect(page.locator('[data-testid="session-search-input"]')).to_be_focused()
_clean_sessions(page)
def test_validation_title_required(page: Page, app_url: str):
"""Empty title shows validation error and prevents save."""
_go_to_sessions(page, app_url)
_clean_sessions(page)
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
page.click('[data-testid="session-new-btn"]')
page.wait_for_selector('[data-testid="session-title"]')
page.click('[data-testid="session-save"]')
expect(page.locator('[data-testid="session-title-error"]')).to_be_visible()
expect(page.locator('[data-testid="session-title"]')).to_be_visible()
def test_duplicate_title_rejected(page: Page, app_url: str):
"""Creating a session with a duplicate title shows an error."""
_go_to_sessions(page, app_url)
_clean_sessions(page)
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
page.click('[data-testid="session-new-btn"]')
page.wait_for_selector('[data-testid="session-title"]')
page.fill('[data-testid="session-title"]', "Unique Session")
page.click('[data-testid="session-save"]')
page.wait_for_selector('[data-testid="session-detail-title"]', timeout=5000)
page.click('[data-testid="session-back-btn"]')
page.wait_for_timeout(500)
page.click('[data-testid="session-new-btn"]')
page.wait_for_selector('[data-testid="session-title"]')
page.fill('[data-testid="session-title"]', "Unique Session")
page.click('[data-testid="session-save"]')
page.wait_for_timeout(500)
title_error_visible = page.locator('[data-testid="session-title-error"]').is_visible()
save_error_visible = page.locator('[data-testid="session-save-error"]').is_visible()
assert title_error_visible or save_error_visible, "Expected duplicate title error"
_clean_sessions(page)
def test_reorder_items(page: Page, app_url: str):
"""Reorder items in a session."""
_go_to_sessions(page, app_url)
_clean_sessions(page)
_clean_exercises(page)
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
ex1_id = _create_exercise_via_repo(page, "Push-ups")
ex2_id = _create_exercise_via_repo(page, "Squats")
ex3_id = _create_exercise_via_repo(page, "Burpees")
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
# Create session with 3 exercises
page.click('[data-testid="session-new-btn"]')
page.wait_for_selector('[data-testid="session-title"]')
page.fill('[data-testid="session-title"]', "Reorder Test")
for ex_id in [ex1_id, ex2_id, ex3_id]:
page.select_option('[data-testid="session-item-type-select"]', "exercise")
page.select_option('[data-testid="session-item-select"]', ex_id)
page.click('[data-testid="session-item-add"]')
page.click('[data-testid="session-save"]')
page.wait_for_selector('[data-testid="session-detail-title"]', timeout=5000)
# Go to edit
page.click('[data-testid="session-edit-btn"]')
page.wait_for_selector('[data-testid="session-title"]')
# Move Squats (index 1) up
page.click('[data-testid="session-item-move-up-1"]')
# Save
page.click('[data-testid="session-save"]')
page.wait_for_selector('[data-testid="session-detail-title"]', timeout=5000)
# Verify order: Squats, Push-ups, Burpees
expect(page.locator('[data-testid="session-detail-item-0"]')).to_contain_text("Squats")
expect(page.locator('[data-testid="session-detail-item-1"]')).to_contain_text("Push-ups")
expect(page.locator('[data-testid="session-detail-item-2"]')).to_contain_text("Burpees")
_clean_sessions(page)
_clean_exercises(page)
def test_remove_item(page: Page, app_url: str):
"""Remove an item from a session."""
_go_to_sessions(page, app_url)
_clean_sessions(page)
_clean_exercises(page)
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
ex1_id = _create_exercise_via_repo(page, "Push-ups")
ex2_id = _create_exercise_via_repo(page, "Squats")
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
# Create session with 2 exercises
page.click('[data-testid="session-new-btn"]')
page.wait_for_selector('[data-testid="session-title"]')
page.fill('[data-testid="session-title"]', "Remove Test")
for ex_id in [ex1_id, ex2_id]:
page.select_option('[data-testid="session-item-type-select"]', "exercise")
page.select_option('[data-testid="session-item-select"]', ex_id)
page.click('[data-testid="session-item-add"]')
page.click('[data-testid="session-save"]')
page.wait_for_selector('[data-testid="session-detail-title"]', timeout=5000)
# Go to edit
page.click('[data-testid="session-edit-btn"]')
page.wait_for_selector('[data-testid="session-title"]')
# Remove first item
page.click('[data-testid="session-item-remove-0"]')
page.click('[data-testid="session-save"]')
page.wait_for_selector('[data-testid="session-detail-title"]', timeout=5000)
# Only Squats should remain
expect(page.locator('[data-testid="session-detail-item-0"]')).to_contain_text("Squats")
_clean_sessions(page)
_clean_exercises(page)
def test_action_bar_buttons(page: Page, app_url: str):
"""New and Search buttons are visible in the action bar on the session list."""
_go_to_sessions(page, app_url)
_clean_sessions(page)
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
expect(page.locator('[data-testid="session-new-btn"]')).to_be_visible()
expect(page.locator('[data-testid="session-search-toggle"]')).to_be_visible()
def test_create_session_with_exercise_and_combo(page: Page, app_url: str):
"""Create session mixing exercises and combos."""
_go_to_sessions(page, app_url)
_clean_sessions(page)
_clean_exercises(page)
_clean_combos(page)
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
ex_id = _create_exercise_via_repo(page, "Push-ups")
combo_id = _create_combo_via_repo(page, "Warm-up")
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
page.click('[data-testid="session-new-btn"]')
page.wait_for_selector('[data-testid="session-title"]')
page.fill('[data-testid="session-title"]', "Mixed Session")
# Add exercise
page.select_option('[data-testid="session-item-type-select"]', "exercise")
page.select_option('[data-testid="session-item-select"]', ex_id)
page.click('[data-testid="session-item-add"]')
# Add combo
page.select_option('[data-testid="session-item-type-select"]', "combo")
page.select_option('[data-testid="session-item-select"]', combo_id)
page.click('[data-testid="session-item-add"]')
page.click('[data-testid="session-save"]')
page.wait_for_selector('[data-testid="session-detail-title"]', timeout=5000)
expect(page.locator('[data-testid="session-detail-item-0"]')).to_contain_text("Push-ups")
expect(page.locator('[data-testid="session-detail-item-1"]')).to_contain_text("Warm-up")
_clean_sessions(page)
_clean_exercises(page)
_clean_combos(page)
def test_create_session_with_reps_and_weight(page: Page, app_url: str):
"""Create session with exercises and set reps/weight values."""
_go_to_sessions(page, app_url)
_clean_sessions(page)
_clean_exercises(page)
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
ex1_id = _create_exercise_via_repo(page, "Push-ups")
ex2_id = _create_exercise_via_repo(page, "Squats")
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
page.click('[data-testid="session-new-btn"]')
page.wait_for_selector('[data-testid="session-title"]')
page.fill('[data-testid="session-title"]', "Reps Weight Test")
# Add first exercise
page.select_option('[data-testid="session-item-type-select"]', "exercise")
page.select_option('[data-testid="session-item-select"]', ex1_id)
page.click('[data-testid="session-item-add"]')
# Add second exercise
page.select_option('[data-testid="session-item-type-select"]', "exercise")
page.select_option('[data-testid="session-item-select"]', ex2_id)
page.click('[data-testid="session-item-add"]')
# Set reps and weight for first exercise
page.fill('[data-testid="session-item-reps-0"]', "12")
page.fill('[data-testid="session-item-weight-0"]', "50")
# Set reps for second exercise (weight stays default)
page.fill('[data-testid="session-item-reps-1"]', "15")
page.click('[data-testid="session-save"]')
page.wait_for_selector('[data-testid="session-detail-title"]', timeout=5000)
# Verify detail view shows reps and weight
expect(page.locator('[data-testid="session-detail-item-0"]')).to_contain_text("Push-ups")
expect(page.locator('[data-testid="session-detail-item-0"]')).to_contain_text("12")
expect(page.locator('[data-testid="session-detail-item-0"]')).to_contain_text("50")
expect(page.locator('[data-testid="session-detail-item-1"]')).to_contain_text("Squats")
expect(page.locator('[data-testid="session-detail-item-1"]')).to_contain_text("15")
_clean_sessions(page)
_clean_exercises(page)
def test_edit_session_reps_and_weight(page: Page, app_url: str):
"""Edit session and change reps/weight values."""
_go_to_sessions(page, app_url)
_clean_sessions(page)
_clean_exercises(page)
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
ex_id = _create_exercise_via_repo(page, "Deadlifts")
# Create session
page.click('[data-testid="session-new-btn"]')
page.wait_for_selector('[data-testid="session-title"]')
page.fill('[data-testid="session-title"]', "Edit Reps Weight Test")
page.select_option('[data-testid="session-item-type-select"]', "exercise")
page.select_option('[data-testid="session-item-select"]', ex_id)
page.click('[data-testid="session-item-add"]')
page.click('[data-testid="session-save"]')
page.wait_for_selector('[data-testid="session-detail-title"]', timeout=5000)
# Edit session
page.click('[data-testid="session-edit-btn"]')
page.wait_for_selector('[data-testid="session-title"]')
# Change reps and weight
page.fill('[data-testid="session-item-reps-0"]', "8")
page.fill('[data-testid="session-item-weight-0"]', "100")
page.click('[data-testid="session-save"]')
page.wait_for_selector('[data-testid="session-detail-title"]', timeout=5000)
# Verify updated values
expect(page.locator('[data-testid="session-detail-item-0"]')).to_contain_text("Deadlifts")
expect(page.locator('[data-testid="session-detail-item-0"]')).to_contain_text("8")
expect(page.locator('[data-testid="session-detail-item-0"]')).to_contain_text("100")
_clean_sessions(page)
_clean_exercises(page)
def test_combo_item_no_weight_in_form(page: Page, app_url: str):
"""Combo items do not show weight input in session form."""
_go_to_sessions(page, app_url)
_clean_sessions(page)
_clean_exercises(page)
_clean_combos(page)
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
combo_id = _create_combo_via_repo(page, "Warm-up")
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
page.click('[data-testid="session-new-btn"]')
page.wait_for_selector('[data-testid="session-title"]')
page.fill('[data-testid="session-title"]', "Combo Weight Test")
# Add combo
page.select_option('[data-testid="session-item-type-select"]', "combo")
page.select_option('[data-testid="session-item-select"]', combo_id)
page.click('[data-testid="session-item-add"]')
# Verify reps input exists but weight input does not
expect(page.locator('[data-testid="session-item-reps-0"]')).to_be_visible()
expect(page.locator('[data-testid="session-item-weight-0"]')).not_to_be_attached()
# Save and verify detail view shows 0 for weight
page.click('[data-testid="session-save"]')
page.wait_for_selector('[data-testid="session-detail-title"]', timeout=5000)
expect(page.locator('[data-testid="session-detail-item-0"]')).to_contain_text("Warm-up")
expect(page.locator('[data-testid="session-detail-item-details-0"]')).to_contain_text("1")
expect(page.locator('[data-testid="session-detail-item-details-0"]')).to_contain_text("0")
_clean_sessions(page)
_clean_exercises(page)
_clean_combos(page)
def test_reps_weight_defaults(page: Page, app_url: str):
"""Reps prefill from the exercise's default_reps and weight defaults to 0."""
_go_to_sessions(page, app_url)
_clean_sessions(page)
_clean_exercises(page)
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
ex_id = _create_exercise_via_repo(page, "Lunges")
page.reload()
page.wait_for_function(
"document.documentElement.getAttribute('data-db-ready') === 'true'",
timeout=15000,
)
page.click('a[href="#/sessions"]')
page.wait_for_timeout(500)
page.click('[data-testid="session-new-btn"]')
page.wait_for_selector('[data-testid="session-title"]')
page.fill('[data-testid="session-title"]', "Defaults Test")
# Add exercise
page.select_option('[data-testid="session-item-type-select"]', "exercise")
page.select_option('[data-testid="session-item-select"]', ex_id)
page.click('[data-testid="session-item-add"]')
# Verify default values in inputs (_create_exercise_via_repo sets default_reps=10)
reps_input = page.locator('[data-testid="session-item-reps-0"]')
weight_input = page.locator('[data-testid="session-item-weight-0"]')
expect(reps_input).to_have_value("10")
expect(weight_input).to_have_value("0")
# Save without changing
page.click('[data-testid="session-save"]')
page.wait_for_selector('[data-testid="session-detail-title"]', timeout=5000)
# Verify defaults are shown in detail view (always shown now)
expect(page.locator('[data-testid="session-detail-item-0"]')).to_contain_text("Lunges")
expect(page.locator('[data-testid="session-detail-item-details-0"]')).to_contain_text("10")
expect(page.locator('[data-testid="session-detail-item-details-0"]')).to_contain_text("0")
_clean_sessions(page)
_clean_exercises(page)