<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Resque</title>
    <description>The latest articles on DEV Community by Resque (@lxcario).</description>
    <link>https://dev.to/lxcario</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4039965%2F88cd62a5-4166-44a4-b910-f91f01607ce4.gif</url>
      <title>DEV Community: Resque</title>
      <link>https://dev.to/lxcario</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lxcario"/>
    <language>en</language>
    <item>
      <title>I let an AI test my app 55 times in a week. Here's what it broke (and what I broke).</title>
      <dc:creator>Resque</dc:creator>
      <pubDate>Thu, 23 Jul 2026 19:04:26 +0000</pubDate>
      <link>https://dev.to/lxcario/i-let-an-ai-test-my-app-55-times-in-a-week-heres-what-it-broke-and-what-i-broke-51eh</link>
      <guid>https://dev.to/lxcario/i-let-an-ai-test-my-app-55-times-in-a-week-heres-what-it-broke-and-what-i-broke-51eh</guid>
      <description>&lt;p&gt;I had a passing test. Green checkmark, banked in my suite, ran clean every time I looked at it. "Pet sprite renders, no broken image." &lt;/p&gt;

&lt;p&gt;Then I opened the app in an incognito window and the pet was a broken image icon. On every page. For days, apparently.&lt;/p&gt;

&lt;p&gt;The test was green the whole time. This is the story of how that happened and what I did about it — but also the story of the 54 other rounds of letting an AI testing agent use my live app before I trusted my own code.&lt;/p&gt;




&lt;h2&gt;
  
  
  some context
&lt;/h2&gt;

&lt;p&gt;I was building &lt;a href="https://norastudy.vercel.app" rel="noopener noreferrer"&gt;Nora&lt;/a&gt; for a hackathon — a pixel-art study app with spaced repetition, Feynman explanations, and a virtual pet that grows as you learn. About 50 routes, Next.js 16, Supabase, deployed on Vercel.&lt;/p&gt;

&lt;p&gt;The hackathon theme was "Build the Loop." So instead of testing once at the end, I put &lt;a href="https://www.testsprite.com/" rel="noopener noreferrer"&gt;TestSprite&lt;/a&gt; (an AI testing agent) between me and every deploy. The rule: write a feature, let the agent open the live app in a cloud browser and use it like a real person, get a verdict. Pass = banked. Fail = I get a failure bundle with screenshots, DOM snapshots, and a root cause guess. Fix it, redeploy, rerun.&lt;/p&gt;

&lt;p&gt;I did this 55 times over a week. Here's what I learned.&lt;/p&gt;




&lt;h2&gt;
  
  
  how the loop actually works
&lt;/h2&gt;

&lt;p&gt;Four commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# describe what the feature should do, run against live app&lt;/span&gt;
testsprite &lt;span class="nb"&gt;test &lt;/span&gt;create &lt;span class="nt"&gt;--plan-from&lt;/span&gt; ./plans/signup.plan.json &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--type&lt;/span&gt; frontend &lt;span class="nt"&gt;--run&lt;/span&gt; &lt;span class="nt"&gt;--wait&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--target-url&lt;/span&gt; https://norastudy.vercel.app

&lt;span class="c"&gt;# it failed? pull the bundle&lt;/span&gt;
testsprite &lt;span class="nb"&gt;test &lt;/span&gt;failure get &amp;lt;test-id&amp;gt; &lt;span class="nt"&gt;--out&lt;/span&gt; ./.testsprite/failure/

&lt;span class="c"&gt;# fix. redeploy. then:&lt;/span&gt;
testsprite &lt;span class="nb"&gt;test &lt;/span&gt;rerun &amp;lt;test-id&amp;gt; &lt;span class="nt"&gt;--wait&lt;/span&gt;

&lt;span class="c"&gt;# green? banked. next feature.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the whole thing. Not complicated. The interesting part is what it finds.&lt;/p&gt;




&lt;h2&gt;
  
  
  the blank page every new user would've seen
&lt;/h2&gt;

&lt;p&gt;I always test logged into my own account. My account has data. So my dashboard looks great.&lt;/p&gt;

