<?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>Forem: Lucas Andrade</title>
    <description>The latest articles on Forem by Lucas Andrade (@lucashdoa).</description>
    <link>https://forem.com/lucashdoa</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%2F194592%2Fa7274efc-b7db-453b-b2da-6f3f2327c7c4.jpg</url>
      <title>Forem: Lucas Andrade</title>
      <link>https://forem.com/lucashdoa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/lucashdoa"/>
    <language>en</language>
    <item>
      <title>Building an Image Gallery with Pure JavaScript</title>
      <dc:creator>Lucas Andrade</dc:creator>
      <pubDate>Thu, 16 Mar 2023 20:27:39 +0000</pubDate>
      <link>https://forem.com/lucashdoa/building-an-image-gallery-with-pure-javascript-151a</link>
      <guid>https://forem.com/lucashdoa/building-an-image-gallery-with-pure-javascript-151a</guid>
      <description>&lt;p&gt;Hello there! 👋 &lt;/p&gt;

&lt;p&gt;I'm Lucas, a Brazilian engineer, and this is &lt;em&gt;Yet Another DEV Content&lt;/em&gt; nobody asked for (but I made it anyway 😂). My goal with this blog is to talk about things related to the software development world and document personal projects I've worked on, while also honing recently acquired knowledge by sharing it. If you like it, follow me for more posts like this one!&lt;/p&gt;

&lt;p&gt;Today we'll tackle a small JavaScript project called &lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Image_gallery#project_brief" rel="noopener noreferrer"&gt;Image Gallery&lt;/a&gt;&lt;/strong&gt; featured in one of MDN's JavaScript tutorials. &lt;/p&gt;

&lt;p&gt;Please note that this is my solution to this challenge and probably not the best one you will find out there. Also note that the code is shown in this article in a manner that not always represent the final files. If you want to check the final code, a link to the Github repository as well as a link to the deployed app are provided in the Reference section at the end of the article.&lt;/p&gt;

&lt;p&gt;The GIF below shows how the project should look like when we're finished. Let's build it!&lt;/p&gt;

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




&lt;h2&gt;
  
  
  👣 Step-by-step Breakdown
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Image_gallery#project_brief" rel="noopener noreferrer"&gt;MDN tutorial&lt;/a&gt; provides initial boilerplate code for this project and all five images that we're going to use.&lt;/p&gt;

&lt;p&gt;We won't get into details on how the HTML was structured nor how it was styled since the goal here is to focus on the JavaScript part.&lt;/p&gt;

&lt;p&gt;If you open the boilerplate &lt;em&gt;index.html&lt;/em&gt; file, this is how it initially looks like:&lt;/p&gt;

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

&lt;p&gt;You can immediately notice that the thumbnail images are missing and the button has no functionality for now. So here's what we're going to do step-by-step:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Declare array of image filenames and append them to the DOM (inside the thumb bar);&lt;/li&gt;
&lt;li&gt;Add a click event handler to each thumbnail image;&lt;/li&gt;
&lt;li&gt;Add a click event handler to the Darken/Lighten button.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1️⃣ Adding the thumbnail images to the DOM
&lt;/h2&gt;

&lt;p&gt;We can do it by first declaring a constant array to hold the image filenames for us. This is a viable alternative because we know the number of images is low and static (five).&lt;/p&gt;

&lt;p&gt;Then it is time to declare an object with an alt description for each image. This step is extra important to improve the accessibility of our app and is often overlooked. I chose to use the filenames as keys, so its easier to retrieve the value we want in the next steps.&lt;/p&gt;

&lt;p&gt;We'll also need to store a reference to the thumb bar div HTML element, so we can append the images to it next. Fortunately this has been provided in the boilerplate code already as the &lt;em&gt;thumbBar&lt;/em&gt; constant.&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="cm"&gt;/** 
  File: "~/main.js"
  Showing: Only code related to step 1
*/&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;thumbBar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.thumb-bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="cm"&gt;/* Declaring the array of image filenames */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imageFilenames&lt;/span&gt; &lt;span class="o"&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;pic1.jpg&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;pic2.jpg&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;pic3.jpg&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;pic4.jpg&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;pic5.jpg&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="cm"&gt;/* Declaring the alternative text for each image file */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;altTexts&lt;/span&gt; &lt;span class="o"&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;pic1.jpg&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;A closeup of an human eye&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;pic2.jpg&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;An abstract pattern painting&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;pic3.jpg&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;A lot of violet and white flowers&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;pic4.jpg&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;An Egyptian painting in a wall&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;pic5.jpg&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;A yellow butterfly in a leaf&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;Next, we'll loop through the array with the forEach method so we can append the images. The image elements will be created inside each iteration of the loop, the needed HTML attributes will be added and finally the element will be appended as a child of the thumb bar container div.&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="cm"&gt;/** 
  File: "~/main.js"
  Showing: Only code related to step 1
*/&lt;/span&gt;

