FeaturesNested RoutingTesting Strategy

Testing Strategy

Testing is structured in three tiers: backend unit/integration tests, frontend unit tests, and end-to-end Playwright tests. Every tier covers the new path resolution, redirect mechanics, and listing contract.


Backend Tests (pytest)

Path Resolution

TestDescription
Resolve top-level section/blog resolves to the blog section
Resolve nested section/creative-work/photography resolves to photography section
Resolve deeply nested section/a/b/c/d resolves through 4 levels
Resolve content item/blog/my-post resolves to section=blog, content=my-post
Resolve nested content item/creative-work/photography/beach-sunset resolves correctly
Path not found returns 404/nonexistent/path returns 404
Unpublished section returns 404Unpublished sections are not resolvable by public requests
Redirect resolutionMoved content returns 301 with new path
Expired redirect returns 404Redirect past expires_at is ignored
Breadcrumbs are correctResponse includes full ancestor chain with titles and paths

Redirect Mechanics

TestDescription
Move content writes redirectMoving a story from section A to B creates a redirect
Move section cascades pathsMoving a section updates all descendant paths
Move section cascades redirectsAll descendant content gets redirects written
Redirect flatteningA->B then B->C results in A->C (no chain)
Cycle detectionMoving a section into its own descendant returns 400
Slug collision on moveMoving content to a section where the slug exists returns 409
Move to same section is no-opNo redirect created, returns current state
Rename slug cascadesRenaming a section’s slug updates all descendant paths

Section Hierarchy

TestDescription
Create child sectionSection created with parent_id gets correct path
Slug unique within parentTwo children of the same parent cannot share a slug
Slug unique across parentsTwo children of different parents can share a slug
Delete section with childrenVerify behavior (soft delete, children remain but become orphans?)
path rebuilt on parent renameChild paths update when parent slug changes

Children Endpoint

TestDescription
Direct children returnedGET /sections/{id}/children returns child sections + content items
Sections sorted firstChild sections appear before content items
Content from multiple typesMixed stories and projects in one section both appear
Pagination workslimit and offset control result window
Subtree querysubtree=true returns content from all descendants
Featured filterfeatured_only=true returns only is_featured items
Unpublished filteredUnpublished items excluded unless authenticated
ListingItem shape correctResponse items conform to the listing contract

Migration

TestDescription
Existing sections get path fieldMigration adds path to all existing sections
content_type removed from sectionsField no longer present after migration
Existing content still resolvesCurrent URLs continue to work post-migration
Slug uniqueness index updatedNew compound index (parent_id, slug) replaces global slug index

Frontend Unit Tests (vitest)

Path Resolution Hook

TestDescription
Section response renders display typetype: "section" response triggers correct display component
Content response renders detail viewtype: "content" response renders detail based on content_type
Redirect triggers navigation301 response causes client-side redirect
404 shows not found404 response renders the not-found page
Breadcrumbs renderBreadcrumb data from response renders as navigation

ListingCard Component

TestDescription
Renders with all fieldsImage, title, summary, tags, date all present
Renders without optional fieldsNo image, no summary, no video — renders title and date only
Content type doesn’t affect renderingA story and a project with same fields render identically
Link points to correct pathhref combines section path with item slug

Display Components

TestDescription
CardGrid renders items in gridCorrect CSS grid layout with pagination
Feed renders items in listVertical list with infinite scroll trigger
Gallery renders image-focused layoutItems with images emphasized
Mixed content types in one displayStories and projects render together

End-to-End Tests (Playwright)

TestDescription
Top-level section loadsNavigate to /blog, page renders
Nested section loadsNavigate to /creative-work/photography, page renders
Content item detail loadsNavigate to /blog/my-post, detail view renders
Nested content item loadsNavigate to /creative-work/photography/beach-sunset, detail renders
Deep nesting worksNavigate through 4+ levels, each resolves correctly
Breadcrumbs navigateClick breadcrumb, navigate to ancestor section
404 for bad pathsNavigate to /nonexistent/path, 404 page renders

Redirects

TestDescription
Old URL redirectsAfter moving content, old URL redirects to new location
Redirect chain flattenedAfter two moves, original URL goes directly to final location
Browser URL updatesAfter redirect, address bar shows the new URL

Mixed Content Sections

TestDescription
Section shows mixed typesA section containing stories and projects renders both
Card grid with mixed typesGrid layout renders cards for different content types
Click-through to correct detailClicking a story card opens story detail; clicking a project card opens project detail

Content Creation

TestDescription
New content in nested sectionCreate a story inside a nested section, verify it appears in the section’s list
Content type picker”New content” action shows type picker, selected type opens correct editor
Created content URL is correctNew content’s URL reflects the section hierarchy

Admin Operations

TestDescription
Create nested sectionCreate a child section, verify it appears under parent
Move content via adminMove a content item, verify redirect works and new location correct
Rename sectionRename a section’s slug, verify old URLs redirect

Test Data Seeding

Local development and e2e tests require a consistent section hierarchy for testing. The seed data creates:

/ (root)
├── blog/                          (feed, contains stories)
│   ├── tech/                      (feed, contains stories)
│   └── personal/                  (feed, contains stories)
├── creative-work/                 (broadsheet)
│   ├── photography/               (gallery)
│   │   └── portraits/             (gallery, contains photo essays)
│   └── writing/                   (feed, contains stories)
├── projects/                      (card-grid, contains projects)
├── about/                         (static-page)
└── contact/                       (static-page)

Each section is seeded with 2-3 content items of appropriate types so that list views, pagination, and mixed-type rendering are all exercisable.

The e2e mock server (frontend/e2e/mock-server.ts) and test data (frontend/e2e/test-data.ts) must be updated to serve this hierarchy through the new resolve-path endpoint and children endpoint.


Manual Testing Checklist

Before shipping, manually verify against the local dev environment (make dev-local):

  • Navigate to every seeded section at every depth level
  • Click through to content items from list views
  • Create content in a nested section, verify URL
  • Move content between sections, verify old URL redirects
  • Rename a section, verify all child URLs redirect
  • Check breadcrumbs at every level
  • Verify 404 page for non-existent paths
  • Test with both light and dark mode
  • Test mobile navigation with nested sections
  • Verify the “new content” type picker works in nested sections