feat: complete workspace-first-ui cleanup and tests
- Delete dead repo-workspace code: RepoWorkspacePage, useRepoWorkspace, WorkspaceLayout, FileBrowser, old git components (git-toolbar, file-editor, commit-panel), and repo-workspace.css. - Fix stale backend test imports for moved models/services. - Add GitOperations unit tests. - Add integration tests for workspace files, git, and instances endpoints. - Add frontend tests for WorkspaceDetailPage and ProjectCard. - Update OpenSpec workspace-first-ui tasks and mark change completed. - Regenerate project maps. Quality gates: npm run typecheck, npm run lint, npm test -- --run (87 passed), python3 -m py_compile on changed backend files, pytest backend workspace tests.
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
"""Unit tests for GitOperations."""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
import pytest
|
||||
|
||||
from src.models import Workspace
|
||||
from src.services.git.git_operations import GitOperations
|
||||
|
||||
|
||||
def _run_git(*args: str, cwd: str) -> None:
|
||||
subprocess.run(["git", *args], cwd=cwd, check=True, capture_output=True)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def temp_workspace():
|
||||
"""Create a temporary git workspace."""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
_run_git("init", cwd=tmpdir)
|
||||
_run_git("config", "user.email", "test@test.com", cwd=tmpdir)
|
||||
_run_git("config", "user.name", "Test User", cwd=tmpdir)
|
||||
|
||||
readme = os.path.join(tmpdir, "README.md")
|
||||
with open(readme, "w") as f:
|
||||
f.write("# Test\n")
|
||||
_run_git("add", "README.md", cwd=tmpdir)
|
||||
_run_git("commit", "-m", "Initial commit", cwd=tmpdir)
|
||||
|
||||
ws = Workspace(
|
||||
id="00000000-0000-0000-0000-000000000001",
|
||||
name="test-ws",
|
||||
repo_id="00000000-0000-0000-0000-000000000002",
|
||||
user_id="00000000-0000-0000-0000-000000000003",
|
||||
branch="main",
|
||||
path=tmpdir,
|
||||
)
|
||||
yield ws
|
||||
|
||||
|
||||
class TestGitOperationsStatus:
|
||||
"""Tests for GitOperations.status."""
|
||||
|
||||
def test_status_clean(self, temp_workspace: Workspace):
|
||||
git = GitOperations(temp_workspace)
|
||||
status = asyncio.run(git.status())
|
||||
assert status.branch == "main"
|
||||
assert status.modified == []
|
||||
assert status.added == []
|
||||
assert status.deleted == []
|
||||
assert status.untracked == []
|
||||
|
||||
def test_status_modified(self, temp_workspace: Workspace):
|
||||
with open(os.path.join(temp_workspace.path, "README.md"), "a") as f:
|
||||
f.write("modified\n")
|
||||
|
||||
git = GitOperations(temp_workspace)
|
||||
status = asyncio.run(git.status())
|
||||
assert "README.md" in status.modified
|
||||
|
||||
def test_status_untracked(self, temp_workspace: Workspace):
|
||||
with open(os.path.join(temp_workspace.path, "new.py"), "w") as f:
|
||||
f.write("print('hello')\n")
|
||||
|
||||
git = GitOperations(temp_workspace)
|
||||
status = asyncio.run(git.status())
|
||||
assert "new.py" in status.untracked
|
||||
|
||||
|
||||
class TestGitOperationsCommit:
|
||||
"""Tests for GitOperations.commit."""
|
||||
|
||||
def test_commit_stages_and_commits(self, temp_workspace: Workspace):
|
||||
with open(os.path.join(temp_workspace.path, "new.py"), "w") as f:
|
||||
f.write("print('hello')\n")
|
||||
|
||||
git = GitOperations(temp_workspace)
|
||||
asyncio.run(git.commit("Add new file"))
|
||||
|
||||
status = asyncio.run(git.status())
|
||||
assert "new.py" not in status.untracked
|
||||
assert "new.py" not in status.added
|
||||
|
||||
history = asyncio.run(git.history())
|
||||
assert history[0].message == "Add new file"
|
||||
|
||||
def test_commit_fails_without_changes(self, temp_workspace: Workspace):
|
||||
git = GitOperations(temp_workspace)
|
||||
with pytest.raises(RuntimeError):
|
||||
asyncio.run(git.commit("Nothing to commit"))
|
||||
|
||||
|
||||
class TestGitOperationsHistory:
|
||||
"""Tests for GitOperations.history."""
|
||||
|
||||
def test_history_returns_commits(self, temp_workspace: Workspace):
|
||||
git = GitOperations(temp_workspace)
|
||||
history = asyncio.run(git.history())
|
||||
assert len(history) >= 1
|
||||
assert history[0].message == "Initial commit"
|
||||
|
||||
def test_history_filters_by_path(self, temp_workspace: Workspace):
|
||||
with open(os.path.join(temp_workspace.path, "new.py"), "w") as f:
|
||||
f.write("print('hello')\n")
|
||||
|
||||
git = GitOperations(temp_workspace)
|
||||
asyncio.run(git.commit("Add new file"))
|
||||
|
||||
history = asyncio.run(git.history(path="new.py"))
|
||||
assert len(history) == 1
|
||||
assert history[0].message == "Add new file"
|
||||
|
||||
|
||||
class TestGitOperationsBranches:
|
||||
"""Tests for GitOperations.branches."""
|
||||
|
||||
def test_branches_lists_main(self, temp_workspace: Workspace):
|
||||
git = GitOperations(temp_workspace)
|
||||
branches, current = asyncio.run(git.branches())
|
||||
assert "main" in branches
|
||||
assert current == "main"
|
||||
|
||||
def test_checkout_switches_branch(self, temp_workspace: Workspace):
|
||||
_run_git("checkout", "-b", "feature", cwd=temp_workspace.path)
|
||||
_run_git("checkout", "main", cwd=temp_workspace.path)
|
||||
|
||||
git = GitOperations(temp_workspace)
|
||||
asyncio.run(git.checkout("feature"))
|
||||
|
||||
status = asyncio.run(git.status())
|
||||
assert status.branch == "feature"
|
||||
Reference in New Issue
Block a user