<?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: Alexandru A</title>
    <description>The latest articles on DEV Community by Alexandru A (@programmer4web).</description>
    <link>https://dev.to/programmer4web</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%2F3862880%2Febd2d0a8-5feb-4c94-a413-17e5769bd609.png</url>
      <title>DEV Community: Alexandru A</title>
      <link>https://dev.to/programmer4web</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/programmer4web"/>
    <language>en</language>
    <item>
      <title>How We Stopped Mixing Up Test Cases Across 5 Client Projects</title>
      <dc:creator>Alexandru A</dc:creator>
      <pubDate>Sat, 12 Sep 2026 11:27:40 +0000</pubDate>
      <link>https://dev.to/programmer4web/how-we-stopped-mixing-up-test-cases-across-5-client-projects-4bjj</link>
      <guid>https://dev.to/programmer4web/how-we-stopped-mixing-up-test-cases-across-5-client-projects-4bjj</guid>
      <description>&lt;p&gt;A typical week running QA for multiple clients looks something like this: Monday, a SaaS client needs results by Wednesday. Tuesday, an e-commerce client finds a checkout bug that needs same-day regression. Wednesday, a healthcare client uploads a new feature for next week's review. Three clients, three timelines, one QA team keeping all of it moving at once. If that rhythm sounds familiar, the actual challenge usually isn't the workload itself, it's keeping each client's context, test cases, and defects from blurring together while you context-switch between them all day.&lt;/p&gt;

&lt;p&gt;We found one structural decision, not a new tool and not more process, that made the biggest difference in keeping all three engagements on track without any of them bleeding into each other. We wrote up the complete workflow in &lt;a href="https://app.evaficy.com/managing-multiple-qa-projects" rel="noopener noreferrer"&gt;Managing Multiple Client QA Projects&lt;/a&gt;. Here's the short version.&lt;/p&gt;

&lt;h2&gt;
  
  
  One project, one client
&lt;/h2&gt;

&lt;p&gt;The boundary that actually matters is the project itself: each client gets their own project, holding their scenarios, defects, and environments completely apart from anyone else's. There's no separate "client" object in Evaficy Smart Test, so a naming convention like "Acme Corp: Checkout" isn't just decoration, it's what actually lets your team recognize which project belongs to which client at a glance, whether that's scanning a project list or reading a message about a defect. Skip that discipline, or get inconsistent about it across the team, and projects blur together fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Roles don't leak between projects
&lt;/h2&gt;

&lt;p&gt;This is the detail that made the real difference for us. Roles (Owner, Product Owner, Tech Lead, QA Engineer, Viewer) are set per project, not per account. The same person can be QA Engineer on one client's project and Tech Lead on another's, at the same time, with zero crossover between them.&lt;/p&gt;

&lt;p&gt;In practice, that looks like this: your most experienced tester is a QA Engineer executing tests on your SaaS client's project on Monday, then spends Tuesday as the Tech Lead approving validation requests on your e-commerce client's project, then is back to QA Engineer for the healthcare client on Wednesday. Three different responsibilities, three different clients, same person, and none of those permissions bleed into a project they don't belong to.&lt;/p&gt;

&lt;p&gt;That single fact changes how you staff engagements. You can assign each client the role structure that specific project needs, without spinning up a new account for someone or worrying that a permission granted on one project quietly carries over somewhere it shouldn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Know your ceiling before you say yes
&lt;/h2&gt;

&lt;p&gt;Before taking on a fourth or fifth concurrent client, it's worth checking your actual capacity on two fronts: the practical kind (how much time your team genuinely has) and the platform kind (how many projects and team members your current plan supports). The second one is easy to overlook until it becomes a blocker mid-onboarding, so it's worth checking before the sales conversation, not during it. If you're already close to your plan's ceiling, upgrading ahead of time is a much smoother move than discovering the limit with a client waiting on you. Knowing both numbers ahead of time makes "can we take this client?" a much easier conversation than finding out the hard way mid-engagement.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four-step loop that repeats for every client
&lt;/h2&gt;

&lt;p&gt;The same loop runs for every client project, and that repetition is the point:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Kickoff: scope and access get defined, so everyone agrees upfront on what's in and what's out&lt;/li&gt;
&lt;li&gt;Build: scenarios and test cases come together based on that agreed scope&lt;/li&gt;
&lt;li&gt;Validate: a Tech Lead and Product Owner sign off before anything runs, catching gaps early&lt;/li&gt;
&lt;li&gt;Execute: testing happens and results get delivered to the client&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because the loop is identical across clients, onboarding a new team member only means teaching it once. They can apply the same four steps to the next client project without relearning anything, and you can spot-check quality by asking the same questions at the same stage regardless of which client it's for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scope creep's one-line defense
&lt;/h2&gt;

&lt;p&gt;New scope that shows up mid-engagement becomes its own scenario, not an edit to the one you already validated. That keeps the original scope's history intact and gives you a clean, honest record of what was actually agreed to versus what got added later, which matters the next time a client asks why an estimate changed.&lt;/p&gt;

