<?xml version="1.0"?><feed xmlns:media="http://search.yahoo.com/mrss/" xmlns:gr="http://www.google.com/schemas/reader/atom/" xmlns:idx="urn:atom-extension:indexing" xmlns="http://www.w3.org/2005/Atom" idx:index="no" gr:dir="ltr"><!--
Content-type: Preventing XSRF in IE.

--><generator uri="https://bazqux.com">BazQux Reader</generator><id>tag:google.com,2005:reader/feed/http://007unlicensedtotest.blogspot.com/feeds/posts/default</id><title>blogs</title><subtitle type="html">blogs</subtitle><link rel="self" href="https://bazqux.com/feed/d45a6ead98c5f8f9f99f?no_branding"></link><gr:continuation>5725191405590</gr:continuation><updated>2026-08-09T16:47:07Z</updated><entry gr:crawl-timestamp-msec="1786287600000"><id gr:original-id="https://thenewstack.io/?p=22833031">tag:google.com,2005:reader/item/00000b0e000000b9</id><category term="AI Agents"></category><category term="AI Engineering"></category><category term="Software Testing"></category><category term="sponsor-clickhouse"></category><category term="sponsored-post-contributed"></category><title type="html">Coding agents can be evaluated. We just have to evaluate the work.</title><published>2026-08-09T15:00:00Z</published><updated>2026-08-09T15:00:00Z</updated><link rel="alternate" href="https://thenewstack.io/evaluating-coding-agents-framework/" type="text/html"></link><summary type="html">Stop grading coding agents like chatbots. Here is how to evaluate non-deterministic AI agents using executable contracts and scorecards.</summary><author><name>Pete Hampton</name></author><source gr:stream-id="feed/https://thenewstack.io/software-testing/feed/"><id>tag:google.com,2005:reader/feed/https://thenewstack.io/software-testing/feed/</id><title type="html">Software Testing Archives - The New Stack</title><link rel="alternate" href="https://thenewstack.io/software-testing/" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1786282502993"><id gr:original-id="https://www.thegreenreport.blog/?t=1786286802">tag:google.com,2005:reader/item/00000861000000a4</id><category term="javascript"></category><category term="playwright"></category><category term="qa"></category><category term="database"></category><category term="web"></category><title type="html">The Invisible Difference: Unicode Normalization in Test Assertions</title><published>2026-08-09T13:35:02Z</published><updated>2026-08-09T13:35:02Z</updated><link rel="alternate" href="https://www.thegreenreport.blog/articles/the-invisible-difference-unicode-normalization-in-test-assertions/the-invisible-difference-unicode-normalization-in-test-assertions.html" type="text/html"></link><summary type="html">Every so often a test fails with a diff you cannot see. The expected value and the actual value are printed one above the other, they are character for character the...</summary><author><name></name></author><source gr:stream-id="feed/https://www.thegreenreport.blog/resources/xml/feeds.xml"><id>tag:google.com,2005:reader/feed/https://www.thegreenreport.blog/resources/xml/feeds.xml</id><title type="html">The Green Report | Quality Assurance Blog</title><link rel="alternate" href="https://www.thegreenreport.blog/" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1786254108000"><id gr:original-id="http://testingideas.wordpress.com/?p=1996">tag:google.com,2005:reader/item/0000053500000017</id><category term="Testing"></category><title type="html">Humans Are the New Middleware</title><published>2026-08-09T05:41:48Z</published><updated>2026-08-09T05:41:48Z</updated><link rel="alternate" href="https://testingideas.wordpress.com/2026/08/09/humans-are-the-new-middleware/" type="text/html"></link><summary type="html">A meeting ends. Nobody took notes. The AI did. The transcript lands in someone’s inbox, they glance at the length, forward it to another AI, and ask for a proper document. Four pages come out. They forward that too. The recipient sees four pages, sighs, and asks their AI to summarise it. Three bullets come … &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://testingideas.wordpress.com/2026/08/09/humans-are-the-new-middleware/&quot;&gt;Continue reading &lt;span&gt;Humans Are the New Middleware&lt;/span&gt; &lt;span&gt;→&lt;/span&gt;&lt;/a&gt;</summary><author><name>Dhanasekar Subramaniam</name></author><source gr:stream-id="feed/https://testingideas.wordpress.com/feed/"><id>tag:google.com,2005:reader/feed/https://testingideas.wordpress.com/feed/</id><title type="html">The Pragmatist</title><link rel="alternate" href="https://testingideas.wordpress.com" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1786204786000"><id gr:original-id="6a77506cbc9ca900014a8a9d">tag:google.com,2005:reader/item/0000071a000000f6</id><category term="Puzzle"></category><title type="html">Puzzle 40b</title><published>2026-08-08T15:59:46Z</published><updated>2026-08-08T15:59:46Z</updated><link rel="alternate" href="https://www.workroom-productions.com/puzzle-040b/" type="text/html"></link><summary type="html">&lt;section id=&quot;article-jKZAnjgThqUyeaL-LYCMJlpRRIg-puzzle040UI&quot;&gt;
			&lt;div id=&quot;article-jKZAnjgThqUyeaL-LYCMJlpRRIg-lamp1&quot;&gt;&lt;/div&gt;
			&lt;div id=&quot;article-jKZAnjgThqUyeaL-LYCMJlpRRIg-lamp2&quot;&gt;&lt;/div&gt;
			&lt;div id=&quot;article-jKZAnjgThqUyeaL-LYCMJlpRRIg-lamp3&quot;&gt;&lt;/div&gt;
			&lt;div id=&quot;article-jKZAnjgThqUyeaL-LYCMJlpRRIg-lamp4&quot;&gt;&lt;/div&gt;
			&lt;div id=&quot;article-jKZAnjgThqUyeaL-LYCMJlpRRIg-lamp8&quot;&gt;&lt;/div&gt;
			&lt;div id=&quot;article-jKZAnjgThqUyeaL-LYCMJlpRRIg-lamp7&quot;&gt;&lt;/div&gt;
			&lt;div id=&quot;article-jKZAnjgThqUyeaL-LYCMJlpRRIg-lamp6&quot;&gt;&lt;/div&gt;
			&lt;div id=&quot;article-jKZAnjgThqUyeaL-LYCMJlpRRIg-lamp5&quot;&gt;&lt;/div&gt;
			&lt;button tabindex=&quot;-1&quot; id=&quot;article-jKZAnjgThqUyeaL-LYCMJlpRRIg-button1&quot;&gt;&lt;/button&gt;
			&lt;button tabindex=&quot;-1&quot; id=&quot;article-jKZAnjgThqUyeaL-LYCMJlpRRIg-button3&quot;&gt;&lt;/button&gt;
			&lt;button tabindex=&quot;-1&quot; id=&quot;article-jKZAnjgThqUyeaL-LYCMJlpRRIg-button5&quot;&gt;&lt;/button&gt;
			&lt;button tabindex=&quot;-1&quot; id=&quot;article-jKZAnjgThqUyeaL-LYCMJlpRRIg-button7&quot;&gt;&lt;/button&gt;
			&lt;button tabindex=&quot;-1&quot; id=&quot;article-jKZAnjgThqUyeaL-LYCMJlpRRIg-button2&quot;&gt;&lt;/button&gt;
			&lt;button tabindex=&quot;-1&quot; id=&quot;article-jKZAnjgThqUyeaL-LYCMJlpRRIg-button4&quot;&gt;&lt;/button&gt;
			&lt;button tabindex=&quot;-1&quot; id=&quot;article-jKZAnjgThqUyeaL-LYCMJlpRRIg-button6&quot;&gt;&lt;/button&gt;
			&lt;button tabindex=&quot;-1&quot; id=&quot;article-jKZAnjgThqUyeaL-LYCMJlpRRIg-button8&quot;&gt;&lt;/button&gt;
&lt;/section&gt;



&lt;section&gt;

&lt;img class=&quot;bqrUnknownImgSize&quot; src=&quot;https://storage.ghost.io/c/7e/30/7e30843b-2abb-494a-ab80-0e931d8ae9a9/content/images/2026/08/puzzle040.jpg&quot; alt=&quot;Puzzle 40b&quot;&gt;&lt;p&gt;Describe how the buttons affect the lamps. &lt;/p&gt;&lt;p&gt;This version has a single meaningful change from &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.workroom-productions.com/puzzle-040/&quot; rel=&quot;noreferrer&quot;&gt;Puzzle 40&lt;/a&gt; – you could use &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.workroom-productions.com/diff-for-testers/&quot; rel=&quot;noreferrer&quot;&gt;&lt;code&gt;diff&lt;/code&gt;&lt;/a&gt; to find it, you could look at the behaviours, you could think of somewhere I might easily have dropped in a meaningful change that doesn&amp;apos;t quite get picked up by typical validation tests. You could ask, of course. &lt;/p&gt;&lt;p&gt;I don&amp;apos;t typically put bugs in. This change is intentional, so arguably it isn&amp;apos;t a bug. But the behaviour it introduces does, in some sense, break the symmetry of what you might have found in 40. Off we go then.&lt;/p&gt;

&lt;details id=&quot;article-jKZAnjgThqUyeaL-LYCMJlpRRIg-patreons&quot; style=&quot;margin-bottom: 1.5rem&quot; closed&gt;&lt;summary&gt;&lt;h3&gt;Currently supported by these lovely people&lt;/h3&gt;&lt;/summary&gt;

&lt;p&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://talent-unleashed.com&quot;&gt;&lt;strong&gt;&lt;em&gt;Julie Gardiner&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;, &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://smallsheds.garden&quot;&gt;&lt;strong&gt;&lt;em&gt;Joep Schuurkes&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;, &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://huibschoots.nl/about-me/&quot;&gt;&lt;strong&gt;Huib Schoots&lt;/strong&gt;&lt;/a&gt;, &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.linkedin.com/in/koopside/?lipi=urn%3Ali%3Apage%3Ad_flagship3_search_srp_people%3BXWQgAmL6QD%2BrTEFLDXdF4g%3D%3D&quot;&gt;&lt;em&gt;Ide Koops&lt;/em&gt;&lt;/a&gt;, &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.linkedin.com/in/kriscorbus/&quot;&gt;&lt;em&gt;Kris Corbus&lt;/em&gt;&lt;/a&gt;, &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.eviltester.com&quot;&gt;Alan Richardson&lt;/a&gt;, Rob van Steenbergen, Ioana Chiorean, Peter Houghton, Adun Urke, Christine Yen, Pascal Dufour all support me on &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.patreon.com/workroomprds&quot;&gt;Patreon&lt;/a&gt;. &lt;/p&gt;&lt;p&gt;Help me make more and I&amp;apos;ll put your name on this list. There are other perks, too, eventually.&lt;/p&gt;

&lt;/details&gt;



			&lt;section id=&quot;article-jKZAnjgThqUyeaL-LYCMJlpRRIg-supportMore&quot;&gt;
				&lt;p&gt;Enjoy this? &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.patreon.com/workroomprds&quot;&gt;Support another!&lt;/a&gt;&lt;/p&gt;
			&lt;/section&gt;
			&lt;div&gt;
				&lt;p&gt;Built by James Lyndsay - &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://twitter.com/workroomprds&quot;&gt;@workroomprds&lt;/a&gt;&lt;/p&gt;
				&lt;p id=&quot;article-jKZAnjgThqUyeaL-LYCMJlpRRIg-copyright&quot;&gt;© Workroom Productions 2026&lt;/p&gt;&lt;/div&gt;&lt;/section&gt;</summary><author><name>James Lyndsay</name></author><source gr:stream-id="feed/https://www.workroom-productions.com/rss/"><id>tag:google.com,2005:reader/feed/https://www.workroom-productions.com/rss/</id><title type="html">Workroom Productions</title><link rel="alternate" href="https://www.workroom-productions.com/" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1786203966986"><id gr:original-id="tag:blogger.com,1999:blog-3033838173445667449.post-2262307056031943527">tag:google.com,2005:reader/item/000001a60000002c</id><title type="html">ESP32-C3 supermini</title><published>2026-08-08T15:46:06Z</published><updated>2026-08-08T15:46:06Z</updated><link rel="alternate" href="https://softcircuitry.blogspot.com/2026/08/esp32-c3-supermini.html" type="text/html"></link><summary type="html">&lt;p&gt; I used one of these recently for a single one-shot timer. For a simple timer with one I/O pin the supermini is even overkill because it has about 8 I/O pins most of them usable for anything and BT + wifi. &lt;/p&gt;&lt;p&gt;I did not use the wifi for my timer and did not disable it, so maybe I should do that now.&lt;/p&gt;&lt;p&gt;Here is a list of pins to not connect to peripherals that might pull them into states the prevent booting&lt;/p&gt;&lt;div align=&quot;left&quot; dir=&quot;ltr&quot; style=&quot;margin-left: 0pt&quot;&gt;&lt;table style=&quot;border-collapse: collapse; border-color: currentcolor; border-image: none; border-style: none; border-width: medium; border: none&quot;&gt;&lt;colgroup&gt;&lt;col width=&quot;88&quot;&gt;&lt;col width=&quot;236&quot;&gt;&lt;/colgroup&gt;&lt;tbody&gt;&lt;tr style=&quot;height: 24.75pt&quot;&gt;&lt;td style=&quot;background-color: #f6f7fa; border-bottom: 0.681818pt solid rgb(231, 232, 237); overflow-wrap: break-word; overflow: hidden; padding: 6pt 11pt; vertical-align: top&quot;&gt;&lt;p dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt&quot;&gt;&lt;span face=&quot;Arial,sans-serif&quot; style=&quot;background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre&quot;&gt;Pin&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f6f7fa; border-bottom: 0.681818pt solid rgb(231, 232, 237); overflow-wrap: break-word; overflow: hidden; padding: 6pt 11pt; vertical-align: top&quot;&gt;&lt;p dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt&quot;&gt;&lt;span face=&quot;Arial,sans-serif&quot; style=&quot;background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre&quot;&gt;Affect on the boot up&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 30pt&quot;&gt;&lt;td style=&quot;background-color: white; border-bottom: 0.681818pt solid rgb(231, 232, 237); border-top: 0.681818pt solid rgb(231, 232, 237); overflow-wrap: break-word; overflow: hidden; padding: 7pt 11pt; vertical-align: top&quot;&gt;&lt;p dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt&quot;&gt;&lt;span face=&quot;Arial,sans-serif&quot; style=&quot;background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre&quot;&gt;GPIO2&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;background-color: white; border-bottom: 0.681818pt solid rgb(231, 232, 237); border-top: 0.681818pt solid rgb(231, 232, 237); overflow-wrap: break-word; overflow: hidden; padding: 7pt 11pt; vertical-align: top&quot;&gt;&lt;p dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt&quot;&gt;&lt;span face=&quot;Arial,sans-serif&quot; style=&quot;background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre&quot;&gt;If low, normal flash boot may fail&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 30pt&quot;&gt;&lt;td style=&quot;background-color: white; border-bottom: 0.681818pt solid rgb(231, 232, 237); border-top: 0.681818pt solid rgb(231, 232, 237); overflow-wrap: break-word; overflow: hidden; padding: 7pt 11pt; vertical-align: top&quot;&gt;&lt;p dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt&quot;&gt;&lt;span face=&quot;Arial,sans-serif&quot; style=&quot;background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre&quot;&gt;GPIO8&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;background-color: white; border-bottom: 0.681818pt solid rgb(231, 232, 237); border-top: 0.681818pt solid rgb(231, 232, 237); overflow-wrap: break-word; overflow: hidden; padding: 7pt 11pt; vertical-align: top&quot;&gt;&lt;p dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt&quot;&gt;&lt;span face=&quot;Arial,sans-serif&quot; style=&quot;background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre&quot;&gt;If low, flashing/boot may not fail&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 41.25pt&quot;&gt;&lt;td style=&quot;background-color: white; border-bottom: 0.681818pt solid rgb(231, 232, 237); border-top: 0.681818pt solid rgb(231, 232, 237); overflow-wrap: break-word; overflow: hidden; padding: 7pt 11pt; vertical-align: top&quot;&gt;&lt;p dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt&quot;&gt;&lt;span face=&quot;Arial,sans-serif&quot; style=&quot;background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre&quot;&gt;GPIO9&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;background-color: white; border-bottom: 0.681818pt solid rgb(231, 232, 237); border-top: 0.681818pt solid rgb(231, 232, 237); overflow-wrap: break-word; overflow: hidden; padding: 7pt 11pt; vertical-align: top&quot;&gt;&lt;p dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt&quot;&gt;&lt;span face=&quot;Arial,sans-serif&quot; style=&quot;background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre&quot;&gt;If low normal flash boot may fail&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; style=&quot;margin-left: auto; margin-right: auto&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh10OOi7KOJYR2J0Racdc5_MLuVwnlNqmpXgDqnHn-nRYyOjGNehFiLut4BCh2MzDzt5AnLiMoaxS-NV05aaF4eI4x9c5HaCxWb2hUAaZE0v3hr0r5IzCkIv7PU0A4jygdVbTf1H-A9S8RjfITyVCSgRKSJoGkNc7KVyjuCt8onDytFFuk9Aujh3WaYsdk/s1020/esp32%20a.png&quot; style=&quot;margin-left: auto; margin-right: auto&quot;&gt;&lt;img width=&quot;640&quot; height=&quot;286&quot; style=&quot;border: 0px solid black&quot; data-original-height=&quot;456&quot; data-original-width=&quot;1020&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh10OOi7KOJYR2J0Racdc5_MLuVwnlNqmpXgDqnHn-nRYyOjGNehFiLut4BCh2MzDzt5AnLiMoaxS-NV05aaF4eI4x9c5HaCxWb2hUAaZE0v3hr0r5IzCkIv7PU0A4jygdVbTf1H-A9S8RjfITyVCSgRKSJoGkNc7KVyjuCt8onDytFFuk9Aujh3WaYsdk/w640-h286/esp32%20a.png&quot;&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center&quot;&gt;From below&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br&gt;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; style=&quot;margin-left: auto; margin-right: auto&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi41iagqO4Gu6qg1aQKC8J6i1cg1Moftj82vkqvSYGjRDSgH2iq9yoWuJmrila0iURQ_TdUfUXm4VtxlwCpQTF-LBM6NilaOFxIH9F06U0UBNDYtNOue-5CKoBPd7-T1AVruWfu6JlJzTwP6b2pHRF7_arvdHvEJ0az2LmIenPcKDVJ0XCnBdZzqlMjY7w/s974/esp32%20b.png&quot; style=&quot;margin-left: auto; margin-right: auto&quot;&gt;&lt;img width=&quot;640&quot; height=&quot;301&quot; style=&quot;border: 0px solid black&quot; data-original-height=&quot;458&quot; data-original-width=&quot;974&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi41iagqO4Gu6qg1aQKC8J6i1cg1Moftj82vkqvSYGjRDSgH2iq9yoWuJmrila0iURQ_TdUfUXm4VtxlwCpQTF-LBM6NilaOFxIH9F06U0UBNDYtNOue-5CKoBPd7-T1AVruWfu6JlJzTwP6b2pHRF7_arvdHvEJ0az2LmIenPcKDVJ0XCnBdZzqlMjY7w/w640-h301/esp32%20b.png&quot;&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center&quot;&gt;From above&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;/p&gt;&lt;h3 style=&quot;text-align: left&quot;&gt;Simple one-shot timer sketch&lt;/h3&gt;&lt;span id=&quot;article-JU0yqD0ubrscEVZEvdt0FZgEggg-docs-internal-guid-6bb9529e-7fff-7162-86dc-c9da660d7fb7&quot;&gt;&lt;/span&gt;&lt;p&gt;&lt;/p&gt;&lt;div style=&quot;background-color: white; color: #4e5b61; font-family: Consolas, &amp;quot;Courier New&amp;quot;, monospace; font-size: 14px; white-space: pre&quot;&gt;&lt;div&gt;&lt;span style=&quot;color: #00979d&quot;&gt;void&lt;/span&gt; &lt;span style=&quot;color: #d35400&quot;&gt;setup&lt;/span&gt;&lt;span style=&quot;color: #434f54&quot;&gt;()&lt;/span&gt; &lt;span style=&quot;color: #434f54&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #95a5a6&quot;&gt;  // put your setup code here, to run once:&lt;/span&gt;&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;span style=&quot;color: #95a5a6&quot;&gt;  // after power up wait a while, turn on output, wait then turn output off and go to sleep&lt;/span&gt;&lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #d35400&quot;&gt;pinMode&lt;/span&gt;&lt;span style=&quot;color: #434f54&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #005c5f&quot;&gt;8&lt;/span&gt;, INPUT&lt;span style=&quot;color: #434f54&quot;&gt;)&lt;/span&gt;;&lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #d35400&quot;&gt;delay&lt;/span&gt;&lt;span style=&quot;color: #434f54&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #005c5f&quot;&gt;8000&lt;/span&gt;&lt;span style=&quot;color: #434f54&quot;&gt;)&lt;/span&gt;;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #434f54&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #00979d&quot;&gt;int&lt;/span&gt; once = &lt;span style=&quot;color: #005c5f&quot;&gt;1&lt;/span&gt;;&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;span style=&quot;color: #00979d&quot;&gt;void&lt;/span&gt; &lt;span style=&quot;color: #d35400&quot;&gt;loop&lt;/span&gt;&lt;span style=&quot;color: #434f54&quot;&gt;()&lt;/span&gt; &lt;span style=&quot;color: #434f54&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #95a5a6&quot;&gt;  // put your main code here, to run repeatedly:&lt;/span&gt;&lt;/div&gt;&lt;br&gt;&lt;div&gt;  &lt;span style=&quot;color: #728e00&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #434f54&quot;&gt;(&lt;/span&gt;once&lt;span style=&quot;color: #434f54&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #434f54&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #d35400&quot;&gt;delay&lt;/span&gt;&lt;span style=&quot;color: #434f54&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #005c5f&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color: #434f54&quot;&gt;)&lt;/span&gt;;&lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #d35400&quot;&gt;pinMode&lt;/span&gt;&lt;span style=&quot;color: #434f54&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #005c5f&quot;&gt;8&lt;/span&gt;, OUTPUT&lt;span style=&quot;color: #434f54&quot;&gt;)&lt;/span&gt;;&lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #d35400&quot;&gt;digitalWrite&lt;/span&gt;&lt;span style=&quot;color: #434f54&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #005c5f&quot;&gt;8&lt;/span&gt;, LOW&lt;span style=&quot;color: #434f54&quot;&gt;)&lt;/span&gt;;&lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #d35400&quot;&gt;delay&lt;/span&gt;&lt;span style=&quot;color: #434f54&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #005c5f&quot;&gt;300&lt;/span&gt;&lt;span style=&quot;color: #434f54&quot;&gt;)&lt;/span&gt;;&lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #d35400&quot;&gt;digitalWrite&lt;/span&gt;&lt;span style=&quot;color: #434f54&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #005c5f&quot;&gt;8&lt;/span&gt;, HIGH&lt;span style=&quot;color: #434f54&quot;&gt;)&lt;/span&gt;;&lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #d35400&quot;&gt;pinMode&lt;/span&gt;&lt;span style=&quot;color: #434f54&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #005c5f&quot;&gt;8&lt;/span&gt;, INPUT&lt;span style=&quot;color: #434f54&quot;&gt;)&lt;/span&gt;;&lt;/div&gt;&lt;div&gt;  once = &lt;span style=&quot;color: #005c5f&quot;&gt;0&lt;/span&gt;;&lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #434f54&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #434f54&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;br&gt;&lt;/div&gt;&lt;div style=&quot;background-color: white; color: #4e5b61; font-family: Consolas, &amp;quot;Courier New&amp;quot;, monospace; font-size: 14px; white-space: pre&quot;&gt;&lt;i&gt;&lt;b&gt;Possibly the most overkill one-shot way to use the 3.3V of the micro to drive a 3V coin-cell load.&lt;/b&gt;&lt;/i&gt;&lt;/div&gt;&lt;div style=&quot;background-color: white&quot;&gt;&lt;span style=&quot;color: #4e5b61; font-family: Consolas, Courier New, monospace&quot;&gt;&lt;span style=&quot;font-size: 14px; white-space: pre&quot;&gt;Simple project that briefly presses the remote on an action cam.
1. wait a determined interval to allow the action cam to boot
2. press the button for abotu 100ms to start recording

