<?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: Corina: Web for Everyone</title>
    <description>The latest articles on DEV Community by Corina: Web for Everyone (@corinamurg).</description>
    <link>https://dev.to/corinamurg</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1164642%2F0af76079-b23b-4149-b55c-4ac79ddffefe.jpg</url>
      <title>DEV Community: Corina: Web for Everyone</title>
      <link>https://dev.to/corinamurg</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/corinamurg"/>
    <language>en</language>
    <item>
      <title>Testing for SC 2.5.3 Label in Name with Playwright</title>
      <dc:creator>Corina: Web for Everyone</dc:creator>
      <pubDate>Tue, 21 May 2024 17:45:43 +0000</pubDate>
      <link>https://dev.to/corinamurg/testing-for-sc-253-label-in-name-21dl</link>
      <guid>https://dev.to/corinamurg/testing-for-sc-253-label-in-name-21dl</guid>
      <description>&lt;h2&gt;
  
  
  What is Success Criterion 2.5.3?
&lt;/h2&gt;

&lt;p&gt;It’s a WCAG (&lt;a href="https://www.w3.org/TR/WCAG22/" rel="noopener noreferrer"&gt;Web Content Accessibility Guidelines&lt;/a&gt;) rule that requires careful naming of interactive elements and headings. For these types of elements, the browser has to compute an &lt;a href="https://webforeveryone.us/blog/how-accessibility-works#the-accessible-name" rel="noopener noreferrer"&gt;accessible name&lt;/a&gt; which may be different from the visible text or label of that element. The &lt;a href="https://www.w3.org/WAI/WCAG22/Understanding/label-in-name.html" rel="noopener noreferrer"&gt;2.5.3 criterion&lt;/a&gt; requires that the accessible name contains the visible text. In fact, as a best practice, the start of the accessible name should match the visible text.&lt;/p&gt;

&lt;p&gt;For example, given a button with visible text “Submit”, an accessible name of “Submit form” will guarantee compliance with the rule, but “Form submission” will not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This rule helps two groups of users:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Speech input users who rely on the visible text to activate an interactive element. Since voice software can recognize an element only by its accessible name, a user’s command should match the name assistive tech will recognize.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sighted users who rely on screen readers. With this rule in place, they will hear the same text as the one they see on the screen. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Testing conformance with 2.5.3
&lt;/h2&gt;

&lt;p&gt;In the past, I used to rely on &lt;a href="https://developer.chrome.com/docs/lighthouse/overview/" rel="noopener noreferrer"&gt;Google’s Lighthouse&lt;/a&gt; scans. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Google's Lighthouse scans use &lt;a href="https://github.com/dequelabs/axe-core/tree/develop" rel="noopener noreferrer"&gt;Deque's axe-core library&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Several months ago my code unexpectedly failed this rule a couple of times, so I decided to develop my own test. I just wanted to explore the criteria such an evaluation might use. Since the source of failures were elements with &lt;code&gt;aria-label&lt;/code&gt;, I decided to design the test around them. &lt;/p&gt;

&lt;p&gt;This is certainly not to say that &lt;code&gt;aria-label&lt;/code&gt; is the recommended way to name an interactive element. Quite the contrary. I just didn't know any better at the time. My advice: use it when semantic HTML can’t take you any further, and even then you should first consider better ARIA solutions (like &lt;code&gt;aria-labelledby&lt;/code&gt;) or CSS solutions (like &lt;code&gt;visually-hidden&lt;/code&gt; text).&lt;/p&gt;






&lt;h2&gt;
  
  
  First approach: collect all elements with &lt;code&gt;aria-label&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This approach has one advantage: once all elements are collected, it takes the visible text and the accessible name (given by the &lt;code&gt;aria-label&lt;/code&gt; value) and compares the first few words.&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="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://webforeveryone.us/&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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Controls conform with SC 2.5.3 Label in Name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;elements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;main&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[aria-label]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;elementsCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;elementsCount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;visibleText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;innerText&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;accName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aria-label&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;visibleText&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;accName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;textToCompareFromVisible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;firstNWords&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;visibleText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;textToCompareFromAccName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;firstNWords&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;accName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;textToCompareFromAccName&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;textToCompareFromVisible&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Acc name "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;accName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" should start with "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;visibleText&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Label in Name test failed:\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;firstNWords&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;slice&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="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why this first approach is far from perfect
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;It excludes any elements named with &lt;code&gt;aria-labeledby&lt;/code&gt;, the other ARIA attribute used to compute the accessible name. This attribute supersedes any attribute, including the &lt;code&gt;aria-label&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It excludes elements whose accessible name is based on visually-hidden text or attributes like the &lt;code&gt;alt&lt;/code&gt; text for images.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It does not try to match the entire string of the visible text with the start of the accessible name.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: When testing with Windows’ speech software, I can successfully activate a control using the first two words of the visible text or label. Of course, one testing scenario should not speak for all possible contexts, but for the purpose of this test I went with the assumption that the speech software can recognize an element based on the first few words of its accessible name. This assumption takes care of the speech input users that SC 2.5.3 is concerned with, but it ignores the sighted screen reader users. For them, a scenario in which the visible text and the accessible name diverge significantly after the first few words is not a great experience.&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p&gt;The motivation to try a different approach was driven not only by these drawbacks but also by necessity. Lighthouse has removed the 2.5.3 rule from its tests, and it’s only available with the axe-core Pro account. Below is my second, still very raw attempt. I’m hoping to improve on it as I keep tinkering with it. &lt;/p&gt;




&lt;h2&gt;
  
  
  Second approach: manually select all target elements
&lt;/h2&gt;

&lt;p&gt;This is more labor intensive. Playwright’s Codegen feature helped with collecting the information about each clicked element:&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Learn accessibility&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then I used it to set up the &lt;code&gt;Locator&lt;/code&gt; object:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buttonLearnA11y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;link&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Learn accessibility&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ideal solution would involve grabbing a &lt;code&gt;Locator&lt;/code&gt; using &lt;code&gt;page.getByRole('link', { name: 'Some name' })&lt;/code&gt; or &lt;code&gt;page.getLabel('link', { name: 'Some name' })&lt;/code&gt; and then directly accessing the &lt;code&gt;name&lt;/code&gt; from the &lt;code&gt;Locator&lt;/code&gt; object itself. As far as I can tell, this is not possible, so I had to manually add the name value to the &lt;code&gt;checkLabelInName&lt;/code&gt; function:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;labelCheck&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;checkLabelInName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buttonLearnA11y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Learn accessibility&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;br&gt;&lt;br&gt;
Here’s the entire code, including the helper functions:&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;checkLabelInName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;accName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;visibleText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;innerText&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;visibleText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;accName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;normalizedVisibleText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;normalizeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;visibleText&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;normalizedAccName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;normalizeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;accName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;numWordsToCompare&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;countWords&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;normalizedVisibleText&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;countWords&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;normalizedAccName&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;textToCompareFromVisible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getWords&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;normalizedVisibleText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;numWordsToCompare&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;textToCompareFromAccName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getWords&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;normalizedAccName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;numWordsToCompare&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;textToCompareFromVisible&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;textToCompareFromAccName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;normalizeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&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="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&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="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &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="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;                      
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;countWords&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&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="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getWords&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;slice&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="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &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="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://webforeveryone.us/&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="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;home-main controls conform to 2.5.3 Label in Name&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;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Learn accessibility BUTTON conforms to 2.5.3 Label in Name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buttonLearnA11y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;link&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Learn accessibility&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;labelCheck&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;checkLabelInName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buttonLearnA11y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Learn accessibility&lt;/span&gt;&lt;span class="dl"&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;labelCheck&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeTruthy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// more 2.5.3 Label in Name tests&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;h3&gt;
  
  
  Why the second approach in not perfect
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Quite labor intensive (or maybe Playwright has been spoiling me too much with its Codegen voodoo?! Is this even an excuse when judging the quality of a test?!)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It relies on the tester’s accuracy and knowledge of which elements need to be tested (I know, I know. That's the tester's job ...)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The test passes in scenarios where the rule simply does not apply. As test defects go, this is not an outrageous one, but it's still misleading.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;This is it! Right now, I'm out of ideas. As I'm adding this test to all the pages of my site, I will (hopefully) come across instances of false positives and other inconsistencies that will help with the next iteration. &lt;/p&gt;

&lt;p&gt;Thank you for reading! I'd appreciate your thoughts or hints on how to improve my approach.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Image credit&lt;/strong&gt;: Photo by &lt;a href="https://unsplash.com/@alexkondratiev" rel="noopener noreferrer"&gt;Alex Kondratiev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Image description: Glass test tubes containing green, orange, and blue liquids. &lt;/p&gt;

</description>
      <category>playwright</category>
      <category>a11y</category>
      <category>e2e</category>
    </item>
    <item>
      <title>Testing for Accessibility with Playwright</title>
      <dc:creator>Corina: Web for Everyone</dc:creator>
      <pubDate>Mon, 27 Nov 2023 04:18:11 +0000</pubDate>
      <link>https://dev.to/corinamurg/testing-for-accessibility-with-playwright-9o</link>
      <guid>https://dev.to/corinamurg/testing-for-accessibility-with-playwright-9o</guid>
      <description>&lt;p&gt;&lt;strong&gt;Merging my favorite tool with my passion:&lt;/strong&gt; 🎭 &lt;strong&gt;+ A11y&lt;/strong&gt; &lt;/p&gt;




&lt;p&gt;For my first accessibility tests, I decided to start with a couple of ready-made scripts provided in the documentation. These tests use the &lt;code&gt;@axe-core/playwright&lt;/code&gt; package to evaluate a wide range of accessibility rules.&lt;/p&gt;

&lt;p&gt;Some of these rules align with specific criteria from the Web Content Accessibility Guidelines (WCAG), while others are considered best practices but not explicitly required by WCAG. &lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing for WCAG A Compliance
&lt;/h2&gt;

&lt;p&gt;If you are interested in scanning an entire page for accessibility violations, the following test is a good start:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;homepage&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;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should not have any automatically detectable accessibility issues&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://corinamurg.netlify.app/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;accessibilityScanResults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AxeBuilder&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;analyze&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;accessibilityScanResults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;violations&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt; 
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If you prefer to focus on rules that correspond to particular WCAG criteria, you could use &lt;code&gt;AxeBuilder.withTags()&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;I also started with &lt;code&gt;AxeBuilder.withTags()&lt;/code&gt;. My targets were the &lt;strong&gt;WCAG A&lt;/strong&gt; guidelines for which I used the &lt;code&gt;wcag2a&lt;/code&gt; and &lt;code&gt;wcag21a&lt;/code&gt; tags.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@playwright/test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;AxeBuilder&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@axe-core/playwright&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should not have any automatically detectable WCAG A violations&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;testInfo&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://corinamurg.netlify.app/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;accessibilityScanResults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AxeBuilder&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;withTags&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wcag2a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wcag21a&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="nf"&gt;analyze&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;accessibilityScanResults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;violations&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&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;I did not expect to see any violations, and indeed there were none. Moving on!&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Unexpected Results with WCAG AA
&lt;/h2&gt;

