<?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: Daniel Reade</title>
    <description>The latest articles on DEV Community by Daniel Reade (@daniel_reade123).</description>
    <link>https://dev.to/daniel_reade123</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%2F3888921%2F8dbc25ff-e3ac-4a11-a16d-b20948660044.png</url>
      <title>DEV Community: Daniel Reade</title>
      <link>https://dev.to/daniel_reade123</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/daniel_reade123"/>
    <language>en</language>
    <item>
      <title>Are AI Test-Generation Tools Actually Worth It Yet?</title>
      <dc:creator>Daniel Reade</dc:creator>
      <pubDate>Wed, 15 Jul 2026 12:57:33 +0000</pubDate>
      <link>https://dev.to/daniel_reade123/are-ai-test-generation-tools-actually-worth-it-yet-113d</link>
      <guid>https://dev.to/daniel_reade123/are-ai-test-generation-tools-actually-worth-it-yet-113d</guid>
      <description>&lt;p&gt;Most teams do not buy test-generation tools because they love tests. They buy them after a sprint where a small checkout change breaks five unrelated flows, nobody catches it in review, and the team spends half a day tracing a bug that a decent regression test would have found in minutes. That is the real pitch: less drift, fewer blind spots, and less time writing setup code by hand. The harder question is whether current AI tools can deliver that without filling a repo with brittle noise.&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%2Fimages.unsplash.com%2Fphoto-1579389083078-4e7018379f7e%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3w5NzAwMDh8MHwxfHNlYXJjaHwxfHxwcm9ncmFtbWVyJTIwb2ZmaWNlJTIwbGFwdG9wfGVufDB8MHx8fDE3ODQwNTQxNTd8MA%26ixlib%3Drb-4.1.0%26q%3D80%26w%3D1080" 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%2Fimages.unsplash.com%2Fphoto-1579389083078-4e7018379f7e%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3w5NzAwMDh8MHwxfHNlYXJjaHwxfHxwcm9ncmFtbWVyJTIwb2ZmaWNlJTIwbGFwdG9wfGVufDB8MHx8fDE3ODQwNTQxNTd8MA%26ixlib%3Drb-4.1.0%26q%3D80%26w%3D1080" width="1080" height="720"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where AI test generation already helps
&lt;/h2&gt;

&lt;p&gt;The strongest use case is not full test authoring. It is draft generation around obvious seams. Give a model a controller, a service boundary, and a couple of input shapes, and it can often produce a first pass that saves thirty minutes of setup. For a Java team working with mocks and fixtures, that matters. A developer who used to spend the first hour of a task wiring test objects can now start from generated scaffolding, then trim and tighten.&lt;/p&gt;

&lt;p&gt;That is a narrower promise than the marketing copy, but it is a useful one. Teams exploring &lt;a href="https://en.wikipedia.org/wiki/AI_automation_testing_tools" rel="noopener noreferrer"&gt;how AI is being applied to automate testing workflows&lt;/a&gt; usually get the best return when they keep the tool close to repetitive work: fixture creation, edge-case suggestions, and parameterized input expansion. Those are annoying jobs, and they are easy to review.&lt;/p&gt;

&lt;p&gt;There is another practical win. Generated tests can expose gaps in naming and structure. If a model keeps producing confusing assertions around one module, the module may be the problem. The code may have too many hidden dependencies or side effects that even a machine struggles to isolate. In that sense, the tool acts like a rough mirror. It does not just produce tests. It reveals where testability has already been neglected.&lt;/p&gt;

&lt;h2&gt;
  
  
  The quality problem is still real
&lt;/h2&gt;

&lt;p&gt;A generated test that passes is not automatically a good test. This is the central problem, and it is why many senior engineers remain cautious. Current tools often optimize for syntactic completion instead of behavioral intent. They can produce a green checkmark while asserting almost nothing important.&lt;/p&gt;

&lt;p&gt;Picture a payment method validator with eight branches: expired card, missing CVV, unsupported region, malformed token, and a few happy-path variations. A weak model may generate ten tests, but seven only verify that a method returns a non-null response. That looks like coverage. It is not meaningful protection. The test file grows, CI slows down, and the team gains very little signal.&lt;/p&gt;

&lt;p&gt;This is where &lt;a href="https://en.wikipedia.org/wiki/Software_testing" rel="noopener noreferrer"&gt;core concepts and levels of software testing&lt;/a&gt; still matter more than the tool itself. Unit tests should isolate behavior. Integration tests should verify boundaries that matter. Regression suites should protect known failure points. If a team cannot explain what a test is meant to catch, AI will only automate confusion faster. Good testing still begins with risk selection, not output volume. The repo does not care how quickly weak tests were produced.&lt;/p&gt;

&lt;h2&gt;
  
  
  The best results come from constrained generation
&lt;/h2&gt;

&lt;p&gt;The tools look far better when the target is tightly scoped. Ask for a full suite across an unfamiliar codebase and the output often turns generic. Ask for tests around one pure function with clear inputs and expected failures, and results improve fast. Constraint is doing most of the work.&lt;/p&gt;

&lt;p&gt;This is why tools such as &lt;a href="https://en.wikipedia.org/wiki/EvoSuite" rel="noopener noreferrer"&gt;an automated JUnit test generator for Java projects&lt;/a&gt; remain relevant in the conversation. They come from a world where generation is bounded by method signatures, search strategies, and measurable goals rather than open-ended prompting. Modern AI layers can be useful on top of that, especially for readability or cleanup, but the older lesson still holds: narrow the target and inspect every assertion.&lt;/p&gt;

&lt;p&gt;A practical workflow looks like this. A developer selects one utility class of maybe 150 lines, asks for edge-case candidates, reviews the proposed cases, then keeps only the tests that express a business rule or a plausible failure mode. That is manageable. Letting a bot spray 200 tests across a module with network calls, caching behavior, and hidden time dependencies is how teams end up deleting half the output a week later.&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%2Fimages.unsplash.com%2Fphoto-1606857521015-7f9fcf423740%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3w5NzAwMDh8MHwxfHNlYXJjaHwxfHxkZXZlbG9wZXJzJTIwb2ZmaWNlJTIwcmV2aWV3fGVufDB8MHx8fDE3ODQwNTQxNTh8MA%26ixlib%3Drb-4.1.0%26q%3D80%26w%3D1080" 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%2Fimages.unsplash.com%2Fphoto-1606857521015-7f9fcf423740%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3w5NzAwMDh8MHwxfHNlYXJjaHwxfHxkZXZlbG9wZXJzJTIwb2ZmaWNlJTIwcmV2aWV3fGVufDB8MHx8fDE3ODQwNTQxNTh8MA%26ixlib%3Drb-4.1.0%26q%3D80%26w%3D1080" width="1080" height="720"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What practitioners are arguing about
&lt;/h2&gt;

