<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Denis De O: Automation & Tools]]></title><description><![CDATA[Tools don’t make you a better QA engineer — but knowing how to use them the right way does.

Here I break down automation, Playwright, APIs, and testing tools in a practical way — focused on real usage, not tutorials you forget the next day.

The goal is simple:
Use tools to support your thinking — not replace it.]]></description><link>https://denisdeoqa.substack.com/s/automation-and-tools</link><image><url>https://substackcdn.com/image/fetch/$s_!8GJg!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F569668de-b6b1-47f6-bc84-b3229c2b261f_1024x1024.png</url><title>Denis De O: Automation &amp; Tools</title><link>https://denisdeoqa.substack.com/s/automation-and-tools</link></image><generator>Substack</generator><lastBuildDate>Sun, 07 Jun 2026 12:55:37 GMT</lastBuildDate><atom:link href="https://denisdeoqa.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Denis De O]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[denisdeoqa@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[denisdeoqa@substack.com]]></itunes:email><itunes:name><![CDATA[Denis De O]]></itunes:name></itunes:owner><itunes:author><![CDATA[Denis De O]]></itunes:author><googleplay:owner><![CDATA[denisdeoqa@substack.com]]></googleplay:owner><googleplay:email><![CDATA[denisdeoqa@substack.com]]></googleplay:email><googleplay:author><![CDATA[Denis De O]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Azure DevOps Test Plans: The Tool That Separates Organized QA from Chaos]]></title><description><![CDATA[Why most QA teams struggle without structured test management]]></description><link>https://denisdeoqa.substack.com/p/azure-devops-test-plans-the-tool</link><guid isPermaLink="false">https://denisdeoqa.substack.com/p/azure-devops-test-plans-the-tool</guid><dc:creator><![CDATA[Denis De O]]></dc:creator><pubDate>Thu, 26 Mar 2026 01:54:12 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!blwB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe755b967-107c-42be-9a91-e432e7baddb9_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!blwB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe755b967-107c-42be-9a91-e432e7baddb9_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!blwB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe755b967-107c-42be-9a91-e432e7baddb9_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!blwB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe755b967-107c-42be-9a91-e432e7baddb9_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!blwB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe755b967-107c-42be-9a91-e432e7baddb9_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!blwB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe755b967-107c-42be-9a91-e432e7baddb9_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!blwB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe755b967-107c-42be-9a91-e432e7baddb9_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e755b967-107c-42be-9a91-e432e7baddb9_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:783821,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://denisdeoqa.substack.com/i/192162985?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe755b967-107c-42be-9a91-e432e7baddb9_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!blwB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe755b967-107c-42be-9a91-e432e7baddb9_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!blwB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe755b967-107c-42be-9a91-e432e7baddb9_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!blwB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe755b967-107c-42be-9a91-e432e7baddb9_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!blwB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe755b967-107c-42be-9a91-e432e7baddb9_1536x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>There&#8217;s a moment in every project where things start slipping.</p><p>Tests are being executed&#8230; but no one is fully sure:</p><ul><li><p>what was tested</p></li><li><p>what&#8217;s still pending</p></li><li><p>what failed yesterday vs today</p></li><li><p>or whether we&#8217;re actually ready to release</p></li></ul><p>I&#8217;ve seen this many times.</p><p>Not because teams lack skill.<br>But because they lack structure.</p><p>That&#8217;s where <strong>Azure Test Plans</strong> comes in.</p><div><hr></div><h2>What Azure Test Plans really is (beyond the definition)</h2><p>Azure Test Plans is not just a place to &#8220;store test cases.&#8221;</p><p>It&#8217;s a <strong>centralized system to control quality</strong> across:</p><ul><li><p>test cases</p></li><li><p>test execution</p></li><li><p>traceability</p></li><li><p>reporting</p></li><li><p>releases</p></li></ul><p>Think of it as the <strong>control tower for QA</strong>.</p><p>Everything flows through it:</p><ul><li><p>requirements &#8594; test cases</p></li><li><p>test cases &#8594; executions</p></li><li><p>executions &#8594; defects</p></li><li><p>defects &#8594; release decisions</p></li></ul><div><hr></div><h2>The core components (simple and practical)</h2><h3>1. Test Plans</h3><p>A <strong>Test Plan = a release or sprint scope</strong></p><p>Example:</p><ul><li><p>Sprint 12 Regression</p></li><li><p>Release 1.5 Validation</p></li></ul><p>&#128073; This is where you define <em>what you&#8217;re validating</em></p><div><hr></div><h3>2. Test Suites</h3><p>Organized containers inside a Test Plan.</p><p>Types:</p><ul><li><p>Static suites (manual grouping)</p></li><li><p>Requirement-based suites (linked to backlog items)</p></li><li><p>Query-based suites (dynamic via filters)</p></li></ul><p>&#128073; This is where structure starts to matter</p><div><hr></div><h3>3. Test Cases</h3><p>Each test case includes:</p><ul><li><p>Steps</p></li><li><p>Expected results</p></li><li><p>Preconditions</p></li><li><p>Attachments</p></li><li><p>Parameters (for data-driven testing)</p></li></ul><p>&#128073; This is your <strong>single source of truth</strong></p><div><hr></div><h3>4. Test Runs &amp; Execution</h3><p>This is where real QA happens.</p><p>You:</p><ul><li><p>execute tests</p></li><li><p>mark Pass / Fail / Blocked</p></li><li><p>log bugs directly</p></li></ul><p>&#128073; Everything is tracked automatically</p><div><hr></div><h3>5. Traceability (This is HUGE)</h3><p>This is where Azure Test Plans shines.</p><p>You can link:</p><ul><li><p>User Story &#8594; Test Case &#8594; Test Result &#8594; Bug</p></li></ul><p>So when someone asks:</p><blockquote><p>&#8220;What was tested for this feature?&#8221;</p></blockquote><p>You don&#8217;t guess.<br>You <strong>show it</strong>.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://denisdeoqa.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://denisdeoqa.substack.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><h2>How a real QA workflow looks like</h2><p>Here&#8217;s a simple, senior-level flow you can explain in interviews:</p><ol><li><p>Requirements are created in Azure Boards</p></li><li><p>Test cases are linked to requirements</p></li><li><p>Test Plan is created for the release</p></li><li><p>Test Suites organize coverage</p></li><li><p>QA executes tests during the sprint</p></li><li><p>Bugs are logged directly from failed steps</p></li><li><p>Reports show progress, pass rate, and gaps</p></li><li><p>Release decision is based on real data</p></li></ol><p>&#128073; This is <strong>test governance in practice</strong></p><div><hr></div><h2>Why companies like Azure Test Plans</h2><p>From a Test Manager perspective:</p><h3>&#9989; Full traceability (audit-ready)</h3><p>Everything is linked and versioned.</p><h3>&#9989; Built-in reporting</h3><ul><li><p>Pass rate</p></li><li><p>Fail trends</p></li><li><p>Execution progress</p></li></ul><h3>&#9989; Integration with DevOps</h3><p>No tool switching:</p><ul><li><p>Boards (requirements)</p></li><li><p>Repos (code)</p></li><li><p>Pipelines (CI/CD)</p></li><li><p>Test Plans (QA)</p></li></ul><h3>&#9989; Supports manual + automation</h3><p>You can:</p><ul><li><p>track manual tests</p></li><li><p>integrate automated results</p></li></ul><div><hr></div><h2>Where people struggle (real talk)</h2><p>Azure Test Plans is powerful&#8230; but not always simple.</p><p>Common issues:</p><ul><li><p>Overcomplicated suite structure</p></li><li><p>Poorly written test cases</p></li><li><p>No clear ownership</p></li><li><p>Treating it as &#8220;just documentation&#8221;</p></li></ul><p>And the biggest mistake:</p><blockquote><p>Using the tool without defining a process</p></blockquote><div><hr></div><h2>How I approach it (practical mindset)</h2><p>When I use Azure Test Plans, I focus on:</p><h3>1. Keep structure simple</h3><ul><li><p>Don&#8217;t over-engineer suites</p></li><li><p>Align with features or flows</p></li></ul><h3>2. Write test cases for clarity, not volume</h3><ul><li><p>Clear steps</p></li><li><p>Clear expected results</p></li><li><p>Easy to execute</p></li></ul><h3>3. Enforce traceability</h3><p>Every test must answer:<br>&#128073; &#8220;What requirement does this validate?&#8221;</p><h3>4. Make results meaningful</h3><p>Execution is not just clicking &#8220;Pass&#8221;</p><p>It&#8217;s:</p><ul><li><p>validating behavior</p></li><li><p>identifying risks</p></li><li><p>supporting release decisions</p></li></ul><div><hr></div><h2>The real value (what most people miss)</h2><p>Azure Test Plans is not about test cases.</p><p>It&#8217;s about <strong>confidence</strong>.</p><p>Confidence that:</p><ul><li><p>what needed to be tested &#8594; was tested</p></li><li><p>what failed &#8594; is visible</p></li><li><p>what is risky &#8594; is known</p></li></ul><p>And when you reach release day&#8230;</p><p>You&#8217;re not guessing.</p><p>You&#8217;re making a <strong>data-driven decision</strong>.</p><div><hr></div><h2>Final thought</h2><p>Tools don&#8217;t improve quality.</p><p><strong>Clarity does. Structure does. Discipline does.</strong></p><p>Azure Test Plans simply provide the environment to apply them at scale.</p><p>If used right, it doesn&#8217;t just organize testing.</p><p>It elevates how your team thinks about quality.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://denisdeoqa.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://denisdeoqa.substack.com/p/azure-devops-test-plans-the-tool?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://denisdeoqa.substack.com/p/azure-devops-test-plans-the-tool?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[🚀 Finding the Best Playwright Locators in Seconds with Codegen]]></title><description><![CDATA[Use Playwright Codegen and the Inspector to generate stable locators automatically and speed up your automation workflow.]]></description><link>https://denisdeoqa.substack.com/p/finding-the-best-playwright-locators</link><guid isPermaLink="false">https://denisdeoqa.substack.com/p/finding-the-best-playwright-locators</guid><dc:creator><![CDATA[Denis De O]]></dc:creator><pubDate>Fri, 06 Mar 2026 23:17:21 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Ho-8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc013171f-7d26-48c4-b58d-ad686f6ff2e6_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ho-8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc013171f-7d26-48c4-b58d-ad686f6ff2e6_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ho-8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc013171f-7d26-48c4-b58d-ad686f6ff2e6_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!Ho-8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc013171f-7d26-48c4-b58d-ad686f6ff2e6_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!Ho-8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc013171f-7d26-48c4-b58d-ad686f6ff2e6_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!Ho-8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc013171f-7d26-48c4-b58d-ad686f6ff2e6_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ho-8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc013171f-7d26-48c4-b58d-ad686f6ff2e6_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c013171f-7d26-48c4-b58d-ad686f6ff2e6_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2945924,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://denisdeoqa.substack.com/i/190155460?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc013171f-7d26-48c4-b58d-ad686f6ff2e6_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Ho-8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc013171f-7d26-48c4-b58d-ad686f6ff2e6_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!Ho-8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc013171f-7d26-48c4-b58d-ad686f6ff2e6_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!Ho-8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc013171f-7d26-48c4-b58d-ad686f6ff2e6_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!Ho-8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc013171f-7d26-48c4-b58d-ad686f6ff2e6_1536x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>When I first started learning Playwright, I spent far too much time trying to find the &#8220;perfect&#8221; locator. I would inspect elements, experiment with CSS selectors, and constantly fix tests that broke after small UI changes. Then I discovered <strong>Playwright Codegen</strong>. Suddenly, finding stable locators became almost effortless. In this article, I&#8217;ll show you how to use Codegen and the Playwright Inspector to generate reliable locators in seconds.</p><p>&#128073; <strong>Playwright Codegen</strong></p><p>Codegen can automatically generate <strong>recommended locators</strong> while you interact with your application.</p><p>In this article, you&#8217;ll learn how to use <strong>Playwright Codegen + Inspector</strong> to discover the <strong>best locator in seconds</strong>.</p><h3>What is Playwright Codegen?</h3><p>Codegen is a Playwright tool that:</p><ul><li><p>Opens a browser</p></li><li><p>Records your interactions</p></li><li><p>Generates Playwright test code automatically</p></li><li><p>Suggests <strong>the best locator strategy</strong></p></li></ul><p>Instead of manually searching the DOM, Playwright analyzes the page and recommends locators like:</p><ul><li><p><code>getByRole()</code></p></li><li><p><code>getByLabel()</code></p></li><li><p><code>getByText()</code></p></li><li><p><code>getByPlaceholder()</code></p></li></ul><p>These are <strong>user-facing locators</strong>, which are more stable than raw CSS selectors.</p><div><hr></div><h3>Step 1 &#8212; Run Playwright Codegen</h3><p>Run this command in your terminal:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:&quot;0823a0f2-90e5-44dc-94a4-b3af6aa3d01b&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">npx playwright codegen http://localhost:4200</code></pre></div><p>Playwright will:</p><ol><li><p>Open a browser</p></li><li><p>Launch the <strong>Playwright Inspector</strong></p></li><li><p>Start generating code as you interact with the page</p></li></ol><p>You&#8217;ll see something like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1jLa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2bb2f93e-6350-45b7-952b-24efdb7a70d3_1277x675.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1jLa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2bb2f93e-6350-45b7-952b-24efdb7a70d3_1277x675.png 424w, https://substackcdn.com/image/fetch/$s_!1jLa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2bb2f93e-6350-45b7-952b-24efdb7a70d3_1277x675.png 848w, https://substackcdn.com/image/fetch/$s_!1jLa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2bb2f93e-6350-45b7-952b-24efdb7a70d3_1277x675.png 1272w, https://substackcdn.com/image/fetch/$s_!1jLa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2bb2f93e-6350-45b7-952b-24efdb7a70d3_1277x675.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1jLa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2bb2f93e-6350-45b7-952b-24efdb7a70d3_1277x675.png" width="1277" height="675" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2bb2f93e-6350-45b7-952b-24efdb7a70d3_1277x675.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:675,&quot;width&quot;:1277,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:76947,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://denisdeoqa.substack.com/i/190155460?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2bb2f93e-6350-45b7-952b-24efdb7a70d3_1277x675.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!1jLa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2bb2f93e-6350-45b7-952b-24efdb7a70d3_1277x675.png 424w, https://substackcdn.com/image/fetch/$s_!1jLa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2bb2f93e-6350-45b7-952b-24efdb7a70d3_1277x675.png 848w, https://substackcdn.com/image/fetch/$s_!1jLa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2bb2f93e-6350-45b7-952b-24efdb7a70d3_1277x675.png 1272w, https://substackcdn.com/image/fetch/$s_!1jLa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2bb2f93e-6350-45b7-952b-24efdb7a70d3_1277x675.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:&quot;130c0855-2300-4313-bada-09c1ef4c5b7f&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">await page.getByRole('textbox', { name: 'Email' }).click();
await page.getByRole('textbox', { name: 'Email' }).fill('denis@email.com');
await page.getByRole('button', { name: 'Login' }).click();</code></pre></div><p>Notice something important here:</p><p>Playwright prefers:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;85780cd7-a88a-4d8f-9420-753ef799faff&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">getByRole
getByLabel
getByText</code></pre></div><p>These locators are based on <strong>how users see the interface</strong>, not on fragile DOM structures.</p><div><hr></div><h3>Step 2 &#8212; Click Elements to Generate Code</h3><p>Once Codegen is running:</p><ol><li><p>Click inside the browser window</p></li><li><p>Interact with your application normally</p></li><li><p>Playwright will generate test code automatically</p></li></ol><p>Example interaction:</p><ul><li><p>Click email field</p></li><li><p>Type email</p></li><li><p>Click login button</p></li></ul><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;d500ed19-1297-4085-a143-e2f789579cd3&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">await page.getByRole('textbox', { name: 'Email' }).fill('denis@email.com');
await page.getByRole('button', { name: 'Login' }).click();</code></pre></div><p>This code can be copied directly into your test files.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XPjv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3f74a9b-5fb6-467a-88d2-89a708b7dec4_576x589.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XPjv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3f74a9b-5fb6-467a-88d2-89a708b7dec4_576x589.png 424w, https://substackcdn.com/image/fetch/$s_!XPjv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3f74a9b-5fb6-467a-88d2-89a708b7dec4_576x589.png 848w, https://substackcdn.com/image/fetch/$s_!XPjv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3f74a9b-5fb6-467a-88d2-89a708b7dec4_576x589.png 1272w, https://substackcdn.com/image/fetch/$s_!XPjv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3f74a9b-5fb6-467a-88d2-89a708b7dec4_576x589.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XPjv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3f74a9b-5fb6-467a-88d2-89a708b7dec4_576x589.png" width="576" height="589" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e3f74a9b-5fb6-467a-88d2-89a708b7dec4_576x589.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:589,&quot;width&quot;:576,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:47665,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://denisdeoqa.substack.com/i/190155460?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3f74a9b-5fb6-467a-88d2-89a708b7dec4_576x589.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!XPjv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3f74a9b-5fb6-467a-88d2-89a708b7dec4_576x589.png 424w, https://substackcdn.com/image/fetch/$s_!XPjv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3f74a9b-5fb6-467a-88d2-89a708b7dec4_576x589.png 848w, https://substackcdn.com/image/fetch/$s_!XPjv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3f74a9b-5fb6-467a-88d2-89a708b7dec4_576x589.png 1272w, https://substackcdn.com/image/fetch/$s_!XPjv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3f74a9b-5fb6-467a-88d2-89a708b7dec4_576x589.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://denisdeoqa.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><h3>Step 3 &#8212; Understand the Locator Strategy</h3><p>Playwright follows a <strong>locator hierarchy</strong> when generating selectors.</p><p>Best &#8594; Worst</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;457743ad-3b42-4f35-aa61-65a1eaa162b6&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">getByRole()
getByLabel()
getByPlaceholder()
getByText()
getByTestId()
CSS locator()
XPath</code></pre></div><p>This is why Codegen rarely generates something like:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;0b041e46-2b70-4458-89f4-acacd5136cd1&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">page.locator("div:nth-child(3) &gt; button")</code></pre></div><p>Those selectors are <strong>fragile and break easily</strong>.</p><h3>Step 4 &#8212; Refine Locators with the Inspector</h3><p>While Codegen is running, you also have access to the <strong>Playwright Inspector</strong>.</p><p>The Inspector allows you to:</p><ul><li><p>Pick elements visually</p></li><li><p>Highlight matched elements</p></li><li><p>See how many elements match a locator</p></li><li><p>Debug tests interactively</p></li></ul><p>For example, if a locator matches multiple elements, the Inspector will show something like:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;c4676d1a-201b-4c98-9c95-e35d364bdc11&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">3 elements matched</code></pre></div><p>This immediately tells you the locator is <strong>too broad</strong>.</p><h3>Example: Improving a Locator</h3><p>Bad locator:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:&quot;bd78be72-06b5-4d9f-9d70-08867d38b733&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">await page.locator("input").first().fill("test@email.com");</code></pre></div><p>Why this is problematic:</p><ul><li><p>It depends on <strong>DOM order</strong></p></li><li><p>If another input appears, the test breaks</p></li></ul><p>Better locator:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:&quot;056d670a-b426-42e1-bf94-12a77a119771&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">await page.getByLabel("Email").fill("test@email.com");</code></pre></div><p>Now the test is <strong>clearer and more stable</strong>.</p><div><hr></div><h3>Debugging Tip: Use the Playwright Inspector</h3><p>You can also pause your tests and inspect locators interactively.</p><p>Add this line to your test:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:&quot;3de55a2e-cce3-4a4d-aa7b-99eff7afe6e7&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">await page.pause();</code></pre></div><p>Then run:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:&quot;303e149b-2949-4b95-833a-a0173d2ca724&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">npx playwright test --headed</code></pre></div><p>The <strong>Playwright Inspector</strong> opens, letting you:</p><ul><li><p>select elements</p></li><li><p>test locators</p></li><li><p>refine selectors quickly</p></li></ul><h3>Why Codegen is So Powerful</h3><p>Codegen is extremely useful because it:</p><p>&#10004; saves time<br>&#10004; suggests stable locators<br>&#10004; teaches best practices automatically<br>&#10004; helps beginners learn Playwright faster</p><p>Many automation engineers use Codegen as a <strong>starting point for writing tests</strong>.</p><div><hr></div><h3>Final Thoughts</h3><p>Writing stable locators is one of the most important skills in automation testing.</p><p>Instead of manually guessing selectors, use <strong>Playwright Codegen</strong> to generate reliable locators in seconds.</p><p>The workflow becomes simple:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;ebe7e9f8-279d-41a4-a653-ddd887c68abc&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">Run Codegen
&#8595;
Interact with your app
&#8595;
Copy generated locators
&#8595;
Refine if necessary</code></pre></div><p>With this approach, you&#8217;ll spend <strong>less time debugging locators</strong> and more time building meaningful tests.</p><p>Writing good automation tests isn&#8217;t just about tools&#8212;it&#8217;s about choosing the right techniques. Locator strategy is one of the biggest reasons tests become fragile over time. By using Playwright Codegen and the Inspector, you can immediately discover stable locators and build more reliable tests from the start.</p><p>If you&#8217;re learning Playwright or working in QA automation, I&#8217;ll continue sharing practical tips like this&#8212;things that save time and improve test stability.</p><p>Subscribe if you&#8217;d like more guides on <strong>Playwright, automation testing, and modern QA workflows.</strong></p><p>Happy testing &#128640;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://denisdeoqa.substack.com/p/finding-the-best-playwright-locators?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://denisdeoqa.substack.com/p/finding-the-best-playwright-locators?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://denisdeoqa.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Mastering Playwright Locators: The Syntax Rules Every QA Should Know]]></title><description><![CDATA[How understanding locator syntax can make your automated tests more reliable and easier to maintain.]]></description><link>https://denisdeoqa.substack.com/p/mastering-playwright-locators-the</link><guid isPermaLink="false">https://denisdeoqa.substack.com/p/mastering-playwright-locators-the</guid><dc:creator><![CDATA[Denis De O]]></dc:creator><pubDate>Thu, 05 Mar 2026 22:23:49 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!I3Y_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3969004-b36c-4c15-b9b4-721bf7a2b409_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!I3Y_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3969004-b36c-4c15-b9b4-721bf7a2b409_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!I3Y_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3969004-b36c-4c15-b9b4-721bf7a2b409_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!I3Y_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3969004-b36c-4c15-b9b4-721bf7a2b409_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!I3Y_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3969004-b36c-4c15-b9b4-721bf7a2b409_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!I3Y_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3969004-b36c-4c15-b9b4-721bf7a2b409_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!I3Y_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3969004-b36c-4c15-b9b4-721bf7a2b409_1536x1024.png" width="728" height="485.5" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c3969004-b36c-4c15-b9b4-721bf7a2b409_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:1678451,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://denisdeoqa.substack.com/i/190045402?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3969004-b36c-4c15-b9b4-721bf7a2b409_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!I3Y_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3969004-b36c-4c15-b9b4-721bf7a2b409_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!I3Y_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3969004-b36c-4c15-b9b4-721bf7a2b409_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!I3Y_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3969004-b36c-4c15-b9b4-721bf7a2b409_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!I3Y_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3969004-b36c-4c15-b9b4-721bf7a2b409_1536x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>When learning Playwright, one of the first things you realize is that <strong>finding elements correctly is everything</strong>.</p><p>If your locator is weak or ambiguous, your tests will fail.<br>If your locator is precise and well-designed, your automation becomes <strong>stable, readable, and maintainable</strong>.</p><p>In this article, I want to walk through the <strong>basic locator syntax rules in Playwright</strong> &#8212; the foundation every QA engineer should understand before writing complex automation.</p><p>Let&#8217;s look at a simple test example.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:&quot;82663efa-ce2a-4b5a-ab3f-75035ad7341d&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">test('locator syntax rules', async({page}) =&gt;{

    // by Tag name
    page.locator('input')

    // by ID (# indicates the locator is an ID)
    page.locator('#inputEmail1')

    // by class value ( "." indicates class )
    page.locator('.shape-rectangle')

    // by attribute ([] indicates attribute)
    page.locator('[placeholder="Email"]')

    // by entire class value (full class selector)
    page.locator('[class="input-full-width size-medium status-basic shape-rectangle nb-transition"]')

    // combining selectors (tag + attribute)
    page.locator('input[placeholder="Email"]')

})</code></pre></div><p>Now let&#8217;s break down <strong>what each of these selectors means</strong>.</p><h3>1. Locating Elements by Tag Name</h3><p>The simplest selector is the <strong>HTML tag itself</strong>.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:&quot;f00a5770-dc10-4797-a267-48fedec4330f&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">page.locator('input')</code></pre></div><p>This finds <strong>all </strong><code>&lt;input&gt;</code><strong> elements on the page</strong>.</p><p>However, this approach is usually <strong>too broad</strong>. Most pages have many input fields, so relying only on the tag name can make your locator unstable.</p><p>It&#8217;s useful for quick exploration, but rarely ideal for production tests.</p><div><hr></div><h3>2. Locating by ID</h3><p>IDs are often the <strong>most reliable selectors</strong>.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;69a6d61f-e648-411f-bc37-64f00706195d&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">page.locator('#inputEmail1')</code></pre></div><p>The <code>#</code> symbol tells Playwright that you're targeting an <strong>element ID</strong>.</p><p>Example HTML:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;html&quot;,&quot;nodeId&quot;:&quot;db6d1412-8321-4807-9052-340965791f1a&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-html">&lt;input id="inputEmail1"&gt;</code></pre></div><p>If the ID is unique (as it should be), this locator becomes <strong>very precise</strong>.</p><div><hr></div><h3>3. Locating by Class</h3><p>You can target elements using their <strong>CSS class</strong>.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:&quot;4296b884-c395-4021-95b6-54d07dfd43ba&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">page.locator('.shape-rectangle')</code></pre></div><p>The <code>.</code> symbol represents a <strong>class selector</strong>.</p><p>Example HTML:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;html&quot;,&quot;nodeId&quot;:&quot;654eb254-224f-4ebd-8a4a-dcbd126e9243&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-html">&lt;input class="shape-rectangle"&gt;</code></pre></div><p>This works well, but remember: <strong>many elements can share the same class</strong>, so sometimes this selector is not unique enough.</p><div><hr></div><h3>4. Locating by Attribute</h3><p>Another powerful technique is using <strong>HTML attributes</strong>.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:&quot;7e4775bf-f35b-44b6-9789-f02a02df6215&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">page.locator('[placeholder="Email"]')</code></pre></div><p>Example HTML:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;html&quot;,&quot;nodeId&quot;:&quot;e6ed63cf-4927-4a5b-bd00-f87d5888ae8c&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-html">&lt;input placeholder="Email"&gt;</code></pre></div><p>The square brackets <code>[ ]</code> indicate that we are selecting by <strong>attribute value</strong>.</p><p>This method is extremely useful because attributes like:</p><ul><li><p><code>placeholder</code></p></li><li><p><code>type</code></p></li><li><p><code>data-testid</code></p></li><li><p><code>aria-label</code></p></li></ul><p>are often <strong>very stable</strong>.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://denisdeoqa.substack.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share Denis De O&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://denisdeoqa.substack.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share Denis De O</span></a></p><div><hr></div><h3>5. Using the Full Class Attribute</h3><p>Sometimes you may see selectors like this:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:&quot;198b7bdc-b3b8-4d8c-95e3-14920697e95e&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">page.locator('[class="input-full-width size-medium status-basic shape-rectangle nb-transition"]')</code></pre></div><p>This targets the <strong>entire class attribute value</strong>.</p><p>While it works, it&#8217;s usually <strong>not recommended</strong>, because UI frameworks frequently change class combinations. Even a small change can break your locator.</p><p>A better approach is selecting <strong>only a relevant class</strong>.</p><div><hr></div><h3>6. Combining Selectors (The Powerful Technique)</h3><p>One of the best practices in Playwright is <strong>combining selectors</strong>.</p><p>Example:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:&quot;6c16b6c8-33ba-4392-81db-aeb10407758a&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">page.locator('input[placeholder="Email"]')</code></pre></div><p>This means:</p><ul><li><p>find an <strong>input tag</strong></p></li><li><p>that also has <strong>placeholder=&#8221;Email&#8221;</strong></p></li></ul><p>Combining selectors helps create <strong>unique and stable locators</strong>.</p><p>This is extremely powerful because it reduces the chance of selecting the wrong element.</p><div><hr></div><h3>7. What About XPath Locators?</h3><p>If you come from Selenium or older automation projects, you might be used to XPath, like:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:&quot;53c771da-19d7-4d69-a072-903abcbeadc7&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">page.locator('//input[@placeholder="Email"]')</code></pre></div><p>XPath can work &#8212; but <strong>Playwright&#8217;s documentation recommends avoiding XPath when you can</strong>, because it often leads to:</p><ul><li><p><strong>Brittle tests</strong> (UI structure changes &#8594; XPath breaks)</p></li><li><p><strong>Hard-to-read selectors</strong> (especially long XPaths)</p></li><li><p><strong>More maintenance</strong> over time</p></li></ul><h3>A better approach than XPath</h3><p>Instead of relying on the DOM tree structure, prefer <strong>CSS selectors and meaningful attributes</strong>, or even better, <strong>user-facing locators</strong> like role-based selectors:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:&quot;01345c89-572c-404f-85d4-420a09042dd3&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">// CSS: simple and stable
page.locator('input[placeholder="Email"]')