&lt;p&gt;A different story with &lt;strong&gt;WCAG AA&lt;/strong&gt;! Again, I did not expect any violations, but there were quite a few!&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;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should not have any automatically detectable WCAG AA violations&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;testInfo&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://corinamurg.netlify.app/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;accessibilityScanResults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AxeBuilder&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;withTags&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wcag2aa&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wcag21aa&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="nf"&gt;analyze&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;accessibilityScanResults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;violations&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&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;I had previously run the &lt;strong&gt;axe Dev Tools&lt;/strong&gt; scan and the page received a clean bill of health:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftidj8er3o5erktvqtc1h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftidj8er3o5erktvqtc1h.png" alt="This image shows the results of an accessibility test run on the website 'https://corinamurg.netlify.app/' using axe DevTools. The results display a total of zero issues, indicating no detected accessibility problems. There are additional categories such as 'Critical', 'Serious', 'Moderate', and 'Minor', all of which also show zero issues. The 'Best Practices' switch is toggled on, and the WCAG 2.1 AA standards have been applied to the test. The interface includes a 'Re-run scan' button, suggesting that the test can be performed again. There are options to sign up or sign in at the top right corner of the tool's interface."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But the Playwright scan revealed SIX(!) elements with color contrast issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;three with the &lt;code&gt;sample-project--title&lt;/code&gt; class, and &lt;/li&gt;
&lt;li&gt;three with the &lt;code&gt;sample-project--description&lt;/code&gt; class.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All failure summaries were similar to this one:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;failureSummary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Fix any of the following:
+    Element has insufficient color contrast of 2.61 
       (foreground color: #a0a0a0, 
       background color: #ffffff, 
       font size: 14.4pt (19.2px), 
       font weight: normal). 
       Expected contrast ratio of 4.5:1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="o"&gt;+&lt;/span&gt;   &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;p class=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;sample-project--description&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;
                    React, Typescript
              &amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;impact&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;serious&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;target&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
 &lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.my-portfolio-site &amp;gt; .sample-project &amp;gt; .sample-project--description&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="o"&gt;+&lt;/span&gt;         &lt;span class="p"&gt;],&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Troubleshooting the Color Contrast Issue
&lt;/h2&gt;

&lt;p&gt;It was quite the head-scratching moment because the CSS declaration blocks told a different story.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="nc"&gt;.sample-project--title&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;align-self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;inline-block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.7rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;32px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="nc"&gt;.sample-project--description&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.2rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;400&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&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;To determine the color contrast of an element we need to know the foreground and the background colors. In this case, neither element has specific colors, so they inherit from the body element: white background, and black text. Doesn't this combination give the best color contrast one can ask for?! 🤔&lt;/p&gt;

&lt;p&gt;And yet, the test revealed a color-contrast violation … Not only that, but it was referring to a text color that my site does not even use: &lt;code&gt;foreground color #a0a0a0&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;This actually gave me the idea to be more specific about the colors for each element. So, I added &lt;code&gt;color:inherit&lt;/code&gt;. And … surprise! It worked ... for the &lt;code&gt;sample-project--title&lt;/code&gt; elements, that is! Running the test again revealed only 3 errors, one for each of the three &lt;code&gt;sample-project--description&lt;/code&gt; elements.&lt;/p&gt;

&lt;p&gt;After this semi-victory, I assumed the test needed more specificity so I replaced &lt;code&gt;color:inherit&lt;/code&gt; with the actual hex values. No luck! (and in hindsight, no surprise. I was at a point where I was just guessing …) 😕&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Looking for Help from the WebAIM’s Contrast Checker
&lt;/h2&gt;

&lt;p&gt;Was the size of the text too small? I wouldn’t have thought that to be the cause of the violation, again because of the black text on white background combination. Still, I checked WebAIM’s color contrast tool just to make sure (and because I did not know what else to do!!!):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqiu17p1c0dg88m5hdk30.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqiu17p1c0dg88m5hdk30.png" alt="The image is of a Contrast Checker tool displaying the results for a color contrast test between a black foreground color (#000000) and a white background color (#FFFFFF). The contrast ratio is indicated as 21:1, which is the highest possible score, and it is enclosed in a green-outlined box. Below the ratio, there are results for 'Normal Text' and 'Large Text' showing a green "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s also WebAIM’s specification about the relationship between font size and expected color contrast:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;WCAG 2.0 level &lt;strong&gt;AA&lt;/strong&gt; requires a contrast ratio of at least &lt;strong&gt;4.5:1 for normal text&lt;/strong&gt; and &lt;strong&gt;3:1 for large text&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;WCAG 2.1 requires a contrast ratio of at least 3:1 for graphics and user interface components (such as form input borders). &lt;/p&gt;

&lt;p&gt;WCAG Level &lt;strong&gt;AAA&lt;/strong&gt; requires a contrast ratio of at least &lt;strong&gt;7:1 for normal text&lt;/strong&gt; and &lt;strong&gt;4.5:1 for large text&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Large text is defined as 14 point (typically 18.66px) and bold or larger, or 18 point (typically 24px) or larger.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Back to my trouble-making elements: with a font size of 19.2px and a contrast ratio of 21:1, they should pass not just the AA guidelines, but the AAA ones as well!&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Will AAA Fail Too?!
&lt;/h2&gt;

&lt;p&gt;Sigh of relief … running the &lt;strong&gt;WCAG AAA&lt;/strong&gt; scan found no errors with those particular elements. But wait ... why not? They failed the lower standard. How come they passed the higher standard?! 😲  &lt;/p&gt;

&lt;p&gt;There were a few errors regarding another elements, and for good reasons. This is an example of one of the failure summaries:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;failureSummary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Fix any of the following:
+    Element has insufficient color contrast of 4.5 
       (foreground color: #1a73c6, 
        background color: #f6f6f6,
        font size: 12.0pt (16px), 
        font weight: normal). 
        Expected contrast ratio of 7:1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;span class=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;footer-heading&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;Profiles&amp;lt;/span&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;impact&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;serious&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;target&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;           &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.footer-right--social &amp;gt; .footer-heading&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;         &lt;span class="p"&gt;],&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is the CSS declaration block for one of the elements with the AAA violations:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="nc"&gt;.footer-heading&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background-color&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#f6f6f6&lt;/span&gt;
    &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#1a73c6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;text-transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;uppercase&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;At 16px, the font-size for this element is considered “normal” so it needs a contrast ratio of 7:1 to meet the AAA guideline. The failure summary confirmed (correctly this time!) the contrast checker’s result: the element’s contrast ratio is only 4.5:1, good enough for AA but falling short of the AAA guidelines.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq04ddbk5fbinly23ti8q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq04ddbk5fbinly23ti8q.png" alt="The image shows a web interface of a Contrast Checker tool. It indicates the contrast ratio between a blue foreground color (#1A73C6) and a light gray background color (#F6F6F6) as 4.5:1, which is outlined in a green box and labeled as the minimum ratio for WCAG AA compliance. The tool shows 'Pass' for large text compliance with both WCAG AA and AAA standards, but 'Fail' for normal text under WCAG AAA. Sample text "&gt;&lt;/a&gt;&lt;/p&gt;



&lt;h2&gt;
  
  
  Back to the WCAG AA failed test …
&lt;/h2&gt;

&lt;p&gt;How much time is too much time investigating and troubleshooting a problem when you have no idea why it exists in the first place? After the failed attempts mentioned above, I scoured the documentation, reached out to Playwright’s Discord community, and opened a bug issue on Playwright’s GitHub repo. It had to be a bug, there was no other explanation I could find.&lt;/p&gt;

&lt;p&gt;The response was swift: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This sounds like a bug which should be reported at @axe-core/playwright or axe-core since Playwright does not do anything related to axe.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ahhh ... if it’s indeed a bug, as I had assumed, it must be from the package that actually checks for violations. Why did I not think about that?!&lt;/p&gt;

&lt;p&gt;Another round of electronically leafing through another documentation. So far, no answers. But will soon find a way to submit a bug report. Stay tune! 😎&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Update
&lt;/h2&gt;

&lt;p&gt;I did reach out to the axe-core team and they were super helpful. They explained that &lt;code&gt;AxeBuilder analyze()&lt;/code&gt; runs as soon as the DOM is ready. Since my code has CSS fade-in transitions, they get in the way of the Playwright test. Adding a 2-second timeout solved the problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  Coming Up
&lt;/h2&gt;

&lt;p&gt;In the mean time, I have another a11y bug to deal with. Found by &lt;strong&gt;Google’s Lighthouse&lt;/strong&gt; extension:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa7siyztd35t4gi64y97q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa7siyztd35t4gi64y97q.png" alt="The image shows a Lighthouse web accessibility evaluation report for 'https://corinamurg.netlify.app/'. The report gives the following results: Performance 99, Accessibility 95, Best Practices 100, SEO 90."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can you guess my next challenge?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Write a test in Playwright that will check for the following WCAG guideline:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For each user interface component that includes a visible text label, the accessible name MUST match (or include) the visible text in the label.&lt;/p&gt;
&lt;/blockquote&gt;



&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://webaim.org/resources/contrastchecker/" rel="noopener noreferrer"&gt;WebAIM Contrast Checker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/debs_obrien/series/25202"&gt;Debbie O’Brien’s Playwright Series on dev.to&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://playwright.dev/docs/intro" rel="noopener noreferrer"&gt;Playwright Documentation&lt;/a&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Image credit&lt;/strong&gt;: Photo by &lt;a href="https://unsplash.com/@alexkondratiev" rel="noopener noreferrer"&gt;Alex Kondratiev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Description: The image shows a hand pouring a blue liquid from a glass test tube into a flask with red liquid, and another hand pouring a green liquid into the flask. The background is plain white.&lt;/p&gt;

</description>
      <category>playwright</category>
      <category>testing</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Using Codegen</title>
      <dc:creator>Corina: Web for Everyone</dc:creator>
      <pubDate>Mon, 20 Nov 2023 03:51:52 +0000</pubDate>
      <link>https://dev.to/corinamurg/using-codegen-2gib</link>
      <guid>https://dev.to/corinamurg/using-codegen-2gib</guid>
      <description>&lt;p&gt;&lt;strong&gt;Start with confidence with autogenerated tests!&lt;/strong&gt; 🎭&lt;/p&gt;




&lt;p&gt;Playwright allows you to generate test scripts based on your interactions with the UI. This feature is known as Playwright's code generation capability. When you interact with your app's UI elements during a testing session, Playwright records these interactions and generates corresponding test scripts. Quite straightforward! &lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Steps to Get Started with Codegen
&lt;/h2&gt;



&lt;p&gt;&lt;br&gt;&lt;strong&gt;Step 1&lt;/strong&gt;. &lt;strong&gt;Open the Testing sidebar and click Record new&lt;/strong&gt;.&lt;br&gt;
Playwright will open a new test file, as well as a blank browser page.&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;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&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="c1"&gt;// Recording...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;. In the browser, &lt;strong&gt;type the URL for the site&lt;/strong&gt; you want to test. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;. Once typed in, the &lt;strong&gt;URL automatically gets recorded inside the testing file&lt;/strong&gt;:&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;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://corinamurg.netlify.app/&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4&lt;/strong&gt;. Now Playwright expects you to &lt;strong&gt;manually perform actions&lt;/strong&gt; on that site, so it can translate these actions into test scripts. &lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;For more details, visit &lt;a href="https://playwright.dev/docs/codegen#record-a-new-test" rel="noopener noreferrer"&gt;Playwright's documentation on codegen&lt;/a&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  My Codegen Session
&lt;/h2&gt;

&lt;p&gt;My goal was to test the links inside my navbar. As I was manually clicking every link in my navbar, Playwright translated these actions into test scripts. At the end, my &lt;code&gt;test&lt;/code&gt; function looked like this:&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;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test navigation links&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://corinamurg.netlify.app/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;banner&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;link&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Corina Murg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;navigation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;link&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;navigation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;link&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Projects&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;navigation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;link&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Accessibility&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;navigation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;link&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;About&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;page2Promise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;popup&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;navigation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;link&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Blog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;page2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page2Promise&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;My assumption was that the automated test would &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;check that each link is clickable, and &lt;/li&gt;
&lt;li&gt;check that it opens the expected page. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It just happens that when I learn, I like to break the code and notice how it reflects in the browser. So, I disabled the paths to the &lt;strong&gt;Blog&lt;/strong&gt; and the &lt;strong&gt;About&lt;/strong&gt; links and expected an error for each link. &lt;/p&gt;