This works because the ESP32-supermini is powering the camera as passthrough using the 5V pin to just supply USB power. 
So we get power at the same time and know roughly how long the camera takes to scan the SD card.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;background-color: white&quot;&gt;&lt;span style=&quot;color: #4e5b61; font-family: Consolas, Courier New, monospace&quot;&gt;&lt;span style=&quot;font-size: 14px; white-space: pre&quot;&gt;Works with 256 and 512GB Sandisk or Kingston class 1 .&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;</summary><author><name>Conrad Braam</name></author><source gr:stream-id="feed/http://softcircuitry.blogspot.com/feeds/posts/default"><id>tag:google.com,2005:reader/feed/http://softcircuitry.blogspot.com/feeds/posts/default</id><title type="html">soft circuitry</title><link rel="alternate" href="https://softcircuitry.blogspot.com/" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1786164646000"><id gr:original-id="https://medium.com/p/996f831d527e">tag:google.com,2005:reader/item/0000085d00000014</id><title type="html">“Developers Should Own Quality” Is a Great Way to Ruin Quality</title><published>2026-08-08T04:50:46Z</published><updated>2026-08-08T04:50:46Z</updated><link rel="alternate" href="https://medium.com/@john.gluck/developers-should-own-quality-is-a-great-way-to-ruin-quality-996f831d527e?source=rss-e071c348813f------2" type="text/html"></link><summary type="html">&lt;p&gt;There’s a mantra that’s been floating around tech teams for the past decade or so like it’s some kind of enlightened truth:&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;“Developers should own quality.”&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;At first glance, it sounds great. Empowering. Accountable. Forward-thinking.&lt;/p&gt;&lt;p&gt;But peel back the phrasing, and you’ll find a mess of assumptions, mismatched incentives, and semantic fog that leads to worse — not better — quality outcomes.&lt;/p&gt;&lt;p&gt;Let’s talk about why this statement is dangerously vague, and what we should be saying instead.&lt;/p&gt;&lt;h3&gt;First: What Does “Quality” Even Mean?&lt;/h3&gt;&lt;p&gt;If you ask five people on your team what “quality” is, you’ll get seven answers.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;No bugs?&lt;/li&gt;&lt;li&gt;Fast performance?&lt;/li&gt;&lt;li&gt;Beautiful UX?&lt;/li&gt;&lt;li&gt;Secure APIs?&lt;/li&gt;&lt;li&gt;Accessible UI?&lt;/li&gt;&lt;li&gt;Happy customers?&lt;/li&gt;&lt;li&gt;Clean code?&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;They’re all right. That’s the problem.&lt;/p&gt;&lt;p&gt;“Quality” is a system property. It’s the result of everything — from design, to research, to testing, to user feedback, to operational maturity.&lt;/p&gt;&lt;p&gt;Saying &lt;em&gt;“developers own quality”&lt;/em&gt; is like saying &lt;em&gt;“chefs own nutrition”&lt;/em&gt;. Sure, they influence it. But so do farmers, grocers, supply chains, and your own self-control.&lt;/p&gt;&lt;h3&gt;What This Phrase Usually Means in Practice&lt;/h3&gt;&lt;p&gt;Let’s be honest about how this gets used in real teams.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;“We don’t have time for QA, so devs should own quality.”&lt;/li&gt;&lt;li&gt;“We let that bug into prod. Who&lt;em&gt; owns quality&lt;/em&gt; on that feature?”&lt;/li&gt;&lt;li&gt;“We don’t do post-launch validation. Devs should just build it right.”&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;This isn’t ownership — it’s outsourcing blame.&lt;/p&gt;&lt;p&gt;It’s a euphemism for “we aren’t investing in feedback loops, testing infrastructure, or cross-functional alignment — so just don’t mess up.”&lt;/p&gt;&lt;h3&gt;Developers Do Own QC — Not QA&lt;/h3&gt;&lt;p&gt;Let’s draw an important distinction:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Quality Control (QC):&lt;/strong&gt;&lt;br&gt;The stuff that happens during and around the act of building. Unit tests. Static analysis. Code review. These are squarely in a developer’s domain.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Quality Assurance (QA):&lt;/strong&gt;&lt;br&gt;The broader system: whether the thing &lt;em&gt;does what it’s supposed to do&lt;/em&gt; in the real world, for real users, in all the messy ways they’ll use it.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Developers can (and should) own &lt;strong&gt;QC&lt;/strong&gt;.&lt;br&gt;QA is &lt;strong&gt;shared&lt;/strong&gt; — and pretending otherwise burns teams out and lets important context fall through the cracks.&lt;/p&gt;&lt;h3&gt;“Ownership” Without Scope Is a Trap&lt;/h3&gt;&lt;p&gt;Another issue: this phrase offers &lt;strong&gt;no clarity of scope&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;Are developers now responsible for:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Product requirements?&lt;/li&gt;&lt;li&gt;UX testing?&lt;/li&gt;&lt;li&gt;Compliance?&lt;/li&gt;&lt;li&gt;Load testing?&lt;/li&gt;&lt;li&gt;Accessibility?&lt;/li&gt;&lt;li&gt;Analytics?&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;If everything is your job, then nothing is.&lt;/p&gt;&lt;p&gt;When devs “own quality” without clear boundaries, you end up with:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Slower shipping (because everything needs to be “perfect”)&lt;/li&gt;&lt;li&gt;Fragile confidence (because “perfect” is undefined)&lt;/li&gt;&lt;li&gt;Diminished collaboration (because you’re trying to be the whole QA department &lt;em&gt;and&lt;/em&gt; the builder)&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;It Also Undermines Specialists&lt;/h3&gt;&lt;p&gt;Saying “devs own quality” subtly devalues the roles of QA engineers, UX researchers, testers, and product folks who bring vital perspectives into the quality conversation.&lt;/p&gt;&lt;p&gt;Quality isn’t an engineering-only concern. It lives in design tradeoffs, in user behavior, in support tickets, in operational metrics.&lt;/p&gt;&lt;p&gt;True product quality comes from &lt;strong&gt;cross-functional ownership&lt;/strong&gt;, not consolidation.&lt;/p&gt;&lt;h3&gt;What To Say Instead&lt;/h3&gt;&lt;p&gt;Here are better phrases, with actual clarity:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;“Developers are responsible for quality control.”&lt;/strong&gt;&lt;br&gt;They write tests. Use static analysis. Ensure correctness at the code level.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;“Quality is a shared outcome.”&lt;/strong&gt;&lt;br&gt;Everyone has a piece. Designers own usability. QA owns validation. PMs own alignment. Devs own integrity.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;“Shipping confidence comes from system feedback, not just test coverage.”&lt;/strong&gt;&lt;br&gt;You don’t get real quality until you can see it, measure it, and adapt to it.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;TL;DR&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;“Developers should own quality” sounds nice but is semantically vague and structurally risky.&lt;/li&gt;&lt;li&gt;It often leads to burnout, overreach, and blind spots.&lt;/li&gt;&lt;li&gt;Developers should &lt;strong&gt;own QC&lt;/strong&gt;, not the full spectrum of QA.&lt;/li&gt;&lt;li&gt;Quality is not a hero’s journey — it’s a team sport.&lt;/li&gt;&lt;li&gt;If you want to build high-quality software, build &lt;strong&gt;clarity&lt;/strong&gt; and &lt;strong&gt;collaboration&lt;/strong&gt;, not maxims and mantras.&lt;/li&gt;&lt;/ul&gt;</summary><author><name>John Gluck</name></author><source gr:stream-id="feed/https://medium.com/feed/@john.gluck"><id>tag:google.com,2005:reader/feed/https://medium.com/feed/@john.gluck</id><title type="html">Stories by John Gluck on Medium</title><link rel="alternate" href="https://medium.com/@john.gluck?source=rss-e071c348813f------2" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1786158643830"><id gr:original-id="tag:blogger.com,1999:blog-3868566217808655382.post-8167333771863877031">tag:google.com,2005:reader/item/000002c500000473</id><title type="html">Add Type Checking and TSConfig to Bun-Create-Playwright</title><published>2026-08-08T03:10:43Z</published><updated>2026-08-08T03:10:43Z</updated><link rel="alternate" href="https://www.tjmaher.com/2026/08/add-type-checking-and-tsconfig-to-bun.html" type="text/html"></link><summary type="html">&lt;div&gt;&lt;div&gt;Now that we have &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.tjmaher.com/2026/08/introducing-bun-new-package-manager-and.html&quot;&gt;installed bun&lt;/a&gt;, Anthropic&amp;apos;s package manager, and &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.tjmaher.com/2026/08/what-happens-when-you-create-playwright.html&quot;&gt;scaffolded a Playwright framework and closely examined the results&lt;/a&gt;, we are going to explore with our &lt;b&gt;Bun-Create-Playwright&lt;/b&gt; project ways to check if our code is correct. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;The first method we will be exploring is &lt;b&gt;typechecking&lt;/b&gt;. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;Why Typechecking? As the &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://playwright.dev/docs/test-typescript#introduction&quot;&gt;Playwright.dev / Node.js Introduction&lt;/a&gt; mentions:&lt;/div&gt;&lt;blockquote&gt;&amp;quot;[...] Playwright does not check the types and will run tests even if there are non-critical TypeScript compilation errors. We recommend you run TypeScript compiler alongside Playwright.&lt;br&gt;&lt;br&gt;&amp;quot;[...]  Note that Playwright only supports the following tsconfig options: allowJs, baseUrl, paths, references and extends.&lt;br&gt;&lt;br&gt;&amp;quot;[...] By default, Playwright will look up a closest tsconfig for each imported file by going up the directory structure and looking for tsconfig.json or jsconfig.json. This way, you can create a tests/tsconfig.json file that will be used only for your tests and Playwright will pick it up automatically&amp;quot;.&lt;/blockquote&gt;Before we go further down this road...&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;h2 style=&quot;text-align: left&quot;&gt;What is Type Checking? &lt;/h2&gt;&lt;br&gt;According to &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://zerotomastery.io/blog/typescript-type-checking/&quot;&gt;Type Checking in TypeScript: A Beginners Guide&lt;/a&gt;, every piece of data in TypeScript is given a &amp;quot;type&amp;quot;, and this &amp;quot;type&amp;quot; determines what properties the data has, and what methods are available to it. The types can be things like a Number, String, Enum, Boolean, Array, Object, Type assertions, or others.&lt;/div&gt;&lt;span&gt;&lt;a name=&quot;article-IYUwxR4w6pDpDZ_RDp5U2joZKEY-more&quot;&gt;&lt;/a&gt;&lt;/span&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;Since all data in TypeScript is given a type, it means that the TypeScript compiler, tsc, can check every property to make sure it is being used correctly. It makes sure that the expected properties exist and that the methods and functions are all compatible. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;And best of all, you can run these checks in your IDE as you are writing the code! &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;To run typechecking against our code, all we have to do is execute from the Terminal:&lt;/div&gt;&lt;div&gt;&lt;ul style=&quot;text-align: left&quot;&gt;&lt;li&gt;tsc --noEmit&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Since we are just kicking the tires of our code to see what happens, we don&amp;apos;t need to emit &amp;quot;compiler output files like JavaScript source code, source-maps or declarations. This makes room for another tool like &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://babeljs.io/&quot;&gt;Babel&lt;/a&gt;, or &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/swc-project/swc&quot;&gt;swc&lt;/a&gt; to handle converting the TypeScript file to a file which can run inside a JavaScript environment. You can then use TypeScript as a tool for providing editor integration, and as a source code type-checker&amp;quot;. ( &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.typescriptlang.org/tsconfig/#noEmit&quot;&gt;TypeScriptLang.org / noEmit&lt;/a&gt; )&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;The only problem? We need a TypeScript configuration file added to our project before we do that, and as you could see when we &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.tjmaher.com/2026/08/what-happens-when-you-create-playwright.html&quot;&gt;examined what &amp;quot;bun create playwright&amp;quot; produced&lt;/a&gt;, we don&amp;apos;t have one. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;If you try to run the &amp;quot;tsc --noEmit&amp;quot; command without a tsconfig.json, you get the message: &lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;i&gt;Version 6.0.3&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;tsc: The TypeScript Compiler - Version 6.0.3                                                                        &lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;                                                                                                                 &lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;TS COMMON COMMANDS&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;  tsc: Compiles the current project (tsconfig.json in the working directory.)&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;  tsc app.ts util.ts: Ignoring tsconfig.json, compiles the specified files with default compiler options.&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;  tsc -b: Build a composite project in the working directory.&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;  tsc --init: Creates a tsconfig.json with the recommended settings in the working directory.&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;  tsc -p ./path/to/tsconfig.json: Compiles the TypeScript project located at the specified path.&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;  tsc --help --all: An expanded version of this information, showing all possible compiler options&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;  tsc --noEmit&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;  tsc --target esnext&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;  Compiles the current project, with additional settings.&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;COMMAND LINE FLAGS&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;      --help, -h  Print this message.&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;    ...&lt;/i&gt; &lt;/div&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;div&gt;&lt;i&gt;              --outFile  Specify a file that bundles all outputs into one JavaScript file. If &amp;apos;declaration&amp;apos; is true,                          also designates a file that bundles all .d.ts output.&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;               --outDir  Specify an output folder for all emitted files.&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;You can learn about all of the compiler options at &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://aka.ms/tsc&quot;&gt;https://aka.ms/tsc&lt;/a&gt;&lt;/i&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;So, how do we create with bun a tsconfig.json file? &lt;/div&gt;&lt;div&gt;&lt;ul style=&quot;text-align: left&quot;&gt;&lt;li&gt;bun init&lt;/li&gt;&lt;/ul&gt;&lt;h2 style=&quot;text-align: left&quot;&gt;What does Bun Init Do?&lt;/h2&gt;&lt;/div&gt;&lt;div&gt;According to the &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://bun.com/docs/runtime/templating/init&quot;&gt;Bun.com / Init Templating docs&lt;/a&gt;, It creates: &lt;/div&gt;&lt;div&gt;&lt;ul style=&quot;text-align: left&quot;&gt;&lt;li&gt;a package.json file with a name that defaults to the current directory name&lt;/li&gt;&lt;li&gt;a tsconfig.json or jsconfig.json file, depending on whether the entry point is a TypeScript file&lt;/li&gt;&lt;li&gt;an entry point, which defaults to index.ts unless any of index.{tsx, jsx, js, mts, mjs} exist or the package.json specifies a module or main field&lt;/li&gt;&lt;li&gt;a README.md file&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;It also creates AI Agent rules (disable with $BUN_AGENT_RULE_DISABLED=1):&lt;/div&gt;&lt;div&gt;&lt;ul style=&quot;text-align: left&quot;&gt;&lt;li&gt;a CLAUDE.md file when Claude CLI is detected (disable with CLAUDE_CODE_AGENT_RULE_DISABLED env var)&lt;/li&gt;&lt;li&gt;a .cursor/rules/*.mdc file when Cursor is detected, which tells &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://cursor.sh/&quot;&gt;Cursor AI&lt;/a&gt; to use Bun instead of Node.js and npm&lt;/li&gt;&lt;/ul&gt;But we already scaffolded a Playwright project! Do we have to start from scratch and do everything all over again? &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;No, but we do need to make some modifications:&lt;/div&gt;&lt;div&gt;&lt;ul style=&quot;text-align: left&quot;&gt;&lt;li&gt;Does your package.json in your root folder of the project have &amp;quot;main&amp;quot; to be &amp;quot;index.js&amp;quot;? Change that JavaScript extension to &amp;quot;.ts&amp;quot;.&lt;/li&gt;&lt;li&gt;Do you have a &amp;quot;jsconfig.json&amp;quot; file? Delete it. &lt;/li&gt;&lt;li&gt;Do you have an index.html file? Delete it. &lt;/li&gt;&lt;li&gt;Then run: bun init &lt;br&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 style=&quot;text-align: left&quot;&gt;TSConfig.json Achieved! First version!&lt;/h2&gt;&lt;div&gt;The resulting&lt;b&gt; tsconfig.json&lt;/b&gt; file produced by &amp;quot;bun init&amp;quot;, according to Google AI, &amp;quot;configures TypeScript to act strictly as a type-checker while offloading the actual bundling, compiling, and running of your JavaScript/TypeScript code to Bun&amp;quot;. &lt;/div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;{
  &amp;quot;compilerOptions&amp;quot;: {
    // Environment setup &amp;amp; latest features
    &amp;quot;lib&amp;quot;: [&amp;quot;ESNext&amp;quot;],
    &amp;quot;target&amp;quot;: &amp;quot;ESNext&amp;quot;,
    &amp;quot;module&amp;quot;: &amp;quot;Preserve&amp;quot;,
    &amp;quot;moduleDetection&amp;quot;: &amp;quot;force&amp;quot;,
    &amp;quot;jsx&amp;quot;: &amp;quot;react-jsx&amp;quot;,
    &amp;quot;allowJs&amp;quot;: true,
    &amp;quot;types&amp;quot;: [&amp;quot;bun&amp;quot;],

    // Bundler mode
    &amp;quot;moduleResolution&amp;quot;: &amp;quot;bundler&amp;quot;,
    &amp;quot;allowImportingTsExtensions&amp;quot;: true,
    &amp;quot;verbatimModuleSyntax&amp;quot;: true,
    &amp;quot;noEmit&amp;quot;: true,

    // Best practices
    &amp;quot;strict&amp;quot;: true,
    &amp;quot;skipLibCheck&amp;quot;: true,
    &amp;quot;noFallthroughCasesInSwitch&amp;quot;: true,
    &amp;quot;noUncheckedIndexedAccess&amp;quot;: true,
    &amp;quot;noImplicitOverride&amp;quot;: true,

    // Some stricter flags (disabled by default)
    &amp;quot;noUnusedLocals&amp;quot;: false,
    &amp;quot;noUnusedParameters&amp;quot;: false,
    &amp;quot;noPropertyAccessFromIndexSignature&amp;quot;: false
  }
}
&lt;/code&gt;&lt;/pre&gt;
  
  
  &lt;p dir=&quot;ltr&quot;&gt;&lt;strong&gt;Environment setup &amp;amp; latest features&lt;/strong&gt;&lt;/p&gt;&lt;p dir=&quot;ltr&quot;&gt;These settings ensure TypeScript understands the latest syntax and runtime environment variables.&lt;/p&gt;