&lt;p&gt;TestSprite creates a fresh account every run. Fresh account = no data = my redirect logic dumped it on a blank &lt;code&gt;/app&lt;/code&gt; shell with nothing on it. No onboarding, no welcome, just white.&lt;/p&gt;

&lt;p&gt;Every new signup would've seen that and left. The fix was one redirect line. But I never would've found it because I never test as someone with zero history.&lt;/p&gt;




&lt;h2&gt;
  
  
  the analytics page that took four rounds to pass
&lt;/h2&gt;

&lt;p&gt;Round 1: 404. I renamed a route during a refactor and forgot.&lt;/p&gt;

&lt;p&gt;Round 2: fixed the route, agent couldn't navigate there through my nested sidebar. Got lost clicking.&lt;/p&gt;

&lt;p&gt;Round 3: told it to hit the URL directly. Worked! Then it asserted a chart that doesn't render on a low-activity account.&lt;/p&gt;

&lt;p&gt;Round 4: fixed the assertion. Still failed.&lt;/p&gt;

&lt;p&gt;The problem was the test's &lt;em&gt;name&lt;/em&gt;. It was called "Analytics page shows stats and charts." The agent read its own name as context and kept hunting for charts that weren't supposed to be there anymore.&lt;/p&gt;

&lt;p&gt;I renamed it. It passed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The name of your test is part of the prompt.&lt;/strong&gt; If you update a test plan but leave the old name, the agent reads the name and gets confused. Weird lesson to learn from a testing tool. But it stuck.&lt;/p&gt;




&lt;h2&gt;
  
  
  the lying test
&lt;/h2&gt;

&lt;p&gt;So — the pet sprite thing.&lt;/p&gt;

&lt;p&gt;Nora has companion pets (Pokémon-like sprites). I had a banked test: "pet sprite renders, not a broken image placeholder." It ran green every single time.&lt;/p&gt;

&lt;p&gt;The sprites were hotlinked from a third-party CDN. That CDN rate-limits. Sometimes it serves the image, sometimes it 404s. My test was running during "good" windows. The green was real but meaningless — it was measuring someone else's uptime, not my code.&lt;/p&gt;

&lt;p&gt;I fixed it by self-hosting all 39 sprites locally. Then banked a new regression test.&lt;/p&gt;

&lt;p&gt;But here's the thing I want to be honest about: &lt;strong&gt;TestSprite did not catch this bug.&lt;/strong&gt; I found it myself — I was demoing the app to a friend on their laptop, opened it fresh with no cache, and there it was. Broken images everywhere. The existing test had been &lt;em&gt;masking&lt;/em&gt; it with flaky passes. I logged it as a manual find in my iteration log, not a tool catch.&lt;/p&gt;

&lt;p&gt;If your testing writeup isn't honest about what the tool finds vs. what you find yourself, none of it means anything.&lt;/p&gt;




&lt;h2&gt;
  
  
  testing the layer a browser can't see
&lt;/h2&gt;

&lt;p&gt;This was genuinely a surprise to me.&lt;/p&gt;

&lt;p&gt;A browser test tells you "the page loads." Cool. But it can't tell you whether the database actually rejects unauthorized access. Those look identical in the UI — the page either loads your data or loads nothing. You can't tell from the outside whether RLS is working or broken.&lt;/p&gt;

&lt;p&gt;TestSprite has a &lt;code&gt;--type backend&lt;/code&gt; mode that runs Python server-side instead of Playwright:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;testsprite &lt;span class="nb"&gt;test &lt;/span&gt;create &lt;span class="nt"&gt;--type&lt;/span&gt; backend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"RLS rejects unauthorized reward manipulation"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--code-file&lt;/span&gt; ./test_rls_security.py &lt;span class="nt"&gt;--run&lt;/span&gt; &lt;span class="nt"&gt;--wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I wrote 7 of these. They prove anonymous users can't call reward RPCs, can't read other users' profiles, can't insert fake flashcards. Stuff that's invisible from the browser.&lt;/p&gt;

&lt;p&gt;If you use Supabase and you don't have something testing your RLS from the outside... you're just trusting it works. Which is brave, I guess.&lt;/p&gt;




&lt;h2&gt;
  
  
  the test I deleted
&lt;/h2&gt;