&lt;span class="cm"&gt;/* Looping through images */&lt;/span&gt;
&lt;span class="nx"&gt;imageFilenames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;imageName&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;newImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;img&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;newImage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`images/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;imageName&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="nx"&gt;newImage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;alt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;altTexts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;imageName&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="nx"&gt;thumbBar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newImage&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;With this we've finished the first step. Again, we won't dive into how it was styled. This is how it should like now:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fax84ax7wr83yyxhs8w7t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fax84ax7wr83yyxhs8w7t.png" alt="A GIF showing the project after step one is finished" width="800" height="569"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  2️⃣ Add a click event handler to each thumbnail image
&lt;/h2&gt;

&lt;p&gt;What we want to achieve next is to change the displayed image (the bigger one) whenever the user clicks any of the thumbnail images that we added. In order to achieve that, we will need reference to the displayed image element just like we did for the thumb bar container, but it was also already declared in the boilerplate code.&lt;/p&gt;

&lt;p&gt;Let's create a function to handle the click event on the images. Any function passed as a callback to the &lt;em&gt;addEventListener()&lt;/em&gt; method will automatically pass the event as an argument. The Event object has a &lt;em&gt;target&lt;/em&gt; property that holds a reference to the HTML element that triggered the event. We will use the target element so we can know the new src and alt attributes of the clicked image, and change the attributes of the displayed image to equals the target image.&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="cm"&gt;/** 
  File: "~/main.js"
  Showing: Only code related to step 2
*/&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleImageClick&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;displayedImage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&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;src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nx"&gt;displayedImage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;alt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&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;alt&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;displayedImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.displayed-img&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="cm"&gt;/* Looping through images */&lt;/span&gt;
&lt;span class="nx"&gt;imageFilenames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;imageName&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;newImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;img&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;newImage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`images/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;imageName&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="nx"&gt;newImage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;alt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;altTexts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;imageName&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="nx"&gt;thumbBar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newImage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleImageClick&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;With this we have successfully achieved step 2 and are only missing the last part!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ljxdq8tidk43w9fcelo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ljxdq8tidk43w9fcelo.gif" alt="A GIF showing the project after step2 is completed" width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  3️⃣ Add a click event handler to the Darken/Lighten button
&lt;/h2&gt;

&lt;p&gt;To achieve what we want in the third and last step let's create a function to handle the click event on the button. This function should read the class name value of the button and take one of two actions depending on the result.&lt;/p&gt;

&lt;p&gt;If the class is "dark", it means the user clicked the Darken button. When this happens the text content of the button should change to "Lighten", the overlay div background opacity should change to "0.5" and finally the class name should change to "light" so the action changes when the next click happens.&lt;/p&gt;

&lt;p&gt;Else it means the class is "light". In this case the button text content should change to "Lighten", the overlay div opacity should change to "0" so it becomes invisible again and finally the class name should change to "dark" so the action changes when the next click happens.&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="cm"&gt;/** 
  File: "~/main.js"
  Showing: Only code related to step 3
*/&lt;/span&gt;

&lt;span class="cm"&gt;/* Wiring up the Darken/Lighten button */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleButtonClick&lt;/span&gt;&lt;span class="p"&gt;()&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;currentClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;btn&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;class&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;currentClass&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dark&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;btn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lighten&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;overlay&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;backgroundColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rgba(0,0,0,0.5)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;btn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;class&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;light&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="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;btn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Darken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;overlay&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;backgroundColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rgba(0,0,0,0)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;btn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;class&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;dark&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="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;btn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleButtonClick&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We're done! This is how the button functionality should look like now:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F464ny8kfjetjf4bub9hk.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F464ny8kfjetjf4bub9hk.gif" alt="A gif of the project ready" width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;If you've read this far, I hope the content has added something for you. If it didn't, remember: &lt;em&gt;This is just another ordinary DEV content&lt;/em&gt; 😬.&lt;/p&gt;

&lt;p&gt;🍀 See ya!&lt;/p&gt;
&lt;h3&gt;
  
  
  🔍 References
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Image_gallery#project_brief" rel="noopener noreferrer"&gt;Image gallery - Learn web development | MDN&lt;/a&gt;&lt;br&gt;
&lt;a href="https://mdn.github.io/learning-area/javascript/building-blocks/gallery/" rel="noopener noreferrer"&gt;Image gallery finished example&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/lucashdoa/lucashdoa.github.io/tree/main/mdn-image-gallery" rel="noopener noreferrer"&gt;Github repository with the final code&lt;/a&gt;&lt;br&gt;
&lt;a href="https://lucashdoa.github.io/mdn-image-gallery" rel="noopener noreferrer"&gt;Final app deployed on Github Actions&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  😁 Let's chat!
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/lucashdoa" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.linkedin.com/in/lucashdoa/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag__user ltag__user__id__194592"&gt;
    &lt;a href="/lucashdoa" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F194592%2Fa7274efc-b7db-453b-b2da-6f3f2327c7c4.jpg" alt="lucashdoa image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/lucashdoa"&gt;Lucas Andrade&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/lucashdoa"&gt;I'm a Brazilian QA Engineer. passionate about automation.&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>todayilearned</category>
      <category>beginners</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Selenium 4 Looks Pretty</title>
      <dc:creator>Lucas Andrade</dc:creator>
      <pubDate>Sun, 31 Oct 2021 17:22:05 +0000</pubDate>
      <link>https://forem.com/lucashdoa/selenium-4-looks-pretty-1a83</link>
      <guid>https://forem.com/lucashdoa/selenium-4-looks-pretty-1a83</guid>
      <description>&lt;p&gt;Hello there! 👋&lt;/p&gt;

