"""Regression tests for the enhanced commits list page. Covers the four feature areas added to commits_list_page(): Filter bar - test_commits_enhanced_filter_bar_present — filter-bar HTML element present - test_commits_enhanced_author_dropdown_present — author present - test_commits_enhanced_tag_filter_input_present — tag filter present Server-side filtering - test_commits_enhanced_author_filter_narrows_results — ?author= returns only that author's commits - test_commits_enhanced_author_filter_excludes_others — commits by other authors absent - test_commits_enhanced_search_filter_matches_message — ?q= matches substring in commit message - test_commits_enhanced_search_filter_excludes_others — non-matching commits absent - test_commits_enhanced_date_from_filter — ?dateFrom= excludes older commits - test_commits_enhanced_tag_filter_matches_tag — ?tag=emotion:funky matches message substring Compare mode - test_commits_enhanced_compare_toggle_btn_present — compare-toggle-btn button present - test_commits_enhanced_compare_strip_present — compare-strip container present - test_commits_enhanced_compare_check_inputs_present — compare-check checkboxes per row - test_commits_enhanced_compare_js_function — toggleCompareMode() JS function present Metadata badges (client-side JS) - test_commits_enhanced_meta_badges_container_present — meta-badges span present per row - test_commits_enhanced_badge_js_extract_function — extractBadges() JS function present - test_commits_enhanced_chip_css_classes_present — chip-tempo / chip-key / chip-emotion CSS defined Mini-lane - test_commits_enhanced_dag_merge_arm_present — dag-merge-arm element on merge commits - test_commits_enhanced_mini_lane_dag_col_present — dag-col column present Pagination with active filters - test_commits_enhanced_pagination_preserves_filters — page links carry active filter params """ from __future__ import annotations import uuid from datetime import datetime, timezone import pytest from httpx import AsyncClient from sqlalchemy.ext.asyncio import AsyncSession from musehub.db.musehub_models import MusehubBranch, MusehubCommit, MusehubRepo # ── Constants ───────────────────────────────────────────────────────────────── _OWNER = "enhancedowner" _SLUG = "enhanced-commits" _SHA_ALICE_1 = "a1" + "0" * 38 _SHA_ALICE_2 = "a2" + "0" * 38 _SHA_BOB_1 = "b1" + "0" * 38 _SHA_MERGE = "cc" + "0" * 38 # ── Seed helpers ────────────────────────────────────────────────────────────── async def _seed_repo(db: AsyncSession) -> str: """Seed a public repo with 4 commits from 2 authors and return repo_id.""" repo = MusehubRepo( repo_id=str(uuid.uuid4()), name=_SLUG, owner=_OWNER, slug=_SLUG, visibility="public", owner_user_id=str(uuid.uuid4()), ) db.add(repo) await db.flush() repo_id = str(repo.repo_id) branch = MusehubBranch(repo_id=repo_id, name="main", head_commit_id=_SHA_MERGE) db.add(branch) # Alice: two commits with music metadata in messages db.add(MusehubCommit( commit_id=_SHA_ALICE_1, repo_id=repo_id, branch="main", parent_ids=[], message="Add walking bass line 120 BPM Cm emotion:funky", author="alice", timestamp=datetime(2026, 1, 10, tzinfo=timezone.utc), )) db.add(MusehubCommit( commit_id=_SHA_ALICE_2, repo_id=repo_id, branch="main", parent_ids=[_SHA_ALICE_1], message="Refine rhodes chord voicings stage:chorus", author="alice", timestamp=datetime(2026, 2, 15, tzinfo=timezone.utc), )) # Bob: one commit db.add(MusehubCommit( commit_id=_SHA_BOB_1, repo_id=repo_id, branch="main", parent_ids=[_SHA_ALICE_2], message="Add jazz drums groove 90 BPM Gm", author="bob", timestamp=datetime(2026, 3, 1, tzinfo=timezone.utc), )) # Merge commit db.add(MusehubCommit( commit_id=_SHA_MERGE, repo_id=repo_id, branch="main", parent_ids=[_SHA_ALICE_2, _SHA_BOB_1], message="Merge feat/drums into main", author="alice", timestamp=datetime(2026, 3, 2, tzinfo=timezone.utc), )) await db.commit() return repo_id def _url(path: str = "") -> str: return f"/musehub/ui/{_OWNER}/{_SLUG}/commits{path}" # ── Filter bar HTML ─────────────────────────────────────────────────────────── @pytest.mark.anyio async def test_commits_enhanced_filter_bar_present( client: AsyncClient, db_session: AsyncSession ) -> None: """filter-bar container is rendered on the commits list page.""" await _seed_repo(db_session) resp = await client.get(_url()) assert resp.status_code == 200 assert "filter-bar" in resp.text @pytest.mark.anyio async def test_commits_enhanced_author_dropdown_present( client: AsyncClient, db_session: AsyncSession ) -> None: """Author