diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..4c13890 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,83 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + pre-commit: + name: Pre-commit checks + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Install uv + uses: astral-sh/setup-uv@v4 + + - name: Cache Python dependencies + uses: actions/cache@v4 + with: + path: ~/.cache/uv + key: ${{ runner.os }}-uv-${{ hashFiles('**/uv.lock') }} + restore-keys: | + ${{ runner.os }}-uv- + + - name: Install dependencies + run: uv sync + + - name: Run pre-commit + run: | + uv run pre-commit install + uv run pre-commit run --all-files + + test: + name: Run tests + runs-on: ubuntu-latest + env: + DJANGO_SETTINGS_MODULE: app.settings.dev + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install uv + uses: astral-sh/setup-uv@v4 + + - name: Cache Python dependencies + uses: actions/cache@v4 + with: + path: ~/.cache/uv + key: ${{ runner.os }}-uv-${{ hashFiles('**/uv.lock') }} + restore-keys: | + ${{ runner.os }}-uv- + + - name: Install Python dependencies + run: uv sync + + - name: Install Node dependencies + run: npm install + + - name: Build frontend assets + run: npm run build + + - name: Collect static files + run: uv run python manage.py collectstatic --noinput + + - name: Run Django tests + run: uv run python manage.py test diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index a4c8f6a..8164f7d 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -54,4 +54,3 @@ jobs: # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md # or https://code.claude.com/docs/en/cli-reference for available options claude_args: '--allowed-tools "Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"' - diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 79fe056..d199848 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -47,4 +47,3 @@ jobs: # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md # or https://code.claude.com/docs/en/cli-reference for available options # claude_args: '--allowed-tools Bash(gh pr:*)' - diff --git a/app/home/tests.py b/app/home/tests.py index af1c59d..5b9f502 100644 --- a/app/home/tests.py +++ b/app/home/tests.py @@ -5,19 +5,62 @@ class HomeTestCase(TestCase): + """Tests for the home app frontend and admin.""" + + @classmethod + def setUpTestData(cls): + """Set up test data for the entire test case.""" + cls.home_page = HomePage.objects.first() + cls.test_password = "TestPass123!" + def setUp(self): - User.objects.create_user( - username="testuser", password="12345", is_staff=True, is_superuser=True - ).save() + """Create a test user for admin access.""" + self.user = User.objects.create_user( + username="testuser", + password=self.test_password, + is_staff=True, + is_superuser=True, + ) + + def _login_as_admin(self): + """Helper method to log in as admin user.""" + self.client.login(username="testuser", password=self.test_password) - def test_home_view(self): + def test_home_frontend_returns_200(self): + """Test that the home page frontend returns 200 OK.""" response = self.client.get("/") self.assertEqual(response.status_code, 200) self.assertContains(response, "Welcome to your new Wagtail site!") self.assertTemplateUsed(response, "home/home_page.html") - def test_home_admin(self): - self.client.login(username="testuser", password="12345") - home_page = HomePage.objects.first() - response = self.client.get(f"/admin/pages/{home_page.pk}/") + def test_home_admin_edit_returns_200(self): + """Test that the home page admin edit page returns 200 OK.""" + self._login_as_admin() + response = self.client.get(f"/admin/pages/{self.home_page.pk}/edit/") + self.assertEqual(response.status_code, 200) + self.assertContains(response, self.home_page.title) + + def test_home_admin_delete_returns_200(self): + """Test that the home page admin delete page returns 200 OK.""" + self._login_as_admin() + response = self.client.get(f"/admin/pages/{self.home_page.pk}/delete/") + self.assertEqual(response.status_code, 200) + self.assertContains(response, "Are you sure") + + def test_home_admin_copy_returns_200(self): + """Test that the home page admin copy page returns 200 OK.""" + self._login_as_admin() + response = self.client.get(f"/admin/pages/{self.home_page.pk}/copy/") + self.assertEqual(response.status_code, 200) + + def test_home_admin_move_returns_200(self): + """Test that the home page admin move page returns 200 OK.""" + self._login_as_admin() + response = self.client.get(f"/admin/pages/{self.home_page.pk}/move/") + self.assertEqual(response.status_code, 200) + + def test_home_admin_history_returns_200(self): + """Test that the home page admin history page returns 200 OK.""" + self._login_as_admin() + response = self.client.get(f"/admin/pages/{self.home_page.pk}/history/") self.assertEqual(response.status_code, 200) diff --git a/app/search/tests.py b/app/search/tests.py index 2825d25..99f9727 100644 --- a/app/search/tests.py +++ b/app/search/tests.py @@ -2,20 +2,34 @@ class SearchTestCase(TestCase): - def test_search_view(self): + """Tests for the search app frontend.""" + + def test_search_frontend_returns_200(self): + """Test that the search page returns 200 OK and contains search form.""" response = self.client.get("/search/") self.assertEqual(response.status_code, 200) self.assertContains(response, "Search") + self.assertContains(response, 'name="query"') + self.assertTemplateUsed(response, "search/search.html") + + def test_search_with_query_returns_200(self): + """Test that search with a query returns 200 OK and shows query.""" + response = self.client.get("/search/?query=test") + self.assertEqual(response.status_code, 200) + self.assertContains(response, "test") self.assertTemplateUsed(response, "search/search.html") - def test_seach_no_results(self): - response = self.client.get("/search/?query=empty") + def test_search_no_results(self): + """Test that search with no results shows appropriate message.""" + response = self.client.get("/search/?query=nonexistentquery12345") self.assertEqual(response.status_code, 200) self.assertContains(response, "No results found") self.assertTemplateUsed(response, "search/search.html") def test_search_empty_query(self): + """Test that search with empty query shows form but no results.""" response = self.client.get("/search/?query=") self.assertEqual(response.status_code, 200) self.assertNotContains(response, "No results found") + self.assertContains(response, 'name="query"') self.assertTemplateUsed(response, "search/search.html") diff --git a/app/style_guide/tests.py b/app/style_guide/tests.py index 6bfd345..b574f73 100644 --- a/app/style_guide/tests.py +++ b/app/style_guide/tests.py @@ -2,7 +2,10 @@ class StyleGuideTestCase(TestCase): - def test_style_guide(self): + """Tests for the style_guide app frontend.""" + + def test_style_guide_frontend_returns_200(self): + """Test that the style guide page returns 200 OK.""" response = self.client.get("/style-guide/") self.assertEqual(response.status_code, 200) self.assertContains(response, "Style Guide")