&lt;p&gt;I'm Lucas, a Brazilian QA engineer, and this is Another QA Content nobody asked for (but i made it anyway 😂). My goal with this blog is to talk about things related to the QA world in my own way, giving my opinion and point of view. If you like it, follow me for more posts like this one!&lt;/p&gt;

&lt;p&gt;Selenium 4 is finally officially released! And I've been playing with some of the new features. In this post, I'll show you in practice some cool new things you can do with Selenium now.&lt;/p&gt;

&lt;p&gt;I won't be focusing on good practices, like using hooks or not setting long explicit waits. The main goal here is to test out some new stuff. I'll show code snippets to summarize, but you can find a link to the Github repo at the end of this post if you want to check out the full code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3j43il2mpmogoxsa9t8e.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3j43il2mpmogoxsa9t8e.gif" alt="lets get to work" width="480" height="400"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  😃 Relative Locators are here
&lt;/h2&gt;

&lt;p&gt;Remember &lt;a href="https://dev.to/lucashdoa/interacting-with-a-web-page-without-inspecting-it-using-taiko-2597"&gt;Taiko's Proximity Selectors&lt;/a&gt;? Selenium now has its own similar feature called Relative Locators. It works similarly, you can find web elements that are &lt;em&gt;above&lt;/em&gt;, &lt;em&gt;below&lt;/em&gt;, &lt;em&gt;toRightOf&lt;/em&gt;, &lt;em&gt;toLeftOF&lt;/em&gt; or even &lt;em&gt;near&lt;/em&gt; a fixed reference element.&lt;/p&gt;

&lt;p&gt;And it's simple to use. All you have to do is import the &lt;em&gt;with&lt;/em&gt; class. Use &lt;em&gt;with&lt;/em&gt; to encapsulate the &lt;em&gt;By&lt;/em&gt; object and then, you'll be able to chain a relative selector.&lt;/p&gt;

&lt;p&gt;For this example, we'll be using &lt;a href="https://blazedemo.com/" rel="noopener noreferrer"&gt;BlazeDemo&lt;/a&gt; (a sample travel agency website). Let's try to perform a simple click at the button "Find Flights" without creating a specific &lt;em&gt;selector/xpath&lt;/em&gt; for it.&lt;/p&gt;

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

&lt;p&gt;To achieve our goal, let's use the destination city &lt;em&gt;select&lt;/em&gt; as reference. Inspecting it, we can see that one option to retrieve it is by its "name" &lt;em&gt;attribute&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Let's implement a simple test then. We'll select "Dublin" as the destination city and then assert that the available flights page title is displayed correctly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
* File: AppTest.java
*/&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;relativeSelector&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="c1"&gt;// 1. Configuration steps;&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;expectedTitle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Flights from Paris to Dublin:"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"webdriver.chrome.driver"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"c:/chromedriver.exe"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;WebDriver&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ChromeDriver&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;window&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;maximize&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://blazedemo.com/"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// 2. Retrieve the select "Destination city" and select option 'Dublin';&lt;/span&gt;
        &lt;span class="nc"&gt;WebElement&lt;/span&gt; &lt;span class="n"&gt;toDestination&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cssSelector&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[name='toPort']"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="nc"&gt;Select&lt;/span&gt; &lt;span class="n"&gt;selectElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Select&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;toDestination&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;selectElement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;selectByVisibleText&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Dublin"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// 3. Use Relative Locator 'below' to retrieve the "Find Flights" button;&lt;/span&gt;
        &lt;span class="nc"&gt;WebElement&lt;/span&gt; &lt;span class="n"&gt;findFlightsButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tagName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"input"&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;below&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;toDestination&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;findFlightsButton&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;click&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="c1"&gt;// 4. Assert that the button was clicked by validating page title.&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;actualTitle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tagName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"h3"&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;getText&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;Assertions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expectedTitle&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actualTitle&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;quit&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I've added a sleep to the code snippet above so that we can see the test in action!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxol9z1de8qij1gjc7pf7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxol9z1de8qij1gjc7pf7.gif" alt="test 1 running" width="1897" height="952"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is useful when you don't have access to the source code (to add an &lt;em&gt;'id'&lt;/em&gt; or &lt;em&gt;'test-id'&lt;/em&gt; in the HTML) and want to avoid writing a complex &lt;em&gt;xpath&lt;/em&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  🤯 Support for Chrome DevTools Protocol