// Better (when possible): role-based, closer to how a user interacts
page.getByRole('textbox', { name: 'Email' })</code></pre></div><h3>When XPath is &#8220;acceptable.&#8221;</h3><p>Sometimes XPath is the only option &#8212; especially in legacy apps with no stable attributes. If you must use it, keep it:</p><ul><li><p>short</p></li><li><p>specific</p></li><li><p>and avoid absolute paths like <code>/html/body/div/...</code></p></li></ul><p>But in modern Playwright-style automation, XPath should be the <strong>last resort</strong>, not the default.</p><div><hr></div><h3>A Practical Tip for QA Engineers</h3><p>In real projects, I try to follow a simple rule:</p><p><strong>Start with the most meaningful selector possible.</strong></p><p>Good options include:</p><ul><li><p><code>getByRole()</code> (best for accessibility)</p></li><li><p><code>data-testid</code></p></li><li><p>unique IDs</p></li><li><p>attribute combinations</p></li></ul><p>Weak selectors like <strong>tag name alone</strong> should usually be avoided.</p><div><hr></div><h3>8. Locating Elements by Exact Text</h3><p>Sometimes the easiest way to locate an element is simply by the <strong>visible text the user sees on the page</strong>.</p><p>Example:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:&quot;622ff721-0760-4c22-b3ca-7e6f9db203da&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">page.locator(':text-is("Using the Grid")')</code></pre></div><p>This finds an element whose <strong>visible text is exactly "</strong>Using the Grid<strong>"</strong>.</p><p>Example HTML:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;html&quot;,&quot;nodeId&quot;:&quot;43ec30f0-3a43-4a40-95d7-d067b84690d9&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-html">&lt;button&gt;"Using the Grid"&lt;/button&gt;</code></pre></div><p>This approach is powerful because it matches <strong>what the user actually sees</strong>, rather than relying on technical attributes that may change.</p><p>In modern Playwright testing, <strong>text-based selectors are often preferred</strong> because they reflect real user interactions.</p><div><hr></div><h3>9. Locating Elements by Partial Text</h3><p>You can also locate elements using <strong>partial text matches</strong>.</p><p>Example:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;69577b4a-d55f-4e41-93d7-00b6fdbd0a01&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">page.locator(':text("Using")')</code></pre></div><p>This would match elements such as:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;7a134a40-cb50-4063-97bb-042e19ce5e57&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">Using the Grid
Using tag
Using settings</code></pre></div><p>Partial text matching is helpful when:</p><ul><li><p>The full text may change slightly</p></li><li><p>The UI contains dynamic content</p></li><li><p>You only need part of the label</p></li></ul><p>However, be careful: <strong>partial matches can sometimes return multiple elements</strong>, so make sure the locator is still unique.</p><div><hr></div><h3>Why Locator Quality Matters</h3><p>Good locators lead to:</p><p>&#10004; More stable tests<br>&#10004; Easier debugging<br>&#10004; Cleaner automation code<br>&#10004; Less maintenance when the UI changes</p><p>Poor locators lead to the opposite: flaky tests that waste hours of investigation.</p><div><hr></div><h3>Final Thought</h3><p>Learning automation is not only about writing scripts.</p><p>It&#8217;s about <strong>learning how the browser sees the page</strong>.</p><p>Once you understand locator strategies, your Playwright tests become <strong>simpler, stronger, and much easier to maintain</strong>.</p><p>And in QA automation, that makes all the difference.</p><p>If you&#8217;re learning Playwright like I am, remember:</p><p>Small details like <strong>locator strategy</strong> often separate fragile test scripts from <strong>professional-level automation</strong>.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://denisdeoqa.substack.com/p/mastering-playwright-locators-the?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://denisdeoqa.substack.com/p/mastering-playwright-locators-the?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://denisdeoqa.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Why getByRole() Is Better Than getByText() in Playwright]]></title><description><![CDATA[how this one change can make your tests more stable, readable, and professional]]></description><link>https://denisdeoqa.substack.com/p/why-getbyrole-is-better-than-getbytext</link><guid isPermaLink="false">https://denisdeoqa.substack.com/p/why-getbyrole-is-better-than-getbytext</guid><dc:creator><![CDATA[Denis De O]]></dc:creator><pubDate>Sat, 21 Feb 2026 15:55:05 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Pd-l!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faed0847f-18da-4a8a-a85f-959f09a3c0ba_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Pd-l!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faed0847f-18da-4a8a-a85f-959f09a3c0ba_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Pd-l!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faed0847f-18da-4a8a-a85f-959f09a3c0ba_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!Pd-l!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faed0847f-18da-4a8a-a85f-959f09a3c0ba_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!Pd-l!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faed0847f-18da-4a8a-a85f-959f09a3c0ba_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!Pd-l!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faed0847f-18da-4a8a-a85f-959f09a3c0ba_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Pd-l!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faed0847f-18da-4a8a-a85f-959f09a3c0ba_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/aed0847f-18da-4a8a-a85f-959f09a3c0ba_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1752357,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://denisdeoqa.substack.com/i/188719547?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faed0847f-18da-4a8a-a85f-959f09a3c0ba_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Pd-l!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faed0847f-18da-4a8a-a85f-959f09a3c0ba_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!Pd-l!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faed0847f-18da-4a8a-a85f-959f09a3c0ba_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!Pd-l!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faed0847f-18da-4a8a-a85f-959f09a3c0ba_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!Pd-l!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faed0847f-18da-4a8a-a85f-959f09a3c0ba_1536x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>When you start writing Playwright tests, one of the first things you learn is:</p><pre><code>await page.getByText(&#8217;Login&#8217;).click();</code></pre><p>It feels simple.<br><br>It works.</p><p>And in the beginning&#8230; it&#8217;s enough.</p><p>But then something happens.</p><div><hr></div><h2>The moment things start breaking</h2><p>You run your tests again.</p><p>And suddenly, you see this:</p><pre><code>strict mode violation: getByText(&#8217;Login&#8217;) resolved to 2 elements</code></pre><p>Or worse&#8230;</p><p>Your test clicks the wrong thing.<br><br>Or fails randomly.<br><br>Or passes locally but fails in CI.</p><p>Nothing changed.<br><br>But everything broke.</p><div><hr></div><h2>The real problem isn&#8217;t Playwright</h2><p>It&#8217;s how we are selecting elements.</p><p><code>getByText()</code> feels natural because it mimics how we read pages:</p><blockquote><p>&#8220;Find something that says Login and click it.&#8221;</p></blockquote><p>But the browser doesn&#8217;t think like a human.<br><br>It sees <strong>structure, roles, and accessibility</strong>, not just visible text.</p><p>And that&#8217;s where <code>getByRole()</code> changes everything.</p><div><hr></div><h2>What <code>getByRole()</code> really does</h2><p>Instead of searching for <em>any element with text</em>, <code>getByRole()</code> searches for elements based on <strong>what they are meant to do</strong>.</p><p>Example:</p><pre><code>await page.getByRole(&#8217;button&#8217;, { name: &#8216;Login&#8217; }).click();</code></pre><p>You&#8217;re no longer saying:</p><blockquote><p>&#8220;Find text &#8216;Login&#8217; somewhere.&#8221;</p></blockquote><p>You&#8217;re saying:</p><blockquote><p>&#8220;Find the button that the user sees as &#8216;Login&#8217;.&#8221;</p></blockquote><p>That&#8217;s a completely different level of precision.</p><div><hr></div><h2>Why this matters more than you think</h2><p>Modern web apps are full of repeated text:</p><ul><li><p>&#8220;Save&#8221;</p></li><li><p>&#8220;Submit&#8221;</p></li><li><p>&#8220;Edit&#8221;</p></li><li><p>&#8220;Charts&#8221;</p></li></ul><p>And <code>getByText()</code> doesn&#8217;t know which one you mean.</p><p>It might match:</p><ul><li><p>hidden elements</p></li><li><p>labels</p></li><li><p>tooltips</p></li><li><p>partial matches (like &#8220;Echarts&#8221; vs &#8220;Charts&#8221;)</p></li></ul><p>That&#8217;s how flaky tests are born.</p><div><hr></div><h2>A real example</h2><p>You write:</p><pre><code>await page.getByText(&#8217;Charts&#8217;).click();</code></pre><p>But your app also has:</p><ul><li><p>&#8220;Charts&#8221;</p></li><li><p>&#8220;Echarts&#8221;</p></li></ul><p>Now Playwright finds <strong>two elements</strong>.</p><p>And you get:</p><pre><code>strict mode violation</code></pre><div><hr></div><h2>The fix</h2><pre><code>await page.getByRole(&#8217;link&#8217;, { name: &#8216;Charts&#8217;, exact: true }).click();</code></pre><p>Now you&#8217;re saying:</p><ul><li><p>it must be a <strong>link</strong></p></li><li><p>it must be named exactly <strong>&#8220;Charts&#8221;</strong></p></li></ul><p>No ambiguity.<br><br>No guessing.<br><br>No flakiness.</p><div><hr></div><h2>The hidden superpower: accessibility</h2><p><code>getByRole()</code> doesn&#8217;t just make tests better.</p><p>It aligns your tests with <strong>how real users interact with your app</strong>, including:</p><ul><li><p>screen readers</p></li><li><p>keyboard navigation</p></li><li><p>accessibility tools</p></li></ul><p>So when you use:</p><pre><code>getByRole(&#8217;button&#8217;, { name: &#8216;Submit&#8217; })</code></pre><p>You&#8217;re testing the <strong>user experience</strong>, not just the DOM.</p><p>And that&#8217;s a big shift.</p><div><hr></div><h2>Cleaner tests, clearer intent</h2><p>Compare these two:</p><pre><code>await page.locator(&#8217;.btn.primary&#8217;).nth(2).click();</code></pre><p>vs</p><pre><code>await page.getByRole(&#8217;button&#8217;, { name: &#8216;Submit&#8217; }).click();</code></pre><p>The first one says:</p><blockquote><p>&#8220;Click the third button with this CSS class.&#8221;</p></blockquote><p>The second one says:</p><blockquote><p>&#8220;Click the Submit button.&#8221;</p></blockquote><p>One is implementation.<br><br>The other is intent.</p><p>And tests should always reflect intent.</p><div><hr></div><h2>The senior QA mindset</h2><p>At some point, you stop asking:</p><blockquote><p>&#8220;How do I click this element?&#8221;</p></blockquote><p>And start asking:</p><blockquote><p>&#8220;How would a user find this?&#8221;</p></blockquote><p>That&#8217;s when your tests become:</p><ul><li><p>more stable</p></li><li><p>easier to read</p></li><li><p>easier to maintain</p></li><li><p>easier to trust</p></li></ul><div><hr></div><h2>When should you use <code>getByText()</code>?</h2><p>It&#8217;s not useless.</p><p>You can still use it for:</p><ul><li><p>simple static content</p></li><li><p>unique text (like headings)</p></li><li><p>quick experiments</p></li></ul><p>But for <strong>interactive elements</strong>, prefer:</p><ul><li><p><code>getByRole()</code></p></li><li><p><code>getByTestId()</code></p></li></ul><div><hr></div><h2>A simple rule to remember</h2><p>If the element is clickable, typeable, or interactive&#8230;</p><p>&#128073; Use <code>getByRole()</code></p><p>If the element is just content&#8230;</p><p>&#128073; <code>getByText()</code> is fine</p><div><hr></div><h2>One small change, big impact</h2><p>You don&#8217;t need a new framework.<br><br>You don&#8217;t need more tools.</p><p>Just change this:</p><pre><code>getByText()</code></pre><p>To this:</p><pre><code>getByRole()</code></pre><p>And over time, your tests will feel different.</p><p>More stable.<br><br>More intentional.<br><br>More professional.</p><div><hr></div><h2>A small exercise</h2><p>Open one of your existing tests.</p><p>Find a line like this:</p><pre><code>await page.getByText(&#8217;Login&#8217;).click();</code></pre><p>Replace it with:</p><pre><code>await page.getByRole(&#8217;button&#8217;, { name: &#8216;Login&#8217; }).click();</code></pre><p>Run your tests again.</p><p>Notice how it feels.</p><div><hr></div><h2>Final thought</h2><p>Good automation isn&#8217;t about making tests pass.</p><p>It&#8217;s about building tests you can trust.</p><p>And trust comes from clarity.</p><p>Not just for the machine&#8230;</p><p>&#8230;but for the human reading the code.</p><p></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://denisdeoqa.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://denisdeoqa.substack.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://denisdeoqa.substack.com/p/why-getbyrole-is-better-than-getbytext?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://denisdeoqa.substack.com/p/why-getbyrole-is-better-than-getbytext?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Being a TestRail Admin Is Not a Configuration Job]]></title><description><![CDATA[Why ownership, not setup, determines whether TestRail actually works]]></description><link>https://denisdeoqa.substack.com/p/being-a-testrail-admin-is-not-a-configuration</link><guid isPermaLink="false">https://denisdeoqa.substack.com/p/being-a-testrail-admin-is-not-a-configuration</guid><dc:creator><![CDATA[Denis De O]]></dc:creator><pubDate>Sun, 25 Jan 2026 18:12:36 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!syb9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25bd59ef-c3a6-423f-aece-f93fba8aea24_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!syb9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25bd59ef-c3a6-423f-aece-f93fba8aea24_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!syb9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25bd59ef-c3a6-423f-aece-f93fba8aea24_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!syb9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25bd59ef-c3a6-423f-aece-f93fba8aea24_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!syb9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25bd59ef-c3a6-423f-aece-f93fba8aea24_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!syb9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25bd59ef-c3a6-423f-aece-f93fba8aea24_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!syb9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25bd59ef-c3a6-423f-aece-f93fba8aea24_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/25bd59ef-c3a6-423f-aece-f93fba8aea24_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2300271,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://denisdeoqa.substack.com/i/185749903?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25bd59ef-c3a6-423f-aece-f93fba8aea24_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!syb9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25bd59ef-c3a6-423f-aece-f93fba8aea24_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!syb9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25bd59ef-c3a6-423f-aece-f93fba8aea24_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!syb9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25bd59ef-c3a6-423f-aece-f93fba8aea24_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!syb9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25bd59ef-c3a6-423f-aece-f93fba8aea24_1536x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>When someone becomes a TestRail admin, the expectation is usually simple:</p><p>&#8220;Set it up.&#8221;<br>&#8220;Create the projects.&#8221;<br>&#8220;Configure the fields.&#8221;<br>&#8220;Give people access.&#8221;</p><p>Once that&#8217;s done, everyone assumes the job is finished.</p><p>That assumption is where most TestRail setups start to quietly fail.</p><p>Because being a TestRail admin isn&#8217;t really about configuration.<br>It&#8217;s about <strong>ownership</strong>.</p><div><hr></div><h2>Setup Is a Moment. Ownership Is Ongoing.</h2><p>Configuration happens at a specific point in time.<br>Ownership happens every week.</p><p>If your role as a TestRail admin stops after setup, a few things slowly begin to happen:</p><ul><li><p>Test cases start to look different from each other</p></li><li><p>Naming becomes inconsistent</p></li><li><p>Reports feel less and less useful</p></li><li><p>Automation results don&#8217;t quite match reality</p></li></ul><p>None of this breaks overnight. That&#8217;s what makes it dangerous.</p><div><hr></div><h2>What You&#8217;re Actually Responsible For</h2><p>Most TestRail admins don&#8217;t realize how much influence they have.</p><p>Whether you intend it or not, you&#8217;re shaping:</p><ul><li><p>How testers think about coverage</p></li><li><p>What &#8220;good enough&#8221; looks like</p></li><li><p>What people trust when a release is coming</p></li><li><p>How confident (or confused) new team members feel</p></li></ul><p>These aren&#8217;t technical decisions.<br>They&#8217;re <strong>system decisions</strong>.</p><p>And if no one actively makes them, the system still evolves &#8212; just in random ways.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://denisdeoqa.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://denisdeoqa.substack.com/subscribe?"><span>Subscribe now</span></a></p><p></p><div><hr></div><h2>Why Configuration-Only Setups Don&#8217;t Last</h2><p>I&#8217;ve seen this pattern many times.</p><p>A TestRail instance starts clean.<br>Everyone agrees on structure.<br>The first few months look great.</p><p>Then:</p><ul><li><p>Teams grow</p></li><li><p>Deadlines tighten</p></li><li><p>Shortcuts creep in</p></li></ul><p>Without someone paying attention, the system absorbs all of that pressure.<br>TestRail doesn&#8217;t complain. It just records it.</p><p>A year later, people say:</p><blockquote><p>&#8220;TestRail used to be useful.&#8221;</p></blockquote><p>What usually changed wasn&#8217;t the tool.<br>It was the lack of ongoing ownership.</p><div><hr></div><h2>Ownership Doesn&#8217;t Mean Being the Police</h2><p>This is an important point.</p><p>Owning TestRail doesn&#8217;t mean blocking people or enforcing rules for the sake of control.<br>It means keeping the system understandable and trustworthy.</p><p>Good TestRail admins:</p><ul><li><p>Set clear expectations early</p></li><li><p>Adjust structure when reality changes</p></li><li><p>Keep standards simple and visible</p></li><li><p>Step in before small inconsistencies become big problems</p></li></ul><p>The goal isn&#8217;t perfection.<br>The goal is <strong>clarity</strong>.</p><div><hr></div><h2>The Cost of Not Owning the System</h2><p>When no one truly owns TestRail, the cost shows up slowly:</p><ul><li><p>Time wasted arguing about coverage</p></li><li><p>Reports that management stops looking at</p></li><li><p>Automation metrics that confuse more than they help</p></li><li><p>New testers who don&#8217;t know what matters</p></li></ul><p>At that point, teams often blame the tool.</p><p>But TestRail is just reflecting what&#8217;s happening underneath.</p><div><hr></div><h2>A Better Way to Think About the Role</h2><p>If you&#8217;re a TestRail admin, a useful way to think about your role is this:</p><p>You&#8217;re not maintaining a tool.<br>You&#8217;re maintaining <strong>shared understanding</strong>.</p><p>That means regularly asking:</p><ul><li><p>Does this still reflect how we test today?</p></li><li><p>Are we capturing a signal or just accumulating data?</p></li><li><p>Would someone new understand this setup without explanation?</p></li></ul><p>If the answer drifts over time, configuration alone won&#8217;t fix it.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://denisdeoqa.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://denisdeoqa.substack.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://denisdeoqa.substack.com/p/being-a-testrail-admin-is-not-a-configuration?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://denisdeoqa.substack.com/p/being-a-testrail-admin-is-not-a-configuration?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://denisdeoqa.substack.com/p/being-a-testrail-admin-is-not-a-configuration/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://denisdeoqa.substack.com/p/being-a-testrail-admin-is-not-a-configuration/comments"><span>Leave a comment</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[TestRail Doesn’t Fix QA — But It Reveals Whether You Have One]]></title><description><![CDATA[Why TestRail exposes broken QA systems instead of magically improving them]]></description><link>https://denisdeoqa.substack.com/p/testrail-doesnt-fix-qa-but-it-reveals</link><guid isPermaLink="false">https://denisdeoqa.substack.com/p/testrail-doesnt-fix-qa-but-it-reveals</guid><dc:creator><![CDATA[Denis De O]]></dc:creator><pubDate>Sun, 25 Jan 2026 18:03:11 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!9PhV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F783c93d3-f25e-48f3-9c85-d50844291640_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9PhV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F783c93d3-f25e-48f3-9c85-d50844291640_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9PhV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F783c93d3-f25e-48f3-9c85-d50844291640_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!9PhV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F783c93d3-f25e-48f3-9c85-d50844291640_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!9PhV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F783c93d3-f25e-48f3-9c85-d50844291640_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!9PhV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F783c93d3-f25e-48f3-9c85-d50844291640_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9PhV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F783c93d3-f25e-48f3-9c85-d50844291640_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/783c93d3-f25e-48f3-9c85-d50844291640_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2303798,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://denisdeoqa.substack.com/i/185748552?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F783c93d3-f25e-48f3-9c85-d50844291640_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!9PhV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F783c93d3-f25e-48f3-9c85-d50844291640_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!9PhV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F783c93d3-f25e-48f3-9c85-d50844291640_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!9PhV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F783c93d3-f25e-48f3-9c85-d50844291640_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!9PhV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F783c93d3-f25e-48f3-9c85-d50844291640_1536x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>Most teams adopt TestRail hoping it will <em>solve</em> their QA problems.</p><p>It doesn&#8217;t.</p><p>What TestRail actually does is something far more uncomfortable:<br><strong>It exposes how your QA system really works &#8212; or doesn&#8217;t.</strong></p><p>Used well, TestRail becomes a powerful coordination and decision-making tool.<br>Used poorly, it turns into an expensive archive of outdated test cases that no one trusts.</p><p>The difference has very little to do with the tool itself.</p><div><hr></div><h2>What TestRail Is Actually Good At</h2><p>At its best, TestRail helps teams answer a few critical questions:</p><ul><li><p>What do we actually test &#8212; and why?</p></li><li><p>What changed, and what needs coverage now?</p></li><li><p>What risks are we accepting in this release?</p></li><li><p>Where does automation help, and where does it not?</p></li></ul><p>In other words, TestRail is not about storing test cases.<br>It&#8217;s about <strong>making testing visible, structured, and intentional</strong>.</p><p>When TestRail works, it&#8217;s usually because:</p><ul><li><p>Someone owns the system</p></li><li><p>There are clear standards</p></li><li><p>Decisions are explicit, not accidental</p></li></ul><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://denisdeoqa.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://denisdeoqa.substack.com/subscribe?"><span>Subscribe now</span></a></p><p></p><div><hr></div><h2>Where Most Teams Go Wrong</h2><p>Most TestRail implementations fail for predictable reasons:</p><ul><li><p>No one owns the structure long-term</p></li><li><p>Test cases grow without pruning</p></li><li><p>Permissions are too loose or too strict</p></li><li><p>Reports exist, but no one uses them to decide anything</p></li><li><p>Automation is bolted on without a clear purpose</p></li></ul><p>Over time, TestRail becomes a reflection of organizational entropy.<br>The tool didn&#8217;t cause the problem &#8212; it simply <strong>made it visible</strong>.</p><p>This is why teams often say things like:</p><blockquote><p>&#8220;TestRail doesn&#8217;t really help us anymore.&#8221;</p></blockquote><p>What they usually mean is:</p><blockquote><p>&#8220;We stopped making decisions about how QA should work.&#8221;</p></blockquote><div><hr></div><h2>TestRail as a QA System, Not a Tool</h2><p>The biggest shift teams need to make is mental, not technical.</p><p>TestRail is not:</p><ul><li><p>A checklist generator</p></li><li><p>A compliance box</p></li><li><p>A mirror of your automation framework</p></li></ul><p>TestRail <em>is</em>:</p><ul><li><p>A coordination layer</p></li><li><p>A shared language between QA, engineering, and management</p></li><li><p>A place where test intent and risk become explicit</p></li></ul><p>When treated as a system, TestRail helps teams:</p><ul><li><p>Scale without losing control</p></li><li><p>Onboard new testers faster</p></li><li><p>Understand coverage without false confidence</p></li></ul><p>When treated as a tool, it quietly decays.</p><div><hr></div><h2>Why TestRail Helps &#8212; When Used Correctly</h2><p>TestRail helps not because it has features, but because it <strong>forces structure</strong>.</p><p>It forces teams to decide:</p><ul><li><p>What a &#8220;good&#8221; test case looks like</p></li><li><p>How much detail is enough</p></li><li><p>What matters to report &#8212; and what doesn&#8217;t</p></li><li><p>How manual and automated testing relate</p></li></ul><p>These decisions are uncomfortable.<br>Avoiding them is easy.<br>TestRail simply refuses to hide the consequences.</p><div><hr></div><h2>What This Publication Will Focus On</h2><p>I won&#8217;t explain how to click buttons or recreate documentation.</p><p>Instead, I&#8217;ll write about:</p><ul><li><p>Owning TestRail as a QA system</p></li><li><p>Governance, structure, and long-term maintainability</p></li><li><p>How TestRail and automation should (and should not) interact</p></li><li><p>The patterns that make TestRail useful &#8212; and the ones that destroy it</p></li></ul><p>I&#8217;m documenting these lessons as part of a <strong>practical TestRail Admin Playbook</strong>, built from real production environments, not idealized setups.</p><p>If you&#8217;ve ever felt that TestRail <em>should</em> be helping more than it does, this is where we&#8217;ll unpack why &#8212; and what to do about it.</p><p>In the next post, I&#8217;ll explain why <strong>being a TestRail admin is not a configuration job</strong>, and why that misunderstanding causes most setups to fail.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://denisdeoqa.substack.com/p/testrail-doesnt-fix-qa-but-it-reveals/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://denisdeoqa.substack.com/p/testrail-doesnt-fix-qa-but-it-reveals/comments"><span>Leave a comment</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://denisdeoqa.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://denisdeoqa.substack.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://denisdeoqa.substack.com/p/testrail-doesnt-fix-qa-but-it-reveals?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://denisdeoqa.substack.com/p/testrail-doesnt-fix-qa-but-it-reveals?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p></p>]]></content:encoded></item></channel></rss>