&lt;p&gt;Well, this did not happen! At least not for both links, that is. I received the error for the &lt;strong&gt;Blog&lt;/strong&gt; link (note: this link connects to an external site and has an target="_blank" attribute), but I did not receive the error for the &lt;strong&gt;About&lt;/strong&gt; link. 🤔&lt;/p&gt;

&lt;p&gt;Help came from the (awesome) Playwright documentation! Here's what it says about &lt;code&gt;.click()&lt;/code&gt; method:&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Under the hood, this and other pointer-related methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;wait for the element with the given selector to be in the DOM&lt;/li&gt;
&lt;li&gt;wait for it to become displayed, i.e., not empty, no display: none, no visibility: hidden&lt;/li&gt;
&lt;li&gt;wait for it to stop moving, for example, until the CSS transition finishes&lt;/li&gt;
&lt;li&gt;scroll the element into view&lt;/li&gt;
&lt;li&gt;wait for it to receive pointer events at the action point, for example, wait until the element becomes non-obscured by other elements&lt;/li&gt;
&lt;li&gt;retry if the element is detached during any of the above checks

&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;It turns out that in the case of my 'About' link, the &lt;code&gt;.click()&lt;/code&gt; method checks if an element with the role of 'link' and the name 'About' exists within the navigation, and then it clicks on that element. BUT it does not check whether the link leads to a specific destination!&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Checking a Link to an External Page
&lt;/h2&gt;

&lt;p&gt;There was no error for the &lt;strong&gt;About&lt;/strong&gt; link, but then why did I get the error about the &lt;strong&gt;Blog&lt;/strong&gt; link? The clue was in the last three lines of code:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;page2Promise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;popup&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;navigation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;link&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Blog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;page2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page2Promise&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a page is opened by a &lt;code&gt;target="_blank"&lt;/code&gt; link, we get a reference to it by listening to the &lt;code&gt;popup&lt;/code&gt; event on the page. The &lt;code&gt;waitForEvent()&lt;/code&gt; method waits for the &lt;code&gt;popup&lt;/code&gt; to happen within a given timeout. If the &lt;code&gt;popup&lt;/code&gt; event doesn't occur, Playwright will throw an error. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One caveat&lt;/strong&gt;: the &lt;code&gt;waitForEvent()&lt;/code&gt; method and the &lt;code&gt;popup&lt;/code&gt; event help confirm the link's functionality by triggering its action, yet they don't verify if the link navigates to a specific URL. To make sure the link led to my blog page, I had to add additional lines of code. I also personalized the code by renaming the &lt;code&gt;popup&lt;/code&gt; promise variable:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blogPromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;popup&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;navigation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;link&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Blog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;blogPromise&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// WAIT FOR THE BLOG PAGE TO LOAD, THEN CHECK URL AND TITLE&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;blog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForLoadState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&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;blog&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://dev.to/corinamurg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&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;blog&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Corina: Web is for Everyone - DEV Community&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;h2&gt;
  
  
  Checking the Link to an Internal Page
&lt;/h2&gt;

&lt;p&gt;As I mentioned above, using &lt;code&gt;.click()&lt;/code&gt; is a necessary start, but not sufficient on its own. We have to add extra checks or assertions to verify the full functionality of a link.&lt;/p&gt;

&lt;p&gt;For my (internal) navbar links, I added assertions for all the URLs and a check for the 'About' page that a certain text was visible:&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;navigation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;link&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Projects&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&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;page&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://corinamurg.netlify.app/projects&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;navigation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;link&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Accessibility&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&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;page&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://corinamurg.netlify.app/accessibility&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;navigation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;link&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;About&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&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;page&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://corinamurg.netlify.app/about&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&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;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My Career in a Nutshell&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBeVisible&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;What should you focus on while in codegen mode? &lt;/p&gt;

&lt;p&gt;First, decide on what tests you want to automate. Then, when using the codegen feature, interact with those elements of your web application that are relevant to the test you want to automate. &lt;/p&gt;

&lt;p&gt;The idea is to mimic the actions a real user would perform to achieve a certain task or navigate through a particular flow in your application. The code generated by Playwright will reflect these interactions, creating a baseline script. &lt;/p&gt;

&lt;p&gt;I ❤️ how the codegen feature significantly simplifies the initial setup of a test, especially for those who are new to writing test scripts (moi!). I don't have to write code from scratch and I can quickly get started. But of course, as I shared above, the auto-generated code has to be refined and expanded upon to create comprehensive automated tests. For that, don't forget to make use of the documentation!&lt;/p&gt;

&lt;p&gt;So, what are you waiting for? Start playing! 🎭&lt;/p&gt;

&lt;p&gt;Coming up: testing for accessibility!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: My site is still in construction, so expect to find UI and accessibility bugs/errors beyond those tested here.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/debs_obrien/series/25202"&gt;Debbie O’Brien’s Playwright Series on dev.to&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://playwright.dev/docs/intro" rel="noopener noreferrer"&gt;Playwright Documentation&lt;/a&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Image credit&lt;/strong&gt;: Photo by &lt;a href="https://unsplash.com/@alexkondratiev" rel="noopener noreferrer"&gt;Alex Kondratiev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Description: The image shows a hand pouring a blue liquid from a glass test tube into a flask with red liquid, and another hand pouring a green liquid into the flask. The background is plain white.&lt;/p&gt;

</description>
      <category>playwright</category>
      <category>testing</category>
      <category>codegen</category>
      <category>vscode</category>
    </item>
    <item>
      <title>My First Playwright Tests</title>
      <dc:creator>Corina: Web for Everyone</dc:creator>
      <pubDate>Fri, 17 Nov 2023 14:18:54 +0000</pubDate>
      <link>https://dev.to/corinamurg/my-first-tests-in-playwright-20lc</link>
      <guid>https://dev.to/corinamurg/my-first-tests-in-playwright-20lc</guid>
      <description>&lt;p&gt;&lt;strong&gt;A blog series about playing and writing in 🎭&lt;/strong&gt;&lt;br&gt;
&lt;br&gt;&lt;br&gt;
I'm a developer learning about web accessibility, and I would like to add Playwright to my toolset for testing web accessibility compliance.&lt;/p&gt;

&lt;p&gt;So far, I've found that it offers straightforward syntax and excellent automation capabilities. Plus, the best documentation in the universe. (Yes, I believe aliens would use Playwright for some of their testing needs!)&lt;/p&gt;

&lt;p&gt;This post is about the first three tests I wrote and how I applied them to my portfolio site. &lt;/p&gt;


&lt;h2&gt;
  
  
  Getting Started with 🎭
&lt;/h2&gt;

&lt;p&gt;First, to get started (i.e., installation, how to run tests, etc.), I highly recommend Debbie O’Brien’s series of articles published on dev.to. I've included the link below in the Resources section.&lt;/p&gt;

&lt;p&gt;Once installed, Playwright comes with example tests to help you get started. I adapted some of these examples to create three tests specifically for my portfolio site:&lt;/p&gt;

&lt;p&gt;✔️ To navigate to the home page of my portfolio site and check if the title matches an expected string. &lt;br&gt;
✔️ To check for the visibility of the home page’s heading.&lt;br&gt;
✔️ To check whether the “My Projects” link is functional.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: My site is still in construction, so expect to find errors beyond those tested here.&lt;/p&gt;

&lt;p&gt;Here are all three of the tests:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@playwright/test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;has title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://corinamurg.netlify.app/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;await&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;page&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/Corina's Portfolio/&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;has heading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://mywebsite.com/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;await&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;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;heading&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;HELLO, I’m CORINA!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;})).&lt;/span&gt;&lt;span class="nf"&gt;toBeVisible&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My Projects link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://corinamurg.netlify.app/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;link&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My Projects&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;click&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;
  
  
  Understanding the Code for Test 1
&lt;/h2&gt;

&lt;p&gt;Let's break the code down into smaller steps and analyze them!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; We have to import two functions from Playwright: &lt;code&gt;test&lt;/code&gt; and &lt;code&gt;expect&lt;/code&gt;:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@playwright/test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;the &lt;code&gt;test&lt;/code&gt; function is used to define an individual test. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;expect&lt;/code&gt; is an assertion function that checks whether a certain condition is met. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Heads up&lt;/strong&gt;: the term &lt;strong&gt;assertion&lt;/strong&gt; frequently appears in Playwright. An assertion is a check within a test that verifies whether certain conditions are met. So it basically evaluates a specific condition and passes or fails the test based on the result.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; Define a test named &lt;code&gt;has title&lt;/code&gt;&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;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;has title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; Navigate to my website&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://corinamurg.netlify.app/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4:&lt;/strong&gt;  Add an assertion to check if the webpage's title contains the text "Corina's Portfolio"&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="k"&gt;await&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;page&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/Corina's Portfolio/&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;&lt;strong&gt;A few important notes&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;code&gt;test&lt;/code&gt; function requires a string as its first argument to name the test, and a function as its second argument. This function is where you write the actual test code. It’s an asynchronous function that receives a &lt;code&gt;page&lt;/code&gt; object. &lt;/li&gt;
&lt;li&gt;a test interacts with web pages through this &lt;code&gt;page&lt;/code&gt; object, which is an instance of the &lt;code&gt;Page&lt;/code&gt; class. The &lt;code&gt;Page&lt;/code&gt; class provides a wide range of methods that allows us to simulate any possible user interactions and scenario. For example, use  &lt;code&gt;.goto()&lt;/code&gt;  to navigate to URLs, &lt;code&gt;page.click()&lt;/code&gt; or &lt;code&gt;page.fill()&lt;/code&gt; to interact with elements,  &lt;code&gt;page.locator()&lt;/code&gt; to query the DOM. I highly recommend checking out &lt;a href="https://playwright.dev/docs/pom" rel="noopener noreferrer"&gt;the documentation on the Page class and its methods&lt;/a&gt;. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;await&lt;/code&gt; is necessary because Playwright operates asynchronously. It performs actions in a browser environment that requires waiting for the actions to complete before moving to the next step.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let’s look briefly at the other two tests as well.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Test 2
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Define a test named 'has heading' &lt;/span&gt;
&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;has heading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://corinamurg.netlify.app/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// Expect page to have a heading with name of 'HELLO, I’m CORINA!'&lt;/span&gt;
    &lt;span class="k"&gt;await&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;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;heading&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;HELLO, I’m CORINA!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})).&lt;/span&gt;&lt;span class="nf"&gt;toBeVisible&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;
  
  
  Test 3
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Define a test named 'My Projects link'&lt;/span&gt;
&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My Projects link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://corinamurg.netlify.app/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// simulate a user clicking on the 'My Projects' link&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;link&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My Projects&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;click&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;
  
  
  Playing with Errors
&lt;/h2&gt;

&lt;p&gt;As an experiment, I modified the &lt;code&gt;has title&lt;/code&gt; test with a different expected title, which, as anticipated, led to a failed test due to the mismatch.&lt;/p&gt;