&lt;p&gt;The debate has moved past whether generated tests are possible. Now the argument is about trust. In &lt;a href="https://www.reddit.com/r/PracticalTesting/comments/1u86ct6/are_aigenerated_tests_becoming_good_enough/" rel="noopener noreferrer"&gt;practical testers debating whether AI-generated tests are "good enough"&lt;/a&gt;, the recurring pattern is cautious optimism from people using AI as an assistant, not as a replacement for judgment. That distinction matters. The tool is acceptable when it accelerates known work and suspicious when it claims to remove thinking from the loop.&lt;/p&gt;

&lt;p&gt;The skeptical side has a strong case too. In &lt;a href="https://www.reddit.com/r/AI_Coders/comments/1s4d7s0/the_problem_with_aigenerated_tests_theyre_written/" rel="noopener noreferrer"&gt;a critique arguing AI-generated tests can create false confidence&lt;/a&gt;, the concern is familiar to anyone who has inherited a noisy suite: lots of assertions, little intent, poor maintainability. A generated test can look polished enough to survive code review while still missing the branch that actually breaks production.&lt;/p&gt;

&lt;p&gt;So where does that leave a team lead deciding whether to adopt one of these tools? The right question is boring and useful: what failure mode is this supposed to reduce? If the answer is setup time on repetitive units, fine. If the answer is “better overall quality,” that is too vague to manage. Tools earn their keep when the expected gain can be checked in a pull request and felt during incident review.&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%2Fimages.unsplash.com%2Fphoto-1497032628192-86f99bcd76bc%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3w5NzAwMDh8MHwxfHNlYXJjaHwxfHxsYXB0b3AlMjBkZXNrJTIwY29mZmVlfGVufDB8MHx8fDE3ODQwNTQxNTh8MA%26ixlib%3Drb-4.1.0%26q%3D80%26w%3D1080" 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%2Fimages.unsplash.com%2Fphoto-1497032628192-86f99bcd76bc%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3w5NzAwMDh8MHwxfHNlYXJjaHwxfHxsYXB0b3AlMjBkZXNrJTIwY29mZmVlfGVufDB8MHx8fDE3ODQwNTQxNTh8MA%26ixlib%3Drb-4.1.0%26q%3D80%26w%3D1080" width="1080" height="720"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;AI test-generation tools are worth using when the bar is set correctly. They can save time on repetitive scaffolding, surface missed edge cases, and help teams move faster through low-risk test authoring. They still struggle with the part that matters most: choosing assertions that protect real behavior instead of decorating a codebase with busywork.&lt;/p&gt;

&lt;p&gt;That makes the adoption decision less dramatic than vendors suggest. A team does not need to choose between full trust and total rejection. It needs a review standard. Keep generated tests if they express a clear rule, fail for an understandable reason, and remain cheap to maintain after the original prompt is forgotten. Drop the rest without sentiment.&lt;/p&gt;

&lt;p&gt;The useful framing is simple. These tools are junior contributors with unnatural speed and uneven judgment. Teams that treat them that way can get real value now. Teams that mistake output for coverage will pay for that confusion later.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>testing</category>
      <category>devops</category>
      <category>automation</category>
    </item>
    <item>
      <title>Taming Flaky Automated Tests For Good</title>
      <dc:creator>Daniel Reade</dc:creator>
      <pubDate>Wed, 08 Jul 2026 17:47:18 +0000</pubDate>
      <link>https://dev.to/daniel_reade123/taming-flaky-automated-tests-for-good-42al</link>
      <guid>https://dev.to/daniel_reade123/taming-flaky-automated-tests-for-good-42al</guid>
      <description>&lt;p&gt;A flaky test usually reveals itself at the worst possible moment: the build is green on one commit, red on the next, and green again after someone hits rerun. That pattern wastes more than CI minutes. It trains teams to doubt the signal from the suite, then to ignore failures that may actually matter. Once that habit sets in, shipping slows down because nobody trusts the line between a real regression and random noise.&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%2F5rdg0jskiigozyc75gyq.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%2F5rdg0jskiigozyc75gyq.jpg" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Start by classifying the failure mode
&lt;/h2&gt;

&lt;p&gt;Teams often call every intermittent failure "flaky," but that label is too broad to fix anything. A timeout during a browser click, a test that passes only in parallel runs, and an assertion that fails near midnight are different classes of problems. Treating them as one bucket leads to generic cleanup work that never lands.&lt;/p&gt;

&lt;p&gt;A useful first pass is to tag failures by observable behavior. For example, create categories like timing, shared state, test data drift, environment mismatch, and nondeterministic assertions. In a suite of 800 tests, even a rough spreadsheet can surface patterns fast. If 25 failures in one week all involve delayed page rendering after an API call, the next step is obvious. If another cluster appears only when tests run on Linux workers, that points somewhere else entirely. The point is to reduce mystery.&lt;/p&gt;

&lt;p&gt;This is where &lt;a href="https://en.wikipedia.org/wiki/Flaky_test" rel="noopener noreferrer"&gt;understanding flaky tests and mitigation strategies&lt;/a&gt; helps because it frames flakiness as a test-quality problem rather than simple bad luck. Pair that with &lt;a href="https://en.wikipedia.org/wiki/Software_testing" rel="noopener noreferrer"&gt;core principles of software testing and test design&lt;/a&gt;, and the work becomes less emotional. Engineers stop arguing about whether a test is "probably fine" and start asking what input, dependency, or assumption is moving under it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Remove hidden sources of nondeterminism
&lt;/h2&gt;

&lt;p&gt;Many flaky tests are self-inflicted. They pull live time from the system clock, depend on randomized ordering, reuse the same user account across workers, or assume a database starts empty. All of those choices can work for weeks, then fall apart when parallelism increases or CI agents get slower.&lt;/p&gt;

