test(docs): RSpec + Capybara + Playwright system suite for the dogfood site

Merged
MH
4mo ago
+972-92

Why

The gem's CI never exercised the /docs app, so the og:image 404 shipped with zero coverage — it was a bug that only manifests through a booted app's asset pipeline (a logical og_image path resolving to the served, digested /assets URL), which no isolated component spec can reach. This gives the dogfood site a real browser suite so that class of regression can't ship again.

Matches the stack you use everywhere else (cosmos / phlex-reactive / pgbus): RSpec + Capybara + Playwright (chromium). Replaces the throwaway minitest test from the fix PR.

What's covered

System specs (real browser + Puma + Propshaft):

  • seo_meta_tags_spec.rb — the 404 regression guard: visit /, assert og:image is a /assets URL, and that visiting it returns 200 (a shared link's image must actually load). Also og/twitter parity + per-page description.
  • docs_chrome_spec.rb — landing hero, a doc page (masthead + Rouge code block), active sidebar link, sidebar navigation.
  • theme_persistence_spec.rb — theme applies in place and survives navigation (docs-nav + localStorage, no flash).

Request specs (no browser — the JS-off invariant):

  • progressive_enhancement_spec.rb — complete HTML document, sidebar <details open>, server-side active nav, the .md twin, llms.txt.

Setup (mirrors the sibling repos)

  • Gemfile: rspec-rails, capybara + capybara-playwright-driver (require: false), rubocop-capybara/rubocop-rspec. package.json: playwright. bin/rspec binstub.
  • spec/spec_helper.rb, rails_helper.rb (DB-less — use_active_record = false), system_helper.rb; spec/system/support/{playwright,capybara}_setup.rb — Puma server, chromium, HEADLESS env, a viewport matrix (CAPYBARA_SCREEN) with a :desktop_only skip for the always-open-drawer sidebar specs.
  • spec/support/assets.rb precompiles once before a system/request run, so image_url (Propshaft's Static resolver) resolves og:image — mirroring the deploy-time assets:precompile condition, so the suite is self-sufficient.

CI

  • docs/config/ci.rb gains a Test: RSpec step (so bin/ci runs it).
  • .github/workflows/ci.yml gains a docs-site job: bundle in docs/, setup-bun, cache + install Playwright chromium, run rspec. BUNDLE_FROZEN: "false" (the path: ".." gemspec digest changes every commit). Commits docs/Gemfile.lock for reproducible installs — un-ignored, since it's a real deployable app (same as phlex-reactive/docs).

Verification

  • docs: bundle exec rspec → 15 examples, 0 failures from a clean asset state (CI parity).
  • docs: responsive matrix → desktop 10, mobile 8 (:desktop_only skipped).
  • docs: bin/rubocop → 34 files, no offenses.
  • gem: bundle exec rake → 714 examples, 0 failures, rubocop clean (untouched).

Refs #48.

https://claude.ai/code/session_01FPQb6z3YwcKRMbvoJhdxnX