What Pest tests should you run before deploying CMS changes?

What Pest tests should you run before deploying CMS changes?

Short answer: before every CMS deploy, run a focused Pest subset that proves (1) public pages render crawlable content, (2) published() scopes hide future posts, (3) SEO endpoints (sitemap.xml, robots.txt) reflect real data, and (4) write APIs (MCP/Filament paths) cannot bypass auth. Skip the full suite only when you are fixing unrelated code with zero CMS touch.

On Aviwebsquad I treat these as merge gates—not vanity coverage numbers.

Why CMS regressions hurt more than feature bugs

A broken checkout annoys users. A broken publish scope leaks drafts. A broken sitemap deindexes your blog. A broken crawlable fallback triggers AdSense “low value content” even when articles are fine.

CMS tests should protect distribution, not just CRUD.

My minimum deploy set (7 tests)

1. Homepage crawlable fallback

Assert id="inertia-static-fallback" exists, includes <h1>, and meta description appears before Vite module scripts. Proves non-JS clients and reviewers see substance.

2. Blog post show + Article schema props

Hit a factory-published post. Assert 200, inertia component blog/Show, and articleJsonLd present. Optional: strip tags from crawlableHtml and assert word count > 300.

3. Future published_at hidden

Create status=published with published_at = now()->addWeek(). Blog index and sitemap must not list it.

4. Sitemap honesty

5. Category archive crawlable copy

Category with description renders in static fallback; CollectionPage JSON prop exists.

6. Contact form happy path

POST valid payload (with reCAPTCHA faked in tests). Assert mail queued and DB row created.

7. MCP upsert auth

Token without mcp:cms.write gets 403. Valid token creates/updates post and respects published_at.

Run them:

vendor/bin/sail artisan test --compact \
  tests/Feature/Seo/CrawlablePagesTest.php \
  tests/Feature/Cms/SeoEndpointsTest.php \
  tests/Feature/Api/McpUpsertBlogPostTest.php

Adjust paths to your project; keep the categories stable.

Tests I add when touching specific areas

Change Extra tests
Search query matches title + tag slug
Comments moderation flag, honeypot field
Media upload MIME allowlist, collection name
Menus primary/footer locations render
Legal pages policy slugs 200 + canonical

Pest patterns that age well

Factories over fixtures. BlogPost::factory()->published() encodes the scope rules once.

Inertia assertions for JSON-LD when schema is client-rendered:

$response->assertInertia(fn (Assert $page) => $page
    ->has('faqJsonLd')
    ->where('faqJsonLd.@type', 'FAQPage'));

RefreshDatabase on feature tests touching posts—CMS state rots fast without it.

Avoid brittle HTML equality. Assert substrings and invariants, not full Blade dumps.

What I deliberately do not test every deploy

Solo maintainers need a 10-minute gate, not a 40-minute suite.

CI recommendation

- name: CMS smoke tests
  run: vendor/bin/sail artisan test --compact tests/Feature/Seo tests/Feature/Cms/SeoEndpointsTest.php

Fail the deploy if SEO/CMS smoke fails—even when “only” frontend changed. Inertia still depends on controller props.

FAQ

Is 100% coverage worth it for a blog CMS?

No. Cover invariants: visibility, SEO surfaces, auth on writes, and public 200s for golden paths.

Should MCP tests hit production?

Never in CI. Test against local/Sail with Sanctum tokens from php artisan mcp:token.

How do I test scheduled posts go live?

Travel time in Pest:

$this->travel(8)->days();
// assert post now visible

Do architecture tests help?

php artisan test --filter=arch can ban env() outside config and enforce controller namespaces—useful guardrails, not a deploy blocker.

Bottom line

Treat Pest as your CMS seatbelt: small, uncomfortable for two minutes, invaluable when you refactor publish logic at midnight. The list above is what I run before shipping Aviwebsquad content changes—copy the categories, plug in your paths, and keep publishing without fearing invisible SEO regressions.