&lt;/h2&gt;

&lt;p&gt;The Chrome DevTools Protocol (CDP) is a protocol to communicate with Chromium-based browser internal configurations. Tools can build an API around it to allow a low-level browser configuration (e.g. instrument, inspect, debug and profile). If you're interested in learning more about what you can do with it, visit &lt;a href="https://chromedevtools.github.io/devtools-protocol/" rel="noopener noreferrer"&gt;CDP Github.io page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Selenium 4 brings its own API to communicate with CDP. Now its possible to do a lot of advanced browser configurations for your tests, like changing the client's geolocation for example.&lt;/p&gt;

&lt;p&gt;We can implement a sample test for the above situation using the page &lt;a href="https://www.gps-coordinates.net/my-location" rel="noopener noreferrer"&gt;gps-coordinates/my-location&lt;/a&gt;. It has a feature that show user's location coordinates and address based on the geolocation. We'll implement a test that simply asserts that the location shown is the location we set. See an example below:&lt;/p&gt;

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

&lt;p&gt;Since I need some vacation, let's teleport ourselves to Cancún/Mexico using code! I've already googled the latitude and longitude values for us, so let's jump to the part where i show you the code:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
* File: AppTest.java
*/&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;setGeolocation&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nf"&gt;InterruptedException&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="c1"&gt;// 1. Configuration Steps&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;expectedAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Calle 50 Poniente, 77510 Cancun, ROO, Mexico"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"webdriver.chrome.driver"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"c:/chromedriver.exe"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;WebDriver&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ChromeDriver&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;window&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;maximize&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="c1"&gt;// 2. Create map with arguments for "Emulate.setGeolocationOverride"&lt;/span&gt;
        &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;coordinatesMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;();&lt;/span&gt;
        &lt;span class="n"&gt;coordinatesMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"latitude"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;21.17429&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;coordinatesMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"longitude"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;86.84656&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;coordinatesMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"accuracy"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// 3. Calls CDP's "Emulation.setGeolocationOverride" to set new geolocation&lt;/span&gt;
        &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;ChromeDriver&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;executeCdpCommand&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Emulation.setGeolocationOverride"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;coordinatesMap&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://www.gps-coordinates.net/my-location"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// 4. Asserts that the Address shown is Cancún/Mexico&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;actualAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"addr"&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;getText&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;Assertions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expectedAddress&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actualAddress&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;quit&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;


&lt;p&gt;And it's time to see our second test running!&lt;/p&gt;

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

&lt;p&gt;We've just teleported! Of course, you'll have to believe that i'm not writing this from Cancún 😂. But you'll have to agree with me, this new feature (calling CDP commands) is really powerful. This geolocation change allow us to test features like "Find the nearest store" for example.&lt;/p&gt;

&lt;p&gt;This is it for today. Have you learned some other new stuff on Selenium 4 already? Share with me in the comments!&lt;/p&gt;

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



&lt;p&gt;If you've read this far, I hope the content has added something for you. If it didn't, remember: This is just another ordinary QA content 😬.&lt;/p&gt;

&lt;p&gt;🍀 See ya!&lt;/p&gt;
&lt;h3&gt;
  
  
  👩‍💻 Full Code
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/lucashdoa/selenium4-demo" rel="noopener noreferrer"&gt;lucashdoa/selenium4-demo&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  🔍 References
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://chromedevtools.github.io/devtools-protocol/" rel="noopener noreferrer"&gt;Chrome DevTools Protocol docs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=czp7mxGHL88&amp;amp;t=1051s" rel="noopener noreferrer"&gt;Naveem AutomationLabs YouTube Channel - Mock Geo Location using ChromeDevTools&lt;/a&gt;&lt;br&gt;
&lt;a href="https://angiejones.tech/selenium-4-mocking-geolocation/" rel="noopener noreferrer"&gt;Angie Jones's blog - Mocking Geolocation&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.selenium.dev/documentation/webdriver/locating_elements/" rel="noopener noreferrer"&gt;Selenium docs - Locating elements&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  😁 Let's chat!
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/lucashdoa" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.linkedin.com/in/lucashdoa/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag__user ltag__user__id__194592"&gt;
    &lt;a href="/lucashdoa" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F194592%2Fa7274efc-b7db-453b-b2da-6f3f2327c7c4.jpg" alt="lucashdoa image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/lucashdoa"&gt;Lucas Andrade&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/lucashdoa"&gt;I'm a Brazilian QA Engineer. passionate about automation.&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>todayilearned</category>
      <category>java</category>
      <category>selenium</category>
      <category>testing</category>
    </item>
    <item>
      <title>Grey Box Testing</title>
      <dc:creator>Lucas Andrade</dc:creator>
      <pubDate>Sat, 23 Oct 2021 03:06:11 +0000</pubDate>
      <link>https://forem.com/lucashdoa/grey-box-testing-41h1</link>
      <guid>https://forem.com/lucashdoa/grey-box-testing-41h1</guid>
      <description>&lt;p&gt;Hello there! 👋&lt;/p&gt;

