惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Y
Y Combinator Blog
腾讯CDC
Recent Announcements
Recent Announcements
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Hugging Face - Blog
Hugging Face - Blog
H
Help Net Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Last Week in AI
Last Week in AI
博客园_首页
D
DataBreaches.Net
P
Proofpoint News Feed
云风的 BLOG
云风的 BLOG
V
Visual Studio Blog
月光博客
月光博客
Jina AI
Jina AI
Stack Overflow Blog
Stack Overflow Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 【当耐特】
Vercel News
Vercel News
WordPress大学
WordPress大学
J
Java Code Geeks
博客园 - 聂微东
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
U
Unit 42

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
A test that catches the bug your feature tests can't see
Nasrul Hazim Bin Mohamad · 2026-06-12 · via DEV Community

There's a class of bug that's maddening: it passes every test you have, then crashes in the user's face. I hit one in the admin UI of laravel-config-sso today, and the real fix wasn't changing an icon name — it was writing a test that could see the bug in the first place.

The bug: wrong icon name, crashes only at runtime

The admin UI uses Flux. Flux resolves icons through <flux:delegate-component>, and it throws for a name that doesn't exist:

Flux component [icon.ellipsis] does not exist.

It's an easy mistake. Flux ships Heroicons, not Lucide. So your Lucide reflexes lie to you:

You type (Lucide) Flux wants (Heroicon)
ellipsis ellipsis-horizontal
trash-2 trash
eye-off eye-slash

Why feature tests don't catch it

Here's the interesting part. I had a feature test that hits the admin route and asserts 200. Green. But the real UI crashes. How?

Because in the headless test harness, Flux renders icons as no-ops. No real <flux:delegate-component> boots, so the icon name never gets resolved. The crash only surfaces under a full boot (testbench serve) — exactly where your automated tests don't go.

Analogy: it's like a spell-checker that only runs when you print the document, not while you type. Your tests type away happily. The crash waits at the printer.

The fix: a static test that reads the Blade and validates every icon

Instead of relying on runtime, I wrote a Pest test that reads the Blade view, extracts every icon name (static and inside dynamic expressions), and asserts Flux actually ships a stub for each one:

$fluxIconStubs = base_path('vendor/livewire/flux/stubs/resources/views/flux/icon');

it('only references Flux icons that exist', function () use ($fluxIconStubs) {
    expect(is_dir($fluxIconStubs))->toBeTrue("Flux icon stubs not found");

    $view = file_get_contents(__DIR__.'/../../resources/views/livewire/sso-providers.blade.php');

    // Static `icon="name"` plus quoted tokens inside dynamic
    // `icon="{{ $cond ? 'eye-slash' : 'eye' }}"` expressions
    preg_match_all('/icon="([a-z][a-z0-9-]*)"/', $view, $static);
    preg_match_all('/icon="\{\{(.+?)\}\}"/', $view, $dynamic);

    $names = $static[1];
    foreach ($dynamic[1] as $expression) {
        preg_match_all("/'([a-z][a-z0-9-]*)'/", $expression, $tokens);
        $names = array_merge($names, $tokens[1]);
    }

    $names = array_values(array_unique($names));
    expect($names)->not->toBeEmpty();

    foreach ($names as $name) {
        expect(is_file("{$fluxIconStubs}/{$name}.blade.php"))
            ->toBeTrue("Flux has no icon [{$name}] — use a valid Heroicon name (Flux ships Heroicons, not Lucide).");
    }
});

What I like about this test:

  • It runs against the source of truth. Flux's icon registry is a folder of stubs in vendor/. The test checks directly against that — not a hardcoded list that goes stale.
  • It handles dynamic icons. Toggles like eye / eye-slash are the ones that usually slip through. The second regex catches quoted tokens inside Blade expressions.
  • The failure message teaches. When it breaks, it tells you the real reason: "Flux ships Heroicons, not Lucide." Future-me will be grateful.

That payoff was immediate: the very same Flux free-vs-Pro icon trap bit a sibling package the same day (a webhook/ellipsis/list set that only exists in Flux Pro). A guard test like this turns a "crashes in production" into a "fails in CI" — which is exactly where you want it.

When to reach for this pattern

Not every typo deserves a test. This pattern shines when your runtime lies to you during tests — where a component becomes a no-op, where an adapter is mocked out, where the environment differs from production. There, a static test that reads the artifact (a Blade view, a config file, a migration) can catch what a dynamic test can't.

The rule I keep: if a failure only appears under a full boot but your tests run headless, don't chase the full boot in CI. Catch the thing earlier with a static check over the source files. It's cheaper, faster, and it never renders a no-op.