<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: codebeast</title>
    <description>The latest articles on DEV Community by codebeast (@xcodebeast).</description>
    <link>https://dev.to/xcodebeast</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4233477%2Fd61e572d-b615-41e2-93b2-00f2a0e2814c.png</url>
      <title>DEV Community: codebeast</title>
      <link>https://dev.to/xcodebeast</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/xcodebeast"/>
    <language>en</language>
    <item>
      <title>I made Playwright 3.5x faster 🔥</title>
      <dc:creator>codebeast</dc:creator>
      <pubDate>Fri, 13 Nov 2026 16:30:12 +0000</pubDate>
      <link>https://dev.to/xcodebeast/i-made-playwright-35x-faster-d1f</link>
      <guid>https://dev.to/xcodebeast/i-made-playwright-35x-faster-d1f</guid>
      <description>&lt;p&gt;I have a weird obsession with making stuff run faster, even when it seems practically impossible to do so, which was the case with Playwright.&lt;/p&gt;

&lt;p&gt;I thought most of my tests were slow because my app or the way I designed my tests sucked, so I took every measure I could to improve my e2e suite's speed. I saw a lot of improvements by simply "doing things right", like using data-testid selectors, running tests in parallel, caching frontend builds, seeding data efficiently, etc.&lt;/p&gt;

&lt;p&gt;Eventually, I hit a wall, and I started wondering how much of that wall was Playwright's fault. My first instinct, like any good vibecoder, was to ask Claude to rewrite the entire thing in Rust, to which he smartly replied that it would be pointless after running some benchmarks.&lt;/p&gt;

&lt;p&gt;I didn't know what to do, so I (and Claude) came up with a bunch of ideas for how to speed up tests, from preparing your next test run while the current one is running to skipping CSS animations. I had GPT 6 Astra write down 120 potential ideas for improving speed, of which only a few actually worked out without compromising functionality, in total I had 2 agents running everyday for almost an entire week. And this is the result:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flashwright&lt;/strong&gt;, a fork of Playwright that keeps the API almost identical while adding some performance tricks and QoL features.&lt;/p&gt;

&lt;h2&gt;
  
  
  I benchmarked it against Playwright across its own example suites and a bunch of other scenarios:
&lt;/h2&gt;

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

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

&lt;p&gt;It passes all &lt;strong&gt;2616/2616&lt;/strong&gt; tests from Playwright's own test suite, which means almost anyone can probably use it as a drop-in replacement.&lt;/p&gt;

&lt;p&gt;Here's the repo in case you're interested: &lt;a href="https://github.com/xcodebeast/flashwright" rel="noopener noreferrer"&gt;https://github.com/xcodebeast/flashwright&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>playwright</category>
      <category>testing</category>
      <category>automation</category>
    </item>
    <item>
      <title>I built the fastest e2e framework</title>
      <dc:creator>codebeast</dc:creator>
      <pubDate>Tue, 10 Nov 2026 19:31:10 +0000</pubDate>
      <link>https://dev.to/xcodebeast/i-built-the-fastest-e2e-framework-1pbk</link>
      <guid>https://dev.to/xcodebeast/i-built-the-fastest-e2e-framework-1pbk</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvz2tw2ewfyakjltm1dg4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvz2tw2ewfyakjltm1dg4.gif" alt="Playwright and Flashwright running the same 24 tests side by side: Playwright takes 3.65 s, Flashwright 1.05 s" width="720" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's Playwright's TodoMVC example, 24 tests, same machine, same &lt;code&gt;npx playwright test&lt;/code&gt;. Left: 3.65 s. Right: 1.05 s.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;Flashwright&lt;/strong&gt;, a fork of Playwright that keeps its API intact while making it blazingly fast!&lt;/p&gt;