&lt;p&gt;This turns "can you also just check X while you're in there" from an invisible scope expansion into a visible, separately-tracked item. It doesn't stop clients from asking, and it shouldn't, since requirements genuinely evolve. What it does is make the extra work legible: your team can point to exactly what was added, when, and estimate it on its own terms instead of quietly absorbing it into the original timeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Project-per-client is a structural boundary, not a naming habit, and it's what actually keeps client data from crossing over.&lt;/li&gt;
&lt;li&gt;Roles are set per project, so the same person can take on different responsibilities for different clients with zero crossover.&lt;/li&gt;
&lt;li&gt;Check your real capacity, both team time and plan limits, before committing to a new client engagement.&lt;/li&gt;
&lt;li&gt;New scope gets tracked as a new scenario, keeping the original agreement and the additions clearly separate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this required new tooling on top of what we already used day to day, just a different way of structuring the same work. That's usually the more durable fix anyway: a decision about structure holds up better under deadline pressure than a habit does.&lt;/p&gt;

&lt;p&gt;The full workflow, including plan limits, a real capacity-planning framework, and the complete kickoff-to-delivery handoff, is here: &lt;a href="https://app.evaficy.com/managing-multiple-qa-projects" rel="noopener noreferrer"&gt;Managing Multiple Client QA Projects&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>qa</category>
      <category>productivity</category>
    </item>
    <item>
      <title>We Ran the Numbers: Manual vs. AI-Generated Test Cases (Real Cost Breakdown)</title>
      <dc:creator>Alexandru A</dc:creator>
      <pubDate>Thu, 10 Sep 2026 07:32:55 +0000</pubDate>
      <link>https://dev.to/programmer4web/we-ran-the-numbers-manual-vs-ai-generated-test-cases-real-cost-breakdown-3kbf</link>
      <guid>https://dev.to/programmer4web/we-ran-the-numbers-manual-vs-ai-generated-test-cases-real-cost-breakdown-3kbf</guid>
      <description>&lt;p&gt;Manual test case writing brings something valuable to every project: a QA engineer's full context and judgment on each individual case. AI-assisted generation brings something equally valuable: speed, producing a complete first draft in seconds instead of hours. Both approaches have real strengths, and most QA agencies end up using some blend of the two. What's less common is actually measuring that blend, so we wanted to know exactly how much time and cost each approach takes for the same scope of work, and where the line between them should sit.&lt;/p&gt;

&lt;p&gt;We measured it on a real e-commerce checkout flow project (product selection, cart, payment, order confirmation) and wrote up the complete workflow in &lt;a href="https://app.evaficy.com/qa-for-agencies" rel="noopener noreferrer"&gt;How QA Agencies Use AI Test Generation to Deliver Faster&lt;/a&gt;. Here's the short version: just the arithmetic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the 30-34 hours go with manual testing
&lt;/h2&gt;

&lt;p&gt;A checkout flow redesign is a well-scoped project. Here's where a QA engineer's time typically goes when writing test cases by hand for a project like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reviewing requirements and acceptance criteria: 2 hours&lt;/li&gt;
&lt;li&gt;Writing 50-100 test cases across happy paths, negative flows, edge cases, and boundary conditions: 16-20 hours&lt;/li&gt;
&lt;li&gt;Reviewing and refining with the product owner: 4 hours&lt;/li&gt;
&lt;li&gt;Executing tests and logging defects: 8 hours&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's 30-34 hours total, with 16-20 of them dedicated to writing test cases before execution even begins. Those hours buy something real: test cases shaped by product knowledge and judgment about what's likely to break.&lt;/p&gt;

&lt;h2&gt;
  
  
  The napkin math
&lt;/h2&gt;

&lt;p&gt;At a fully-loaded QA engineer cost of $25/hour (a typical blended rate for a team based in Eastern Europe, for example), writing 50-100 test cases by hand costs $750-850 in labor. That's the investment in a thorough, well-considered first draft of your test suite.&lt;/p&gt;

&lt;p&gt;An AI-assisted pass on the same scope works differently: about 30 minutes describing the feature, generation in seconds, then two hours reviewing and refining the output. Labor cost: roughly $150.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Manual&lt;/th&gt;
&lt;th&gt;AI-assisted&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Time&lt;/td&gt;
&lt;td&gt;16-20 hours&lt;/td&gt;
&lt;td&gt;~2.5 hours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;$750-850&lt;/td&gt;
&lt;td&gt;~$150&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Same scope. Same 50-100 test cases covering the same flows. An 18-hour, roughly $1,350 difference: time you can reallocate to execution, defect analysis, and deeper exploratory work.&lt;/p&gt;

&lt;p&gt;That difference compounds well. If your agency runs five similar projects a year, that's roughly 90 hours and $6,750 in labor freed up for the work clients notice most: deeper exploratory testing, faster turnaround, or taking on an additional project without hiring anyone. It's a standing margin improvement on every project of similar shape going forward.&lt;/p&gt;

&lt;h2&gt;
  
  
  What each approach is best at
&lt;/h2&gt;

&lt;p&gt;Manual test writing and AI generation aren't competing for the same job. Each is strongest in a different place.&lt;/p&gt;

&lt;p&gt;Where AI-assisted generation excels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Functional testing of well-defined features and forms&lt;/li&gt;
&lt;li&gt;Regression testing after product updates&lt;/li&gt;
&lt;li&gt;API and backend testing with consistent, rule-based scenarios&lt;/li&gt;
&lt;li&gt;Happy paths, negative scenarios, and standard boundary conditions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Where manual QA judgment adds the most value:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exploratory testing: finding the cases nobody thought to write down&lt;/li&gt;
&lt;li&gt;UX and usability judgment calls&lt;/li&gt;
&lt;li&gt;Complex workflows spanning multiple systems&lt;/li&gt;
&lt;li&gt;Security, compliance, and accessibility testing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The strongest setup combines both. AI-assisted generation covers the structured, high-volume ground quickly, and the hours it frees up go straight into the exploratory and judgment-based testing that benefits most from a human. Teams getting the biggest margin benefit tend to be the ones who moved their QA engineers from writing to reviewing, then reinvested the extra hours into the testing that genuinely needs a person doing the thinking.&lt;/p&gt;