&lt;p&gt;I wrote a mobile navigation test. The component worked fine on my phone. But the cloud runner uses a fixed desktop viewport and can't resize.&lt;/p&gt;

&lt;p&gt;So the test kept failing. Not because my code was wrong — the runner just couldn't see the mobile nav.&lt;/p&gt;

&lt;p&gt;I deleted the test and wrote exactly why in my log. A suite should only contain tests that can give honest verdicts. A test that fails because of infrastructure limitations trains you to ignore red. That's worse than having no test at all.&lt;/p&gt;




&lt;h2&gt;
  
  
  I also broke the CLI (and fixed it)
&lt;/h2&gt;

&lt;p&gt;I ran the TestSprite CLI so many times that I hit bugs in it. A timeout that swallowed output. A credential edge case. So I fixed them upstream — 10 PRs, all merged. Including a new command called &lt;code&gt;test flaky&lt;/code&gt; that replays a test N times and reports stability.&lt;/p&gt;

&lt;p&gt;Which is exactly what I needed after the green-test-lying-to-me situation. Irony noted.&lt;/p&gt;




&lt;h2&gt;
  
  
  MCP vs CLI vs portal — honest comparison
&lt;/h2&gt;

&lt;p&gt;I tried all three. Here's where I actually ended up:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MCP server&lt;/strong&gt; (IDE integration): used it day one. You tell your AI assistant "test this project" and it figures out what to test. Good for getting started. But for a repeatable loop with specific assertions, the CLI gives you more control.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CLI&lt;/strong&gt;: where I lived. 90% of my workflow. Create, run, fail, fix, rerun. Scriptable. Works in CI/CD. This is the thing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Web portal&lt;/strong&gt;: used for forensics only. When a test fails you can see the exact screenshot, the DOM at that moment, network logs. Useful for debugging. Not where I created or managed tests.&lt;/p&gt;




&lt;h2&gt;
  
  
  the final count
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;55 iterations, 7 build days&lt;/li&gt;
&lt;li&gt;57 tests banked (50 frontend, 7 backend), all green&lt;/li&gt;
&lt;li&gt;100+ total runs&lt;/li&gt;
&lt;li&gt;10 real product bugs found and fixed&lt;/li&gt;
&lt;li&gt;1 test deleted (runner limitation, documented honestly)&lt;/li&gt;
&lt;li&gt;10 PRs merged to the CLI itself&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  what I'd actually tell someone starting this
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Let it test as a stranger.&lt;/strong&gt; The signup bug existed because I only ever tested with my own data-rich account.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Read blocked runs carefully.&lt;/strong&gt; &lt;code&gt;blocked&lt;/code&gt; means the agent couldn't finish the scenario (usually your assertion is bad). &lt;code&gt;failed&lt;/code&gt; means your app broke. Different problems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test the invisible layer.&lt;/strong&gt; If your security is at the database level, a browser test can't prove it works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Distrust green tests that lean on third parties.&lt;/strong&gt; They measure someone else's reliability, not yours.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Be honest.&lt;/strong&gt; I deleted a test, credited a manual find as manual, and documented every "the tool didn't catch this" moment. That honesty is the only reason the other 54 iterations are credible.&lt;/p&gt;




&lt;p&gt;The app is open source: &lt;a href="https://github.com/lxcario/Nora" rel="noopener noreferrer"&gt;github.com/lxcario/Nora&lt;/a&gt;. The full iteration log: &lt;a href="https://github.com/lxcario/Nora/blob/master/LOOP.md" rel="noopener noreferrer"&gt;LOOP.md&lt;/a&gt;. TestSprite CLI: &lt;a href="https://github.com/TestSprite/testsprite-cli" rel="noopener noreferrer"&gt;github.com/TestSprite/testsprite-cli&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you've tried AI-powered testing or have thoughts on flaky test detection, I'd genuinely like to hear about it.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built for &lt;a href="https://www.testsprite.com/hackathon-s3" rel="noopener noreferrer"&gt;TestSprite Hackathon S3&lt;/a&gt;. This won first place — but the workflow is the part that actually stuck with me after.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0p2m1bgitbnpwznkclk6.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0p2m1bgitbnpwznkclk6.jpg" alt="TestSprite logo" width="650" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>ai</category>
      <category>webdev</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