&lt;p&gt;The fix is rarely glamorous. Freeze time in code paths that compare timestamps. Seed randomness so the same execution path can be reproduced. Generate test data with unique IDs per run, then clean it up in a predictable way. If a suite provisions one temporary account for 40 parallel tests, expect collisions around password resets, profile edits, or background jobs. Give each worker isolated state and most of that noise disappears.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Test_automation" rel="noopener noreferrer"&gt;Practical test automation practices to reduce flakiness&lt;/a&gt; matter here because automation is not just about coverage. It is also about repeatability. A browser test that clicks a button before the app has settled is not fast, it is fragile. A service test that assumes queue processing finishes within 300 milliseconds is not precise, it is optimistic. Stability comes from controlling inputs and waiting on meaningful signals, such as a completed network response, a visible state change, or a known event in the log stream.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retries hide symptoms when they replace diagnosis
&lt;/h2&gt;

&lt;p&gt;Retries have a place, but only as a short-term containment tool with clear rules. A single retry can help absorb a known infrastructure blip, such as a worker losing network for a moment. The problem starts when teams use reruns as the main strategy. Then the suite stays nominally green while the underlying fault keeps spreading.&lt;/p&gt;

&lt;p&gt;Picture a test that fails one run out of ten because it reads from an eventually consistent search index too soon. Add two retries and the pipeline may look healthy. The defect is still there. Engineers now spend less time seeing the issue, which means they spend less time fixing it. Later, another test hits the same index and the suite becomes noisy again. The retry bought quiet, not reliability.&lt;/p&gt;

&lt;p&gt;That is why &lt;a href="https://www.reddit.com/r/PracticalTesting/comments/1tr0yjj/just_add_retries_is_not_a_flaky_test_strategy/" rel="noopener noreferrer"&gt;why retries alone don't solve flaky test problems&lt;/a&gt; is a useful framing. Retries should produce evidence. Log the first failure, count retry rates per test, and set a threshold where repeated flakes trigger quarantine or mandatory repair. If a test needed a retry in 7 of the last 20 runs, that is not a healthy pass. It is debt with a green badge.&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%2Fcxyd0wy4bq6i6qwjvb59.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%2Fcxyd0wy4bq6i6qwjvb59.jpg" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Build an ownership model for flaky test debt
&lt;/h2&gt;

&lt;p&gt;Flaky tests persist when everybody complains and nobody owns the repair loop. The suite becomes a shared nuisance instead of a maintained system. Ownership does not mean one unlucky person fixes every unstable test. It means the team has a defined path from detection to resolution.&lt;/p&gt;

&lt;p&gt;One workable model is to assign ownership at the service or feature boundary. If checkout tests are unstable, the checkout team gets the alert, the failure history, and the authority to quarantine a test for a short period. Put a time limit on that quarantine. Seven days is concrete enough to create pressure without forcing rushed patches. Also track the cost. If one quarantined test blocks confidence in a release-critical path, that should be visible in sprint planning, not buried in CI logs.&lt;/p&gt;

&lt;p&gt;This is where &lt;a href="https://www.reddit.com/r/programming/comments/1hqsipv/how_to_manage_flaky_tests/" rel="noopener noreferrer"&gt;community approaches to managing flaky test debt and ownership&lt;/a&gt; can be useful, especially for teams that have normalized red builds. Good ownership turns vague frustration into routine maintenance. Someone sees the alert. Someone investigates the last ten failures. Someone either fixes the root cause or removes a test that no longer earns its runtime. Without that loop, flakiness becomes culture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the suite observable enough to debug quickly
&lt;/h2&gt;

&lt;p&gt;A test that fails without context invites guesswork. A test that fails with timing data, screenshots, network traces, and environment details usually gets fixed faster. Observability is what turns an intermittent problem into an actionable one.&lt;/p&gt;

&lt;p&gt;For UI tests, capture the DOM snapshot at failure, a screenshot, browser console output, and the sequence of awaited conditions. For API and integration tests, log request IDs, dependency response times, queue lag, and fixture versions. Keep the logs structured enough that a maintainer can compare two failing runs side by side. If one failure took 14 seconds waiting for a job and another took 200 milliseconds before asserting stale data, they are likely different bugs wearing the same mask.&lt;/p&gt;

&lt;p&gt;The investment pays back quickly. A team with 50 daily CI runs does not need perfect telemetry for every test, but it does need enough evidence to avoid blind reruns. The goal is simple: when a failure appears, the first person looking at it should be able to form a real hypothesis in two minutes. That is how a flaky suite stops feeling haunted and starts acting like software again.&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%2F4gtt5azhyzm7qam5wkhm.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%2F4gtt5azhyzm7qam5wkhm.jpg" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Flaky tests are rarely random in the strict sense. They are systems telling you that timing, state, isolation, or visibility is weaker than the team assumed. The fastest way out is to stop treating each red build as a one-off annoyance. Classify failures, remove nondeterministic inputs, keep retries on a short leash, and make ownership explicit. Then add enough runtime evidence that debugging starts from facts instead of superstition.&lt;/p&gt;

&lt;p&gt;There is a deeper payoff here. A trustworthy test suite changes how a team ships. Reviews move faster, releases feel less ceremonial, and engineers spend less energy negotiating whether a failure counts. That trust is hard to earn once the suite has gone noisy. It is still worth rebuilding, because every stable test becomes a small contract the code can actually keep.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>devops</category>
      <category>automation</category>
      <category>ci</category>
    </item>
    <item>
      <title>The Page Object Model, And When To Skip It</title>
      <dc:creator>Daniel Reade</dc:creator>
      <pubDate>Wed, 01 Jul 2026 15:37:30 +0000</pubDate>
      <link>https://dev.to/daniel_reade123/the-page-object-model-and-when-to-skip-it-2k7m</link>
      <guid>https://dev.to/daniel_reade123/the-page-object-model-and-when-to-skip-it-2k7m</guid>
      <description>&lt;p&gt;A flaky UI suite usually does not fail because the browser is hard. It fails because the test code slowly turns into a second product with its own architecture, naming debates, and maintenance debt. The Page Object Model grew popular for a reason: once a suite passes a few dozen browser tests, selectors spread everywhere, login flows get copied, and one small button rename can break six files at once.&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%2Fm91mxlw5l1zuwoshml8a.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%2Fm91mxlw5l1zuwoshml8a.jpg" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Page Objects Became the Default
&lt;/h2&gt;

&lt;p&gt;Page Object Model, usually shortened to POM, solves a plain problem: too many tests know too much about the page. When a checkout test directly references &lt;code&gt;#email&lt;/code&gt;, &lt;code&gt;.submit-btn&lt;/code&gt;, and a coupon modal selector inside the same spec file, the test becomes brittle in a very practical way. Change the checkout form structure, and every test that touches it needs edits.&lt;/p&gt;