&lt;h2&gt;
  
  
  What clients actually respond to
&lt;/h2&gt;

&lt;p&gt;Clients care about outcomes more than methodology. Whatever mix of manual and AI-assisted testing produces the result, what matters to a client is turnaround time, quality, and cost.&lt;/p&gt;

&lt;p&gt;In practice, that means leading with the outcome works well: "We deliver test results in 48 hours instead of five business days, at the same quality." It keeps the conversation focused on what the client actually came for, regardless of which methods produced the result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it in a week, not a quarter
&lt;/h2&gt;

&lt;p&gt;You don't need to overhaul your process to see how this compares for your own team. Pick one feature you'd test this week anyway. Write the acceptance criteria the way you normally would. Generate half the test cases with AI and write the other half by hand, then have someone senior review both sets without knowing which is which. Compare time spent and defects found.&lt;/p&gt;

&lt;p&gt;That's the whole pilot: a controlled comparison on real work you were already planning to do. It gives you your own numbers, on your own codebase, with your own team's actual review standards, which matters more than any published benchmark including this one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Manual test case writing and AI-assisted generation each bring something different: judgment and context versus speed and volume.&lt;/li&gt;
&lt;li&gt;Combining both, using AI for structured coverage and reinvesting the saved hours into exploratory and judgment-based testing, is where the real margin benefit shows up.&lt;/li&gt;
&lt;li&gt;Clients respond to outcomes such as faster turnaround and consistent quality, whatever mix of methods produces them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We go deeper on this in &lt;a href="https://app.evaficy.com/qa-for-agencies" rel="noopener noreferrer"&gt;How QA Agencies Use AI Test Generation to Deliver Faster&lt;/a&gt;: the full breakdown of where the hybrid model pays off, how to introduce it to your own team, and a real 3-week pilot plan for testing it on your next client project.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>ai</category>
      <category>productivity</category>
      <category>agile</category>
    </item>
    <item>
      <title>How I Used AI Tools to Create a SaaS Demo Video as a Solo Developer</title>
      <dc:creator>Alexandru A</dc:creator>
      <pubDate>Thu, 02 Jul 2026 16:11:21 +0000</pubDate>
      <link>https://dev.to/programmer4web/how-i-used-ai-tools-to-create-a-saas-demo-video-as-a-solo-developer-3145</link>
      <guid>https://dev.to/programmer4web/how-i-used-ai-tools-to-create-a-saas-demo-video-as-a-solo-developer-3145</guid>
      <description>&lt;p&gt;Creating a product demo video for a SaaS launch sounds straightforward until you actually sit down to do it. As a solo developer launching Evaficy Smart Test on Product Hunt, I had no active video production setup, no marketing team, and no budget for professional editing. I did have some basic video editing knowledge from about ten years ago, enough to understand tracks, timelines, and how to import files — but nothing recent and nothing close to professional production experience. Here is how AI-assisted tools bridged that gap and made the entire process not just possible but genuinely good.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting with AI consultation
&lt;/h2&gt;

&lt;p&gt;The first step was not picking up a camera or opening an editor. It was thinking through the structure. I consulted with Claude to build a script optimized specifically for a Product Hunt audience — short attention spans, technical viewers, and a 60 to 90 second sweet spot for demo videos. The script went through several iterations: adjusting the opening to lead with value rather than complaints about the problem space, trimming feature coverage to the three or four most impactful moments, and rewriting every sentence for &lt;strong&gt;AI voiceover&lt;/strong&gt; pacing — shorter sentences, no ambiguous numbers, natural pause points between scenes.&lt;br&gt;
The consultation also produced something I would not have thought of independently: splitting the recording into separate scene clips rather than one continuous screen recording. The reasoning was simple — if one scene needs a retake, you redo 15 seconds, not the entire video. This single decision saved significant time during editing.&lt;/p&gt;
&lt;h2&gt;
  
  
  Choosing the right tools for each job
&lt;/h2&gt;

&lt;p&gt;A trap many developers fall into is reaching for the most powerful tool available rather than the most appropriate one. For &lt;strong&gt;screen recording&lt;/strong&gt;, Windows Snipping Tool was genuinely sufficient. It captures at 1080p, exports clean MP4 files, and requires zero setup. No OBS configuration, no scene management, no learning curve. For a silent screen capture of a web application UI, it was exactly the right tool.&lt;br&gt;
For AI voiceover I used ElevenLabs Text to Speech — the only part of this entire production where I spent any money, approximately 7 USD for the full script across all six scenes. The settings that produced natural calm narration suitable for a technical SaaS product:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Voice: Joseff Novak — Calm and Professional&lt;/li&gt;
&lt;li&gt;Model: Eleven Multilingual v2&lt;/li&gt;
&lt;li&gt;Speed: 0.98&lt;/li&gt;
&lt;li&gt;Stability: 60%&lt;/li&gt;
&lt;li&gt;Similarity Boost: 75%&lt;/li&gt;
&lt;li&gt;Style: 0%&lt;/li&gt;
&lt;li&gt;Speaker Boost: Enabled&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The stability at 60% gave consistent delivery without sounding robotic, while the slightly reduced speed at 0.98 added natural breathing room between sentences. Generating each scene as a separate audio clip rather than one long file made timeline alignment in the editor significantly easier.&lt;/p&gt;