&lt;p&gt;I'm Lucas, a Brazilian QA engineer, and this is Another QA Content nobody asked for (but i made it anyway 😂). My goal with this blog is to talk about things related to the QA world in my own way, giving my opinion and point of view. If you like it, follow me for more posts like this one!&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;CTFL syllabus (2018)&lt;/em&gt; covers White-box and Black-box testing, but it doesn't mention a single word about Grey-box testing. Nor the book &lt;em&gt;The art of software testing (3rd edition)&lt;/em&gt;. What is it? Is it really not worth the mention? Let's find out.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧩A brief about Black-box and White-box testing techniques
&lt;/h2&gt;

&lt;p&gt;To understand what Grey-box testing is, we first must know what Black-box and White-box testing are.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;⬛ Black-box testing (a.k.a. Closed-box testing) is a set of techniques in which the tester test a software's functionality without the need to know how it has been built. In other words, the tester checks whether determined inputs will produce desired outputs. Some examples of Black-box techniques are: Equivalence Partitioning, Boundary Value and Cause-Effect Graph.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;⬜ White-box testing (a.k.a. Open-box testing) at the other hand, is a technique in which internal structure of the software is known by the tester. This way he can verify the code flow (conditionals, loops, etc.), security holes and other things. Some examples of White-box techniques are: Statement Coverage and Decision Coverage.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  👩‍🏫 The definition of Grey-box testing can be confuse
&lt;/h2&gt;

&lt;p&gt;Ok, now its easier to define what Grey-box testing is! If you access any page listed at the references section you'll find this definition: Grey-box testing is a technique in which the tester has &lt;strong&gt;PARTIAL&lt;/strong&gt; knowledge of the source code. It's like it fits somewhere in the middle of White-box and Black-box testing, or even a sum of the two previous. Some example of Grey-box testing techniques are: Matrix Testing, Orthonogal Array Testing and Pattern Testing.&lt;/p&gt;

&lt;p&gt;Have you seen the problem yet? I'll tell you: How much knowledge is considered partial?&lt;/p&gt;

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

&lt;p&gt;Let's consider some options for answering the question above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have access to just a part of the code;&lt;/li&gt;
&lt;li&gt;You have access to the code, but you can't understand it fully.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How would you define Grey-box testing then?&lt;/p&gt;

&lt;h2&gt;
  
  
  😯 How much dev knowledge should i have as QA
&lt;/h2&gt;

&lt;p&gt;Let's say you, as a QA engineer, are testing a web application and you have access to the source code. Hence, you're able to apply White-box testing techniques, right? Not exactly.&lt;/p&gt;

&lt;p&gt;As a QA, you're not expected to deeply know the programming languages and frameworks used to build the application (or at least you shouldn't). This is a job for your fellow comrades developers. Therefore, White-box testing techniques seems to be a lot more useful for designing unit/component tests.&lt;/p&gt;

&lt;p&gt;Of course, that doesn't mean a QA can't have some front-end or back-end development knowledge and apply White-box techniques to help the team to improve testing coverage. But knowing how conditionals and loops work may not be sufficient in some cases. That's why the most common scenario is: Devs design and automate unit/integration tests and QAs design and automate end-to-end/API tests (there are more tests a QA can perform but more of that in later posts).&lt;/p&gt;

&lt;p&gt;And Black-box testing techniques consists mostly on detecting the best test data (inputs) for minimizing the amount of tests cases needed. It seems like a perfect fit for QAs, right? And it is! No wonder it's a high demanded skill when applying for a QA role.&lt;/p&gt;

&lt;h2&gt;
  
  
  💭 What i concluded about Grey-box testing
&lt;/h2&gt;

&lt;p&gt;After doing some research, i've found out that Grey-box testing techniques are much like Black-box testing techniques and are best suited for QAs in general. But the tests are performed by a QA that has some knowledge of how applications are made.&lt;/p&gt;

&lt;p&gt;Consider the following example from Thomas Hamilton at &lt;em&gt;Guru99's&lt;/em&gt; Grey-Box testing page (You can find the whole article at the references section):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;While testing websites feature like links or orphan links, if tester encounters any problem with these links, then he can make the changes straightaway in HTML code and can check in real time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In another words. If a tester is accustumed to perform Black-box testing, he would just open a bug for developers to fix saying that the link is broken. In this case, a QA applying a Grey-box technique could open the browser devtools and check the HTML structure to see if the href attribute is set correctly on the anchor tag, providing a more detailed bug report.&lt;/p&gt;

&lt;p&gt;The same can happen for example if some requisiton fails with a 4xx or 5xx status. Opening devtools network tab and observing things like the requisiton header or response can lead to a detail-rich bug report, helping developers to debug the problem easily.&lt;/p&gt;

&lt;p&gt;There's even a Grey-box technique in which the variables of the software are examined and assessed according to the risks it presents (Matrix Testing).&lt;/p&gt;