&lt;p&gt;You can find below benchmarks for nine frameworks on one suite, 18 Playwright scenarios head to head and what I did to make it faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Swap it in
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i -D @playwright/test@npm:flashwright-test
npx playwright install chromium
npx playwright &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Nine frameworks, one suite
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftsf5tywtp68ryaviqj8v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftsf5tywtp68ryaviqj8v.png" alt="The same 24 TodoMVC tests in 9 frameworks; Flashwright is the fastest with 1 and 4 workers" width="799" height="628"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;1 worker&lt;/th&gt;
&lt;th&gt;4 workers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Flashwright&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.41 s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.54 s&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bun test + Bun.WebView&lt;/td&gt;
&lt;td&gt;4.39 s&lt;/td&gt;
&lt;td&gt;2.80 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Playwright&lt;/td&gt;
&lt;td&gt;4.63 s&lt;/td&gt;
&lt;td&gt;3.12 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Selenium + Mocha&lt;/td&gt;
&lt;td&gt;5.48 s&lt;/td&gt;
&lt;td&gt;2.77 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Puppeteer + Jest&lt;/td&gt;
&lt;td&gt;6.29 s&lt;/td&gt;
&lt;td&gt;2.98 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nightwatch&lt;/td&gt;
&lt;td&gt;6.45 s&lt;/td&gt;
&lt;td&gt;3.38 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WebdriverIO&lt;/td&gt;
&lt;td&gt;10.57 s&lt;/td&gt;
&lt;td&gt;4.91 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cypress&lt;/td&gt;
&lt;td&gt;17.29 s&lt;/td&gt;
&lt;td&gt;17.37 s (one spec at a time without Cypress Cloud)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TestCafe&lt;/td&gt;
&lt;td&gt;22.55 s&lt;/td&gt;
&lt;td&gt;9.28 s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;TodoMVC is tiny, so this is mostly measuring the framework. On a slow app the gap could be a smaller.&lt;/p&gt;

&lt;h2&gt;
  
  
  Playwright's own benches
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdh1mzuh7x79qtgi6yn2n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdh1mzuh7x79qtgi6yn2n.png" alt="Wall-clock time of 18 scenarios, Playwright vs Flashwright; Flashwright is 2.04× to 4.01× faster in each" width="800" height="704"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At least &lt;strong&gt;2× everywhere&lt;/strong&gt;, &lt;strong&gt;2.86×&lt;/strong&gt; on average. Whole &lt;code&gt;test&lt;/code&gt; command, median of 15 alternating runs, headless Chromium, warm session off (CI mode). Test code untouched.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Workers&lt;/th&gt;
&lt;th&gt;Playwright&lt;/th&gt;
&lt;th&gt;Flashwright&lt;/th&gt;
&lt;th&gt;Speedup&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TodoMVC (24 tests)&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;3670 ms&lt;/td&gt;
&lt;td&gt;1011 ms&lt;/td&gt;
&lt;td&gt;3.63×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TodoMVC&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;1812 ms&lt;/td&gt;
&lt;td&gt;734 ms&lt;/td&gt;
&lt;td&gt;2.47×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Click + assertion (15 tests)&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1611 ms&lt;/td&gt;
&lt;td&gt;402 ms&lt;/td&gt;
&lt;td&gt;4.01×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Suite with real failures&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;4334 ms&lt;/td&gt;
&lt;td&gt;1154 ms&lt;/td&gt;
&lt;td&gt;3.76×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shop app (setup project, 40 ms API)&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;6297 ms&lt;/td&gt;
&lt;td&gt;2967 ms&lt;/td&gt;
&lt;td&gt;2.12×&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Strip out app and server time and Flashwright spends &lt;strong&gt;3–4.5×&lt;/strong&gt; less than Playwright on framework overhead. Reproduce: &lt;code&gt;node bench/matrix.mjs 15&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the time went
&lt;/h2&gt;