&lt;p&gt;That is why teams building browser suites with tools like &lt;a href="https://en.wikipedia.org/wiki/Selenium_(software)" rel="noopener noreferrer"&gt;why Selenium is used for browser automation and how POM relates&lt;/a&gt; adopted page classes so widely. A &lt;code&gt;CheckoutPage&lt;/code&gt; object can hold selectors, helper methods, and workflow actions in one place. A team with 40 regression cases across sign-in, cart, and payment flows often sees this pay off fast. Rename one selector in the page object, and half the suite survives untouched.&lt;/p&gt;

&lt;p&gt;There is also a design argument behind it. POM borrows from the broader idea that code should hide implementation details behind stable interfaces, a point covered in &lt;a href="https://en.wikipedia.org/wiki/Software_design_pattern" rel="noopener noreferrer"&gt;principles for choosing reusable software design patterns&lt;/a&gt;. If the test says &lt;code&gt;checkout.applyCoupon()&lt;/code&gt; instead of clicking through four nested elements, the intent is easier to read. The benefit is real, especially when the suite is maintained by several engineers over months rather than one person over a sprint.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where POM Starts to Hurt
&lt;/h2&gt;

&lt;p&gt;The trouble begins when page objects become a reflex instead of a choice. A modern front end rarely behaves like a neat stack of pages. It has drawers, embedded widgets, reusable cards, multi-step forms, and state that appears only after an API response. Stuffing all of that into giant &lt;code&gt;HomePage&lt;/code&gt;, &lt;code&gt;DashboardPage&lt;/code&gt;, and &lt;code&gt;SettingsPage&lt;/code&gt; classes can create an awkward abstraction layer that mirrors file names more than user behavior.&lt;/p&gt;

&lt;p&gt;Picture a test suite with 25 Playwright specs and 18 page object files. The &lt;code&gt;DashboardPage&lt;/code&gt; class has methods for opening filters, checking metrics, dismissing banners, exporting reports, and editing profile settings because those controls all exist somewhere on the same route. Now the object is not protecting complexity. It is collecting it. New contributors have to jump between spec and object just to learn where a single click lives.&lt;/p&gt;

&lt;p&gt;This is where the core purpose of &lt;a href="https://en.wikipedia.org/wiki/Test_automation" rel="noopener noreferrer"&gt;how test automation works and when to automate UI tests&lt;/a&gt; matters. UI tests already cost more than service-level checks. If the abstraction layer adds another maintenance surface, the suite gets slower to change without becoming more reliable. The hard question is not whether POM is good or bad. The hard question is whether the page object removes duplication that actually exists, or whether it creates a framework before the suite has earned one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Modern Tools Changed
&lt;/h2&gt;

&lt;p&gt;Playwright and similar frameworks shifted the tradeoff because they already ship with stronger primitives than older browser tools. Locators are more expressive, waiting behavior is built in, and test fixtures can manage setup without as much handwritten plumbing. A short test can stay readable even when it talks to the page directly.&lt;/p&gt;

&lt;p&gt;That is why you now see arguments like &lt;a href="https://www.reddit.com/r/QualityAssurance/comments/14lggw1" rel="noopener noreferrer"&gt;discussion arguing Playwright often eliminates the need for Page Object classes&lt;/a&gt;. The point is not that structure no longer matters. The point is that a lot of historical POM boilerplate existed to compensate for weak ergonomics in older tooling. When a spec can say &lt;code&gt;page.getByRole('button', { name: 'Save' })&lt;/code&gt; and rely on sane waiting, a thin helper may be enough.&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%2Fmwhcbhwja5qoejj0qh38.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%2Fmwhcbhwja5qoejj0qh38.jpg" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take a common case: a login helper, an authenticated fixture, and two small component helpers for a date picker and a modal. That may cover most reuse in a medium suite. Building full page classes for every route can feel tidy at first, but it often buries intent under ceremony. The better abstraction is the one that makes the next failing test easier to fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Skipping POM Is the Smarter Call
&lt;/h2&gt;

&lt;p&gt;Skipping POM makes sense when tests are short, the application uses stable semantic selectors, and most reuse happens around state setup rather than page interaction. In many teams, the bigger source of repetition is not clicking the same button. It is creating the same account, seeding the same cart, or forcing the same permission state before the browser even opens.&lt;/p&gt;

&lt;p&gt;That is the idea behind conversations like &lt;a href="https://www.reddit.com/r/Playwright/comments/1rzb45e/if_we_use_api_calls_for_test_setup_state/" rel="noopener noreferrer"&gt;thread on whether API-based state setup makes Page Object abstractions unnecessary&lt;/a&gt;. Imagine a suite for a subscription app. Instead of navigating through signup, email confirmation, plan selection, and onboarding in every test, a fixture creates a user through an API call and stores auth state once. Each spec can land directly on the scenario it cares about. In that setup, a heavy &lt;code&gt;SignupPage&lt;/code&gt; object adds little value because the flow rarely appears in tests.&lt;/p&gt;

&lt;p&gt;Skipping POM also helps when the UI is highly component-driven. A &lt;code&gt;DateRangePicker&lt;/code&gt; helper used in six screens is often more useful than six page classes that each wrap the same widget differently. Direct locators plus a few focused helpers keep the structure close to the real source of reuse. That makes failures easier to trace when the product team ships fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Better Rule Than “Always Use POM”
&lt;/h2&gt;

&lt;p&gt;The useful rule is simpler: abstract around volatility and repetition, not around every route in the app. If one modal appears in eight flows, extract it. If an address form has the same fields across admin and checkout screens, give it a helper. If a page is touched by one test and has five selectors, leave it inline until duplication shows up twice and starts to bite.&lt;/p&gt;

&lt;p&gt;This keeps architecture proportional to the suite. A 12-spec smoke pack does not need the same shape as a 400-spec cross-browser regression suite. One team may do well with classic page objects because its product is route-heavy and its engineers rotate often. Another team may prefer fixtures, component helpers, and direct locators because most tests are narrow and setup lives in APIs. The right choice depends on where maintenance time is actually going each week.&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%2Fesrr2j8ll7wuigueigr1.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%2Fesrr2j8ll7wuigueigr1.jpg" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The Page Object Model is still useful, but it is no longer the automatic answer many teams inherited from older browser stacks. Good test architecture should reduce the cost of change. That cost shows up in very ordinary places: finding the right selector, updating setup logic, tracing a flaky assertion, or onboarding the next engineer who has to debug a failure at 8 a.m.&lt;/p&gt;

