<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ytrofr</title>
    <description>The latest articles on DEV Community by ytrofr (@ytrofr).</description>
    <link>https://dev.to/ytrofr</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4107847%2Ffbcc34d5-6998-4dca-8216-1ebb310293f5.png</url>
      <title>DEV Community: ytrofr</title>
      <link>https://dev.to/ytrofr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ytrofr"/>
    <language>en</language>
    <item>
      <title>A button that covers another button passes every test you have</title>
      <dc:creator>ytrofr</dc:creator>
      <pubDate>Thu, 03 Sep 2026 10:48:18 +0000</pubDate>
      <link>https://dev.to/ytrofr/a-button-that-covers-another-button-passes-every-test-you-have-1j9b</link>
      <guid>https://dev.to/ytrofr/a-button-that-covers-another-button-passes-every-test-you-have-1j9b</guid>
      <description>&lt;p&gt;Yesterday I shipped a share button onto the win screen of a games site I&lt;br&gt;
maintain. It was correct code. It type-checked, it rendered, every assertion&lt;br&gt;
about it passed, and it covered a control that children use.&lt;/p&gt;

&lt;p&gt;Here is the whole of it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;absolute&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;insetInlineStart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;insetInlineEnd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;max(12px, env(safe-area-inset-bottom))&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;justifyContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;zIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;openShareSheet&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Share my result&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bottom centre of the play area, floating, above everything. That is a&lt;br&gt;
reasonable place to put a thing that appears when you win.&lt;/p&gt;

&lt;p&gt;It is also where the game puts its controls. Measured in a browser on the built&lt;br&gt;
bundle, in two games:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;memory   chip 526-556   "Two players" button 512-549    covered
maze     chip 443-495   direction pad DOWN   432-492    covered
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every game on the site that steers with a direction pad puts that pad at the&lt;br&gt;
bottom centre of the same box. A centred floating pill anchored to the bottom&lt;br&gt;
of that box is not sometimes going to collide with them. It always was.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why nothing caught it
&lt;/h2&gt;

&lt;p&gt;The suite is not thin - about 4,500 tests, and several of them are specifically&lt;br&gt;
about this component. All of them passed, and none of them could have failed,&lt;br&gt;
for two separate reasons.&lt;/p&gt;

&lt;p&gt;The first is that a button covering another button is a completely valid&lt;br&gt;
program. Both elements exist. Both are in the accessibility tree. Both respond&lt;br&gt;
to a click, if you dispatch one at them directly. Every question a unit test&lt;br&gt;
knows how to ask - does it render, does it call the handler, does it carry the&lt;br&gt;
label, is it absent on a loss - has the same answer whether or not the thing is&lt;br&gt;
sitting on top of something else.&lt;/p&gt;

&lt;p&gt;The second is more specific, and it is the one worth carrying around:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;jsdom has no layout engine.&lt;/strong&gt; &lt;code&gt;getBoundingClientRect()&lt;/code&gt; returns zeros. Every&lt;br&gt;
element in a jsdom test occupies the rectangle (0, 0, 0, 0), which means no two&lt;br&gt;
elements ever overlap, which means an overlap assertion written against jsdom&lt;br&gt;
cannot fail. You can write the check. It will be green forever, on every&lt;br&gt;
codebase, for every element, including ones that are genuinely covering each&lt;br&gt;
other.&lt;/p&gt;

&lt;p&gt;That is a nastier property than "we did not write the test". A test that cannot&lt;br&gt;
fail is worse than a missing one, because it appears in coverage and it appears&lt;br&gt;
in review.&lt;/p&gt;
&lt;h2&gt;
  
  
  What actually found it
&lt;/h2&gt;

&lt;p&gt;I played the game.&lt;/p&gt;

&lt;p&gt;Won a round of the memory game, looked at the screen, and the pill was sitting&lt;br&gt;
on the "Two players" button. Total time to find: about four seconds after the&lt;br&gt;
win animation finished. Total time it had survived automated verification:&lt;br&gt;
every run, forever.&lt;/p&gt;

&lt;p&gt;I have a note in my repo, written after an earlier incident, that says a gate&lt;br&gt;
reading the bytes of an artifact cannot tell you the artifact runs. This is the&lt;br&gt;
same lesson one layer up. A gate that reads the DOM cannot tell you the DOM is&lt;br&gt;
usable, because usable is a geometric property and the DOM is not a geometry.&lt;/p&gt;
&lt;h2&gt;
  
  
  The fix, and the thing I pinned instead of the pixels
&lt;/h2&gt;

&lt;p&gt;The chip is in normal flow now. It reserves a strip at the end of the play area&lt;br&gt;
rather than being painted over one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0 0 auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;justifyContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10px 0 max(10px, env(safe-area-inset-bottom))&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same overlap check afterwards: zero covered controls.&lt;/p&gt;

&lt;p&gt;The interesting question was what to write a test for. I cannot test the&lt;br&gt;
geometry - see above. So the test reads the source and asserts the DECISION:&lt;br&gt;
this element does not get &lt;code&gt;position: absolute&lt;/code&gt;, does not get &lt;code&gt;position: fixed&lt;/code&gt;,&lt;br&gt;
does not get a &lt;code&gt;zIndex&lt;/code&gt;, and is not anchored to an edge.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;is in normal flow, so it reserves space instead of covering a control&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toMatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/position:&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;"'&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;absolute&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;"'&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toMatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/position:&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;"'&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;fixed&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;"'&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is an unusual shape for a test and I went back and forth on it. What sold&lt;br&gt;
me is that it fails for the right reason. I planted the exact code that shipped&lt;br&gt;
and three of its five assertions went red. And it carries its own instruction:&lt;br&gt;
if somebody later wants the chip floating, they have to bring a measurement&lt;br&gt;
against a direction-pad game, and delete this test to say so. A deliberate&lt;br&gt;
deletion with a reason is a much better artifact than a silent regression.&lt;/p&gt;

&lt;p&gt;The vacuity guard matters too, because a source-reading test can pass by&lt;br&gt;
accident on the wrong slice of file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;the block this test reads is the chip's, and not something else&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toMatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/Icon name="share"/&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeGreaterThan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The general version
&lt;/h2&gt;

&lt;p&gt;If a defect is geometric - overlap, clipping, contrast, reachable tap target,&lt;br&gt;
something below the fold that needed to be above it - your test suite is&lt;br&gt;
probably structurally incapable of seeing it, and it will be green with total&lt;br&gt;
confidence. Open the thing and use it.&lt;/p&gt;

&lt;p&gt;For what it is worth the site is Ellaz (&lt;a href="https://ellaz.fun/" rel="noopener noreferrer"&gt;ellaz.fun&lt;/a&gt;), 42 free browser games for&lt;br&gt;
kids in four languages, no ads and no accounts, and the source is MIT at&lt;br&gt;
&lt;a href="https://github.com/Sigmafier/ellaz" rel="noopener noreferrer"&gt;github.com/Sigmafier/ellaz&lt;/a&gt;. But the bug is the point, and I would have written&lt;br&gt;
this up the same if it had happened at work.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>testing</category>
      <category>react</category>
      <category>css</category>
    </item>
  </channel>
</rss>