&lt;p&gt;Most of a "fast" e2e test isn't your test. It's setup, waiting, and starting over.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Warm context, fresh tab.&lt;/strong&gt; Playwright opens a new browser context per test, so V8 compiles your app again and again. We keep one context per worker and give each test a new tab, then reset cookies, storage, routes, permissions, downloads, clock, the lot, before the next test. Want Playwright isolation back? &lt;code&gt;isolation: 'strict'&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Waits that listen.&lt;/strong&gt; Auto-wait used 20–500 ms backoff. We re-check as soon as the page moves. If nothing on the page can still change the DOM (no timers, requests, navigation, animation, workers), failing assertions bail immediately. That failure suite: 4334 ms → 1154 ms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Input without frame tax.&lt;/strong&gt; Clicks and hovers don't wait for animations to finish. Hit-target checks still block clicks on the wrong element.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start work before you need it.&lt;/strong&gt; Workers and browsers spin up while the CLI reads config. Idle spares hold the context the next test wants. After a failure, a spare is already warm. Slow tests from last run go first when you've got parallelism.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cheaper cold start.&lt;/strong&gt; V8 code cache on our bundles, lazy load what this run doesn't need, fewer round trips per action, leaner page scripts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Screenshots.&lt;/strong&gt; Faster PNG encode (same pixels). &lt;code&gt;toHaveScreenshot()&lt;/code&gt; baselines stay byte-identical to Playwright.&lt;/p&gt;

&lt;h2&gt;
  
  
  Designed for agentic workflows
&lt;/h2&gt;

&lt;p&gt;Agents don't run the whole suite once. They edit, run one test, edit, run again. Outside CI we keep a &lt;strong&gt;warm session&lt;/strong&gt;: runner, workers, and browsers stay up for five minutes after the last run, contexts reset, renderers warm.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Run, 1.5 s after the previous&lt;/th&gt;
&lt;th&gt;Playwright&lt;/th&gt;
&lt;th&gt;Flashwright&lt;/th&gt;
&lt;th&gt;+ warm session&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;One TodoMVC test&lt;/td&gt;
&lt;td&gt;673 ms&lt;/td&gt;
&lt;td&gt;240 ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;76 ms (8.9×)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TodoMVC suite, 4 workers&lt;/td&gt;
&lt;td&gt;1804 ms&lt;/td&gt;
&lt;td&gt;728 ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;508 ms (3.6×)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Fresh processes each run so config and env changes still land. &lt;code&gt;FLASHWRIGHT_SESSION=0&lt;/code&gt; kills it. CI keeps it off.&lt;/p&gt;

&lt;p&gt;MCP: &lt;code&gt;playwright mcp --adaptive-settle&lt;/code&gt; returns when the page is done, not after a fixed 500 ms. One save-through-API click: 1014 ms → 234 ms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dial it back to Playwright when you need to
&lt;/h2&gt;

&lt;p&gt;Defaults favor speed. Per project, file, or &lt;code&gt;describe&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;testOrder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'file'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;waitForAnimations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;failFastWhenIdle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;instantAnimations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;blockResources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'image'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'font'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'media'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More knobs (&lt;code&gt;isolation: 'strict'&lt;/code&gt;, &lt;code&gt;workersPerProcess&lt;/code&gt;, &lt;code&gt;locatorPolicy: 'test-id'&lt;/code&gt;, etc.) and measured effects are in the README.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compatibility
&lt;/h2&gt;

&lt;p&gt;I ran it against Playwright 1.64.1 on the same box: &lt;code&gt;tests/page&lt;/code&gt; 2616/2616 on Chromium, playwright-test / mcp / electron / extension parity, library parity except two internal bookkeeping tests that see recycled contexts, stress 1100/1100 in &lt;strong&gt;20 s vs 49 s&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Repo and benches: &lt;a href="https://github.com/xcodebeast/flashwright" rel="noopener noreferrer"&gt;https://github.com/xcodebeast/flashwright&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://flashwright.dev/" rel="noopener noreferrer"&gt;https://flashwright.dev/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;npm: &lt;code&gt;flashwright-test&lt;/code&gt;, &lt;code&gt;flashwright&lt;/code&gt;, &lt;code&gt;flashwright-core&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you throw it at a real suite, tell me the before/after. Especially anything that diverges from Playwright. GitHub issues are open.&lt;/p&gt;

</description>
      <category>playwright</category>
      <category>testing</category>
      <category>javascript</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