&lt;p&gt;If page objects make those jobs easier, use them. If they turn a small suite into a mini framework with classes nobody enjoys touching, skip them and keep the code closer to the test. Modern automation tools reward smaller abstractions, especially when fixtures and API setup remove most of the repetitive work before the UI even loads. The strongest teams are usually the ones willing to prune patterns that once made sense, then stopped paying rent.&lt;/p&gt;

</description>
      <category>selenium</category>
      <category>testing</category>
      <category>softwaredevelopment</category>
      <category>devops</category>
    </item>
    <item>
      <title>Writing your first end-to-end test in Playwright</title>
      <dc:creator>Daniel Reade</dc:creator>
      <pubDate>Fri, 26 Jun 2026 06:30:20 +0000</pubDate>
      <link>https://dev.to/daniel_reade123/writing-your-first-end-to-end-test-in-playwright-4059</link>
      <guid>https://dev.to/daniel_reade123/writing-your-first-end-to-end-test-in-playwright-4059</guid>
      <description>&lt;p&gt;The first end-to-end test usually feels bigger than it is. A new project, a browser opening and closing, selectors that might break tomorrow, and a quiet suspicion that "real" engineers must have a cleaner way to do it. They do not. Most people start with one useful path, make it pass, then spend the next few runs learning what should have been obvious from the start.&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%2Fo1e25tmsw3f7wtgk7v3y.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%2Fo1e25tmsw3f7wtgk7v3y.jpg" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Pick One User Journey and Keep It Small
&lt;/h2&gt;

&lt;p&gt;A first test should cover a path a real user takes in under a minute. Login is the classic choice, but only if the app actually depends on authentication. A product search, a cart add, or a form submission can be better because the result is visible and easy to verify. The point is not to "cover the app." The point is to prove that the browser can drive one important flow from start to finish without hand-holding.&lt;/p&gt;

&lt;p&gt;That sounds basic, but beginners often reach for too much. They script sign-up, email verification, profile setup, billing, and logout in one file, then wonder why every failure takes ten minutes to diagnose. A tighter start is a six-step path: open homepage, click sign-in, fill two fields, submit, wait for dashboard, verify one heading. That gives enough moving parts to learn navigation, selectors, waits, and assertions.&lt;/p&gt;

&lt;p&gt;If the broader structure of testing still feels fuzzy, reviewing &lt;a href="https://en.wikipedia.org/wiki/Software_testing" rel="noopener noreferrer"&gt;essential software testing concepts for end to end tests&lt;/a&gt; helps frame what this layer is meant to catch. End-to-end tests sit near the top of the stack. They are slower than unit checks, more exposed to UI changes, and valuable because they exercise the system the way a user does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set Up the Test Like a Reader Will Maintain It
&lt;/h2&gt;

&lt;p&gt;A first Playwright file should be readable even after two bad weeks away from the codebase. That means clear naming, one scenario per test, and setup that stays close to the behavior. A lot of early pain comes from abstraction added too soon. If a selector is used once, keep it inline. If a helper hides five browser actions, ask whether the helper saves time or hides the thing that failed.&lt;/p&gt;

&lt;p&gt;A simple structure works well: open the page, perform the action, verify the result. In practice, that might look like visiting &lt;code&gt;/login&lt;/code&gt;, filling email and password, clicking submit, then checking for a visible account panel. If login requires test data, create a single known account for local runs rather than generating fresh users every time. Stable inputs make debugging less theatrical.&lt;/p&gt;

&lt;p&gt;For people just getting oriented, the &lt;a href="https://en.wikipedia.org/wiki/Playwright_%28software%29" rel="noopener noreferrer"&gt;overview of Playwright and its core features&lt;/a&gt; is useful because it explains why the tool feels faster than older browser automation setups. Auto-waiting matters. Built-in locators matter. Cross-browser support matters too, though first tests should run in one browser until the flow is trustworthy.&lt;/p&gt;

&lt;p&gt;A good first milestone is boring: one file, one path, one assertion that means something.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Locators and Assertions That Survive Real UI Changes
&lt;/h2&gt;

&lt;p&gt;The first brittle Playwright test usually breaks because it targets the wrong thing. A CSS chain copied from devtools may pass today and explode after the next layout tweak. Better locators describe what the user can perceive: a button by role and name, an input by label, a heading by text, a form control by placeholder if nothing else exists.&lt;/p&gt;

&lt;p&gt;That approach changes the maintenance cost. Suppose a checkout button moves from the sidebar to a sticky footer. A selector like &lt;code&gt;div.wrapper &amp;gt; div:nth-child(2) button.primary&lt;/code&gt; dies instantly. A locator aimed at a button named "Checkout" often keeps working because the meaning stayed the same while the layout moved around it.&lt;/p&gt;

&lt;p&gt;Assertions should also match the user outcome. After submitting a form, checking that the URL contains &lt;code&gt;/dashboard&lt;/code&gt; can help, but a visible heading or account menu is usually a stronger signal. If a user would say "I know I'm logged in because I can see my account area," your test should verify something equally grounded.&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%2Fbr977zahy2cat2mp9gb7.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%2Fbr977zahy2cat2mp9gb7.jpg" width="799" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to see how working developers talk through these choices, &lt;a href="https://www.reddit.com/r/Playwright/comments/1r136h4/how_do_actual_engineers_write_playwright_tests/" rel="noopener noreferrer"&gt;engineers discuss practical approaches to writing Playwright tests&lt;/a&gt; in a way that feels closer to day-to-day practice than polished tutorials often do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Treat Waiting, State, and Test Data as the Real Work
&lt;/h2&gt;

&lt;p&gt;Most first-test frustration is not about syntax. It is about timing and state. The page loads before the data does. A click succeeds before the UI updates. A previous run leaves behind a user session and the login screen never appears. This is where new testers learn that "works on my machine" can happen inside automation too.&lt;/p&gt;

&lt;p&gt;Playwright helps by waiting for elements to be actionable, but it cannot guess every business-level condition. If a report table takes a second to populate, verify that a specific row or empty-state message appears rather than sleeping for an arbitrary timeout. A hard wait of five seconds is easy to write and expensive to keep. Ten tests using the same habit can add almost a minute of dead time to a run.&lt;/p&gt;