&lt;p&gt;And just for the mention, it's possible to implement Grey-box testing as a form of penetration testing (Pentest) too.&lt;/p&gt;

&lt;p&gt;My conclusion is that combining Black-box and Grey-box testing techniques is the way to go for modern software testers/QA engineers. It has some cool benefits like making your teammates appreciate working with you 😉.&lt;/p&gt;

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

&lt;p&gt;How about you? Do you have a different point of view? Share with me in the comments.&lt;/p&gt;




&lt;p&gt;If you've read this far, i hope the content has added something for you. If it didn't, remember: This is just another ordinary QA content 😬.&lt;/p&gt;

&lt;p&gt;🍀 See ya!&lt;/p&gt;

&lt;h3&gt;
  
  
  🔍 References
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.istqb.org/downloads/category/2-foundation-level-documents.html" rel="noopener noreferrer"&gt;CTFL Syllabus 2018&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.guru99.com/grey-box-testing.html" rel="noopener noreferrer"&gt;Thomas Hamilton at Guru99&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.imperva.com/learn/application-security/gray-box-testing/" rel="noopener noreferrer"&gt;Imperva&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.softwaretestinghelp.com/grey-box-testing-tutorial/" rel="noopener noreferrer"&gt;Software Testing Help&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  😁 Let's chat!
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/lucashdoa" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.linkedin.com/in/lucashdoa/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;&lt;/p&gt;

</description>
      <category>qa</category>
      <category>testing</category>
      <category>test</category>
      <category>sdet</category>
    </item>
    <item>
      <title>The 7 Software Testing Principles</title>
      <dc:creator>Lucas Andrade</dc:creator>
      <pubDate>Sun, 10 Oct 2021 21:19:41 +0000</pubDate>
      <link>https://forem.com/lucashdoa/the-7-software-testing-principles-hlc</link>
      <guid>https://forem.com/lucashdoa/the-7-software-testing-principles-hlc</guid>
      <description>&lt;p&gt;Hello there! 👋 &lt;/p&gt;

&lt;p&gt;I'm Lucas, a Brazilian QA engineer, and this is Another QA Content nobody asked for (but i made it anyway 😂). My goal with this blog is to talk about things related to the QA world in my own way, giving my opinion and point of view. If you like it, follow me for more posts like this one!&lt;/p&gt;