&lt;p&gt;For editing I used &lt;strong&gt;DaVinci Resolve&lt;/strong&gt; free version — no watermark, no length limit, full 1080p export at 30fps as H.264 MP4. My ten year old video editing knowledge was just enough to feel oriented in the interface: I understood what tracks were, how importing worked, and the general concept of a timeline. What I did not know — specifically how to add separate audio tracks and unlink video from its embedded silent audio — took about fifteen minutes of trial and error to figure out. The free version handled everything needed for a straightforward assembly edit without any paid features. The YouTube preset in the Deliver tab handled all the technical export settings automatically.&lt;/p&gt;

&lt;p&gt;For hosting, YouTube was the natural choice — free, reliable, and dev.to renders YouTube links as embedded players automatically when you paste the URL on its own line.&lt;/p&gt;
&lt;h2&gt;
  
  
  The scene-by-scene approach in practice
&lt;/h2&gt;

&lt;p&gt;The final video runs approximately 82 seconds across six scenes, each recorded separately against the actual product UI at app.evaficy.com:&lt;/p&gt;

&lt;p&gt;Homepage hero section overview (8 seconds)&lt;br&gt;
Projects and Scenarios view (12 seconds)&lt;br&gt;
AI test case generation in action (15 seconds)&lt;br&gt;
Test runs overview with step by step execution, pass/fail tracking, and the defect creation form (22 seconds — the most complex scene, intentionally given more time)&lt;br&gt;
AI Risk Insights dashboard (13 seconds)&lt;br&gt;
Sign-up and CTA screen (12 seconds)&lt;/p&gt;

&lt;p&gt;The 22 second test runs scene is worth noting specifically. The initial script allocated 15 seconds but the feature complexity genuinely required more time to demonstrate meaningfully. Rather than rushing it, I extended that scene and adjusted the voiceover script accordingly. Having separate clips made this a simple timeline adjustment rather than a full re-record.&lt;/p&gt;

&lt;p&gt;The result&lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/NQBM6-UYqjc"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  What AI actually changed
&lt;/h2&gt;

&lt;p&gt;The honest conclusion is not that AI replaced skill or effort — it is that AI compressed the learning curve and filled the gaps where inexperience or rustiness would have otherwise created a bottleneck. Script structure that would have taken hours of research came from a conversation. Voiceover that would have required hiring a narrator or recording myself as a non-native English speaker came from a text input and approximately 7 USD in ElevenLabs credits. Remembering how DaVinci Resolve's track system worked took minutes of guided trial and error rather than watching hours of tutorials.&lt;br&gt;
The creative and technical decisions were still mine. AI handled the parts where a ten year gap in experience would have slowed everything down.&lt;br&gt;
For &lt;strong&gt;solo developers&lt;/strong&gt; building in public with no marketing budget, that compression matters. The total production cost was under 7 USD. The tools are good enough now that production quality is no longer gated behind budget, specialization, or an unbroken decade of keeping your skills current.&lt;/p&gt;

&lt;p&gt;Have you created a demo video for your own product? What tools did you use and what would you do differently? Drop it in the comments.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Evaficy Smart Test is live on Product Hunt today if you are curious what I have been building&lt;/em&gt;:&lt;br&gt;
&lt;a href="https://www.producthunt.com/products/evaficy-smart-test?utm_source=other&amp;amp;utm_medium=social" rel="noopener noreferrer"&gt;Evaficy Smart Test on Product Hunt&lt;/a&gt;&lt;br&gt;
&lt;a href="https://app.evaficy.com" rel="noopener noreferrer"&gt;Evaficy Smart Test&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>tutorial</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Chasing a Ghost: Debugging a Silent Google OAuth Failure in Production</title>
      <dc:creator>Alexandru A</dc:creator>
      <pubDate>Thu, 02 Jul 2026 09:22:33 +0000</pubDate>
      <link>https://dev.to/programmer4web/chasing-a-ghost-debugging-a-silent-google-oauth-failure-in-production-p4j</link>
      <guid>https://dev.to/programmer4web/chasing-a-ghost-debugging-a-silent-google-oauth-failure-in-production-p4j</guid>
      <description>&lt;p&gt;Yesterday I launched &lt;a href="https://www.producthunt.com/products/evaficy-smart-test?utm_source=other&amp;amp;utm_medium=social" rel="noopener noreferrer"&gt;Evaficy Smart Test&lt;/a&gt; on Product Hunt — an AI-powered QA platform I've been building solo. Quiet launch, but that's not really what this post is about.&lt;/p&gt;

&lt;p&gt;This morning I woke up to intermittent &lt;code&gt;invalid_grant&lt;/code&gt; errors on Google Sign-In in production. No clear pattern. No reliable way to reproduce it by clicking around myself. Just the occasional 500, logged with no obvious trigger next to it.&lt;/p&gt;

&lt;p&gt;Here's how I tracked it down — because the actual cause turned out to be something I wouldn't have guessed, and I suspect it's more common than people realize.&lt;/p&gt;

&lt;h2&gt;
  
  
  The symptom
&lt;/h2&gt;

&lt;p&gt;Users occasionally hit a 500 error trying to sign in with Google. Not every time. Not for every user. No visible pattern in &lt;em&gt;when&lt;/em&gt; it happened.&lt;/p&gt;