&lt;p&gt;State control matters just as much. Run each test with a known starting point. That can mean clearing storage, using a fresh browser context, or logging in through setup code and landing directly on the target page. The discussion around &lt;a href="https://en.wikipedia.org/wiki/System_testing" rel="noopener noreferrer"&gt;how system testing relates to end to end testing&lt;/a&gt; is useful here because it highlights the difference between validating a whole integrated system and checking a smaller behavior inside it. Your first test does not need to prove every dependency at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  Expect Refactoring After the First Passing Run
&lt;/h2&gt;

&lt;p&gt;A passing test is the start of the work, not the finish line. Once the path succeeds a few times, patterns become obvious. Repeated login steps should move into setup. Selectors that looked fine during the first run start to smell when copied into a second file. Screenshot and trace output becomes more useful after the first confusing failure than it ever was during the happy path.&lt;/p&gt;

&lt;p&gt;This is also the point where many developers begin building a small framework around Playwright. That can be healthy if the extra structure solves a repeated problem. A page object for a noisy checkout screen makes sense after the third test touches it. A giant folder tree with base classes, utility layers, wrappers, and custom runners before test two usually creates more ceremony than value.&lt;/p&gt;

&lt;p&gt;The most grounded advice often comes from people who just went through the messy part. In &lt;a href="https://www.reddit.com/r/Playwright/comments/1tmua5t/built_my_first_playwright_automation_framework/" rel="noopener noreferrer"&gt;developer shares their first Playwright automation framework&lt;/a&gt;, you can see that tension clearly: structure is helpful, but only after the raw test cases reveal what should be extracted.&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%2Fzi00dv1cd8c8r44zvojq.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%2Fzi00dv1cd8c8r44zvojq.jpg" width="800" height="567"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;A first end-to-end test earns its value by teaching boundaries. It shows what the browser can verify, where the app is flaky, and how much hidden setup sits behind a "simple" user action. That lesson matters more than the single green checkmark. Teams that learn it early tend to write fewer oversized tests, choose stronger assertions, and treat test data as part of the product surface rather than background plumbing.&lt;/p&gt;

&lt;p&gt;The smart next step is not to multiply test count as fast as possible. It is to make one test dependable, then add a second path that covers a different risk. If the first file proved login works, the next one might prove a user can complete a purchase or submit a request. After that, patterns worth abstracting reveal themselves on their own. Good Playwright suites usually grow from repeated evidence, not from grand design.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>playwright</category>
      <category>automation</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Writing your first end-to-end test in Playwright</title>
      <dc:creator>Daniel Reade</dc:creator>
      <pubDate>Wed, 24 Jun 2026 12:26:30 +0000</pubDate>
      <link>https://dev.to/daniel_reade123/writing-your-first-end-to-end-test-in-playwright-1cfn</link>
      <guid>https://dev.to/daniel_reade123/writing-your-first-end-to-end-test-in-playwright-1cfn</guid>
      <description>&lt;p&gt;The first end-to-end test usually feels bigger than it is. A new project, a browser opening and closing, selectors that might break tomorrow, and a quiet suspicion that "real" engineers must have a cleaner way to do it. They do not. Most people start with one useful path, make it pass, then spend the next few runs learning what should have been obvious from the start.&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%2Fjxxw5mg3ib1q4qc15z8a.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%2Fjxxw5mg3ib1q4qc15z8a.jpg" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Pick One User Journey and Keep It Small
&lt;/h2&gt;

&lt;p&gt;A first test should cover a path a real user takes in under a minute. Login is the classic choice, but only if the app actually depends on authentication. A product search, a cart add, or a form submission can be better because the result is visible and easy to verify. The point is not to "cover the app." The point is to prove that the browser can drive one important flow from start to finish without hand-holding.&lt;/p&gt;

&lt;p&gt;That sounds basic, but beginners often reach for too much. They script sign-up, email verification, profile setup, billing, and logout in one file, then wonder why every failure takes ten minutes to diagnose. A tighter start is a six-step path: open homepage, click sign-in, fill two fields, submit, wait for dashboard, verify one heading. That gives enough moving parts to learn navigation, selectors, waits, and assertions.&lt;/p&gt;

&lt;p&gt;If the broader structure of testing still feels fuzzy, reviewing &lt;a href="https://en.wikipedia.org/wiki/Software_testing" rel="noopener noreferrer"&gt;essential software testing concepts for end to end tests&lt;/a&gt; helps frame what this layer is meant to catch. End-to-end tests sit near the top of the stack. They are slower than unit checks, more exposed to UI changes, and valuable because they exercise the system the way a user does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set Up the Test Like a Reader Will Maintain It
&lt;/h2&gt;

&lt;p&gt;A first Playwright file should be readable even after two bad weeks away from the codebase. That means clear naming, one scenario per test, and setup that stays close to the behavior. A lot of early pain comes from abstraction added too soon. If a selector is used once, keep it inline. If a helper hides five browser actions, ask whether the helper saves time or hides the thing that failed.&lt;/p&gt;

&lt;p&gt;A simple structure works well: open the page, perform the action, verify the result. In practice, that might look like visiting &lt;code&gt;/login&lt;/code&gt;, filling email and password, clicking submit, then checking for a visible account panel. If login requires test data, create a single known account for local runs rather than generating fresh users every time. Stable inputs make debugging less theatrical.&lt;/p&gt;

&lt;p&gt;For people just getting oriented, the &lt;a href="https://en.wikipedia.org/wiki/Playwright_%28software%29" rel="noopener noreferrer"&gt;overview of Playwright and its core features&lt;/a&gt; is useful because it explains why the tool feels faster than older browser automation setups. Auto-waiting matters. Built-in locators matter. Cross-browser support matters too, though first tests should run in one browser until the flow is trustworthy.&lt;/p&gt;

&lt;p&gt;A good first milestone is boring: one file, one path, one assertion that means something.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Locators and Assertions That Survive Real UI Changes
&lt;/h2&gt;

&lt;p&gt;The first brittle Playwright test usually breaks because it targets the wrong thing. A CSS chain copied from devtools may pass today and explode after the next layout tweak. Better locators describe what the user can perceive: a button by role and name, an input by label, a heading by text, a form control by placeholder if nothing else exists.&lt;/p&gt;

&lt;p&gt;That approach changes the maintenance cost. Suppose a checkout button moves from the sidebar to a sticky footer. A selector like &lt;code&gt;div.wrapper &amp;gt; div:nth-child(2) button.primary&lt;/code&gt; dies instantly. A locator aimed at a button named "Checkout" often keeps working because the meaning stayed the same while the layout moved around it.&lt;/p&gt;