&lt;ul dir=&quot;ltr&quot;&gt;
&lt;li&gt;&lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;&amp;quot;lib&amp;quot;: [&amp;quot;ESNext&amp;quot;]&lt;/code&gt; -- includes type definitions for the newest JavaScript standard library features (Promise, Array methods, etc.).&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;&amp;quot;target&amp;quot;: &amp;quot;ESNext&amp;quot;&lt;/code&gt; -- compiles/type-checks against the latest ECMAScript syntax rather than downleveling to an older version.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;&amp;quot;module&amp;quot;: &amp;quot;Preserve&amp;quot;&lt;/code&gt; -- keeps your import/export statements as written (doesn&amp;apos;t rewrite ESM to CommonJS or vice versa); left for Bun to handle at runtime.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;&amp;quot;moduleDetection&amp;quot;: &amp;quot;force&amp;quot;&lt;/code&gt; -- treats every file as a module (adds import/export scoping) even if it has no import/export statements itself.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;&amp;quot;jsx&amp;quot;: &amp;quot;react-jsx&amp;quot;&lt;/code&gt; -- compiles JSX using the React 17+ automatic runtime (no need to &lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;import React&lt;/code&gt; in every file that uses JSX).&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;&amp;quot;allowJs&amp;quot;: true&lt;/code&gt; --  lets &lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;.js&lt;/code&gt; files be included and type-checked alongside &lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;.ts&lt;/code&gt; files.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;&amp;quot;types&amp;quot;: [&amp;quot;bun&amp;quot;]&lt;/code&gt; -- only loads Bun&amp;apos;s global type definitions (e.g. &lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;Bun.serve&lt;/code&gt;), instead of auto-including every &lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;@types/*&lt;/code&gt; package found in &lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;node_modules&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;ltr&quot;&gt;&lt;strong&gt;Bundler mode&lt;/strong&gt;&lt;/p&gt;&lt;p dir=&quot;ltr&quot;&gt;These rules match how modern build tools resolve file paths and handle module definitions.&lt;/p&gt;
&lt;ul dir=&quot;ltr&quot;&gt;
&lt;li&gt;&lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;&amp;quot;moduleResolution&amp;quot;: &amp;quot;bundler&amp;quot;&lt;/code&gt; -- resolves imports the way modern bundlers do, closer to Node&amp;apos;s ESM resolution but more permissive (works with &lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;paths&lt;/code&gt;, package &lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;exports&lt;/code&gt;, etc.).&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;&amp;quot;allowImportingTsExtensions&amp;quot;: true&lt;/code&gt; -- permits writing &lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;import &amp;apos;./foo.ts&amp;apos;&lt;/code&gt; with the explicit extension (normally disallowed).&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;&amp;quot;verbatimModuleSyntax&amp;quot;: true&lt;/code&gt; -- requires type-only imports to be explicitly marked (&lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;import type { Foo }&lt;/code&gt;), so the compiler doesn&amp;apos;t have to guess what to strip at build time.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;&amp;quot;noEmit&amp;quot;: true&lt;/code&gt; -- TypeScript only type-checks; it doesn&amp;apos;t output compiled &lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;.js&lt;/code&gt; files (Bun runs the &lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;.ts&lt;/code&gt; files directly).&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;ltr&quot;&gt;&lt;strong&gt;Best practices&lt;/strong&gt;&lt;/p&gt;These options activate strict type-safety rules to catch potential bugs early.
&lt;ul dir=&quot;ltr&quot;&gt;
&lt;li&gt;&lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;&amp;quot;strict&amp;quot;: true&lt;/code&gt; -- turns on TypeScript&amp;apos;s full strict type-checking mode (&lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;strictNullChecks&lt;/code&gt;, &lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;noImplicitAny&lt;/code&gt;, etc. all at once).&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;&amp;quot;skipLibCheck&amp;quot;: true&lt;/code&gt; -- skips type-checking inside &lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;.d.ts&lt;/code&gt; declaration files (faster builds, avoids errors in third-party type definitions you don&amp;apos;t control).&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;&amp;quot;noFallthroughCasesInSwitch&amp;quot;: true&lt;/code&gt; -- errors if a &lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;switch&lt;/code&gt; case falls through to the next case without a &lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;break&lt;/code&gt;/&lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;return&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;&amp;quot;noUncheckedIndexedAccess&amp;quot;: true&lt;/code&gt; -- accessing an object/array by index (e.g. &lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;arr[i]&lt;/code&gt;) returns &lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;T | undefined&lt;/code&gt; instead of just &lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;T&lt;/code&gt;, forcing you to handle the &amp;quot;might not exist&amp;quot; case. Useful in test code that reads array/object results.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;&amp;quot;noImplicitOverride&amp;quot;: true&lt;/code&gt; -- requires the &lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;override&lt;/code&gt; keyword when a subclass method overrides a parent class method (relevant if you&amp;apos;re using Page Object classes with inheritance).&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;ltr&quot;&gt;&lt;strong&gt;Stricter flags (disabled here)&lt;/strong&gt;&lt;/p&gt;&lt;p dir=&quot;ltr&quot;&gt;These are options explicitly turned off to keep the development experience smoother and less strict during early coding phases.&lt;/p&gt;
&lt;ul dir=&quot;ltr&quot;&gt;
&lt;li&gt;&lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;&amp;quot;noUnusedLocals&amp;quot;: false&lt;/code&gt; -- won&amp;apos;t error on declared-but-unused local variables.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;&amp;quot;noUnusedParameters&amp;quot;: false&lt;/code&gt; -- won&amp;apos;t error on unused function parameters (common in test fixtures/callbacks where you don&amp;apos;t use every argument).&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;&amp;quot;noPropertyAccessFromIndexSignature&amp;quot;: false&lt;/code&gt; -- allows dot notation (&lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://obj.foo&quot;&gt;obj.foo&lt;/a&gt;&lt;/code&gt;) even on objects typed with an index signature, instead of forcing bracket notation (&lt;code class=&quot;language-bg-text-200/5 language-border language-border-0.5 language-border-border-300 language-text-danger-000 language-whitespace-pre-wrap language-rounded-[0.4rem] language-px-1 language-py-px language-text-[0.9rem]&quot;&gt;obj[&amp;apos;foo&amp;apos;]&lt;/code&gt;).&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;... This is what &amp;quot;bun init&amp;quot; produced. Let&amp;apos;s investigate with Claude.ai or Google AI to see if we should now be all set with our Bun + Playwright + TypeScript project... &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;h2&gt;TSConfig.json: Take Two!&lt;/h2&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;After I ran it by GitHub Copilot, it suggested to change the tsconfig like so... &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;background-color: #121314; color: #bbbebf; font-family: Consolas, &amp;quot;Courier New&amp;quot;, monospace; font-size: 14px; white-space: pre&quot;&gt;&lt;div&gt;  &lt;span style=&quot;color: #7ee787&quot;&gt;&amp;quot;compilerOptions&amp;quot;&lt;/span&gt;: {&lt;/div&gt;&lt;div&gt;    &lt;span style=&quot;color: #8b949e&quot;&gt;// Environment setup &amp;amp; latest features&lt;/span&gt;&lt;/div&gt;&lt;div&gt;    &lt;span style=&quot;color: #7ee787&quot;&gt;&amp;quot;lib&amp;quot;&lt;/span&gt;: [&lt;span style=&quot;color: #a5d6ff&quot;&gt;&amp;quot;ES2022&amp;quot;&lt;/span&gt;, &lt;span style=&quot;color: #a5d6ff&quot;&gt;&amp;quot;DOM&amp;quot;&lt;/span&gt;],&lt;/div&gt;&lt;div&gt;    &lt;span style=&quot;color: #7ee787&quot;&gt;&amp;quot;target&amp;quot;&lt;/span&gt;: &lt;span style=&quot;color: #a5d6ff&quot;&gt;&amp;quot;ES2022&amp;quot;&lt;/span&gt;,&lt;/div&gt;&lt;div&gt;    &lt;span style=&quot;color: #7ee787&quot;&gt;&amp;quot;module&amp;quot;&lt;/span&gt;: &lt;span style=&quot;color: #a5d6ff&quot;&gt;&amp;quot;ESNext&amp;quot;&lt;/span&gt;,&lt;/div&gt;&lt;div&gt;    &lt;span style=&quot;color: #7ee787&quot;&gt;&amp;quot;moduleDetection&amp;quot;&lt;/span&gt;: &lt;span style=&quot;color: #a5d6ff&quot;&gt;&amp;quot;force&amp;quot;&lt;/span&gt;,&lt;/div&gt;&lt;div&gt;    &lt;span style=&quot;color: #7ee787&quot;&gt;&amp;quot;types&amp;quot;&lt;/span&gt;: [&lt;span style=&quot;color: #a5d6ff&quot;&gt;&amp;quot;node&amp;quot;&lt;/span&gt;, &lt;span style=&quot;color: #a5d6ff&quot;&gt;&amp;quot;bun&amp;quot;&lt;/span&gt;],&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;But Why, Claude? &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&amp;quot;These choices are better because they match the runtime and tooling you actually have, rather than using the most generic &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://defaults.target&quot;&gt;defaults.target&lt;/a&gt;: &amp;quot;ES2022&amp;quot;: this targets a modern JavaScript version that is broadly supported and a good default for current Node/Bun environments. It is more practical than ESNext because it gives a stable, explicit baseline.&lt;br&gt;&lt;ul style=&quot;text-align: left&quot;&gt;&lt;li&gt;lib: [&amp;quot;ES2022&amp;quot;, &amp;quot;DOM&amp;quot;]: this tells TypeScript about modern JavaScript features plus browser APIs like window, document, and fetch. That matters for Playwright tests, which often interact with browser-like environments.&lt;/li&gt;&lt;li&gt;module: &amp;quot;ESNext&amp;quot;: this matches modern ESM-style projects and works well with current Bun/Node tooling. It is a better fit than older module systems when you are using modern package resolution.&lt;/li&gt;&lt;li&gt;types: [&amp;quot;node&amp;quot;, &amp;quot;bun&amp;quot;]: this makes the compiler aware of both Node and Bun globals/types. That is useful because your project is using Bun as the package runner while also relying on Node-compatible APIs.&lt;/li&gt;&lt;/ul&gt;&amp;quot;In short, the new config is more explicit, more compatible with current tooling, and less likely to surprise you later when you add scripts, browser APIs, or ESM-style imports&amp;quot;.&lt;br&gt;&lt;h2 style=&quot;text-align: left&quot;&gt;Add the TypeScript Checking to a Script&lt;/h2&gt;&lt;div&gt;Okay, let&amp;apos;s add the &amp;quot;tsc --noEmit&amp;quot; command to our package.json script:&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;background-color: #121314; color: #bbbebf; font-family: Consolas, &amp;quot;Courier New&amp;quot;, monospace; font-size: 14px; white-space: pre&quot;&gt;&lt;div&gt;  &lt;span style=&quot;color: #7ee787&quot;&gt;&amp;quot;scripts&amp;quot;&lt;/span&gt;: {&lt;/div&gt;&lt;div&gt;    &lt;span style=&quot;color: #7ee787&quot;&gt;&amp;quot;test&amp;quot;&lt;/span&gt;: &lt;span style=&quot;color: #a5d6ff&quot;&gt;&amp;quot;playwright test&amp;quot;&lt;/span&gt;,&lt;/div&gt;&lt;div&gt;    &lt;span style=&quot;color: #7ee787&quot;&gt;&amp;quot;typecheck&amp;quot;&lt;/span&gt;: &lt;span style=&quot;color: #a5d6ff&quot;&gt;&amp;quot;tsc --noEmit&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;  },&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;Now, when you run &amp;quot;bun run typecheck&amp;quot;, the TypeScript Compiler will test out your code. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;No errors? No output. No problem! &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;With our next post, we will see other ways to add ways to review our code. &lt;br&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;Until then... Happy Testing! &lt;br&gt;&lt;br&gt;
-T.J. Maher&lt;br&gt;
Software Engineer in Test&lt;br&gt;
&lt;br&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://bsky.app/profile/tjmaher1.bsky.social&quot;&gt;BlueSky&lt;/a&gt; | &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://bit.ly/tj_youtube&quot;&gt;YouTube&lt;/a&gt; | &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.linkedin.com/in/tjmaher1&quot;&gt;LinkedIn&lt;/a&gt; | &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://www.tjmaher.com/p/media.html&quot;&gt;Articles&lt;/a&gt;&lt;/div&gt;</summary><author><name>T.J. Maher</name></author><source gr:stream-id="feed/http://www.tjmaher.com/feeds/posts/default"><id>tag:google.com,2005:reader/feed/http://www.tjmaher.com/feeds/posts/default</id><title type="html">Adventures in Automation</title><link rel="alternate" href="https://www.tjmaher.com/" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1786138326000"><id gr:original-id="6a76390cbc9ca900014a89a2">tag:google.com,2005:reader/item/0000071a000000f5</id><category term="Puzzle"></category><title type="html">Puzzle 40</title><published>2026-08-07T21:32:06Z</published><updated>2026-08-07T21:32:06Z</updated><link rel="alternate" href="https://www.workroom-productions.com/puzzle-040/" type="text/html"></link><summary type="html">&lt;section id=&quot;article-KiIoL-zcQLFmhWNDU_IL9kUMSe4-puzzle040UI&quot;&gt;
			&lt;div id=&quot;article-KiIoL-zcQLFmhWNDU_IL9kUMSe4-lamp1&quot;&gt;&lt;/div&gt;
			&lt;div id=&quot;article-KiIoL-zcQLFmhWNDU_IL9kUMSe4-lamp2&quot;&gt;&lt;/div&gt;
			&lt;div id=&quot;article-KiIoL-zcQLFmhWNDU_IL9kUMSe4-lamp3&quot;&gt;&lt;/div&gt;
			&lt;div id=&quot;article-KiIoL-zcQLFmhWNDU_IL9kUMSe4-lamp4&quot;&gt;&lt;/div&gt;
			&lt;div id=&quot;article-KiIoL-zcQLFmhWNDU_IL9kUMSe4-lamp8&quot;&gt;&lt;/div&gt;
			&lt;div id=&quot;article-KiIoL-zcQLFmhWNDU_IL9kUMSe4-lamp7&quot;&gt;&lt;/div&gt;
			&lt;div id=&quot;article-KiIoL-zcQLFmhWNDU_IL9kUMSe4-lamp6&quot;&gt;&lt;/div&gt;
			&lt;div id=&quot;article-KiIoL-zcQLFmhWNDU_IL9kUMSe4-lamp5&quot;&gt;&lt;/div&gt;
			&lt;button tabindex=&quot;-1&quot; id=&quot;article-KiIoL-zcQLFmhWNDU_IL9kUMSe4-button1&quot;&gt;&lt;/button&gt;
			&lt;button tabindex=&quot;-1&quot; id=&quot;article-KiIoL-zcQLFmhWNDU_IL9kUMSe4-button3&quot;&gt;&lt;/button&gt;
			&lt;button tabindex=&quot;-1&quot; id=&quot;article-KiIoL-zcQLFmhWNDU_IL9kUMSe4-button5&quot;&gt;&lt;/button&gt;
			&lt;button tabindex=&quot;-1&quot; id=&quot;article-KiIoL-zcQLFmhWNDU_IL9kUMSe4-button7&quot;&gt;&lt;/button&gt;
			&lt;button tabindex=&quot;-1&quot; id=&quot;article-KiIoL-zcQLFmhWNDU_IL9kUMSe4-button2&quot;&gt;&lt;/button&gt;
			&lt;button tabindex=&quot;-1&quot; id=&quot;article-KiIoL-zcQLFmhWNDU_IL9kUMSe4-button4&quot;&gt;&lt;/button&gt;
			&lt;button tabindex=&quot;-1&quot; id=&quot;article-KiIoL-zcQLFmhWNDU_IL9kUMSe4-button6&quot;&gt;&lt;/button&gt;
			&lt;button tabindex=&quot;-1&quot; id=&quot;article-KiIoL-zcQLFmhWNDU_IL9kUMSe4-button8&quot;&gt;&lt;/button&gt;
&lt;/section&gt;



&lt;section&gt;

&lt;img class=&quot;bqrUnknownImgSize&quot; src=&quot;https://storage.ghost.io/c/7e/30/7e30843b-2abb-494a-ab80-0e931d8ae9a9/content/images/2026/08/puzzle040.jpg&quot; alt=&quot;Puzzle 40&quot;&gt;&lt;p&gt;Describe how the buttons affect the lamps.&lt;/p&gt;

&lt;details id=&quot;article-KiIoL-zcQLFmhWNDU_IL9kUMSe4-patreons&quot; style=&quot;margin-bottom: 1.5rem&quot; closed&gt;&lt;summary&gt;&lt;h3&gt;Currently supported by these lovely people&lt;/h3&gt;&lt;/summary&gt;

&lt;p&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://talent-unleashed.com&quot;&gt;&lt;strong&gt;&lt;em&gt;Julie Gardiner&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;, &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://smallsheds.garden&quot;&gt;&lt;strong&gt;&lt;em&gt;Joep Schuurkes&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;, &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://huibschoots.nl/about-me/&quot;&gt;&lt;strong&gt;Huib Schoots&lt;/strong&gt;&lt;/a&gt;, &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.linkedin.com/in/koopside/?lipi=urn%3Ali%3Apage%3Ad_flagship3_search_srp_people%3BXWQgAmL6QD%2BrTEFLDXdF4g%3D%3D&quot;&gt;&lt;em&gt;Ide Koops&lt;/em&gt;&lt;/a&gt;, &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.linkedin.com/in/kriscorbus/&quot;&gt;&lt;em&gt;Kris Corbus&lt;/em&gt;&lt;/a&gt;, &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.eviltester.com&quot;&gt;Alan Richardson&lt;/a&gt;, Rob van Steenbergen, Ioana Chiorean, Peter Houghton, Adun Urke, Christine Yen, Pascal Dufour all support me on &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.patreon.com/workroomprds&quot;&gt;Patreon&lt;/a&gt;. &lt;/p&gt;&lt;p&gt;Help me make more and I&amp;apos;ll put your name on this list. There are other perks, too, eventually.&lt;/p&gt;

&lt;/details&gt;



			&lt;section id=&quot;article-KiIoL-zcQLFmhWNDU_IL9kUMSe4-supportMore&quot;&gt;
				&lt;p&gt;Enjoy this? &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.patreon.com/workroomprds&quot;&gt;Support another!&lt;/a&gt;&lt;/p&gt;
			&lt;/section&gt;
			&lt;div&gt;
				&lt;p&gt;Built by James Lyndsay - &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://twitter.com/workroomprds&quot;&gt;@workroomprds&lt;/a&gt;&lt;/p&gt;
				&lt;p id=&quot;article-KiIoL-zcQLFmhWNDU_IL9kUMSe4-copyright&quot;&gt;© Workroom Productions 2026&lt;/p&gt;&lt;/div&gt;&lt;/section&gt;</summary><author><name>James Lyndsay</name></author><source gr:stream-id="feed/https://www.workroom-productions.com/rss/"><id>tag:google.com,2005:reader/feed/https://www.workroom-productions.com/rss/</id><title type="html">Workroom Productions</title><link rel="alternate" href="https://www.workroom-productions.com/" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1786075200000"><id gr:original-id="https://glebbahmutov.com/blog/cant-stop-wont-stop/">tag:google.com,2005:reader/item/0000097e00000278</id><category term="products"></category><category term="testing"></category><category term="cypress"></category><title type="html">Can’t Stop, Won’t Stop</title><published>2026-08-07T04:00:00Z</published><updated>2026-08-07T04:00:00Z</updated><link rel="alternate" href="https://glebbahmutov.com/blog/cant-stop-wont-stop/" type="text/html"></link><summary type="html">&lt;p&gt;Let&amp;apos;s say you have a long-ish Cypress test and you know a place where it might fail. You want to stop / skip the test commands. What options do you have for stopping Cypress tests?&lt;/p&gt;&lt;p&gt;Imagine these two specs in our project&lt;/p&gt;&lt;figure&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;&lt;span&gt;1&lt;/span&gt;&lt;br&gt;&lt;span&gt;2&lt;/span&gt;&lt;br&gt;&lt;span&gt;3&lt;/span&gt;&lt;br&gt;&lt;span&gt;4&lt;/span&gt;&lt;br&gt;&lt;span&gt;5&lt;/span&gt;&lt;br&gt;&lt;span&gt;6&lt;/span&gt;&lt;br&gt;&lt;span&gt;7&lt;/span&gt;&lt;br&gt;&lt;span&gt;8&lt;/span&gt;&lt;br&gt;&lt;span&gt;9&lt;/span&gt;&lt;br&gt;&lt;span&gt;10&lt;/span&gt;&lt;br&gt;&lt;span&gt;11&lt;/span&gt;&lt;br&gt;&lt;span&gt;12&lt;/span&gt;&lt;br&gt;&lt;span&gt;13&lt;/span&gt;&lt;br&gt;&lt;span&gt;14&lt;/span&gt;&lt;br&gt;&lt;span&gt;15&lt;/span&gt;&lt;br&gt;&lt;span&gt;16&lt;/span&gt;&lt;br&gt;&lt;span&gt;17&lt;/span&gt;&lt;br&gt;&lt;span&gt;18&lt;/span&gt;&lt;br&gt;&lt;span&gt;19&lt;/span&gt;&lt;br&gt;&lt;span&gt;20&lt;/span&gt;&lt;br&gt;&lt;span&gt;21&lt;/span&gt;&lt;br&gt;&lt;span&gt;22&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre&gt;&lt;span&gt;&lt;span&gt;// cypress/e2e/spec-a.cy.js&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span&gt;&lt;span&gt;describe&lt;/span&gt;(&lt;span&gt;&amp;apos;Suite 1&amp;apos;&lt;/span&gt;, &lt;span&gt;() =&amp;gt;&lt;/span&gt; {&lt;/span&gt;&lt;br&gt;&lt;span&gt;  &lt;span&gt;it&lt;/span&gt;(&lt;span&gt;&amp;apos;works 1&amp;apos;&lt;/span&gt;, &lt;span&gt;function&lt;/span&gt; () {&lt;/span&gt;&lt;br&gt;&lt;span&gt;    cy.&lt;span&gt;wrap&lt;/span&gt;(&lt;span&gt;&amp;apos;Hello&amp;apos;&lt;/span&gt;).&lt;span&gt;should&lt;/span&gt;(&lt;span&gt;&amp;apos;eq&amp;apos;&lt;/span&gt;, &lt;span&gt;&amp;apos;Hello&amp;apos;&lt;/span&gt;).&lt;span&gt;wait&lt;/span&gt;(&lt;span&gt;2000&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span&gt;    &lt;span&gt;// this command fails on purpose,&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span&gt;    &lt;span&gt;// we want to stop the test before we run it&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span&gt;    cy.&lt;span&gt;wrap&lt;/span&gt;(&lt;span&gt;42&lt;/span&gt;).&lt;span&gt;should&lt;/span&gt;(&lt;span&gt;&amp;apos;not.eq&amp;apos;&lt;/span&gt;, &lt;span&gt;42&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span&gt;  })&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span&gt;  &lt;span&gt;it&lt;/span&gt;(&lt;span&gt;&amp;apos;works 2&amp;apos;&lt;/span&gt;, &lt;span&gt;() =&amp;gt;&lt;/span&gt; {&lt;/span&gt;&lt;br&gt;&lt;span&gt;    cy.&lt;span&gt;wrap&lt;/span&gt;(&lt;span&gt;&amp;apos;Bye&amp;apos;&lt;/span&gt;).&lt;span&gt;should&lt;/span&gt;(&lt;span&gt;&amp;apos;eq&amp;apos;&lt;/span&gt;, &lt;span&gt;&amp;apos;Bye&amp;apos;&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span&gt;  })&lt;/span&gt;&lt;br&gt;&lt;span&gt;})&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span&gt;&lt;span&gt;// cypress/e2e/spec-b.cy.js&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span&gt;&lt;span&gt;describe&lt;/span&gt;(&lt;span&gt;&amp;apos;Suite 2&amp;apos;&lt;/span&gt;, &lt;span&gt;() =&amp;gt;&lt;/span&gt; {&lt;/span&gt;&lt;br&gt;&lt;span&gt;  &lt;span&gt;it&lt;/span&gt;(&lt;span&gt;&amp;apos;works b&amp;apos;&lt;/span&gt;, &lt;span&gt;() =&amp;gt;&lt;/span&gt; {&lt;/span&gt;&lt;br&gt;&lt;span&gt;    cy.&lt;span&gt;wrap&lt;/span&gt;(&lt;span&gt;&amp;apos;Hello&amp;apos;&lt;/span&gt;).&lt;span&gt;should&lt;/span&gt;(&lt;span&gt;&amp;apos;eq&amp;apos;&lt;/span&gt;, &lt;span&gt;&amp;apos;Hello&amp;apos;&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span&gt;  })&lt;/span&gt;&lt;br&gt;&lt;span&gt;})&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&lt;p&gt;The first spec has the test &amp;quot;works 1&amp;quot; that fails at the end. There is another passing test in the first spec. The second spec has just a single passing test. If we use &lt;code&gt;cypress open&lt;/code&gt; and look at the first test, the test runner shows the commands in the two finished tests.&lt;/p&gt;&lt;p&gt;&lt;img class=&quot;bqrUnknownImgSize&quot; src=&quot;https://glebbahmutov.com/images/cant-stop-wont-stop/fails.png&quot; alt=&quot;The two tests in the first spec&quot;&gt;&lt;/p&gt;&lt;p&gt;The first test fails, the second one passes.&lt;/p&gt;&lt;h2&gt;&lt;span id=&quot;article-i6V9v-NzTZpoafkNbdloVsmigas-option-1-hard-cypress-stop&quot;&gt;Option 1: Hard Cypress stop&lt;/span&gt;&lt;/h2&gt;&lt;p&gt;Let&amp;apos;s try using &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://on.cypress.io/stop&quot;&gt;Cypress.stop&lt;/a&gt; before the failing command.&lt;/p&gt;&lt;figure&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;&lt;span&gt;1&lt;/span&gt;&lt;br&gt;&lt;span&gt;2&lt;/span&gt;&lt;br&gt;&lt;span&gt;3&lt;/span&gt;&lt;br&gt;&lt;span&gt;4&lt;/span&gt;&lt;br&gt;&lt;span&gt;5&lt;/span&gt;&lt;br&gt;&lt;span&gt;6&lt;/span&gt;&lt;br&gt;&lt;span&gt;7&lt;/span&gt;&lt;br&gt;&lt;span&gt;8&lt;/span&gt;&lt;br&gt;&lt;span&gt;9&lt;/span&gt;&lt;br&gt;&lt;span&gt;10&lt;/span&gt;&lt;br&gt;&lt;span&gt;11&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre&gt;&lt;span&gt;&lt;span&gt;it&lt;/span&gt;(&lt;span&gt;&amp;apos;works 1&amp;apos;&lt;/span&gt;, &lt;span&gt;function&lt;/span&gt; () {&lt;/span&gt;&lt;br&gt;&lt;span&gt;  cy.&lt;span&gt;wrap&lt;/span&gt;(&lt;span&gt;&amp;apos;Hello&amp;apos;&lt;/span&gt;).&lt;span&gt;should&lt;/span&gt;(&lt;span&gt;&amp;apos;eq&amp;apos;&lt;/span&gt;, &lt;span&gt;&amp;apos;Hello&amp;apos;&lt;/span&gt;).&lt;span&gt;wait&lt;/span&gt;(&lt;span&gt;2000&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span&gt;  &lt;span&gt;Cypress&lt;/span&gt;.&lt;span&gt;stop&lt;/span&gt;()&lt;/span&gt;&lt;br&gt;&lt;span&gt;  &lt;span&gt;// this command fails on purpose,&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span&gt;  &lt;span&gt;// we want to stop the test before we run it&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span&gt;  cy.&lt;span&gt;wrap&lt;/span&gt;(&lt;span&gt;42&lt;/span&gt;).&lt;span&gt;should&lt;/span&gt;(&lt;span&gt;&amp;apos;not.eq&amp;apos;&lt;/span&gt;, &lt;span&gt;42&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span&gt;})&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span&gt;&lt;span&gt;it&lt;/span&gt;(&lt;span&gt;&amp;apos;works 2&amp;apos;&lt;/span&gt;, &lt;span&gt;() =&amp;gt;&lt;/span&gt; {&lt;/span&gt;&lt;br&gt;&lt;span&gt;  cy.&lt;span&gt;wrap&lt;/span&gt;(&lt;span&gt;&amp;apos;Bye&amp;apos;&lt;/span&gt;).&lt;span&gt;should&lt;/span&gt;(&lt;span&gt;&amp;apos;eq&amp;apos;&lt;/span&gt;, &lt;span&gt;&amp;apos;Bye&amp;apos;&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span&gt;})&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&lt;p&gt;Here is what happens when this test runs in Cypress&lt;/p&gt;&lt;center&gt;  &lt;video width=&quot;560&quot; height=&quot;315&quot; controls preload=&quot;none&quot; playsinline=&quot;true&quot; webkit-playsinline=&quot;true&quot; tabindex=&quot;-1&quot; muted loop&gt;    &lt;source src=&quot;https://glebbahmutov.com/images/cant-stop-wont-stop/cypress-stop.mp4&quot; type=&quot;video/mp4&quot;&gt;    &lt;img src=&quot;https://glebbahmutov.com/images/cant-stop-wont-stop/cypress-stop.png&quot;&gt;  &lt;/video&gt;&lt;/center&gt;&lt;p&gt;Notice that &lt;code&gt;Cypress.stop&lt;/code&gt; &lt;em&gt;destroys&lt;/em&gt; the Command Log and skips the rest of the tests in the spec file. We lose everything. We cannot even see any successful commands inside the first test.&lt;/p&gt;&lt;h2&gt;&lt;span id=&quot;article-i6V9v-NzTZpoafkNbdloVsmigas-option-2-mocha-test-skip&quot;&gt;Option 2: Mocha test skip&lt;/span&gt;&lt;/h2&gt;&lt;p&gt;We can stop the current test without skipping th rest of the tests in the spec file by using the &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://medium.com/bigpanda-engineering/skip-tests-in-mocha-70e0733c5b51&quot;&gt;Mocha test skip&lt;/a&gt; command. We just need to be careful about pointing &lt;code&gt;this&lt;/code&gt; at the test context object, thus I am using &lt;code&gt;it(..., function () { ... })&lt;/code&gt; syntax and not &lt;code&gt;it(..., () =&amp;gt; { ... })&lt;/code&gt; version.&lt;/p&gt;&lt;figure&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;&lt;span&gt;1&lt;/span&gt;&lt;br&gt;&lt;span&gt;2&lt;/span&gt;&lt;br&gt;&lt;span&gt;3&lt;/span&gt;&lt;br&gt;&lt;span&gt;4&lt;/span&gt;&lt;br&gt;&lt;span&gt;5&lt;/span&gt;&lt;br&gt;&lt;span&gt;6&lt;/span&gt;&lt;br&gt;&lt;span&gt;7&lt;/span&gt;&lt;br&gt;&lt;span&gt;8&lt;/span&gt;&lt;br&gt;&lt;span&gt;9&lt;/span&gt;&lt;br&gt;&lt;span&gt;10&lt;/span&gt;&lt;br&gt;&lt;span&gt;11&lt;/span&gt;&lt;br&gt;&lt;span&gt;12&lt;/span&gt;&lt;br&gt;&lt;span&gt;13&lt;/span&gt;&lt;br&gt;&lt;span&gt;14&lt;/span&gt;&lt;br&gt;&lt;span&gt;15&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre&gt;&lt;span&gt;&lt;span&gt;it&lt;/span&gt;(&lt;span&gt;&amp;apos;works 1&amp;apos;&lt;/span&gt;, &lt;span&gt;function&lt;/span&gt; () {&lt;/span&gt;&lt;br&gt;&lt;span&gt;  cy.&lt;span&gt;wrap&lt;/span&gt;(&lt;span&gt;&amp;apos;Hello&amp;apos;&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span&gt;    .&lt;span&gt;should&lt;/span&gt;(&lt;span&gt;&amp;apos;eq&amp;apos;&lt;/span&gt;, &lt;span&gt;&amp;apos;Hello&amp;apos;&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span&gt;    .&lt;span&gt;wait&lt;/span&gt;(&lt;span&gt;2000&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span&gt;    .&lt;span&gt;then&lt;/span&gt;(&lt;span&gt;() =&amp;gt;&lt;/span&gt; {&lt;/span&gt;&lt;br&gt;&lt;span&gt;      &lt;span&gt;this&lt;/span&gt;.&lt;span&gt;skip&lt;/span&gt;()&lt;/span&gt;&lt;br&gt;&lt;span&gt;    })&lt;/span&gt;&lt;br&gt;&lt;span&gt;  &lt;span&gt;// this command fails on purpose,&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span&gt;  &lt;span&gt;// we want to stop the test before we run it&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span&gt;  cy.&lt;span&gt;wrap&lt;/span&gt;(&lt;span&gt;42&lt;/span&gt;).&lt;span&gt;should&lt;/span&gt;(&lt;span&gt;&amp;apos;not.eq&amp;apos;&lt;/span&gt;, &lt;span&gt;42&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span&gt;})&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span&gt;&lt;span&gt;it&lt;/span&gt;(&lt;span&gt;&amp;apos;works 2&amp;apos;&lt;/span&gt;, &lt;span&gt;() =&amp;gt;&lt;/span&gt; {&lt;/span&gt;&lt;br&gt;&lt;span&gt;  cy.&lt;span&gt;wrap&lt;/span&gt;(&lt;span&gt;&amp;apos;Bye&amp;apos;&lt;/span&gt;).&lt;span&gt;should&lt;/span&gt;(&lt;span&gt;&amp;apos;eq&amp;apos;&lt;/span&gt;, &lt;span&gt;&amp;apos;Bye&amp;apos;&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span&gt;})&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&lt;p&gt;This is how the spec runs - the first test collapses, but the second test runs and can be viewed in the Command Log.&lt;/p&gt;&lt;center&gt;  &lt;video width=&quot;560&quot; height=&quot;315&quot; controls preload=&quot;none&quot; playsinline=&quot;true&quot; webkit-playsinline=&quot;true&quot; tabindex=&quot;-1&quot; muted loop&gt;    &lt;source src=&quot;https://glebbahmutov.com/images/cant-stop-wont-stop/this-skip.mp4&quot; type=&quot;video/mp4&quot;&gt;    &lt;img src=&quot;https://glebbahmutov.com/images/cant-stop-wont-stop/this-skip.png&quot;&gt;  &lt;/video&gt;&lt;/center&gt;&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; you can avoid using &lt;code&gt;it(..., function () { ... })&lt;/code&gt; syntax and simply grab the Mocha test context object using the following internal &lt;code&gt;cy.state&lt;/code&gt; command&lt;/p&gt;&lt;figure&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;&lt;span&gt;1&lt;/span&gt;&lt;br&gt;&lt;span&gt;2&lt;/span&gt;&lt;br&gt;&lt;span&gt;3&lt;/span&gt;&lt;br&gt;&lt;span&gt;4&lt;/span&gt;&lt;br&gt;&lt;span&gt;5&lt;/span&gt;&lt;br&gt;&lt;span&gt;6&lt;/span&gt;&lt;br&gt;&lt;span&gt;7&lt;/span&gt;&lt;br&gt;&lt;span&gt;8&lt;/span&gt;&lt;br&gt;&lt;span&gt;9&lt;/span&gt;&lt;br&gt;&lt;span&gt;10&lt;/span&gt;&lt;br&gt;&lt;span&gt;11&lt;/span&gt;&lt;br&gt;&lt;span&gt;12&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre&gt;&lt;span&gt;&lt;span&gt;it&lt;/span&gt;(&lt;span&gt;&amp;apos;works 1&amp;apos;&lt;/span&gt;, &lt;span&gt;() =&amp;gt;&lt;/span&gt; {&lt;/span&gt;&lt;br&gt;&lt;span&gt;  cy.&lt;span&gt;wrap&lt;/span&gt;(&lt;span&gt;&amp;apos;Hello&amp;apos;&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span&gt;    .&lt;span&gt;should&lt;/span&gt;(&lt;span&gt;&amp;apos;eq&amp;apos;&lt;/span&gt;, &lt;span&gt;&amp;apos;Hello&amp;apos;&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span&gt;    .&lt;span&gt;wait&lt;/span&gt;(&lt;span&gt;2000&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span&gt;    .&lt;span&gt;then&lt;/span&gt;(&lt;span&gt;() =&amp;gt;&lt;/span&gt; {&lt;/span&gt;&lt;br&gt;&lt;span&gt;      &lt;span&gt;const&lt;/span&gt; ctx = cy.&lt;span&gt;state&lt;/span&gt;(&lt;span&gt;&amp;apos;runnable&amp;apos;&lt;/span&gt;).&lt;span&gt;ctx&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span&gt;      ctx.&lt;span&gt;skip&lt;/span&gt;()&lt;/span&gt;&lt;br&gt;&lt;span&gt;    })&lt;/span&gt;&lt;br&gt;&lt;span&gt;  &lt;span&gt;// this command fails on purpose,&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span&gt;  &lt;span&gt;// we want to stop the test before we run it&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span&gt;  cy.&lt;span&gt;wrap&lt;/span&gt;(&lt;span&gt;42&lt;/span&gt;).&lt;span&gt;should&lt;/span&gt;(&lt;span&gt;&amp;apos;not.eq&amp;apos;&lt;/span&gt;, &lt;span&gt;42&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span&gt;})&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&lt;p&gt;Works the same way: skips and collapses the first test, but lets the rest of the spec proceed&lt;/p&gt;&lt;h2&gt;&lt;span id=&quot;article-i6V9v-NzTZpoafkNbdloVsmigas-option-3-skip-the-rest-of-the-command-queue&quot;&gt;Option 3: skip the rest of the command queue&lt;/span&gt;&lt;/h2&gt;&lt;p&gt;There is a better way. Instead of hitting &amp;quot;the emergency brake&amp;quot;, we can skip the remaining Cypress commands by writing a little bit of custom code. To remind: Cypress runs the test callback function, which adds all &lt;code&gt;cy&lt;/code&gt; commands to a queue (which you can watch yourself, read &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://glebbahmutov.com/blog/visualize-cypress-command-queue/&quot; title=&quot;Visualize Cypress Command Queue&quot;&gt;Visualize Cypress Command Queue&lt;/a&gt;). So here is what we can do when we decide to skip the rest of the test: simply skip the remaining commands instead of stopping the test.&lt;/p&gt;&lt;figure&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;&lt;span&gt;1&lt;/span&gt;&lt;br&gt;&lt;span&gt;2&lt;/span&gt;&lt;br&gt;&lt;span&gt;3&lt;/span&gt;&lt;br&gt;&lt;span&gt;4&lt;/span&gt;&lt;br&gt;&lt;span&gt;5&lt;/span&gt;&lt;br&gt;&lt;span&gt;6&lt;/span&gt;&lt;br&gt;&lt;span&gt;7&lt;/span&gt;&lt;br&gt;&lt;span&gt;8&lt;/span&gt;&lt;br&gt;&lt;span&gt;9&lt;/span&gt;&lt;br&gt;&lt;span&gt;10&lt;/span&gt;&lt;br&gt;&lt;span&gt;11&lt;/span&gt;&lt;br&gt;&lt;span&gt;12&lt;/span&gt;&lt;br&gt;&lt;span&gt;13&lt;/span&gt;&lt;br&gt;&lt;span&gt;14&lt;/span&gt;&lt;br&gt;&lt;span&gt;15&lt;/span&gt;&lt;br&gt;&lt;span&gt;16&lt;/span&gt;&lt;br&gt;&lt;span&gt;17&lt;/span&gt;&lt;br&gt;&lt;span&gt;18&lt;/span&gt;&lt;br&gt;&lt;span&gt;19&lt;/span&gt;&lt;br&gt;&lt;span&gt;20&lt;/span&gt;&lt;br&gt;&lt;span&gt;21&lt;/span&gt;&lt;br&gt;&lt;span&gt;22&lt;/span&gt;&lt;br&gt;&lt;span&gt;23&lt;/span&gt;&lt;br&gt;&lt;span&gt;24&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre&gt;&lt;span&gt;&lt;span&gt;Cypress&lt;/span&gt;.&lt;span&gt;Commands&lt;/span&gt;.&lt;span&gt;add&lt;/span&gt;(&lt;span&gt;&amp;apos;skip&amp;apos;&lt;/span&gt;, &lt;span&gt;() =&amp;gt;&lt;/span&gt; {&lt;/span&gt;&lt;br&gt;&lt;span&gt;  &lt;span&gt;const&lt;/span&gt; log = &lt;span&gt;Cypress&lt;/span&gt;.&lt;span&gt;log&lt;/span&gt;({&lt;/span&gt;&lt;br&gt;&lt;span&gt;    &lt;span&gt;message&lt;/span&gt;: &lt;span&gt;&amp;apos;Skipping the rest of commands&amp;apos;&lt;/span&gt;,&lt;/span&gt;&lt;br&gt;&lt;span&gt;  })&lt;/span&gt;&lt;br&gt;&lt;span&gt;  &lt;span&gt;let&lt;/span&gt; next = &lt;span&gt;Cypress&lt;/span&gt;.&lt;span&gt;state&lt;/span&gt;(&lt;span&gt;&amp;apos;current&amp;apos;&lt;/span&gt;).&lt;span&gt;attributes&lt;/span&gt;?.&lt;span&gt;next&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span&gt;  &lt;span&gt;while&lt;/span&gt; (next) {&lt;/span&gt;&lt;br&gt;&lt;span&gt;    next.&lt;span&gt;skip&lt;/span&gt;()&lt;/span&gt;&lt;br&gt;&lt;span&gt;    next = next.&lt;span&gt;attributes&lt;/span&gt;?.&lt;span&gt;next&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span&gt;  }&lt;/span&gt;&lt;br&gt;&lt;span&gt;})&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span&gt;&lt;span&gt;describe&lt;/span&gt;(&lt;span&gt;&amp;apos;Suite 1&amp;apos;&lt;/span&gt;, &lt;span&gt;() =&amp;gt;&lt;/span&gt; {&lt;/span&gt;&lt;br&gt;&lt;span&gt;  &lt;span&gt;it&lt;/span&gt;(&lt;span&gt;&amp;apos;works 1&amp;apos;&lt;/span&gt;, &lt;span&gt;() =&amp;gt;&lt;/span&gt; {&lt;/span&gt;&lt;br&gt;&lt;span&gt;    cy.&lt;span&gt;wrap&lt;/span&gt;(&lt;span&gt;&amp;apos;Hello&amp;apos;&lt;/span&gt;).&lt;span&gt;should&lt;/span&gt;(&lt;span&gt;&amp;apos;eq&amp;apos;&lt;/span&gt;, &lt;span&gt;&amp;apos;Hello&amp;apos;&lt;/span&gt;).&lt;span&gt;wait&lt;/span&gt;(&lt;span&gt;2000&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span&gt;    cy.&lt;span&gt;skip&lt;/span&gt;()&lt;/span&gt;&lt;br&gt;&lt;span&gt;    &lt;span&gt;// this command fails on purpose,&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span&gt;    &lt;span&gt;// we want to stop the test before we run it&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span&gt;    cy.&lt;span&gt;wrap&lt;/span&gt;(&lt;span&gt;42&lt;/span&gt;).&lt;span&gt;should&lt;/span&gt;(&lt;span&gt;&amp;apos;not.eq&amp;apos;&lt;/span&gt;, &lt;span&gt;42&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span&gt;  })&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span&gt;  &lt;span&gt;it&lt;/span&gt;(&lt;span&gt;&amp;apos;works 2&amp;apos;&lt;/span&gt;, &lt;span&gt;() =&amp;gt;&lt;/span&gt; {&lt;/span&gt;&lt;br&gt;&lt;span&gt;    cy.&lt;span&gt;wrap&lt;/span&gt;(&lt;span&gt;&amp;apos;Bye&amp;apos;&lt;/span&gt;).&lt;span&gt;should&lt;/span&gt;(&lt;span&gt;&amp;apos;eq&amp;apos;&lt;/span&gt;, &lt;span&gt;&amp;apos;Bye&amp;apos;&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span&gt;  })&lt;/span&gt;&lt;br&gt;&lt;span&gt;})&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&lt;p&gt;The custom command &lt;code&gt;cy.skip()&lt;/code&gt; can be added anywhere and it will mark the remaining individual commands using &lt;code&gt;&amp;lt;command&amp;gt;.skip&lt;/code&gt; method.&lt;/p&gt;&lt;center&gt;  &lt;video width=&quot;560&quot; height=&quot;315&quot; controls preload=&quot;none&quot; playsinline=&quot;true&quot; webkit-playsinline=&quot;true&quot; tabindex=&quot;-1&quot; muted loop&gt;    &lt;source src=&quot;https://glebbahmutov.com/images/cant-stop-wont-stop/skip-commands.mp4&quot; type=&quot;video/mp4&quot;&gt;    &lt;img src=&quot;https://glebbahmutov.com/images/cant-stop-wont-stop/skip-commands.png&quot;&gt;  &lt;/video&gt;&lt;/center&gt;&lt;p&gt;This approach offers an obvious advantage: you can still inspect the current test and see all completed commands. Of course, you can make this &lt;code&gt;cy.skip&lt;/code&gt; custom command as complex as needed: add condition / subject support, or run it conditionally using &lt;code&gt;cy.then(callback)&lt;/code&gt; syntax:&lt;/p&gt;&lt;figure&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;&lt;span&gt;1&lt;/span&gt;&lt;br&gt;&lt;span&gt;2&lt;/span&gt;&lt;br&gt;&lt;span&gt;3&lt;/span&gt;&lt;br&gt;&lt;span&gt;4&lt;/span&gt;&lt;br&gt;&lt;span&gt;5&lt;/span&gt;&lt;br&gt;&lt;span&gt;6&lt;/span&gt;&lt;br&gt;&lt;span&gt;7&lt;/span&gt;&lt;br&gt;&lt;span&gt;8&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre&gt;&lt;span&gt;cy.&lt;span&gt;get&lt;/span&gt;(...)&lt;/span&gt;&lt;br&gt;&lt;span&gt;  .&lt;span&gt;then&lt;/span&gt;(&lt;span&gt;&lt;span&gt;x&lt;/span&gt; =&amp;gt;&lt;/span&gt; {&lt;/span&gt;&lt;br&gt;&lt;span&gt;    &lt;span&gt;if&lt;/span&gt; (!x) {&lt;/span&gt;&lt;br&gt;&lt;span&gt;      &lt;span&gt;// no need to run the rest of the test&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span&gt;      cy.&lt;span&gt;skip&lt;/span&gt;()&lt;/span&gt;&lt;br&gt;&lt;span&gt;    }&lt;/span&gt;&lt;br&gt;&lt;span&gt;  })&lt;/span&gt;&lt;br&gt;&lt;span&gt;&lt;span&gt;// the rest of the test&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&lt;p&gt;Happy test stopping!&lt;/p&gt;</summary><author><name>Gleb Bahmutov</name></author><source gr:stream-id="feed/https://glebbahmutov.com/blog/atom.xml"><id>tag:google.com,2005:reader/feed/https://glebbahmutov.com/blog/atom.xml</id><title type="html">Better world by better software</title><link rel="alternate" href="https://glebbahmutov.com/blog/" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1786053600000"><id gr:original-id="https://wickstrom.tech/2026-08-07-bombadil-race-condition-antithesis.html">tag:google.com,2005:reader/item/0000065300000046</id><title type="html">How Antithesis Found and Explained a Bombadil Race Condition</title><published>2026-08-06T22:00:00Z</published><updated>2026-08-06T22:00:00Z</updated><link rel="alternate" href="https://wickstrom.tech/2026-08-07-bombadil-race-condition-antithesis.html" type="text/html"></link><summary type="html">&lt;p&gt;&lt;em&gt;Disclosure: I’m the original author and lead for the Bombadil project at Antithesis.&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://catala.dev/&quot;&gt;Carlos Catala&lt;/a&gt;, interning at Antithesis and working on testing our webapps, found a strange crash while I was out camping. The tests he works on runs Antithesis’ webapp &lt;em&gt;inside Antithesis&lt;/em&gt; and explores it using Bombadil. That surfaced a particular sequence of events leading up to the following crash (logs are simplified for readability):&lt;/p&gt; &lt;pre&gt;&lt;code&gt;state machine error: unhandled transition: Running(10) + ActionAccepted(Click(&amp;quot;Filters&amp;quot;))&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;What does this mean? To understand it, we need to back up a little.&lt;/p&gt; &lt;p&gt;The heart of the browser &lt;em&gt;driver&lt;/em&gt; is a finite state machine, an abstract model of a tab in Chrome or Chromium, and how we’re interacting with it over CDP. This is necessary due to how you can only invoke certain commands in certain browser states, or it might hang or behave in other confounding ways. In our state machine, some transitions are valid, and those are handled in a big &lt;code&gt;match (state, event) { ... }&lt;/code&gt; expression that returns a new state. Invalid transitions are covered by the last branch that returns an &lt;code&gt;Err&lt;/code&gt; with a message like the above.&lt;/p&gt; &lt;p&gt;There’s another important component involved which is called the &lt;em&gt;runner&lt;/em&gt;. It decides the control flow of the test, and uses the driver to run the system under test. The driver emits a state, and the runner decides what action to take in that state. It hands back the action to the driver so that it can apply it. The browser driver actually pauses the JS runtime when capturing a state, and doesn’t resume execution until the driver has given back the next action.&lt;/p&gt; &lt;p&gt;Hence, the &lt;code&gt;ActionAccepted&lt;/code&gt; event (which is when the driver gets a new action from the runner) is not valid in the &lt;code&gt;Running&lt;/code&gt; state. It really is only valid in the &lt;code&gt;Paused&lt;/code&gt; state. How could this happen? The driver and runner are supposed to operate in lock-step, where the driver is only in control while the JS runtime is paused. This was the nut to crack.&lt;/p&gt; &lt;p&gt;When Carlos told me about this during my PTO, my camping brain was definitely not helpful, so I let it rest until I was back at work. Staring at logs and code also didn’t help much, except for a poorly conceived theory about what could be going on, mislead by the presence of &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://antithesis.com/docs/product/fault_injection/fault_types/#network-faults&quot;&gt;network faults&lt;/a&gt; in one test where we saw the bug. We tried but failed to reproduce this locally, so I decided to find a simpler test subject and, crucially, try to reproduce it in Antithesis.&lt;/p&gt; &lt;h2 id=&quot;article-MzxzgWAfSzePJw32rNTeNDdKWpI-a-simple-reproduction-with-causality-analysis&quot;&gt;A Simple Reproduction with Causality Analysis&lt;/h2&gt; &lt;p&gt;To reduce possible confusion I wanted to first see if I could trigger the same bug in Bombadil with a simpler system under test. I found a Dockerized version of &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://the-internet.herokuapp.com/&quot;&gt;the-internet&lt;/a&gt;, an example application by Sauce Labs made for automated browser testing. Based on what we had seen before, I wrote a very small specification that only performs three actions:&lt;/p&gt; &lt;div id=&quot;article-MzxzgWAfSzePJw32rNTeNDdKWpI-cb2&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sourceCode language-typescript&quot;&gt;&lt;span id=&quot;article-MzxzgWAfSzePJw32rNTeNDdKWpI-cb2-1&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://wickstrom.tech/2026-08-07-bombadil-race-condition-antithesis.html#cb2-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span&gt;export&lt;/span&gt; &lt;span&gt;*&lt;/span&gt; &lt;span&gt;from&lt;/span&gt; &lt;span&gt;&amp;quot;@antithesishq/bombadil/browser/defaults/properties&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;article-MzxzgWAfSzePJw32rNTeNDdKWpI-cb2-2&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://wickstrom.tech/2026-08-07-bombadil-race-condition-antithesis.html#cb2-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span&gt;import&lt;/span&gt; { weighted } &lt;span&gt;from&lt;/span&gt; &lt;span&gt;&amp;quot;@antithesishq/bombadil/browser&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;article-MzxzgWAfSzePJw32rNTeNDdKWpI-cb2-3&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://wickstrom.tech/2026-08-07-bombadil-race-condition-antithesis.html#cb2-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span&gt;import&lt;/span&gt; {&lt;/span&gt; &lt;span id=&quot;article-MzxzgWAfSzePJw32rNTeNDdKWpI-cb2-4&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://wickstrom.tech/2026-08-07-bombadil-race-condition-antithesis.html#cb2-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; back&lt;span&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;article-MzxzgWAfSzePJw32rNTeNDdKWpI-cb2-5&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://wickstrom.tech/2026-08-07-bombadil-race-condition-antithesis.html#cb2-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; forward&lt;span&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;article-MzxzgWAfSzePJw32rNTeNDdKWpI-cb2-6&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://wickstrom.tech/2026-08-07-bombadil-race-condition-antithesis.html#cb2-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; clicks&lt;span&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;article-MzxzgWAfSzePJw32rNTeNDdKWpI-cb2-7&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://wickstrom.tech/2026-08-07-bombadil-race-condition-antithesis.html#cb2-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;} &lt;span&gt;from&lt;/span&gt; &lt;span&gt;&amp;quot;@antithesishq/bombadil/browser/defaults/actions&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;article-MzxzgWAfSzePJw32rNTeNDdKWpI-cb2-8&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://wickstrom.tech/2026-08-07-bombadil-race-condition-antithesis.html#cb2-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt; &lt;span id=&quot;article-MzxzgWAfSzePJw32rNTeNDdKWpI-cb2-9&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://wickstrom.tech/2026-08-07-bombadil-race-condition-antithesis.html#cb2-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span&gt;export&lt;/span&gt; &lt;span&gt;const&lt;/span&gt; navigation &lt;span&gt;=&lt;/span&gt; &lt;span&gt;weighted&lt;/span&gt;([&lt;/span&gt; &lt;span id=&quot;article-MzxzgWAfSzePJw32rNTeNDdKWpI-cb2-10&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://wickstrom.tech/2026-08-07-bombadil-race-condition-antithesis.html#cb2-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; [&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; clicks]&lt;span&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;article-MzxzgWAfSzePJw32rNTeNDdKWpI-cb2-11&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://wickstrom.tech/2026-08-07-bombadil-race-condition-antithesis.html#cb2-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; [&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; back]&lt;span&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;article-MzxzgWAfSzePJw32rNTeNDdKWpI-cb2-12&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://wickstrom.tech/2026-08-07-bombadil-race-condition-antithesis.html#cb2-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; [&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; forward]&lt;/span&gt; &lt;span id=&quot;article-MzxzgWAfSzePJw32rNTeNDdKWpI-cb2-13&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://wickstrom.tech/2026-08-07-bombadil-race-condition-antithesis.html#cb2-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;])&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; &lt;p&gt;In addition to finding various bugs in the Ruby code, it also immediately reproduced the Bombadil bug! Time to dig in. I went through a few instances and started to see a pattern. In addition, this gave me an excellent opportunity to try out &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://antithesis.com/docs/product/debugging/causality_analysis/&quot;&gt;Causality Analysis&lt;/a&gt;, a mind-bending feature for learning what behavior increases the likelihood of a bug appearing. Here’s the report I got:&lt;/p&gt; &lt;figure&gt; &lt;img class=&quot;bqrUnknownImgSize&quot; src=&quot;https://wickstrom.tech/assets/causality-analysis.webp&quot; alt=&quot;The causality analysis report plots the likelihood and helps you understand what events caused a certain bug.&quot;&gt; &lt;figcaption aria-hidden=&quot;true&quot;&gt;The causality analysis report plots the likelihood and helps you understand what events caused a certain bug.&lt;/figcaption&gt; &lt;/figure&gt; &lt;p&gt;As you may see in the chart, there are three points where the probability increases markedly. Correlating those with the logs (which is easy, you see the bumps highlighted in the log too), I could find the chain leading up to the bug:&lt;/p&gt; &lt;ol type=&quot;1&quot;&gt; &lt;li&gt;Click a link that navigates to &lt;code&gt;/frames&lt;/code&gt; (probability goes to 20%)&lt;/li&gt; &lt;li&gt;On that page, click a link that navigates to &lt;code&gt;/iframe&lt;/code&gt; (probability goes to 47%)&lt;/li&gt; &lt;li&gt;Go back (I was a bit surprised that this didn’t bump probability noticeably)&lt;/li&gt; &lt;li&gt;Go forward (probability goes to 99.98%)&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;After the last “Go forward” action, it’s a done deal. Digging into the details in between these points, I could then see how going back to a page which immediately throws an exception, after restoring from &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/bfcache&quot;&gt;bfcache&lt;/a&gt;, takes a different path than most page loads do.&lt;/p&gt; &lt;h2 id=&quot;article-MzxzgWAfSzePJw32rNTeNDdKWpI-the-bug&quot;&gt;The Bug&lt;/h2&gt; &lt;p&gt;When going back or forward in history, the state machine immediately transitions to &lt;code&gt;Running&lt;/code&gt;, waiting for confirmation by the browser to know what actually happened. Some pages prevent bfcache through JavaScript or HTTP headers, so a history navigation can also end up as a full page load with new HTTP requests. When the page is confirmed to have been restored from bfcache, the page and thus the state machine model skips the &lt;code&gt;Loading&lt;/code&gt; state entirely, and goes straight to &lt;code&gt;Running&lt;/code&gt;.&lt;/p&gt; &lt;p&gt;In this case, that was followed by the exception being thrown immediately (you can see it in the bottom of the screenshot above), which triggers another path: exceptions thrown while in &lt;code&gt;Running&lt;/code&gt; aren’t collected and reported at a later state capture, as is the case for the &lt;code&gt;Loading&lt;/code&gt; state — they immediately pause the runtime and trigger a new state read. This in turn let the runner pick a new action to perform. But the CDP event that confirms that the page was restored from bfcache hadn’t arrived yet.&lt;/p&gt; &lt;p&gt;This is a race between the asynchronous communication of runner and browser state machine, selecting the next action, and the CDP event sent by Chromium over a WebSocket confirming the bfcache restore. The unfortunate ordering that triggers the bug is:&lt;/p&gt; &lt;ol type=&quot;1&quot;&gt; &lt;li&gt;Back or forward, restoring from bfcache&lt;/li&gt; &lt;li&gt;Exception thrown on restored page, pausing the debugger and capturing a new state&lt;/li&gt; &lt;li&gt;Runner picking a new action and passing it back to the browser state machine&lt;/li&gt; &lt;li&gt;Confirmation of bfcache restoration coming in, transitioning state machine to &lt;code&gt;Running&lt;/code&gt;&lt;/li&gt; &lt;li&gt;State machine applying the &lt;code&gt;ActionAccepted&lt;/code&gt; event, which, as we noted in the beginning of this excursion, is not valid when in &lt;code&gt;Running&lt;/code&gt;&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;This sequence causes the crash. It only happens with bfcache-enabled history navigation to a page with an exception being thrown before the confirmation from Chromium comes back. Antithesis’ deterministic fuzzing environment messes with process scheduling and action selection and discovers this sequence reliably.&lt;/p&gt; &lt;h2 id=&quot;article-MzxzgWAfSzePJw32rNTeNDdKWpI-in-conclusion&quot;&gt;In Conclusion&lt;/h2&gt; &lt;p&gt;I’m not going to describe the fix in too much detail, but it involves a more robust use of the already existing &lt;code&gt;Generation&lt;/code&gt; value in the browser state machine. It’s a monotonically increasing number that is used to detect stale timeouts and actions, so that the state machine can discard them. The browser state now carries the current generation, and that is threaded through the runner’s action selection process, so that a stale action (as in step 5 above) can be safely ignored. Additionally, some transitions now increment the generation in cases where all existing timeouts or actions are stale.&lt;/p&gt; &lt;p&gt;I’ve had bugs of this kind before, and understanding them from staring at logs, let alone reproducing them, has been painful. This, in contrast, feels a bit like cheating. Moreover, it extends to race conditions and complicated bugs in the webapps themselves, which makes me very excited about continued work on the Bombadil and Antithesis integration.&lt;/p&gt;</summary><author><name>Oskar Wickström</name></author><source gr:stream-id="feed/https://wickstrom.tech/feed.xml"><id>tag:google.com,2005:reader/feed/https://wickstrom.tech/feed.xml</id><title type="html">Oskar Wickström</title><link rel="alternate" href="https://wickstrom.tech/" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1786044455000"><id gr:original-id="https://www.o2sn.dk/?p=1260">tag:google.com,2005:reader/item/0000100000000015</id><category term="Testing &amp; Quality Engineering"></category><category term="Automation"></category><category term="Leadership"></category><category term="LLM"></category><category term="Testmanagement"></category><title type="html">More about the testing, less about testers</title><published>2026-08-06T19:27:35Z</published><updated>2026-08-06T19:27:35Z</updated><link rel="alternate" href="https://www.o2sn.dk/2026/08/06/more-about-the-testing-less-about-testers/" type="text/html"></link><summary type="html">&lt;p&gt;I’m sure shift-left moved old-school testers task to the developers. Twenty odd years ago, when I started as a tester it was all about the test cases, about coverage and test techniques.  We spent loads of time covering basic system functionality, but with shift-left, the test automation pyramid and many other advances the basic tester’s task of juggling trivial system functionality was covered closer to the code. Hence, the basic testing job opportunities declined.&lt;/p&gt;



&lt;p&gt;It’s part of my ongoing experience that much “business” testing was better done with actual business representatives than a team of testers. Especially in the context of Software-as-a-service or standard system implementations: SAP ERP, Microsoft Dynamics Finance and Operations, ITIL implementations in ServiceNow and the like. I especially remember a Dynamics implementation for a public data services (yeah, it’s a thing here). The development team was configuration specialists and the “testers” actual public service case workers needing to work in the solution afterwards. My job as a test coordinator was primarily to setup a test case tooling and to follow up that tasks where finalized. Was this about testing – YES! But it was never about the testers. There where no formal test team, only actual case workers who had to juggle their “actual” job in the current system on the side.  &lt;/p&gt;



&lt;figure&gt;&lt;div&gt;
&lt;blockquote data-secret=&quot;li7YznIHY3&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.o2sn.dk/2021/01/25/the-testing-not-the-testers/&quot;&gt;The Testing, not the Testers&lt;/a&gt;&lt;/blockquote&gt;&lt;iframe width=&quot;500&quot; height=&quot;282&quot; src=&quot;https://www.o2sn.dk/2021/01/25/the-testing-not-the-testers/embed/&quot; allow=&quot;autoplay; fullscreen; encrypted-media; clipboard-write; picture-in-picture; web-share&quot; sandbox=&quot;allow-same-origin allow-scripts allow-forms allow-popups allow-presentation&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;&lt;/figure&gt;



&lt;p&gt;Recent years work experience in the consulting and outsourcing business has also given plenty of examples of testing tasks, that for historic reasons was usually a fringe in the larger testing spaces: usability, accessibility, compliance and security. Each of these are fields of their own, but could as easily been a space for a tester. Similarly I have experienced yet again over the past year, that was is required to lead testing activities is part project management skills, leadership and communication – less about documents and status reports. &lt;/p&gt;



&lt;figure&gt;&lt;div&gt;
&lt;blockquote data-secret=&quot;DNM7x9xo0Q&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.o2sn.dk/2020/06/03/someone-else-will-do-it-2020/&quot;&gt;Someone else will do it, 2020&lt;/a&gt;&lt;/blockquote&gt;&lt;iframe width=&quot;500&quot; height=&quot;282&quot; src=&quot;https://www.o2sn.dk/2020/06/03/someone-else-will-do-it-2020/embed/&quot; allow=&quot;autoplay; fullscreen; encrypted-media; clipboard-write; picture-in-picture; web-share&quot; sandbox=&quot;allow-same-origin allow-scripts allow-forms allow-popups allow-presentation&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;&lt;/figure&gt;



&lt;p&gt;So here we are, in 2026. Facing yet another technology shift. When the dust settles in a few years or so, there will be even less testing jobs about curating test cases. And there will be less formal testers in the delivery teams, as some of the menial testing tasks will have been substituted out by technology. In my part of the IT world of consulting and outsourcing, the signs are there that the team-embedded tester is more about automation and AI-test work, than classic hands-on system interaction testing.&lt;/p&gt;



&lt;p&gt;Still plenty of testing will happen, and plenty of testing needs coordination and alignment.    &lt;/p&gt;



&lt;p&gt;Plenty of solution and system requirements needs verification and validation. &lt;/p&gt;



&lt;p&gt;The sooner we step up and leave the “testers” label – the more we can grow the &lt;strong&gt;testing.&lt;/strong&gt; &lt;/p&gt;



&lt;p&gt;These are my experiences and “reading of the room” – Your milage may vary. &lt;/p&gt;</summary><author><name>Jesper</name></author><source gr:stream-id="feed/https://www.o2sn.dk/feed/"><id>tag:google.com,2005:reader/feed/https://www.o2sn.dk/feed/</id><title type="html">Jesper Ottosen</title><link rel="alternate" href="https://www.o2sn.dk" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1786037826209"><id gr:original-id="tag:blogger.com,1999:blog-3868566217808655382.post-684749975742149467">tag:google.com,2005:reader/item/000002c500000472</id><category term="bun"></category><category term="Playwright"></category><title type="html">What happens when you scaffold a Playwright framework and run installed tests using bun?</title><published>2026-08-06T17:37:06Z</published><updated>2026-08-06T17:37:06Z</updated><link rel="alternate" href="https://www.tjmaher.com/2026/08/what-happens-when-you-create-playwright.html" type="text/html"></link><summary type="html">We covered &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.tjmaher.com/2026/08/introducing-bun-new-package-manager-and.html&quot;&gt;in the last blog post &lt;/a&gt;how to install &lt;b&gt;bun&lt;/b&gt;, a new package manager. &lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;In this blog post, we will look into using bun to install a new Playwright framework. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;h2 style=&quot;text-align: left&quot;&gt;Create the Playwright Framework&lt;/h2&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;Once I installed bun on my Windows PC and was up and running I created a new folder, &amp;quot;bun-create-playwright&amp;quot;.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;I opened up that folder in VS Code, along with a new PowerShell terminal. In that terminal I entered:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;bun create playwright &lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;This activated the interactive Playwright installer that Playwright comes with. &lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;I selected I wanted it to create for me a &lt;b&gt;TypeScript&lt;/b&gt; project, placing the tests in the default folder, &lt;b&gt;tests&lt;/b&gt;, but I decided &lt;b&gt;not &lt;/b&gt;to add a GitHub Actions workflow. I wanted to experiment with using &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://gitlab.com/&quot;&gt;GitLab&lt;/a&gt;. &lt;/li&gt;&lt;li&gt;I chose it to set up and install all the browsers for me... which it did... using NPX, part of Node.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Wait a second, when it comes to our Playwright framework, doesn&amp;apos;t bun replace node?&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;No. Bun might be a JavaScript runtime, a package manager, and a bundler shipped as a single software tool, but in our case we are simply using it as a package manager in our Playwright framework. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;Bun works alongside Node.js in the Playwright project. We still use Playwright&amp;apos;s test runner, a Node.js program. Bun handles installations and run tasks.&lt;/div&gt;&lt;span&gt;&lt;a name=&quot;article-ipba3utewxtXmOfBHXypFRDf1_o-more&quot;&gt;&lt;/a&gt;&lt;/span&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;h3&gt;Alert: Windows Bug!&lt;/h3&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;Initially, that wasn&amp;apos;t enough to install Playwright&amp;apos;s internal browsers. There is a bug with bun + Playwright Windows where we also need to:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;bun add --dev @playwright/test&lt;/li&gt;&lt;li&gt;bunx playwright install&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;That was enough for the browsers to install.&lt;/div&gt;&lt;/div&gt;&lt;h3&gt;Create the Bun Lock File&lt;/h3&gt;&lt;div&gt;After the browsers are installed, we need to install bun in our project, to create from the package.json a bun installation. &lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Run in the Terminal: &lt;/b&gt;bun install&lt;/li&gt;&lt;li&gt;Review the newly created file bun.lock.file in the root directory of the project.&lt;/li&gt;&lt;li&gt;Delete the &lt;b&gt;package-lock.json&lt;/b&gt; file. &lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Add the test script to the Package.json&lt;/h3&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;If you look in the package.json file, you can see that the scripts code block is currently empty.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&amp;quot;scripts&amp;quot;: {}&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt; Inside this code block, we will be adding:&lt;/div&gt;&lt;br&gt;
  
  &lt;pre&gt;&lt;code&gt;&amp;quot;scripts&amp;quot;: {    
    &amp;quot;test&amp;quot;: &amp;quot;playwright test&amp;quot;  
  },
    &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;text-align: left&quot;&gt;Examine the Included Tests&lt;/h2&gt;&lt;div style=&quot;text-align: left&quot;&gt;Two tests will automatically be set up for you: &lt;/div&gt;&lt;div style=&quot;text-align: left&quot;&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;has title&lt;/b&gt;: Navigates to &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://playwright.dev&quot;&gt;playwright.dev&lt;/a&gt; and expects the title of the page to have the word &amp;quot;Playwright&amp;quot;.&lt;/li&gt;&lt;li&gt;&lt;b&gt;get started&lt;/b&gt;: Navigates to &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://playwright.dev&quot;&gt;playwright.dev&lt;/a&gt; and checks the &amp;quot;Get started&amp;quot; link.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left&quot;&gt;&lt;b&gt;&lt;u&gt;tests/ example.spec.ts&lt;/u&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left&quot;&gt;&lt;div style=&quot;background-color: #121314; color: #bbbebf; font-family: Consolas, &amp;quot;Courier New&amp;quot;, monospace; font-size: 14px; white-space: pre&quot;&gt;&lt;div&gt;&lt;span style=&quot;color: #c586c0&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #c9d1d9&quot;&gt;{ test, expect }&lt;/span&gt; &lt;span style=&quot;color: #c586c0&quot;&gt;from&lt;/span&gt; &lt;span style=&quot;color: #a5d6ff&quot;&gt;&amp;apos;@playwright/test&amp;apos;&lt;/span&gt;;&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;span style=&quot;color: #d2a8ff&quot;&gt;test&lt;/span&gt;(&lt;span style=&quot;color: #a5d6ff&quot;&gt;&amp;apos;has title&amp;apos;&lt;/span&gt;, &lt;span style=&quot;color: #569cd6&quot;&gt;async&lt;/span&gt; ({ &lt;span style=&quot;color: #ffa657&quot;&gt;page&lt;/span&gt; }) &lt;span style=&quot;color: #ff7b72&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #c9d1d9&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #c586c0&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ffa657&quot;&gt;page&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #d2a8ff&quot;&gt;goto&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #a5d6ff&quot;&gt;&amp;apos;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://playwright.dev/&quot;&gt;https://playwright.dev/&lt;/a&gt;&amp;apos;&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #8b949e&quot;&gt;// Expect a title &amp;quot;to contain&amp;quot; a substring.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #c586c0&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #d2a8ff&quot;&gt;expect&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ffa657&quot;&gt;page&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color: #d2a8ff&quot;&gt;toHaveTitle&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #a5d6ff&quot;&gt;/Playwright/&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;}&lt;/span&gt;);&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;span style=&quot;color: #d2a8ff&quot;&gt;test&lt;/span&gt;(&lt;span style=&quot;color: #a5d6ff&quot;&gt;&amp;apos;get started link&amp;apos;&lt;/span&gt;, &lt;span style=&quot;color: #569cd6&quot;&gt;async&lt;/span&gt; ({ &lt;span style=&quot;color: #ffa657&quot;&gt;page&lt;/span&gt; }) &lt;span style=&quot;color: #ff7b72&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #c9d1d9&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #c586c0&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ffa657&quot;&gt;page&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #d2a8ff&quot;&gt;goto&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #a5d6ff&quot;&gt;&amp;apos;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://playwright.dev/&quot;&gt;https://playwright.dev/&lt;/a&gt;&amp;apos;&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #8b949e&quot;&gt;// Click the get started link.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #c586c0&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ffa657&quot;&gt;page&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #d2a8ff&quot;&gt;getByRole&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #a5d6ff&quot;&gt;&amp;apos;link&amp;apos;&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;, { &lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #9cdcfe&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #a5d6ff&quot;&gt;&amp;apos;Get started&amp;apos;&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt; }).&lt;/span&gt;&lt;span style=&quot;color: #d2a8ff&quot;&gt;click&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #8b949e&quot;&gt;// Expects page to have a heading with the name of Installation.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #c586c0&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #d2a8ff&quot;&gt;expect&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ffa657&quot;&gt;page&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #d2a8ff&quot;&gt;getByRole&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #a5d6ff&quot;&gt;&amp;apos;heading&amp;apos;&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;, { &lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #9cdcfe&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #a5d6ff&quot;&gt;&amp;apos;Installation&amp;apos;&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt; })).&lt;/span&gt;&lt;span style=&quot;color: #d2a8ff&quot;&gt;toBeVisible&lt;/span&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #c9d1d9&quot;&gt;}&lt;/span&gt;);&lt;/div&gt;&lt;br&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;There are three stages you want to follow when you are designing an automated test:&lt;/div&gt;&lt;div&gt;&lt;ul style=&quot;text-align: left&quot;&gt;&lt;li&gt;&lt;b&gt;Arrange&lt;/b&gt;: Setup things like opening up a browser page.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Act&lt;/b&gt;: Go to a web site and see if you can get a link and click on it. &lt;/li&gt;&lt;li&gt;&lt;b&gt;Assert&lt;/b&gt;: Expect that the conditions of the tests are met, failing the test if the expected results and actual results do not match up.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;import &lt;/b&gt;pulls code that lives in another file or package so you can use it in your project. We import two specific named functions, &lt;i&gt;test &lt;/i&gt;and &lt;i&gt;expect&lt;/i&gt;, from the @playwright/test package (the Playwright Test framework&amp;apos;s core library). &lt;br&gt;&lt;ul style=&quot;text-align: left&quot;&gt;&lt;li&gt;test is a function used to define an individual test case. &lt;/li&gt;&lt;li&gt;expect is a function used to create assertions (checks that something is true, and fail the test if it isn&amp;apos;t). [ &lt;i&gt;See &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://playwright.dev/docs/test-assertions&quot;&gt;Playwright.dev / Assertions&lt;/a&gt;&lt;/i&gt; ]&lt;/li&gt;&lt;/ul&gt;The { test, expect } syntax is called a &amp;quot;named import&amp;quot;, getting specific things out of the package rather than the whole package as one object.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;test blocks&lt;/b&gt; set up two Playwright tests. Strings such as &amp;quot;has title&amp;quot; sets up the name of the test. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;async &lt;/b&gt;sets up this test function to be asynchronous, with many tests allowed to be executed at the same time as this one. The browser to run the first &amp;quot;has title&amp;quot; test might not be able to navigate to the page right away. The aync keyword allows the test to pause and wait for any slower actions to be completed before moving to the next part of the test. Once we set up async, we can use await later in the test. Meanwhile, it returns a &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;JavaScript Promise&lt;/a&gt;, a placeholder container until we determine the success or failure of the action, when it actually will contain a value. This promise will be either pending, fulfilled, or rejected. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;page &lt;/b&gt;sets up the pre-defined Playwright page fixture [ See &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://playwright.dev/docs/test-fixtures&quot;&gt;Playwright.dev / Fixtures&lt;/a&gt; ]. With this call, before the individual test starts, a fresh isolated page is launched just for this test, so the &amp;quot;has title&amp;quot; test does not interfere with the &amp;quot;get started&amp;quot; test. This page fixture has automatic setup and teardown. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;=&amp;gt;&lt;/b&gt; is a &amp;quot;hash rocket&amp;quot;, representing the &amp;quot;arrow function&amp;quot;, separating the earlier parameters of the test with the coming body of the test function. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;await&lt;/b&gt; returns a Promise, a placeholder, so if we can&amp;apos;t do something like go to a page right away, the test won&amp;apos;t automatically go to the next line of code and possibly fail. Playwright by default waits 30 seconds for a goto to complete, 30 seconds for an action to happen, but only 5 seconds on an assertion like &amp;quot;expect&amp;quot;. If it goes over that timeout, the test will fail.  &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;goto&lt;/b&gt; is part of the &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://playwright.dev/docs/api/class-page#page-goto&quot;&gt;Page fixture&lt;/a&gt;, that automatically handles page navigation. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;expect&lt;/b&gt; is an assertion. By default, the test expects this condition to be met within five minutes, else the test fails.  &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;toHaveTitle &lt;/b&gt;is a built in &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-title&quot;&gt;Playwright page assertion&lt;/a&gt;. It allows regular expressions such as /Playwright/ to let the test know that having the word &amp;quot;Playwright&amp;quot; in the title is acceptable. Playwright has many assertions, &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://playwright.dev/docs/api/class-pageassertions&quot;&gt;such as the PageAssertions&lt;/a&gt; toHaveTitle, toHaveURL, toHaveScrreenshot(name).&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;getByRole&lt;/b&gt; is &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://playwright.dev/docs/api/class-locator#locator-get-by-role&quot;&gt;a Playwright Locator&lt;/a&gt;, that helps you find a web element on the page. Are you looking for a certain alert, alertDialog, banner, button, checkbox, heading, img, link, listbox, menu, menubar, list, listbox, progressbar, searchbox, table, or textbox, tooltip, amongst others? You can try to getByRole. With this you are locating elements by their &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.w3.org/TR/wai-aria-1.2/#roles&quot;&gt;ARIA role&lt;/a&gt;, &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.w3.org/TR/wai-aria-1.2/#aria-attributes&quot;&gt;ARIA attributes&lt;/a&gt; and &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://w3c.github.io/accname/#dfn-accessible-name&quot;&gt;accessible name&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;... Note that with locators, you can also getByTestId, getByAltText, getByText, getByTitle, etc. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;.click&lt;/b&gt; is a &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://playwright.dev/docs/input&quot;&gt;Playwright action&lt;/a&gt; you can perform.&lt;/div&gt;&lt;div&gt;&lt;ul style=&quot;text-align: left&quot;&gt;&lt;li&gt;Once you found an element by a locator, you can .click or .dblclick it, .click({ button: &amp;apos;right&amp;apos; }) or .click({ modifiers: [&amp;apos;Shift&amp;apos;]}), and .hover.&lt;/li&gt;&lt;li&gt;You can .check a checkbox or .selectOption on a radio button, and expect it .toBeChecked. &lt;/li&gt;&lt;li&gt;You can drag and drop an item. &lt;/li&gt;&lt;li&gt;You can fill a textbox, input field, or text area. &lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;b&gt;.toByVisible&lt;/b&gt; is a &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://playwright.dev/docs/api/class-locatorassertions&quot;&gt;Playwright Locator Assertion&lt;/a&gt;. &lt;/div&gt;&lt;div&gt;&lt;ul style=&quot;text-align: left&quot;&gt;&lt;li&gt;Once you found an element by a &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://playwright.dev/docs/api/class-locator&quot;&gt;Playwright locator&lt;/a&gt;, you can in the test expect it .toBeChecked, .toBeDisabled, .toBeEditable, .toBeEmpty, .toBeEnabled, .toBeFocused, .toBeHidden, .toBeInViewport, .toBeVisible, .toContainClass, .toContainText, /toHavaAccessibleDescription, .toHaveAttribute, .toHaveId, .toHaveRole, .toHaveText, .toHaveValue. &lt;/li&gt;&lt;li&gt;Each of these methods can be negated chaining a &amp;quot;not&amp;quot; value. Expect a text box .not.toBeEmpty. &lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 style=&quot;text-align: left&quot;&gt;Execute the Playwright Tests: Bun Run Test&lt;/h2&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;Now, we should be able to run the tests that come with the initial Playwright scaffolding:&lt;/div&gt;&lt;div&gt;&lt;ul style=&quot;text-align: left&quot;&gt;&lt;li&gt;bun run test&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;The Playwright tests, are automatically run in Chromium, Firefox, and WebKit / Safari, and should pass. &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;You can see the results if you open up the &lt;b&gt;bun-create-playwright&lt;/b&gt; folder in an IDE such as VS Code:&lt;/div&gt;&lt;div&gt;&lt;ul style=&quot;text-align: left&quot;&gt;&lt;li&gt;Go to the playwright-report folder&lt;/li&gt;&lt;li&gt;Right click on the index.html file that was produced.&lt;/li&gt;&lt;li&gt;Select &amp;quot;Open with Live Server&amp;quot;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;div style=&quot;clear: both; text-align: center&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEiXctKCd4pvQbwjsbEHO8s0z3slVGJdvPXcJnOi5kY64GDzY0fDp5oBkCSuJNycXgS3RziW_kGXLB0q5iMwI79QxuRDJJ3-08T0mGt4evCqlMBzhZa8KB-w31DIOf_OsspME2rJrWI3YltGuJm1JYHljma6JsWxtjJZBGGFVsnedk4P80W45tJH01wOV6c&quot; style=&quot;margin-left: 1em; margin-right: 1em&quot;&gt;&lt;img class=&quot;bqrUnknownImgSize&quot; data-original-height=&quot;414&quot; data-original-width=&quot;549&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEiXctKCd4pvQbwjsbEHO8s0z3slVGJdvPXcJnOi5kY64GDzY0fDp5oBkCSuJNycXgS3RziW_kGXLB0q5iMwI79QxuRDJJ3-08T0mGt4evCqlMBzhZa8KB-w31DIOf_OsspME2rJrWI3YltGuJm1JYHljma6JsWxtjJZBGGFVsnedk4P80W45tJH01wOV6c=s1600&quot; title=&quot;Playwright test results&quot;&gt;&lt;/a&gt;&lt;/div&gt;&lt;br&gt;You can drill down into the test to see more information about the tests. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;clear: both; text-align: center&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEitA1iq8y_stUm8mfoEKFSwUlgy_gPeD5qC1LFi2q0VWzdZLiZlTupEW72bg0KkeHoNSWpLpXrZe02dPWGNPjPZyuAQTyBpr1ewtBMiJxb-GKrG0jFKEfZzt89Br0HDyWIHBZi5CEzVxywqNupP-OvwhpVl7LU8LuCCG91soltvdVOqHcDIFlll0giy_Dg&quot; style=&quot;margin-left: 1em; margin-right: 1em&quot;&gt;&lt;img width=&quot;482&quot; height=&quot;640&quot; data-original-height=&quot;931&quot; data-original-width=&quot;701&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEitA1iq8y_stUm8mfoEKFSwUlgy_gPeD5qC1LFi2q0VWzdZLiZlTupEW72bg0KkeHoNSWpLpXrZe02dPWGNPjPZyuAQTyBpr1ewtBMiJxb-GKrG0jFKEfZzt89Br0HDyWIHBZi5CEzVxywqNupP-OvwhpVl7LU8LuCCG91soltvdVOqHcDIFlll0giy_Dg=w482-h640&quot;&gt;&lt;/a&gt;&lt;/div&gt;&lt;br&gt;&lt;br&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;h2&gt;What Does Playwright Install? &lt;/h2&gt;&lt;/div&gt;&lt;div&gt;The Playwright scaffolder installs:&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b style=&quot;text-decoration-line: underline&quot;&gt;node_modules&lt;/b&gt; folder: &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;blockquote style=&quot;border-color: currentcolor; border-image: none; border-style: none; border-width: medium; border: none; margin: 0px 0px 0px 40px; padding: 0px&quot;&gt;&lt;div style=&quot;text-align: left&quot;&gt;Created by a package manager (npm, yarn, bun, pnpm) when you install dependencies. Contains the actual source code of every package your project depends on, plus the dependencies of those dependencies (transitive dependencies), recursively. It&amp;apos;s populated by running an install command (npm install, bun install, etc.), and never edited by hand. &lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;blockquote style=&quot;border-color: currentcolor; border-image: none; border-style: none; border-width: medium; border: none; margin: 0px 0px 0px 40px; padding: 0px&quot;&gt;&lt;div style=&quot;text-align: left&quot;&gt;Node&amp;apos;s module resolution algorithm looks inside node_modules when you import/require a package by name.&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;blockquote style=&quot;border-color: currentcolor; border-image: none; border-style: none; border-width: medium; border: none; margin: 0px 0px 0px 40px; padding: 0px&quot;&gt;&lt;div style=&quot;text-align: left&quot;&gt;Contains .bin, @playwright, @types. bun-types, playwright, playwright-core, typescript, undici-types. According to Claude.ai: &lt;/div&gt;&lt;/blockquote&gt;&lt;blockquote style=&quot;border-color: currentcolor; border-image: none; border-style: none; border-width: medium; margin: 0px 0px 0px 40px; padding: 0px; text-align: left&quot;&gt;&lt;br&gt;&lt;b&gt;.bin&lt;/b&gt;: Executable scripts for installed packages. This is where npm/bun puts symlinks (&lt;i&gt;symbolic links&lt;/i&gt;) to CLI (&lt;i&gt;Command Line Interface&lt;/i&gt;) tools so you can run them via npx playwright or through package.json scripts, instead of needing global installation of every executable. &lt;/blockquote&gt;&lt;br&gt;&lt;blockquote style=&quot;border-color: currentcolor; border-image: none; border-style: none; border-width: medium; margin: 0px 0px 0px 40px; padding: 0px; text-align: left&quot;&gt;&lt;b&gt;@playwright&lt;/b&gt;: Scoped npm namespace. Typically contains @playwright/test, the Playwright Test runner package (test runner, assertions, fixtures, config handling — what you import when you write import { test, expect } from &amp;apos;@playwright/test&amp;apos;). &lt;/blockquote&gt;&lt;br&gt;&lt;blockquote style=&quot;border-color: currentcolor; border-image: none; border-style: none; border-width: medium; margin: 0px 0px 0px 40px; padding: 0px&quot;&gt;&lt;b&gt;@types&lt;/b&gt;: Folder that Bun creates to hold TypeScript type declaration packages published under the @types scope on npm. These packages come from &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://definitelytyped.org&quot;&gt;DefinitelyTyped.org&lt;/a&gt;, a large community-maintained repository on GitHub where volunteers write and publish TypeScript type declarations for JavaScript libraries that don&amp;apos;t include their own. When a package doesn&amp;apos;t ship built-in types (common for older libraries or runtime built-ins like Node.js itself), DefinitelyTyped contributors write a separate package describing that library&amp;apos;s functions, arguments, and return values, then publish it to npm as @types/&amp;lt;library-name&amp;gt;These give you IntelliSense and type-checking for JS APIs.&lt;/blockquote&gt;&lt;br&gt;&lt;blockquote style=&quot;border-color: currentcolor; border-image: none; border-style: none; border-width: medium; margin: 0px 0px 0px 40px; padding: 0px; text-align: left&quot;&gt;&lt;b&gt;bun-types&lt;/b&gt;: Type declarations for Bun&amp;apos;s runtime APIs (Bun.file, Bun.serve, etc.), letting TypeScript understand Bun-specific globals if you&amp;apos;re running/building with Bun instead of Node. &lt;/blockquote&gt;&lt;br&gt;&lt;blockquote style=&quot;border-color: currentcolor; border-image: none; border-style: none; border-width: medium; margin: 0px 0px 0px 40px; padding: 0px; text-align: left&quot;&gt;&lt;b&gt;playwright&lt;/b&gt;: The full Playwright package, including the browser automation driver and CLI. This is distinct from @playwright/test: playwright is the core library (browser launching, contexts, pages), while @playwright/test builds the test runner on top of it. &lt;/blockquote&gt;&lt;br&gt;&lt;blockquote style=&quot;border-color: currentcolor; border-image: none; border-style: none; border-width: medium; margin: 0px 0px 0px 40px; padding: 0px; text-align: left&quot;&gt;&lt;b&gt;playwright-core&lt;/b&gt;: The stripped-down core of Playwright without the browser-download step. playwright depends on this internally; you&amp;apos;d typically only see it listed as a top-level dependency if something needs Playwright&amp;apos;s automation APIs without auto-downloading browser binaries. &lt;/blockquote&gt;&lt;br&gt;&lt;blockquote style=&quot;border-color: currentcolor; border-image: none; border-style: none; border-width: medium; margin: 0px 0px 0px 40px; padding: 0px; text-align: left&quot;&gt;&lt;b&gt;typescript&lt;/b&gt;: The TypeScript compiler (tsc) itself, used for type-checking and/or transpiling .ts files. &lt;/blockquote&gt;&lt;br&gt;&lt;blockquote style=&quot;border-color: currentcolor; border-image: none; border-style: none; border-width: medium; margin: 0px 0px 0px 40px; padding: 0px; text-align: left&quot;&gt;&lt;b&gt;undici-types&lt;/b&gt;: type declarations for undici, Node&amp;apos;s HTTP client, pulled in automatically by @types/node.&lt;/blockquote&gt; &lt;div style=&quot;text-align: left&quot;&gt;&lt;br&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left&quot;&gt;&lt;b style=&quot;text-decoration-line: underline&quot;&gt;playwright-report&lt;/b&gt; folder:&lt;/div&gt;&lt;div style=&quot;text-align: left&quot;&gt;&lt;br&gt;&lt;/div&gt;&lt;blockquote style=&quot;border-color: currentcolor; border-image: none; border-style: none; border-width: medium; margin: 0px 0px 0px 40px; padding: 0px; text-align: left&quot;&gt;A folder to store HTML Reports produced after a test run. &lt;/blockquote&gt;&lt;blockquote style=&quot;border-color: currentcolor; border-image: none; border-style: none; border-width: medium; border: none; margin: 0px 0px 0px 40px; padding: 0px&quot;&gt;&lt;p style=&quot;text-align: left&quot;&gt; According to &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://playwright.dev/docs/test-reporters#html-reporter&quot;&gt;Playwright.dev / HTML Reporter&lt;/a&gt;, &amp;quot;HTML reporter produces a self-contained folder that contains report for the test run that can be served as a web page. &lt;/p&gt;&lt;/blockquote&gt;&lt;blockquote style=&quot;border-color: currentcolor; border-image: none; border-style: none; border-width: medium; border: none; margin: 0px 0px 0px 40px; padding: 0px&quot;&gt;&lt;p style=&quot;text-align: left&quot;&gt;&amp;quot;[...] By default, HTML report is opened automatically if some of the tests failed. You can control this behavior via the open property in the Playwright config or the PLAYWRIGHT_HTML_OPEN environmental variable. The possible values for that property are always, never and on-failure (default)&amp;quot;.&lt;/p&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;b&gt;&lt;u&gt;test-results&lt;/u&gt;&lt;/b&gt; folder:&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;blockquote style=&quot;border-color: currentcolor; border-image: none; border-style: none; border-width: medium; border: none; margin: 0px 0px 0px 40px; padding: 0px&quot;&gt;&lt;div style=&quot;text-align: left&quot;&gt;After running the test, it contains .last-run.json which contains &amp;quot;status: passed&amp;quot; with an empty array of failedTests. &lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;u&gt;tests&lt;/u&gt;&lt;/b&gt; folder:&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;blockquote style=&quot;border-color: currentcolor; border-image: none; border-style: none; border-width: medium; border: none; margin: 0px 0px 0px 40px; padding: 0px&quot;&gt;&lt;div style=&quot;text-align: left&quot;&gt;&lt;b&gt;example.spec.ts&lt;/b&gt; contains the pre-installed Playwright tests we have already covered. &lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;u&gt;.gitignore&lt;/u&gt;&lt;/b&gt;:&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;blockquote style=&quot;border-color: currentcolor; border-image: none; border-style: none; border-width: medium; border: none; margin: 0px 0px 0px 40px; padding: 0px&quot;&gt;&lt;div style=&quot;text-align: left&quot;&gt;Want something to not be checked in, committed, and merged to an outside source? Place it here. &lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;blockquote style=&quot;border-color: currentcolor; border-image: none; border-style: none; border-width: medium; border: none; margin: 0px 0px 0px 40px; padding: 0px&quot;&gt;&lt;div style=&quot;text-align: left&quot;&gt;Playwright automatically has it so node_modules, local test-results, local playwright-reports, and things in the local .cache and .auth do not get committed. &lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;u&gt;bun.lock&lt;/u&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;This lockfile is produced by &amp;quot;bun install&amp;quot;. Why have a lockfile? According to &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://lock-file-in-programming-why-does-it-matter.pages.dev/&quot;&gt;Code Protection Hub&lt;/a&gt;, &lt;/div&gt;&lt;br&gt;&lt;blockquote style=&quot;border-color: currentcolor; border-image: none; border-style: none; border-width: medium; margin: 0px 0px 0px 40px; padding: 0px; text-align: left&quot;&gt;&amp;quot;The entire philosophy of lock file programming revolves around a concept called Semantic Versioning (SemVer). In a manifest file (like package.json), developers specify acceptable version ranges using caret (^) or tilde (~) symbols. For example, ^2.4.1 allows the package manager to download minor updates and bug fixes (up to version 3.0.0).&lt;/blockquote&gt;&lt;br&gt;&lt;blockquote style=&quot;border-color: currentcolor; border-image: none; border-style: none; border-width: medium; margin: 0px 0px 0px 40px; padding: 0px; text-align: left&quot;&gt;&amp;quot;While this allows projects to automatically receive security patches, it introduces a severe risk: Dependency Drift.&lt;/blockquote&gt;&lt;br&gt;&lt;blockquote style=&quot;border-color: currentcolor; border-image: none; border-style: none; border-width: medium; margin: 0px 0px 0px 40px; padding: 0px; text-align: left&quot;&gt;&amp;quot;Imagine Developer A runs npm install on Monday and receives version 2.4.1. On Friday, the package author publishes version 2.5.0 containing a subtle bug. When Developer B joins the team and runs npm install, they receive the buggy 2.5.0 version. The application breaks for Developer B, but works perfectly for Developer A. This is the classic &amp;quot;it works on my machine&amp;quot; nightmare.&lt;br&gt;The lock file acts as a historical snapshot. It records the exact version, the registry URL, and the cryptographic hash (SHA-512) of the code downloaded on Monday. When Developer B installs the project, the package manager ignores the flexible package.json ranges and strictly enforces the exact tree defined in the lock file&amp;quot;. &lt;/blockquote&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;u&gt;package.json:&lt;/u&gt;&lt;/b&gt;&lt;/div&gt;&lt;br&gt;&lt;br&gt;From &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://heynode.com/tutorial/what-packagejson/&quot;&gt;HeyNode / What is Package.json&lt;/a&gt;: &lt;br&gt;&lt;br&gt;&lt;blockquote style=&quot;border-color: currentcolor; border-image: none; border-style: none; border-width: medium; margin: 0px 0px 0px 40px; padding: 0px; text-align: left&quot;&gt;&amp;quot;If you’ve worked with Node.js before, you have likely encountered a package.json file. It is a &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://www.json.org/&quot;&gt;JSON&lt;/a&gt; file that lives in the root directory of your project. Your package.json holds important information about the project. It contains human-readable metadata about the project (like the project name and description) as well as functional metadata like the package version number and a list of dependencies required by the application.&lt;/blockquote&gt;&lt;br&gt;&lt;blockquote style=&quot;border-color: currentcolor; border-image: none; border-style: none; border-width: medium; margin: 0px 0px 0px 40px; padding: 0px; text-align: left&quot;&gt;&amp;quot;Your project’s package.json is the central place to configure and describe how to interact with and run your application. It is used by the npm CLI (and yarn) to identify your project and understand how to handle the project’s dependencies. It’s the package.json file that enables npm to start your project, run scripts, install dependencies, publish to the NPM registry, and many other useful tasks. The npm CLI is also the best way to manage your package.json because it helps generate and update your package.json file throughout a project’s life.&lt;/blockquote&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;blockquote style=&quot;border: none; margin: 0 0 0 40px; padding: 0px&quot;&gt;&lt;div style=&quot;text-align: left&quot;&gt;&amp;quot;Your package.json fills several roles in the lifecycle of your project, some of which only apply for packages published to NPM. If you’re not publishing your project to the NPM registry or otherwise making it publicly available to others, your package.json is still essential to the development flow.&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;blockquote style=&quot;border: none; margin: 0 0 0 40px; padding: 0px&quot;&gt;&lt;div style=&quot;text-align: left&quot;&gt;&amp;quot;The &lt;b&gt;name &lt;/b&gt;field defines the name of the package. When publishing to the NPM registry, this is the name the package will be listed under. It must be no more than 214 characters, only lowercase letters, and it must be URL-safe (hyphens and underscores allowed, but no spaces or other characters disallowed in URLs).&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;blockquote style=&quot;border: none; margin: 0 0 0 40px; padding: 0px&quot;&gt;&lt;div style=&quot;text-align: left&quot;&gt;&amp;quot;The &lt;b&gt;version &lt;/b&gt;field is very important for any published package, and required before publishing. It is the current version of the software that the package.json is describing.&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;blockquote style=&quot;border: none; margin: 0 0 0 40px; padding: 0px&quot;&gt;&lt;div style=&quot;text-align: left&quot;&gt;&amp;quot;You are not required to use &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://docs.npmjs.com/about-semantic-versioning&quot;&gt;SemVer&lt;/a&gt;, but it is the standard used in the Node.js ecosystem and highly recommended. For an unpublished package, this property isn’t strictly required. Typically, the version number is bumped according to SemVer before publishing new versions to NPM. &lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;blockquote style=&quot;border: none; margin: 0 0 0 40px; padding: 0px&quot;&gt;&lt;div style=&quot;text-align: left&quot;&gt;&amp;quot;The &lt;b&gt;license &lt;/b&gt;field lets us define what license applies to the code the package.json is describing. Again, this is very important when publishing a project to the NPM registry, as the license may limit the use of your software by some developers or organizations. Having a clear license in place helps clearly define what terms the software is able to be used under&amp;quot;.&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;
{
  &amp;quot;name&amp;quot;: &amp;quot;bun-create-playwright&amp;quot;,
  &amp;quot;version&amp;quot;: &amp;quot;1.0.0&amp;quot;,
  &amp;quot;description&amp;quot;: &amp;quot;&amp;quot;,
  &amp;quot;main&amp;quot;: &amp;quot;index.js&amp;quot;,
  &amp;quot;scripts&amp;quot;: {
    &amp;quot;test&amp;quot;: &amp;quot;playwright test&amp;quot;
  },
  &amp;quot;keywords&amp;quot;: [],
  &amp;quot;author&amp;quot;: &amp;quot;&amp;quot;,
  &amp;quot;license&amp;quot;: &amp;quot;ISC&amp;quot;,
  &amp;quot;type&amp;quot;: &amp;quot;commonjs&amp;quot;,
  &amp;quot;devDependencies&amp;quot;: {
    &amp;quot;@playwright/test&amp;quot;: &amp;quot;^1.62.1&amp;quot;,
    &amp;quot;@types/bun&amp;quot;: &amp;quot;latest&amp;quot;,
    &amp;quot;@types/node&amp;quot;: &amp;quot;^26.1.2&amp;quot;
  },
  &amp;quot;private&amp;quot;: true,
  &amp;quot;peerDependencies&amp;quot;: {
    &amp;quot;typescript&amp;quot;: &amp;quot;^5&amp;quot;
  }
}      
      &lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;u&gt;playwright.config.ts:&lt;/u&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;u&gt;&lt;br&gt;&lt;/u&gt;&lt;/b&gt;&lt;/div&gt;&lt;/div&gt;&lt;blockquote style=&quot;border: none; margin: 0 0 0 40px; padding: 0px&quot;&gt;&lt;div style=&quot;text-align: left&quot;&gt;This &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://playwright.dev/docs/test-configuration&quot;&gt;Playwright Configuration file&lt;/a&gt; is the central configuration file for a Playwright test project. It lives at the root of your project and tells Playwright how to run your tests: which browsers to use, where to find test files, how to handle failures, what reports to generate, etc. Instead of passing a dozen command-line flags every time you run tests, you define the settings once here.&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;div&gt;
&lt;pre&gt;&lt;code&gt;
import { defineConfig, devices } from &amp;apos;@playwright/test&amp;apos;;

/**
 * Read environment variables from file.
 * &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/motdotla/dotenv&quot;&gt;https://github.com/motdotla/dotenv&lt;/a&gt;
 */