&lt;p&gt;Here is the (quite long) error log:&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="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Timed&lt;/span&gt; &lt;span class="nx"&gt;out&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt; &lt;span class="nx"&gt;waiting&lt;/span&gt; &lt;span class="k"&gt;for&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;locator&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="nx"&gt;Locator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;:root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="nx"&gt;Expected&lt;/span&gt; &lt;span class="nx"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;My&lt;/span&gt; &lt;span class="nx"&gt;site&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt; 
&lt;span class="nx"&gt;Received&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Corina's Portfolio&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
&lt;span class="nx"&gt;Call&lt;/span&gt; &lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toHaveTitle&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;timeout&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt; 
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;waiting&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nf"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;:root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;locator&lt;/span&gt; &lt;span class="nx"&gt;resolved&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/html&amp;gt;&lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;unexpected&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Corina's Portfolio&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;locator&lt;/span&gt; &lt;span class="nx"&gt;resolved&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/html&amp;gt;&lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;unexpected&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Corina's Portfolio&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;locator&lt;/span&gt; &lt;span class="nx"&gt;resolved&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/html&amp;gt;&lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;unexpected&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Corina's Portfolio&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;locator&lt;/span&gt; &lt;span class="nx"&gt;resolved&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/html&amp;gt;&lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;unexpected&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Corina's Portfolio&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;locator&lt;/span&gt; &lt;span class="nx"&gt;resolved&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/html&amp;gt;&lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;unexpected&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Corina's Portfolio&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;locator&lt;/span&gt; &lt;span class="nx"&gt;resolved&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/html&amp;gt;&lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;unexpected&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Corina's Portfolio
- locator resolved to &amp;lt;html lang=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="nx"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;…&amp;lt;/html&amp;gt; 
- unexpected value &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="nx"&gt;Corina&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s Portfolio" 
- locator resolved to &amp;lt;html lang="en"&amp;gt;…&amp;lt;/html&amp;gt; 
- unexpected value "Corina&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="nx"&gt;Portfolio&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;expect&lt;/code&gt; function was waiting for the page title to match "My site", but instead found "Corina's Portfolio". This mismatch between expected and actual results caused the test to fail.&lt;/p&gt;

&lt;p&gt;The repeated lines like &lt;code&gt;-unexpected value 'Corina's Portfolio'&lt;/code&gt; and &lt;code&gt;-locator resolved to &amp;lt;html lang='en'&amp;gt;…&amp;lt;/html&amp;gt;&lt;/code&gt; show that &lt;strong&gt;Playwright&lt;/strong&gt; was continually checking the page title within the specified timeout period (5000ms). Each line likely represents an attempt to recheck the title against the expected value. Of course, it consistently found a value that did not match the expected pattern. &lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion 😊
&lt;/h2&gt;

&lt;p&gt;I'm thrilled that my first three tests were successful! To create these tests I adapted the example tests that Playwright adds at installation. In the next post I will talk about another test that I created with just a click of a button! Seriously!&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/debs_obrien/series/25202"&gt;Debbie O’Brien’s Playwright Series on dev.to&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://playwright.dev/docs/intro" rel="noopener noreferrer"&gt;Playwright Documentation&lt;/a&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Image credit&lt;/strong&gt;: Photo by &lt;a href="https://unsplash.com/@alexkondratiev" rel="noopener noreferrer"&gt;Alex Kondratiev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Description: The image shows a hand pouring a blue liquid from a glass test tube into a flask with red liquid, and another hand pouring a green liquid into the flask. The background is plain white.&lt;/p&gt;

</description>
      <category>playwright</category>
      <category>testing</category>
      <category>vscode</category>
    </item>
    <item>
      <title>HTML: Buttons vs. Links</title>
      <dc:creator>Corina: Web for Everyone</dc:creator>
      <pubDate>Wed, 15 Nov 2023 04:04:11 +0000</pubDate>
      <link>https://dev.to/corinamurg/html-buttons-vs-links-5059</link>
      <guid>https://dev.to/corinamurg/html-buttons-vs-links-5059</guid>
      <description>&lt;p&gt;&lt;strong&gt;Using Buttons and Links with Accessibility in Mind&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Buttons and links are fundamental elements in web design, but each has a distinct semantic meaning and accessibility implications. &lt;/p&gt;

&lt;p&gt;Let’s learn how to use them!&lt;/p&gt;




&lt;h2&gt;
  
  
  Buttons
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Use them for actions!&lt;br&gt;
They are intended to trigger an event when you click on them. Examples include submitting a form, opening a modal window, or any other action that does not navigate to a new page or resource.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Be Accessibility-focused&lt;/strong&gt;: Create them with the &amp;lt;button&amp;gt; tag! &lt;/p&gt;

&lt;p&gt;Buttons created with this tag come with important benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;assistive technologies like screen readers interpret them as interactive controls;&lt;/li&gt;
&lt;li&gt;they are focusable by default, which means they are accessible through keyboard navigation;
&lt;/li&gt;
&lt;li&gt;they can be activated with the Enter or Space key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All these features are important for users who do not use a mouse and/or rely on assistive technologies, and they come for &lt;strong&gt;free&lt;/strong&gt; just because you use the &amp;lt;button&amp;gt; tag! &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Name Your Buttons!&lt;/strong&gt;&lt;br&gt;
When screen reader users navigate to a button they need to hear its name in order to understand its purpose.&lt;/p&gt;

&lt;p&gt;What should you do?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use descriptive text that clearly describe the action it will perform. For instance, "Search Flight Deals" is more informative than just "Search."&lt;/li&gt;
&lt;li&gt;avoid using the same text for multiple buttons on the same page unless they perform the same action. Unique and specific text for each button helps users distinguish between different actions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Styling Buttons&lt;/strong&gt;: You can style them to look like almost anything! But make sure they are still recognizable as interactive elements.&lt;/p&gt;


&lt;h2&gt;
  
  
  Links (Anchors)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Use them for navigation!&lt;br&gt;
Their primary role is to take you from the current location to a new resource. This could be a different page, a different section of the same page, or an external website.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Be Accessibility-focused&lt;/strong&gt;: Create them with the &amp;lt;a&amp;gt; HTML tag! You’ll also have to add an &lt;code&gt;href&lt;/code&gt; attribute pointing to the destination URL or page anchor. &lt;/p&gt;

&lt;p&gt;Screen readers announce links as such, and just like buttons, they are focusable by default and can be accessed through keyboard navigation. To activate a link, press the Enter key.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Label Your Links!&lt;/strong&gt;&lt;br&gt;
Just like buttons, links must have a name. Screen readers might announce links separately from their surrounding text, so make sure to use descriptive text.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Styling Links&lt;/strong&gt;: You have many options to style them as long as they remain distinguishable from the surrounding text. Stick with the default style (underlined and colored differently from surrounding text) to help users identify them as actionable items. &lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What to Avoid
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;div&lt;/code&gt; or &lt;code&gt;span&lt;/code&gt; elements as substitutes for buttons or links! Simply because they are not inherently accessible. If you (or your designer) insist on using them, then you must add the appropriate ARIA roles, tabindex, and keyboard event handling to make them accessible.&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; 
    &lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
    &lt;span class="nx"&gt;tabindex&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
    &lt;span class="nx"&gt;onclick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;yourFunction();&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
    &lt;span class="nx"&gt;onkeydown&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;if(event.key === 'Enter') { yourFunction(); }&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;onkeyup&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;if(event.key === 'Space') { yourFunction(); }&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;Close&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Really, why would you go down this road given all the extra work?!&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Aspects To Remember
&lt;/h2&gt;

&lt;p&gt;Your users have specific expectations when activating a link (e.g., the page will change) versus a button (e.g., some action will occur on the page). So use the correct element for the intended action: &amp;lt;button&amp;gt; for on-page actions, &amp;lt;a&amp;gt; for navigation.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;Please visit &lt;a href="https://https://webforeveryone.us/" rel="noopener noreferrer"&gt;Web for Everyone&lt;/a&gt; for a thorough introduction to accessibility.&lt;/p&gt;

</description>
      <category>button</category>
      <category>link</category>
      <category>a11y</category>
      <category>semantichtml</category>
    </item>
    <item>
      <title>HTML: Tag vs. Element</title>
      <dc:creator>Corina: Web for Everyone</dc:creator>
      <pubDate>Sat, 11 Nov 2023 23:05:29 +0000</pubDate>
      <link>https://dev.to/corinamurg/html-tag-vs-element-3dc5</link>
      <guid>https://dev.to/corinamurg/html-tag-vs-element-3dc5</guid>
      <description>&lt;p&gt;In a previous post, we looked at &lt;strong&gt;semantic&lt;/strong&gt; vs. &lt;strong&gt;non-semantic&lt;/strong&gt; HTML elements. Now, it’s common for web developers to use &lt;strong&gt;HTML element&lt;/strong&gt; and &lt;strong&gt;HTML tag&lt;/strong&gt; interchangeably. But are they really the same thing? Or is there more than meets the eye?&lt;/p&gt;

&lt;p&gt;Let's decode this lingo!&lt;/p&gt;




&lt;h2&gt;
  
  
  HTML Tag
&lt;/h2&gt;

&lt;p&gt;A tag is used to create an HTML element in source code. When we say tag we must refer to the opening &amp;lt;tagname&amp;gt; or closing &amp;lt;/tagname&amp;gt; syntax used in HTML documents. &lt;/p&gt;

&lt;p&gt;Tags come in pairs for most elements, with an opening tag marking the beginning of the element and a closing tag marking the end. However, some tags are self-closing, such as &amp;lt;img /&amp;gt; or &amp;lt;br /&amp;gt;, which do not need a closing tag.&lt;/p&gt;

&lt;h2&gt;
  
  
  HTML Element
&lt;/h2&gt;

&lt;p&gt;An HTML element is a DOM element. It refers to everything from the start tag to the end tag, including the tag itself, its attributes, and the content in between. &lt;/p&gt;

&lt;p&gt;For example, an element can consist of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the opening tag: &amp;lt;p&amp;gt;&lt;/li&gt;
&lt;li&gt;the content: Hello, World!&lt;/li&gt;
&lt;li&gt;the closing tag: &amp;lt;/p&amp;gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So when you write &amp;lt;p&amp;gt;Hello, World!&amp;lt;/p&amp;gt;, you're creating a paragraph element. &lt;/p&gt;