&lt;p&gt;The stack trace pointed at &lt;code&gt;passport-oauth2&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TokenError: Bad Request
    at OAuth2Strategy.parseErrorResponse
    at OAuth2Strategy._createOAuthError
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Classic &lt;code&gt;invalid_grant&lt;/code&gt; — Google rejecting an authorization code as invalid, expired, or already used.&lt;/p&gt;

&lt;h2&gt;
  
  
  The obvious suspects (all wrong)
&lt;/h2&gt;

&lt;p&gt;My first instinct was &lt;strong&gt;double-invocation&lt;/strong&gt; — somewhere, the same authorization code was probably being sent to Google twice. Common causes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A router mounted twice (I actually found a comment in my own code from a past bug: &lt;code&gt;// Bug fixed: was '/auth/google' (double prefix since router is mounted at /auth)&lt;/code&gt; — promising lead, right?)&lt;/li&gt;
&lt;li&gt;A React &lt;code&gt;useEffect&lt;/code&gt; firing twice, maybe due to StrictMode&lt;/li&gt;
&lt;li&gt;The OAuth callback route being hit twice in the middleware chain
I checked all three. All clean. The router was mounted exactly once. The frontend button did a plain &lt;code&gt;window.location.href&lt;/code&gt; redirect — no React state, no effects anywhere near the callback. The middleware chain had no loop-back.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dead ends, but useful ones — they narrowed the search.&lt;/p&gt;

&lt;h2&gt;
  
  
  The clue that mattered
&lt;/h2&gt;

&lt;p&gt;I asked for the actual server logs instead of trying to reproduce the bug live (reproducing intermittent bugs by clicking around is a great way to burn an afternoon for nothing). One log entry stood out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/auth/google/callback?iss=https%3A%2F%2Faccounts.google.com&amp;amp;code=...
&amp;amp;scope=email+profile+...&amp;amp;authuser=2&amp;amp;prompt=none"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;prompt=none&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;My actual "Continue with Google" button used &lt;code&gt;prompt: 'select_account'&lt;/code&gt; — it always produces an interactive flow with a visible account picker. It would &lt;em&gt;never&lt;/em&gt; generate a &lt;code&gt;prompt=none&lt;/code&gt; callback. That single query parameter meant this request wasn't coming from a real click on my button at all. Something else was silently triggering Google auth in the background.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual cause
&lt;/h2&gt;

&lt;p&gt;A quick grep through the frontend turned up this, still mounted at the app root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GoogleOAuthProvider&lt;/span&gt; &lt;span class="na"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Authentication&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;GoogleOAuthProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;GoogleOAuthProvider&lt;/code&gt; is from &lt;code&gt;@react-oauth/google&lt;/code&gt; — a &lt;em&gt;different&lt;/em&gt;, client-side OAuth pattern than the one I was actually using. My real login flow was 100% server-side: browser redirect → Express → &lt;code&gt;passport-google-oauth20&lt;/code&gt; → session. Textbook, and it worked fine on its own.&lt;/p&gt;

&lt;p&gt;But at some earlier point I'd started migrating toward the client-side flow, wired up the provider, wrote a &lt;code&gt;useGoogleLogin&lt;/code&gt; hook — then abandoned it and commented the hook out. The provider, though, stayed mounted.&lt;/p&gt;

&lt;p&gt;Here's the part that got me: &lt;strong&gt;commenting out the hook doesn't stop the provider from doing anything.&lt;/strong&gt; &lt;code&gt;GoogleOAuthProvider&lt;/code&gt; loads Google's Identity Services script the moment it renders, regardless of whether anything downstream actually consumes its context. That script can independently trigger a silent/background re-authentication check using the same &lt;code&gt;client_id&lt;/code&gt; — completely decoupled from any button click. Since that client ID's redirect URI pointed at my real callback endpoint, the silent flow's (possibly stale or already-consumed) code was landing on my production auth route and getting rejected by Google as &lt;code&gt;invalid_grant&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Dead code, alive side effects. The import was unused. The component it wrapped didn't need it. But the script it loaded was doing something the whole time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix&lt;/strong&gt; was one line of removal — dropping the provider wrapper entirely, since nothing in the active code path used it. I also hardened the callback handler itself, since &lt;code&gt;TokenError&lt;/code&gt; was throwing &lt;em&gt;before&lt;/em&gt; passport's &lt;code&gt;failureRedirect&lt;/code&gt; logic could catch it, turning a normal auth failure into an unhandled 500:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/google/callback&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;passport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;google&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;clientUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?auth_error=google`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loginErr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loginErr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loginErr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;})(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* existing session logic */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dead code isn't always inert.&lt;/strong&gt; An unused import can still execute side effects the moment it's rendered/loaded — check what a component &lt;em&gt;does on mount&lt;/em&gt;, not just whether anything reads its output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A single unexplained query parameter can be the whole story.&lt;/strong&gt; &lt;code&gt;prompt=none&lt;/code&gt; was the one detail that ruled out every "obvious" theory and pointed straight at the real cause.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logs before reproduction, when the bug is intermittent.&lt;/strong&gt; I never had to manually trigger this bug once — the production logs had already recorded exactly the parameter I needed to diagnose it.
If you're running Google OAuth alongside any client-side Google library (&lt;code&gt;@react-oauth/google&lt;/code&gt;, &lt;code&gt;google-one-tap&lt;/code&gt;, etc.) — even ones you think are unused — it's worth checking whether they're still mounted somewhere, quietly doing their own thing in the background.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Building &lt;a href="https://www.producthunt.com/products/evaficy-smart-test?utm_source=other&amp;amp;utm_medium=social" rel="noopener noreferrer"&gt;Evaficy Smart Test&lt;/a&gt;, an AI-powered QA/test case generation platform, solo. Happy to answer questions about the debugging process or the product itself in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>debugging</category>
      <category>oauth</category>
      <category>mongodb</category>
      <category>node</category>
    </item>
    <item>
      <title>I built an AI-powered QA platform because manual testing tools haven't kept up — launching on Product Hunt today</title>
      <dc:creator>Alexandru A</dc:creator>
      <pubDate>Wed, 01 Jul 2026 00:54:59 +0000</pubDate>
      <link>https://dev.to/programmer4web/i-built-an-ai-powered-qa-platform-because-manual-testing-tools-havent-kept-up-launching-on-3h64</link>
      <guid>https://dev.to/programmer4web/i-built-an-ai-powered-qa-platform-because-manual-testing-tools-havent-kept-up-launching-on-3h64</guid>
      <description>&lt;p&gt;For the past year and a half, I've been building &lt;strong&gt;Evaficy Smart Test&lt;/strong&gt; — a QA platform for manual testing teams that brings AI into the parts of the workflow that are still painfully manual: writing test cases, tracking validation, and figuring out what to test before a release.&lt;/p&gt;

&lt;p&gt;We're launching on Product Hunt today, and I wanted to share the story behind it, plus some of the technical decisions along the way.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/NQBM6-UYqjc"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The problem&lt;br&gt;
Most QA tooling falls into two buckets: traditional test management tools (think spreadsheets with extra steps), or newer AI tools that focus almost entirely on test automation — generating Selenium/Playwright scripts, self-healing locators, that kind of thing.&lt;br&gt;
But a huge number of QA teams are still doing manual testing — and that segment hasn't gotten much attention from AI tooling. Writing comprehensive test cases, covering edge cases, tracking validation across reviewers, linking failed tests to defects — all of that is still mostly manual, repetitive work.&lt;/p&gt;

&lt;p&gt;What I built&lt;br&gt;
Evaficy Smart Test covers the full manual QA workflow:&lt;/p&gt;

&lt;p&gt;Projects &amp;amp; Scenarios — organize test cases by project, with role-based access for Owners, POs, Tech Leads, and QA&lt;br&gt;
AI test case generation — generate comprehensive test cases (including edge cases and negative scenarios) based on test type and affected page&lt;br&gt;
Expert validation — PO/Tech Lead review workflow before test cases go live&lt;br&gt;
Test runs — step-by-step execution with real-time pass/fail tracking&lt;br&gt;
Defect tracking — inline defect logging with full traceability, one-click push to Jira&lt;br&gt;
AI Risk Insights — scores scenarios by failure risk using historical test run data, so teams know where to focus before a release&lt;/p&gt;

&lt;p&gt;Stack &amp;amp; technical notes&lt;br&gt;
Built with React and Material UI on the frontend, with Stripe for subscription billing. Some of the more interesting build challenges:&lt;/p&gt;

&lt;p&gt;Designing the AI generation flow to feel fast and controllable rather than a black box — letting users specify criteria (test type, affected page, custom fields) rather than just a free-text prompt&lt;br&gt;
Building the validation workflow so AI-generated and manually-written test cases go through the same review process, since trust in test cases matters more than where they came from&lt;br&gt;
Keeping the defect → Jira sync simple (one click, no field mapping headaches) since context-switching is the #1 complaint QA teams have about their current tools&lt;/p&gt;

&lt;p&gt;Try it out&lt;br&gt;
If you work in QA, or you're a dev/PM who's tired of testing falling through the cracks, I'd genuinely love your feedback.&lt;br&gt;
🚀 We're live on Product Hunt today: &lt;a href="https://www.producthunt.com/products/evaficy-smart-test?launch=evaficy-smart-test" rel="noopener noreferrer"&gt;Evaficy Smart Test - Launch Page&lt;/a&gt;&lt;br&gt;
🔗 Try Evaficy Smart Test: &lt;a href="https://app.evaficy.com" rel="noopener noreferrer"&gt;Evaficy Smart Test&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy to answer any questions about the build, the AI integration, or manual QA workflows in general — drop a comment below!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>saas</category>
      <category>qa</category>
    </item>
    <item>
      <title>AI Made Me a Better Reviewer (The Hard Way)</title>
      <dc:creator>Alexandru A</dc:creator>
      <pubDate>Mon, 13 Apr 2026 03:45:53 +0000</pubDate>
      <link>https://dev.to/programmer4web/ai-made-me-a-better-reviewer-the-hard-way-3dm5</link>
      <guid>https://dev.to/programmer4web/ai-made-me-a-better-reviewer-the-hard-way-3dm5</guid>
      <description>&lt;p&gt;I build a SaaS QA platform. When AI coding assistants became good enough to trust with real work, I leaned in — and my velocity went up noticeably. Less boilerplate, faster feature implementation, fewer rabbit holes on syntax I'd forgotten.&lt;/p&gt;

&lt;p&gt;But something shifted that I didn't expect. I wasn't writing less code and saving time. I was writing less code and reviewing more instead.&lt;/p&gt;

&lt;p&gt;For a while I thought that was fine. Then one evening I pushed a feature involving Google SSO and suddenly users couldn't log in. Not "the Google button doesn't work" — I mean the entire sign-in and logout flow was broken. Silent. No obvious error.&lt;/p&gt;

&lt;p&gt;I dug in. The AI had been working on routing middleware to serve pre-rendered pages for SEO. Reasonable task. What it also did, without flagging it, was intercept every GET request that looked like a browser navigation — including /auth/google. The OAuth redirect came back from Google, hit the middleware, got served the SPA shell instead, and the session was never established.&lt;/p&gt;

&lt;p&gt;The fix was one line. The damage could have been significant if it had reached more users.&lt;/p&gt;

&lt;p&gt;Here's what stayed with me: the feature it was building worked perfectly. The tests I ran against the new functionality passed. What broke was something adjacent — code I didn't ask it to touch, changed in a way that was internally logical but contextually wrong.&lt;/p&gt;

&lt;p&gt;That's the real lesson about working with AI on production code. It doesn't lack skill. It lacks awareness of consequences outside the task boundary. It will solve the problem you gave it and not think twice about what it quietly rearranged to get there.&lt;/p&gt;

&lt;p&gt;So now I review differently. I don't just check that the feature works. I read the diff the way I'd read a pull request from a smart junior developer who might not know what they don't know — looking for what changed that I didn't ask to change.&lt;/p&gt;

&lt;p&gt;The trade-off is real: I write far less code than before, but I spend more time in review. Whether that's a net win depends on how careful you are. If you test properly and treat every AI output as a PR that needs approval, the productivity gain holds. If you trust the result because the happy path works, you're accumulating invisible risk.&lt;/p&gt;

&lt;p&gt;I've caught CORS middleware generating 500 stack traces from bot traffic. A VAT field being HTML-encoded into / before storing in the database. A soft-delete flag silently stripped from a user object because the context mapper didn't know about the new field.&lt;/p&gt;

&lt;p&gt;Each one was a sensible decision in isolation. Each one was wrong in context.&lt;/p&gt;

&lt;p&gt;AI didn't make me a worse engineer. But it did make me a much more deliberate reviewer. That wasn't in the marketing material.&lt;/p&gt;

&lt;p&gt;Do you have similar situations — where AI solved the task but broke something it wasn't supposed to touch? How do you review AI-generated code differently now?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>codereview</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How Do You Actually Integrate Jira and CI/CD Into a Real Web Application?</title>
      <dc:creator>Alexandru A</dc:creator>
      <pubDate>Sat, 11 Apr 2026 11:31:24 +0000</pubDate>
      <link>https://dev.to/programmer4web/how-do-you-actually-integrate-jira-and-cicd-into-a-real-web-application-417d</link>
      <guid>https://dev.to/programmer4web/how-do-you-actually-integrate-jira-and-cicd-into-a-real-web-application-417d</guid>
      <description>&lt;p&gt;When you first hear about integrating Jira with CI/CD, it often sounds abstract—like something happening “around” your application rather than inside it. But once you start building a real system, you quickly realize the challenge is very concrete:&lt;/p&gt;

&lt;p&gt;How do you connect your &lt;strong&gt;codebase, pipelines, and issue tracking&lt;/strong&gt; into one coherent flow?&lt;/p&gt;

&lt;p&gt;Recently, while working on a quality assurance platform, I had to implement this integration from scratch—and the biggest lesson was this: integration is not a feature, it’s an architecture decision.&lt;/p&gt;

&lt;p&gt;At the application level, everything starts with traceability. Your web app doesn’t directly “talk” to Jira in most cases, but your development workflow does. The first real bridge between your application and Jira is your version control strategy. By enforcing that every branch and commit references a Jira ticket, you create a consistent link between code and requirement. This small discipline allows Jira to automatically reflect development activity without any custom logic inside your application.&lt;/p&gt;

&lt;p&gt;From there, CI/CD becomes the execution engine. Tools like Jenkins or GitHub Actions take over whenever code is pushed. They build your application, run validations, and determine whether the current state of the code is reliable. At this point, your application is indirectly part of the integration: every change to it triggers a pipeline that evaluates its health.&lt;/p&gt;

&lt;p&gt;The real integration happens when you close the loop between pipelines and Jira. A CI/CD system that only runs builds is useful, but not enough. The moment it starts sending results back—marking tickets as ready, blocked, or completed—you move from automation to coordination. This is where your application lifecycle becomes visible to the entire team.&lt;/p&gt;

&lt;p&gt;In practice, this often means configuring your pipeline to communicate with Jira through existing integrations or APIs. For example, after a successful build, a ticket can automatically move to a “Ready for Testing” state. If something fails, the same ticket can be flagged or annotated with the failure context. None of this requires your web application to change—but it fundamentally changes how your application is delivered and validated.&lt;/p&gt;

&lt;p&gt;While implementing this for a QA-focused platform, I went a step further and introduced a few key capabilities to make the integration truly practical in real-world scenarios. One of them was &lt;strong&gt;personal access tokens&lt;/strong&gt;, allowing users to securely authenticate API requests and integrate the platform with CI/CD pipelines, scripts, and internal tools—without exposing credentials. This made automation much safer and easier to adopt.&lt;/p&gt;

&lt;p&gt;Another important piece was the ability to &lt;strong&gt;push defects directly to Jira&lt;/strong&gt;, including detailed information and reproduction steps. Instead of manually copying bugs, test failures could be turned into structured Jira issues instantly, improving both speed and consistency in defect tracking.&lt;/p&gt;

&lt;p&gt;Finally, I implemented &lt;strong&gt;CI/CD-triggered Test Runs&lt;/strong&gt;, where pipelines can automatically create test runs as part of the delivery process. This ensures that every build is not just compiled, but also prepared for structured and traceable manual testing, fully connected back to Jira.&lt;/p&gt;

&lt;p&gt;One subtle but important realization is that your application’s structure influences how effective this integration can be. If your project lacks clear environments, consistent build steps, or reliable test execution, even the best Jira integration will feel unreliable. In other words, CI/CD doesn’t fix chaos—it exposes it.&lt;/p&gt;

&lt;p&gt;What truly defines a good integration is not how many tools you connect, but how well they communicate. A well-integrated setup creates a powerful effect: your Jira board becomes a real-time reflection of your application’s state. You no longer rely on manual updates or status meetings, because the system itself tells the story.&lt;/p&gt;

&lt;p&gt;In the end, integrating Jira and CI/CD into a web application is not about embedding APIs into your frontend or backend. It’s about connecting the lifecycle around your application so tightly that every change is tracked, validated, and visible.&lt;/p&gt;

&lt;p&gt;And once that happens, your application is no longer just code—it becomes part of a system that continuously proves its own quality.&lt;/p&gt;

&lt;p&gt;So the real question is not whether you can integrate Jira and CI/CD…&lt;/p&gt;

&lt;p&gt;…but whether your application lifecycle is structured well enough to support it.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>automation</category>
      <category>testing</category>
      <category>javascript</category>
    </item>
    <item>
      <title>What happens when you give an AI your acceptance criteria and ask it to write test cases?</title>
      <dc:creator>Alexandru A</dc:creator>
      <pubDate>Mon, 06 Apr 2026 06:13:08 +0000</pubDate>
      <link>https://dev.to/programmer4web/what-happens-when-you-give-an-ai-your-acceptance-criteria-and-ask-it-to-write-test-cases-1d3</link>
      <guid>https://dev.to/programmer4web/what-happens-when-you-give-an-ai-your-acceptance-criteria-and-ask-it-to-write-test-cases-1d3</guid>
      <description>&lt;p&gt;After years of building frontend applications across e-health and e-learning products, I've sat in enough sprint reviews to notice a pattern: &lt;em&gt;QA test cases&lt;/em&gt; are written the same way every time. Happy path first, a handful of negative cases if the deadline allows, edge cases if the tester has seen that bug before.&lt;/p&gt;

&lt;p&gt;The process is repetitive, experience-dependent, and the first thing to get cut when a release is running late.&lt;/p&gt;

&lt;p&gt;So I started experimenting — feeding acceptance criteria directly to an AI and asking for a complete test suite. Here's an honest account of what works, what doesn't, and what it actually changes about the process.&lt;/p&gt;

&lt;p&gt;What the AI gets right immediately&lt;/p&gt;

&lt;p&gt;The output quality on structured coverage is genuinely impressive. Given clear acceptance criteria, the AI will produce happy path cases, negative scenarios, boundary conditions, and precondition states faster than any manual process — and it won't skip the boring ones.&lt;/p&gt;

&lt;p&gt;It also structures the output consistently: steps, expected results, preconditions. That consistency alone has value when you're maintaining a growing test library across releases.&lt;/p&gt;

&lt;p&gt;Where it falls short&lt;/p&gt;

&lt;p&gt;The AI has no knowledge of your system beyond what you give it. It doesn't know that your application handles an unauthenticated empty cart differently from an authenticated one, or that a particular field has a known edge case from three sprints ago.&lt;/p&gt;

&lt;p&gt;More critically: vague acceptance criteria produce vague test cases. With a human tester, ambiguity triggers a question. With an AI, it triggers a confident but incorrect assumption. If your requirements only describe the happy path, the generated test suite will skew heavily toward the happy path.&lt;/p&gt;

&lt;p&gt;What actually determines the output quality&lt;/p&gt;

&lt;p&gt;After enough iterations, the pattern is consistent: the quality of the generated tests is almost entirely determined by the quality of the input. A few things that made a measurable difference:&lt;/p&gt;

&lt;p&gt;Write constraints explicitly. "The form should validate correctly" is not a requirement. "The email field must reject inputs without an @ symbol and a valid domain" is.&lt;br&gt;
Include failure conditions in your acceptance criteria. If you only document what should succeed, the AI will generate tests for success.&lt;br&gt;
Specify the user role and context. "As an admin" and "as a guest" produce meaningfully different test suites for the same feature.&lt;br&gt;
Add environment context. First-time user vs returning user, mobile vs desktop, authenticated vs unauthenticated — these details shape coverage significantly.&lt;br&gt;
An honest assessment&lt;/p&gt;

&lt;p&gt;AI doesn't replace a QA engineer. It replaces the first draft.&lt;/p&gt;

&lt;p&gt;A good tester still needs to review the output, discard cases that don't apply to the actual system, and add scenarios based on knowledge no requirements document captures. That judgment isn't going away.&lt;/p&gt;

&lt;p&gt;But the shift from writing to reviewing is more significant than it sounds. Starting with 80% of the test suite already structured means your QA effort goes toward the cases that actually require expertise — the ones that come from understanding the system, not from reading the spec.&lt;/p&gt;

&lt;p&gt;That's a different kind of QA work. Arguably a more valuable one.&lt;/p&gt;

&lt;p&gt;I cover this in more depth in a free QA handbook — link in my profile if you're interested.&lt;/p&gt;

&lt;p&gt;Has anyone else been experimenting with AI-generated test cases? Curious whether the input quality pattern holds across different approaches — and what you've found the AI consistently gets wrong.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>productivity</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