&lt;p&gt;Assertions should also match the user outcome. After submitting a form, checking that the URL contains &lt;code&gt;/dashboard&lt;/code&gt; can help, but a visible heading or account menu is usually a stronger signal. If a user would say "I know I'm logged in because I can see my account area," your test should verify something equally grounded.&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%2Faovc8in6vm4bq2qa7m21.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%2Faovc8in6vm4bq2qa7m21.jpg" width="799" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to see how working developers talk through these choices, &lt;a href="https://www.reddit.com/r/Playwright/comments/1r136h4/how_do_actual_engineers_write_playwright_tests/" rel="noopener noreferrer"&gt;engineers discuss practical approaches to writing Playwright tests&lt;/a&gt; in a way that feels closer to day-to-day practice than polished tutorials often do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Treat Waiting, State, and Test Data as the Real Work
&lt;/h2&gt;

&lt;p&gt;Most first-test frustration is not about syntax. It is about timing and state. The page loads before the data does. A click succeeds before the UI updates. A previous run leaves behind a user session and the login screen never appears. This is where new testers learn that "works on my machine" can happen inside automation too.&lt;/p&gt;

&lt;p&gt;Playwright helps by waiting for elements to be actionable, but it cannot guess every business-level condition. If a report table takes a second to populate, verify that a specific row or empty-state message appears rather than sleeping for an arbitrary timeout. A hard wait of five seconds is easy to write and expensive to keep. Ten tests using the same habit can add almost a minute of dead time to a run.&lt;/p&gt;

&lt;p&gt;State control matters just as much. Run each test with a known starting point. That can mean clearing storage, using a fresh browser context, or logging in through setup code and landing directly on the target page. The discussion around &lt;a href="https://en.wikipedia.org/wiki/System_testing" rel="noopener noreferrer"&gt;how system testing relates to end to end testing&lt;/a&gt; is useful here because it highlights the difference between validating a whole integrated system and checking a smaller behavior inside it. Your first test does not need to prove every dependency at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  Expect Refactoring After the First Passing Run
&lt;/h2&gt;

&lt;p&gt;A passing test is the start of the work, not the finish line. Once the path succeeds a few times, patterns become obvious. Repeated login steps should move into setup. Selectors that looked fine during the first run start to smell when copied into a second file. Screenshot and trace output becomes more useful after the first confusing failure than it ever was during the happy path.&lt;/p&gt;

&lt;p&gt;This is also the point where many developers begin building a small framework around Playwright. That can be healthy if the extra structure solves a repeated problem. A page object for a noisy checkout screen makes sense after the third test touches it. A giant folder tree with base classes, utility layers, wrappers, and custom runners before test two usually creates more ceremony than value.&lt;/p&gt;

&lt;p&gt;The most grounded advice often comes from people who just went through the messy part. In &lt;a href="https://www.reddit.com/r/Playwright/comments/1tmua5t/built_my_first_playwright_automation_framework/" rel="noopener noreferrer"&gt;developer shares their first Playwright automation framework&lt;/a&gt;, you can see that tension clearly: structure is helpful, but only after the raw test cases reveal what should be extracted.&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%2F5gahbg8c1txtz7tl9nyr.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%2F5gahbg8c1txtz7tl9nyr.jpg" width="800" height="567"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;A first end-to-end test earns its value by teaching boundaries. It shows what the browser can verify, where the app is flaky, and how much hidden setup sits behind a "simple" user action. That lesson matters more than the single green checkmark. Teams that learn it early tend to write fewer oversized tests, choose stronger assertions, and treat test data as part of the product surface rather than background plumbing.&lt;/p&gt;

&lt;p&gt;The smart next step is not to multiply test count as fast as possible. It is to make one test dependable, then add a second path that covers a different risk. If the first file proved login works, the next one might prove a user can complete a purchase or submit a request. After that, patterns worth abstracting reveal themselves on their own. Good Playwright suites usually grow from repeated evidence, not from grand design.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>playwright</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Selenium vs Playwright vs Cypress: an honest 2026 take</title>
      <dc:creator>Daniel Reade</dc:creator>
      <pubDate>Mon, 22 Jun 2026 05:30:21 +0000</pubDate>
      <link>https://dev.to/daniel_reade123/selenium-vs-playwright-vs-cypress-an-honest-2026-take-3fhj</link>
      <guid>https://dev.to/daniel_reade123/selenium-vs-playwright-vs-cypress-an-honest-2026-take-3fhj</guid>
      <description>&lt;p&gt;Most teams do not choose a browser testing tool because of a clean technical evaluation. They choose it after a painful week: flaky checkout tests, a CI pipeline that suddenly takes forty minutes, or a new app that mixes tabs, popups, file downloads, and API-heavy pages in ways the old setup never handled well. That is why the Selenium versus Playwright versus Cypress debate still matters in 2026. The useful answer is less about winners and more about fit under real constraints: team skill, browser coverage, debugging speed, and how much test instability a team can tolerate before confidence collapses.&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%2Fknv1d94mlohmc0pfzffh.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%2Fknv1d94mlohmc0pfzffh.jpg" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What teams are really optimizing for
&lt;/h2&gt;

&lt;p&gt;Browser automation choices are rarely about raw feature checklists. A team with six engineers shipping a React dashboard has different needs from a bank maintaining fifteen older internal apps, some of them still carrying brittle workflows inside legacy browsers and custom auth steps. The first team wants fast feedback, simple setup, and traces that show exactly why a selector failed. The second team often cares more about broad compatibility and long-term vendor neutrality.&lt;/p&gt;

&lt;p&gt;That is where Selenium still earns respect. &lt;a href="https://en.wikipedia.org/wiki/Selenium_%28software%29" rel="noopener noreferrer"&gt;Selenium's history, components, and WebDriver API&lt;/a&gt; help explain why it remains deeply embedded in enterprise testing stacks. It fits organizations that already have large suites, custom frameworks, grid infrastructure, and engineers who understand browser drivers at a low level. Replacing that overnight can cost more than continuing to improve it.&lt;/p&gt;

&lt;p&gt;Playwright and Cypress gained ground because they reduced friction. You can feel that difference on day one. A developer writes a login flow, runs it locally, gets auto-waiting behavior, useful error output, and fewer driver headaches. That kind of ergonomics changes adoption. Tooling choices become cultural choices fast, because the team will write more tests with the product that annoys them less.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Playwright feels strongest in 2026
&lt;/h2&gt;

