<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>tweak Blog</title>
        <link>https://tweak-extension.com/blog</link>
        <description>tweak Blog</description>
        <lastBuildDate>Mon, 12 Oct 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[How to Intercept and Edit HTTP Requests Before They Are Sent (No Proxy Needed)]]></title>
            <link>https://tweak-extension.com/blog/edit-http-request-before-sending</link>
            <guid>https://tweak-extension.com/blog/edit-http-request-before-sending</guid>
            <pubDate>Mon, 12 Oct 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Pause a fetch or XHR request in the browser, edit its URL, body or headers, then let it go. A step by step guide to request breakpoints without Charles, Fiddler or Burp, and what each option costs.]]></description>
            <content:encoded><![CDATA[
<p><strong>You want the next request to go out a little differently. A bigger quantity, an expired token, someone else's id, a field the backend does not support yet. Not forever, just this once, to see what happens.</strong></p>
<p>That is a request breakpoint: stop the request in flight, edit it, let it go. Desktop proxies have done this for twenty years, but they ask you to reroute your traffic and trust a certificate first. This guide shows how to do it from inside the page with tweak's <strong>Edit before send</strong>, which use cases it covers, and how it compares, feature and price, with Charles, Fiddler, Proxyman, Burp Suite and the free tools.</p>
<div class="theme-admonition theme-admonition-note admonition_mDP4 alert alert--secondary"><div class="admonitionHeading_Mfam"><span class="admonitionIcon_ba76"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>A word on transparency</div><div class="admonitionContent_LzEm"><p>I'm the founder of tweak, so read this with that in mind. Several tools in this article are industry leaders that have proven themselves for years, and I would not mention them if they weren't good. This article is not about crowning a winner. It is about helping you pick the right tool for the job in front of you. The most expensive tool is not always the right answer: sometimes all you need is a small, focused tool that does one specific task well.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="tldr">TL;DR<a href="https://tweak-extension.com/blog/edit-http-request-before-sending#tldr" class="hash-link" aria-label="Direct link to TL;DR" title="Direct link to TL;DR" translate="no">​</a></h2>
<ul>
<li class=""><strong>Edit before send</strong> pauses a matching <code>fetch</code> or XHR request on the page. You change the URL, body or headers, then press <strong>Continue request</strong>. You can also pause the <strong>response</strong> and rewrite it before your app reads it.</li>
<li class=""><strong>No proxy, no certificate, no DevTools required.</strong> The editor opens over the page, in the tab you are working in.</li>
<li class=""><strong>Edits are one-off.</strong> They never change the rule, so the next request behaves as saved.</li>
<li class=""><strong>Price:</strong> $36 a year or $4 a month. That is <strong>93% less than Burp Suite Professional</strong>, <strong>75% less than Fiddler Everywhere Pro</strong>, and less than a Proxyman or Charles license in year one. <a class="" href="https://tweak-extension.com/pricing?feature=edit-before-send">Try it free for 7 days</a>.</li>
</ul>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="why-devtools-is-not-enough">Why DevTools is not enough<a href="https://tweak-extension.com/blog/edit-http-request-before-sending#why-devtools-is-not-enough" class="hash-link" aria-label="Direct link to Why DevTools is not enough" title="Direct link to Why DevTools is not enough" translate="no">​</a></h2>
<p>Most developers try the browser's own tools first, and hit the same wall:</p>
<table><thead><tr><th>What you try in DevTools</th><th>What it actually does</th></tr></thead><tbody><tr><td>XHR/fetch breakpoints (Sources)</td><td>Pauses <strong>your JavaScript</strong> at the <code>fetch</code> call. You can poke variables, not the request.</td></tr><tr><td>Local Overrides</td><td>Replaces a <strong>response</strong> with a file on disk. Every time, not once. Requests are untouched.</td></tr><tr><td>Copy as fetch / cURL, then edit</td><td><strong>Replays</strong> a request that already went out, outside your app's flow.</td></tr><tr><td>Edit and Resend (Firefox)</td><td>Same: a <strong>new</strong> request after the fact, the page never sees the answer.</td></tr></tbody></table>
<p>None of them hold the real request your app is sending, let you change it, and hand the edited version back to your app's flow. That gap is why people go looking for "Tamper Data for Chrome", a Charles Proxy alternative, or an intercept tool like Burp.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="how-to-set-up-edit-before-send-step-by-step">How to set up Edit before send, step by step<a href="https://tweak-extension.com/blog/edit-http-request-before-sending#how-to-set-up-edit-before-send-step-by-step" class="hash-link" aria-label="Direct link to How to set up Edit before send, step by step" title="Direct link to How to set up Edit before send, step by step" translate="no">​</a></h2>
<p>You need <a class="" href="https://tweak-extension.com/docs/intro">tweak installed</a> and a Premium plan (the <a class="" href="https://tweak-extension.com/pricing?feature=edit-before-send">7 day trial</a> works).</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="1-create-a-rule-that-matches-the-request">1. Create a rule that matches the request<a href="https://tweak-extension.com/blog/edit-http-request-before-sending#1-create-a-rule-that-matches-the-request" class="hash-link" aria-label="Direct link to 1. Create a rule that matches the request" title="Direct link to 1. Create a rule that matches the request" translate="no">​</a></h3>
<p>Open tweak on the tab running your app and add a rule:</p>
<ul>
<li class=""><strong>URL</strong>: part of the request URL, for example <code>/api/cart</code>. Partial matching is the default, or switch on the <a class="" href="https://tweak-extension.com/docs/intro">regular expression toggle</a> for something stricter. If <a class="" href="https://tweak-extension.com/docs/request-capture">request capture</a> is on, the URL field suggests the requests the tab already made.</li>
<li class=""><strong>Method</strong>: the HTTP method, for example <code>POST</code>.</li>
<li class=""><strong>Rule type</strong>: <strong>Modify</strong> to edit real traffic that goes to your server. <strong>Mock</strong> if you want tweak to answer instead of the server (useful when the backend is down or not built yet).</li>
</ul>
<p>Tip: if several requests share a URL (GraphQL, batch endpoints), narrow the rule with <a class="" href="https://tweak-extension.com/docs/rule/partial-request-payload-matching">partial request payload matching</a> so only the operation you care about pauses.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="2-choose-where-the-rule-should-stop">2. Choose where the rule should stop<a href="https://tweak-extension.com/blog/edit-http-request-before-sending#2-choose-where-the-rule-should-stop" class="hash-link" aria-label="Direct link to 2. Choose where the rule should stop" title="Direct link to 2. Choose where the rule should stop" translate="no">​</a></h3>
<p>In the rule's debugging group, next to the breakpoint, open the <strong>Edit before send</strong> menu:</p>
<table><thead><tr><th>Option</th><th>What pauses</th></tr></thead><tbody><tr><td><strong>Pause the request</strong></td><td>the request, before it leaves the page</td></tr><tr><td><strong>Pause the request and response</strong></td><td>the request first, then the response before the page reads it</td></tr><tr><td><strong>Pause the response</strong></td><td>the response only, before the page reads it</td></tr></tbody></table>
<p>A small <code>req</code>, <code>both</code> or <code>res</code> caption under the icon reminds you the rule is armed.</p>
<p><img decoding="async" loading="lazy" alt="the Edit before send menu on a modify rule, set to pause the request and response" src="https://tweak-extension.com/assets/images/edit-before-send-01-menu-0495f3183d4006b103e4d178e327b0eb.png" title="Pick where the rule stops: the request, the response, or both." width="1600" height="1136" class="img_F_NH"></p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="3-trigger-the-request-and-edit-it">3. Trigger the request and edit it<a href="https://tweak-extension.com/blog/edit-http-request-before-sending#3-trigger-the-request-and-edit-it" class="hash-link" aria-label="Direct link to 3. Trigger the request and edit it" title="Direct link to 3. Trigger the request and edit it" translate="no">​</a></h3>
<p>Use your app as normal. When it sends a matching request, tweak holds it and opens an editor <strong>on the page itself</strong>, showing only the side that is paused. On a modify rule you edit the live request: the URL, body and headers that are about to go out.</p>
<p><img decoding="async" loading="lazy" alt="a paused request, framed over the page, with its body edited before it is sent" src="https://tweak-extension.com/assets/images/edit-before-send-02-request-57515a5e0ad4525143065a04ebf1f5a2.png" title="Request paused: here the body is edited to ask for 99 items." width="2400" height="1366" class="img_F_NH"></p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="4-continue-or-send-it-untouched">4. Continue, or send it untouched<a href="https://tweak-extension.com/blog/edit-http-request-before-sending#4-continue-or-send-it-untouched" class="hash-link" aria-label="Direct link to 4. Continue, or send it untouched" title="Direct link to 4. Continue, or send it untouched" translate="no">​</a></h3>
<ul>
<li class=""><strong>Continue request</strong> (<kbd>Ctrl/⌘ + Enter</kbd>): the request goes out with your edits.</li>
<li class=""><strong>Send without edits</strong>: it goes out as the rule would have sent it.</li>
<li class=""><strong>Cancel request</strong>: it never goes out. Your app sees it aborted (<code>fetch</code> rejects with an <code>AbortError</code>), a quick way to test that path too.</li>
</ul>
<p>If several matching requests fire at once, they wait in line and the editor shows how many are queued.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="5-optional-rewrite-the-response-before-your-app-reads-it">5. Optional: rewrite the response before your app reads it<a href="https://tweak-extension.com/blog/edit-http-request-before-sending#5-optional-rewrite-the-response-before-your-app-reads-it" class="hash-link" aria-label="Direct link to 5. Optional: rewrite the response before your app reads it" title="Direct link to 5. Optional: rewrite the response before your app reads it" translate="no">​</a></h3>
<p>With <strong>Pause the response</strong> (or both), the server's answer waits for you. Change the body, then <strong>Deliver response</strong>, <strong>Deliver without edits</strong>, or <strong>Cancel request</strong>.</p>
<p><img decoding="async" loading="lazy" alt="a paused response, framed over the page, edited before the page reads it" src="https://tweak-extension.com/assets/images/edit-before-send-03-response-73379ece67c101adeec4c38648fce8f1.png" title="Response paused: edited into an out of stock error to see how the page copes." width="2400" height="1366" class="img_F_NH"></p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="6-make-it-permanent-or-switch-it-off">6. Make it permanent, or switch it off<a href="https://tweak-extension.com/blog/edit-http-request-before-sending#6-make-it-permanent-or-switch-it-off" class="hash-link" aria-label="Direct link to 6. Make it permanent, or switch it off" title="Direct link to 6. Make it permanent, or switch it off" translate="no">​</a></h3>
<p>Edits apply to that one request only. If you find yourself making the same edit every time, put it in the rule itself (the request payload tab, a <a class="" href="https://tweak-extension.com/docs/rule/request-hook">request hook</a> or a <a class="" href="https://tweak-extension.com/docs/rule/javascript-snippet">JavaScript snippet</a> for the response) and turn Edit before send off.</p>
<p>Full reference: <a class="" href="https://tweak-extension.com/docs/debug-request/pause-and-edit">Edit before send docs</a>.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="9-things-you-can-do-with-a-paused-request">9 things you can do with a paused request<a href="https://tweak-extension.com/blog/edit-http-request-before-sending#9-things-you-can-do-with-a-paused-request" class="hash-link" aria-label="Direct link to 9 things you can do with a paused request" title="Direct link to 9 things you can do with a paused request" translate="no">​</a></h2>
<ol>
<li class=""><strong>Test server side validation.</strong> Your form blocks a quantity of 99, a negative price or an expired coupon. The API should too. Pause the request, type the value the UI would never send, and see if the backend rejects it.</li>
<li class=""><strong>Check authorization on your own app.</strong> Swap the user, tenant or order id in the URL or body and confirm the server answers <code>403</code>, not someone else's data.</li>
<li class=""><strong>Expire a session on demand.</strong> Edit the <code>Authorization</code> header to a stale token and watch how your refresh and logout flow behaves, without waiting an hour.</li>
<li class=""><strong>Try an API change before the backend ships it.</strong> Add the new field to the body and see what the current server does with it.</li>
<li class=""><strong>Reproduce a bug report.</strong> A customer sent a payload that broke something. Paste it into the paused request and hit the exact path again.</li>
<li class=""><strong>Design error states with real traffic.</strong> Pause the response and turn a <code>200</code> into the out of stock, rate limited or validation error your designer asked about.</li>
<li class=""><strong>Freeze a loading state.</strong> While a request is paused, your app is waiting on it. Skeletons, spinners and disabled buttons stay on screen as long as you need to inspect or screenshot them.</li>
<li class=""><strong>Debug third party calls.</strong> See exactly what an analytics, payment or chat widget sends from your page, and change one field to see how it reacts.</li>
<li class=""><strong>Stage a demo.</strong> Edit a response so the dashboard shows the numbers you want to present, then deliver it. Nothing on the server changes.</li>
</ol>
<p>Use it on applications you own or are authorised to test.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="edit-before-send-vs-the-alternatives">Edit before send vs the alternatives<a href="https://tweak-extension.com/blog/edit-http-request-before-sending#edit-before-send-vs-the-alternatives" class="hash-link" aria-label="Direct link to Edit before send vs the alternatives" title="Direct link to Edit before send vs the alternatives" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="feature-comparison">Feature comparison<a href="https://tweak-extension.com/blog/edit-http-request-before-sending#feature-comparison" class="hash-link" aria-label="Direct link to Feature comparison" title="Direct link to Feature comparison" translate="no">​</a></h3>
<table><thead><tr><th></th><th>tweak</th><th>Charles</th><th>Fiddler Everywhere</th><th>Proxyman</th><th>Burp Suite Pro</th><th>HTTP Toolkit</th></tr></thead><tbody><tr><td>Pause and edit request</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr><tr><td>Pause and edit response</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr><tr><td>Runs as</td><td>browser extension</td><td>desktop proxy</td><td>desktop proxy</td><td>desktop proxy</td><td>desktop proxy</td><td>desktop proxy</td></tr><tr><td>Root certificate / proxy setup</td><td>none</td><td>required for HTTPS</td><td>required for HTTPS</td><td>required for HTTPS</td><td>required for HTTPS</td><td>automated, per client</td></tr><tr><td>Editor appears</td><td>over the page</td><td>in the app window</td><td>in the app window</td><td>in the app window</td><td>in the app window</td><td>in the app window</td></tr><tr><td>Mock and rewrite rules</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>match and replace</td><td>✅ (Pro)</td></tr><tr><td>Mobile apps, desktop apps, cURL</td><td>❌</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr></tbody></table>
<p>The pattern is clear: desktop proxies see <strong>everything</strong> on your machine, and pay for it with setup. tweak sees <strong>what your web app sends</strong>, and needs nothing but the extension. If your bug lives in a browser tab, the second is the shorter path.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="price-comparison">Price comparison<a href="https://tweak-extension.com/blog/edit-http-request-before-sending#price-comparison" class="hash-link" aria-label="Direct link to Price comparison" title="Direct link to Price comparison" translate="no">​</a></h3>
<p>List prices for the paid tier that includes breakpoints, as published in October 2026. Check each vendor's site before buying, prices move.</p>
<table><thead><tr><th>Tool</th><th>Price for 1 developer</th><th>Model</th><th>tweak saves (year one)</th></tr></thead><tbody><tr><td><strong><a class="" href="https://tweak-extension.com/pricing?feature=edit-before-send">tweak Premium</a></strong></td><td><strong>$36 / year</strong> or <strong>$4 / month</strong></td><td>subscription, cancel any time</td><td>n/a</td></tr><tr><td><a href="https://portswigger.net/burp/pro" target="_blank" rel="noopener noreferrer" class="">Burp Suite Professional</a></td><td>$499 / year</td><td>subscription, per user</td><td><strong>$463 (93%)</strong></td></tr><tr><td><a href="https://www.telerik.com/purchase/fiddler" target="_blank" rel="noopener noreferrer" class="">Fiddler Everywhere Pro</a></td><td>~$144 / year ($12 / month annual)</td><td>subscription, per user</td><td><strong>$108 (75%)</strong></td></tr><tr><td><a href="https://proxyman.com/pricing" target="_blank" rel="noopener noreferrer" class="">Proxyman Standard</a></td><td>$89</td><td>perpetual, 1 year of updates</td><td><strong>$53 (60%)</strong></td></tr><tr><td><a href="https://www.charlesproxy.com/buy/" target="_blank" rel="noopener noreferrer" class="">Charles Proxy</a></td><td>$50</td><td>perpetual license</td><td><strong>$14 (28%)</strong></td></tr></tbody></table>
<p>Two honest notes:</p>
<ul>
<li class=""><strong>Charles and Proxyman are one time purchases.</strong> Over several years without upgrades, Charles ends up cheaper than a tweak subscription. If you need system wide interception, that is a fair trade. If you only debug web apps, you are paying for a proxy you have to configure, and tweak's $4 month lets you pay for the one week you actually need it.</li>
<li class=""><strong>Free tools exist.</strong> <a href="https://httptoolkit.com/pricing/" target="_blank" rel="noopener noreferrer" class="">HTTP Toolkit</a>'s free tier includes request and response breakpoints, and Burp Suite Community, OWASP ZAP and mitmproxy intercept for free. They are proxies or separate apps, each with its own setup. <a href="https://github.com/google/tamperchrome" target="_blank" rel="noopener noreferrer" class="">Tamper Dev</a> is a free extension that pauses requests, though its store reviews report it misses requests made by JavaScript. tweak's case is not "the only way", it is "the fastest way, in the browser you already use, alongside your mocks".</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="what-about-requestly-and-modheader">What about Requestly and ModHeader?<a href="https://tweak-extension.com/blog/edit-http-request-before-sending#what-about-requestly-and-modheader" class="hash-link" aria-label="Direct link to What about Requestly and ModHeader?" title="Direct link to What about Requestly and ModHeader?" translate="no">​</a></h3>
<p>Both rewrite traffic automatically from rules: set a header, redirect a URL, replace a response. That covers the "every time" case. We did not find an interactive pause and edit in either at the time of writing. tweak does both: rules for every time, Edit before send for just this once. Coming from ModHeader? See <a class="" href="https://tweak-extension.com/blog/goodbye-modheader-hello-tweak">Goodbye ModHeader, hello tweak</a>. Comparing with Requestly in general? See <a class="" href="https://tweak-extension.com/blog/tweak-vs-requestly">tweak vs Requestly</a>.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="choosing-the-right-tool-for-the-job">Choosing the right tool for the job<a href="https://tweak-extension.com/blog/edit-http-request-before-sending#choosing-the-right-tool-for-the-job" class="hash-link" aria-label="Direct link to Choosing the right tool for the job" title="Direct link to Choosing the right tool for the job" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="start-with-your-ai-assistant">Start with your AI assistant<a href="https://tweak-extension.com/blog/edit-http-request-before-sending#start-with-your-ai-assistant" class="hash-link" aria-label="Direct link to Start with your AI assistant" title="Direct link to Start with your AI assistant" translate="no">​</a></h3>
<p>These days, ask your AI tools first. They are breaking down the barriers between tools and stitching different workflows together, so if one of them can do the job for you, start there.</p>
<p>Sometimes they can't. Some jobs are <strong>runtime configuration of your environment</strong>, and they repeat on every page load:</p>
<ul>
<li class="">attaching certain request headers to every request in a browsing session (<a class="" href="https://tweak-extension.com/docs/rule/modify-headers">headers only rules</a>)</li>
<li class="">continuously redirecting a set of outbound HTTP requests to a different host (<a class="" href="https://tweak-extension.com/docs/rule/redirect">redirect rules</a>)</li>
<li class="">pausing the next matching request so you can change it by hand (Edit before send)</li>
</ul>
<p>An AI assistant is not a good fit for that kind of work. You don't want to ask for the same header on every request; you want a rule that keeps applying it, in the browser, until you switch it off. That is the gap a focused tool fills.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="when-a-desktop-proxy-is-the-better-choice">When a desktop proxy is the better choice<a href="https://tweak-extension.com/blog/edit-http-request-before-sending#when-a-desktop-proxy-is-the-better-choice" class="hash-link" aria-label="Direct link to When a desktop proxy is the better choice" title="Direct link to When a desktop proxy is the better choice" translate="no">​</a></h3>
<p>Pick Charles, Proxyman, Fiddler or Burp if:</p>
<ul>
<li class="">the traffic comes from a <strong>mobile app</strong>, a desktop app, a CLI or a backend service</li>
<li class="">you need to pause <strong>page navigations, scripts, images</strong> or service worker requests (tweak pauses <code>fetch</code> and XHR, see <a class="" href="https://tweak-extension.com/docs/known-limitations">known limitations</a>)</li>
<li class="">you are running a full <strong>security assessment</strong> with scanners, intruders and repeaters</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="when-tweak-is-the-better-choice">When tweak is the better choice<a href="https://tweak-extension.com/blog/edit-http-request-before-sending#when-tweak-is-the-better-choice" class="hash-link" aria-label="Direct link to When tweak is the better choice" title="Direct link to When tweak is the better choice" translate="no">​</a></h3>
<p>Pick tweak if the request comes from a web page and you want to change it <strong>now</strong>, without leaving the tab.</p>
<p>Every tool in this article is a good tool, and experts with different specialities reach for different ones to get different jobs done. What I'm saying is that in some cases you are better off with tweak, and you will save a lot of money doing it. Weigh which one best fits the problem you have, not the one with the longest feature list.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="faq">FAQ<a href="https://tweak-extension.com/blog/edit-http-request-before-sending#faq" class="hash-link" aria-label="Direct link to FAQ" title="Direct link to FAQ" translate="no">​</a></h2>
<div><h3>How do I edit an HTTP request before it is sent from the browser?</h3><p>Use a tool that can pause the request in flight. Desktop proxies (Charles, Fiddler, Proxyman, Burp Suite) call this a breakpoint and need the browser routed through them with a trusted certificate. tweak does it inside the page: create a modify rule for the URL, switch on Edit before send, trigger the request, change the URL, body or headers in the editor that opens, and press Continue request.</p></div><div><h3>Can Chrome DevTools pause a request and let me change it?</h3><p>No. DevTools can pause your JavaScript when a fetch or XHR fires (XHR/fetch breakpoints), and Local Overrides can replace a response, but there is no built in way to edit the outgoing request itself and send the edited version. "Edit and Resend" style features replay a request that already went out.</p></div><div><h3>Can I edit the response before the page reads it?</h3><p>Yes. Set Edit before send to "Pause the response" or "Pause the request and response". The server answers, tweak holds the answer, and you can rewrite it (an error, an empty list, an out of stock item) before your app sees it.</p></div><div><h3>Do my edits change the rule?</h3><p>No. Edits apply to the one request that is paused. The rule keeps doing what it was saved to do for every request after it.</p></div><div><h3>Do I need a proxy or to install a certificate?</h3><p>Not with tweak. It runs as a browser extension inside the page, so there is no proxy to configure, no root certificate to trust and no system wide traffic rerouting.</p></div><div><h3>Which requests can tweak pause?</h3><p>Requests your page makes with fetch or XMLHttpRequest, which covers REST and GraphQL API calls. It does not pause page navigations, images, scripts, service worker requests or traffic from apps outside the browser. For those, a desktop proxy is the right tool.</p></div><div><h3>How much does Edit before send cost?</h3><p>Edit before send is part of tweak Premium: $4 a month or $36 a year, with a 7 day free trial. Commercial proxies with breakpoints are listed at $50 (Charles, one time), $89 (Proxyman Standard), about $144 a year (Fiddler Everywhere Pro, billed annually) and $499 a year (Burp Suite Professional).</p></div><div><h3>Is there a free way to pause and edit requests?</h3><p>Yes. HTTP Toolkit (free tier), Burp Suite Community, OWASP ZAP and mitmproxy all have free request interception, and Tamper Dev is a free extension. They are proxies or standalone tools with their own setup. tweak is the option for developers who want pausing, mocking and rewriting in one rule, inside the browser they already use.</p></div>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="try-it">Try it<a href="https://tweak-extension.com/blog/edit-http-request-before-sending#try-it" class="hash-link" aria-label="Direct link to Try it" title="Direct link to Try it" translate="no">​</a></h2>
<p><a class="" href="https://tweak-extension.com/pricing?feature=edit-before-send">Start the 7 day free trial</a>, add a modify rule for the request you are debugging, set Edit before send to <strong>Pause the request</strong>, and trigger it. The next request is yours to change.</p>
<p>New to tweak? Start with the <a class="" href="https://tweak-extension.com/docs/intro">introduction</a>. The free plan gives you 12 mock rules, no account required.</p>
<br><hr><div class="buttons_rr6z"><h3>Was this page helpful?</h3><div class="thumbs_zuU5"><button class="button button--outline button--primary"><span class="fa fa-thumbs-up"></span>&nbsp;<!-- -->Yes</button><button class="button button--outline button--primary"><span class="fa fa-thumbs-down"></span>&nbsp;<!-- -->No</button></div></div><small>Need something else? <a href="https://tally.so/r/VLzbl6" target="_blank">Request a feature</a></small><div class="message_SA7R" style="visibility:hidden"><span class="fa fa-bolt"></span>&nbsp; <i>Thanks for your feedback!</i></div>
]]></content:encoded>
            <category>tweak</category>
            <category>HTTP Debugging</category>
            <category>Software Testing</category>
            <category>Productivity</category>
        </item>
        <item>
            <title><![CDATA[Goodbye ModHeader, hello tweak!]]></title>
            <link>https://tweak-extension.com/blog/goodbye-modheader-hello-tweak</link>
            <guid>https://tweak-extension.com/blog/goodbye-modheader-hello-tweak</guid>
            <pubDate>Tue, 01 Sep 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Google and Microsoft pulled ModHeader after dormant data-collection code was found inside it. Here is what happened, and how tweak, a free alternative for modifying both request and response headers, handles it with a different security posture.]]></description>
            <content:encoded><![CDATA[<p><strong>On July 10, 2026, Google and Microsoft pulled ModHeader from the Chrome Web Store and Edge Add-ons. Roughly 1.6 million installs, gone in a few days, after dormant data-collection code was found buried in the extension</strong>. If you were one of those users, or you're just re-evaluating what you trust with request and header access, here's what happened and what tweak does differently.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="what-happened">What happened<a href="https://tweak-extension.com/blog/goodbye-modheader-hello-tweak#what-happened" class="hash-link" aria-label="Direct link to What happened" title="Direct link to What happened" translate="no">​</a></h2>
<p>ModHeader had a large install base built over years as a go-to tool for editing request and response headers. The code that got it pulled wasn't collecting data on day one, it was dormant, waiting. That's the part worth sitting with: an extension with broad host permissions can ship inert code today and activate it later, and most users would have no way to know until someone found it.</p>
<p>Header and network permissions are some of the most sensitive an extension can request. They see every request your browser makes: cookies, auth tokens, internal URLs, all of it. That access has to be earned with a track record, not just a good changelog.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="where-tweak-stands-on-header-modification">Where tweak stands on header modification<a href="https://tweak-extension.com/blog/goodbye-modheader-hello-tweak#where-tweak-stands-on-header-modification" class="hash-link" aria-label="Direct link to Where tweak stands on header modification" title="Direct link to Where tweak stands on header modification" translate="no">​</a></h2>
<p>tweak has a dedicated <a class="" href="https://tweak-extension.com/docs/rule/modify-headers">headers only rule type</a> built specifically for this job:</p>
<ul>
<li class=""><strong>Set, append, or remove</strong> any request or response header, including ones a page's own JavaScript is forbidden from touching, like <code>Referer</code>, <code>Origin</code>, and <code>User-Agent</code>.</li>
<li class=""><strong>Reaches every request</strong>, not just <code>fetch</code>/<code>XHR</code> calls: page navigations, scripts, images, stylesheets, and fonts are all in scope.</li>
<li class=""><strong>Two scopes</strong>: run it only on the active tab while tweak is on, or set it to <strong>Global</strong> so it persists across tabs and browser restarts, for the cases where you want an override simply always on.</li>
<li class="">Matching uses the browser's own <a href="https://github.com/google/re2/wiki/Syntax" target="_blank" rel="noopener noreferrer" class="">RE2</a> engine, so you get real regex matching without a hand-rolled parser trying to guess intent.</li>
</ul>
<p>None of this runs through a proxy or a remote service. It's applied by the browser itself, tweak included, working entirely on your device.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="how-it-actually-looks">How it actually looks<a href="https://tweak-extension.com/blog/goodbye-modheader-hello-tweak#how-it-actually-looks" class="hash-link" aria-label="Direct link to How it actually looks" title="Direct link to How it actually looks" translate="no">​</a></h2>
<p>Switch a rule to <strong>Headers only</strong> and you get a row per header, with a dropdown that picks the operation:</p>
<p><img decoding="async" loading="lazy" alt="a headers only rule with three operations" src="https://tweak-extension.com/assets/images/modify-headers-01-rule-6731c7d8f8b4ee780747a2cbc9b7cd68.png" title="a headers only rule with three operations" width="1600" height="1018" class="img_F_NH"></p>
<p>Each row can <strong>Set</strong> (replace the value, or add the header if it's missing), <strong>Append</strong> (add a value alongside the existing one, useful for a second <code>Set-Cookie</code>), or <strong>Remove</strong> (strip it out entirely):</p>
<p><img decoding="async" loading="lazy" alt="the operation dropdown showing set, append and remove" src="https://tweak-extension.com/assets/images/modify-headers-02-operations-08dfdb314246a539914ba29875e6a274.png" title="set, append or remove" width="1600" height="1136" class="img_F_NH"></p>
<p>Browsers only allow <strong>Append</strong> on a fixed allowlist of request headers (things like <code>Accept</code>, <code>Cookie</code>, <code>User-Agent</code>). Pick it on anything outside that list and the row tells you right there, instead of silently failing:</p>
<p><img decoding="async" loading="lazy" alt="an append picked on a header the browser refuses, flagged in red" src="https://tweak-extension.com/assets/images/modify-headers-05-append-allowlist-30a89c75a519aa86c6442197104dd855.png" title="appending outside the allowlist" width="1600" height="1018" class="img_F_NH"></p>
<p>Below the header table, a <strong>Scope</strong> dropdown decides how far the rule reaches: <strong>Active tab</strong> applies it only while tweak is running, on the tab it's running on. <strong>Global</strong> applies it on every tab, whether or not tweak is running, and survives a browser restart, for the override you want simply always on:</p>
<p><img decoding="async" loading="lazy" alt="the scope dropdown with active tab and global options" src="https://tweak-extension.com/assets/images/modify-headers-03-scope-cfe17a5813af7eb444a2c6eb49af6f4f.png" title="active tab or global" width="1600" height="1136" class="img_F_NH"></p>
<p>That's the whole workflow: pick a header, pick an operation, pick a scope. No proxy setup, no certificate, no desktop app to install alongside it.</p>
<p><strong>tweak is a free alternative to ModHeader for modifying both request and response headers.</strong> Every operation (<strong>Set</strong>, <strong>Append</strong>, <strong>Remove</strong>), on request and response headers, in both scopes, is on the free plan, with no account and no sign-up. The one <a class="" href="https://tweak-extension.com/pricing">paid</a> part is templating, putting <code>{{variables}}</code> or generated values inside a header cell:</p>
<table><thead><tr><th>Capability</th><th>Free</th><th><a class="" href="https://tweak-extension.com/pricing">Paid</a></th></tr></thead><tbody><tr><td>Request headers, Set / Append / Remove</td><td>✅</td><td>✅</td></tr><tr><td>Response headers, Set / Append / Remove</td><td>✅</td><td>✅</td></tr><tr><td>Both scopes</td><td>✅</td><td>✅</td></tr><tr><td>Templating (<code>{{variables}}</code>, generators)</td><td>❌</td><td>✅</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="profiles--collections">Profiles → Collections<a href="https://tweak-extension.com/blog/goodbye-modheader-hello-tweak#profiles--collections" class="hash-link" aria-label="Direct link to Profiles → Collections" title="Direct link to Profiles → Collections" translate="no">​</a></h2>
<p>ModHeader's "Profiles" let you group header sets and switch between them. tweak's equivalent is <a class="" href="https://tweak-extension.com/docs/collections">Collections</a>: folders that group your rules, not just headers only rules, so a collection can mix header rewrites with mocks and redirects if that's what a given workflow needs.</p>
<p><img decoding="async" loading="lazy" alt="Collections management in the left side panel" src="https://tweak-extension.com/assets/images/collections-01-panel-9f5383d6e0847bccb106e5bc32c49d78.png" title="Collections management in the left side panel" width="1600" height="1136" class="img_F_NH"></p>
<ul>
<li class=""><strong>Add a collection</strong> from the plus button in the side panel, drag to reorder, double-click to rename.</li>
<li class=""><strong>Open collections show up as tabs</strong> in the main workspace, so you can flip between them the way you'd flip between profiles:</li>
</ul>
<p><img decoding="async" loading="lazy" alt="Collections in the main workspace as tabs" src="https://tweak-extension.com/assets/images/collections-02-nav-bar-e0cc2dc3f4ef1097dcb29556ac342c45.png" title="Collections in the main workspace as tabs" width="1600" height="1136" class="img_F_NH"></p>
<ul>
<li class=""><strong>A closed collection keeps working.</strong> While tweak runs, a green dot on its name in the side panel means it has active rules, even while the tab itself isn't open, no need to keep every profile "selected" to have it apply.</li>
<li class=""><strong>Move rules between collections</strong> from a rule's own menu, and <strong>import/export</strong> either a single collection or everything at once.</li>
</ul>
<p><strong>We want to be upfront about this:</strong> Collections are a paid-plan feature. The free plan runs your 12 rules unorganized; grouping them into folders is part of <a class="" href="https://tweak-extension.com/pricing">Premium</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="our-security-posture-is-in-the-open">Our security posture is in the open<a href="https://tweak-extension.com/blog/goodbye-modheader-hello-tweak#our-security-posture-is-in-the-open" class="hash-link" aria-label="Direct link to Our security posture is in the open" title="Direct link to Our security posture is in the open" translate="no">​</a></h2>
<ul>
<li class=""><strong>Manifest V3</strong>, and every permission maps to a capability the product visibly uses. No unused reach "for later."</li>
<li class=""><strong>No server-side visibility into your rules, mocks, or traffic.</strong> They live in the browser's own storage APIs, on your device. Our servers only handle account sign-in, checkout, and license validation, they're not in the request path at all.</li>
<li class=""><strong>Source is reviewed before every release.</strong> We don't ship code we haven't read, and dependencies are audited as part of that process.</li>
<li class=""><strong>Vulnerability reports are welcome</strong>, not deflected: <a href="mailto:help@tweak-extension.com" target="_blank" rel="noopener noreferrer" class="">help@tweak-extension.com</a>, with good-faith fixes and disclosure.</li>
</ul>
<p>Full detail is on our <a class="" href="https://tweak-extension.com/security">security page</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="moving-over">Moving over<a href="https://tweak-extension.com/blog/goodbye-modheader-hello-tweak#moving-over" class="hash-link" aria-label="Direct link to Moving over" title="Direct link to Moving over" translate="no">​</a></h2>
<p>If you're migrating header rules off ModHeader, tweak's <a class="" href="https://tweak-extension.com/docs/rule/modify-headers">headers only rule type</a> covers set, append, and remove operations on both request and response headers, all of it free, with no account and no sign-up.</p>
<p>Try tweak free on <a href="https://chromewebstore.google.com/detail/tweak-mock-and-modify-htt/feahianecghpnipmhphmfgmpdodhcapi?utm_source=modheader_blog&amp;utm_medium=blog&amp;utm_campaign=goodbye_modheader" target="_blank" rel="noopener noreferrer" class="">Chrome</a> or <a href="https://microsoftedge.microsoft.com/addons/detail/tweak-mock-and-modify-ht/igmkallacokolpajpaboinafcebkfafl?utm_source=modheader_blog&amp;utm_medium=blog&amp;utm_campaign=goodbye_modheader" target="_blank" rel="noopener noreferrer" class="">Edge</a>. 12 rules on the free plan, no account required.</p>
<br><hr><div class="buttons_rr6z"><h3>Was this page helpful?</h3><div class="thumbs_zuU5"><button class="button button--outline button--primary"><span class="fa fa-thumbs-up"></span>&nbsp;<!-- -->Yes</button><button class="button button--outline button--primary"><span class="fa fa-thumbs-down"></span>&nbsp;<!-- -->No</button></div></div><small>Need something else? <a href="https://tally.so/r/VLzbl6" target="_blank">Request a feature</a></small><div class="message_SA7R" style="visibility:hidden"><span class="fa fa-bolt"></span>&nbsp; <i>Thanks for your feedback!</i></div>
]]></content:encoded>
            <category>tweak</category>
            <category>Security</category>
            <category>Privacy</category>
            <category>Browser Extensions</category>
        </item>
        <item>
            <title><![CDATA[v9: two new rules, a faster editor, and Data X-Ray (beta)]]></title>
            <link>https://tweak-extension.com/blog/v9-announcement</link>
            <guid>https://tweak-extension.com/blog/v9-announcement</guid>
            <pubDate>Tue, 01 Sep 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[tweak v9.0.0 ships headers-only rules, redirect rules for any request type, a rebuilt floating-window editor, and a first look at Data X-Ray in beta.]]></description>
            <content:encoded><![CDATA[<p><strong>Four things shipped in v9.0.0. On their own, each one saves you a few clicks. Put together, they change how a debugging session actually feels: fewer detours, less waiting, more of your attention staying on the problem in front of you.</strong></p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="1-rewrite-headers-without-touching-the-body">1. Rewrite headers without touching the body<a href="https://tweak-extension.com/blog/v9-announcement#1-rewrite-headers-without-touching-the-body" class="hash-link" aria-label="Direct link to 1. Rewrite headers without touching the body" title="Direct link to 1. Rewrite headers without touching the body" translate="no">​</a></h2>
<p>A dedicated <a class="" href="https://tweak-extension.com/docs/rule/modify-headers">Headers only rule type</a>. Set, append, or remove request and response headers, on any tab or globally, without a mock response getting in the way. Flip a feature flag via a cookie, force a <code>Cache-Control</code> off, spoof <code>X-Powered-By</code>, all from one focused rule.</p>
<p><img decoding="async" loading="lazy" alt="A headers only rule setting, appending and removing response headers" src="https://tweak-extension.com/assets/images/modify-headers-01-rule-6731c7d8f8b4ee780747a2cbc9b7cd68.png" title="A headers only rule: set, append and remove, side by side." width="1600" height="1018" class="img_F_NH"></p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="2-redirect-anything-not-just-api-calls">2. Redirect anything, not just API calls<a href="https://tweak-extension.com/blog/v9-announcement#2-redirect-anything-not-just-api-calls" class="hash-link" aria-label="Direct link to 2. Redirect anything, not just API calls" title="Direct link to 2. Redirect anything, not just API calls" translate="no">​</a></h2>
<p>This one's been requested for a while: <a class="" href="https://tweak-extension.com/docs/rule/redirect">Redirect rules</a> now catch images, stylesheets, scripts, whatever you point them at, not only XHR/fetch. Swap a CDN asset for a local file, send a whole API to <code>localhost</code>, or regex your way from <code>v1</code> to <code>v2</code> with a capture group.</p>
<p><img decoding="async" loading="lazy" alt="A redirect rule sending an API call to a local server" src="https://tweak-extension.com/assets/images/redirect-01-rule-bf88c7e3dce0411bf65f949dd1b925a7.png" title="Sending a live API straight to localhost, path and query untouched." width="1600" height="1020" class="img_F_NH"></p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="3-a-lighter-faster-editor-that-follows-you-around">3. A lighter, faster editor that follows you around<a href="https://tweak-extension.com/blog/v9-announcement#3-a-lighter-faster-editor-that-follows-you-around" class="hash-link" aria-label="Direct link to 3. A lighter, faster editor that follows you around" title="Direct link to 3. A lighter, faster editor that follows you around" translate="no">​</a></h2>
<p>The rule editor got a rebuild: snappier to open, snappier to type in. And it no longer has to live docked in DevTools. Pop it into a floating window from the menu and keep it on screen while you work anywhere else in the browser.</p>
<p><img decoding="async" loading="lazy" alt="The menu showing the option to open tweak in a floating window" src="https://tweak-extension.com/assets/images/01-intro-import-export-a6ea585eecca7e521dd4b8941781112a.png" title="Open in floating window, tucked under the overflow menu." width="560" height="400" class="img_F_NH"></p>
<p><img decoding="async" loading="lazy" alt="tweak running in a floating window, detached from DevTools, next to the page it&amp;#39;s inspecting" src="https://tweak-extension.com/assets/images/floating-window-full-8eb71655057eebd7f2ba97c458b85bb3.png" title="Detached from DevTools, tweak stays on screen wherever you work." width="2880" height="1800" class="img_F_NH"></p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="4-the-fastest-way-to-discover-your-application-data-beta">4. The fastest way to discover your application data (Beta)<a href="https://tweak-extension.com/blog/v9-announcement#4-the-fastest-way-to-discover-your-application-data-beta" class="hash-link" aria-label="Direct link to 4. The fastest way to discover your application data (Beta)" title="Direct link to 4. The fastest way to discover your application data (Beta)" translate="no">​</a></h2>
<p>Crop-select any part of a page and <a class="" href="https://tweak-extension.com/docs/data-x-ray">Data X-Ray</a> matches what you're looking at against the requests that produced it, badges every matching element, and lets you open, edit and import the payload as a tweak rule without leaving the page or digging through the Network panel.</p>
<p><img decoding="async" loading="lazy" alt="Data X-Ray: crop-select a page region, get badges on every matched element, and pop payloads into editable side-by-side JSON editors" src="https://tweak-extension.com/assets/images/05-data-x-ray-04-multi-editor-68781667912e6d1a4e8595d4d7341fb8.png" title="Select a region, get badges, pop payloads into side-by-side editors." width="2400" height="1366" class="img_F_NH"></p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="try-it">Try it<a href="https://tweak-extension.com/blog/v9-announcement#try-it" class="hash-link" aria-label="Direct link to Try it" title="Direct link to Try it" translate="no">​</a></h2>
<p>Two new rule types, a faster editor, and a first look at Data X-Ray: that's the bet behind v9.0.0. Update your extension and give it a try.</p>
<p><strong>On Tweak Premium?</strong> All of this is unrestricted and already live in your extension, nothing to activate.</p>
<p><a class="" href="https://tweak-extension.com/changelog">See what's new in v9.0.0</a></p>]]></content:encoded>
            <category>tweak</category>
            <category>Release</category>
            <category>Rules</category>
            <category>Data X-Ray</category>
        </item>
        <item>
            <title><![CDATA[6 Powerful Browser Extensions for Frontend Development]]></title>
            <link>https://tweak-extension.com/blog/top-browser-extensions-frontend</link>
            <guid>https://tweak-extension.com/blog/top-browser-extensions-frontend</guid>
            <pubDate>Tue, 09 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Discover the most powerful browser extensions for frontend developers. Boost productivity with tools for debugging, mocking, performance, and more.]]></description>
            <content:encoded><![CDATA[<p>We're always looking for new ways to improve our effectiveness as frontend developers. We want to pick the right tools to get the job done. We want to have a fully equipped browser, to troubleshoot any tricky bug that comes our way.</p>
<p>Browser extensions have been around for a while, making their way into our development workflow in many different shapes. We can think of extensions as development companions.</p>
<p>In this article, we would like to share a few of them that, in our opinion, provide valuable assistance for frontend developers.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="cookie-editor">Cookie-Editor<a href="https://tweak-extension.com/blog/top-browser-extensions-frontend#cookie-editor" class="hash-link" aria-label="Direct link to Cookie-Editor" title="Direct link to Cookie-Editor" translate="no">​</a></h2>
<p><strong>tl;dr</strong>: Cookie manager. Create/update/delete cookies on any website<br>
<strong>Users</strong>: 2M+<br>
<strong>References</strong>: <a href="https://chromewebstore.google.com/detail/cookie-editor/hlkenndednhfkekhgcdicdfddnkalmdm" target="_blank" rel="noopener noreferrer" class="">chrome web store</a> | <a href="https://cookie-editor.com//" target="_blank" rel="noopener noreferrer" class="">website</a><br></p>
<p>Cookie-Editor really feels productive due to its simple user experience. To access the application storage section, we often need to open the developer tools and perform a couple of clicks. Having the popup floating on top of the page just makes sense and feels more efficient. Modifying a specific cookie value becomes a quick task. Global actions are also available such as clearing all the site cookies.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="jsonview">JSONView<a href="https://tweak-extension.com/blog/top-browser-extensions-frontend#jsonview" class="hash-link" aria-label="Direct link to JSONView" title="Direct link to JSONView" translate="no">​</a></h2>
<p><strong>tl;dr</strong>: Enhances your experience when visualizing JSON documents in the browser<br>
<strong>Users</strong>: 900k+<br>
<strong>References</strong>: <a href="https://chrome.google.com/webstore/detail/jsonview/chklaanhfefbnpoihckbnefhakgolnmc" target="_blank" rel="noopener noreferrer" class="">chrome web store</a> | <a href="https://github.com/gildas-lormeau/JSONView-for-Chrome" target="_blank" rel="noopener noreferrer" class="">website</a><br></p>
<p>JSON is undoubtedly one of the most used data formats on the web. Sometimes when inspecting REST API endpoints directly in the browser, it's beneficial to have a way to properly visualize JSON content. That's where JSONView comes in, providing a preview of JSON documents.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="react-developer-tools">React Developer Tools<a href="https://tweak-extension.com/blog/top-browser-extensions-frontend#react-developer-tools" class="hash-link" aria-label="Direct link to React Developer Tools" title="Direct link to React Developer Tools" translate="no">​</a></h2>
<p><strong>tl;dr</strong>: Addon for React development. Tooling to inspect React components, their state, and component hierarchies<br>
<strong>Users</strong>: 5M+<br>
<strong>References</strong>: <a href="https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi" target="_blank" rel="noopener noreferrer" class="">chrome web store</a></p>
<p>If you are a React developer, this tool is a must-have in your toolkit. It will make your life much easier when navigating through your application component tree, simultaneously allowing you to look up the current state of a given component, which is much more powerful than simply looking up a DOM element through the default HTML inspector. This tool is equipped with a profiler component, allowing you to tap into the performance of your React application.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="redux-devtools">Redux DevTools<a href="https://tweak-extension.com/blog/top-browser-extensions-frontend#redux-devtools" class="hash-link" aria-label="Direct link to Redux DevTools" title="Direct link to Redux DevTools" translate="no">​</a></h2>
<p><strong>tl;dr</strong>: Inspect your Redux application state and how it changes throughout time<br>
<strong>Users</strong>: 1M+<br>
<strong>References</strong>: <a href="https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd" target="_blank" rel="noopener noreferrer" class="">chrome web store</a> | <a href="https://github.com/reduxjs/redux-devtools/tree/main/extension" target="_blank" rel="noopener noreferrer" class="">website</a><br></p>
<p>Much of the Redux library's success can be traced to the fantastic debuggability capabilities shipped within this extension. The Redux DevTools complements the library very well, powering the developer's decision to adopt Redux as a solution for state management. Just jump over to the "Reviews" section and be amazed by the unanimity gathered among so many developers.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="change-timezone-time-shift">Change Timezone (Time Shift)<a href="https://tweak-extension.com/blog/top-browser-extensions-frontend#change-timezone-time-shift" class="hash-link" aria-label="Direct link to Change Timezone (Time Shift)" title="Direct link to Change Timezone (Time Shift)" translate="no">​</a></h2>
<p><strong>tl;dr</strong>: Change your default browser timezone<br>
<strong>Users</strong>: 20K+<br>
<strong>References</strong>: <a href="https://chrome.google.com/webstore/detail/change-timezone-time-shif/nbofeaabhknfdcpoddmfckpokmncimpj" target="_blank" rel="noopener noreferrer" class="">chrome web store</a><br></p>
<p>The tool description mentions privacy protection as a selling point to bring users on board. This extension is most useful for frontend developers when your application deals with timezone-specific logic/UI visualization. This means you no longer need to hack your way around globals or mess with the host/system time settings. Instead, let this extension work for you toggling different timezones on the fly; you'll be able to perform whatever validations you need in a quick and easily reversible way.</p>
<p><img decoding="async" loading="lazy" alt="change timezone demonstration" src="https://tweak-extension.com/assets/images/timezone-demo-4ea70b8bab2204bfa4ba3a6927cc32ef.gif" title="change timezone demonstration" width="1278" height="814" class="img_F_NH"></p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="tweak">tweak<a href="https://tweak-extension.com/blog/top-browser-extensions-frontend#tweak" class="hash-link" aria-label="Direct link to tweak" title="Direct link to tweak" translate="no">​</a></h2>
<p><strong>tl;dr</strong>: Mock, modify, delay HTTP requests and much more!<br>
<strong>Users</strong>: 50K+<br></p>
<p><strong>The missing piece</strong> 😊 &nbsp;. tweak tackles a prevalent problem in web development: simulate data-driven UI behaviors. We've developed yet another mocking tool with a unique perspective to help you quickly tap into your HTTP requests and easily manipulate them, without writing code, in any environment. We put our best into providing a unique and quality user experience.</p>
<br>
<br>
<p sx="[object Object]">If you liked this article, consider sharing (<a href="https://twitter.com/share?text=6%20Powerful%20Browser%20Extensions%20for%20Frontend%20Development&amp;url=https://tweak-extension.com/blog/top-browser-extensions-frontend" target="_blank" rel="noreferrer" title="tweeting"><span style="text-decoration:underline">tweeting</span></a>) it to your followers.</p>
<br><hr><div class="buttons_rr6z"><h3>Did you like this article?</h3><div class="thumbs_zuU5"><button class="button button--outline button--primary"><span class="fa fa-thumbs-up"></span>&nbsp;<!-- -->Yes</button><button class="button button--outline button--primary"><span class="fa fa-thumbs-down"></span>&nbsp;<!-- -->No</button></div></div><small>Need something else? <a href="https://tally.so/r/VLzbl6" target="_blank">Request a feature</a></small><div class="message_SA7R" style="visibility:hidden"><span class="fa fa-bolt"></span>&nbsp; <i>Thanks for your feedback!</i></div>]]></content:encoded>
            <category>Productivity</category>
            <category>Browser Extensions</category>
        </item>
        <item>
            <title><![CDATA[tweak vs Mock Service Worker (MSW)]]></title>
            <link>https://tweak-extension.com/blog/msw-vs-browser-extension-tweak</link>
            <guid>https://tweak-extension.com/blog/msw-vs-browser-extension-tweak</guid>
            <pubDate>Tue, 09 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Compare Mock Service Worker (MSW) and tweak extension for API mocking. Discover which tool fits your frontend development, QA, and automated testing workflow.]]></description>
            <content:encoded><![CDATA[<p>If you're debugging HTTP requests or mocking APIs for frontend development, you've likely considered both <strong>tweak</strong> and <strong>Mock Service Worker (MSW)</strong>. While both tools allow you to intercept and modify network traffic, they approach the problem from completely different angles. tweak is a lightweight browser extension; MSW is a code-level library that integrates directly into your project. Understanding their differences will help you pick the right one for your workflow.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="quick-verdict">Quick verdict<a href="https://tweak-extension.com/blog/msw-vs-browser-extension-tweak#quick-verdict" class="hash-link" aria-label="Direct link to Quick verdict" title="Direct link to Quick verdict" translate="no">​</a></h2>
<table><thead><tr><th></th><th>tweak</th><th>Mock Service Worker (MSW)</th></tr></thead><tbody><tr><td><strong>Setup time</strong></td><td>~1 min, no account needed</td><td>~15 mins, code integration required</td></tr><tr><td><strong>Scope</strong></td><td>Browser requests only</td><td>Browser and Node.js (via interceptors)</td></tr><tr><td><strong>Code required</strong></td><td>No</td><td>Yes</td></tr><tr><td><strong>Automated testing</strong></td><td>No</td><td>First-class support (Jest, Vitest)</td></tr><tr><td><strong>Shared in Git</strong></td><td>Export/Import JSON</td><td>Natively via code handlers</td></tr><tr><td><strong>Best for</strong></td><td>Manual testing, rapid UI dev, QA</td><td>Automated tests, CI pipelines, team mocks</td></tr><tr><td><strong>Price</strong></td><td>Free / $36/year</td><td>Free (Open Source)</td></tr><tr><td><strong>Learning curve</strong></td><td>Minimal</td><td>Moderate</td></tr></tbody></table>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="what-tweak-does-well">What tweak does well<a href="https://tweak-extension.com/blog/msw-vs-browser-extension-tweak#what-tweak-does-well" class="hash-link" aria-label="Direct link to What tweak does well" title="Direct link to What tweak does well" translate="no">​</a></h2>
<p><strong>Zero codebase changes.</strong> You don't need to install NPM packages, configure Webpack, or initialize service workers in your public directory. Install the extension, open the panel, and create a rule. You're intercepting requests within 60 seconds without writing a single line of code.</p>
<p><strong>Testing in production.</strong> Because tweak sits at the browser level and doesn't require source code access, you can mock requests on live production sites. This is incredibly useful for reproducing bugs or testing edge cases on a deployed application where MSW is typically disabled.</p>
<p><strong>Simple, visual UI.</strong> tweak is designed for immediate feedback. There's no need to write JavaScript resolvers or handle route matching syntax. You just use a clean interface with toggles and JSON editors to mock what you need and move on.</p>
<p><strong>Accessible for non-developers.</strong> QAs, product managers, and designers can easily use tweak to simulate different application states (like an empty state or a 500 error) without needing to understand the underlying codebase or spin up a local development environment.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="what-msw-does-well">What MSW does well<a href="https://tweak-extension.com/blog/msw-vs-browser-extension-tweak#what-msw-does-well" class="hash-link" aria-label="Direct link to What MSW does well" title="Direct link to What MSW does well" translate="no">​</a></h2>
<p><strong>First-class automated testing.</strong> MSW is built to shine in your test suite. By intercepting requests at the network level in Node.js, it provides incredibly reliable mocks for tools like Jest, Vitest, and React Testing Library without patching your HTTP clients.</p>
<p><strong>Single source of truth.</strong> With MSW, you write your mock handlers once and reuse them across your unit tests, integration tests, Storybook, and local development. This prevents the classic problem of having fragmented mock data across different testing tools.</p>
<p><strong>Version controlled by default.</strong> Since MSW mocks are just code in your repository, they live alongside your application logic. When an API contract changes, the mocks are updated in the same pull request. Every developer on the team gets the exact same mock environment out of the box.</p>
<p><strong>Framework agnostic.</strong> It intercepts requests below the client level, meaning it doesn't matter if your app uses Fetch, Axios, Apollo, or React Query. The same handlers work perfectly across the board.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="head-to-head-common-scenarios">Head-to-head: common scenarios<a href="https://tweak-extension.com/blog/msw-vs-browser-extension-tweak#head-to-head-common-scenarios" class="hash-link" aria-label="Direct link to Head-to-head: common scenarios" title="Direct link to Head-to-head: common scenarios" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="i-need-to-quickly-mock-a-500-error-to-test-a-ui-bug">"I need to quickly mock a 500 error to test a UI bug"<a href="https://tweak-extension.com/blog/msw-vs-browser-extension-tweak#i-need-to-quickly-mock-a-500-error-to-test-a-ui-bug" class="hash-link" aria-label="Direct link to &quot;I need to quickly mock a 500 error to test a UI bug&quot;" title="Direct link to &quot;I need to quickly mock a 500 error to test a UI bug&quot;" translate="no">​</a></h3>
<p><strong>Use tweak.</strong> No need to write an override handler or touch the code. Just open the extension, create a quick rule returning a 500 status, and refresh the page.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="i-am-writing-an-integration-test-in-jest">"I am writing an integration test in Jest"<a href="https://tweak-extension.com/blog/msw-vs-browser-extension-tweak#i-am-writing-an-integration-test-in-jest" class="hash-link" aria-label="Direct link to &quot;I am writing an integration test in Jest&quot;" title="Direct link to &quot;I am writing an integration test in Jest&quot;" translate="no">​</a></h3>
<p><strong>Use MSW.</strong> tweak only works in the browser. MSW's Node.js interceptors are practically the industry standard for intercepting requests during automated tests.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="i-want-the-whole-team-to-share-the-exact-same-mock-data">"I want the whole team to share the exact same mock data"<a href="https://tweak-extension.com/blog/msw-vs-browser-extension-tweak#i-want-the-whole-team-to-share-the-exact-same-mock-data" class="hash-link" aria-label="Direct link to &quot;I want the whole team to share the exact same mock data&quot;" title="Direct link to &quot;I want the whole team to share the exact same mock data&quot;" translate="no">​</a></h3>
<p><strong>Use MSW.</strong> Because handlers are committed to Git, your team is always on the same page. While tweak allows you to export and share rules manually, MSW makes sharing implicit and automatic.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="im-testing-an-issue-on-our-live-staging-environment">"I'm testing an issue on our live staging environment"<a href="https://tweak-extension.com/blog/msw-vs-browser-extension-tweak#im-testing-an-issue-on-our-live-staging-environment" class="hash-link" aria-label="Direct link to &quot;I'm testing an issue on our live staging environment&quot;" title="Direct link to &quot;I'm testing an issue on our live staging environment&quot;" translate="no">​</a></h3>
<p><strong>Use tweak.</strong> MSW is almost always stripped out of production and staging builds for performance and security reasons. tweak works perfectly on live URLs since it operates via the browser extension sandbox.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="i-need-to-mock-responses-for-a-backend-api-that-isnt-built-yet">"I need to mock responses for a backend API that isn't built yet"<a href="https://tweak-extension.com/blog/msw-vs-browser-extension-tweak#i-need-to-mock-responses-for-a-backend-api-that-isnt-built-yet" class="hash-link" aria-label="Direct link to &quot;I need to mock responses for a backend API that isn't built yet&quot;" title="Direct link to &quot;I need to mock responses for a backend API that isn't built yet&quot;" translate="no">​</a></h3>
<p><strong>Either works.</strong> If you're a solo developer working quickly in the browser, tweak is faster. If you're establishing the foundation for a project that will eventually need automated tests anyway, setting up MSW early is a smart investment.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="pricing-compared">Pricing compared<a href="https://tweak-extension.com/blog/msw-vs-browser-extension-tweak#pricing-compared" class="hash-link" aria-label="Direct link to Pricing compared" title="Direct link to Pricing compared" translate="no">​</a></h2>
<p><strong>tweak</strong> is free for up to 12 rules with no account required. Premium is $36/year (billed annually) or $4/month, granting unlimited rules and advanced matching capabilities.</p>
<p><strong>MSW</strong> is completely free and open-source (MIT License). There are no paid tiers or limits on rules.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="when-to-use-each-tool">When to use each tool<a href="https://tweak-extension.com/blog/msw-vs-browser-extension-tweak#when-to-use-each-tool" class="hash-link" aria-label="Direct link to When to use each tool" title="Direct link to When to use each tool" translate="no">​</a></h2>
<p>Choose <strong>tweak</strong> if:</p>
<ul>
<li class="">You want to mock requests immediately without touching application code.</li>
<li class="">You need to intercept requests on deployed environments (staging/production).</li>
<li class="">You're a manual QA, designer, or PM who isn't working directly in the codebase.</li>
<li class="">You value a visual interface over writing mock definitions in code.</li>
</ul>
<p>Choose <strong>MSW</strong> if:</p>
<ul>
<li class="">You are setting up an automated testing suite (Jest, Vitest, Cypress).</li>
<li class="">You want a single source of truth for mock data across your entire project.</li>
<li class="">You need mock definitions to be version-controlled in Git.</li>
<li class="">You are building a complex application where development and testing share the same network mocks.</li>
</ul>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="the-bottom-line">The bottom line<a href="https://tweak-extension.com/blog/msw-vs-browser-extension-tweak#the-bottom-line" class="hash-link" aria-label="Direct link to The bottom line" title="Direct link to The bottom line" translate="no">​</a></h2>
<p><strong>tweak and MSW are not mutually exclusive; in fact, they are highly complementary.</strong> tweak is optimised for speed, manual testing, and immediate visual feedback in the browser. MSW is the definitive tool for code-driven API mocking and automated testing.</p>
<p>Most modern frontend teams benefit from using both: MSW to power robust automated tests and provide baseline development mocks, and tweak for rapid exploratory testing, edge-case simulation, and debugging live environments without code changes.</p>
<p><a href="https://tweak-extension.com/" target="_blank" rel="noopener noreferrer" class="">Try tweak free</a>. No account required, 12 rules on the free plan.</p>
<br>
<br>
<p sx="[object Object]">If you liked this article, consider sharing (<a href="https://twitter.com/share?text=tweak%20vs%20Mock%20Service%20Worker%20(MSW)&amp;url=https://tweak-extension.com/blog/msw-vs-browser-extension-tweak" target="_blank" rel="noreferrer" title="tweeting"><span style="text-decoration:underline">tweeting</span></a>) it to your followers.</p>
<br><hr><div class="buttons_rr6z"><h3>Did you like this article?</h3><div class="thumbs_zuU5"><button class="button button--outline button--primary"><span class="fa fa-thumbs-up"></span>&nbsp;<!-- -->Yes</button><button class="button button--outline button--primary"><span class="fa fa-thumbs-down"></span>&nbsp;<!-- -->No</button></div></div><small>Need something else? <a href="https://tally.so/r/VLzbl6" target="_blank">Request a feature</a></small><div class="message_SA7R" style="visibility:hidden"><span class="fa fa-bolt"></span>&nbsp; <i>Thanks for your feedback!</i></div>]]></content:encoded>
            <category>tweak</category>
            <category>Software Testing</category>
        </item>
        <item>
            <title><![CDATA[tweak vs Proxyman: Browser Extension vs Desktop Proxy]]></title>
            <link>https://tweak-extension.com/blog/tweak-vs-proxyman</link>
            <guid>https://tweak-extension.com/blog/tweak-vs-proxyman</guid>
            <pubDate>Tue, 02 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Comparing tweak and Proxyman for HTTP request interception. Feature breakdown, pricing, and use cases to help you choose the right tool.]]></description>
            <content:encoded><![CDATA[<p>If you're debugging HTTP requests and network issues, you've likely considered both <strong>tweak</strong> and <strong>Proxyman</strong>. Both tools let you intercept, inspect, and modify network traffic, but they approach the problem from different angles. tweak is a lightweight browser extension; Proxyman is a full-featured desktop proxy application. Understanding their differences will help you pick the right one for your workflow.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="quick-verdict">Quick verdict<a href="https://tweak-extension.com/blog/tweak-vs-proxyman#quick-verdict" class="hash-link" aria-label="Direct link to Quick verdict" title="Direct link to Quick verdict" translate="no">​</a></h2>
<table><thead><tr><th></th><th>tweak</th><th>Proxyman</th></tr></thead><tbody><tr><td>Setup time</td><td>~1 min, no account needed</td><td>Download app, configure proxy</td></tr><tr><td>Free tier</td><td>12 rules, no sign-up</td><td>Free with limitations</td></tr><tr><td>Browser support</td><td>Chrome, Edge, Firefox</td><td>Works across all browsers</td></tr><tr><td>Scope</td><td>Browser requests only</td><td>System-wide network traffic</td></tr><tr><td>Code required</td><td>No</td><td>No</td></tr><tr><td>Mobile debugging</td><td>Limited (requires setup)</td><td>Full iOS/Android support</td></tr><tr><td>Price</td><td>Free / $36/year</td><td>Free / ~$99/year</td></tr><tr><td>Learning curve</td><td>Minimal</td><td>Moderate</td></tr></tbody></table>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="what-tweak-does-well">What tweak does well<a href="https://tweak-extension.com/blog/tweak-vs-proxyman#what-tweak-does-well" class="hash-link" aria-label="Direct link to What tweak does well" title="Direct link to What tweak does well" translate="no">​</a></h2>
<p><strong>Zero friction to start.</strong> Install the extension, open the panel, create a rule. No account, no proxy configuration, no certificate installation. You're intercepting requests within 60 seconds.</p>
<p><strong>Simple, focused UI.</strong> tweak does one thing exceptionally well: intercept and modify HTTP requests in the browser. The interface is lean and intentional. There's no dashboard overload, no learning curve, just rules and toggles.</p>
<p><strong>Free tier that's actually useful.</strong> The free plan includes 12 mock rules with no account required. For solo developers and debugging workflows, that's genuinely sufficient for real work.</p>
<p><strong>Browser-native, no system overhead.</strong> tweak runs entirely inside your browser extension sandbox. There's no proxy to configure, no certificate to install, no system-level meddling. It works in your existing browser session with zero external dependencies.</p>
<p><strong>Cross-browser compatibility.</strong> Works natively in Chrome, Edge, and Firefox. Install once, use everywhere.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="what-proxyman-does-well">What Proxyman does well<a href="https://tweak-extension.com/blog/tweak-vs-proxyman#what-proxyman-does-well" class="hash-link" aria-label="Direct link to What Proxyman does well" title="Direct link to What Proxyman does well" translate="no">​</a></h2>
<p><strong>System-wide traffic interception.</strong> Proxyman is a desktop proxy that can intercept traffic from any application on your machine, not just browsers. Desktop apps, mobile devices, command-line tools, servers: if it makes HTTP requests, Proxyman can see it and modify it.</p>
<p><strong>Mobile debugging powerhouse.</strong> Proxyman has first-class support for iOS and Android debugging. Forward your mobile device traffic through Proxyman's proxy to inspect and mock network calls from your apps in real time. This is invaluable if you're building mobile applications.</p>
<p><strong>Deep HTTP inspection.</strong> Proxyman gives you granular control over every aspect of requests and responses: headers, cookies, timing, SSL/TLS details, and more. If you need forensic-level visibility into network behavior, Proxyman delivers.</p>
<p><strong>All browsers and tools.</strong> Since Proxyman works at the system proxy level, it works with Chrome, Safari, Firefox, Edge, curl, Postman, and any other HTTP client on your machine.</p>
<p><strong>Breakpoints and request modification.</strong> Pause requests in flight, inspect them, and modify them before they're sent. Useful for complex debugging scenarios where you need to intercept at specific points.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="head-to-head-common-scenarios">Head-to-head: common scenarios<a href="https://tweak-extension.com/blog/tweak-vs-proxyman#head-to-head-common-scenarios" class="hash-link" aria-label="Direct link to Head-to-head: common scenarios" title="Direct link to Head-to-head: common scenarios" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="i-need-to-mock-an-api-endpoint-quickly-during-development">"I need to mock an API endpoint quickly during development"<a href="https://tweak-extension.com/blog/tweak-vs-proxyman#i-need-to-mock-an-api-endpoint-quickly-during-development" class="hash-link" aria-label="Direct link to &quot;I need to mock an API endpoint quickly during development&quot;" title="Direct link to &quot;I need to mock an API endpoint quickly during development&quot;" translate="no">​</a></h3>
<p><strong>Use tweak.</strong> No setup, no account, no proxy hassle. Create a rule and test immediately.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="i-need-to-debug-a-mobile-apps-api-calls">"I need to debug a mobile app's API calls"<a href="https://tweak-extension.com/blog/tweak-vs-proxyman#i-need-to-debug-a-mobile-apps-api-calls" class="hash-link" aria-label="Direct link to &quot;I need to debug a mobile app's API calls&quot;" title="Direct link to &quot;I need to debug a mobile app's API calls&quot;" translate="no">​</a></h3>
<p><strong>Use Proxyman.</strong> tweak is browser-only. Proxyman's mobile debugging capabilities are built for exactly this use case.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="i-need-to-intercept-traffic-from-a-desktop-application">"I need to intercept traffic from a desktop application"<a href="https://tweak-extension.com/blog/tweak-vs-proxyman#i-need-to-intercept-traffic-from-a-desktop-application" class="hash-link" aria-label="Direct link to &quot;I need to intercept traffic from a desktop application&quot;" title="Direct link to &quot;I need to intercept traffic from a desktop application&quot;" translate="no">​</a></h3>
<p><strong>Use Proxyman.</strong> tweak doesn't work outside the browser. Proxyman's system proxy handles any application.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="i-need-to-test-error-states-and-edge-cases-in-the-browser">"I need to test error states and edge cases in the browser"<a href="https://tweak-extension.com/blog/tweak-vs-proxyman#i-need-to-test-error-states-and-edge-cases-in-the-browser" class="hash-link" aria-label="Direct link to &quot;I need to test error states and edge cases in the browser&quot;" title="Direct link to &quot;I need to test error states and edge cases in the browser&quot;" translate="no">​</a></h3>
<p><strong>Either works.</strong> Both tools can mock responses and override status codes. tweak is faster to set up; Proxyman offers more granular control if you need it.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="im-debugging-in-multiple-tools-browser-mobile-desktop-app-backend">"I'm debugging in multiple tools (browser, mobile, desktop app, backend)"<a href="https://tweak-extension.com/blog/tweak-vs-proxyman#im-debugging-in-multiple-tools-browser-mobile-desktop-app-backend" class="hash-link" aria-label="Direct link to &quot;I'm debugging in multiple tools (browser, mobile, desktop app, backend)&quot;" title="Direct link to &quot;I'm debugging in multiple tools (browser, mobile, desktop app, backend)&quot;" translate="no">​</a></h3>
<p><strong>Use Proxyman.</strong> Proxyman covers all of these. tweak is limited to browser contexts.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="i-want-something-lightweight-that-doesnt-slow-down-my-machine">"I want something lightweight that doesn't slow down my machine"<a href="https://tweak-extension.com/blog/tweak-vs-proxyman#i-want-something-lightweight-that-doesnt-slow-down-my-machine" class="hash-link" aria-label="Direct link to &quot;I want something lightweight that doesn't slow down my machine&quot;" title="Direct link to &quot;I want something lightweight that doesn't slow down my machine&quot;" translate="no">​</a></h3>
<p><strong>Use tweak.</strong> It's a browser extension with minimal overhead. Proxyman, as a system proxy, uses more resources and can impact performance if poorly configured.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="im-solo-working-in-the-browser-and-want-zero-friction">"I'm solo, working in the browser, and want zero friction"<a href="https://tweak-extension.com/blog/tweak-vs-proxyman#im-solo-working-in-the-browser-and-want-zero-friction" class="hash-link" aria-label="Direct link to &quot;I'm solo, working in the browser, and want zero friction&quot;" title="Direct link to &quot;I'm solo, working in the browser, and want zero friction&quot;" translate="no">​</a></h3>
<p><strong>Use tweak.</strong> Free tier, no account, no configuration. You're done in seconds.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="pricing-compared">Pricing compared<a href="https://tweak-extension.com/blog/tweak-vs-proxyman#pricing-compared" class="hash-link" aria-label="Direct link to Pricing compared" title="Direct link to Pricing compared" translate="no">​</a></h2>
<p><strong>tweak</strong> is free for up to 12 rules with no account required. Premium is $36/year (billed annually) or $4/month, with a 7-day free trial.</p>
<p><strong>Proxyman</strong> is free with some limitations (history and rule limits). Paid plans are around $99/year per person, with slightly higher pricing for teams.</p>
<p>For solo developers working primarily in the browser, tweak is significantly cheaper. For teams or developers who need system-wide proxy capabilities, Proxyman's pricing aligns with its broader feature set.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="when-to-use-each-tool">When to use each tool<a href="https://tweak-extension.com/blog/tweak-vs-proxyman#when-to-use-each-tool" class="hash-link" aria-label="Direct link to When to use each tool" title="Direct link to When to use each tool" translate="no">​</a></h2>
<p>Choose <strong>tweak</strong> if:</p>
<ul>
<li class="">You work primarily in the browser</li>
<li class="">You want to start mocking requests immediately with zero setup</li>
<li class="">You're a solo developer or small team</li>
<li class="">You value simplicity and lightweight tooling</li>
<li class="">You need cross-browser compatibility without fiddling with system proxies</li>
</ul>
<p>Choose <strong>Proxyman</strong> if:</p>
<ul>
<li class="">You need to debug mobile apps (iOS/Android)</li>
<li class="">You need to intercept traffic from any application on your machine</li>
<li class="">You need system-wide proxy capabilities</li>
<li class="">You're doing deep HTTP forensics or performance analysis</li>
<li class="">You're working in a team environment with diverse debugging needs</li>
</ul>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="the-bottom-line">The bottom line<a href="https://tweak-extension.com/blog/tweak-vs-proxyman#the-bottom-line" class="hash-link" aria-label="Direct link to The bottom line" title="Direct link to The bottom line" translate="no">​</a></h2>
<p><strong>tweak</strong> and <strong>Proxyman</strong> serve different use cases. tweak is optimised for speed and simplicity in the browser; Proxyman is a comprehensive proxy solution for anyone who needs visibility into system-wide network traffic.</p>
<p>If your work stays in the browser, tweak is the faster, simpler, cheaper choice. If you're debugging mobile apps, desktop applications, or need system-wide interception, Proxyman is worth the investment.</p>
<p>Most developers benefit from having both: tweak for quick browser-based debugging, and Proxyman for the occasions when you need deeper system-level visibility.</p>
<p><a class="" href="https://tweak-extension.com/docs/intro">Try tweak free</a>. No account required, 12 rules on the free plan.</p>
<br><hr><div class="buttons_rr6z"><h3>Was this page helpful?</h3><div class="thumbs_zuU5"><button class="button button--outline button--primary"><span class="fa fa-thumbs-up"></span>&nbsp;<!-- -->Yes</button><button class="button button--outline button--primary"><span class="fa fa-thumbs-down"></span>&nbsp;<!-- -->No</button></div></div><small>Need something else? <a href="https://tally.so/r/VLzbl6" target="_blank">Request a feature</a></small><div class="message_SA7R" style="visibility:hidden"><span class="fa fa-bolt"></span>&nbsp; <i>Thanks for your feedback!</i></div>
]]></content:encoded>
            <category>tweak</category>
            <category>Software Testing</category>
            <category>Productivity</category>
            <category>HTTP Debugging</category>
        </item>
        <item>
            <title><![CDATA[tweak vs Requestly: Which HTTP Mocking Tool Is Right for You?]]></title>
            <link>https://tweak-extension.com/blog/tweak-vs-requestly</link>
            <guid>https://tweak-extension.com/blog/tweak-vs-requestly</guid>
            <pubDate>Sun, 26 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Comparing tweak and Requestly for mocking HTTP requests in the browser. Side-by-side breakdown of features, pricing, and use cases to help you choose.]]></description>
            <content:encoded><![CDATA[<p>If you've been searching for a way to mock HTTP requests in your browser, you've likely come across both <strong>tweak</strong> and <strong>Requestly</strong>. Both tools let you intercept and modify network requests without touching your backend, but they approach the problem differently. This post breaks down what each tool does well and when you should reach for one over the other.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="quick-verdict">Quick verdict<a href="https://tweak-extension.com/blog/tweak-vs-requestly#quick-verdict" class="hash-link" aria-label="Direct link to Quick verdict" title="Direct link to Quick verdict" translate="no">​</a></h2>
<table><thead><tr><th></th><th>tweak</th><th>Requestly</th></tr></thead><tbody><tr><td>Setup time</td><td>~1 min, no account needed</td><td>Account required</td></tr><tr><td>Free tier</td><td>12 rules, no sign-up</td><td>Limited rules, sign-up required</td></tr><tr><td>Browser extension</td><td>Chrome, Edge, Firefox (limited)</td><td>Chrome, Firefox, Edge, Safari</td></tr><tr><td>Desktop app</td><td>No</td><td>Yes</td></tr><tr><td>Code required</td><td>No</td><td>No</td></tr><tr><td>Team sharing</td><td>No</td><td>Yes</td></tr><tr><td>Price</td><td>Free / $36/year</td><td>Free / from ~$9/month</td></tr></tbody></table>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="what-tweak-does-well">What tweak does well<a href="https://tweak-extension.com/blog/tweak-vs-requestly#what-tweak-does-well" class="hash-link" aria-label="Direct link to What tweak does well" title="Direct link to What tweak does well" translate="no">​</a></h2>
<p><strong>Zero friction to start.</strong> Install the extension, open the panel, create a rule. No account, no sign-up flow, no onboarding wizard. You're mocking requests within 60 seconds of installing.</p>
<p><strong>Simple, focused UI.</strong> tweak does one thing: intercept and modify HTTP requests. The interface reflects that. You see your rules, you toggle them on and off, you're done. There's no feature sprawl to navigate.</p>
<p><strong>Free tier that's actually useful.</strong> The free plan gives you 12 mock rules with no account required. For most solo development and debugging workflows, that's enough to get real work done.</p>
<p><strong>Browser-native, no proxy.</strong> tweak runs entirely in the browser. There's no proxy to configure, no certificate to install, no system-level setup. It works in your existing browser session with your existing cookies and headers intact.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="what-requestly-does-well">What Requestly does well<a href="https://tweak-extension.com/blog/tweak-vs-requestly#what-requestly-does-well" class="hash-link" aria-label="Direct link to What Requestly does well" title="Direct link to What Requestly does well" translate="no">​</a></h2>
<p><strong>Desktop app.</strong> Requestly has a standalone desktop application that can intercept system-wide traffic, not just browser requests. If you need to mock requests from a mobile app or a non-browser client, Requestly can handle that.</p>
<p><strong>Team collaboration.</strong> Requestly has built-in support for sharing rule sets across a team, which is valuable in larger engineering organisations where mock configurations need to be consistent across developers.</p>
<p><strong>More rule types.</strong> Requestly supports a wider range of rule types including script injection, response delays at the rule level, and more granular redirect logic. If your mocking requirements are complex, Requestly's breadth may be a better fit.</p>
<p><strong>Safari support.</strong> Requestly supports Safari in addition to Chrome, Firefox, and Edge. If you need to test on Safari specifically, that's a deciding factor.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="head-to-head-common-scenarios">Head-to-head: common scenarios<a href="https://tweak-extension.com/blog/tweak-vs-requestly#head-to-head-common-scenarios" class="hash-link" aria-label="Direct link to Head-to-head: common scenarios" title="Direct link to Head-to-head: common scenarios" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="i-need-to-mock-an-api-endpoint-quickly-during-development-or-quick-live-production-testing">"I need to mock an API endpoint quickly during development or quick live production testing"<a href="https://tweak-extension.com/blog/tweak-vs-requestly#i-need-to-mock-an-api-endpoint-quickly-during-development-or-quick-live-production-testing" class="hash-link" aria-label="Direct link to &quot;I need to mock an API endpoint quickly during development or quick live production testing&quot;" title="Direct link to &quot;I need to mock an API endpoint quickly during development or quick live production testing&quot;" translate="no">​</a></h3>
<p><strong>Use tweak.</strong> No account, no configuration overhead. Create a rule, set the response, move on.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="i-need-to-share-mock-rules-with-my-whole-frontend-team">"I need to share mock rules with my whole frontend team"<a href="https://tweak-extension.com/blog/tweak-vs-requestly#i-need-to-share-mock-rules-with-my-whole-frontend-team" class="hash-link" aria-label="Direct link to &quot;I need to share mock rules with my whole frontend team&quot;" title="Direct link to &quot;I need to share mock rules with my whole frontend team&quot;" translate="no">​</a></h3>
<p><strong>Use Requestly.</strong> Its team sharing features are built for this. tweak's sharing story is limited to <a class="" href="https://tweak-extension.com/docs/import-export">exporting/importing rule files manually</a>.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="i-need-to-mock-requests-from-a-react-native-app">"I need to mock requests from a React Native app"<a href="https://tweak-extension.com/blog/tweak-vs-requestly#i-need-to-mock-requests-from-a-react-native-app" class="hash-link" aria-label="Direct link to &quot;I need to mock requests from a React Native app&quot;" title="Direct link to &quot;I need to mock requests from a React Native app&quot;" translate="no">​</a></h3>
<p><strong>Use Requestly.</strong> tweak is a browser extension; it only works inside a browser. Requestly's desktop proxy can intercept traffic from any client.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="i-need-to-test-a-specific-error-state-or-edge-case-without-changing-the-backend">"I need to test a specific error state or edge case without changing the backend"<a href="https://tweak-extension.com/blog/tweak-vs-requestly#i-need-to-test-a-specific-error-state-or-edge-case-without-changing-the-backend" class="hash-link" aria-label="Direct link to &quot;I need to test a specific error state or edge case without changing the backend&quot;" title="Direct link to &quot;I need to test a specific error state or edge case without changing the backend&quot;" translate="no">​</a></h3>
<p><strong>Either works.</strong> Both tools handle response mocking, status code overrides, and header modification. tweak's UI is faster to reach for a one-off test; Requestly is better if the rule will live long-term in a shared workspace.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="im-a-solo-developer-and-just-want-something-that-works">"I'm a solo developer and just want something that works"<a href="https://tweak-extension.com/blog/tweak-vs-requestly#im-a-solo-developer-and-just-want-something-that-works" class="hash-link" aria-label="Direct link to &quot;I'm a solo developer and just want something that works&quot;" title="Direct link to &quot;I'm a solo developer and just want something that works&quot;" translate="no">​</a></h3>
<p><strong>Use tweak.</strong> The free tier, the zero-sign-up experience, and the focused interface make it the lower-friction choice for individual developers.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="pricing-compared">Pricing compared<a href="https://tweak-extension.com/blog/tweak-vs-requestly#pricing-compared" class="hash-link" aria-label="Direct link to Pricing compared" title="Direct link to Pricing compared" translate="no">​</a></h2>
<p><strong>tweak</strong> is free for up to 12 rules with no account. Premium is $36/year (billed annually) or $4/month, with a 7-day free trial.</p>
<p><strong>Requestly</strong> has a free tier that requires account creation. Paid plans start at around $9/month per user, with team plans priced higher.</p>
<p>For solo developers, tweak's annual plan is meaningfully cheaper. For teams already paying for Requestly's collaboration features, the cost calculus changes.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="the-bottom-line">The bottom line<a href="https://tweak-extension.com/blog/tweak-vs-requestly#the-bottom-line" class="hash-link" aria-label="Direct link to The bottom line" title="Direct link to The bottom line" translate="no">​</a></h2>
<p>Choose <strong>tweak</strong> if:</p>
<ul>
<li class="">You want to start mocking immediately with no account</li>
<li class="">You're a solo developer or work mostly independently</li>
<li class="">You value a clean, minimal interface</li>
<li class="">Browser-only interception covers your use case</li>
</ul>
<p>Choose <strong>Requestly</strong> if:</p>
<ul>
<li class="">You need to share rules across a team</li>
<li class="">You need to intercept non-browser traffic (desktop app, mobile)</li>
<li class="">You need Safari support</li>
<li class="">You require more advanced rule types</li>
</ul>
<p>Neither tool is strictly better. They serve different points on the complexity spectrum. tweak optimises for speed and simplicity; Requestly optimises for breadth and team use.</p>
<p><a class="" href="https://tweak-extension.com/docs/intro">Try tweak free</a>. No account required, 12 rules on the free plan.</p>
<br><hr><div class="buttons_rr6z"><h3>Was this page helpful?</h3><div class="thumbs_zuU5"><button class="button button--outline button--primary"><span class="fa fa-thumbs-up"></span>&nbsp;<!-- -->Yes</button><button class="button button--outline button--primary"><span class="fa fa-thumbs-down"></span>&nbsp;<!-- -->No</button></div></div><small>Need something else? <a href="https://tally.so/r/VLzbl6" target="_blank">Request a feature</a></small><div class="message_SA7R" style="visibility:hidden"><span class="fa fa-bolt"></span>&nbsp; <i>Thanks for your feedback!</i></div>
]]></content:encoded>
            <category>tweak</category>
            <category>Software Testing</category>
            <category>Productivity</category>
        </item>
        <item>
            <title><![CDATA[We're not obsoleted by AI yet. Two more years? Maybe?]]></title>
            <link>https://tweak-extension.com/blog/2025-wrapped</link>
            <guid>https://tweak-extension.com/blog/2025-wrapped</guid>
            <pubDate>Sat, 24 Jan 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[tweak in 2025: another year building developer tools in a world being reshaped by AI. Reflections, numbers, and what's next.]]></description>
            <content:encoded><![CDATA[
<p>Another year, another existential question: will AI tools/agents or AI browsers replace browser extensions? Spoiler alert: not yet. But let's talk about what actually happened in 2025.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="the-numbers-that-matter">The numbers that matter<a href="https://tweak-extension.com/blog/2025-wrapped#the-numbers-that-matter" class="hash-link" aria-label="Direct link to The numbers that matter" title="Direct link to The numbers that matter" translate="no">​</a></h2>
<p><strong>54 million requests intercepted</strong> across 83,971 users. That's a lot of HTTP traffic being tweaked, modified, and debugged by actual humans doing actual work.</p>
<p>Most users keep it simple: 6 rules or less. But there's a fascinating tail of a few hundred power users configuring 100+ rules. We have no idea who they are, because that's how anonymous tracking is supposed to work 😊. What are they building? Enterprise test environments? Elaborate API mocking setups? We don't know, but we're impressed.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="what-weve-learned">What we've learned<a href="https://tweak-extension.com/blog/2025-wrapped#what-weve-learned" class="hash-link" aria-label="Direct link to What we've learned" title="Direct link to What we've learned" translate="no">​</a></h2>
<p><strong>Feature complexity doesn't drive conversion.</strong> We built sophisticated functionality: breakpoints, logpoints, mock generation and auto-enabled sites. Usage is negligible. Meanwhile, simple request modification continues to dominate.</p>
<p><strong>The 6-rule threshold is real.</strong> There's a massive drop-off after 6 rules. This suggests most use cases are relatively simple: override an API endpoint, inject test data, modify some headers. Done.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="the-ai-question">The AI question<a href="https://tweak-extension.com/blog/2025-wrapped#the-ai-question" class="hash-link" aria-label="Direct link to The AI question" title="Direct link to The AI question" translate="no">​</a></h2>
<p>Will AI agents replace tweak in two years? Probably not entirely. Here's why:</p>
<p>AI is great at generating code, answering questions, even writing API mocks. But <strong>intercepting and modifying live HTTP traffic requires precision, not probability.</strong> You need to know exactly which request to catch, exactly what to change, and exactly when it fires. In addition to that, you probably won't want an AI agent poking around your live API traffic without strict controls.</p>
<p>That said, AI could make our UI obsolete. "Intercept all requests to /api/users and add an Authorization header": that's a perfect AI prompt. The question isn't whether AI replaces HTTP interception, but whether it replaces our configuration interface (this is not just true for tweak of course).</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="whats-next">What's next<a href="https://tweak-extension.com/blog/2025-wrapped#whats-next" class="hash-link" aria-label="Direct link to What's next" title="Direct link to What's next" translate="no">​</a></h2>
<p>We're not pivoting to AI (everyone else already is). We're going back to basics:</p>
<ol>
<li class=""><strong>Double down on the core:</strong> Request modification works. Make it bulletproof, address edge cases and customer pain points.</li>
<li class=""><strong>Explore GraphQL tooling:</strong> The signal is weak but consistent. GraphQL has made it, it has become a boring technology. Maybe there's something there.</li>
<li class=""><strong>Rethink paid features:</strong> Complex features don't convert. What would?</li>
</ol>
<p>54 million requests intercepted. 83,971 users trusting us with their HTTP traffic. Not obsolete yet.</p>
<p>See you in 2026, if we're still here.</p>
<hr>
<p><strong>Want to help us not get obsoleted?</strong> <a href="https://tweak-extension.com/" target="_blank" rel="noopener noreferrer" class="">Try tweak</a> and tell us what actually matters to you. We're clearly bad at guessing.</p>
<p sx="[object Object]">If you liked this article, consider sharing (<a href="https://twitter.com/share?text=We%27re%20not%20obsoleted%20by%20AI%20yet.%20Two%20more%20years?%20Maybe?&amp;url=https://tweak-extension.com/blog/2025-wrapped" target="_blank" rel="noreferrer" title="tweeting"><span style="text-decoration:underline">tweeting</span></a>) it to your followers.</p>
<br><hr><div class="buttons_rr6z"><h3>Did you like this article?</h3><div class="thumbs_zuU5"><button class="button button--outline button--primary"><span class="fa fa-thumbs-up"></span>&nbsp;<!-- -->Yes</button><button class="button button--outline button--primary"><span class="fa fa-thumbs-down"></span>&nbsp;<!-- -->No</button></div></div><small>Need something else? <a href="https://tally.so/r/VLzbl6" target="_blank">Request a feature</a></small><div class="message_SA7R" style="visibility:hidden"><span class="fa fa-bolt"></span>&nbsp; <i>Thanks for your feedback!</i></div>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to pin extensions on Chrome for easy access]]></title>
            <link>https://tweak-extension.com/blog/pin-extension-chrome</link>
            <guid>https://tweak-extension.com/blog/pin-extension-chrome</guid>
            <pubDate>Sun, 26 Jan 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[How to pin browser extensions to the Chrome toolbar for faster access. A quick tip for developers who use extensions like tweak every day.]]></description>
            <content:encoded><![CDATA[
<!-- -->
<p>It's possible to pin a Chrome extension in the Chrome browser simply following the steps:</p>
<ol>
<li class="">Open the Chrome browser.</li>
<li class="">Click on the "puzzle piece" icon in the top right corner of the browser.</li>
<li class="">Locate the extension you want to pin.</li>
<li class="">Click on the "pin" icon next to the extension you want to pin.</li>
</ol>
<p>Below an imagine and a short clip to illustrate the steps.</p>
<p>Here's a short clip, demonstrating it pinning the tweak chrome extension in this case.</p>
<div class="wrapper_XaN7" style="--tracked-video-aspect-ratio:16 / 9"><div style="width:100%;height:100%"></div></div>
<p>And here are the key UI key points to pin an extension.</p>
<p><img decoding="async" loading="lazy" alt="Pin Extension" src="https://tweak-extension.com/assets/images/pin-extension-image-chrome-60159ae5ec65703699f404d0a9799c0b.png" width="1534" height="1206" class="img_F_NH"></p>
<p sx="[object Object]">If you liked this article, consider sharing (<a href="https://twitter.com/share?text=How%20to%20pin%20extensions%20on%20Chrome%20for%20easy%20access&amp;url=https://tweak-extension.com/blog/ping-extension-chrome" target="_blank" rel="noreferrer" title="tweeting"><span style="text-decoration:underline">tweeting</span></a>) it to your followers.</p>
<br><hr><div class="buttons_rr6z"><h3>Did you like this article?</h3><div class="thumbs_zuU5"><button class="button button--outline button--primary"><span class="fa fa-thumbs-up"></span>&nbsp;<!-- -->Yes</button><button class="button button--outline button--primary"><span class="fa fa-thumbs-down"></span>&nbsp;<!-- -->No</button></div></div><small>Need something else? <a href="https://tally.so/r/VLzbl6" target="_blank">Request a feature</a></small><div class="message_SA7R" style="visibility:hidden"><span class="fa fa-bolt"></span>&nbsp; <i>Thanks for your feedback!</i></div>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[tweak wrapped 2024: A Year of Growth]]></title>
            <link>https://tweak-extension.com/blog/2024-wrapped</link>
            <guid>https://tweak-extension.com/blog/2024-wrapped</guid>
            <pubDate>Sat, 04 Jan 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[tweak in 2024: a look back at growth, new features, and what the year meant for the developer tools extension.]]></description>
            <content:encoded><![CDATA[
<p>Closing on 2024, we’re thrilled to share the milestones and achievements that made this year unforgettable for Tweak Extension. With <strong>+65% more active users and more than 48M requests intercepted! Here’s a look at some 2024 numbers</strong>:</p>
<ul>
<li class=""><strong>Breaking Barriers</strong>: For the first time, we smashed the <strong>50k weekly active users</strong> mark, growing from 30k to 50k, a massive <strong>+65% increase</strong>!</li>
<li class=""><strong>Browsers in Action</strong>: Tweak users span across Chrome, Firefox, and Edge. Unsurprisingly, <strong>Chrome leads the pack</strong> with <strong>94%</strong> of users choosing it for Tweak.</li>
<li class=""><strong>Power Users</strong>:<!-- -->
<ul>
<li class=""><strong>4.6k users</strong> intercepted 1k+ requests, <strong>4x more than in 2023</strong>!</li>
<li class="">Over <strong>500 users</strong> intercepted 10k+ requests, <strong>6x more than last year</strong>.</li>
<li class=""><strong>20+ users</strong> hit the incredible milestone of 100k+ intercepted requests, growing by <strong>+40% YoY</strong>.</li>
</ul>
</li>
<li class=""><strong>Rule Creators Unite</strong>:<!-- -->
<ul>
<li class="">Our users crafted a whopping <strong>248,406 tweak rules</strong> this year.</li>
<li class="">Over <strong>400 users</strong> created 100+ rules, showing just how engaged and creative our community is.</li>
</ul>
</li>
<li class=""><strong>Intercepting at Scale</strong>: Together, you intercepted <strong>48.6M requests</strong> this year, <strong>+38% YoY</strong>, breaking that down to <strong>133k requests every single day</strong>!</li>
</ul>
<p>None of this would be possible without you. As we head into 2025, we’re excited to continue growing, innovating, and helping you maximize your development and testing productivity.</p>
<p>Here’s to another year of tweaking the web, together! 🎉</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[HAR Files: A Developer's Insight]]></title>
            <link>https://tweak-extension.com/blog/har-file-developer-insight</link>
            <guid>https://tweak-extension.com/blog/har-file-developer-insight</guid>
            <pubDate>Wed, 27 Dec 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[What is a HAR file and how do you use it? A developer's guide to recording, reading, and analysing HTTP Archive files for debugging and performance.]]></description>
            <content:encoded><![CDATA[<p>HTTP Archive, commonly known as HAR, is a file format used by developers to capture and store network communication data between a web browser and a website. This valuable tool provides a detailed record of the interactions between a user's browser and the various web elements that compose a site. But why do developers find HAR files indispensable, and what information do these files encapsulate?</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="purpose">Purpose<a href="https://tweak-extension.com/blog/har-file-developer-insight#purpose" class="hash-link" aria-label="Direct link to Purpose" title="Direct link to Purpose" translate="no">​</a></h2>
<p>Developers leverage HAR files primarily for performance analysis and debugging. When a user reports slow page load times or unexpected behavior on a website, developers can use HAR files to trace the issue back to its source. The file captures a comprehensive log of all network requests and responses, including details such as URLs, headers, and timings. This enables developers to pinpoint bottlenecks, identify inefficient resource loading, and optimize the overall performance of a web page.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="advantages-why-use-them">Advantages (why use them?)<a href="https://tweak-extension.com/blog/har-file-developer-insight#advantages-why-use-them" class="hash-link" aria-label="Direct link to Advantages (why use them?)" title="Direct link to Advantages (why use them?)" translate="no">​</a></h2>
<p>The adoption of HAR files is widespread due to several key advantages. Firstly, HAR files offer a standardized, platform-independent format. This means developers can share and analyze these files across different tools and environments, streamlining collaboration and issue resolution. Secondly, HAR files provide a granular level of detail. Developers can scrutinize each HTTP request, enabling them to detect issues like slow server responses, unnecessary redirects, or large resource files that contribute to sluggish page loads.</p>
<p>Moreover, HAR files are not limited to capturing just the technical aspects of web interactions. They also include timing information, allowing developers to understand the chronological sequence of network events. This is crucial for diagnosing problems related to rendering delays or asynchronous resource loading.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="inside-har-files">Inside HAR Files<a href="https://tweak-extension.com/blog/har-file-developer-insight#inside-har-files" class="hash-link" aria-label="Direct link to Inside HAR Files" title="Direct link to Inside HAR Files" translate="no">​</a></h2>
<p>A typical HAR file includes a variety of information, organized into key sections. The <code>"log"</code> section encapsulates the overall structure of the file, containing details about the creator, browser, and the start and end times of the recording. The <code>"entries"</code> section is the heart of the HAR file, documenting each individual HTTP request and its corresponding response. For every entry, developers can inspect headers, timings, and content, gaining insights into the performance characteristics of each resource fetched.</p>
<p>Additionally, the <code>"pages"</code> section provides a high-level overview of the loaded pages, and the <code>"browser"</code> section offers information about the browser's version and capabilities during the recording. Altogether, the information within a HAR file forms a comprehensive record of a user's interaction with a website, empowering developers to analyze and optimize every aspect of web performance.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="conclusion">Conclusion<a href="https://tweak-extension.com/blog/har-file-developer-insight#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h2>
<p>In conclusion, HAR files serve as invaluable tools for developers seeking to enhance the performance and user experience of web applications. They offer a standardized, detailed record of network interactions, enabling efficient collaboration and issue resolution. From identifying bottlenecks to optimizing resource loading, HAR files provide a comprehensive view of a website's behavior. They are widely adopted mainly due to their effectiveness in streamlining the development and debugging processes, making them an indispensable asset in the toolkit of web developers.</p>
<p>With <a class="" href="https://tweak-extension.com/docs/import-export#importing-har-files">tweak you can easily import HAR files</a> and convert them into tweak rules which allow you to quickly simulate the network conditions captured in the HAR file. This is particularly useful for testing and debugging purposes, as you can replicate specific scenarios and analyze how your web application behaves.</p>
<!-- -->
<p sx="[object Object]">If you liked this article, consider sharing (<a href="https://twitter.com/share?text=HAR%20Files:%20A%20Developer%20Insight&amp;url=https://tweak-extension.com/blog/har-file-developer-insight" target="_blank" rel="noreferrer" title="tweeting"><span style="text-decoration:underline">tweeting</span></a>) it to your followers.</p>
<br><hr><div class="buttons_rr6z"><h3>Did you like this article?</h3><div class="thumbs_zuU5"><button class="button button--outline button--primary"><span class="fa fa-thumbs-up"></span>&nbsp;<!-- -->Yes</button><button class="button button--outline button--primary"><span class="fa fa-thumbs-down"></span>&nbsp;<!-- -->No</button></div></div><small>Need something else? <a href="https://tally.so/r/VLzbl6" target="_blank">Request a feature</a></small><div class="message_SA7R" style="visibility:hidden"><span class="fa fa-bolt"></span>&nbsp; <i>Thanks for your feedback!</i></div>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Override Query Parameters with tweak]]></title>
            <link>https://tweak-extension.com/blog/modify-url-query-params</link>
            <guid>https://tweak-extension.com/blog/modify-url-query-params</guid>
            <pubDate>Thu, 28 Sep 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Learn how to override and modify URL query parameters in your browser using the tweak extension, without touching your application code.]]></description>
            <content:encoded><![CDATA[<p>It's really hard to express the power of tweak just through our documentation. Some use cases fall through the cracks. We got some recent feedback on users searching for a way to modify URL query parameters and not being able to find it in tweak. <strong>This short "how to" article explains how you can manipulate the URL and its query parameters with tweak in just 3 simple steps</strong>.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="1-create-the-rule-with-an-appropriate-url-expression">1. Create the rule with an appropriate URL expression<a href="https://tweak-extension.com/blog/modify-url-query-params#1-create-the-rule-with-an-appropriate-url-expression" class="hash-link" aria-label="Direct link to 1. Create the rule with an appropriate URL expression" title="Direct link to 1. Create the rule with an appropriate URL expression" translate="no">​</a></h2>
<p>Through the use of regular expressions (toggling the <code>.*</code> button) or through a <em>catch-all</em> partial URL rule you are able to target your desired URL without specificying all the nitty gritty details of the URL such as the query parameters or entity identifiers. Here's an example where we'll grab all the <code>GET</code> requests for "Game of Thrones" characters without specifying their identifier in the URL.</p>
<p><img decoding="async" loading="lazy" alt="tweak rule with broad URL expression" src="https://tweak-extension.com/assets/images/override-query-1-00e2a64c7e06f893f5aee0b9b899ef55.png" title="tweak rule with broad URL expression" width="2154" height="1130" class="img_F_NH"></p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="2-use-a-modify-rule-with-a-request-hook">2. Use a modify rule with a request hook<a href="https://tweak-extension.com/blog/modify-url-query-params#2-use-a-modify-rule-with-a-request-hook" class="hash-link" aria-label="Direct link to 2. Use a modify rule with a request hook" title="Direct link to 2. Use a modify rule with a request hook" translate="no">​</a></h2>
<p>Toggle the rule to <a class="" href="https://tweak-extension.com/docs/rule/mock-vs-modify#modify-rule">Modify</a>. Modify rules will allow you to manipulate the URL using JavaScript as we'll see next. Click the <code>Request hook</code> editor tab and write the code to manipulate the URL.</p>
<p><img decoding="async" loading="lazy" alt="writing a script to modify the query parameters" src="https://tweak-extension.com/assets/images/override-query-2-8b391b4f6dee4f1a46db2c50a3ccada7.png" title="writing a script to modify the query parameters" width="2214" height="1164" class="img_F_NH"></p>
<details class="details_D5C4 alert alert--info details_Pm84" data-collapsed="true"><summary>Expand to get the full JS code used in the example.</summary><div><div class="collapsibleContent_n8KP"><div class="language-js codeBlockContainer_FOcj theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_guI0"><pre tabindex="0" class="prism-code language-js codeBlock_PD6s thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_EpoG"><div class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// Grab string after ?.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> urlParams </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">new</span><span class="token plain"> </span><span class="token class-name">URLSearchParams</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">url</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">split</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'?'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token number">1</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// If "continent" param is preset override its value.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">urlParams</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">has</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'continent'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  urlParams</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">set</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'continent'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'weOverrideContinentWithThisValue'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> finalUrl </span><span class="token operator">=</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation">url</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation method function property-access" style="color:rgb(80, 250, 123)">split</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token template-string interpolation string" style="color:rgb(255, 121, 198)">'?'</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token template-string interpolation number">0</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string string" style="color:rgb(255, 121, 198)">?</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation">urlParams</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation method function property-access" style="color:rgb(80, 250, 123)">toString</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  method</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token comment" style="color:rgb(98, 114, 164)">// Don't forget to return the modified URL here.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token literal-property property">url</span><span class="token operator">:</span><span class="token plain"> finalUrl</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  body</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  headers</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><br></div></code></pre></div></div></div></div></details>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="3-trigger-the-request-again-with-the-rule-active">3. Trigger the request again with the rule active<a href="https://tweak-extension.com/blog/modify-url-query-params#3-trigger-the-request-again-with-the-rule-active" class="hash-link" aria-label="Direct link to 3. Trigger the request again with the rule active" title="Direct link to 3. Trigger the request again with the rule active" translate="no">​</a></h2>
<p>As show in the above screenshot triggering the request again after activating your modify rule actives overrides the query parameter with your desired value. That's all ✅.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="what-else-can-you-do">What else can you do?<a href="https://tweak-extension.com/blog/modify-url-query-params#what-else-can-you-do" class="hash-link" aria-label="Direct link to What else can you do?" title="Direct link to What else can you do?" translate="no">​</a></h2>
<p>There's really no limit, here's some ideas:</p>
<ul>
<li class="">Modify the URL entirely, e.g. forward the request to some other server or endpoint.</li>
<li class="">Generate random query parameters using JavaScript to fullfill a myriad of testing use cases.</li>
<li class="">Use <code>console.table</code>s to print a structured view of the URL query parameters.</li>
<li class="">Write your own generic script that can modify any URL query parameters given an object with key value pairs (query param, query param value) 🚀</li>
</ul>
<p>And so much more. It's really up to you how you leverage the power of request hooks. If you're finding this pattern useful there's a very high change that you'll find <a class="" href="https://tweak-extension.com/docs/rule/javascript-snippet">response hooks just as useful</a>.</p>
<br>
<br>
<!-- -->
<p sx="[object Object]">If you liked this article, consider sharing (<a href="https://twitter.com/share?text=Override%20query%20parameters%20with%20tweak&amp;url=https://tweak-extension.com/blog/modify-url-query-params" target="_blank" rel="noreferrer" title="tweeting"><span style="text-decoration:underline">tweeting</span></a>) it to your followers.</p>
<br><hr><div class="buttons_rr6z"><h3>Did you like this article?</h3><div class="thumbs_zuU5"><button class="button button--outline button--primary"><span class="fa fa-thumbs-up"></span>&nbsp;<!-- -->Yes</button><button class="button button--outline button--primary"><span class="fa fa-thumbs-down"></span>&nbsp;<!-- -->No</button></div></div><small>Need something else? <a href="https://tally.so/r/VLzbl6" target="_blank">Request a feature</a></small><div class="message_SA7R" style="visibility:hidden"><span class="fa fa-bolt"></span>&nbsp; <i>Thanks for your feedback!</i></div>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Celebrating tweak on Microsoft Edge 🎉]]></title>
            <link>https://tweak-extension.com/blog/tweak-available-microsoft-edge</link>
            <guid>https://tweak-extension.com/blog/tweak-available-microsoft-edge</guid>
            <pubDate>Tue, 06 Jun 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[tweak is now available on Microsoft Edge. Install the HTTP request mocking extension directly from the Edge Add-ons store.]]></description>
            <content:encoded><![CDATA[<p>We are thrilled to announce the exciting launch of <a href="https://microsoftedge.microsoft.com/addons/detail/tweak-mock-and-modify-ht/igmkallacokolpajpaboinafcebkfafl" target="_blank" rel="noopener noreferrer" class="">tweak in the Microsoft Edge Browser</a>! With this powerful tool at your fingertips, you can define rules, capture HTTP requests, and receive customized mocked responses directly within your browser. Say goodbye to cumbersome server setups and welcome a more efficient and streamlined development process.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="unleashing-the-power-of-mocking-in-microsoft-edge">Unleashing the Power of Mocking in Microsoft Edge<a href="https://tweak-extension.com/blog/tweak-available-microsoft-edge#unleashing-the-power-of-mocking-in-microsoft-edge" class="hash-link" aria-label="Direct link to Unleashing the Power of Mocking in Microsoft Edge" title="Direct link to Unleashing the Power of Mocking in Microsoft Edge" translate="no">​</a></h2>
<p>Our customizable API mock server extension, aptly named "tweak," brings unparalleled convenience to developers working in the Microsoft Edge Browser. By seamlessly integrating into your browser environment, tweak eliminates the need for external tools or complex server setups, allowing you to mock HTTP requests directly within your development workflow.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="overwhelming-amount-of-requests">Overwhelming amount of requests<a href="https://tweak-extension.com/blog/tweak-available-microsoft-edge#overwhelming-amount-of-requests" class="hash-link" aria-label="Direct link to Overwhelming amount of requests" title="Direct link to Overwhelming amount of requests" translate="no">​</a></h2>
<p>We were not expecting to receive so many requests to have the extension available in the Microsoft Edge store, but it seems to match the recent increase in adoption of the Microsoft browser.</p>
<br>
<br>
<!-- -->
<!-- -->
<p sx="[object Object]">If you liked this article, consider sharing (<a href="https://twitter.com/share?text=Celebrating%20tweak%20on%20Microsoft%20Edge&amp;url=https://tweak-extension.com/blog/tweak-available-microsoft-edge" target="_blank" rel="noreferrer" title="tweeting"><span style="text-decoration:underline">tweeting</span></a>) it to your followers.</p>
<br><hr><div class="buttons_rr6z"><h3>Did you like this article?</h3><div class="thumbs_zuU5"><button class="button button--outline button--primary"><span class="fa fa-thumbs-up"></span>&nbsp;<!-- -->Yes</button><button class="button button--outline button--primary"><span class="fa fa-thumbs-down"></span>&nbsp;<!-- -->No</button></div></div><small>Need something else? <a href="https://tally.so/r/VLzbl6" target="_blank">Request a feature</a></small><div class="message_SA7R" style="visibility:hidden"><span class="fa fa-bolt"></span>&nbsp; <i>Thanks for your feedback!</i></div>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Demystifying HTTP Status Codes: A Fun Guide]]></title>
            <link>https://tweak-extension.com/blog/fun-guide-http-status-code</link>
            <guid>https://tweak-extension.com/blog/fun-guide-http-status-code</guid>
            <pubDate>Tue, 23 May 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[A fun, accessible guide to HTTP status codes. Understand what 200, 301, 404, 500 and the rest actually mean and when each one appears.]]></description>
            <content:encoded><![CDATA[<p>HTTP status codes may seem like a bunch of cryptic numbers, but they hold the key to unlocking the mysteries of the web. Whether you're a developer, a curious user, or just someone who stumbled upon this article, get ready to embark on an adventure to uncover the hidden meanings behind those three-digit codes.</p>
<p><strong>From playful successes to mysterious redirects, and from sassy client errors to menacing server mishaps, let's dive into the fun and fascinating world of HTTP status codes!</strong></p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="cracking-the-code-different-groups-different-semantics">Cracking the Code: Different Groups, Different Semantics<a href="https://tweak-extension.com/blog/fun-guide-http-status-code#cracking-the-code-different-groups-different-semantics" class="hash-link" aria-label="Direct link to Cracking the Code: Different Groups, Different Semantics" title="Direct link to Cracking the Code: Different Groups, Different Semantics" translate="no">​</a></h2>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status" target="_blank" rel="noopener noreferrer" class="">HTTP status codes</a> are divided into groups based on their first digit. Each group carries its own set of semantics, giving us clues about what's happening behind the scenes. Let's take a look at the four main groups. Let's dive in.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="2xx-success-you-rock">2xx Success: "You Rock!"<a href="https://tweak-extension.com/blog/fun-guide-http-status-code#2xx-success-you-rock" class="hash-link" aria-label="Direct link to 2xx Success: &quot;You Rock!&quot;" title="Direct link to 2xx Success: &quot;You Rock!&quot;" translate="no">​</a></h3>
<p>These status codes (aka the success codes) indicate that your request was successful, and everything is fine. It's the web's way of giving you a high-five for a job well done. Here are a few of the coolest members of this group:</p>
<table><thead><tr><th>Status</th><th>Code</th><th>Semantics</th></tr></thead><tbody><tr><td>200</td><td>OK</td><td>The request succeeded.</td></tr><tr><td>201</td><td>Created</td><td>New resrouce was created.</td></tr><tr><td>204</td><td>No content</td><td>The request was successful, but no resposne body needed (e.g. "save and continue editing" kind of feature).</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="3xx-redirection-follow-the-rabbit-hole">3xx Redirection: "Follow the Rabbit Hole"<a href="https://tweak-extension.com/blog/fun-guide-http-status-code#3xx-redirection-follow-the-rabbit-hole" class="hash-link" aria-label="Direct link to 3xx Redirection: &quot;Follow the Rabbit Hole&quot;" title="Direct link to 3xx Redirection: &quot;Follow the Rabbit Hole&quot;" translate="no">​</a></h3>
<p>When you encounter these codes, the web is guiding you through the labyrinth. It's like following a trail of breadcrumbs, hoping to find what you're looking for. Here are a few notable codes from the redirection group:</p>
<table><thead><tr><th>Status</th><th>Code</th><th>Semantics</th></tr></thead><tbody><tr><td>301</td><td>Moved Permanently</td><td>Resource has a new permanent location.</td></tr><tr><td>302</td><td>Found</td><td>Resource has a temporary location.</td></tr><tr><td>307</td><td>Temporary Redirect</td><td>Follow me, but keep your original request method.</td></tr></tbody></table>
<div class="theme-admonition theme-admonition-tip admonition_mDP4 alert alert--success"><div class="admonitionHeading_Mfam"><span class="admonitionIcon_ba76"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_LzEm"><p>The only difference between 307 and 302 is that 307 guarantees that the method and the body will not be changed when the redirected request is made (<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/307" target="_blank" rel="noopener noreferrer" class="">source</a>).</p></div></div>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="4xx-client-errors-whoopsie-daisy-its-your-fault">4xx Client Errors: "Whoopsie-daisy! It's Your Fault"<a href="https://tweak-extension.com/blog/fun-guide-http-status-code#4xx-client-errors-whoopsie-daisy-its-your-fault" class="hash-link" aria-label="Direct link to 4xx Client Errors: &quot;Whoopsie-daisy! It's Your Fault&quot;" title="Direct link to 4xx Client Errors: &quot;Whoopsie-daisy! It's Your Fault&quot;" translate="no">​</a></h3>
<p>These error codes occur when the client sends a malformed request. What does it mean "malformed" anyways? A simple exmaple is when sending invalid parameters in the URL, e.g. the API expects a number but you send text. The web can get a little sassy here, playfully nudging you to correct your mistakes. Beware of these amusingly troublesome codes:</p>
<table><thead><tr><th>Status</th><th>Code</th><th>Semantics</th></tr></thead><tbody><tr><td>400</td><td>Bad Request</td><td>Uh-oh, something's wrong with your request.</td></tr><tr><td>404</td><td>Not Found</td><td>The resource you're seeking is as elusive as Bigfoot.</td></tr><tr><td>418</td><td>I'm a teapot</td><td>Seriously, why are you trying to make me pour coffee?</td></tr></tbody></table>
<div class="theme-admonition theme-admonition-info admonition_mDP4 alert alert--info"><div class="admonitionHeading_Mfam"><span class="admonitionIcon_ba76"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_LzEm"><p>The teapot thing it's not a joke, it's actually stated HTTP spec <a href="https://www.rfc-editor.org/rfc/rfc2324#section-2.3.2" target="_blank" rel="noopener noreferrer" class="">rfc2324#section-2.3.2</a></p><blockquote>
<p>2.3.2 418 I'm a teapot</p>
<p>Any attempt to brew coffee with a teapot should result in the error
code "418 I'm a teapot". The resulting entity body MAY be short and
stout.</p>
</blockquote></div></div>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="5xx-server-errors-houston-we-have-a-problem">5xx Server Errors: "Houston, We Have a Problem"<a href="https://tweak-extension.com/blog/fun-guide-http-status-code#5xx-server-errors-houston-we-have-a-problem" class="hash-link" aria-label="Direct link to 5xx Server Errors: &quot;Houston, We Have a Problem&quot;" title="Direct link to 5xx Server Errors: &quot;Houston, We Have a Problem&quot;" translate="no">​</a></h3>
<p>When the server experiences internal difficulties, it politely informs you with these error codes. It's like the web's way of saying, "Oops, my bad. Something went wrong on my end.". Here are a few dramatic codes from the server error group:</p>
<table><thead><tr><th>Status</th><th>Code</th><th>Semantics</th></tr></thead><tbody><tr><td>500</td><td>Internal Server Error</td><td>Oops, something unexpected happened.</td></tr><tr><td>502</td><td>Bad Gateway</td><td>The server is playing middleman and got an invalid response.</td></tr><tr><td>503</td><td>Service Unavailable</td><td>The server needs a break; try again later.</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="the-pitfalls-of-misinterpreting-semantics">The Pitfalls of Misinterpreting Semantics<a href="https://tweak-extension.com/blog/fun-guide-http-status-code#the-pitfalls-of-misinterpreting-semantics" class="hash-link" aria-label="Direct link to The Pitfalls of Misinterpreting Semantics" title="Direct link to The Pitfalls of Misinterpreting Semantics" translate="no">​</a></h2>
<p>Misunderstanding or misusing HTTP status codes can lead to some hilarious yet frustrating situations. Here are a couple of common pitfalls to avoid:</p>
<ul>
<li class=""><strong>Expecting the Unexpected</strong>: Assume you're expecting a 200 "OK" response, but you receive a 404 "Not Found" instead. You might find yourself scratching your head, wondering if the internet has gone haywire. Double-check your URLs and ensure you're sending the right requests.</li>
<li class=""><strong>Chasing Redirections</strong>: You're following a series of 302 "Found" redirects, feeling like Alice in Wonderland, only to discover that the resource you're looking for has moved permanently.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="client-side-gotchas-watch-out">Client-Side Gotchas: Watch Out!<a href="https://tweak-extension.com/blog/fun-guide-http-status-code#client-side-gotchas-watch-out" class="hash-link" aria-label="Direct link to Client-Side Gotchas: Watch Out!" title="Direct link to Client-Side Gotchas: Watch Out!" translate="no">​</a></h3>
<p>When working with HTTP status codes, client-side surprises can sometimes catch you off guard. Here are a couple of quirky situations to keep an eye out for:</p>
<ul>
<li class=""><strong>Caching Conundrums</strong>: The browser caches responses, which can lead to confusion. You make a request, but instead of fetching fresh data, the browser serves up a stale 304 "Not Modified" response. Clear your cache or use <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching#cache_busting" target="_blank" rel="noopener noreferrer" class="">cache-busting</a> techniques to ensure you're getting the latest and greatest.</li>
<li class=""><strong>Permission Predicaments</strong>: You're trying to access a resource, but you receive a 403 "Forbidden" response, leaving you feeling like an unwelcome guest. Double-check your credentials, permissions, or any necessary authentication tokens to access the desired resource.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="note-about-real-life">Note about real life<a href="https://tweak-extension.com/blog/fun-guide-http-status-code#note-about-real-life" class="hash-link" aria-label="Direct link to Note about real life" title="Direct link to Note about real life" translate="no">​</a></h2>
<p>While HTTP status codes provide a structured way of communicating between clients and servers, <strong>it's important to remember that they are ultimately just guidelines. It's up to developers to ensure their implementations align with the standard semantics</strong>. Occasionally, you might encounter situations where a server error is disguised as a 200 "OK" response. This can happen when developers mishandle errors or fail to properly adhere to the expected conventions.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="wrapping-up-the-adventure">Wrapping Up the Adventure<a href="https://tweak-extension.com/blog/fun-guide-http-status-code#wrapping-up-the-adventure" class="hash-link" aria-label="Direct link to Wrapping Up the Adventure" title="Direct link to Wrapping Up the Adventure" translate="no">​</a></h2>
<p>Congratulations! You've ventured through the whimsical world of HTTP status codes. We hope this playful guide has shed some light on HTTP status codes!</p>
<br>
<br>
<!-- -->
<p sx="[object Object]">If you liked this article, consider sharing (<a href="https://twitter.com/share?text=Demystifying%20HTTP%20Status%20Codes:%20A%20Fun%20Guide&amp;url=https://tweak-extension.com/blog/fun-guide-http-status-code" target="_blank" rel="noreferrer" title="tweeting"><span style="text-decoration:underline">tweeting</span></a>) it to your followers.</p>
<br><hr><div class="buttons_rr6z"><h3>Did you like this article?</h3><div class="thumbs_zuU5"><button class="button button--outline button--primary"><span class="fa fa-thumbs-up"></span>&nbsp;<!-- -->Yes</button><button class="button button--outline button--primary"><span class="fa fa-thumbs-down"></span>&nbsp;<!-- -->No</button></div></div><small>Need something else? <a href="https://tally.so/r/VLzbl6" target="_blank">Request a feature</a></small><div class="message_SA7R" style="visibility:hidden"><span class="fa fa-bolt"></span>&nbsp; <i>Thanks for your feedback!</i></div>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Essential HTTP Headers: 5 Must-Knows for Developers]]></title>
            <link>https://tweak-extension.com/blog/must-know-http-headers</link>
            <guid>https://tweak-extension.com/blog/must-know-http-headers</guid>
            <pubDate>Mon, 22 May 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[The 5 most important HTTP headers every developer should understand, from Content-Type and Authorization to CORS and caching headers.]]></description>
            <content:encoded><![CDATA[<p>HTTP headers play a crucial role in the communication between clients and servers. They provide essential information about the request or response being sent, enabling efficient data exchange and enhancing the functionality and security of web applications. In this blog post, we will detail five of the most common HTTP headers, their meanings, use cases, and why you should care about them.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="content-type">Content-Type<a href="https://tweak-extension.com/blog/must-know-http-headers#content-type" class="hash-link" aria-label="Direct link to Content-Type" title="Direct link to Content-Type" translate="no">​</a></h2>
<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type" target="_blank" rel="noopener noreferrer" class="">Content-Type header</a> specifies the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_Types" target="_blank" rel="noopener noreferrer" class="">MIME type</a> (<em>Multipurpose Internet Mail Extensions</em>) of the content being sent or received. It informs the recipient about the format and structure of the data, allowing it to be processed correctly. For example, <code>"Content-Type: text/html"</code> indicates that the content is HTML, while <code>"Content-Type: application/json"</code> signifies JSON data.</p>
<h5 class="anchor anchorTargetStickyNavbar_SgJR" id="use-case">Use case<a href="https://tweak-extension.com/blog/must-know-http-headers#use-case" class="hash-link" aria-label="Direct link to Use case" title="Direct link to Use case" translate="no">​</a></h5>
<p>Properly setting the <code>Content-Type</code> header ensures that the client understands how to interpret and render the received content, avoiding parsing errors or misinterpretation.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="user-agent">User-Agent<a href="https://tweak-extension.com/blog/must-know-http-headers#user-agent" class="hash-link" aria-label="Direct link to User-Agent" title="Direct link to User-Agent" translate="no">​</a></h2>
<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent" target="_blank" rel="noopener noreferrer" class="">User-Agent</a> header identifies the client application or user agent (e.g., web browser, crawler, or API client) making the request. It provides details about the software and version, operating system, and device used by the client.</p>
<h5 class="anchor anchorTargetStickyNavbar_SgJR" id="use-case-1">Use case<a href="https://tweak-extension.com/blog/must-know-http-headers#use-case-1" class="hash-link" aria-label="Direct link to Use case" title="Direct link to Use case" translate="no">​</a></h5>
<p>Web servers utilize the <code>User-Agent</code> header to determine the capabilities of the client, enabling server-side optimizations and customization based on the client's characteristics. Are you getting unwanted traffic in your servers? Well, the <code>User-Agent</code> might be a good hint often indicating the presence of bots! 🤖</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="accept">Accept<a href="https://tweak-extension.com/blog/must-know-http-headers#accept" class="hash-link" aria-label="Direct link to Accept" title="Direct link to Accept" translate="no">​</a></h2>
<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept" target="_blank" rel="noopener noreferrer" class="">Accept</a> header specifies the media types or content types that the client can handle or prefers in the response. It allows the client to communicate its preference regarding the format of the response data.</p>
<div class="theme-admonition theme-admonition-tip admonition_mDP4 alert alert--success"><div class="admonitionHeading_Mfam"><span class="admonitionIcon_ba76"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_LzEm"><p>The <code>Accept</code> header always indicates what kind of response from the server a client prefers, the <code>Content-type</code> refers to the content of the current request/response.</p></div></div>
<h5 class="anchor anchorTargetStickyNavbar_SgJR" id="use-case-2">Use case<a href="https://tweak-extension.com/blog/must-know-http-headers#use-case-2" class="hash-link" aria-label="Direct link to Use case" title="Direct link to Use case" translate="no">​</a></h5>
<p>Servers can analyze the <code>Accept</code> header to choose an appropriate response format when multiple options are available. For example, if the <code>Accept</code> header contains <code>"application/json"</code>, the server may respond with JSON data rather than XML or HTML.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="authorization">Authorization<a href="https://tweak-extension.com/blog/must-know-http-headers#authorization" class="hash-link" aria-label="Direct link to Authorization" title="Direct link to Authorization" translate="no">​</a></h2>
<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization" target="_blank" rel="noopener noreferrer" class="">Authorization</a> header carries credentials or tokens required for authentication purposes. It is used to provide proof of identity and permissions to access protected resources.</p>
<h5 class="anchor anchorTargetStickyNavbar_SgJR" id="use-case-3">Use case<a href="https://tweak-extension.com/blog/must-know-http-headers#use-case-3" class="hash-link" aria-label="Direct link to Use case" title="Direct link to Use case" translate="no">​</a></h5>
<p>When making requests to restricted areas or performing actions that require authentication; the <code>Authorization</code> header holds the necessary information to validate the client's identity.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="cache-control">Cache-Control<a href="https://tweak-extension.com/blog/must-know-http-headers#cache-control" class="hash-link" aria-label="Direct link to Cache-Control" title="Direct link to Cache-Control" translate="no">​</a></h2>
<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control" target="_blank" rel="noopener noreferrer" class="">Cache-Control</a> header controls caching behavior for both the client and intermediary servers. It specifies directives to define caching rules, such as caching duration, cache validation, or disabling caching altogether.</p>
<h5 class="anchor anchorTargetStickyNavbar_SgJR" id="use-case-4">Use case<a href="https://tweak-extension.com/blog/must-know-http-headers#use-case-4" class="hash-link" aria-label="Direct link to Use case" title="Direct link to Use case" translate="no">​</a></h5>
<p>Caching improves performance and reduces the load on servers. By setting appropriate <code>Cache-Control</code> <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#cache_directives" target="_blank" rel="noopener noreferrer" class="">directives</a>, developers can optimize how content is cached and delivered to clients, improving page load times and reducing bandwidth usage.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="conclusion">Conclusion<a href="https://tweak-extension.com/blog/must-know-http-headers#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h2>
<p>HTTP headers are integral components of web communication, facilitating effective data exchange between clients and servers. <strong>By understanding the meaning and use cases of common HTTP headers like the ones above ☝️, developers can enhance their web applications' functionality, security, and performance</strong>.</p>
<br>
<br>
<!-- -->
<p sx="[object Object]">If you liked this article, consider sharing (<a href="https://twitter.com/share?text=Essential%20HTTP%20Headers:%205%20Must-Knows%20for%20Developers&amp;url=https://tweak-extension.com/blog/must-know-http-headers" target="_blank" rel="noreferrer" title="tweeting"><span style="text-decoration:underline">tweeting</span></a>) it to your followers.</p>
<br><hr><div class="buttons_rr6z"><h3>Did you like this article?</h3><div class="thumbs_zuU5"><button class="button button--outline button--primary"><span class="fa fa-thumbs-up"></span>&nbsp;<!-- -->Yes</button><button class="button button--outline button--primary"><span class="fa fa-thumbs-down"></span>&nbsp;<!-- -->No</button></div></div><small>Need something else? <a href="https://tally.so/r/VLzbl6" target="_blank">Request a feature</a></small><div class="message_SA7R" style="visibility:hidden"><span class="fa fa-bolt"></span>&nbsp; <i>Thanks for your feedback!</i></div>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Override Response Headers with Chrome DevTools]]></title>
            <link>https://tweak-extension.com/blog/how-to-override-response-headers-chrome</link>
            <guid>https://tweak-extension.com/blog/how-to-override-response-headers-chrome</guid>
            <pubDate>Sun, 21 May 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Learn how to override HTTP response headers in Chrome using DevTools or the tweak extension. Debug CORS issues and modify headers without a proxy.]]></description>
            <content:encoded><![CDATA[<p>Modern browsers have advanced development <em>toolkits</em> allowing HTTP request inspection in detail. <strong>With the recent Chrome 111 release users are now able to override response headers</strong> directly in the network panel. This means tools like browser extension are not needed to accomplish simple use cases. In this article we explore the current possibilities and limitations of one of the newest Chrome DevTools features.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="motivation">Motivation<a href="https://tweak-extension.com/blog/how-to-override-response-headers-chrome#motivation" class="hash-link" aria-label="Direct link to Motivation" title="Direct link to Motivation" translate="no">​</a></h2>
<blockquote>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" target="_blank" rel="noopener noreferrer" class="">HTTP headers</a> let the client and the server pass additional information with an HTTP request or response. This meta-information is important for a website’s functionality and security. Until now, editing HTTP headers required having access to the actual web server, which often made it difficult to quickly experiment with changes to HTTP headers.</p>
</blockquote>
<p>[source: <a href="https://github.com/ChromeDevTools/rfcs/discussions/4" target="_blank" rel="noopener noreferrer" class="">ChromeDevTools/rfcs</a>]</p>
<p>Overriding a response header is a developer need that is tipically related with the following use cases:</p>
<ol>
<li class=""><strong>Debugging and troubleshooting</strong>: modifying response headers helps developers debug and troubleshoot issues by simulating different server behaviors.</li>
<li class=""><strong>API testing and development</strong>: developers can test and handle various API responses by modifying response headers in the browser.</li>
<li class=""><strong>Caching and performance optimization</strong>: modifying response headers allows developers to experiment with caching configurations and optimize frontend performance.</li>
<li class=""><strong>Security</strong>: response header modification helps verify security measures and test authentication mechanisms.</li>
<li class=""><strong>API versioning and compatibility</strong>: developers can ensure API compatibility by modifying headers and testing different API versions.</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="how">How<a href="https://tweak-extension.com/blog/how-to-override-response-headers-chrome#how" class="hash-link" aria-label="Direct link to How" title="Direct link to How" translate="no">​</a></h2>
<p>The Chrome team made it very simple this time. <strong>Here's how you can add or modify response headers</strong>:</p>
<ol>
<li class="">Open the devtools panel in the Network tab.</li>
<li class="">Locate and open the request you wish to modify the response headers.</li>
<li class="">Locate the <code>Response Headers</code> in the <code>Headers</code> panel.</li>
<li class="">You'll see that the UI looks a little bit different from usual:<!-- -->
<ol>
<li class="">You can click <code>+ Add header</code> to add a new response header.</li>
<li class="">You can edit existing reponse header values.</li>
</ol>
</li>
</ol>
<p><img decoding="async" loading="lazy" alt="example override response header" src="https://tweak-extension.com/assets/images/image-01-664fc0286465dafeee407ac65059f31e.png" title="example override response header" width="2410" height="1312" class="img_F_NH"></p>
<p>Once you trigger the same request again your modifications are applied to the response header(s) as you can see in the highlighted sections in the screenshot above.</p>
<p>That's it!</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="limitations">Limitations<a href="https://tweak-extension.com/blog/how-to-override-response-headers-chrome#limitations" class="hash-link" aria-label="Direct link to Limitations" title="Direct link to Limitations" translate="no">​</a></h2>
<p>For simple modifications the Chrome Network Panel has you covered. <strong>However if you find yourself bumping into these limitations</strong>:</p>
<ol>
<li class="">You need to <strong>easily restore overrides</strong> without having to manage chrome override files.</li>
<li class="">You need to <strong>also modify request headers</strong> in a similar fashion.</li>
<li class="">You need to <strong>programatically change headers</strong> (say with custom JavaScript code?).</li>
</ol>
<p><strong>You came to the right place, please read on!</strong></p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="beyond-browser-developer-tools">Beyond browser developer tools<a href="https://tweak-extension.com/blog/how-to-override-response-headers-chrome#beyond-browser-developer-tools" class="hash-link" aria-label="Direct link to Beyond browser developer tools" title="Direct link to Beyond browser developer tools" translate="no">​</a></h2>
<p>Altough Chrome will cover most of your basic needs, if you're hitting on the above limitations, you can try <a href="https://tweak-extension.com/" target="_blank" rel="noopener noreferrer" class="">tweak</a> whenever you're ready.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="modify-request-headers">Modify request headers<a href="https://tweak-extension.com/blog/how-to-override-response-headers-chrome#modify-request-headers" class="hash-link" aria-label="Direct link to Modify request headers" title="Direct link to Modify request headers" translate="no">​</a></h3>
<p>With an intuitive table like interface you modify both <a href="https://tweak-extension.com/docs/rule/http-headers" target="_blank" rel="noopener noreferrer" class="">request and response headers</a>.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="programatically-modify-request-headers">Programatically modify request headers<a href="https://tweak-extension.com/blog/how-to-override-response-headers-chrome#programatically-modify-request-headers" class="hash-link" aria-label="Direct link to Programatically modify request headers" title="Direct link to Programatically modify request headers" translate="no">​</a></h3>
<p>With <a href="https://tweak-extension.com/docs/rule/request-hook" target="_blank" rel="noopener noreferrer" class="">request hooks</a> you can write your own custom script that modifies the specificied headers only when the request meets some criteria; for example when the URL or request body have specific keywords or content.</p>
<br>
<br>
<!-- -->
<p sx="[object Object]">If you liked this article, consider sharing (<a href="https://twitter.com/share?text=How%20to%20Override%20Response%20Headers%20with%20Chrome%20DevTools&amp;url=https://tweak-extension.com/blog/how-to-override-response-headers-chrome" target="_blank" rel="noreferrer" title="tweeting"><span style="text-decoration:underline">tweeting</span></a>) it to your followers.</p>
<br><hr><div class="buttons_rr6z"><h3>Did you like this article?</h3><div class="thumbs_zuU5"><button class="button button--outline button--primary"><span class="fa fa-thumbs-up"></span>&nbsp;<!-- -->Yes</button><button class="button button--outline button--primary"><span class="fa fa-thumbs-down"></span>&nbsp;<!-- -->No</button></div></div><small>Need something else? <a href="https://tally.so/r/VLzbl6" target="_blank">Request a feature</a></small><div class="message_SA7R" style="visibility:hidden"><span class="fa fa-bolt"></span>&nbsp; <i>Thanks for your feedback!</i></div>]]></content:encoded>
            <category>Browser</category>
            <category>Productivity</category>
        </item>
        <item>
            <title><![CDATA[Boost Your Productivity with Keyboard Shortcuts]]></title>
            <link>https://tweak-extension.com/blog/productivity-keyboard-shortcuts</link>
            <guid>https://tweak-extension.com/blog/productivity-keyboard-shortcuts</guid>
            <pubDate>Mon, 12 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Level up your development workflow with essential keyboard shortcuts for VS Code, Chrome DevTools, and your operating system.]]></description>
            <content:encoded><![CDATA[<p>Keyboard shortcuts are an essential tool for web developers, as they can help <strong>speed up common tasks and improve efficiency in the development process</strong>. In modern browsers such as Google Chrome and Mozilla Firefox, keyboard shortcuts can be especially helpful for debugging, as they allow developers to quickly access and navigate various development tools without needing to use their mouse or trackpad. We're also looking into <a class="" href="https://tweak-extension.com/blog/productivity-keyboard-shortcuts#why-should-i-care">why you should give a damn about shortcuts</a>.</p>
<p>One of the key benefits of keyboard shortcuts is that <strong>they allow developers to quickly access and use the various debugging tools that are built into modern browsers</strong>. For example, in Chrome, developers can use the shortcut <kbd>CTRL + SHIFT + I</kbd> (<em>CMD on Mac</em>) to open the Developer Tools window, which provides a range of tools for inspecting and debugging web pages. This shortcut is much faster than using the mouse to click on the Developer Tools icon in the browser's toolbar.</p>
<p>Another great example is the use of <kdb>CTRL + SHIFT + C</kdb> to enter Inspect Element mode, which allows them to click on any element on a web page and see its HTML and CSS code. This can be very useful for quickly identifying and fixing problems with the layout or styling of a web page.</p>
<p>If you're curious about particular keyboard shortucts for web development, <a class="" href="https://tweak-extension.com/blog/10-must-know-chrome-shortcuts">here are 10 Must Known Chrome Keyboard Shortcuts</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="why-should-i-care">Why should I care?<a href="https://tweak-extension.com/blog/productivity-keyboard-shortcuts#why-should-i-care" class="hash-link" aria-label="Direct link to Why should I care?" title="Direct link to Why should I care?" translate="no">​</a></h2>
<p>tl;dr</p>
<ol>
<li class=""><strong>Efficiency</strong>.</li>
<li class=""><strong>Accuracy</strong>.</li>
<li class=""><strong>Accessibility</strong>.</li>
</ol>
<p>Let's expand on these:</p>
<ol>
<li class="">They can help speed up common tasks and improve <strong>efficiency</strong> in the development process.</li>
<li class="">Keyboard shortcuts can also help to improve <strong>accuracy</strong> and precision in the development process. By using the keyboard to navigate and interact with the development tools, developers can avoid the potential for errors that can occur when using a mouse or trackpad, such as accidentally clicking the wrong element or button</li>
<li class="">By using shortcuts you are contributing to the overall improvement of web applications. By using keyboard shortcuts to navigate and interact with web pages, developers can ensure that their applications are <strong>accessible</strong> and usable by users who may not be able to use a mouse or trackpad, such as those with motor impairments or users who prefer to use a keyboard</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="tips-for-memorizing-shortcuts">Tips for memorizing shortcuts<a href="https://tweak-extension.com/blog/productivity-keyboard-shortcuts#tips-for-memorizing-shortcuts" class="hash-link" aria-label="Direct link to Tips for memorizing shortcuts" title="Direct link to Tips for memorizing shortcuts" translate="no">​</a></h2>
<p><strong>Ultimately, the key to memorizing keyboard shortcuts is to make a conscious effort to use them regularly</strong>.</p>
<p>Another helpful tip is to customize the keyboard shortcuts to match the developer's individual preferences and workstyle. Most tools nowadays support this.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="conclusion">Conclusion<a href="https://tweak-extension.com/blog/productivity-keyboard-shortcuts#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h2>
<p>Overall, <strong>keyboard shortcuts are an invaluable tool for web developers</strong>, as they can help speed up common tasks and improve efficiency in the development process. By learning and using these shortcuts, developers can save time and streamline their workflow, allowing them to focus on the important work of creating great web applications.</p>
<p sx="[object Object]">If you liked this article, consider sharing (<a href="https://twitter.com/share?text=Boost%20Your%20Productivity%20with%20Keyboard%20Shortcuts&amp;url=https://tweak-extension.com/blog/productivity-keyboard-shortcuts" target="_blank" rel="noreferrer" title="tweeting"><span style="text-decoration:underline">tweeting</span></a>) it to your followers.</p>
<br><hr><div class="buttons_rr6z"><h3>Did you like this article?</h3><div class="thumbs_zuU5"><button class="button button--outline button--primary"><span class="fa fa-thumbs-up"></span>&nbsp;<!-- -->Yes</button><button class="button button--outline button--primary"><span class="fa fa-thumbs-down"></span>&nbsp;<!-- -->No</button></div></div><small>Need something else? <a href="https://tally.so/r/VLzbl6" target="_blank">Request a feature</a></small><div class="message_SA7R" style="visibility:hidden"><span class="fa fa-bolt"></span>&nbsp; <i>Thanks for your feedback!</i></div>]]></content:encoded>
            <category>Productivity</category>
        </item>
        <item>
            <title><![CDATA[Why do Developers Mock HTTP Requests?]]></title>
            <link>https://tweak-extension.com/blog/why-developers-mock-http-requests</link>
            <guid>https://tweak-extension.com/blog/why-developers-mock-http-requests</guid>
            <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Discover why developers mock HTTP requests and the common scenarios where mocking saves time. Decouple frontend development from backend availability.]]></description>
            <content:encoded><![CDATA[<p>This short article covers what "mocking" means in web development, how developers achieve this, and how it helps them. We'll also cover some disadvantages of mocking.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="demystifying-mocking">Demystifying mocking<a href="https://tweak-extension.com/blog/why-developers-mock-http-requests#demystifying-mocking" class="hash-link" aria-label="Direct link to Demystifying mocking" title="Direct link to Demystifying mocking" translate="no">​</a></h2>
<blockquote>
<p>The term "mock" comes from the verb "to mock," which means to imitate or copy something in a teasing or derisive manner.</p>
</blockquote>
<p>Mocks, or mock objects, are often referred to as "fake" because they are not the real thing. In testing, <strong>a mock is a simulated version of a real object or service</strong>, such as a database or a network connection. It is called a mock because it <strong>is not the real thing</strong>, but it behaves similarly and can be used to test the code without relying on the actual object or service.</p>
<p>In the context of testing, mocking is a way of imitating the behavior of a real object or service in a controlled and predictable way so that the code can be tested without relying on the real thing. So when developers refer to mocks as "fake" data, they use the term to indicate that the data is not real but is being used as a stand-in for testing purposes.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="mocking-in-web-development">Mocking in web development?<a href="https://tweak-extension.com/blog/why-developers-mock-http-requests#mocking-in-web-development" class="hash-link" aria-label="Direct link to Mocking in web development?" title="Direct link to Mocking in web development?" translate="no">​</a></h2>
<p>In the context of web development, mocking is a common practice because it allows them to test their code without making real network requests. This can be useful for various reasons, such as testing how the code handles different response data types or <a href="https://tweak-extension.com/blog/how-to-simulate-error-http-request" target="_blank" rel="noopener noreferrer" class="">simulating error conditions</a> that would be difficult or impossible to reproduce in a live environment.
One way to mock HTTP requests in JavaScript is to use a library like <a href="https://github.com/nock/nock" target="_blank" rel="noopener noreferrer" class="">nock</a> or <a href="https://sinonjs.org/" target="_blank" rel="noopener noreferrer" class="">sinon.js</a>. These libraries provide a fake implementation of the XMLHttpRequest object, which is the object that JavaScript uses to make network requests. By using a fake XMLHttpRequest object, you can control exactly what data the code receives when it makes a request, which makes it much easier to test different scenarios.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="disadvantages-of-mocking">Disadvantages of mocking<a href="https://tweak-extension.com/blog/why-developers-mock-http-requests#disadvantages-of-mocking" class="hash-link" aria-label="Direct link to Disadvantages of mocking" title="Direct link to Disadvantages of mocking" translate="no">​</a></h2>
<p>One disadvantage of mocking HTTP requests is that it can make your tests less realistic. Since you are not actually making a real network request, your tests <strong>may not accurately reflect how the code will behave in a production environment</strong>. This can make it more difficult to catch bugs or other issues that only arise when the code is running in a real-world production environment.</p>
<p>Another disadvantage is that mocking HTTP requests can <strong>complicate your tests</strong>. Since you are not actually making a real network request, you have to manually set up all of the data that the code would receive in a real request. This can take a significant amount of time and effort, and it can make your tests more difficult to read and maintain.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="conclusion">Conclusion<a href="https://tweak-extension.com/blog/why-developers-mock-http-requests#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h2>
<p>While mocking HTTP requests can be a helpful tool, it is essential to use it wisely and only when necessary. Sometimes, it may be better to make an actual network request and use techniques like stubbing or faking to control the response data. This can provide a more realistic and efficient testing environment.</p>
<p>However, sometimes, it is handy to use mocking across any environment, for example, to debug an issue in production. With our browser extension <a href="https://tweak-extension.com/" target="_blank" rel="noopener noreferrer" class="">tweak</a> you can achieve all of this without worrying about the implementation details and the maintainability burden they pose for you and your team. Furthermore, you can use the tool seamlessly for testing across any environment, from local development to production.</p>
<p sx="[object Object]">If you liked this article, consider sharing (<a href="https://twitter.com/share?text=Why%20do%20Developers%20Mock%20HTTP%20Requests&amp;url=https://tweak-extension.com/blog/why-developers-mock-http-requests" target="_blank" rel="noreferrer" title="tweeting"><span style="text-decoration:underline">tweeting</span></a>) it to your followers.</p>
<br><hr><div class="buttons_rr6z"><h3>Did you like this article?</h3><div class="thumbs_zuU5"><button class="button button--outline button--primary"><span class="fa fa-thumbs-up"></span>&nbsp;<!-- -->Yes</button><button class="button button--outline button--primary"><span class="fa fa-thumbs-down"></span>&nbsp;<!-- -->No</button></div></div><small>Need something else? <a href="https://tally.so/r/VLzbl6" target="_blank">Request a feature</a></small><div class="message_SA7R" style="visibility:hidden"><span class="fa fa-bolt"></span>&nbsp; <i>Thanks for your feedback!</i></div>]]></content:encoded>
            <category>JavaScript</category>
            <category>Software Testing</category>
        </item>
        <item>
            <title><![CDATA[What a Google Search Can't Tell You About These JS Testing Frameworks]]></title>
            <link>https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks</link>
            <guid>https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks</guid>
            <pubDate>Tue, 09 Aug 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[An honest comparison of JavaScript end-to-end testing frameworks: Playwright, Cypress, Puppeteer, and WebdriverIO. What the docs don't tell you.]]></description>
            <content:encoded><![CDATA[<p>This blog post gives detailed insights into the most prevalent JavaScript E2E (end-to-end) testing frameworks. We break down our article into two main sections:</p>
<ol>
<li class=""><strong>Our experience</strong> - <strong>we tried six different frameworks by writing the same test case</strong> on the same web application and provided detailed pros/cons of working with those technologies. All the code examples are available <a href="https://github.com/tweak-extension/js-e2e-testing-frameworks" target="_blank" rel="noopener noreferrer" class="">here</a>.</li>
<li class=""><strong>Deep dive</strong> - to help you decide the best framework for your project, we pulled together many different data sources - e.g., the state of JS survey, social networks, GitHub, etc. We evaluate each framework across <strong>four categories: feature set, adoption &amp; popularity, DX (developer experience), and maintenance</strong>.</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="the-frameworks">The frameworks<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#the-frameworks" class="hash-link" aria-label="Direct link to The frameworks" title="Direct link to The frameworks" translate="no">​</a></h2>
<p>Let's start by briefly exploring the background of the chosen frameworks. We're listing our picks in alphabetical order.</p>
<ul>
<li class=""><a href="https://www.cypress.io/" target="_blank" rel="noopener noreferrer" class="">Cypress</a> - created by Brian Mann, was <a href="https://www.cypress.io/blog/2017/05/04/cypress-is-going-open-source/" target="_blank" rel="noopener noreferrer" class="">opened to the world in 2017</a>. Cypress became more than a framework. Besides the core library with APIs to write tests, Cypress expanded into a platform that offers a complete overview of the test's performance, presenting an all-in-one monitoring dashboard.</li>
<li class=""><a href="https://nightwatchjs.org/" target="_blank" rel="noopener noreferrer" class="">Nightwatch.js</a> - initially released under a company called <em>pineview.io</em>, now Nighwatch.js belongs to BrowserStack, with Andrei Rusu, creator of Nightwatch.js, still contributing actively to the project. With a relatively small API, Nighwatch.js focus on essentials (e.g., integrated runner, assert API).</li>
<li class=""><a href="https://playwright.dev/" target="_blank" rel="noopener noreferrer" class="">Playwright</a> - backed by Microsoft, with initial developments led by Pavel Feldman and Andrey Lushnikov, Playwright wants to come across as a resilient, robust, and unified tool to run E2E tests against any browser (Opera and Safari included). Playwright goes beyond the JavaScript ecosystem offering support for additional programming languages.</li>
<li class=""><a href="https://github.com/angular/protractor" target="_blank" rel="noopener noreferrer" class="">Protractor</a> 🎖(<em>honorable mention</em>) - we're not going to look into Protractor due to its narrow focus on Angular applications. Regardless, we want to mention this pioneer open-source technology that played its role in the history of JavaScript.</li>
<li class=""><a href="https://pptr.dev/" target="_blank" rel="noopener noreferrer" class="">Puppeteer</a> - backed by Google, Puppeteer had its initial development primarily led by Andrey Lushnikov, who now works on Playwright. The first thing to note is that Puppeteer is a library and not a framework; hence many of the features you would expect to find in a testing framework are not present, such as assert API.</li>
<li class=""><a href="https://testcafe.io/" target="_blank" rel="noopener noreferrer" class="">TestCafe</a> - backed by DevExpress, this framework has good cross-browser support and a simple yet rich testing API. Like Cypress, TestCafe expands into a platform, TestCafe Studio.</li>
<li class=""><a href="https://webdriver.io/" target="_blank" rel="noopener noreferrer" class="">Webdriver.io</a> - with Christian Bromann as lead maintainer, this framework had a major rewrite in <a href="https://webdriver.io/blog/2021/02/09/webdriverio-v7-released" target="_blank" rel="noopener noreferrer" class="">2021 (v7 release)</a>, which reassured its presence amongst other frameworks in this list. The main selling point of Webdriver.io is interoperability. Webdriver.io allows developers to test native mobile applications (iOS and Android), stretching beyond the scope of web application testing.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="-our-experience">🧪 Our experience<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#-our-experience" class="hash-link" aria-label="Direct link to 🧪 Our experience" title="Direct link to 🧪 Our experience" translate="no">​</a></h2>
<p>This section documents our journey while setting up and writing one test with every framework. A hands-on experience with each technology will help us interpret the community trends, which we'll cover later in this article.</p>
<table><thead><tr><th>Framework</th><th style="text-align:center">Time to setup and write first test</th><th style="text-align:right">LOC <small aria-describedby="table-our-experience-1">[1]</small></th><th style="text-align:right">DX<small aria-describedby="table-our-experience-2">[2]</small></th></tr></thead><tbody><tr><td><strong>Cypress</strong></td><td style="text-align:center">30min</td><td style="text-align:right">12</td><td style="text-align:right">Excellent</td></tr><tr><td><strong>Nightwatch.js</strong></td><td style="text-align:center">30min</td><td style="text-align:right">19</td><td style="text-align:right">Very Good</td></tr><tr><td><strong>Playwright</strong></td><td style="text-align:center">18min</td><td style="text-align:right">17</td><td style="text-align:right">Excellent</td></tr><tr><td><strong>Puppeteer</strong></td><td style="text-align:center">30min</td><td style="text-align:right">34</td><td style="text-align:right">Poor</td></tr><tr><td><strong>TestCafe</strong></td><td style="text-align:center">25min</td><td style="text-align:right">21</td><td style="text-align:right">Good</td></tr><tr><td><strong>Webdriver.io</strong></td><td style="text-align:center">50min</td><td style="text-align:right">18</td><td style="text-align:right">Poor</td></tr></tbody></table>
<small><p><strong id="table-our-experience-1">1</strong> - <b>L</b>ines <b>o</b>f <b>C</b>ode&nbsp;|&nbsp;
<strong id="table-our-experience-2">2</strong> - our opinion</p></small>
<h4 class="anchor anchorTargetStickyNavbar_SgJR" id="test-use-case">Test use case<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#test-use-case" class="hash-link" aria-label="Direct link to Test use case" title="Direct link to Test use case" translate="no">​</a></h4>
<p>We've built a simple react application that contains a heading element, a button, and a paragraph. When clicking the button, we trigger an ajax request and display a quote on the screen.</p>
<p><img decoding="async" loading="lazy" alt="&amp;quot;sample application used for testing&amp;quot;" src="https://tweak-extension.com/assets/images/demo-test-app-74c4ecee806c7d2ae5d45bac4956c418.gif" title="sample application used for testing" width="1370" height="792" class="img_F_NH"></p>
<p>It's time to see some code! We'll go through the frameworks in alphabetical order. For each framework, we'll list items we've liked and disliked.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="cypress">Cypress<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#cypress" class="hash-link" aria-label="Direct link to Cypress" title="Direct link to Cypress" translate="no">​</a></h3>
<p>Cypress has detailed documentation about its APIs and contains guides/articles with recommendations and good testing practices.</p>
<div class="language-js codeBlockContainer_FOcj theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockTitle_Smf2">/tests/cypress.spec.js</div><div class="codeBlockContent_guI0"><pre tabindex="0" class="prism-code language-js codeBlock_PD6s thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_EpoG"><div class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> selectors </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">require</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'./common/selectors'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> mock </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">require</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'./common/mock'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token function" style="color:rgb(80, 250, 123)">it</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'Cypress'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token arrow operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  cy</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">intercept</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'/random-quote'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> mock</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token keyword module" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'getRandomQuotes'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  cy</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">visit</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'http://localhost:3000/'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  cy</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">get</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">title</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">should</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'have.text'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'Quotez'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  cy</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">get</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">contentEmpty</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">should</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'be.visible'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  cy</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">get</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">contentEmpty</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">should</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'have.text'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'...'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  cy</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">get</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">trigger</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">click</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  cy</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">get</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">content</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">should</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'have.text'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation">mock</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation property-access">quote</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string string" style="color:rgb(255, 121, 198)"> by </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation">mock</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation property-access">author</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><br></div></code></pre></div></div>
<small><a target="_blank" rel="noopener" href="https://github.com/tweak-extension/js-e2e-testing-frameworks/blob/main/tests/cypress.spec.js">source&nbsp;<span class="fa fa-external-link"></span></a></small>
<h4 class="anchor anchorTargetStickyNavbar_SgJR" id="-disliked">👎 Disliked<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#-disliked" class="hash-link" aria-label="Direct link to 👎 Disliked" title="Direct link to 👎 Disliked" translate="no">​</a></h4>
<ul>
<li class="">We faced overwhelming documentation during onboarding; we felt pulled in many different directions. Onboarding should be a smooth user journey where one learns to use the basics of the framework.</li>
<li class=""><strong>Cypress is highly opinionated about scaffolding</strong>. On the other hand, everything is configurable, so you need to dig through the docs to figure out how to configure the project according to your preference.</li>
<li class="">Cypress has a <a href="https://docs.cypress.io/guides/references/trade-offs#Permanent-trade-offs-1" target="_blank" rel="noopener noreferrer" class="">list of trade-offs</a> that might be a deal-breaker for many projects. It's noteworthy that the Cypress team is transparent about this.</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_SgJR" id="-liked">👍 Liked<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#-liked" class="hash-link" aria-label="Direct link to 👍 Liked" title="Direct link to 👍 Liked" translate="no">​</a></h4>
<p><img decoding="async" loading="lazy" alt="&amp;quot;cypress dashboard running test&amp;quot;" src="https://tweak-extension.com/assets/images/cypress-01-c5bb07b0e05a7e0d15ae2876d4764c5d.png" title="cypress dashboard running test" width="1194" height="987" class="img_F_NH"></p>
<ul>
<li class="">The automated onboarding generates quite some files, but all in all, it's fantastic.</li>
<li class=""><strong>Cypress refreshes the browser as you update your test files</strong>, offering a seamless developer experience.</li>
<li class=""><strong>Cypress has a beautiful API design</strong> that is easy to understand (navigation, selectors, mocking). It took seconds to intercept a request and provide mock data.<!-- -->
<div class="language-js codeBlockContainer_FOcj theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_guI0"><pre tabindex="0" class="prism-code language-js codeBlock_PD6s thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_EpoG"><div class="token-line" style="color:#F8F8F2"><span class="token plain">cy</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">intercept</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'/random-quote'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> mock</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token keyword module" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'getRandomQuotes'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><br></div></code></pre></div></div>
</li>
<li class=""><strong>Intellisense works remarkably well</strong> even on JavaScript-only projects, where you get autocompletion for <code>should</code> statements such as <code>'have.text'</code> or <code>'be.visible'</code>.</li>
<li class=""><strong>The</strong> <a href="https://docs.cypress.io/guides/end-to-end-testing/protractor-to-cypress#Time-travel-through-tests" target="_blank" rel="noopener noreferrer" class=""><strong>time-traveling debugging</strong></a> is a few miles ahead of the competitors, making debugging much more convenient.</li>
<li class=""><strong>Our test has only 12 LOC,</strong> making it the shortest test we've written during our experiments.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="nightwatchjs">Nightwatch.js<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#nightwatchjs" class="hash-link" aria-label="Direct link to Nightwatch.js" title="Direct link to Nightwatch.js" translate="no">​</a></h3>
<p>We implemented our test smoothly with the help of a quick start guide and automated onboarding. Nightwatch.js offers the possibility of integrating existing projects, supporting both JavaScript and TypeScript.</p>
<div class="language-js codeBlockContainer_FOcj theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockTitle_Smf2">/tests/nightwatch.spec.js</div><div class="codeBlockContent_guI0"><pre tabindex="0" class="prism-code language-js codeBlock_PD6s thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_EpoG"><div class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> selectors </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">require</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'./common/selectors'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> mock </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">require</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'./common/mock'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token function" style="color:rgb(80, 250, 123)">describe</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'Nightwatch.js'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">function</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token function" style="color:rgb(80, 250, 123)">it</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'Nightwatch.js'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">async</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">function</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> browser</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">mockNetworkResponse</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'http://localhost:3000/random-quote'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token literal-property property">status</span><span class="token operator">:</span><span class="token plain"> </span><span class="token number">200</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token literal-property property">body</span><span class="token operator">:</span><span class="token plain"> </span><span class="token known-class-name class-name">JSON</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">stringify</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">mock</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">navigateTo</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'http://localhost:3000'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">assert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">textEquals</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">title</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'Quotez'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">assert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">elementPresent</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">contentEmpty</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">assert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">textEquals</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">contentEmpty</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'...'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">click</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">trigger</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">assert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">elementPresent</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">content</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">assert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">textMatches</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">content</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation">mock</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation property-access">quote</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string string" style="color:rgb(255, 121, 198)"> by </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation">mock</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation property-access">author</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><br></div></code></pre></div></div>
<small><a target="_blank" rel="noopener" href="https://github.com/tweak-extension/js-e2e-testing-frameworks/blob/main/tests/nightwatch.spec.js">source&nbsp;<span class="fa fa-external-link"></span></a></small>
<h4 class="anchor anchorTargetStickyNavbar_SgJR" id="-disliked-1">👎 Disliked<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#-disliked-1" class="hash-link" aria-label="Direct link to 👎 Disliked" title="Direct link to 👎 Disliked" translate="no">​</a></h4>
<ul>
<li class="">Does not support mock network requests across all supported browsers.</li>
<li class="">We found <strong>outdated documentation</strong>. The code generated during onboarding is not in sync with the documentation. The docs mention <code>npx nightwatch tests/ecosia.js</code>, which with the new structure should be <code>npx Nightwatch tests/specs/basic/ecosia.js</code>.</li>
<li class="">Having the <strong>tests break because you've deleted empty auto-generated folders</strong> is a frustrating experience.</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_SgJR" id="-liked-1">👍 Liked<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#-liked-1" class="hash-link" aria-label="Direct link to 👍 Liked" title="Direct link to 👍 Liked" translate="no">​</a></h4>
<ul>
<li class="">No config tweaking is necessary to run the test.</li>
<li class=""><strong>The fluent API is super consistent</strong>; you can do everything on the go: mocks, assertions, and interactions.</li>
<li class="">Another pleasant surprise was the debug API <code>.debug({ timeout: 20000 })</code>, which is neat to troubleshoot your tests - many other frameworks adopt a similar API.</li>
<li class="">The <strong>error log is nicely highlighted and formatted</strong>. Many tools don't offer visually friendly logs.</li>
<li class="">After successfully running the test, <strong>we're positively impressed by the good terminal text reports</strong>. Logs are well formatted and have nifty step-by-step assertion statements, all by default.</li>
</ul>
<p><img decoding="async" loading="lazy" alt="&amp;quot;nightwatch.js error logs&amp;quot;" src="https://tweak-extension.com/assets/images/nightwatch-01-32b3dd58a5aa586122c30818b1976a6d.png" title="nightwatch.js error logs" width="1390" height="718" class="img_F_NH"></p>
<p><img decoding="async" loading="lazy" alt="&amp;quot;nightwatch.js test passing logs&amp;quot;" src="https://tweak-extension.com/assets/images/nightwatch-02-630fdb2fbf3b4ac4e10f8d8c645c9395.png" title="nightwatch.js test passing logs" width="1266" height="602" class="img_F_NH"></p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="playwright">Playwright<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#playwright" class="hash-link" aria-label="Direct link to Playwright" title="Direct link to Playwright" translate="no">​</a></h3>
<p>With an automated onboarding, offering support for JavaScript and Typescript, it also comes with options to generate CI integrations (e.g., GitHub Actions). During onboarding, Playwright installs everything for us and provides a list of commands for you to start immediately.</p>
<div class="language-js codeBlockContainer_FOcj theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockTitle_Smf2">/tests/playwright.spec.js</div><div class="codeBlockContent_guI0"><pre tabindex="0" class="prism-code language-js codeBlock_PD6s thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_EpoG"><div class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> test</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> expect </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">require</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'@playwright/test'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> selectors </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">require</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'./common/selectors'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> mock </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">require</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'./common/mock'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token function" style="color:rgb(80, 250, 123)">test</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'Playwright'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">async</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token parameter punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token parameter"> page </span><span class="token parameter punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token arrow operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> page</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">route</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'http://localhost:3000/random-quote'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token parameter">route</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token arrow operator">=&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    route</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">fulfill</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token literal-property property">status</span><span class="token operator">:</span><span class="token plain"> </span><span class="token number">200</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token literal-property property">body</span><span class="token operator">:</span><span class="token plain"> </span><span class="token known-class-name class-name">JSON</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">stringify</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">mock</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> page</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">goto</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'http://localhost:3000/'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">expect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">page</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">locator</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">title</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">toHaveText</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'Quotez'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">expect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">page</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">locator</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">contentEmpty</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">toBeVisible</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">expect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">page</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">locator</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">contentEmpty</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">toHaveText</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'...'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> page</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">locator</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">trigger</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">click</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">expect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">page</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">locator</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">content</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">toBeVisible</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">expect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">page</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">locator</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">content</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">toHaveText</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation">mock</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation property-access">quote</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string string" style="color:rgb(255, 121, 198)"> by </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation">mock</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation property-access">author</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><br></div></code></pre></div></div>
<small><a target="_blank" rel="noopener" href="https://github.com/tweak-extension/js-e2e-testing-frameworks/blob/main/tests/playwright.spec.js">source&nbsp;<span class="fa fa-external-link"></span></a></small>
<h4 class="anchor anchorTargetStickyNavbar_SgJR" id="-disliked-2">👎 Disliked<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#-disliked-2" class="hash-link" aria-label="Direct link to 👎 Disliked" title="Direct link to 👎 Disliked" translate="no">​</a></h4>
<p><strong>There's nothing major to dislike about Playwright</strong>. Like other test libraries and frameworks that leverage <code>async/await</code>, tests might feel bloated in the number of <code>await</code> statements. Still, we believe this is a minor detail and subjective to the developer's preference.</p>
<h4 class="anchor anchorTargetStickyNavbar_SgJR" id="-liked-2">👍 Liked<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#-liked-2" class="hash-link" aria-label="Direct link to 👍 Liked" title="Direct link to 👍 Liked" translate="no">​</a></h4>
<ul>
<li class=""><strong>Outstanding onboarding, fast and practical</strong>, giving us the commands to run a test immediately. The example generated as boilerplate it's small but contains just the right amount of information for anyone to get started.</li>
<li class=""><strong>Friendly test reporting</strong>, with a local server delivering an HTML report that outlines test failures and passes. For fails, it points to the line of code where you made a mistake and gives a nice call log in a human-readable format.</li>
<li class="">The debugging mode has a red dot (pointer) to indicate the cursor position and show you where the click interactions happened; this is extremely handy; it can help uncover the most challenging bugs.</li>
<li class="">The <strong>stepping debugger in a separate window allows developers to step through a test script line by line</strong>! The debugger is impressive, and we haven't seen anything like it.</li>
<li class="">The config file is super intuitive; it comes with inline comments for each config property.</li>
<li class=""><strong>The assert API feels like working with Jest</strong>; hats off to the Playwright team on an <strong>intelligent API design</strong>, not reinventing the wheel, reducing the friction between different technologies.</li>
<li class="">Mocking requests only require a single statement.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="puppeteer">Puppeteer<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#puppeteer" class="hash-link" aria-label="Direct link to Puppeteer" title="Direct link to Puppeteer" translate="no">​</a></h3>
<p>Puppeteer does warn us that it's a general-purpose library, not a testing library; this is felt right from the start. Alone, Puppeteer is not enough; this is the first time we face this entry barrier, given all the other frameworks have an integrated test runner. We've picked Jest to bypass the setup process as quickly as possible.</p>
<div class="language-js codeBlockContainer_FOcj theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockTitle_Smf2">/tests/puppeteer.spec.js</div><div class="codeBlockContent_guI0"><pre tabindex="0" class="prism-code language-js codeBlock_PD6s thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_EpoG"><div class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> puppeteer </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">require</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'puppeteer'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> selectors </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">require</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'./common/selectors'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> mock </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">require</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'./common/mock'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token function" style="color:rgb(80, 250, 123)">it</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'Puppeteer (powered by Jest)'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">async</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token arrow operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> browser </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> puppeteer</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">launch</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token literal-property property">headless</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(98, 114, 164)">// headless: false to see the browser</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> page </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> browser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">newPage</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> page</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">setRequestInterception</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token boolean">true</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  page</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">on</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'request'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token parameter">request</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token arrow operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">request</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">url</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">endsWith</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'/random-quote'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">      request</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">respond</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token literal-property property">status</span><span class="token operator">:</span><span class="token plain"> </span><span class="token number">200</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token literal-property property">contentType</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'application/json'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token literal-property property">body</span><span class="token operator">:</span><span class="token plain"> </span><span class="token known-class-name class-name">JSON</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">stringify</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">mock</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">else</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">      request</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">continue</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> page</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">goto</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'http://localhost:3000'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token literal-property property">waitUntil</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'networkidle0'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> titleEl </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> page</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">$</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">title</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> title </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> titleEl</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">evaluate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token parameter">e</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token arrow operator">=&gt;</span><span class="token plain"> e</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">textContent</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token function" style="color:rgb(80, 250, 123)">expect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">title</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">toEqual</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'Quotez'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> emptyContentEl </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> page</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">$</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">contentEmpty</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> emptyContentText </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> emptyContentEl</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">evaluate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token parameter">e</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token arrow operator">=&gt;</span><span class="token plain"> e</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">textContent</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token function" style="color:rgb(80, 250, 123)">expect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">emptyContentText</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">toEqual</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'...'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> triggerEl </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> page</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">$</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">trigger</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> triggerEl</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">click</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> page</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">waitForNetworkIdle</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> contentEl </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> page</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">$</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">content</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> contentText </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> contentEl</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">evaluate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token parameter">e</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token arrow operator">=&gt;</span><span class="token plain"> e</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">textContent</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token function" style="color:rgb(80, 250, 123)">expect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">contentText</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">toEqual</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation">mock</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation property-access">quote</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string string" style="color:rgb(255, 121, 198)"> by </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation">mock</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation property-access">author</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> browser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">close</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><br></div></code></pre></div></div>
<small><a target="_blank" rel="noopener" href="https://github.com/tweak-extension/js-e2e-testing-frameworks/blob/main/tests/puppeteer.spec.js">source&nbsp;<span class="fa fa-external-link"></span></a></small>
<h4 class="anchor anchorTargetStickyNavbar_SgJR" id="-disliked-3">👎 Disliked<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#-disliked-3" class="hash-link" aria-label="Direct link to 👎 Disliked" title="Direct link to 👎 Disliked" translate="no">​</a></h4>
<ul>
<li class="">In this case, we need to <strong>set up everything from scratch</strong>, including additional tooling (Jest).</li>
<li class=""><strong>Error logs are not readable</strong>. Pay attention not to make errors while you write your tests (especially missing the <code>await</code> keyword somewhere 🔥). Unreadable error stack traces can be demotivating for anyone trying to troubleshoot a failing test.</li>
<li class=""><strong>Tests are too verbose</strong>, which is reflected by the number of LOC for our simple test compared with other alternatives.</li>
<li class="">Having run our simple test a couple of times in the non-headless mode, <strong>we've ended up with lingering Chromium instances that require forceful shutdown</strong>. Lingering chromium instances are most likely related to our Jest integration and how we lack proper handling for teardown. We think this is an <strong>unnecessary extra problem</strong>, which we can easily circumvent by picking another framework.</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_SgJR" id="-liked-3">👍 Liked<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#-liked-3" class="hash-link" aria-label="Direct link to 👍 Liked" title="Direct link to 👍 Liked" translate="no">​</a></h4>
<ul>
<li class=""><strong>API is very minimalistic</strong>. With <code>.evaluate</code> <strong>you can do everything "just" knowing JavaScript</strong>.</li>
<li class="">The ability to explicitly wait for the page to idle is neat; it gives you more control over what's happening in the browser compared to the auto-retry timeout approach many other frameworks adopt. <strong>Nope,</strong> <strong>this control won't save you from flaky tests</strong>.<!-- -->
<div class="language-js codeBlockContainer_FOcj theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_guI0"><pre tabindex="0" class="prism-code language-js codeBlock_PD6s thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_EpoG"><div class="token-line" style="color:#F8F8F2"><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> page</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">goto</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'http://localhost:3000'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token literal-property property">waitUntil</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'networkidle0'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><br></div></code></pre></div></div>
</li>
<li class="">Mocking requests is super easy. <strong>The event-driven interception API is simple to use</strong>.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="testcafe">TestCafe<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#testcafe" class="hash-link" aria-label="Direct link to TestCafe" title="Direct link to TestCafe" translate="no">​</a></h3>
<p>Instead of onboarding, TestCafe jumps from the installation to writing the first test because there's no setup required!</p>
<div class="language-js codeBlockContainer_FOcj theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockTitle_Smf2">/tests/testcafe.spec.js</div><div class="codeBlockContent_guI0"><pre tabindex="0" class="prism-code language-js codeBlock_PD6s thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_EpoG"><div class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token maybe-class-name">Selector</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token maybe-class-name">RequestMock</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">require</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'testcafe'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> selectors </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">require</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'./common/selectors'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> mock </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">require</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'./common/mock'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> tcMock </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:rgb(80, 250, 123)">RequestMock</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">onRequestTo</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'http://localhost:3000/random-quote'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">respond</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token known-class-name class-name">JSON</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">stringify</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">mock</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">202</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">fixture</span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token template-string string" style="color:rgb(255, 121, 198)">TestCafe</span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">page</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'http://localhost:3000'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">requestHooks</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">tcMock</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token function" style="color:rgb(80, 250, 123)">test</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'TestCafe'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">async</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token parameter">t</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token arrow operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> t</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">expect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function maybe-class-name" style="color:rgb(80, 250, 123)">Selector</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">title</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">innerText</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">eql</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'Quotez'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">expect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function maybe-class-name" style="color:rgb(80, 250, 123)">Selector</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">contentEmpty</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">exists</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">ok</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">expect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function maybe-class-name" style="color:rgb(80, 250, 123)">Selector</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">contentEmpty</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">innerText</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">eql</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'...'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">click</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function maybe-class-name" style="color:rgb(80, 250, 123)">Selector</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">trigger</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">expect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function maybe-class-name" style="color:rgb(80, 250, 123)">Selector</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">content</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">exists</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">ok</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">expect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function maybe-class-name" style="color:rgb(80, 250, 123)">Selector</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">content</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">innerText</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">eql</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation">mock</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation property-access">quote</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string string" style="color:rgb(255, 121, 198)"> by </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation">mock</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation property-access">author</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><br></div></code></pre></div></div>
<small><a target="_blank" rel="noopener" href="https://github.com/tweak-extension/js-e2e-testing-frameworks/blob/main/tests/testcafe.spec.js">source&nbsp;<span class="fa fa-external-link"></span></a></small>
<h4 class="anchor anchorTargetStickyNavbar_SgJR" id="-disliked-4">👎 Disliked<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#-disliked-4" class="hash-link" aria-label="Direct link to 👎 Disliked" title="Direct link to 👎 Disliked" translate="no">​</a></h4>
<p><img decoding="async" loading="lazy" alt="&amp;quot;sample security prompt for TestCafe&amp;quot;" src="https://tweak-extension.com/assets/images/testcafe-01-09ac9e04fc21db7f49e0e6665a85a842.png" title="sample security prompt for TestCafe" width="956" height="386" class="img_F_NH"></p>
<ul>
<li class="">There are some <strong>security concerns with the amount of OS permission-related popups we've faced when running the test for the first time</strong>. We haven't experienced this with any other framework. It seems unnecessary to have video recording enabled by default (for example).</li>
<li class=""><strong>Inconvenient API design for <code>RequestMock</code></strong>. Any other alternative does a better job here.</li>
<li class=""><strong>Overall, TestCafe's API design does not match its competitors</strong>, but overall a good experience, excluding setting up network request mocking.</li>
<li class="">Although our example is minimalistic, <strong>the dashboard is much slower to start than the Cypress dashboard or the Playwright debugger.</strong></li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_SgJR" id="-liked-4">👍 Liked<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#-liked-4" class="hash-link" aria-label="Direct link to 👍 Liked" title="Direct link to 👍 Liked" translate="no">​</a></h4>
<ul>
<li class="">There's <strong>no setup required and no boilerplate</strong>, which feels fantastic. Zero configuration is why we <a href="https://github.com/tweak-extension/js-e2e-testing-frameworks/blob/b34436ded0054e44c0a7247c8486506a223c6249/tests/testcafe.spec.js#L1" target="_blank" rel="noopener noreferrer" class="">wrote our first test</a> in 25 minutes, one of our fastest.</li>
<li class="">Just like with Nightwatch.js, we're impressed with the text reports on the terminal.</li>
<li class="">Error stack traces make recommendations about correct API usage.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="webdriverio">Webdriver.io<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#webdriverio" class="hash-link" aria-label="Direct link to Webdriver.io" title="Direct link to Webdriver.io" translate="no">​</a></h3>
<p>The only framework whose test case we couldn't fully complete is Webdriver.io. Although it has a quick start guide and familiar APIs, there are inconsistencies in the documentation that made the experience a bit bumpy. We spent about 30 minutes debugging the following error:</p>
<div class="language-text codeBlockContainer_FOcj theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_guI0"><pre tabindex="0" class="prism-code language-text codeBlock_PD6s thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_EpoG"><div class="token-line" style="color:#F8F8F2"><span class="token plain">Proxy error: Could not proxy request /random-quote from localhost:3000 to http://localhost:3000.</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">See https://nodejs.org/api/errors.html#errors\_common\_system\_errors for more information (ECONNRESET).</span><br></div></code></pre></div></div>
<p>As of today, we still don't know how to mock network requests with Webdriver.io, while we managed to do it effortlessly with all other alternatives. Again, this is just a detail, and the problem is undoubtedly on our end, but our level of effort here was way higher than other frameworks, which should tell us something.</p>
<div class="language-js codeBlockContainer_FOcj theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockTitle_Smf2">/tests/webdriverio.spec.js</div><div class="codeBlockContent_guI0"><pre tabindex="0" class="prism-code language-js codeBlock_PD6s thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_EpoG"><div class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> selectors </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">require</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'./common/selectors'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> mock </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">require</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'./common/mock'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token function" style="color:rgb(80, 250, 123)">describe</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'Webdriver.IO'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token arrow operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token function" style="color:rgb(80, 250, 123)">it</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'Webdriver.IO'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">async</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token arrow operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// Proxy error: Could not proxy request /random-quote from localhost:3000 to http://localhost:3000</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// const iomock = await browser.mock('http://localhost:3000/random-quote')</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// iomock.respond(mock)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// Proxy error: end</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> browser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">url</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'http://localhost:3000/'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">expect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function" style="color:rgb(80, 250, 123)">$</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">title</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">toHaveText</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'Quotez'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token function" style="color:rgb(80, 250, 123)">expect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">$</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">contentEmpty</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">isDisplayedInViewport</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">toBe</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token boolean">true</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">expect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function" style="color:rgb(80, 250, 123)">$</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">contentEmpty</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">toHaveText</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'...'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> btn </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">$</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">selectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token property-access">trigger</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword control-flow" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> btn</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token method function property-access" style="color:rgb(80, 250, 123)">click</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// ...</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><br></div></code></pre></div></div>
<small><a target="_blank" rel="noopener" href="https://github.com/tweak-extension/js-e2e-testing-frameworks/blob/main/tests/webdriverio.spec.js">source&nbsp;<span class="fa fa-external-link"></span></a></small>
<h4 class="anchor anchorTargetStickyNavbar_SgJR" id="-disliked-5">👎 Disliked<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#-disliked-5" class="hash-link" aria-label="Direct link to 👎 Disliked" title="Direct link to 👎 Disliked" translate="no">​</a></h4>
<ul>
<li class="">Upon running the <code>init</code> command, Wedriver.io <strong>changed the formatting of our package.json</strong>; this feels a bit intrusive.</li>
<li class="">The <strong>generated boilerplate was out of place</strong> even though we provided our tests directory path during the onboarding terminal prompt; this is an evident inconsistency.</li>
<li class="">Running the first test, we are <strong>overwhelmed by the amount of logging that appears in the terminal</strong>. A small test generated a lot of noise in the logs. You can tune logging in the file <code>wdio.conf.js</code> through the <code>logLevel</code> property, but a more balanced default logging would bring a better experience.</li>
<li class="">Writing the test took about one hour (without request mocking).</li>
<li class=""><strong>Intellisense is not working for the most critical API</strong>, the selector <code>$</code> interface.</li>
<li class=""><strong>Error stack traces are lengthy</strong> and hard to extract useful information.</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_SgJR" id="-liked-5">👍 Liked<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#-liked-5" class="hash-link" aria-label="Direct link to 👍 Liked" title="Direct link to 👍 Liked" translate="no">​</a></h4>
<ul>
<li class="">A surprising aspect of Webdriver.io is that it <strong>allows us to plug a custom reporter</strong> <a href="https://webdriver.io/docs/allure-reporter" target="_blank" rel="noopener noreferrer" class="">with many different options</a>.</li>
<li class="">The selector API is neat; using the <code>$</code> character as a selector feels familiar and fast to type.</li>
<li class="">Plugging in <a href="https://mochajs.org/" target="_blank" rel="noopener noreferrer" class="">Mocha</a> was straightforward without requiring additional setup besides filling in the command line prompt during onboarding.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="-deep-dive">🎯 Deep dive<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#-deep-dive" class="hash-link" aria-label="Direct link to 🎯 Deep dive" title="Direct link to 🎯 Deep dive" translate="no">​</a></h2>
<p>We break down this analysis into four major categories.</p>
<ol>
<li class=""><strong>Features</strong> - a comprehensive list of features that place our frameworks <em>vis-à-vis</em>.</li>
<li class=""><strong>Adoption &amp; Popularity</strong> - how many people out there are using it? Are developers aware of this technology?</li>
<li class=""><strong>DX (Developer Experience)</strong> - how easy is it to write, run and debug tests? What do users have to say about these technologies? Are they satisfied after using them for a while?</li>
<li class=""><strong>Maintenance</strong> - are these technologies under active development? Who is contributing to them? Are issues quickly addressed?</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="features">Features<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#features" class="hash-link" aria-label="Direct link to Features" title="Direct link to Features" translate="no">​</a></h3>
<table><thead><tr><th>Feature</th><th style="text-align:center">Cypress</th><th style="text-align:right">Nightwatch</th><th style="text-align:right">Playwright</th><th style="text-align:right">Puppeteer</th><th style="text-align:right">TestCafe</th><th style="text-align:right">Webd.io</th></tr></thead><tbody><tr><td><strong>Integrated runner</strong></td><td style="text-align:center">✅</td><td style="text-align:right">✅</td><td style="text-align:right">✅</td><td style="text-align:right">❌<small aria-describedby="table-features-2">[2]</small></td><td style="text-align:right">✅</td><td style="text-align:right">✅</td></tr><tr><td><strong>Assert/Expect APIs</strong></td><td style="text-align:center">✅</td><td style="text-align:right">✅</td><td style="text-align:right">✅</td><td style="text-align:right">❌</td><td style="text-align:right">✅</td><td style="text-align:right">✅</td></tr><tr><td><strong>Browser support</strong></td><td style="text-align:center">Chrome<br>Edge<br>Firefox</td><td style="text-align:right">Chrome<br>Edge<br>Firefox<br>Safari</td><td style="text-align:right">Chrome<br>Edge<br>Firefox<br>Safari<br>Opera</td><td style="text-align:right">Chrome<br>Firefox <small aria-describedby="table-features-3">[3]</small></td><td style="text-align:right">Chrome<br>Edge<br>Firefox<br>IE 11+<br>Safari<br>Opera</td><td style="text-align:right">All <small aria-describedby="table-features-5">[5]</small></td></tr><tr><td><strong>Support multiple tabs/windows</strong></td><td style="text-align:center">❌ <small aria-describedby="table-features-1">[1]</small></td><td style="text-align:right">✅</td><td style="text-align:right">✅</td><td style="text-align:right">✅</td><td style="text-align:right">✅ <small aria-describedby="table-features-4">[4]</small></td><td style="text-align:right">✅</td></tr><tr><td><strong>Auto-waiting<br>Automatic DOM query retries</strong></td><td style="text-align:center">✅</td><td style="text-align:right">✅</td><td style="text-align:right">✅</td><td style="text-align:right">❌</td><td style="text-align:right">✅</td><td style="text-align:right">✅</td></tr><tr><td><strong>Intercept and mock requests</strong></td><td style="text-align:center">✅</td><td style="text-align:right">✅</td><td style="text-align:right">✅</td><td style="text-align:right">✅</td><td style="text-align:right">✅</td><td style="text-align:right">✅ <small aria-describedby="table-features-6">[6]</small></td></tr><tr><td><strong>Browser extensions support</strong></td><td style="text-align:center">❌<small aria-describedby="table-features-9">[9]</small></td><td style="text-align:right">✅</td><td style="text-align:right">✅</td><td style="text-align:right">✅</td><td style="text-align:right">✅</td><td style="text-align:right">✅</td></tr><tr><td><strong>Integrated dashboard</strong></td><td style="text-align:center">✅</td><td style="text-align:right">❌</td><td style="text-align:right">❌</td><td style="text-align:right">❌</td><td style="text-align:right">✅</td><td style="text-align:right">❌</td></tr><tr><td><strong>Integrated stepping debugger</strong></td><td style="text-align:center">✅</td><td style="text-align:right">❌</td><td style="text-align:right">✅</td><td style="text-align:right">❌</td><td style="text-align:right">❌</td><td style="text-align:right">❌</td></tr><tr><td><strong>Screenshots</strong></td><td style="text-align:center">✅</td><td style="text-align:right">✅</td><td style="text-align:right">✅</td><td style="text-align:right">✅</td><td style="text-align:right">✅</td><td style="text-align:right">✅</td></tr><tr><td><strong>Video recording</strong></td><td style="text-align:center">✅</td><td style="text-align:right">❌</td><td style="text-align:right">✅</td><td style="text-align:right">❌</td><td style="text-align:right">❌</td><td style="text-align:right">❌ <small aria-describedby="table-features-7">[7]</small></td></tr><tr><td><strong>Code coverage</strong></td><td style="text-align:center">✅</td><td style="text-align:right">❌</td><td style="text-align:right">✅</td><td style="text-align:right">✅</td><td style="text-align:right">❌</td><td style="text-align:right">✅</td></tr><tr><td><strong>Automated onboarding</strong></td><td style="text-align:center">✅</td><td style="text-align:right">✅</td><td style="text-align:right">✅</td><td style="text-align:right">❌</td><td style="text-align:right">❌</td><td style="text-align:right">✅</td></tr></tbody></table>
<small><p><strong id="table-features-1">1</strong> - see <a target="_blank" rel="noopener" href="https://docs.cypress.io/guides/references/trade-offs#Multiple-tabs">trade-offs</a>&nbsp;|&nbsp;
<strong id="table-features-2">2</strong> - being a library puppeteer has naturally a narrower feature set&nbsp;|&nbsp;
<strong id="table-features-3">3</strong> - it has been experimental <a target="_blank" rel="noopener" href="https://pptr.dev/faq#q-what-is-the-status-of-cross-browser-support">for a long time</a>&nbsp;|&nbsp;
<strong id="table-features-4">4</strong> - <a target="_blank" rel="noopener" href="https://testcafe.io/documentation/402841/guides/intermediate-guides/multiple-browser-windows?search#header">not supported by all browsers</a>&nbsp;|&nbsp;
<strong id="table-features-5">5</strong> - <a target="_blank" rel="noopener" href="https://webdriver.io/docs/wdio-intercept-service/#supported-browsers">no specifics available</a>&nbsp;|&nbsp;
<strong id="table-features-6">6</strong> - but we couldn't make it work&nbsp;|&nbsp;
<strong id="table-features-7">7</strong> - endorces <a target="_blank" rel="noopener" href="https://webdriver.io/docs/wdio-video-reporter/">3rd party package</a>&nbsp;|&nbsp;
<strong id="table-features-8">8</strong> - <a target="_blank" rel="noopener" href="https://nightwatchjs.org/api/mockNetworkResponse.html#apimethod-container">not supported by all browsers</a>&nbsp;|&nbsp;
<strong id="table-features-9">9</strong> - Cypress <a target="_blank" rel="noopener" href="https://docs.cypress.io/api/plugins/browser-launch-api#Syntax">allows you to install extensions</a>, but you won't be able access the URL scheme <code>chrome-extension://...</code></p></small>
<br>
<p>Cypress and Playwright stand out with an almost perfect score in our feature table. The differences in the table might look minor, but there's a lot more to it. <strong>Cypress runs on the browser, which means the test scripts you write are embedded with the target application; hence it is very likely that Cypress will never support features such as multi-window orchestration</strong>. Another limitation (fixed recently) is that Cypress <a href="https://docs.cypress.io/guides/references/trade-offs#Same-origin" target="_blank" rel="noopener noreferrer" class="">can only visit same-origin domains</a>. <strong>That's not the case with Playwright; it runs on Node.js and interacts with the browser through APIs such as</strong> <a href="https://chromedevtools.github.io/devtools-protocol/" target="_blank" rel="noopener noreferrer" class=""><strong>Chrome Devtools Protocol</strong></a><strong>, bypassing Cypress limitations</strong>. How much value can Cypress deliver while running embedded in the browser? And how much of that will be unmatched by Playwright? Only time will tell.</p>
<p>We were surprised to learn that TestCafe and Webdriver.io are the browser support category's champ, but that won't be a differentiator for much longer now that <a href="https://docs.microsoft.com/en-us/lifecycle/products/internet-explorer-11" target="_blank" rel="noopener noreferrer" class="">Microsoft has finally sunsetted Internet Explorer</a>. Options such as Nightwatch.js and Playwright are now equally competitive in browser support.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="adoption--popularity">Adoption &amp; Popularity<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#adoption--popularity" class="hash-link" aria-label="Direct link to Adoption &amp; Popularity" title="Direct link to Adoption &amp; Popularity" translate="no">​</a></h3>
<table><thead><tr><th>Metric</th><th style="text-align:center">Cypress</th><th style="text-align:right">Nightwatch</th><th style="text-align:right">Playwright</th><th style="text-align:right">Puppeteer</th><th style="text-align:right">TestCafe</th><th style="text-align:right">Webd.io</th></tr></thead><tbody><tr><td><strong>GitHub stars</strong></td><td style="text-align:center">39k</td><td style="text-align:right">11k</td><td style="text-align:right">41k</td><td style="text-align:right">79k</td><td style="text-align:right">9k</td><td style="text-align:right">8k</td></tr><tr><td><strong>NPM downloads (per week)</strong></td><td style="text-align:center">4M</td><td style="text-align:right">169k</td><td style="text-align:right">742k</td><td style="text-align:right">3M</td><td style="text-align:right">251k</td><td style="text-align:right">366k</td></tr><tr><td><strong>Interest</strong> <small aria-describedby="table-popularity-2">[2]</small></td><td style="text-align:center">72%</td><td style="text-align:right">n/a <small aria-describedby="table-popularity-3">[3]</small></td><td style="text-align:right">70%</td><td style="text-align:right">58%</td><td style="text-align:right">n/a <small aria-describedby="table-popularity-3">[3]</small></td><td style="text-align:right">38%</td></tr><tr><td><strong>Usage</strong> <small aria-describedby="table-popularity-2">[2]</small></td><td style="text-align:center">42%</td><td style="text-align:right">n/a <small aria-describedby="table-popularity-3">[3]</small></td><td style="text-align:right">10%</td><td style="text-align:right">37%</td><td style="text-align:right">n/a <small aria-describedby="table-popularity-3">[3]</small></td><td style="text-align:right">10%</td></tr><tr><td><strong>Awareness</strong> <small aria-describedby="table-popularity-2">[2]</small></td><td style="text-align:center">83%</td><td style="text-align:right">n/a <small aria-describedby="table-popularity-3">[3]</small></td><td style="text-align:right">34%</td><td style="text-align:right">78%</td><td style="text-align:right">n/a <small aria-describedby="table-popularity-3">[3]</small></td><td style="text-align:right">27%</td></tr><tr><td><strong>Stack Overflow (questions tagged)</strong></td><td style="text-align:center">8k</td><td style="text-align:right">1k</td><td style="text-align:right">1k</td><td style="text-align:right">7k</td><td style="text-align:right">2k</td><td style="text-align:right">2k</td></tr><tr><td><strong>Twitter followers</strong></td><td style="text-align:center">20k</td><td style="text-align:right">3k</td><td style="text-align:right">5k</td><td style="text-align:right">- [4]</td><td style="text-align:right">2k</td><td style="text-align:right">4k</td></tr><tr><td><strong>Youtube subscribers</strong> [5]</td><td style="text-align:center">11k</td><td style="text-align:right">-</td><td style="text-align:right">2k</td><td style="text-align:right">- [4]</td><td style="text-align:right">-</td><td style="text-align:right">-</td></tr></tbody></table>
<small><p><strong id="table-popularity-1">1</strong> - absolute values are rounded&nbsp;|&nbsp;
<strong id="table-popularity-2">2</strong> - source is <a target="_blank" rel="noopener" href="https://2021.stateofjs.com/en-US/libraries/testing">2021.stateofjs.com</a>&nbsp;|&nbsp;
<strong id="table-popularity-3">3</strong> - technologies with less than 10% awareness not considered in the <a target="_blank" rel="noopener" href="https://2021.stateofjs.com/en-US/libraries/testing">2021.stateofjs.com</a>&nbsp;|&nbsp;
<strong id="table-popularity-4">4</strong> - dedicated social only. e.g., Puppeteer points to Chrome Developers, so we don't track it</p></small>
<br>
<p>Cypress has a good reputation, which means it will be around for a good while, whether you love it or hate it. Cypress has a broad social presence and a large community. We think Puppeteer scores well due to its broader scope as a library. An interesting observation on Webdriver.io is that despite the low levels of usage reported in the state of js survey, it has quite some traffic on npm; we believe this is due to native mobile developers using Webdriver.io to write tests. Most likely, mobile developers do not overlap with the respondents' group for the state of js survey.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="dx-developer-experience">DX (Developer Experience)<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#dx-developer-experience" class="hash-link" aria-label="Direct link to DX (Developer Experience)" title="Direct link to DX (Developer Experience)" translate="no">​</a></h3>
<table><thead><tr><th>Metric</th><th style="text-align:center">Cypress</th><th style="text-align:right">Nightwatch</th><th style="text-align:right">Playwright</th><th style="text-align:right">Puppeteer</th><th style="text-align:right">TestCafe</th><th style="text-align:right">Webd.io</th></tr></thead><tbody><tr><td><strong>Satisfaction</strong></td><td style="text-align:center">92%</td><td style="text-align:right">n/a <small aria-describedby="table-dx-1">[1]</small></td><td style="text-align:right">93%</td><td style="text-align:right">82%</td><td style="text-align:right">n/a <small aria-describedby="table-dx-1">[1]</small></td><td style="text-align:right">46%</td></tr><tr><td><strong>Would use again</strong></td><td style="text-align:center">37%</td><td style="text-align:right">n/a <small aria-describedby="table-dx-1">[1]</small></td><td style="text-align:right">16%</td><td style="text-align:right">30%</td><td style="text-align:right">n/a <small aria-describedby="table-dx-1">[1]</small></td><td style="text-align:right">9%</td></tr><tr><td><strong>Would not use again</strong></td><td style="text-align:center">4%</td><td style="text-align:right">n/a <small aria-describedby="table-dx-1">[1]</small></td><td style="text-align:right">1%</td><td style="text-align:right">7%</td><td style="text-align:right">n/a <small aria-describedby="table-dx-1">[1]</small></td><td style="text-align:right">11%</td></tr></tbody></table>
<small><p><strong id="table-dx-1">1</strong> - technologies with less than 10% awareness not considered in the <a target="_blank" rel="noopener" href="https://2021.stateofjs.com/en-US/libraries/testing">2021.stateofjs.com</a></p></small>
<br>
<br>
<p>We're happy to see that these numbers align with our experience. We <strong>believe onboarding and documentation are pilar to creating a good DX and reducing the learning curve</strong>. Another vital aspect that the two technologies (Cypress and Playwright), with the best DX scores, can't afford to miss is debugability. <strong>Functionalities such as stepping debuggers and friendly stack traces reduce friction, making developers less frustrated</strong>.</p>
<h3 class="anchor anchorTargetStickyNavbar_SgJR" id="maintenance">Maintenance<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#maintenance" class="hash-link" aria-label="Direct link to Maintenance" title="Direct link to Maintenance" translate="no">​</a></h3>
<table><thead><tr><th>Parameter</th><th style="text-align:center">Cypress</th><th style="text-align:right">Nightwatch</th><th style="text-align:right">Playwright</th><th style="text-align:right">Puppeteer</th><th style="text-align:right">TestCafe</th><th style="text-align:right">Webd.io</th></tr></thead><tbody><tr><td><strong>Backers</strong></td><td style="text-align:center">-</td><td style="text-align:right"><small>BrowserStack</small></td><td style="text-align:right"><small>Microsoft</small></td><td style="text-align:right"><small>Google</small></td><td style="text-align:right"><small>DevExpress</small></td><td style="text-align:right">-</td></tr><tr><td><strong>Recurrent contributors</strong> <small aria-describedby="table-maintenance-2">[2]</small></td><td style="text-align:center">2</td><td style="text-align:right">1</td><td style="text-align:right">4</td><td style="text-align:right">2 <small aria-describedby="table-maintenance-3">[3]</small></td><td style="text-align:right">3</td><td style="text-align:right">1</td></tr><tr><td><strong>Open issues</strong></td><td style="text-align:center">2k</td><td style="text-align:right">155</td><td style="text-align:right">602</td><td style="text-align:right">327</td><td style="text-align:right">390</td><td style="text-align:right">158</td></tr><tr><td><strong>Issue resolution time median</strong> <small aria-describedby="table-maintenance-1">[1]</small></td><td style="text-align:center">15 days</td><td style="text-align:right">9 days</td><td style="text-align:right">3 days</td><td style="text-align:right">21 days</td><td style="text-align:right">9 days</td><td style="text-align:right">12 hours</td></tr><tr><td><strong>Open pull requests</strong></td><td style="text-align:center">44</td><td style="text-align:right">20</td><td style="text-align:right">18</td><td style="text-align:right">14</td><td style="text-align:right">5</td><td style="text-align:right">6</td></tr><tr><td><strong>% Open issues &amp; pull requests (the lower the better)</strong> <small aria-describedby="table-maintenance-1">[1]</small></td><td style="text-align:center">38%</td><td style="text-align:right">12%</td><td style="text-align:right">21%</td><td style="text-align:right">18%</td><td style="text-align:right">16%</td><td style="text-align:right">4%</td></tr><tr><td><strong>Commits past month (across all branches)</strong></td><td style="text-align:center">343</td><td style="text-align:right">28</td><td style="text-align:right">363</td><td style="text-align:right">85</td><td style="text-align:right">23</td><td style="text-align:right">242</td></tr><tr><td><strong>Merged pull requests past month</strong></td><td style="text-align:center">105</td><td style="text-align:right">11</td><td style="text-align:right">355</td><td style="text-align:right">42</td><td style="text-align:right">42</td><td style="text-align:right">83</td></tr><tr><td><strong>Total contributors</strong></td><td style="text-align:center">378</td><td style="text-align:right">107</td><td style="text-align:right">266</td><td style="text-align:right">424</td><td style="text-align:right">113</td><td style="text-align:right">427</td></tr></tbody></table>
<small><p><strong id="table-maintenance-1">1</strong> - source is <a target="_blank" rel="noopener" href="https://isitmaintained.com/">isitmaintained.com</a>&nbsp;|&nbsp;
<strong id="table-maintenance-2">2</strong> - number of developers that signed ~10% or more of the total of commits to the framework's codebase&nbsp;|&nbsp;
<strong id="table-maintenance-3">3</strong> - one of the individuals that most contributed now works on Playwright</p></small>
<br>
<p><strong>Playwright has superior numbers here. The number of monthly commits and the average time for issue resolution indicates that the Playwright team is developing faster than others. On top of that is backed by Microsoft</strong>. We can not ignore that companies such as Cypress are more prone to impact during unstable economic periods.</p>
<p><strong>Another critical aspect is whether there are knowledge silos in the frameworks' core teams</strong>. A project primarily maintained by a single developer is at a higher risk of being discontinued. Life is unpredictable, and there are many reasons why that person would stop contributing to that project. <strong>Consider that Nightwatch.js and Webdriver.io run as a "one-person operation", while others have larger core teams behind the scenes</strong>.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="-predictions">🔮 Predictions<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#-predictions" class="hash-link" aria-label="Direct link to 🔮 Predictions" title="Direct link to 🔮 Predictions" translate="no">​</a></h2>
<p>This section is great because it will allow us to come back in a few years and understand how wrong we were.</p>
<ul>
<li class="">Conspiracy theory: With VSCode and the acquisition of GitHub, Microsoft has demonstrated to be investing strongly in the open source ecosystem for the past few years. We think that Microsoft could buy out Cypress.io to monopolize the JavaScript browser testing space; this could be another space for Microsoft to thrive (although, realistically, JavaScript testing frameworks feel too niche for a company like Microsoft).</li>
<li class="">Applications are increasingly complex; we think the restrictions imposed by Cypress will pave the road for Playwright to catch up in a year or two. We foresee the usage scores to go up for Playwright.</li>
<li class="">The <a href="https://nightwatchjs.org/blog/nightwatch-has-joined-the-browserstack-family/" target="_blank" rel="noopener noreferrer" class="">Browserstack acquisition of Nightwatch.js</a> will positively impact the project. Now backed by a larger tech organization with a powerful presence in the software testing industry, Nightwatch.js has the resources to thrive.</li>
<li class="">The <a href="https://docs.microsoft.com/en-us/lifecycle/products/internet-explorer-11" target="_blank" rel="noopener noreferrer" class="">discontinuation of Internet Explorer</a> means that TestCafe and Webdriver.io will lose the edge of broader browser compatibility; things even out in this category, leaving fewer excuses for developers not to adopt Cypress, Playwright, or even Nightwatch.js.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="️-conclusion-our-pick">⚖️ Conclusion: Our pick<a href="https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks#%EF%B8%8F-conclusion-our-pick" class="hash-link" aria-label="Direct link to ⚖️ Conclusion: Our pick" title="Direct link to ⚖️ Conclusion: Our pick" translate="no">​</a></h2>
<p><strong>The excellent DX, quick start and documentation make <a href="https://playwright.dev/" target="_blank" rel="noopener noreferrer" class="">Playwright</a> the best option at this time</strong>.</p>
<p>We hope this article becomes a good decision-making tool for you to pick the best JavaScript E2E testing framework.</p>
<p sx="[object Object]">If you liked this article, consider sharing (<a href="https://twitter.com/share?text=What%20a%20Google%20Search%20Can%27t%20Tell%20You%20About%20These%20JS%20Testing%20Frameworks&amp;url=https://tweak-extension.com/blog/comparison-e2e-javascript-testing-frameworks" target="_blank" rel="noreferrer" title="tweeting"><span style="text-decoration:underline">tweeting</span></a>) it to your followers.</p>
<br><hr><div class="buttons_rr6z"><h3>Did you like this article?</h3><div class="thumbs_zuU5"><button class="button button--outline button--primary"><span class="fa fa-thumbs-up"></span>&nbsp;<!-- -->Yes</button><button class="button button--outline button--primary"><span class="fa fa-thumbs-down"></span>&nbsp;<!-- -->No</button></div></div><small>Need something else? <a href="https://tally.so/r/VLzbl6" target="_blank">Request a feature</a></small><div class="message_SA7R" style="visibility:hidden"><span class="fa fa-bolt"></span>&nbsp; <i>Thanks for your feedback!</i></div>
<div></div>]]></content:encoded>
            <category>JavaScript</category>
            <category>Software Testing</category>
        </item>
        <item>
            <title><![CDATA[The Different Shades of Testing Web Apps: Aiming for Balance]]></title>
            <link>https://tweak-extension.com/blog/web-application-testing</link>
            <guid>https://tweak-extension.com/blog/web-application-testing</guid>
            <pubDate>Wed, 27 Jul 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[A practical guide to the different types of web application testing (unit, integration, and end-to-end) and how to strike the right balance.]]></description>
            <content:encoded><![CDATA[<p>It's 2022, and automation is on the rise. The number of software testing tools, libraries, and platforms available increases daily. What different aspects of web applications should you be testing? Which ones should you automate? And when and how should you employ manual testing?</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="testing-dimensions">Testing dimensions<a href="https://tweak-extension.com/blog/web-application-testing#testing-dimensions" class="hash-link" aria-label="Direct link to Testing dimensions" title="Direct link to Testing dimensions" translate="no">​</a></h2>
<p>Software testing has many dimensions, but talking specifically about frontend applications, developers are mainly concerned about:</p>
<ul>
<li class=""><strong>Functionality</strong> - does it work? Does the application react per my actions?</li>
<li class=""><strong>Visual</strong> - does it look good? Are things aligned?</li>
<li class=""><strong>Compatibility</strong> - does the app works seamlessly across all the different supported browsers and devices? Typically companies keep lists of support browsers and devices in publically accessible spaces.</li>
<li class=""><strong>Performance</strong> - does it load fast? Does it perform well on lower-end devices?</li>
<li class=""><strong>Security</strong> - are there any security holes introduced?</li>
<li class=""><strong>Accessibility</strong> - is the app accessible? Could a visually impaired user navigate and use the app?</li>
<li class=""><strong>Legal/Compliance</strong> - are we infringing any user rights laws (e.g., GDPR)? Do these apps make use of cookies and or other browser storage capabilities?</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="kinds-of-tests">Kinds of tests<a href="https://tweak-extension.com/blog/web-application-testing#kinds-of-tests" class="hash-link" aria-label="Direct link to Kinds of tests" title="Direct link to Kinds of tests" translate="no">​</a></h2>
<p>The above section focuses on dimensions (or categories). But within most categories, you will find various options to implement your tests. We will try to briefly go through the most prominent ones:</p>
<ul>
<li class=""><strong>Unit tests</strong> - are typically small and focused around a tinier piece of your code. Usually, run in isolation, which means they run in controlled environments which don't greatly reflect how real-world users interact with your product.</li>
<li class=""><strong>Integration tests</strong> - taking a step further from unit tests. Let us still focus on a particular part of the product. We stretch the scope of a unit test and introduce other components into play.</li>
<li class=""><strong>End-to-end tests</strong> - these should test the product as a whole, no more hiding. The software that runs these tests has the job of playing the role of the user, meaning actually simulating user interactions. Due to their nature, these are typically slower and, hence, more expensive than the two previous types.</li>
<li class=""><strong>Smoke tests</strong> - these are basic health checks for your products. A smoke test typically serves as a guiding light on whether your system is currently available. This is useful for the purposes of monitoring and alerting.</li>
</ul>
<div class="theme-admonition theme-admonition-tip admonition_mDP4 alert alert--success"><div class="admonitionHeading_Mfam"><span class="admonitionIcon_ba76"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_LzEm"><p>To deep dive here we highly recommend you to have a look at <a href="https://martinfowler.com/bliki/TestPyramid.html" target="_blank" rel="noopener noreferrer" class="">"The Test Pyramid" by Martin Fowler</a> to understand the trade-offs between these kinds of tests.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="tools">Tools<a href="https://tweak-extension.com/blog/web-application-testing#tools" class="hash-link" aria-label="Direct link to Tools" title="Direct link to Tools" translate="no">​</a></h2>
<p>That's a lot to take in! Let's see what tools are helping us cover most of the above.</p>
<ul>
<li class=""><strong>Functionality</strong> - typically covered through software testing automation. <a href="https://jestjs.io/" target="_blank" rel="noopener noreferrer" class="">Jest</a> (unit testing), <a href="https://www.cypress.io/" target="_blank" rel="noopener noreferrer" class="">Cypress</a>, <a href="https://playwright.dev/" target="_blank" rel="noopener noreferrer" class="">Playwright</a>, and <a href="https://pptr.dev/" target="_blank" rel="noopener noreferrer" class="">Puppeteer</a> (integration/e2e testing) have risen in popularity over the past years. In addition, no-code solutions have been a hot topic recently, so you will find emergent solutions such as <a href="https://katalon.com/" target="_blank" rel="noopener noreferrer" class="">katalon</a> in this space.</li>
<li class=""><strong>Visual</strong> - a group of tests that has gained more traction recently. We have <a href="https://storybook.js.org/docs/react/writing-tests/visual-testing" target="_blank" rel="noopener noreferrer" class="">Storybook (chromatic add-on)</a>, and <a href="https://github.com/mapbox/pixelmatch" target="_blank" rel="noopener noreferrer" class="">mpbox/pixelmatch</a> (with a Jest wrapper available <a href="https://github.com/americanexpress/jest-image-snapshot" target="_blank" rel="noopener noreferrer" class="">americanexpress/jest-image-snapshot</a>). Beyond libraries, you have platforms such as <a href="https://saucelabs.com/platform/visual-testing" target="_blank" rel="noopener noreferrer" class="">saucelabs</a> and <a href="https://applitools.com/" target="_blank" rel="noopener noreferrer" class="">applitools</a>, the latter more specialized in visual testing.</li>
<li class=""><strong>Compatibility</strong> - cross-device/browser testing could fit in the functionality bucket. Some of the previously mentioned tools will allow you to run your automation across different browsers, operative systems, and devices. If manual testing is required, <a href="https://www.browserstack.com/" target="_blank" rel="noopener noreferrer" class="">BrowserStack</a> is probably the leading tool offering a comprehensive list of device types and browsers that can be accessed on-demand through your browser (independently of your computer/OS. For compatibility (like many of the below dimensions), static code analysis might help prevent disasters. Tools such as <a href="https://github.com/amilajack/eslint-plugin-compat" target="_blank" rel="noopener noreferrer" class="">eslint-plugin-compat</a> allow developers to check for compatibility issues as they code.</li>
<li class=""><strong>Performance</strong> - <a href="https://github.com/GoogleChrome/lighthouse" target="_blank" rel="noopener noreferrer" class="">Google's lighthouse</a> is undoubtedly a big player in this field, allowing you to automate performance audits for your web applications. With the proper integration, you can spot performance degradation at each step.</li>
<li class=""><strong>Security</strong> - along with accessibility, one of the most neglected testing dimensions, has cost large corporations too much to ignore. We've seen the rise of platforms such as <a href="https://snyk.io/" target="_blank" rel="noopener noreferrer" class="">Snyk</a>. This can help you scan for vulnerabilities across your codebases to prevent malicious code from going out with your software. No wonder this space has seen a record-breaking <a href="https://techcrunch.com/2022/02/09/vc-cybersecurity-startups-record-year/" target="_blank" rel="noopener noreferrer" class="">2021 in cybersecurity startup investments</a>.</li>
<li class=""><strong>Accessibility</strong> - another neglected space where <a href="https://github.com/dequelabs/axe-core" target="_blank" rel="noopener noreferrer" class="">axe</a> seems to be the consensual option that powers many integrations. For example, you will find plugins to use the axe-core with libraries such as Jest or Playwright.</li>
<li class=""><strong>Legal/Compliance</strong> - with GDRP out to get you, it's crucial that you pay attention to details such as the use of cookies and user tracking. We are unaware of automation that could help you here, so if this concerns you, you'll probably have to outsource this to legal experts.</li>
</ul>
<p>Note that in the above list, some of the tools mentioned in one testing dimension cover much more.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="how-much-can-you-automate">How much can you automate?<a href="https://tweak-extension.com/blog/web-application-testing#how-much-can-you-automate" class="hash-link" aria-label="Direct link to How much can you automate?" title="Direct link to How much can you automate?" translate="no">​</a></h2>
<p>For your application to have fully automated checks, you will require not only the tools above but also consider:</p>
<ul>
<li class=""><strong>Money</strong> - many of these tools are free, others quite pricey. Regardless of pricing, if you work with teams, you need to have automated pipelines that run this for you hosted somewhere (e.g., GitHub actions), and these resources alone have costs.</li>
<li class=""><strong>Human resources</strong> - in line with money, you need people to put this automation in place and maintain them. Depending on your systems' complexity, you might require the assistance of well-paid experts.</li>
<li class=""><strong>Time</strong> - putting these systems in place takes time.</li>
</ul>
<p>Maybe you have good unit and functional tests that cover most of the cases of your application, but you don't have the expertise to run visual tests. Maybe you work for a big tech company with loads of cash, and you have all the mentioned above in your automation pipeline and other tools that the typical developer won't hear about until 2070. But yet, you're still releasing bugs from time to time. <strong>Finding the right balance between how much you can automate and how much human testing is required is the problem you should be focusing on</strong>.
Evaluate where you and your project/company stand across the different testing dimensions and try to craft the best strategy, but while at it, better to hold and advocate for a testing mindset for your team.</p>
<h2 class="anchor anchorTargetStickyNavbar_SgJR" id="when-you-cant-automate">When you can't automate<a href="https://tweak-extension.com/blog/web-application-testing#when-you-cant-automate" class="hash-link" aria-label="Direct link to When you can't automate" title="Direct link to When you can't automate" translate="no">​</a></h2>
<p>You'll often have to find ways to cover the gaps your automation might leave behind. Next, we'll present a list of different methods to get your product manually tested. You can combine multiple of them with your automation to optimize how much ground your team can cover.</p>
<ul>
<li class=""><strong>Quality assurance as a mandatory step</strong> - set up an approval process for code changes where any given developer must have their changes manually tested by a peer. Sometimes this is part of the code review process, meaning that a developer is responsible for accessing the code quality and approach through the standard review process and manually testing the code changes to approve a given code change (typically a pull/merge request). This is far better than having the code author test their own changes because authors can easily have blindspots caused by their familiarity with the functionality at hand, usually missing very obvious details that an "outsider" would immediately catch.</li>
<li class=""><strong>Have a checklist</strong> to make your developer's life easier that outlines every testing dimension your developer should care about, e.g., "Does the new code work in Safari? Does the new code respect our accessibility standards?". This list should complement your automation.</li>
<li class=""><strong>Dogfooding</strong> - another common way large organizations test their products nowadays is by using the product. Simple right? The idea of dogfooding is to integrate your own product as a mission-critical piece of your own team/company processes. Additionally, most companies will internally run a "beta" version of those products, meaning they purposely leave their customers a few versions behind to leave room for their staff to catch bugs while using the most recent version. This is a brilliant concept that everyone should seriously consider.</li>
<li class=""><strong>Assign a quality assurance person to your team</strong> - in an ideal world, you would have dedicated testers whose job is to create a bug barrier and assess every single code change before it reaches production.</li>
<li class=""><strong>Outsource</strong> - get outside help to perform the testing you need. You will find plenty of offers across the web from companies or freelancers to test your products.</li>
<li class=""><strong>Closed beta programs</strong> - ok, you don't have the funds to outsource just yet. You might want to trade off some of your customers and turn them into testers. This strategy is most commonly used to gather feedback from your users before launching a particular functionality, allowing you to work behind the scenes and iterate while the final product is not publically available. But why not also consider these users as your testing staff? You could leverage them by creating tools and communication channels that make them want to report issues to you.</li>
</ul>
<br>
<p>We hope this article helps you get the big picture of testing frontend applications and give you a couple of alternative ideas to complement your automated checks with some manual testing processes.</p>
<br>
<br>
<p sx="[object Object]">If you liked this article, consider sharing (<a href="https://twitter.com/share?text=The%20Different%20Shades%20of%20Testing%20Web%20Apps:%20Aiming%20for%20Balance&amp;url=https://tweak-extension.com/blog/web-application-testing" target="_blank" rel="noreferrer" title="tweeting"><span style="text-decoration:underline">tweeting</span></a>) it to your followers.</p>
<br><hr><div class="buttons_rr6z"><h3>Did you like this article?</h3><div class="thumbs_zuU5"><button class="button button--outline button--primary"><span class="fa fa-thumbs-up"></span>&nbsp;<!-- -->Yes</button><button class="button button--outline button--primary"><span class="fa fa-thumbs-down"></span>&nbsp;<!-- -->No</button></div></div><small>Need something else? <a href="https://tally.so/r/VLzbl6" target="_blank">Request a feature</a></small><div class="message_SA7R" style="visibility:hidden"><span class="fa fa-bolt"></span>&nbsp; <i>Thanks for your feedback!</i></div>]]></content:encoded>
            <category>Software Testing</category>
        </item>
    </channel>
</rss>