&lt;p&gt;Elements can also be nested, meaning you can have elements within elements, and they can contain attributes that provide additional information about the element.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;br&gt;
Let's look at an example to illustrate the difference:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;a href="https://www.example.com"&amp;gt;Visit Example.com&amp;lt;/a&amp;gt; 


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The &lt;strong&gt;HTML Tags&lt;/strong&gt; include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the opening tag &amp;lt;a&amp;gt; (which also stores the element's attribute &lt;strong&gt;href&lt;/strong&gt; with its corresponding value).&lt;/li&gt;
&lt;li&gt;the closing tag &amp;lt;/a&amp;gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;HTML Element&lt;/strong&gt; is the entire line of code, including &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the opening tag &amp;lt;a&amp;gt;,&lt;/li&gt;
&lt;li&gt;the attribute href="&lt;a href="https://www.example.com" rel="noopener noreferrer"&gt;https://www.example.com&lt;/a&gt;",&lt;/li&gt;
&lt;li&gt;the content Visit Example.com, and &lt;/li&gt;
&lt;li&gt;the closing tag &amp;lt;/a&amp;gt;.

&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In HTML, the terms "element" and "tag" are related but have distinct meanings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a tag is a part of an element that defines the element's type and boundaries&lt;/li&gt;
&lt;li&gt;an element includes the tags, attributes, and content.

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fppepq8s7c4xsi1ss168u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fppepq8s7c4xsi1ss168u.png" alt="An illustration showing the anatomy of an HTML element. It displays a paragraph element with an opening tag &amp;lt;p&amp;gt;, an attribute class="&gt;&lt;/a&gt;. Above each part, labels indicate "Opening tag", "An attribute and its value", "Enclosed text content", and "Closing tag""/&amp;gt;&lt;br&gt;
Source: MDN (see link below)&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Element" rel="noopener noreferrer"&gt;MDN Definition of an HTML element&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Tag" rel="noopener noreferrer"&gt;MDN Definition of an HTML Tag&lt;/a&gt;&lt;/p&gt;

</description>
      <category>html</category>
      <category>a11y</category>
      <category>tag</category>
      <category>element</category>
    </item>
    <item>
      <title>Use Semantic HTML!</title>
      <dc:creator>Corina: Web for Everyone</dc:creator>
      <pubDate>Sat, 11 Nov 2023 22:40:47 +0000</pubDate>
      <link>https://dev.to/corinamurg/use-semantic-html-4b97</link>
      <guid>https://dev.to/corinamurg/use-semantic-html-4b97</guid>
      <description>&lt;p&gt;In most conversations about accessibility, the use of semantic HTML is most likely to be the first and most common piece of advice you will receive. Let's understand why!&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Semantic HTML
&lt;/h2&gt;

&lt;p&gt;These are elements whose names convey information about their content, and sometimes about the role they have on a page. For example, if I see &amp;lt;nav&amp;gt; in a codebase I understand that to be a container for navigation elements. &lt;/p&gt;

&lt;p&gt;Using semantic HTML elements is important for accessibility because of the extra power these elements have: they can provide information about their purpose, and assistive technologies transfer this information to their users.&lt;/p&gt;

&lt;p&gt;Here are a couple of examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an &amp;lt;a&amp;gt; tag creates a link that can lead to a new page or a different section on the same page. &lt;/li&gt;
&lt;li&gt;in order to get a quick understanding of a page's content and structure a screen reader user can press the "h" key and navigate through all the headings - created with tags &amp;lt;h1&amp;gt; through &amp;lt;h6&amp;gt; - because headings are used to define the main sections on a given page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's not an overstatement to note that using semantic HTML elements (using them correctly, of course!) allows assistive tech users to navigate the web with ease. &lt;/p&gt;



&lt;h2&gt;
  
  
  Non-Semantic HTML
&lt;/h2&gt;

&lt;p&gt;Non-semantic elements are those that do not convey any particular meaning about their content to browsers or assistive technologies. They are typically containers used for styling purposes or for layout. &lt;/p&gt;

&lt;p&gt;The &amp;lt;div&amp;gt; and &amp;lt;span&amp;gt; are examples of non-semantic elements. They tell nothing about their purpose on the page and are generally used to apply CSS styling. &lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A Few Semantic Examples
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&amp;lt;header&amp;gt;&lt;/strong&gt;&lt;br&gt;
This element typically contains a group of navigation links and introductory content. Assistive technologies use it to identify the main heading and navigation area of a page, allowing users to easily orient themselves on your site.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&amp;lt;nav&amp;gt;&lt;/strong&gt;&lt;br&gt;
This element contains links to other pages or to parts within the page. When a screen reader encounters this element, it announces to the user that this section of the page is for navigation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&amp;lt;main&amp;gt;&lt;/strong&gt;&lt;br&gt;
It refers to the main content of the page, distinct from content like sidebars, navigation links, and footers. Marking your important content with this tag allows user of assistive technologies to skip directly to the main content, bypassing headers and navigation links for a more streamlined browsing experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&amp;lt;article&amp;gt;&lt;/strong&gt;&lt;br&gt;
Use this for independent, self-contained content that could be distributed outside of the webpage, like a forum post, a magazine or newspaper article, or a blog entry. Assistive devices announce when they reach the end of an article, which can be very useful for users consuming a series of articles or posts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&amp;lt;aside&amp;gt;&lt;/strong&gt;&lt;br&gt;
Use it to mark content that is tangentially related to the main content on the page. One approach would be to make it a sidebar. Assistive technologies will announce this content as additional information, allowing users to distinguish between primary content and side content.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Important to Remember
&lt;/h2&gt;

&lt;p&gt;These semantic elements play a crucial role in accessibility. For users who rely on screen readers or other assistive devices, they present content in a more meaningful and navigable way. &lt;/p&gt;

&lt;p&gt;A semantic element can be the deciding factor in whether or not some users are able to understand and interact with web pages!&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond Accessibility: The Wider Benefits of Semantic HTML
&lt;/h2&gt;

&lt;p&gt;Semantic HTML isn't just about making websites more accessible. It also plays a vital role in making your content machine-readable, which has wide-ranging benefits:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SEO Advantages&lt;/strong&gt;: Search engines love semantics! Semantic HTML helps them understand the structure and content of your website. By tagging your content correctly, you make sure that they can easily parse and index your site, focusing on the content you want them to see.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Maintainability and Scalability&lt;/strong&gt;: For developers, semantic HTML means easier maintenance and scalability. It's like leaving a breadcrumb trail in your code, making it intuitive to understand, update, and extend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Future-Proofing&lt;/strong&gt;: As web standards evolve, having a semantically structured website ensures better compatibility with future browsers and tech. Think of it as an investment in your site's longevity.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.w3schools.com/TAGs/" rel="noopener noreferrer"&gt;W3 Schools Page on HTML Elements and Their Definitions&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element" rel="noopener noreferrer"&gt;MDN Page on HTML Elements and Their Definitions&lt;/a&gt;&lt;/p&gt;

</description>
      <category>html</category>
      <category>semantic</category>
      <category>a11y</category>
    </item>
    <item>
      <title>The World of Sparse Arrays in JavaScript</title>
      <dc:creator>Corina: Web for Everyone</dc:creator>
      <pubDate>Fri, 10 Nov 2023 16:10:04 +0000</pubDate>
      <link>https://dev.to/corinamurg/the-world-of-sparse-arrays-in-javascript-1fpo</link>
      <guid>https://dev.to/corinamurg/the-world-of-sparse-arrays-in-javascript-1fpo</guid>
      <description>&lt;p&gt;&lt;strong&gt;Me: The length of an array is determined by the number of its elements, right? &lt;br&gt;
&lt;br&gt;JavaScript: Hmm, not really . . .&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;Ah, JavaScript arrays!  😊&lt;/p&gt;

&lt;p&gt;At first glance, they seem so simple, just a linear collection of items, right? But dig a little deeper, and you'll find some surprises. Call them just another nod to the sometimes perplexing nature of JavaScript.&lt;/p&gt;

&lt;p&gt;In this post I will talk about: &lt;br&gt;
✅ what determines the length of an array&lt;br&gt;
✅ the difference between sparse and dense arrays&lt;br&gt;
✅ how to work with sparse arrays&lt;/p&gt;


&lt;h2&gt;
  
  
  The Case of the Mysterious Array Length
&lt;/h2&gt;

&lt;p&gt;Remember the first time you thought you'd mastered arrays? Same. I thought the array length was determined by the number of defined elements. But alas, JavaScript had other plans.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Sparse Arrays
&lt;/h3&gt;

&lt;p&gt;Let's create an empty array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let arr = []  ✅
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks harmless, right? Now let's put an element at index 2:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr[2] = 5  ✅
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What do you think &lt;code&gt;arr.length&lt;/code&gt; would be? If you said 1, join the club of the fooled!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log(arr.length) -&amp;gt; 3  😱
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yes, &lt;code&gt;arr.length&lt;/code&gt; is 3, not 1! &lt;/p&gt;

&lt;p&gt;In JavaScript, &lt;code&gt;arr.length = highest index + 1&lt;/code&gt; (plus 1 because we start indexing at 0). &lt;/p&gt;

&lt;p&gt;It's true, this is not your everyday array. It's what we call a sparse array. And if you're wondering what a sparse array is, try logging the array to the console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log(arr) -&amp;gt; [ &amp;lt;2 empty items&amp;gt;, 5 ]  🤔
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll notice that there are two empty spots preceding the value 5. These empty spots, called also holes, make the array sparse, as it contains gaps where no explicit values have been set.&lt;/p&gt;

&lt;p&gt;Think of it like a parking lot where you decide to park your car in a spot marked #10. This implies that there are 9 other spots before it. Even if these preceding spots are empty, the parking lot is still considered to have a capacity of 10 spots. &lt;/p&gt;

&lt;p&gt;JavaScript arrays operate on the same principle: marking a spot at index 2 means there are two other spots before it (at indices 0 and 1), making the array's length 3.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Dense Arrays
&lt;/h3&gt;

&lt;p&gt;In contrast, you may be more accustomed to dense arrays, where every index corresponds to a value, even if it's set to undefined.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let dense = [ "dense", "arrays", "are", "boring"]  😉
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In dense arrays, there are no gaps; each slot in the array is accounted for, whether it's holding a value or is explicitly undefined.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Sparse Array Meets map( )
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;A Surprise&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So, you might wonder, what happens when you run the map() function on our sparse array?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const newArr = arr.map(x =&amp;gt; x + 3)

console.log(newArr) -&amp;gt; [ &amp;lt;2 empty items&amp;gt;, 8 ]  😲
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected to see &lt;code&gt;NaN&lt;/code&gt; (ie "Not-a-Number")? So did I. But it turns out that &lt;code&gt;map()&lt;/code&gt; just ignores the empty spots!&lt;/p&gt;

&lt;p&gt;Think of a sparse array as a parking lot divided into two sections: free parking and paid parking. Free parking spaces are like the empty slots in our array. Our parking officer - the &lt;code&gt;map()&lt;/code&gt; function - ignores them and walks right past them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Question&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A fair question to ask: if the empty spots are ignored, why aren’t they just eliminated from the new array? Because after our parking officer finishes their rounds, the parking lot (our array) must remain the same size! &lt;/p&gt;

&lt;p&gt;Similarly, JavaScript's &lt;code&gt;map()&lt;/code&gt; method will always return a new array of the same length as the original. It doesn't eliminate empty spots; it keeps them as they are, ensuring that the length of the array remains consistent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An Experiment&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now let's explicitly set the first element as &lt;code&gt;undefined&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr[0] = undefined
console.log(arr) -&amp;gt; [ undefined, &amp;lt;1 empty item&amp;gt;, 5 ]  ✅

const newArr = arr.map(x =&amp;gt; x + 3)

console.log(newArr) -&amp;gt; [ NaN, &amp;lt;1 empty item&amp;gt;, 8 ]  😲
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how the first element of the new array is now &lt;code&gt;NaN&lt;/code&gt;. Why? &lt;/p&gt;

&lt;p&gt;When we use &lt;code&gt;map()&lt;/code&gt; on an array in JavaScript, the function we provide as an argument is called on each index that has been assigned a value. We know it ignores the empty spots, but it does pay attention to every element with an assigned value. Even when that value is &lt;code&gt;undefined&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;So if we explicitly set an element to &lt;code&gt;undefined&lt;/code&gt;, &lt;code&gt;map()&lt;/code&gt; will indeed invoke the function on that element. In our specific example of &lt;code&gt;arr.map(x =&amp;gt; x + 3)&lt;/code&gt;, the function is attempting to add 3 to &lt;code&gt;undefined&lt;/code&gt;. In JavaScript, any arithmetic operation involving undefined will output &lt;code&gt;NaN&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To exhaust our parking lot analogy: when an array element is explicitly set to &lt;code&gt;undefined&lt;/code&gt;, it's like a metered but unoccupied spot in the paid parking section. Our parking officer (again, the &lt;code&gt;map()&lt;/code&gt; function) walks by and makes note of it. In JavaScript terms, that means paying attention to that value and trying to work with it. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Note&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the above example, we got lucky. JavaScript will automatically convert &lt;code&gt;undefined&lt;/code&gt; to &lt;code&gt;NaN&lt;/code&gt; when it tries to perform an arithmetic operation. The &lt;code&gt;map()&lt;/code&gt; function will then continue to operate on the rest of the elements in the array.&lt;/p&gt;

&lt;p&gt;It is different with strings. When &lt;code&gt;map()&lt;/code&gt; encounters &lt;code&gt;undefined&lt;/code&gt; and the function is trying to, let’s say, convert it to lowercase, you'll run into a &lt;code&gt;TypeError&lt;/code&gt; because &lt;code&gt;undefined&lt;/code&gt; is not a string and does not have a &lt;code&gt;toLowerCase()&lt;/code&gt; method. The execution stops at that point.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const array = ['HELLO', 'WORLD', undefined]

const newArray = array.map(element =&amp;gt; element.toLowerCase())  🚫
//TypeError: Cannot read properties of undefined 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To ensure your code runs smoothly, it's essential to handle &lt;code&gt;undefined&lt;/code&gt; values before calling any methods on them: filter them out before applying &lt;code&gt;map()&lt;/code&gt; or use a &lt;code&gt;try-catch&lt;/code&gt; block. And of course, do not purposefully declare your elements as undefined! We did it here in the name of learning.  😊&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Sparse Array Meets filter()
&lt;/h3&gt;

&lt;p&gt;Shouldn't we just filter out the empty spots as well? Of course! You can filter out empty spots by using the &lt;code&gt;filter()&lt;/code&gt; method. Remember how &lt;code&gt;map()&lt;/code&gt; ignores them? Well, the empty slots are being treated as &lt;code&gt;undefined&lt;/code&gt; for the purpose of filtering! &lt;/p&gt;

&lt;p&gt;Let’s take our updated array and apply &lt;code&gt;filter()&lt;/code&gt; to it. The array has &lt;code&gt;undefined&lt;/code&gt; at first index, followed by an &lt;code&gt;empty spot&lt;/code&gt;, and value 5 at index 2.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log(newArr) -&amp;gt; [ undefined, &amp;lt;1 empty item&amp;gt;, 5 ]

const filteredNewArr = newArr.filter(x =&amp;gt; x !== undefined);

console.log(filteredNewArr) -&amp;gt; [5]  ✅

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok, but what if, theoretically, you only want to remove the holes but keep the &lt;code&gt;undefined&lt;/code&gt;? You can do something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const filteredNewArr = newArr.filter((item, index) =&amp;gt;         
                            arr.hasOwnProperty(index));

console.log(filteredNewArr) -&amp;gt; [ undefined, 5 ]  ✅
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, &lt;code&gt;hasOwnProperty()&lt;/code&gt; checks if the array has an actual value, including &lt;code&gt;undefined&lt;/code&gt;, at each index. Therefore, it will return true for all indices where a value exists and false for holes.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  To Recap
&lt;/h2&gt;

&lt;p&gt;✔️ Not all array are dense. Some have holes and we call them sparse.&lt;/p&gt;

&lt;p&gt;✔️ For the purpose of finding the length, we must count the holes as well.&lt;/p&gt;

&lt;p&gt;✔️ The &lt;code&gt;map()&lt;/code&gt; method ignores the holes, but it does not remove them.&lt;/p&gt;

&lt;p&gt;✔️ We can remove the holes with the &lt;code&gt;filter()&lt;/code&gt; method.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Are We Ready to Conclude?
&lt;/h2&gt;

&lt;p&gt;Is a sparse array a thing in real-world applications? I don’t have an answer yet, and promise to update the post if and when I do. But then, even if the answer is a resounding no, it does not matter. It would not make these quirky facets of JavaScript arrays any less captivating to explore. Long live quirkiness! &lt;/p&gt;

&lt;p&gt;Keep exploring!  ⛵&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;JavaScript: The Definitive Guide&lt;br&gt;
7th Edition, by David Flanagan&lt;br&gt;
O'Reilly Media, 2020&lt;br&gt;
&lt;br&gt;&lt;br&gt;
Blog post originally published on August 1, 2023 on corinamurg.dev.&lt;/p&gt;

&lt;p&gt;Credit: Photo by &lt;a href="https://unsplash.com/@lancaster83" rel="noopener noreferrer"&gt;Krzysztof Kotkowicz&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/red-car-parked-on-parking-lot-OKPhtQsyvM8" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>arrays</category>
    </item>
    <item>
      <title>Immutability in React</title>
      <dc:creator>Corina: Web for Everyone</dc:creator>
      <pubDate>Sat, 04 Nov 2023 17:30:23 +0000</pubDate>
      <link>https://dev.to/corinamurg/immutability-in-react-1apa</link>
      <guid>https://dev.to/corinamurg/immutability-in-react-1apa</guid>
      <description>&lt;p&gt;&lt;strong&gt;JavaScript objects are mutable. BUT, React asks that we treat objects in state as immutable. Should we listen?&lt;/strong&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Let's dive into the world of React and unravel the following mystery: why updating state feels like we're constantly moving into a new home instead of just rearranging our old furniture. 🏠&lt;/p&gt;

&lt;p&gt;In this post, we will focus on two things:&lt;/p&gt;

&lt;p&gt;✅ What it means to use immutable objects in React&lt;/p&gt;

&lt;p&gt;✅ How to safely update objects in state&lt;/p&gt;

&lt;p&gt;To mutate or not to mutate, that is the question!&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Updating state in React: an example
&lt;/h2&gt;

&lt;p&gt;Whether a beginner or a more seasoned React developer, code like the one below is relatively easy to grasp.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function SingleDie() {

    // set up the state: die is an object, with one property
    const [die, setDie] = useState({
        value: Math.ceil(Math.random() * 6),
        color: "blue"
    });

    // Generate new value when rolled, then update state
    function goodRollDie() {
        const newValue = Math.ceil(Math.random() * 6);
        setDie(oldDie =&amp;gt; ({ ...oldDie, 
                            value: newValue 
        }));
    }

    // JSX code that renders the component
    return (
        &amp;lt;div&amp;gt;
        &amp;lt;p&amp;gt;Value: {die.value}&amp;lt;/p&amp;gt;
        &amp;lt;button onClick={rollDie}&amp;gt;Roll Die&amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
    );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we have a component named &lt;code&gt;SingleDie&lt;/code&gt; that represents a die which can be rolled to produce a random value between 1 and 6.&lt;/p&gt;

&lt;p&gt;The state die is an object with two properties: &lt;code&gt;value&lt;/code&gt; and &lt;code&gt;color&lt;/code&gt; :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;value: Gets a random number between 1 and 6&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;color: Set to the string "blue"&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the &lt;code&gt;goodRollDie&lt;/code&gt; function is invoked a new random value between 1 and 6 is generated. The &lt;code&gt;setDie&lt;/code&gt; function is called to update the die state with this new value. Here, it uses the current state (referred to as &lt;code&gt;oldDie&lt;/code&gt;) to spread out all of its properties and only change the value property to the new random number. The color property remains unchanged.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The Bad, Bad Code 👎
&lt;/h2&gt;

&lt;p&gt;For me, a React newbie, the updating-state-by-creating-a-new-object approach was puzzling in the beginning. Why not just change the properties of the existing die object and update state with the modified object?! 🤔&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function badRollDie() {
    // update value with a newly generated one
    die.value = Math.ceil(Math.random() * 6);  

    // set the modified object as the state
    setDie(die); 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It turns out that this approach is problematic because it directly modifies the state, which goes against the principle of immutability in React.&lt;/p&gt;

&lt;p&gt;Just a reminder: JavaScript/React objects ARE mutable. We CAN change their content. BUT, React wants us (ok, implores us!) that we treat objects that are already in state as read-only, “as if they were immutable.”&lt;/p&gt;

&lt;p&gt;To further quote from the React documentation, &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;. . . without using the state setting function, React has no idea that the object has changed. So React does not do anything in response. It’s like trying to change the order after you’ve already eaten the meal. While mutating state can work in some cases, we don’t recommend it. You should treat the state value you have access to in a render as read-only.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;br&gt;In the (BAD) code example above, the &lt;code&gt;badRollDie&lt;/code&gt; function is designed poorly because it directly modifies the value property of the existing die object. 🚫&lt;/p&gt;

&lt;p&gt;Instead, as the &lt;code&gt;goodRollDie&lt;/code&gt; function shows, and I’m quoting again from the React documentation, "when you want to update an object, you need to create a new one (or make a copy of an existing one), and then set the state to use that copy." ✔️&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The GOOD CODE 👍
&lt;/h2&gt;

&lt;p&gt;So what happens in the good code ? In the &lt;code&gt;goodRollDie&lt;/code&gt; function, a new object is created using the spread operator when updating the die state. This technique ensures that the state is updated in an immutable way. ✔️&lt;/p&gt;

&lt;p&gt;We generate a new value. Then, the spread operator creates a new object by copying all the properties of the &lt;code&gt;oldDie&lt;/code&gt; object and overriding the value property with the &lt;code&gt;newValue&lt;/code&gt;. This new object is used as the updated state to set the die using &lt;code&gt;setDie&lt;/code&gt;. ✔️&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function goodRollDie() {
  const newValue = Math.ceil(Math.random() * 6);

  // Copy the old fields &amp;amp;override the value property  
  setDie(oldDie =&amp;gt; ({...oldDie, value: newValue}));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To summarize, a new object is created for the die to be updated. The &lt;code&gt;... die&lt;/code&gt; syntax, using the spread operator, ensures that the properties of the existing die are copied into a new object. Then, for the &lt;code&gt;goodRollDie&lt;/code&gt; function, a new value is created, which will override the previous value in the NEW object. All is good with the world now! 😊&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The BIG QUESTION
&lt;/h2&gt;

&lt;p&gt;Why immutability? As mentioned above, immutable data structures allow React to quickly determine if changes have occurred, and that makes the re-rendering process more efficient.&lt;/p&gt;

&lt;p&gt;It turns out it provides other benefits as well, such as easier debugging, simpler code maintenance, and compatibility with future React features. React team's reasoning behind these benefits is more thorough than my one-sentence attempt, even if esoteric at times for a React beginner. So for right now, I will just have to take their word for it and simply follow the rule! 😎&lt;/p&gt;

&lt;p&gt;My hope is that, as I continue to work in React and my coding skills improve, by embracing immutability (of course!) I will develop a deeper understanding of its advantages and how it benefits my projects.&lt;/p&gt;

&lt;p&gt;In the meantime, I will remember to REPLACE, and NOT mutate. ✔️&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://react.dev/learn/updating-objects-in-state" rel="noopener noreferrer"&gt;React Documentation on Updating Objects In State&lt;/a&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Blog post originally published on July 24, 2023 on corinamurg.dev.&lt;/p&gt;

&lt;p&gt;Credit: Photo by &lt;a href="https://unsplash.com/@saimens" rel="noopener noreferrer"&gt;Simon Schwyter&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/a-red-and-blue-chamelon-sitting-on-a-branch-Nod8_cz1NDU" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Recent at() Method in JavaScript</title>
      <dc:creator>Corina: Web for Everyone</dc:creator>
      <pubDate>Fri, 03 Nov 2023 13:41:59 +0000</pubDate>
      <link>https://dev.to/corinamurg/the-new-at-method-in-javascript-35mp</link>
      <guid>https://dev.to/corinamurg/the-new-at-method-in-javascript-35mp</guid>
      <description>&lt;p&gt;&lt;strong&gt;The Cool Way to Dial Elements in JavaScript&lt;/strong&gt; 📞 😎&lt;/p&gt;

&lt;p&gt;Python devs, hold the smirks! JavaScripters, rejoice! Our syntax is catching up, and coding just got a tiny bit easier!&lt;/p&gt;

&lt;p&gt;A concise, elegant syntax has been introduced for accessing elements from the end of an array or string. Meet the .at() method! 🎉&lt;/p&gt;

&lt;p&gt;Before we dive into some of the details, here’s a quick example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let arr = [1, 2, 3, 4];

arr.at(-1) -&amp;gt; 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This feature has long been requested by developers, as it can simplify coding and make the syntax more intuitive, similar to languages like Python. Initially, the proposed name was .item(), but due to web incompatibility issues and potential conflicts with existing properties and methods in different libraries, .at() seems to be a better alternative.&lt;/p&gt;

&lt;p&gt;Let's explore it!&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  In a world without at() 😔
&lt;/h2&gt;

&lt;p&gt;Before at(), accessing elements from the end of arrays or strings involved cumbersome syntax or performance drawbacks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;array.length&lt;/strong&gt;&lt;br&gt;
The prevalent method was &lt;code&gt;arr[arr.length - N]&lt;/code&gt;, where N is the Nth item from the end, and &lt;code&gt;arr.length – N&lt;/code&gt; gives the index position to access the N-th element from the end.&lt;/p&gt;

&lt;p&gt;Let's look at an example!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let arr = [10, 20, 30, 40, 50];

arr.length -&amp;gt; 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get the 2nd element from the end (40 in this case), we subtract 2 from 5 (the length of the array), so &lt;code&gt;arr[arr.length - 2]&lt;/code&gt; is equivalent to &lt;code&gt;arr[3]&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr[arr.length - 2]  // Output: 40
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how this approach, while functional, requires using the name of the array twice. It then adds 7 more characters due to &lt;code&gt;.length&lt;/code&gt;. It is also incompatible with anonymous values. If a function returns an array, we first have to store it in a temporary variable before we can grab one of its values. Too much effort for a developer in 2023!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;slice()&lt;/strong&gt;&lt;br&gt;
While it is compatible with anonymous values, &lt;code&gt;slice()&lt;/code&gt; is less optimal: it creates a temporary array that is immediately discarded after retrieving a given element.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let arr = [1, 2, 3, 4, 5];

arr.slice(-2)[0] -&amp;gt; 4

// happening behind the scene
// arr.slice(-2) -&amp;gt; [4, 5]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how it also requires the use of the square brackets to access an element of the resultant array? Too much work!&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Why not just use [ ]? 🤔
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;[]&lt;/code&gt; syntax in JavaScript is a universal one, applicable to all objects, and not exclusive to arrays and strings. When we refer to a value using an index, such as &lt;code&gt;arr[3]&lt;/code&gt;, we are essentially referring to the property of the object with the key "3", a feature applicable to any object.&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;arr[-1]&lt;/code&gt; in the current JavaScript environment will not output an error. JavaScript will be looking for the property with the key "-1", and not for an index counting backward from the end. If it does not find it, the output will be undefined.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  How does at() work? ⚙️
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;.at()&lt;/code&gt; method takes an index as its parameter and returns the element in the array corresponding to the given index. This index is zero-based and is converted to an integer.&lt;/p&gt;

&lt;p&gt;Let's start with an array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let arr = [10, 20, 30, 40, 50];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and loop through every possible case!&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;✅ Given a positive index, &lt;code&gt;at()&lt;/code&gt; behaves just like the square bracket notation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr[2] -&amp;gt; 30

arr.at(2) -&amp;gt; 30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, the &lt;code&gt;[]&lt;/code&gt; syntax is probably better, since it's shorter.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;✅ An index equal to or greater than the array length is out of the range for the given array, and the method will return &lt;code&gt;undefined&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr.at(5) -&amp;gt; undefined
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;br&gt;✅ Given a negative index, &lt;code&gt;at()&lt;/code&gt; will count back from the end of the array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr.at(-2) -&amp;gt; 40

// index + array.length = -2 + 5 = 3

arr[3] -&amp;gt; 40
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how the accessed index will be equivalent to "index + array.length"!&lt;/p&gt;

&lt;p&gt;&lt;br&gt;✅ An index that is less than the negative value of the array length is also out of the range:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr.at(-6) // Output: undefined
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The method will not attempt to access any property, and it will return &lt;code&gt;undefined&lt;/code&gt;.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  All is GOOD with the world now! 😊
&lt;/h2&gt;

&lt;p&gt;So, there we have it, the new .at() method, making array and string manipulation more intuitive and clean!&lt;/p&gt;

&lt;p&gt;Now we can effortlessly dial in the index we want, be it from the start or the end, and JavaScript will connect us to our element without any fuss!&lt;/p&gt;

&lt;p&gt;Who's laughing now, Python? 😜&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at" rel="noopener noreferrer"&gt;MDN Documentation on the at() method&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tc39/proposal-relative-indexing-method" rel="noopener noreferrer"&gt;GitHub repository for the TC39 proposal to add the .at() method to the JavaScript language&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;Blog post originally published September 22, 2023 on corinamurg.dev.&lt;/p&gt;

&lt;p&gt;Credit: Photo by &lt;a href="https://unsplash.com/@wesley_squared" rel="noopener noreferrer"&gt;Wesley Hilario&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/person-holding-black-rotary-telephone-CNSH-JGEwtI" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>atmethod</category>
      <category>javascriptmethods</category>
    </item>
    <item>
      <title>The Temporal Dead Zone</title>
      <dc:creator>Corina: Web for Everyone</dc:creator>
      <pubDate>Thu, 02 Nov 2023 03:24:33 +0000</pubDate>
      <link>https://dev.to/corinamurg/the-temporal-dead-zone-idh</link>
      <guid>https://dev.to/corinamurg/the-temporal-dead-zone-idh</guid>
      <description>&lt;p&gt;&lt;strong&gt;JavaScript's Restricted Realm for LET and CONST&lt;/strong&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;The Temporal Dead Zone sounds like a sci-fi movie, doesn't it? But in the JavaScript universe, it's the space where a variable is off-limits, even though you might think it should be available. This behavior occurs with variables declared using &lt;code&gt;let&lt;/code&gt; and &lt;code&gt;const&lt;/code&gt;.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
In this post we will answer the following questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;What is the Temporal Dead Zone?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Where or when do we encounter it?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Why do we have it?&lt;br&gt;
&lt;br&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Before we dive any deeper though, let's review &lt;strong&gt;hoisting&lt;/strong&gt;.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Hoisting: What is it again?!
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://dev.to/corinamurg/the-curious-case-of-javascript-hoisting-1k8f"&gt;The Curious Case of JavaScript Hoisting&lt;/a&gt; we talked about how both variable and function declarations are moved - or hoisted - to the top of their containing scope during the compilation phase.&lt;/p&gt;

&lt;p&gt;However, not all hoisting is created equal. While function declarations are hoisted with their definitions, allowing us to call them even before their code appears, variables show more nuances:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Variables declared with &lt;code&gt;var&lt;/code&gt; are hoisted, but their initialization stays where it is. This means they'll exist (with an &lt;code&gt;undefined&lt;/code&gt; value) from the beginning of their scope, but they won't get their assigned value until the code execution reaches the point of initialization.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In contrast, variables declared with &lt;code&gt;let&lt;/code&gt; and &lt;code&gt;const&lt;/code&gt; are also hoisted but they enter a 'Temporal Dead Zone'. They remain inaccessible until the point of initialization, and any attempt to access them prematurely will throw an error.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's look at an example!&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  A Variable Declaration with var
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log(myCat) -&amp;gt; undefined

var myCat = "Petunia"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In the code above, the &lt;code&gt;var myCat&lt;/code&gt; declaration is hoisted to the top of the scope, but its initialization with the value &lt;code&gt;Petunia&lt;/code&gt; is not. This is why it returns &lt;code&gt;undefined&lt;/code&gt; when we try to log it before actually defining it.&lt;/p&gt;

&lt;p&gt;Now you might ask: what about &lt;code&gt;let&lt;/code&gt; and &lt;code&gt;const&lt;/code&gt;? Do they also get hoisted? Indeed, they do! JavaScript hoists all declarations, it's very uplifting in that manner. 😊&lt;/p&gt;

&lt;p&gt;Yet, while hoisting applies to all three, &lt;code&gt;let&lt;/code&gt; and &lt;code&gt;const&lt;/code&gt; get special treatment - they get sent to the &lt;strong&gt;Temporal Dead Zone&lt;/strong&gt;! 💀&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The Temporal Dead Zone 🚫
&lt;/h2&gt;

&lt;p&gt;The Temporal Dead Zone (TDZ) is JavaScript's no-access zone. When a &lt;code&gt;let&lt;/code&gt; or &lt;code&gt;const&lt;/code&gt; variable is hoisted, it enters the TDZ. From the start of the block until the line where the variable is declared, it's in the TDZ. Attempt to access it too soon, and JavaScript throws a &lt;code&gt;ReferenceError&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log(myVar)   // Output: undefined
var myVar = 'red'    // myVar is now delcared
console.log(myVar)   // Output: 'red'

console.log(myLet)   // ReferenceError: myLet is not defined
let myLet = 'orange' // myLet is now declared
console.log(myLet)   // Output" 'orange'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how &lt;code&gt;myVar&lt;/code&gt; floats up like a helium balloon and is undefined before the line where it’s actually tied down. This behavior is because of how &lt;code&gt;var&lt;/code&gt; declarations are hoisted. On the other hand, &lt;code&gt;myLet&lt;/code&gt; does get hoisted but lounges in the TDZ until the let &lt;code&gt;myLet = "orange"&lt;/code&gt; line runs.&lt;/p&gt;

&lt;p&gt;Here's an example using &lt;code&gt;const&lt;/code&gt; inside a block scope:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{  // start of the block scope

 console.log(cat)      // ReferenceError: cat is not defined
 const cat = "furry"   //  Ah, now cat is finally declared!
 console.log(cat)      // "furry"

}  // End of the block scope
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the scope of &lt;code&gt;cat&lt;/code&gt; is the entire block (the code within the { }). The TDZ for &lt;code&gt;cat&lt;/code&gt; is the stretch of this block until right before the &lt;code&gt;const cat = "furry"&lt;/code&gt; line. Once we pass that line of code, the cat is out of the TDZ ... and out of the bag, ready to be used (and cuddled).&lt;/p&gt;

&lt;p&gt;Phew, I am finally in the clear! 😸&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Finally: Why Does the TDZ Exist?
&lt;/h2&gt;

&lt;p&gt;Understanding the TDZ is one thing, but you might wonder why such a concept exists in the first place.&lt;/p&gt;

&lt;p&gt;The idea behind the TDZ is to help catch bugs in your code. Deciding between &lt;code&gt;var&lt;/code&gt;, &lt;code&gt;let&lt;/code&gt;, and &lt;code&gt;const&lt;/code&gt; for variable declaration? The strict behavior of &lt;code&gt;let&lt;/code&gt; and &lt;code&gt;const&lt;/code&gt; in TDZ suggests that they are generally better choices for writing robust, debuggable code.&lt;/p&gt;

&lt;p&gt;When you declare a variable using &lt;code&gt;var&lt;/code&gt;, it gets hoisted and initialized with &lt;code&gt;undefined&lt;/code&gt;. Using the variable before it's defined could lead to unexpected behavior, but you will not necessarily see an immediate error. Your code will not explicitly fail; it just operates unexpectedly.&lt;/p&gt;

&lt;p&gt;Let's remember an example from a previous post:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var result = 2 * myVar // Output: NaN

var myVar = 7;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this scenario, result will be &lt;code&gt;NaN&lt;/code&gt; because &lt;code&gt;myVar&lt;/code&gt; is &lt;code&gt;undefined&lt;/code&gt; at the time of the multiplication, and any arithmetic operation involving &lt;code&gt;undefined&lt;/code&gt; results in &lt;code&gt;NaN&lt;/code&gt;. These types of bugs are subtle and can be tricky to debug as they don’t throw an error and might not become apparent until much later in the program’s execution.&lt;/p&gt;

&lt;p&gt;On the other hand, &lt;code&gt;let&lt;/code&gt; and &lt;code&gt;const&lt;/code&gt; put the variable in the Temporal Dead Zone until it's declared and initialized. If you try to access the variable while it's in the TDZ, JavaScript throws a &lt;code&gt;ReferenceError&lt;/code&gt; and the code execution stops; you learn about the potential problem immediately.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;Oh, the intricacies of scope, hoisting, and the Temporal Dead Zone! Only in JavaScript, right? It pays to remember them in order to produce bug-resistant code. So, the next time you declare a variable, remember these quirks and choose wisely!&lt;/p&gt;

&lt;p&gt;Happy Halloween month! 🎃 😸&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;JavaScript: The Definitive Guide&lt;br&gt;
7th Edition, by David Flanagan&lt;br&gt;
O'Reilly Media, 2020&lt;/p&gt;

&lt;p&gt;Blog post: &lt;a href="https://dev.to/corinamurg/the-curious-case-of-javascript-hoisting-1k8f"&gt;The Curious Case of JavaScript Hoisting&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Blog post: &lt;a href="https://dev.to/corinamurg/demystifying-function-declarations-within-conditional-blocks-opm"&gt;Demystifying Function Declarations Within Conditional Blocks&lt;/a&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Blog post originally published October 2, 2023 on corinamurg.dev.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>temporaldeadzone</category>
      <category>hoisting</category>
      <category>variables</category>
    </item>
    <item>
      <title>The Curious Case of JavaScript Hoisting</title>
      <dc:creator>Corina: Web for Everyone</dc:creator>
      <pubDate>Thu, 02 Nov 2023 03:07:46 +0000</pubDate>
      <link>https://dev.to/corinamurg/the-curious-case-of-javascript-hoisting-1k8f</link>
      <guid>https://dev.to/corinamurg/the-curious-case-of-javascript-hoisting-1k8f</guid>
      <description>&lt;p&gt;&lt;strong&gt;Giving Code Elements a Head Start in the Race to Execution!&lt;/strong&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Ever played with a yo-yo? In JavaScript, variables and traditional function declarations act much like one: they start at the bottom but magically make their way to the top!&lt;/p&gt;

&lt;p&gt;Welcome to the fascinating realm of hoisting where function and variable declarations are silently shifted to the top of their respective scopes during the compilation phase (so before execution begins). But here's the plot twist: for some of them, the initializations stay grounded! ⬇️ 😲&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;We will look at the nuanced ways JavaScript deals with hoisting and focus on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;function declarations,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;variables declared with &lt;code&gt;var&lt;/code&gt;, and&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the somewhat mysterious behavior of &lt;code&gt;let&lt;/code&gt; and &lt;code&gt;const&lt;/code&gt;.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Time to elevate our understanding! 🚀&lt;/p&gt;

&lt;p&gt;But before we dive any deeper, let's talk about &lt;strong&gt;scope&lt;/strong&gt;.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What is Scope? 🏖️
&lt;/h2&gt;

&lt;p&gt;&lt;br&gt;Think of scope as your own private beach - only the variables declared there can have access and play!&lt;/p&gt;

&lt;p&gt;In JavaScript, scopes can be:&lt;br&gt;
&lt;br&gt;✅ Block Scope: the region of code within a pair of curly braces { }.&lt;/p&gt;

&lt;p&gt;Variables declared with &lt;code&gt;let&lt;/code&gt; and &lt;code&gt;const&lt;/code&gt; are block-scoped, meaning they can only be accessed within that block in which they are declared.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (true) {
  let blockedCat = "It's cozy in here!";
  const blockedDog = "I am stuck in here!";
} 

// blockedCat and blockedDog are not accessible outside this block
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;&lt;br&gt;✅ Function Scope: the region of code within a function definition.&lt;/p&gt;

&lt;p&gt;Variables declared with &lt;code&gt;var&lt;/code&gt; inside a function are function-scoped, meaning they are only accessible within that function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Here captured is not accessible outside this function

function selfishFunction() {
  var captured = "Get me out of here!";
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;&lt;br&gt;✅ Module Scope: the entire module has its own scope if you're coding using ES6 modules.&lt;/p&gt;

&lt;p&gt;This means that variables declared in a module are only accessible within that module unless they are explicitly exported.&lt;/p&gt;



&lt;p&gt;&lt;br&gt;✅ Global Scope: Variables declared outside of any function or block are globally scoped. These variables can be accessed and altered from any other scope in the program.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The Drama of Hoisting in JavaScript
&lt;/h2&gt;

&lt;p&gt;&lt;br&gt;Everyone is getting an early invite to the party but not everyone is being allowed to enter just yet!&lt;/p&gt;

&lt;p&gt;In JavaScript, both function declarations and variable declarations are hoisted, but their behavior varies due to the JavaScript engine's parsing rules.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Function Declarations
&lt;/h3&gt;

&lt;p&gt;Traditional function declarations - using the &lt;code&gt;function&lt;/code&gt; keyword - enjoy VIP status; they are hoisted along with their definitions. This means you can call such a function BEFORE its code even appears, and it will execute flawlessly. 🍹 😎&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hoistedFunction()
// Output: "This function has been hoisted."

function hoistedFunction() {
    console.log("This function has been hoisted.")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thanks to hoisting, you can structure your code by placing the more important logic at the top and the helper functions at the bottom, even if those helper functions are used in the upper parts of your code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: there are subtle nuances when these declarations appear inside conditional blocks. For a closer look at how different JavaScript environments handle function declarations inside conditional blocks, please refer to the &lt;a href="https://dev.to/corinamurg/demystifying-function-declarations-within-conditional-blocks-opm[](url)"&gt;Demystifying Function Declarations Within Conditional Blocks&lt;/a&gt; post in this series.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Variable Declarations Using &lt;code&gt;var&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Variables declared with &lt;code&gt;var&lt;/code&gt; do get hoisted but without their initializations (where you assign a value to a variable). Should you access such a variable before its definition, you'll receive &lt;code&gt;undefined&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log(myNumber) // Output: undefined

var myNumber = 5      // variable is now assigned a value
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, the &lt;code&gt;var myNumber&lt;/code&gt; declaration is hoisted to the top of the scope, but its initialization with the value 5 is not. This is why it returns &lt;code&gt;undefined&lt;/code&gt; when we try to log it before actually defining it.&lt;/p&gt;

&lt;p&gt;However, in the example above, we are fortunate: the console displays &lt;code&gt;undefined&lt;/code&gt;, silently whispering to us that a variable is being accessed before its assignment.&lt;/p&gt;

&lt;p&gt;What do you think happens when the uninitialized variable is part of a calculation or logical expression? Possible mayhem! Because it can lead to obscure and harder-to-detect issues.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var result = 2 * myVar // Output: NaN

var myVar = 7;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this scenario, result will be &lt;code&gt;NaN&lt;/code&gt; because &lt;code&gt;myVar&lt;/code&gt; is &lt;code&gt;undefined&lt;/code&gt; at the time of the multiplication, and any arithmetic operation involving &lt;code&gt;undefined&lt;/code&gt; results in &lt;code&gt;NaN&lt;/code&gt;. These types of subtle bugs can be especially tricky to debug as they don’t throw an error and might not become apparent until much later in the program’s execution.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Variable Declarations Using &lt;code&gt;let&lt;/code&gt; or &lt;code&gt;const&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Variables declared with &lt;code&gt;let&lt;/code&gt; or &lt;code&gt;const&lt;/code&gt; exhibit unique scope behavior. Although technically hoisted, attempting to access them prematurely leads to a &lt;code&gt;ReferenceError&lt;/code&gt; rather than &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The ultimate effect on your code is crucial: encountering &lt;code&gt;undefined&lt;/code&gt; will not interrupt code execution, but it may lead to logical errors or unexpected behavior. On the other hand, encountering a &lt;code&gt;ReferenceError&lt;/code&gt; will stop execution.&lt;/p&gt;

&lt;p&gt;We call this space from the start of the block until the line where the variable is actually declared the Temporal Dead Zone (TDZ). 🚫&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{  // Start of the block scope

console.log(boo) 
// Output: ReferenceError: boo is not defined

let boo = "ghost"
// boo is declared

console.log(boo) 
// Output: "ghost"

}  // End of the block scope
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the scope of &lt;code&gt;boo&lt;/code&gt; is the entire block (the code within the { }). The TDZ for &lt;code&gt;boo&lt;/code&gt; is the part of this block before the &lt;code&gt;let boo = "ghost"&lt;/code&gt; line. Once we pass that line of code, &lt;code&gt;boo&lt;/code&gt; is out of the TDZ and ready to be used.&lt;/p&gt;

&lt;p&gt;Many developers prefer using &lt;code&gt;let&lt;/code&gt; and &lt;code&gt;const&lt;/code&gt; because a &lt;code&gt;ReferenceError&lt;/code&gt; immediately alerts them to a scoping issue, halting the code and thus making it easier to debug. This behavior reduces the risk of logical errors that could arise when code execution continues with an &lt;code&gt;undefined&lt;/code&gt; value, as is the case with &lt;code&gt;var&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: For an in-depth look at the Temporal Dead Zone, please check out the second post from this series. Link at the end of the post.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  4. What about Function Expressions?
&lt;/h3&gt;

&lt;p&gt;It's important to note that function expressions - defined with &lt;code&gt;var&lt;/code&gt;, &lt;code&gt;let&lt;/code&gt;, or &lt;code&gt;const&lt;/code&gt; - fall into this category as well. &lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log(myFunc)  
// Output: ReferenceError: myFunc is not defined

const myFunc = function() {
    console.log("myFunc is hoisted.")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unlike traditional function declarations, function expressions do not enjoy VIP hoisting privileges, as the example above illustrates. Just the dread of the TDZ!&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Hoisting in Other Languages
&lt;/h2&gt;

&lt;p&gt;While the notion of scope and lifetime of variables exists in virtually all programming languages, can we say the same thing about hoisting? Not at all! The concept of hoisting as it exists in JavaScript is not very common in other programming languages.&lt;/p&gt;

&lt;p&gt;Most languages do not need a crane operator because they have a more straightforward scope and declaration system, where the order in which variables and functions are declared matters explicitly.&lt;/p&gt;

&lt;p&gt;Languages like C, C++, Java, and Python do not hoist variables and functions in the way JavaScript does. In these languages, trying to access a variable before it has been declared usually results in a compile-time or run-time error. Therefore, developers have to be more deliberate about the order in which they declare and use variables and functions.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In JavaScript, hoisting behavior allows for more flexibility (and sometimes more confusion) in how you can order your code. When choosing how to define a function and what types of variables to use, remember the mechanics of hoisting!&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;But, the story continues! Two related posts:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/corinamurg/the-temporal-dead-zone-idh"&gt;The Temporal Dead Zone&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/corinamurg/demystifying-function-declarations-within-conditional-blocks-opm"&gt;Demystifying Function Declarations Within Conditional Blocks&lt;/a&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;JavaScript: The Definitive Guide&lt;br&gt;
7th Edition, by David Flanagan&lt;br&gt;
O'Reilly Media, 2020&lt;br&gt;
&lt;br&gt;&lt;br&gt;
Post originally published August 26, 2023 on corinamurg.dev&lt;/p&gt;

&lt;p&gt;Credit: Photo by &lt;a href="https://unsplash.com/@gunnarridder" rel="noopener noreferrer"&gt;Gunnar Ridderström&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/yellow-crane-under-blue-sky-and-white-clouds-during-daytime-Bix61Z5i2F0" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>hoisting</category>
      <category>temporaldeadzone</category>
      <category>variables</category>
    </item>
  </channel>
</rss>