&lt;p&gt;Playwright has become the default recommendation for many greenfield web apps, mostly because it handles modern browser behavior without making the author fight the tool. Multi-tab flows, file uploads, downloads, permission prompts, and network inspection all feel like first-class use cases rather than edge-case add-ons. &lt;a href="https://en.wikipedia.org/wiki/Playwright_%28software%29" rel="noopener noreferrer"&gt;how Playwright works and its cross-language support&lt;/a&gt; is part of the appeal, especially for teams split across JavaScript, Python, Java, or .NET.&lt;/p&gt;

&lt;p&gt;A concrete example helps. Picture a product team testing an onboarding flow with email verification, a payment step, then a PDF download. In older setups, each handoff can become a timing problem. In Playwright, the workflow tends to stay readable: wait for the popup, assert the URL, inspect the download event, capture a trace when the CI run fails. That shortens debug loops more than any benchmark chart will show.&lt;/p&gt;

&lt;p&gt;It also fits the way many teams now work. Product engineers often own at least some end-to-end coverage, not just QA specialists. When the same person writes UI code in the afternoon and a regression test before leaving, good defaults matter. That practical pull shows up in community conversations like &lt;a href="https://www.reddit.com/r/softwaretesting/comments/1u85cbm/should_i_switch_from_selenium_to_playwright_and/" rel="noopener noreferrer"&gt;developers weighing whether to switch from Selenium to Playwright&lt;/a&gt;. The migration question keeps coming up because the daily writing experience is hard to ignore.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Cypress still has loyal users
&lt;/h2&gt;

&lt;p&gt;Cypress remains attractive for one simple reason: when it fits your app, it is pleasant to use. The runner is approachable, local debugging is often excellent, and front-end developers can get productive quickly. For a single-page application with stable routes, predictable network calls, and a team working mostly in JavaScript, Cypress can still be a very comfortable place to build confidence.&lt;/p&gt;

&lt;p&gt;Its tradeoffs are also clearer now than they were a few years ago. &lt;a href="https://en.wikipedia.org/wiki/Cypress_%28software%29" rel="noopener noreferrer"&gt;Cypress test runner, architecture, and limitations&lt;/a&gt; matter more once a suite expands beyond straightforward app flows. If your product opens a second tab during OAuth, relies on browser contexts that need strict isolation, or includes file handling that must mirror user behavior closely, those constraints show up quickly. A ten-test suite can feel elegant. A four-hundred-test suite sometimes exposes every design assumption the framework made early on.&lt;/p&gt;

&lt;p&gt;That does not make Cypress obsolete. It makes it specific. Teams with strong component testing habits, a front-end-heavy codebase, and a desire for a tight in-browser development loop may still get excellent value from it. The mistake is treating ease of first use as proof of long-term fit. Early comfort and later flexibility are not the same thing.&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%2Fy4ysnysz5rodd5gr5749.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%2Fy4ysnysz5rodd5gr5749.jpg" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Selenium is older, but old is not the same as wrong
&lt;/h2&gt;

&lt;p&gt;A lot of Selenium criticism is really criticism of aging test suites. That distinction matters. A brittle suite built over seven years with weak locator strategy, inconsistent waits, and too many UI-level assertions will be painful in any framework. Move that suite tool-for-tool into something newer and many of the same habits will survive the migration.&lt;/p&gt;

&lt;p&gt;Selenium still makes sense when browser breadth is non-negotiable, when a company already runs parallel execution at scale, or when the stack around it is bigger than the library itself. Think of a QA group supporting twelve product surfaces with shared page objects, internal reporting, custom containers, and compliance review around every dependency update. In that setting, replacing the execution engine is one part of the cost. Retraining people and rebuilding trust is the bigger one.&lt;/p&gt;

&lt;p&gt;The interesting 2026 question is not whether Selenium is modern enough. It is whether the team using Selenium has disciplined enough engineering practices to keep a large suite healthy. &lt;a href="https://www.reddit.com/r/softwaretesting/comments/1t0u47r/selenium_vs_playwright_ai_testing_tools_what/" rel="noopener noreferrer"&gt;QA practitioners discussing Playwright, Selenium, and AI testing tools&lt;/a&gt; often circle back to this same point. Flakiness is usually an architecture problem before it becomes a brand-name problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest recommendation for most teams
&lt;/h2&gt;

&lt;p&gt;If a team is starting fresh on a modern web app, Playwright is the safest default. It offers strong browser automation, useful debugging artifacts, and fewer setup frustrations than Selenium. It also handles more edge cases cleanly than Cypress for many end-to-end scenarios. That does not mean every team should migrate tomorrow. It means the burden of proof now sits with alternatives when there is no legacy to protect.&lt;/p&gt;

&lt;p&gt;Choose Selenium when you already have meaningful investment, cross-browser depth that has been hardened over time, or language and infrastructure requirements that make continuity valuable. Choose Cypress when the team is front-end-led, the app shape aligns with its runner model, and rapid local iteration matters more than broad execution flexibility.&lt;/p&gt;

&lt;p&gt;The worst choice is the one made from trend anxiety. A team with eighty reliable Selenium tests and a stable release process is in a better position than a team halfway through a fashionable migration with no ownership model. Tools do matter. The discipline around test design, fixture strategy, and failure triage matters more.&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%2Fuvzydga6dibiewtmtir4.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%2Fuvzydga6dibiewtmtir4.jpg" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The strongest browser testing setup in 2026 is usually the one your team can keep trustworthy under release pressure. That shifts the decision away from hype and toward operational reality. How quickly can a failed test be explained? How often does a developer rerun a test before believing it? How expensive is a migration when the current suite already covers revenue-critical flows?&lt;/p&gt;

&lt;p&gt;Playwright has the clearest momentum for new work because it reduces friction without asking teams to give up serious testing depth. Selenium remains viable where scale, history, and compatibility carry real weight. Cypress still belongs in the conversation when the app and team shape match its strengths.&lt;/p&gt;

&lt;p&gt;A useful rule is simple: optimize for confidence per hour, not for framework prestige. The tool that helps a team write stable coverage, debug failures fast, and keep ownership close to the product will usually beat the one that looks strongest in a comparison chart.&lt;/p&gt;

</description>
      <category>selenium</category>
      <category>playwright</category>
      <category>cypress</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