&lt;p&gt;Today i want to talk about a subject that is covered at the first chapter of the CTFL syllabus. The seven &lt;del&gt;commandments&lt;/del&gt; principles of software testing. (This was a Moses pun if you didn't get it). No more puns &lt;del&gt;for now&lt;/del&gt;, let's open this ocean of knowlegde!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0adzng72s3gcnca7vkrh.gif" alt="Alt Text" width="360" height="240"&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  1️⃣ Testing shows the presence of defects, not their absence
&lt;/h2&gt;

&lt;p&gt;Many QA engineers may have been in a situation like the following before: The product owner or even the client says your job is to guarantee the sprint deliverable is bug free.&lt;/p&gt;

&lt;p&gt;Testing is a destructive activity, it's goal is to make the software fail. When a tester write a test case, it is meant to find a bug, not to prove there is none.&lt;/p&gt;

&lt;p&gt;So, this principle states that it's impossible to guarantee that a testing object is defect free.&lt;/p&gt;

&lt;p&gt;Some points to be aware: Maybe a non-QA person will misunderstood this principle as an excuse for a QA that isn't good at his job. And on the other hand, it can be misused by a QA to justify not catching a bug that should have been found easily. I personally think this principle isn't meant to justify a bug that has got into production, i think it's meant to avoid creating false expectation on the product and the QA job.&lt;/p&gt;

&lt;h2&gt;
  
  
  2️⃣ Exhaustive testing is impossible
&lt;/h2&gt;

&lt;p&gt;As a QA, you will probably never have the time to test every possible scenario of a software. &lt;/p&gt;

&lt;p&gt;Imagine a small form with 3 select fields, every field has 10 options. To test every possible scenario, it would take you 10³ = 1000 test cases.&lt;/p&gt;

&lt;p&gt;We can use a black box testing technique called equivalent partitioning. Briefly explaining, it consists of dividing test data into partitions in such a way that all the members of a given partition are expected to be processed in the same way.&lt;/p&gt;

&lt;p&gt;There can even be a situation in wich time is a concern. In this case it's more recomended to perform a risk analysis, and prioritize tests based on the higher risks for the business.&lt;/p&gt;

&lt;h2&gt;
  
  
  3️⃣ Early testing saves time and money
&lt;/h2&gt;

&lt;p&gt;This principle is probably the parent of the trending shift-left testing approach. It states that the testing activities should start as soon as possible in a project.&lt;/p&gt;

&lt;p&gt;Testing activities are not limited to execute or automate E2E tests when a feature is ready. A tester can also review documentation and requisits, to prevent errors and mistakes from advancing to later stages of the software development life cycle. Remember, the later you find a problem, the more it will cost to fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  4️⃣ Defects cluster together
&lt;/h2&gt;

&lt;p&gt;This principle is an application of the Pareto Principle. Maybe you don't know it by its name, but you might have heard about it somewhere. Here is a brief about it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For many outcomes, roughly 80% of consequences come from 20% of causes&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In software testing, there's a high probability that 80% of the problems can be found at 20% of the modules/components. So be aware when you find a bug, for there can be more, hiding on the same feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  5️⃣ Beware of the pesticide paradox
&lt;/h2&gt;

&lt;p&gt;To explain this one i'll borrow a paragraph from a Guru99 article about the 7 principles of testing (you can find the link bellow in the references section).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Repetitive use of the same pesticide mix to eradicate insects during farming will over time lead to the insects developing resistance to the pesticide.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, if you repeat the same test case again and again, chances are it will become less effective (consider an effective test case one that has a higher probability of finding bugs). Because of that, as a QA you need to review your testing techniques and test cases frequently. In an Agile project where requisits change very often, this is even more crucial.&lt;/p&gt;

&lt;h2&gt;
  
  
  6️⃣ Testing is context dependent
&lt;/h2&gt;

&lt;p&gt;This principle talks about how different contexts may influence the test in different ways.&lt;/p&gt;

&lt;p&gt;Testing in an agile project is done differently than it's done in waterfall, due to the differences in release periodicity.&lt;/p&gt;

&lt;p&gt;Testing an e-commerce is done differently than testing an internet banking system, due to the different risks involved.&lt;/p&gt;

&lt;p&gt;The correct tool for automating regression tests depends heavily on the context too. As you get more experienced, the more you get to understand the context you're incerted, and plan your QA job to fit it well.&lt;/p&gt;

&lt;h2&gt;
  
  
  7️⃣ Absence-of-errors is a falacy
&lt;/h2&gt;

&lt;p&gt;Like we have seen in principle number 2, testing shows the presence of defects and not their absence. What this principle states is that no matter how much effort you or your team put on testing activities, the tests alone can never guarantee an error-free software.&lt;/p&gt;

&lt;p&gt;A software isn't considered to have an error only when something doesn't work as expected. A system that is overcomplicated for the user (bad usability) or doesn't fullfil the user needs (bad modeling) is also considered to have errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  💰Bonus
&lt;/h2&gt;

&lt;p&gt;To test your understanding of the seven testing principles presented above, try to solve this question from the CTFL 2018 sample exam:&lt;/p&gt;

&lt;p&gt;🤔&lt;b&gt;(Sample Exam C, Question 4)&lt;/b&gt;: A product owner says that your role as a tester on an Agile team is to catch all the bugs before the end of each iteration. Which of the following is a testing principle that could be used to respond to this (false) statement?&lt;/p&gt;

&lt;p&gt;a) Defect clustering&lt;br&gt;
b) Testing shows the presence of defects&lt;br&gt;
c) Absence of error fallacy&lt;br&gt;
d) Root cause analysis&lt;/p&gt;

&lt;p&gt;The answer is below.&lt;/p&gt;




&lt;p&gt;If you've read this far, i hope the content has added something for you. If it didn't, remember: &lt;em&gt;This is just another ordinary QA content&lt;/em&gt; 😬.&lt;/p&gt;

&lt;p&gt;🍀 See ya!&lt;/p&gt;

&lt;h3&gt;
  
  
  ❗ Bonus question answer
&lt;/h3&gt;

&lt;p&gt;&lt;b&gt;b&lt;/b&gt; is correct. Testing can show the presence of defects but cannot prove their absence, which makes it impossible to know if you have caught all the bugs. Further, the impossibility of exhaustive testing makes it impossible for you to catch all the bugs&lt;/p&gt;

&lt;h3&gt;
  
  
  🔍 References
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.istqb.org/downloads/category/2-foundation-level-documents.html" rel="noopener noreferrer"&gt;CTFL Syllabus 2018&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.guru99.com/software-testing-seven-principles.html" rel="noopener noreferrer"&gt;Guru99&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.geeksforgeeks.org/software-engineering-seven-principles-of-software-testing/" rel="noopener noreferrer"&gt;Geek for Geeks&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  😁 Let's chat!
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/lucashdoa" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.linkedin.com/in/lucashdoa/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ctfl</category>
      <category>testing</category>
      <category>qa</category>
      <category>test</category>
    </item>
    <item>
      <title>Taiko's Proximity Selectors</title>
      <dc:creator>Lucas Andrade</dc:creator>
      <pubDate>Sat, 22 May 2021 00:50:44 +0000</pubDate>
      <link>https://forem.com/lucashdoa/interacting-with-a-web-page-without-inspecting-it-using-taiko-2597</link>
      <guid>https://forem.com/lucashdoa/interacting-with-a-web-page-without-inspecting-it-using-taiko-2597</guid>
      <description>&lt;p&gt;Hello there! 👋&lt;/p&gt;