// import dotenv from &amp;apos;dotenv&amp;apos;;
// import path from &amp;apos;path&amp;apos;;
// dotenv.config({ path: path.resolve(__dirname, &amp;apos;.env&amp;apos;) });

/**
 * See &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://playwright.dev/docs/test-configuration&quot;&gt;https://playwright.dev/docs/test-configuration&lt;/a&gt;.
 */
export default defineConfig({      &lt;/code&gt;
&lt;/pre&gt;      
      &lt;br&gt;Breakdown of the main components&lt;br&gt;&lt;ul style=&quot;text-align: left&quot;&gt;&lt;li&gt;&lt;b&gt;testDir&lt;/b&gt;: points Playwright to the folder containing your spec files.&lt;/li&gt;&lt;li&gt;&lt;b&gt;fullyParallel&lt;/b&gt;: controls whether tests within a single file run in parallel workers rather than sequentially.&lt;/li&gt;&lt;li&gt;&lt;b&gt;forbidOnly&lt;/b&gt;: a safety check, usually enabled only in CI, that fails the build if test.only was left in the code.&lt;/li&gt;&lt;li&gt;&lt;b&gt;retries&lt;/b&gt;: how many times a failed test is retried before being marked as failed. Commonly set higher in CI than locally.&lt;/li&gt;&lt;li&gt;&lt;b&gt;workers&lt;/b&gt;: how many tests run concurrently. CI environments often limit this to avoid resource contention.&lt;/li&gt;&lt;li&gt;&lt;b&gt;reporter&lt;/b&gt;: determines the output format for test results (HTML report, list in the terminal, JUnit XML for CI integration, etc). You can specify multiple reporters at once.&lt;/li&gt;&lt;li&gt;&lt;b&gt;use&lt;/b&gt;: shared defaults inherited by every test, unless overridden at the project or test level. Common settings here:&lt;/li&gt;&lt;ul&gt;&lt;li&gt;baseURL for relative navigation &lt;/li&gt;&lt;li&gt;trace for capturing a debuggable trace of the test run &lt;/li&gt;&lt;li&gt;screenshot and video for failure artifacts &lt;/li&gt;&lt;li&gt;headless to control whether the browser UI is shown &lt;/li&gt;&lt;/ul&gt;&lt;li&gt;projects: defines the different browser/device combinations to run the same test suite against. Each project can also override anything in use. This is how you get cross-browser coverage without duplicating test code.&lt;/li&gt;&lt;/ul&gt;With the next post, we are going to make some changes to the project per Playwright Ambassador Butch Mayhew&amp;apos;s recommendation. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;Happy Testing! &lt;br&gt;&lt;br&gt;
-T.J. Maher&lt;br&gt;
Software Engineer in Test&lt;br&gt;
&lt;br&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://bsky.app/profile/tjmaher1.bsky.social&quot;&gt;BlueSky&lt;/a&gt; | &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://bit.ly/tj_youtube&quot;&gt;YouTube&lt;/a&gt; | &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.linkedin.com/in/tjmaher1&quot;&gt;LinkedIn&lt;/a&gt; | &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://www.tjmaher.com/p/media.html&quot;&gt;Articles&lt;/a&gt;&lt;/div&gt;</summary><author><name>T.J. Maher</name></author><source gr:stream-id="feed/http://www.tjmaher.com/feeds/posts/default"><id>tag:google.com,2005:reader/feed/http://www.tjmaher.com/feeds/posts/default</id><title type="html">Adventures in Automation</title><link rel="alternate" href="https://www.tjmaher.com/" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1786027293000"><id gr:original-id="6a748cd0cc18b1150270a192">tag:google.com,2005:reader/item/00000fda00000020</id><title type="html">Doing More With Less: Redefining Value in Software Delivery</title><published>2026-08-06T14:41:33Z</published><updated>2026-08-06T14:41:33Z</updated><link rel="alternate" href="https://www.evolvesoftwareconsulting.com/post/doing-more-with-less-redefining-value-in-software-delivery" type="text/html"></link><summary type="html">Software delivery has never been easy. Today, many teams are expected to deliver more features, faster, with fewer people and tighter budgets. Yet expectations haven&amp;apos;t reduced—they&amp;apos;ve increased. The temptation is to respond by working harder: longer hours, bigger backlogs, saying yes to every request. But that approach doesn&amp;apos;t scale. It creates burnout, increases technical debt, and ultimately slows delivery. Doing more with less isn&amp;apos;t about squeezing more from your teams. It&amp;apos;s about making...&lt;p style=&quot;clear: both&quot;&gt;&lt;/p&gt;&lt;p data-bqr-info=&quot;attachment&quot;&gt;&lt;img class=&quot;bqrUnknownImgSize&quot; src=&quot;https://static.wixstatic.com/media/0054f4_06556811ba5747d2a616e73962079780~mv2.png/v1/fit/w_1000,h_1000,al_c,q_80/file.png&quot;&gt;&lt;/p&gt;</summary><author><name>Phil Hargreaves</name></author><source gr:stream-id="feed/https://www.evolvesoftwareconsulting.com/blog-feed.xml"><id>tag:google.com,2005:reader/feed/https://www.evolvesoftwareconsulting.com/blog-feed.xml</id><title type="html">Evolve Software Consulting Ltd</title><link rel="alternate" href="https://www.evolvesoftwareconsulting.com/blog" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1786005236000"><id gr:original-id="https://reframequality.com/?p=3486">tag:google.com,2005:reader/item/000010310000000a</id><category term="Testing ROI"></category><category term="AI"></category><category term="Test Strategy"></category><title type="html">The Second Law of Software Delivery</title><published>2026-08-06T08:33:56Z</published><updated>2026-08-06T08:33:56Z</updated><link rel="alternate" href="https://reframequality.com/the-second-law-of-software-delivery/" type="text/html"></link><summary type="html">&lt;p&gt;&lt;em&gt;Why the single plan everyone signed off never had a chance — and what actually holds delivery together&lt;/em&gt;&lt;/p&gt;



&lt;div&gt;
&lt;p&gt;The moment a delivery plan is signed off is the most ordered your project will ever be. Everything after that point pulls against it. A requirement gets interpreted. An architecture decision quietly reshapes what is feasible. Three developers read the same ticket and build three subtly different things. An AI assistant generates a plausible function nobody fully reads. A business analyst reconciles two stakeholders who wanted different outcomes. Each of these is someone capable doing their job well — and each nudges the work a fraction away from the tidy single path everyone agreed to.&lt;/p&gt;
&lt;/div&gt;



&lt;figure&gt;&lt;img class=&quot;bqrUnknownImgSize&quot; fetchpriority=&quot;high&quot; decoding=&quot;async&quot; width=&quot;1024&quot; height=&quot;1024&quot; alt data-orig-srcset=&quot;https://reframequality.com/wp-content/uploads/2026/08/Blog-post-11-image-Entropy-1024x1024.png 1024w, https://reframequality.com/wp-content/uploads/2026/08/Blog-post-11-image-Entropy-300x300.png 300w, https://reframequality.com/wp-content/uploads/2026/08/Blog-post-11-image-Entropy-150x150.png 150w, https://reframequality.com/wp-content/uploads/2026/08/Blog-post-11-image-Entropy-768x768.png 768w, https://reframequality.com/wp-content/uploads/2026/08/Blog-post-11-image-Entropy-200x200.png 200w, https://reframequality.com/wp-content/uploads/2026/08/Blog-post-11-image-Entropy.png 1254w&quot; src=&quot;https://reframequality.com/wp-content/uploads/2026/08/Blog-post-11-image-Entropy.png&quot; style=&quot;width: 170px; height: auto&quot;&gt;&lt;/figure&gt;



&lt;p&gt;This drift is not a failure of discipline. It is entropy: the tendency of any ordered system to slide towards disorder unless energy is continuously put back in. Therefore, the quality of your ultimate delivery when viewed against the plan is congruent on the amount of effort you put in to fight that drift.  The single agreed path was never going to hold on its own, and the job of everyone downstream of the plan is less to follow it than to keep noticing where reality has pulled away from it.&lt;/p&gt;



&lt;p&gt;The plan describes how the work is imagined. The product reflects how the work is actually done. The gap between the two is not a risk you might eliminate with tighter project management – it is a property you have to design around.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;A tended garden, left alone, becomes a wilderness&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;A garden makes the point better than a textbook. Designed, planted and pruned, it is a small triumph of order over its surroundings. Leave it a single season and nature reclaims it – not out of malice, but out of sheer tendency. Weeds do not need a plan. Order does.&lt;/p&gt;



&lt;p&gt;This is not a metaphor imported from physics and forced onto software. Software has its own version of it, observed and documented long before the current debate. Manny Lehman’s laws of software evolution, drawn from studying real systems in the 1970s, held that a system’s complexity increases as it evolves unless deliberate work is done to reduce it – a pull Lehman himself described as an analogue of the second law of thermodynamics. A delivery plan is that garden on the day it is finished: at its most manicured, its most complete, its most persuasive. Sign-off is peak order. From there, the only real question is how much energy you are willing to spend keeping the design legible as the season runs on.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Every handoff is a translation, and translation loses&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;Software is not built at a single point. It is assembled across a chain of hands, and every link in that chain is a translation.&lt;/p&gt;



&lt;p&gt;Requirements capture someone’s intent – imperfectly, because intent is slippery and language is lossy. Architecture interprets those requirements into structure. Developers interpret the architecture and the ticket, and where the ticket is silent they fill the gap with reasonable assumptions that may not match anyone else’s. AI now sits inside this chain too, producing fluent, confident code at a speed no reviewer can fully keep pace with. Business analysts reconcile stakeholders who wanted subtly different things. Testers infer the intent behind a specification that was itself an approximation.&lt;/p&gt;



&lt;p&gt;Notice where the loss lives. No individual in this chain is careless; each is competent and doing their job well. The degradation is cumulative, and it accrues in the spaces &lt;em&gt;between&lt;/em&gt; roles rather than inside any one of them. Quality, distributed across all these hands, drifts not because someone dropped it but because nobody was ever holding all of it.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;This is the system, not the people&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;It is tempting to read all this as a discipline problem – tighter specs, stricter sign-offs, someone to blame when the delivered thing does not match the drawn thing. That instinct misreads what is happening.&lt;/p&gt;



&lt;p&gt;Software delivery is a complex system, not merely a complicated one. Dave Snowden’s Cynefin framework draws the distinction well: a complicated system can be fully analysed and planned in advance by experts, whereas a complex one can only be understood by probing it and responding to what emerges. Delivery, full of interacting people and shifting context, sits firmly in the second category. Richard Cook, writing on how complex systems fail, observed that such systems run in a degraded mode as their normal state – always carrying latent faults, always one coincidence away from trouble, and mostly working anyway.&lt;/p&gt;



&lt;p&gt;This is why accountability belongs to the system, not the individuals inside it. W. Edwards Deming made the point decades ago and it has aged well: a bad system will beat a good person every time – he reckoned the overwhelming majority of outcomes are produced by the system rather than the people working within it. Sidney Dekker gave the slow accumulation of small, sensible decisions that ends somewhere nobody intended its name: a drift into failure. The gap between plan and product is that drift. Blaming people for it is like blaming the gardener for autumn.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;The cost of a drift nobody authorised&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;Here is a way to make the loss tangible. Treat each handoff as preserving some fraction of the original intent. Be generous and say 90% survives each step – a high bar in practice. Across seven handoffs, from requirement to production, you retain 0.9 to the seventh power: roughly 48%. On flattering assumptions, more than half the original intent has quietly degraded by the time the feature ships.&lt;/p&gt;



&lt;p&gt;That figure is an illustration, not a measurement – a way to picture accumulation, not a benchmark to quote. But the mechanism it describes is real, and it has a price. Picture a £750,000 programme built to a business goal that shifted by degrees across the chain, so that what ships technically works but no longer does the job it was funded to do. The rebuild is one cost. The quarter it took to notice, while a competitor moved, is the larger one. None of it surfaces on a status report, because at every stage the work looked correct – against the slightly wrong version of intent that reached that stage.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;AI raises the throughput, not the fidelity&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;The current wave of AI tooling is often sold as a way to remove this variability. It is worth being precise about what it actually does. AI is a new input source in the chain – a fast, fluent one – and it amplifies whatever is already there. Point it at a team with strong feedback and clear intent, and it accelerates good work. Point it at an ambiguous requirement, and it generates plausible, confident output that makes drift harder to spot rather than easier, because polish reads as correctness.&lt;/p&gt;



&lt;p&gt;Where you place it decides everything. Wired into the feedback, sensing where output has diverged from intent, it helps hold the system in order. Bolted onto production as a way to generate more, faster, it adds entropy at machine speed and dresses the result in enough polish to pass review. Same tool, opposite effect.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Testing isn’t the gate — it’s the energy you put back in&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;The plan was never going to be what happened. From the moment it was signed, entropy began pulling the work away from it – not because the project was run badly, but because that is what complex, human systems do. The plan’s real job was never to be obeyed; it was to give you something to measure the drift against. What decides the outcome is whether anyone is spending the energy to notice that drift and pull the work back towards its intent.&lt;/p&gt;



&lt;p&gt;This reframes what testing is for. Testing at the end, as a gate that checks the product against the plan, treats the plan as truth and the drift as deviation to be punished. But you cannot assure quality into a product or delivery that way. Leaving it until a gate at the end is far too late.&lt;/p&gt;



&lt;figure&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;THE LEADERSHIP QUESTION&lt;/strong&gt; &lt;em&gt;“How much of your original intent actually reaches production intact — and who is watching the gap?”&lt;/em&gt; Ask your delivery leadership to trace one recent feature from the requirement that funded it to the thing that shipped. If they can show you where intent was checked along the way, you have a system that senses drift. If the only checkpoint was at the end, you have a plan and a hope.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;



&lt;p&gt;Seen through the lens of entropy, information you gain from testing is the energy you feed back into the system to hold it in order. Good testing is a continuous pulse that reveals, throughout delivery, where the work has bent away from intent while the bend is still small and correctable.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Sources&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;&lt;em&gt;Ashby, D. Writing on quality as a distributed system rather than a single activity, and on testing as the production of information. &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://danashby.co.uk&quot;&gt;danashby.co.uk&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;&lt;em&gt;Lehman, M. M. (1996). “Laws of Software Evolution Revisited.” EWSPT — the laws of Continuing Change, Increasing Complexity (described as an analogue of the second law of thermodynamics) and Feedback System.&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;&lt;em&gt;Deming, W. E. “A bad system will beat a good person every time,” and the view that the great majority of outcomes are produced by the system. The W. Edwards Deming Institute, &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://deming.org&quot;&gt;deming.org&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;&lt;em&gt;Cook, R. I. (2000). How Complex Systems Fail. Cognitive Technologies Laboratory, University of Chicago&lt;/em&gt;.&lt;/p&gt;



&lt;p&gt;&lt;em&gt;Dekker, S. (2011). Drift into Failure: From Hunting Broken Components to Understanding Complex Systems. Ashgate.&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;&lt;em&gt;Snowden, D. J. &amp;amp; Boone, M. E. (2007). “A Leader’s Framework for Decision Making.” Harvard Business Review (the Cynefin framework).&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;Hollnagel, E. (2014). &lt;em&gt;Safety-I and Safety-II&lt;/em&gt; (work-as-imagined vs work-as-done). Ashgate.&lt;/p&gt;



&lt;p&gt;&lt;em&gt;DORA / Google Cloud. Accelerate State of DevOps research programme, on fast feedback and delivery performance. &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://dora.dev&quot;&gt;dora.dev&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;</summary><author><name>Matt</name></author><source gr:stream-id="feed/https://reframequality.com/feed/"><id>tag:google.com,2005:reader/feed/https://reframequality.com/feed/</id><title type="html">ReframeQuality Blog</title><link rel="alternate" href="https://reframequality.com" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1785981505754"><id gr:original-id="tag:blogger.com,1999:blog-3868566217808655382.post-1210964296227663634">tag:google.com,2005:reader/item/000002c500000471</id><category term="bun"></category><category term="package manager"></category><category term="Playwright"></category><title type="html">Introducing bun, a new package manager and JavaScript runtime environment</title><published>2026-08-06T01:58:25Z</published><updated>2026-08-06T01:58:25Z</updated><link rel="alternate" href="https://www.tjmaher.com/2026/08/introducing-bun-new-package-manager-and.html" type="text/html"></link><summary type="html">&lt;div&gt;New job? New toolset to explore! In this post I&amp;apos;ll be investigating a new JavaScript package manager and runtime environment called &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://bun.sh&quot;&gt;bun.sh&lt;/a&gt;. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;You may have noticed on Playwright.Dev&amp;apos;s &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://playwright.dev/docs/intro&quot;&gt;Getting Started / Installation section&lt;/a&gt; there are three different ways to install a ui or api test automation framework with the latest version of Playwright:&lt;/div&gt;&lt;div&gt;&lt;ul style=&quot;text-align: left&quot;&gt;&lt;li&gt;npm init playwright@latest&lt;/li&gt;&lt;li&gt;yarn create playwright&lt;/li&gt;&lt;li&gt;pnpm create playwright&lt;/li&gt;&lt;/ul&gt;For this blog post I&amp;apos;ll be investigating a fourth way, the new toolset they just started using at work, &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://bun.sh&quot;&gt;bun.sh&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;ul style=&quot;text-align: left&quot;&gt;&lt;li&gt;bun create playwright&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;What is npm, yarn, pnpm, and bun? These are called&lt;b&gt; package managers&lt;/b&gt;.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;b&gt;What is a package&lt;/b&gt;? Developing a project, you don&amp;apos;t have to figure out how to code everything yourself. You can include in your projects outside libraries, or &amp;quot;packages&amp;quot; of code from from the public JavaScript registry &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://npmjs.com&quot;&gt;npmjs.com&lt;/a&gt;. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;The problem is that these packages then need to be downloaded, installed, managed, and updated whenever they are updated. JavaScript projects can use a package manager, such as bun, to help this process. &lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;When putting together a Playwright automation framework based around JavaScript and TypeScript, Playwright uses the Node.js JavaScript runtime environment, to run its test runner, execute automation scripts, and manage its browser instances.(See &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://nodejs.org/en/about&quot;&gt;Nodejs.org / About&lt;/a&gt; )&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;There is a division of labor: Node.js runs these internal functions like running tests. NPM, Yarn, PNPM, and now Bun handle the packages. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;Why are there so many package managers? Each has its own specialization. The original NPM is bundled already with Node.js. Yarn is a Facebook toolset that was created when NPM was found to work too slow. PNPM was created to be smaller and therefore faster. And bun was built for quick startup and installation speed, good especially if you have a CI/ CD pipeline that has a LOT of packages to install each time the tests run.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;span&gt;&lt;a name=&quot;article-vjsUtoP0ERbKU8bSpU0zKevumTI-more&quot;&gt;&lt;/a&gt;&lt;/span&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;NPM&lt;/b&gt;, released in 2010, is the Node Package Manager for Node.js, a JavaScript Runtime Environment. According to NodeJS.org&amp;apos;s &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://nodejs.org/learn/getting-started/an-introduction-to-the-npm-package-manager#an-introduction-to-the-npm-package-manager&quot;&gt;An introduction to the npm package manager&lt;/a&gt;, &amp;quot;The npm installs, updates and manages downloads of dependencies of your project. Dependencies are pre-built pieces of code, such as libraries and packages, that your Node.js application needs to work&amp;quot;. NPM comes with &lt;b&gt;NPX &lt;/b&gt;(Node Package eXecute) is a command-line tool that runs third-party code, known as packages or dependencies, such as Playwright.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Yarn&lt;/b&gt;&lt;b&gt; &lt;/b&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://yarnpkg.com/&quot;&gt;https://yarnpkg.com/&lt;/a&gt;, released in 2016, is Facebook&amp;apos;s answer to NPM. Facebook needed a lot of JavaScript packages downloaded at the same time. NPM downloaded them only sequentially, one after another, causing it to be very slow the bigger the project became. According to the Engineering at Meta blog article &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://engineering.fb.com/2016/10/11/web/yarn-a-new-package-manager-for-javascript/&quot;&gt;Yarn: A new package manager for JavaScript&lt;/a&gt;, &amp;quot;As the size of [Facebook&amp;apos;s] codebase and the number of engineers grew, we ran into problems with consistency, security, and performance&amp;quot;.  &lt;/div&gt;&lt;br&gt;&lt;b&gt;Pnpm &lt;/b&gt;(Performant npm) is another JavaScript package manager, released in 2017. It uses symbolic links to organize the node_modules, increasing performance by decreasing the number of files needed.&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Bun &lt;/b&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://bun.sh&quot;&gt;https://bun.sh &lt;/a&gt;released in 2021 and purchased by Anthropic in 2025, isn&amp;apos;t just a package manager like NPM. It is a JavaScript runtime environment that was built to replace Node.js. &lt;br&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;In spite of the differences, there are many similarities between these package managers:&lt;/div&gt;&lt;div&gt;&lt;ul style=&quot;text-align: left&quot;&gt;&lt;li&gt;&lt;b&gt;Package Registry&lt;/b&gt;: All tools fetch packages from the official &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://npmjs.com&quot;&gt;npmjs.com&lt;/a&gt; site.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Manifest File&lt;/b&gt;: They all rely on &lt;b&gt;package.json&lt;/b&gt; to read and write project dependencies and scripts. They show the name, version, package manager, license, and more (See &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://docs.npmjs.com/cli/v11/configuring-npm/package-json&quot;&gt;NPM Docs / Package.json&lt;/a&gt; or  &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://yarnpkg.com/configuration/manifest&quot;&gt;Yarn Package / Manifest&lt;/a&gt; )&lt;/li&gt;&lt;li&gt;&lt;b&gt;Dependency Folders&lt;/b&gt;: Each tool downloads packages into a local &lt;b&gt;node_modules&lt;/b&gt; folder inside your project directory. &lt;/li&gt;&lt;li&gt;&lt;b&gt;Lockfiles&lt;/b&gt;: They use &lt;b&gt;lockfiles &lt;/b&gt;to ensure reproducible builds across different environments, such as package-lock.json. (See &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://docs.npmjs.com/cli/v8/configuring-npm/package-lock-json&quot;&gt;NPM Docs / package-lock.json&lt;/a&gt;)&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;There is also one main difference between the others and bun. NPM, Yarn, and PNMP are all built on top of Node.js. Bun is built using an entirely new language interacting with Apple&amp;apos;s JavaScriptCore engine, developed by Apple for Safari.  &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;h2&gt;NPM with V8 vs Apple&amp;apos;s JavaScriptCore&lt;/h2&gt;&lt;div&gt;NPM is built with V8 and Bun is built on JavaScriptCore... But what is V8 and JavaScriptCore? &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;According to the Codeverse Chronicle article, &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://codeverse-chronicles.vercel.app/blogPost/6509b9c36106ed74e339811a&quot;&gt;JavaScriptCore vs V8 Engine&lt;/a&gt;, &amp;quot;JavaScriptCore [...] , is the JavaScript engine developed by Apple. It powers the JavaScript execution within Apple&amp;apos;s Safari browser and is also utilized in various macOS and iOS applications. JavaScriptCore is an open-source project, making its codebase accessible to developers and allowing for contributions from the community.&lt;/div&gt;&lt;br&gt;&amp;quot;JavaScriptCore is deeply integrated into the Apple ecosystem, which means it&amp;apos;s optimized for Safari and other Apple products. This tight integration ensures excellent performance and compatibility within the Apple ecosystem.&lt;br&gt;&lt;br&gt;&amp;quot;[The] V8 Engine is developed by Google and is widely known for powering the Chrome browser. It&amp;apos;s also used in other projects like Node.js and various server-side applications&amp;quot;.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;h2 style=&quot;text-align: left&quot;&gt;About Bun&lt;/h2&gt;&lt;div&gt;Attempting to construct a Minecraft-like game, Jarred Sumner found Next.js painfully slow when trying to save and test his work. Bun initially interacted with the JavaScriptCore engine using the &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://ziglang.org/&quot;&gt;Zig programming language&lt;/a&gt;, but converted it to the &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://rust-lang.org/&quot;&gt;Rust programming language&lt;/a&gt; in 2026. &lt;/div&gt;&lt;div&gt;&lt;ul style=&quot;text-align: left&quot;&gt;&lt;li&gt;Installing Bun: &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://bun.com/docs/installation&quot;&gt;https://bun.com/docs/installation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Creating a project: &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://bun.com/docs/runtime/templating/create&quot;&gt;https://bun.com/docs/runtime/templating/create&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Running a project: &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://bun.com/docs/runtime&quot;&gt;https://bun.com/docs/runtime&lt;/a&gt;&lt;/li&gt;&lt;li&gt;GitHub site: &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/oven-sh/bun&quot;&gt;https://github.com/oven-sh/bun&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;According to the &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/oven-sh/bun&quot;&gt;GitHub README for Bun&lt;/a&gt;, &amp;quot;At its core is the Bun runtime, a fast JavaScript runtime designed as a drop-in replacement for Node.js. It&amp;apos;s written in Rust and powered by JavaScriptCore under the hood, dramatically reducing startup times and memory usage.&lt;br&gt;&lt;br&gt;&amp;quot;The bun command-line tool also implements a test runner, script runner, and Node.js-compatible package manager. Instead of 1,000 node_modules for development, you only need bun. Bun&amp;apos;s built-in tools are significantly faster than existing options and usable in existing Node.js projects with little to no changes&amp;quot;.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;There is one more thing about Bun... it was purchased by Anthropic to be used in Claude Code. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;From the press release, &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.anthropic.com/news/anthropic-acquires-bun-as-claude-code-reaches-usd1b-milestone&quot;&gt;Anthropic acquires Bun as Claude Code reaches $1B milestone&lt;/a&gt;:&lt;/div&gt;&lt;div&gt;&lt;p style=&quot;background-color: #faf9f5; box-sizing: inherit; color: #141413; font-family: anthropicSerif, &amp;quot;anthropicSerif Fallback&amp;quot;, serif; font-feature-settings: &amp;quot;pnum&amp;quot;, &amp;quot;lnum&amp;quot;, &amp;quot;liga&amp;quot;; font-size: 17px; letter-spacing: 0px; margin: 1rem auto; width: 640px&quot;&gt;&amp;quot;Bun is redefining speed and performance for modern software engineering and development. Founded by Jarred Sumner in 2021, Bun is dramatically faster than the leading competition. As an all-in-one toolkit—combining runtime, package manager, bundler, and test runner—it&amp;apos;s become essential infrastructure for AI-led software engineering, helping developers build and test applications at unprecedented velocity.&lt;/p&gt;&lt;p style=&quot;background-color: #faf9f5; box-sizing: inherit; color: #141413; font-family: anthropicSerif, &amp;quot;anthropicSerif Fallback&amp;quot;, serif; font-feature-settings: &amp;quot;pnum&amp;quot;, &amp;quot;lnum&amp;quot;, &amp;quot;liga&amp;quot;; font-size: 17px; letter-spacing: 0px; margin: 1rem auto; width: 640px&quot;&gt;&lt;/p&gt;&lt;p style=&quot;background-color: #faf9f5; box-sizing: inherit; color: #141413; font-family: anthropicSerif, &amp;quot;anthropicSerif Fallback&amp;quot;, serif; font-feature-settings: &amp;quot;pnum&amp;quot;, &amp;quot;lnum&amp;quot;, &amp;quot;liga&amp;quot;; font-size: 17px; letter-spacing: 0px; margin: 1rem auto; width: 640px&quot;&gt;&amp;quot;Bun has improved the JavaScript and TypeScript developer experience by optimizing for reliability, speed, and delight. For those using Claude Code, this acquisition means faster performance, improved stability, and new capabilities. Together, we’ll keep making Bun the best JavaScript runtime for all developers, while building even better workflows into Claude Code.&lt;/p&gt;&lt;p style=&quot;background-color: #faf9f5; box-sizing: inherit; color: #141413; font-family: anthropicSerif, &amp;quot;anthropicSerif Fallback&amp;quot;, serif; font-feature-settings: &amp;quot;pnum&amp;quot;, &amp;quot;lnum&amp;quot;, &amp;quot;liga&amp;quot;; font-size: 17px; letter-spacing: 0px; margin: 1rem auto; width: 640px&quot;&gt;&amp;quot;[...] Bun represents exactly the kind of technical excellence we want to bring into Anthropic,&amp;quot; said Mike Krieger, Chief Product Officer of Anthropic. &amp;quot;Jarred and his team rethought the entire JavaScript toolchain from first principles while remaining focused on real use cases. Claude Code reached $1 billion in run-rate revenue in only 6 months, and bringing the Bun team into Anthropic means we can build the infrastructure to compound that momentum and keep pace with the exponential growth in AI adoption.&amp;quot;&lt;/p&gt;&lt;p style=&quot;background-color: #faf9f5; box-sizing: inherit; color: #141413; font-family: anthropicSerif, &amp;quot;anthropicSerif Fallback&amp;quot;, serif; font-feature-settings: &amp;quot;pnum&amp;quot;, &amp;quot;lnum&amp;quot;, &amp;quot;liga&amp;quot;; font-size: 17px; letter-spacing: 0px; margin: 1rem auto; width: 640px&quot;&gt;&lt;/p&gt;&lt;p style=&quot;background-color: #faf9f5; box-sizing: inherit; color: #141413; font-family: anthropicSerif, &amp;quot;anthropicSerif Fallback&amp;quot;, serif; font-feature-settings: &amp;quot;pnum&amp;quot;, &amp;quot;lnum&amp;quot;, &amp;quot;liga&amp;quot;; font-size: 17px; letter-spacing: 0px; margin: 1rem auto; width: 640px&quot;&gt;&amp;quot;As developers increasingly build with AI, the underlying infrastructure matters more than ever—and Bun has emerged as an essential tool. Bun gets more than 7 million monthly downloads, has earned over 82,000 stars on GitHub, and has been adopted by companies like Midjourney and Lovable to increase speed and productivity.&lt;/p&gt;&lt;p style=&quot;background-color: #faf9f5; box-sizing: inherit; color: #141413; font-family: anthropicSerif, &amp;quot;anthropicSerif Fallback&amp;quot;, serif; font-feature-settings: &amp;quot;pnum&amp;quot;, &amp;quot;lnum&amp;quot;, &amp;quot;liga&amp;quot;; font-size: 17px; letter-spacing: 0px; margin: 1rem auto; width: 640px&quot;&gt;&lt;/p&gt;&lt;p style=&quot;background-color: #faf9f5; box-sizing: inherit; color: #141413; font-family: anthropicSerif, &amp;quot;anthropicSerif Fallback&amp;quot;, serif; font-feature-settings: &amp;quot;pnum&amp;quot;, &amp;quot;lnum&amp;quot;, &amp;quot;liga&amp;quot;; font-size: 17px; letter-spacing: 0px; margin: 1rem auto; width: 640px&quot;&gt;&amp;quot;The decision to acquire Bun is in line with our strategic, disciplined approach to acquisitions: we will continue to pursue opportunities that bolster our technical excellence, reinforce our strength as the leader in enterprise AI, and most importantly, align with our principles and mission&amp;quot;. &lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h2&gt;How to Install Bun&lt;/h2&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;According to the &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/oven-sh/bun#install&quot;&gt;GitHub README for Bun&lt;/a&gt;, you can install Bun on your MacBook using HomeBrew, with Curl, with NPM, or pulling down an image from Docker. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;On Windows, you can use PowerShell. Since I use a Windows PC at home, I&amp;apos;ll install it that way:&lt;/div&gt;&lt;div&gt;&lt;ul style=&quot;text-align: left&quot;&gt;&lt;li&gt;&lt;pre style=&quot;background-color: #f6f8fa; border-radius: 6px; box-sizing: border-box; color: #1f2328; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; tab-size: 4; word-break: normal&quot;&gt;powershell -c &lt;span style=&quot;box-sizing: border-box; color: #0a3069&quot;&gt;&lt;span style=&quot;box-sizing: border-box&quot;&gt;&amp;quot;&lt;/span&gt;irm &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://bun.sh/install.ps1&quot;&gt;bun.sh/install.ps1&lt;/a&gt; | iex&lt;span style=&quot;box-sizing: border-box&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Restarting my PowerShell Terminal, checking that bun was installed correctly:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;pre style=&quot;background-color: #f6f8fa; border-radius: 6px; box-sizing: border-box; color: #1f2328; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; tab-size: 4; word-break: normal&quot;&gt;bun -version&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;... And it replied I am using version 1.3.14. Wonderful! It&amp;apos;s alive! It&amp;apos;s .... alive! Had the installation not gone successfully, it would have errored out. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;In the next blog post, we will figure out how to use bun to create a Playwright framework. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;Happy Testing! &lt;br&gt;&lt;br&gt;
-T.J. Maher&lt;br&gt;
Software Engineer in Test&lt;br&gt;
&lt;br&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://bsky.app/profile/tjmaher1.bsky.social&quot;&gt;BlueSky&lt;/a&gt; | &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://bit.ly/tj_youtube&quot;&gt;YouTube&lt;/a&gt; | &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.linkedin.com/in/tjmaher1&quot;&gt;LinkedIn&lt;/a&gt; | &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://www.tjmaher.com/p/media.html&quot;&gt;Articles&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;</summary><author><name>T.J. Maher</name></author><source gr:stream-id="feed/http://www.tjmaher.com/feeds/posts/default"><id>tag:google.com,2005:reader/feed/http://www.tjmaher.com/feeds/posts/default</id><title type="html">Adventures in Automation</title><link rel="alternate" href="https://www.tjmaher.com/" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1785967200000"><id gr:original-id="https://scrolltest.com/?p=7422">tag:google.com,2005:reader/item/00000444000002e5</id><category term="Playwright tutorial Java"></category><category term="Testing"></category><title type="html">Faker.js for Test Automation: Generate Realistic Test Data That Actually Catches Bugs</title><published>2026-08-05T22:00:00Z</published><updated>2026-08-05T22:00:00Z</updated><link rel="alternate" href="https://scrolltest.com/faker-js-test-automation-realistic-test-data-bugs/" type="text/html"></link><summary type="html">&lt;p&gt;Every test suite has a dirty secret: hardcoded test data. You know the pattern. Every test uses &lt;a href=&quot;mailto:john@example.com&quot;&gt;john@example.com&lt;/a&gt;, the password is always Password123, and the shipping address is 123 Main Street. These comfortable defaults create a dangerous blind spot in your test coverage. Real users have names with apostrophes, emails with plus signs, addresses with...&lt;/p&gt;
&lt;p&gt;The post &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; rel=&quot;nofollow&quot; href=&quot;https://scrolltest.com/faker-js-test-automation-realistic-test-data-bugs/&quot;&gt;Faker.js for Test Automation: Generate Realistic Test Data That Actually Catches Bugs&lt;/a&gt; appeared first on &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; rel=&quot;nofollow&quot; href=&quot;https://scrolltest.com&quot;&gt;Software Testing &amp;amp; Automation&lt;/a&gt;.&lt;/p&gt;</summary><author><name>Pramod Dutta</name></author><source gr:stream-id="feed/https://scrolltest.com/feed/"><id>tag:google.com,2005:reader/feed/https://scrolltest.com/feed/</id><title type="html">Software Testing &amp; Automation</title><link rel="alternate" href="https://scrolltest.com" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1785963211000"><id gr:original-id="https://medium.com/p/41b2cbe15265">tag:google.com,2005:reader/item/0000034700000071</id><category term="software-engineering"></category><category term="automation"></category><category term="testing"></category><category term="ai"></category><title type="html">Don’t Just Use AI to Build Faster. Use It to Ship Faster.</title><published>2026-08-05T20:53:31Z</published><updated>2026-08-05T20:53:31Z</updated><link rel="alternate" href="https://jarbon.medium.com/youre-in-trouble-you-can-t-ship-all-that-ai-generated-code-41b2cbe15265?source=rss-1ee8fdc3bacb------2" type="text/html"></link><summary type="html">&lt;figure&gt;&lt;img class=&quot;bqrUnknownImgSize&quot; alt src=&quot;https://cdn-images-1.medium.com/max/1024/1*ylW7njFjhoTw7axGOYiCDw.png&quot;&gt;&lt;/figure&gt;&lt;p&gt;&lt;em&gt;Coding agents accelerated software creation. The next advantage is using AI to generate the evidence and feedback that let teams deploy with confidence.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;This is Part 1 of a series for engineering managers and CTOs about what AI has already changed about QA, engineering ownership, and the path from generated code to production value.&lt;/p&gt;&lt;p&gt;Your team can create software faster than ever. A developer can describe a feature and watch an agent produce code, tests, documentation, and a pull request in minutes. Leadership sees an explosion of activity and expects a matching explosion in production output.&lt;/p&gt;&lt;p&gt;That second explosion is not happening yet because most companies are applying AI to only one part of delivery. The code appears quickly, but reviews still grow, changes still wait, and green test suites still fail to answer the questions that matter. The opportunity now is to apply AI to the work between generated code and a confident production decision.&lt;/p&gt;&lt;h3&gt;AI Accelerated Only One Part of Delivery&lt;/h3&gt;&lt;p&gt;Most AI coding programs measure what AI makes easy to see: generated code, accepted suggestions, completed tasks, pull requests, and implementation time. Those measures prove that the organization can produce candidate software faster. They do not prove that software reaches customers faster or creates more value.&lt;/p&gt;&lt;p&gt;Generation is only the first part of delivery. The organization still has to understand the change, confirm the product intent, identify broken contracts, collect credible evidence, release safely, observe the result, and recover from failure. AI compressed implementation and exposed everything around it as the next opportunity for acceleration. Generated output becomes valuable when the rest of the system can confidently move it into production.&lt;/p&gt;&lt;h3&gt;The New Queue Is a Confidence Queue&lt;/h3&gt;&lt;p&gt;AI reduces the queue before implementation, but the queue does not disappear. It moves. Work now waits for someone to establish that it is correct, secure, useful, observable, and recoverable enough to release. The scarce resource is no longer a plausible implementation. It is fast, credible confidence in that implementation.&lt;/p&gt;&lt;p&gt;Generated software often looks finished. The agent wrote the code, added tests, ran the suite, and reported success. The remaining uncertainty is invisible, so teams either move slowly because they distrust the output or move quickly without understanding the risk. A better confidence loop makes that uncertainty visible and gives the team evidence it can act on.&lt;/p&gt;&lt;h3&gt;Transform QA to Move at AI Speed&lt;/h3&gt;&lt;p&gt;Traditional QA was designed around human-speed changes. Developers produced a manageable number of features, automation engineers expanded regression coverage, and manual testers worked against builds that stayed relevant long enough to find and route defects.&lt;/p&gt;&lt;p&gt;AI-generated volume requires a different architecture. A test pass tied to one build starts expiring as soon as it begins. A separate automation handoff cannot match the context or speed of the coding agent. A large regression suite can show that old checks still pass while missing an unstated business rule, privacy exposure, broken integration, or unrecoverable failure.&lt;/p&gt;&lt;p&gt;The answer is not simply more tests. AI can generate thousands of tests from the same incomplete understanding that generated the code. The builder and its tests can agree perfectly and still be wrong about what the customer or business needs. A green suite is evidence, but it is not confidence. QA leaders can help engineering make that distinction and redesign validation around the speed, context, and risk of AI-generated change.&lt;/p&gt;&lt;h3&gt;Use AI Across the Confidence Loop&lt;/h3&gt;&lt;p&gt;AI can do far more than generate implementation code. It can inspect a change, identify affected contracts, propose risk-based checks, exercise interfaces, analyze failures, compare production behavior, and help turn incidents into permanent regression evidence. Human experts can then focus on product judgment, customer consequences, privacy, accessibility, business risk, and the uncertainty the organization is willing to accept.&lt;/p&gt;&lt;p&gt;This is not about asking the coding agent that built the feature whether it did a good job. Important changes still need independent challenge. It is about using AI throughout the confidence loop: generating evidence inside development, scaling validation according to risk, controlling production exposure, monitoring real outcomes, and accelerating recovery. Confidence is what allows AI speed to survive contact with production.&lt;/p&gt;&lt;h3&gt;Shipping Faster Is the Engineering Opportunity&lt;/h3&gt;&lt;p&gt;Engineering managers and CTOs cannot delegate this transition to QA and wait for a new test strategy. It reaches into developer workflows, coding agents, observability, release design, production monitoring, incentives, and the definition of done. Those are engineering-system decisions, but QA leaders can bring the risk judgment and product knowledge needed to make them well.&lt;/p&gt;&lt;p&gt;Start by separating generated output from delivered value. Measure the time from an agent’s claimed completion to a production decision. Identify where work waits, which risks have evidence, and which are covered only by hope. Then use AI to shorten that path: generate functional evidence inside the engineering loop, scale validation according to risk, independently challenge important changes, control production exposure, and focus human judgment on questions the builder cannot answer alone.&lt;/p&gt;&lt;p&gt;You already have the ability to generate software faster. The next return comes from using AI to build confidence faster too. The organizations that connect those two capabilities will not merely produce more code. They will learn faster, release faster, and turn more of their AI investment into customer value.&lt;/p&gt;&lt;p&gt;&lt;em&gt;Next in the series: Your Tokens Aren’t Turning Into Value.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;If this transition is now on your plate, &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://icebergqa.com/&quot;&gt;IcebergQA&lt;/a&gt; helps engineering managers and QA leaders transform QA for AI. We work with your existing people, tools, and engineering workflows to build the confidence to ship faster.&lt;/p&gt;&lt;p&gt;— Jason Arbon&lt;/p&gt;</summary><author><name>jason arbon</name></author><source gr:stream-id="feed/https://medium.com/feed/@jarbon"><id>tag:google.com,2005:reader/feed/https://medium.com/feed/@jarbon</id><title type="html">Stories by jason arbon on Medium</title><link rel="alternate" href="https://medium.com/@jarbon?source=rss-1ee8fdc3bacb------2" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1785963211000"><id gr:original-id="https://medium.com/p/41b2cbe15265">tag:google.com,2005:reader/item/000009ff00000031</id><category term="software-engineering"></category><category term="automation"></category><category term="testing"></category><category term="ai"></category><title type="html">Don’t Just Use AI to Build Faster. Use It to Ship Faster.</title><published>2026-08-05T20:53:31Z</published><updated>2026-08-05T20:53:31Z</updated><link rel="alternate" href="https://jarbon.medium.com/youre-in-trouble-you-can-t-ship-all-that-ai-generated-code-41b2cbe15265?source=rss-1ee8fdc3bacb------2" type="text/html"></link><summary type="html">&lt;figure&gt;&lt;img class=&quot;bqrUnknownImgSize&quot; alt src=&quot;https://cdn-images-1.medium.com/max/1024/1*ylW7njFjhoTw7axGOYiCDw.png&quot;&gt;&lt;/figure&gt;&lt;p&gt;&lt;em&gt;Coding agents accelerated software creation. The next advantage is using AI to generate the evidence and feedback that let teams deploy with confidence.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;This is Part 1 of a series for engineering managers and CTOs about what AI has already changed about QA, engineering ownership, and the path from generated code to production value.&lt;/p&gt;&lt;p&gt;Your team can create software faster than ever. A developer can describe a feature and watch an agent produce code, tests, documentation, and a pull request in minutes. Leadership sees an explosion of activity and expects a matching explosion in production output.&lt;/p&gt;&lt;p&gt;That second explosion is not happening yet because most companies are applying AI to only one part of delivery. The code appears quickly, but reviews still grow, changes still wait, and green test suites still fail to answer the questions that matter. The opportunity now is to apply AI to the work between generated code and a confident production decision.&lt;/p&gt;&lt;h3&gt;AI Accelerated Only One Part of Delivery&lt;/h3&gt;&lt;p&gt;Most AI coding programs measure what AI makes easy to see: generated code, accepted suggestions, completed tasks, pull requests, and implementation time. Those measures prove that the organization can produce candidate software faster. They do not prove that software reaches customers faster or creates more value.&lt;/p&gt;&lt;p&gt;Generation is only the first part of delivery. The organization still has to understand the change, confirm the product intent, identify broken contracts, collect credible evidence, release safely, observe the result, and recover from failure. AI compressed implementation and exposed everything around it as the next opportunity for acceleration. Generated output becomes valuable when the rest of the system can confidently move it into production.&lt;/p&gt;&lt;h3&gt;The New Queue Is a Confidence Queue&lt;/h3&gt;&lt;p&gt;AI reduces the queue before implementation, but the queue does not disappear. It moves. Work now waits for someone to establish that it is correct, secure, useful, observable, and recoverable enough to release. The scarce resource is no longer a plausible implementation. It is fast, credible confidence in that implementation.&lt;/p&gt;&lt;p&gt;Generated software often looks finished. The agent wrote the code, added tests, ran the suite, and reported success. The remaining uncertainty is invisible, so teams either move slowly because they distrust the output or move quickly without understanding the risk. A better confidence loop makes that uncertainty visible and gives the team evidence it can act on.&lt;/p&gt;&lt;h3&gt;Transform QA to Move at AI Speed&lt;/h3&gt;&lt;p&gt;Traditional QA was designed around human-speed changes. Developers produced a manageable number of features, automation engineers expanded regression coverage, and manual testers worked against builds that stayed relevant long enough to find and route defects.&lt;/p&gt;&lt;p&gt;AI-generated volume requires a different architecture. A test pass tied to one build starts expiring as soon as it begins. A separate automation handoff cannot match the context or speed of the coding agent. A large regression suite can show that old checks still pass while missing an unstated business rule, privacy exposure, broken integration, or unrecoverable failure.&lt;/p&gt;&lt;p&gt;The answer is not simply more tests. AI can generate thousands of tests from the same incomplete understanding that generated the code. The builder and its tests can agree perfectly and still be wrong about what the customer or business needs. A green suite is evidence, but it is not confidence. QA leaders can help engineering make that distinction and redesign validation around the speed, context, and risk of AI-generated change.&lt;/p&gt;&lt;h3&gt;Use AI Across the Confidence Loop&lt;/h3&gt;&lt;p&gt;AI can do far more than generate implementation code. It can inspect a change, identify affected contracts, propose risk-based checks, exercise interfaces, analyze failures, compare production behavior, and help turn incidents into permanent regression evidence. Human experts can then focus on product judgment, customer consequences, privacy, accessibility, business risk, and the uncertainty the organization is willing to accept.&lt;/p&gt;&lt;p&gt;This is not about asking the coding agent that built the feature whether it did a good job. Important changes still need independent challenge. It is about using AI throughout the confidence loop: generating evidence inside development, scaling validation according to risk, controlling production exposure, monitoring real outcomes, and accelerating recovery. Confidence is what allows AI speed to survive contact with production.&lt;/p&gt;&lt;h3&gt;Shipping Faster Is the Engineering Opportunity&lt;/h3&gt;&lt;p&gt;Engineering managers and CTOs cannot delegate this transition to QA and wait for a new test strategy. It reaches into developer workflows, coding agents, observability, release design, production monitoring, incentives, and the definition of done. Those are engineering-system decisions, but QA leaders can bring the risk judgment and product knowledge needed to make them well.&lt;/p&gt;&lt;p&gt;Start by separating generated output from delivered value. Measure the time from an agent’s claimed completion to a production decision. Identify where work waits, which risks have evidence, and which are covered only by hope. Then use AI to shorten that path: generate functional evidence inside the engineering loop, scale validation according to risk, independently challenge important changes, control production exposure, and focus human judgment on questions the builder cannot answer alone.&lt;/p&gt;&lt;p&gt;You already have the ability to generate software faster. The next return comes from using AI to build confidence faster too. The organizations that connect those two capabilities will not merely produce more code. They will learn faster, release faster, and turn more of their AI investment into customer value.&lt;/p&gt;&lt;p&gt;&lt;em&gt;Next in the series: Your Tokens Aren’t Turning Into Value.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;If this transition is now on your plate, &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://icebergqa.com/&quot;&gt;IcebergQA&lt;/a&gt; helps engineering managers and QA leaders transform QA for AI. We work with your existing people, tools, and engineering workflows to build the confidence to ship faster.&lt;/p&gt;&lt;p&gt;— Jason Arbon&lt;/p&gt;</summary><author><name>jason arbon</name></author><source gr:stream-id="feed/https://jarbon.medium.com/feed"><id>tag:google.com,2005:reader/feed/https://jarbon.medium.com/feed</id><title type="html">Stories by jason arbon on Medium</title><link rel="alternate" href="https://medium.com/@jarbon?source=rss-1ee8fdc3bacb------2" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1785940548000"><id gr:original-id="https://testerstories.com/?p=6880">tag:google.com,2005:reader/item/000001ce000000b0</id><category term="Testing"></category><title type="html">The Integration Seam</title><published>2026-08-05T14:35:48Z</published><updated>2026-08-05T14:35:48Z</updated><link rel="alternate" href="https://testerstories.com/2026/08/the-integration-seam/" type="text/html"></link><summary type="html">&lt;p&gt;Awhile back I posted my call to action posts: &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://testerstories.com/2019/09/testers-act-like-a-developer/&quot;&gt;Testers: Act Like a Developer&lt;/a&gt;. Since that time, I’ve done a few posts on what that looks like specifically and why it matters. This post is another one of those, showing the very early stages of a project.&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;article-8EvktDKnewEcOrdXri9UV0vbSi8-more-6880&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Previously I talked about the &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://testerstories.com/2016/08/the-integration-pact/&quot;&gt;integration pact&lt;/a&gt;, which was essentially the idea that problems live at the seams. Something pretty much any tester becomes aware of very quickly. This post is another way of describing the seam.&lt;/p&gt;
&lt;p&gt;I spent part of my morning doing something that should have been boring: setting up the scaffolding for a new project called &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/jeffnyman/quendor-rs&quot;&gt;quendor-rs&lt;/a&gt;, which is an offshoot of my &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/jeffnyman/quendor-py&quot;&gt;quendor-py&lt;/a&gt;, which is an offshoot of my &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/jeffnyman/quendor&quot;&gt;quendor&lt;/a&gt;. I was not writing the software itself yet. Just the plumbing around it. Commit conventions, enforcement hooks, CI checks, merge policy. The kind of thing every project needs and every tutorial makes look like a fifteen-minute task.&lt;/p&gt;
&lt;p&gt;It took the better part my morning, and almost none of that time went to the work itself. It went to caveats. “One more thing about this.” “Oh, wait, that reveals this other thing.” By the end I was asking a question I know every developer has asked: why is &lt;em&gt;everything&lt;/em&gt; like this? These ecosystems have existed for years. Shouldn’t they be sorted out by now? It’s one thing to know developers ask that question. It’s another to experience why they ask it. And I think testers are well served by knowing exactly that.&lt;/p&gt;
&lt;p&gt;I ended my investigations with an actual answer, and it was one I came to long ago since I’ve been developing and testing for a long time. When I first ran into this, way back in the primeval era when dinosaurs still wore polyester, it changed how I look at this kind of friction. But the answer only makes sense against the specifics, so let me show you the specifics first.&lt;/p&gt;
&lt;h2&gt;The Setup&lt;/h2&gt;
&lt;p&gt;The project I’m working on, in all of its incarnations, is a Z-Machine interpreter written in Rust. The Z-Machine is the virtual machine that runs Infocom-era interactive fiction. That detail mostly doesn’t matter here. What matters is what I wanted from the project’s process, before the first real line of code:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Commit messages following the Conventional Commits specification.&lt;/li&gt;
&lt;li&gt;Local enforcement, so a malformed message is rejected at commit time.&lt;/li&gt;
&lt;li&gt;CI enforcement, so nothing malformed can land on &lt;code&gt;main&lt;/code&gt; regardless of where it was committed.&lt;/li&gt;
&lt;li&gt;A pull-request-only &lt;code&gt;main&lt;/code&gt; branch with squash merging, where the PR title becomes the commit message.&lt;/li&gt;
&lt;li&gt;Automated dependency updates, so the tooling doesn’t silently rot.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Nothing exotic. Every piece is mainstream: git, GitHub rulesets, GitHub Actions, the &lt;code&gt;gh&lt;/code&gt; CLI, a commit-lint tool called cocogitto, its companion GitHub action, Dependabot. Each piece is mature, documented, and widely used.&lt;/p&gt;
&lt;p&gt;Here’s what happened at every joint where two of those pieces met.&lt;/p&gt;
&lt;h2&gt;Five Failures, No Bugs&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The tool that changed its meaning.&lt;/strong&gt; The documented way to install cocogitto’s git hook used to be &lt;code&gt;cog install-hook commit-msg&lt;/code&gt;. By version 7, that syntax no longer exists; the tool now installs hooks you declare in a config file. Fair enough. Except that running the new form, &lt;code&gt;cog install-hook --all&lt;/code&gt;, with no config file present, exits successfully while installing all zero of the hooks you’ve defined. Green check mark, nothing enforced. I only discovered the hook wasn’t installed because I went looking for what the command had actually done. Which was nothing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The action that changed its contract.&lt;/strong&gt; The GitHub action for the same tool went from &lt;code&gt;check: true&lt;/code&gt; in version 3 to a required &lt;code&gt;command: check&lt;/code&gt; input in version 4. A workflow written from v3-era examples and naively bumped to v4 fails on first run. The CLI and the action are siblings from the same project, and even &lt;em&gt;they&lt;/em&gt; don’t drift in sync.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The flag that works, except when it doesn’t.&lt;/strong&gt; The &lt;code&gt;gh pr merge&lt;/code&gt; command has a &lt;code&gt;--delete-branch&lt;/code&gt; flag whose help text reads “Delete the local and remote branch after merge.” Combine it with &lt;code&gt;--auto&lt;/code&gt;, meaning merge when checks pass … well, it turns out the deletion silently doesn’t happen, because &lt;code&gt;gh&lt;/code&gt; merely enables auto-merge server-side and exits. So, when GitHub performs the merge minutes later, there’s no process left to delete anything. No warning tells you this. The truth is in the source code, in an early-return guard the documentation has never heard of. Better still: whether the flag works depends on &lt;em&gt;timing&lt;/em&gt;: if the checks happen to already be green when you run the command, it degrades to an immediate merge and the deletion works exactly as documented.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The commit nobody wrote.&lt;/strong&gt; With everything finally wired up, the very first pull request failed its own commit-message check. Every commit on the branch was valid. The failure was a commit that I didn’t write: on pull-request events, GitHub checks out a synthetic merge commit (effectively: “Merge abc123 into def456”) representing your branch as if merged. The lint tool, doing exactly its job, validated that machine-generated message and rejected it. Two correct behaviors, one broken result. The fix is a config setting that exists precisely because this collision is common enough to deserve&lt;br&gt;
one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The version nobody chose.&lt;/strong&gt; The CI action, it turns out, bundles version 6.4 of the lint tool. My machine runs 7.0. Nothing broke. This time. But it means “passes locally” and “passes in CI” are answered by different&lt;br&gt;
software, and someday that gap will likely be a bug report.&lt;/p&gt;
&lt;p&gt;Notice what this list does &lt;em&gt;not&lt;/em&gt; contain: a single defective tool. Every component did what its maintainers intended. All five failures live in the same place: the joint between two things.&lt;/p&gt;
&lt;h2&gt;Nobody Owns the Pairs&lt;/h2&gt;
&lt;p&gt;Here’s the explanation I originally landed on many, many moons ago and it’s the one that holds true today.&lt;/p&gt;
&lt;p&gt;Each of these tools is owned. Somebody maintains cocogitto, somebody maintains &lt;code&gt;gh&lt;/code&gt;, somebody maintains GitHub’s merge machinery. Within each tool, there’s a test suite, a release process, a place to file bugs.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;pairs&lt;/em&gt; of tools are owned by nobody. GitHub doesn’t test its synthetic merge commits against third-party commit linters. The action’s maintainer doesn’t coordinate releases with the CLI it wraps. The &lt;code&gt;gh&lt;/code&gt; documentation team doesn’t re-derive every flag interaction when auto-merge semantics change upstream. Each maintainer’s responsibility ends at their own boundary (reasonably so!) which means the interactions between boundaries are maintained by no one.&lt;/p&gt;
&lt;p&gt;And the interactions are where I spent my morning. Compose eight tools and you get dozens of pairwise seams, most of which have never been exercised by enough people to have their edges filed down. There is no mechanism by which a bazaar of independent maintainers converges on “sorted,” because sorted-ness is a property of &lt;em&gt;compositions&lt;/em&gt;, and a composition belongs to the person doing the composing.&lt;/p&gt;
&lt;p&gt;Which means, as a tester who dabbles in development, I recognized my role immediately: &lt;strong&gt;I was the integration test&lt;/strong&gt;. First execution, production environment, no prior runs. Of course it found defects. That’s what integration tests are for.&lt;/p&gt;
&lt;p&gt;That “I was the integration test” part is something that I believe is front and center to the relationship between developers and testers and, thus, between development and testing.&lt;/p&gt;
&lt;h2&gt;The Cathedral Next Door&lt;/h2&gt;
&lt;p&gt;Here’s the observation that keeps this from curdling into cynicism. While all of this was happening, one part of the stack produced zero caveats: the Rust toolchain. The compiler, the build tool, the formatter, the linter, the toolchain manager: flawless, all morning. Not one surprise. (That also applied to my Python and Node incarnations of this project.)&lt;/p&gt;
&lt;p&gt;That’s not luck, and it’s not because Rust’s tools are simpler. It’s structure. The Rust toolchain is a cathedral: one project owns the compiler, the build system, the formatter, and the linter, so the seams between them are &lt;em&gt;internal&lt;/em&gt;: somebody’s job to test before every release. The friction in my morning lived almost entirely in the policy-and-automation periphery around GitHub, which is maximally bazaar-shaped: independent tools, no release coordination, composed ad hoc by each user.&lt;/p&gt;
&lt;p&gt;So the feeling that ecosystems &lt;em&gt;should&lt;/em&gt; be sorted out by now isn’t naive. The sorted ones exist. They’re the ones with owners. What can’t ever be fully sorted is the open composition space around them. And that’s not a failure of engineering discipline; it’s the price of an ecosystem being open. Anyone can build a tool; no one is required to test it against every other tool. You get the bazaar’s variety and the bazaar’s seams together, or neither.&lt;/p&gt;
&lt;h2&gt;What This Buys You&lt;/h2&gt;
&lt;p&gt;Three consolations, all practical.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The cost is front-loaded.&lt;/strong&gt; Setup day is expensive because setup is when you cross every seam for the first time. The loop I’ll actually live in for my project — edit, commit, open a PR, watch checks, squash-merge — now runs entirely on paths that have been walked and pinned down. Seams don’t need re-crossing daily.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Automation converts ambushes into signals.&lt;/strong&gt; The two robots I installed exist precisely to keep it that way. Dependency updates turn version drift into visible pull requests instead of silent breakage. CI turns “the composition broke” into a red check instead of a corrupted &lt;code&gt;main&lt;/code&gt;. The caveats don’t disappear. They stop being ambushes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Empiricism is the only documentation that never lies.&lt;/strong&gt; The recurring method that got me through the morning was: check the source, not the docs, and not my memory. The &lt;code&gt;--delete-branch&lt;/code&gt; behavior wasn’t in any manual; it was in an &lt;code&gt;if&lt;/code&gt; statement. The hook no-op wasn’t announced; it was discovered by looking at what the command actually wrote to disk. In a cathedral you can trust the manual. At the seams of a bazaar, the only reliable spec is the behavior itself. Which is to say: at the seams, everyone is a tester, whether they signed up for it or not.&lt;/p&gt;
&lt;p&gt;That last sentence is probably the whole post. The tools were fine. The pairs were untested. (Or, at the very least, circumstantially and situationally tested.) And untested, circumstantially tested, and situationally tested things, when finally executed, behave &lt;em&gt;exactly&lt;/em&gt; the way our profession has always said they would.&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.addtoany.com/share#url=https%3A%2F%2Ftesterstories.com%2F2026%2F08%2Fthe-integration-seam%2F&amp;amp;title=The%20Integration%20Seam&quot; data-a2a-url=&quot;https://testerstories.com/2026/08/the-integration-seam/&quot; data-a2a-title=&quot;The Integration Seam&quot;&gt;&lt;img class=&quot;bqrUnknownImgSize&quot; src=&quot;https://static.addtoany.com/buttons/favicon.png&quot; alt=&quot;Share&quot;&gt;&lt;/a&gt;&lt;/p&gt;</summary><author><name>Jeff Nyman</name></author><source gr:stream-id="feed/http://testerstories.com/feed/"><id>tag:google.com,2005:reader/feed/http://testerstories.com/feed/</id><title type="html">Stories from a Software Tester</title><link rel="alternate" href="https://testerstories.com" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1785914171000"><id gr:original-id="http://testingideas.wordpress.com/?p=1989">tag:google.com,2005:reader/item/0000053500000016</id><category term="Testing"></category><title type="html">WhatsApp Ate My Family Dinner</title><published>2026-08-05T07:16:11Z</published><updated>2026-08-05T07:16:11Z</updated><link rel="alternate" href="https://testingideas.wordpress.com/2026/08/05/whatsapp-ate-my-family-dinner/" type="text/html"></link><summary type="html">It is 9:47 PM. Someone somewhere reaches for their phone to send a family member a photo of their dinner, their kid, or in my case, their cats fighting over the same cardboard box. Before they find the chat, a red badge catches their eye. Someone in the office WhatsApp group has tagged them. Client … &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://testingideas.wordpress.com/2026/08/05/whatsapp-ate-my-family-dinner/&quot;&gt;Continue reading &lt;span&gt;WhatsApp Ate My Family Dinner&lt;/span&gt; &lt;span&gt;→&lt;/span&gt;&lt;/a&gt;</summary><author><name>Dhanasekar Subramaniam</name></author><source gr:stream-id="feed/https://testingideas.wordpress.com/feed/"><id>tag:google.com,2005:reader/feed/https://testingideas.wordpress.com/feed/</id><title type="html">The Pragmatist</title><link rel="alternate" href="https://testingideas.wordpress.com" type="text/html"></link></source></entry></feed>