&lt;p&gt;I'm Lucas, a Brazilian QA engineer, and this is Another QA Content nobody asked for (but i made it anyway 😂). My goal with this blog is to talk about things related to the QA world in my own way, giving my opinion and point of view. If you like it, follow me for more posts like this one!&lt;/p&gt;

&lt;p&gt;Recently i've worked on a User Interface (UI) testing project, where me and my team were using Node.js, Gauge and Taiko as tools for automation. Before i've been a part of this team, i knew some JavaScript test frameworks and libraries, but i had never heard of Taiko. This can be your case, so in this article i'll show you the basic concepts of Taiko and how it can be a great choice for your next automated UI tests project.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔨Installing Taiko
&lt;/h2&gt;

&lt;p&gt;Taiko is a node module developed by ThoughtWorks. It allows us to interact with Chrome and Chromium browsers using proximity selectors to easilly find web elements on a page.&lt;/p&gt;

&lt;p&gt;The simplest way to try out Taiko is using its Read-eval-print-loop (REPL). For that you will need to have Node.js installed on your machine. Open your favorite terminal emulator and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; taiko
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'll not dive deeply into how to set up a full automation project in this post. So, if this is what you're looking for, i recomend you read about &lt;a href="https://gauge.org/" rel="noopener noreferrer"&gt;Gauge&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If the installation was a success, the REPL shall open when you type "taiko" in your terminal. Like shown below:&lt;/p&gt;

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




&lt;h2&gt;
  
  
  👉Using a proximity selector
&lt;/h2&gt;

&lt;p&gt;To demonstrate how easy it is to interact with web elements on a page using Taiko's proximity selectors, i'll be using the Automation Practice e-commerce. You can navigate to the page by running the following commands (I'll explain each one later):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;taiko
openBrowser&lt;span class="o"&gt;()&lt;/span&gt;
goto&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"http://automationpractice.com"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the home page, we can see a situation where Taiko can show its potential. In this case, the page contains two products with exactly the same name.&lt;/p&gt;

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

&lt;p&gt;Using the proximity selectors, it's not necessary to inspect the page looking for a unique identifier for the product you want to perform a click on. In other words, you ain't gonna need a CSS selector or an XPath here.&lt;/p&gt;

&lt;p&gt;Let's supose you want to click at the second "Printed Dress" product, the one whose price is "$50.99". In this case you can tell Taiko to click at the "Printed Dress" that is localized above the "$50.99" text. Like shown in the image below:&lt;/p&gt;

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

&lt;p&gt;Explaining in details what happened:&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="c1"&gt;//Open Taiko's REPL;&lt;/span&gt;
&lt;span class="nx"&gt;taiko&lt;/span&gt;
&lt;span class="c1"&gt;// Open the automation controlled Browser, Chromium by default;&lt;/span&gt;
&lt;span class="nf"&gt;openBrowser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
&lt;span class="c1"&gt;// Navigates to the URL passed as a parameter;&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://automationpractice.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="cm"&gt;/*
Perform a click action. Receive two arguments:
    1st: The element you want to click. 
    Could be a "link" or an "image" for example. 
    If not informed, the default is "text";
    2nd: A proximity selector to help Taiko finding the 
    element. 
    We want the text element that is above another text element 
    "$59.99".
*/&lt;/span&gt;
&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Printed Dress&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;above&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$50.99&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;Cool right? Taiko currently have these other proximity selectors besides above: below, toLeftOf, toRightOf, near and within. &lt;/p&gt;

&lt;p&gt;Of course there is no such thing as an "ultimate automation tool", maybe they won't help you in a more complex situation. But worry not, cause Taiko's API also have methods for locating elements using the old fashion like using the element html attribute "id". You can even combine the two of them! For more on that, refer to &lt;a href="https://docs.taiko.dev/" rel="noopener noreferrer"&gt;Taiko's Documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Besides that team i've worked on, to this day i still haven't found another QA Engineers or Developers that use Taiko to automate tests at their jobs. Maybe you can be next after reading this post.&lt;/p&gt;




&lt;p&gt;If you've read this far, i hope the content has added something for you. If it didn't, remember: &lt;em&gt;This is just another ordinary QA content&lt;/em&gt; 😬.&lt;/p&gt;

&lt;p&gt;🍀 See ya!&lt;/p&gt;

&lt;h3&gt;
  
  
  🤝 Thanks
&lt;/h3&gt;

&lt;p&gt;Thanks to my fellow teammates at everis for all the knowledge we shared during those months working together&lt;br&gt;
Samuca, Ronaldo, Andrei, Felipe and Duda.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔍 References
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://taiko.dev/" rel="noopener noreferrer"&gt;Taiko's Webpage&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/getgauge/taiko" rel="noopener noreferrer"&gt;Taiko's Github Repository&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  😁 Let's chat!
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/lucashdoa" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.linkedin.com/in/lucashdoa/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>javascript</category>
      <category>test</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
