<?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: Gokul Kathirvel</title>
    <description>The latest articles on DEV Community by Gokul Kathirvel (@gokatz).</description>
    <link>https://dev.to/gokatz</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%2F6843%2F15158776.png</url>
      <title>DEV Community: Gokul Kathirvel</title>
      <link>https://dev.to/gokatz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gokatz"/>
    <language>en</language>
    <item>
      <title>My Intro to Chrome Extension Development - A Series</title>
      <dc:creator>Gokul Kathirvel</dc:creator>
      <pubDate>Tue, 10 Aug 2021 03:39:50 +0000</pubDate>
      <link>https://dev.to/gokatz/my-intro-to-chrome-extension-development-46lg</link>
      <guid>https://dev.to/gokatz/my-intro-to-chrome-extension-development-46lg</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://gokatz.me/blog/chrome-extension-intro-part-1/"&gt;gokatz.me&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Building a chrome extension is definitely a fun process! Chrome extensions open a whole new set of doors to the web developers and users as well.&lt;/p&gt;

&lt;p&gt;That is the reason I'm planning this to be a series of blogs explaining in-depth about the chrome extension ecosystem and the development, testing, and deployment process. This is the first part which explains what are chrome extensions and a brief about other browser ecosystems.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Chrome Extensions?
&lt;/h2&gt;

&lt;p&gt;As per the official &lt;a href="https://developer.chrome.com/docs/extensions/"&gt;chrome extension development guide&lt;/a&gt;, the definition for a chrome extension would be:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Extensions are software programs, built on web technologies (such as HTML, CSS, and JavaScript) that enable users to customize the Chrome browsing experience.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This definition is self-explanatory, right? However, I would put it in a slightly different way:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Extensions are used to &lt;strong&gt;enhance the browsing experience&lt;/strong&gt; using the customization feature enabled by the browsers via various APIs&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;These customization ranges from changing a content, &lt;a href="https://chrome.google.com/webstore/detail/dark-mode/dmghijelimhndkbmpgbldicpogfkceaj?hl=en"&gt;look and feel&lt;/a&gt; inside a webpage, &lt;a href="https://chrome.google.com/webstore/detail/grammarly-for-chrome/kbfnbcaeplbcioakkpcpgfkobkghlhen?hl=en"&gt;injecting a widget&lt;/a&gt; into the page and all the way to &lt;a href="https://chrome.google.com/webstore/detail/allow-cors-access-control/lhobafahddgcelffkeicbaginigeejlf?hl=en"&gt;intercept the network request&lt;/a&gt; and change its behavior and content. The possibility is &lt;strong&gt;limitless&lt;/strong&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  A little history
&lt;/h2&gt;

&lt;p&gt;The extension architecture we are using today is a modern take by the web browser vendors to extend the browse functionality. Before the current extension architecture, we had plugin architecture using API surfaces like &lt;a href="https://en.wikipedia.org/wiki/NPAPI"&gt;NPAPI&lt;/a&gt;, etc., You might have heard about the recently &lt;a href="https://www.adobe.com/in/products/flashplayer/end-of-life.html"&gt;depreacted Adobe flash plugiun&lt;/a&gt; for the browsers. This is a classic example of plugin software.&lt;/p&gt;

&lt;p&gt;Due to various limitations and issues such as security (No Sandboxing), stability, etc. browser vendors decided to deprecate the plugin ecosystem and come up with the now existing, browser extension architecture built using the existing web technologies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is it worth our time?
&lt;/h2&gt;

&lt;p&gt;We might have heard about/used extensions that are fun to use and concise in functionality. However, the possibility is not so concise and companies around the globe are making use of this technology to improve the product experience and drive a lot more customers towards their brand/site. For instance, for a business like password managers/vault-like, &lt;a href="https://www.zoho.com/vault"&gt;Zoho Vault&lt;/a&gt; (I worked here 😉), &lt;a href="https://www.lastpass.com/"&gt;LastKeep&lt;/a&gt;, etc., browser extensions are not an optional one. They had to have an extension to work seamlessly and it drives a major part of the user experience and of course, in turn, revenue. &lt;/p&gt;

&lt;p&gt;Hence, depending upon our use case/business model, the knowledge about chrome extensions and it's development might be crucial and of course, there is always fun tweaking the browser behavior, right? 😉&lt;/p&gt;

&lt;h2&gt;
  
  
  How to build one?
&lt;/h2&gt;

&lt;p&gt;We've seen a brief intro about the extension and its ecosystem. Let's dive into the actual chrome extension development process. The chrome extension development history has seen a lot of phases and the process we are following today is a result of the refinement of those phases. In the modern era, we can develop a chrome extension by using the web technologies we are familiar with, &lt;strong&gt;HTML, CSS, and JavaScript&lt;/strong&gt; with the help of a &lt;strong&gt;bunch of browser APIs&lt;/strong&gt; exposed by Chrome to access the internals of the browser itself. These APIs are the ones that help us to build the enhanced experience.&lt;/p&gt;

&lt;p&gt;A-lot-simplified architecture would be something like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--S92-eSY---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/075icm88vl8if8enyk2z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S92-eSY---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/075icm88vl8if8enyk2z.png" alt="Untitled-2021-08-24-0923"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Standard
&lt;/h2&gt;

&lt;p&gt;The development story of the extension had been coupled to individual browser vendors. Each vendor devised their own way to develop and package an extension for their browser software. This causes a lot of roadblocks for developers to build their extensions across multiple browser vendors. To solve this and to make the development process close to today's web developers, initially, Mozilla joined hands with Microsoft and Opera to come up with the initial draft. The spec closely resembles the APIs devised by Chrome for their extensions.&lt;/p&gt;

&lt;p&gt;Unfortunately, lately, the spec has had no traction and dormant for some time. Let's hope the work will be resumed in near future in this space 🤞&lt;/p&gt;

&lt;p&gt;The spec draft can be found here: &lt;a href="https://browserext.github.io/browserext/"&gt;https://browserext.github.io/browserext/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Just Chrome?
&lt;/h2&gt;

&lt;p&gt;As we can see, browser vendors are more keen to unify the extension development process so that the extension will work cross-browser. Then, it will be a natural question, then why should we just learn about Chrome extension and not a genetic development process.&lt;/p&gt;

&lt;p&gt;The main reason is that the web extension spec has still a long way to rely on and they are heavily inspired by Chrome's API. So, &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we are gonna focus on building chrome extension as the skills are transferable to any browser vendors&lt;/li&gt;
&lt;li&gt;We are gonna learn how to port a chrome extension into other browsers at the end of this series as well.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, stay tuned. We gonna explore a lot about chrome extensions and the relevant ecosystem. Until then, see you all 👋👋&lt;/p&gt;

</description>
      <category>chrome</category>
      <category>extension</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Grammarly won't work in dev.to?</title>
      <dc:creator>Gokul Kathirvel</dc:creator>
      <pubDate>Tue, 10 Aug 2021 03:35:12 +0000</pubDate>
      <link>https://dev.to/gokatz/grammarly-won-t-work-in-dev-to-1p3j</link>
      <guid>https://dev.to/gokatz/grammarly-won-t-work-in-dev-to-1p3j</guid>
      <description>&lt;p&gt;I noticed that grammarly is enabled for the editor in dev.to? I'm not sure if this was intentional or any issue with my browser. Anyone facing this? &lt;/p&gt;

&lt;p&gt;I'm using latest Firefox.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>editor</category>
      <category>devto</category>
    </item>
    <item>
      <title>I'm back on track and you should too!</title>
      <dc:creator>Gokul Kathirvel</dc:creator>
      <pubDate>Sun, 25 Jul 2021 07:13:47 +0000</pubDate>
      <link>https://dev.to/gokatz/i-m-back-on-track-and-you-should-too-49ma</link>
      <guid>https://dev.to/gokatz/i-m-back-on-track-and-you-should-too-49ma</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QhWt8BkW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gdeoigj8avhmx6w60o45.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QhWt8BkW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gdeoigj8avhmx6w60o45.jpg" alt="braden-collum-9HI8UJMSdZA-unsplash"&gt;&lt;/a&gt; &lt;em&gt;&lt;center&gt; &lt;small&gt; [Image from From &lt;a href="https://unsplash.com/photos/9HI8UJMSdZA"&gt;unsplash.com&lt;/a&gt;] &lt;/small&gt; &lt;/center&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hello again 👋&lt;/p&gt;

&lt;p&gt;Hope you are doing safe and healthy. This pandemic has sure made a huge not-so-good effect on all of us. Let's hope that fades away 🙏&lt;/p&gt;

&lt;p&gt;Now, to the matter! It has been more than two years since I blogged on this site. That's the longest break I have ever taken since I started writing. Besides that, my time on pet projects was also reduced considerably. I always had some excuse to skip writing, like, &lt;strong&gt;I don't have time, there is a deadline coming up, I don't have any ideas to share, the idea I'm having is not worth sharing&lt;/strong&gt;, so on among others. Honestly, I prioritize other things over writing (Maybe, I'm lazy!  😅)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/h8ZRVXhlb39ZSNKlGv/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/h8ZRVXhlb39ZSNKlGv/giphy.gif" alt="Drag Racing"&gt;&lt;/a&gt; &lt;em&gt;&lt;center&gt; &lt;small&gt; [Image from From giphy.com] &lt;/small&gt; &lt;/center&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When I look back on my two years of "not writing" I can see that there was sufficient space for more innovation on my path as writing was one of the major drives that &lt;strong&gt;pushes me to innovate and upgrade myself&lt;/strong&gt;. Also, writing helped me to &lt;strong&gt;refine my ideas a lot in the past, clears my mind, and improves my concentration&lt;/strong&gt;. I'm missing that "me" time!&lt;/p&gt;

&lt;p&gt;Now, I understand that this is the apt time to resume my blogging habit. I'm gonna set a realistic interval to publish a blog - which I have to decide soon! I'll keep this space updated on the same. If you are also like me, halted your blogging habit, perhaps you can resume too at the earliest. The longest the break, the hardest it will be to resume back! (from my experience 😉)&lt;/p&gt;

&lt;p&gt;See you all in my next blog 👋&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Is there any direct alternative to Docsify to use React component instead of Vue?</title>
      <dc:creator>Gokul Kathirvel</dc:creator>
      <pubDate>Thu, 10 Dec 2020 03:52:57 +0000</pubDate>
      <link>https://dev.to/gokatz/is-there-any-direct-alternative-to-docsify-to-use-react-component-instead-of-vue-2jpg</link>
      <guid>https://dev.to/gokatz/is-there-any-direct-alternative-to-docsify-to-use-react-component-instead-of-vue-2jpg</guid>
      <description>&lt;p&gt;I'm using Docsify to document a web component library. For that I need to render those UI components, pass data, attach events etc., For this purpose, I'm using Vue components inside .md files as Docsify support those. &lt;/p&gt;

&lt;p&gt;Is there any plugin or other generators which does the same using React with the simplicity of Docsify (dropping in a script tag in an existig index.html will work seamlessly)?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>documentation</category>
      <category>react</category>
      <category>webcomponents</category>
    </item>
    <item>
      <title>Fun With forEach</title>
      <dc:creator>Gokul Kathirvel</dc:creator>
      <pubDate>Thu, 06 Jun 2019 09:18:37 +0000</pubDate>
      <link>https://dev.to/gokatz/fun-with-foreach-1p1o</link>
      <guid>https://dev.to/gokatz/fun-with-foreach-1p1o</guid>
      <description>&lt;h2&gt;
  
  
  So, what's a forEach?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;forEach&lt;/code&gt; is a little guy who iterates/loops through the array and executes the given callback for each element. It's more like the traditional &lt;code&gt;for&lt;/code&gt; loop, but with a functional touch. A sample snippet would be like,&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;let&lt;/span&gt; &lt;span class="nx"&gt;colors&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;black&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;blue&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;red&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;colors&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;color&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&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;color&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is a cool color`&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;And the output will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;black is a cool color
blue is a cool color
red is a cool color
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, as you can see, &lt;code&gt;forEach&lt;/code&gt; will invoke the callback for each entry of the callee array. Yes, you might already know that what's fun with this?&lt;/p&gt;

&lt;h2&gt;
  
  
  What's the Fun in there? 👯‍♂️
&lt;/h2&gt;

&lt;p&gt;We are gonna see some snippets that you might not encounter in real-time products/application and try to guess the result of those snippets (without peeking through the output 👀). That's where the real fun lies 😉&lt;/p&gt;

&lt;h3&gt;
  
  
  Snippet 1
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;colors&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;black&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;blue&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;red&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;colors&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;color&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="nx"&gt;colors&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cyan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&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;color&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is a cool color`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, When I thought through this snippet, I predicted this would lead to an infinite loop. That's totally understandable, right? But, our little guy, &lt;code&gt;forEach&lt;/code&gt;, will &lt;strong&gt;run the callback only for the exact number of times as that of the initial array length&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;This is a little &lt;a href="https://twitter.com/_gokatz/status/1129378217226203136" rel="noopener noreferrer"&gt;Twitter poll&lt;/a&gt; stating a snippet like this. Check this out. You are not alone 😛&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1129378217226203136-385" src="https://platform.twitter.com/embed/Tweet.html?id=1129378217226203136"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1129378217226203136-385');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1129378217226203136&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Here, the initial array length is 3 and the callback will be executed only for 3 times. However, the &lt;strong&gt;callback can mutate/change the array&lt;/strong&gt;. But, the callbacks will not be executed for the later elements that are outside the bound (initial length).&lt;/p&gt;

&lt;p&gt;So, the output will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;black is a cool color
blue is a cool color
red is a cool color
[ 'black', 'blue', 'red', 'cyan', 'cyan', 'cyan' ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Snippet 2
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;colors&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;black&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;blue&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;red&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;colors&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;color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&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="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&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="s1"&gt;cyan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&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;color&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is a cool color`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As per the rule that &lt;strong&gt;callback can mutate the array&lt;/strong&gt;, the output for this snippet will be somewhat straight-forward. From the first run itself, we are changing the array value of the next index to &lt;code&gt;cyan&lt;/code&gt; with this &lt;code&gt;colors[index+1] = 'cyan'&lt;/code&gt; statement. So, the output will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;black is a cool color
cyan is a cool color
cyan is a cool color
[ 'black', 'cyan', 'cyan', 'cyan' ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you might be noticed, There is an extra element in the resulting array and that's because, on the last run (index = 2), we are assigning the next index (index = 3) element's value as &lt;code&gt;cyan&lt;/code&gt; and as said before, the callback will not be run for that last element we just pushed as it resides outside the initial array length.&lt;/p&gt;

&lt;h3&gt;
  
  
  Snippet 3
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;colors&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;black&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;blue&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;red&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;colors&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;color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&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;delete&lt;/span&gt; &lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&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;color&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is a cool color`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we delete items from the array. What do you think the output will be? What will be the placeholder for the deleted items? &lt;code&gt;undefined&lt;/code&gt;? &lt;code&gt;NULL&lt;/code&gt;? or something else? &lt;/p&gt;

&lt;p&gt;On Quick skim, a common prediction for the loop would be,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;black is a cool color
undefined is a cool color
undefined is a cool color
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;this is because, we know that callback will be called for the initial length of the array and here in this array, that's &lt;strong&gt;3&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;but, deleting the array element will make that space a &lt;a href="http://2ality.com/2015/09/holes-arrays-es6.html" rel="noopener noreferrer"&gt;hole&lt;/a&gt; and this &lt;code&gt;forEach&lt;/code&gt; guy is &lt;strong&gt;pretty smart and will not run the callback for the holes in the array&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;So, when the callback is executed for the first element (index = 0), it will delete the second element and the callback for the same will not be executed and the loop will be skipped to the third element. So the output will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;black is a cool color
red is a cool color
[ 'black', empty, 'red' ] // empty is just the representation of holes in V8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Snippet 4
&lt;/h3&gt;

&lt;p&gt;So, How an empty array will be treated?&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;let&lt;/span&gt; &lt;span class="nx"&gt;colors&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;Array&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="nx"&gt;colors&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;color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&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="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&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="s1"&gt;cyan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&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;colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt; is a cool color`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing changes, the empty array will be having all elements as holes. &lt;code&gt;console.log(colors)&lt;/code&gt; will result in 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;[empty × 3]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the &lt;strong&gt;callback will not be executed for any of the holes&lt;/strong&gt; and the actual output of the entire snippet will also be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[empty × 3]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Snippet 5
&lt;/h3&gt;

&lt;p&gt;Another less used feature in &lt;code&gt;forEach&lt;/code&gt; is that it can accept a second parameter, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#Using_thisArg" rel="noopener noreferrer"&gt;&lt;code&gt;thisArg&lt;/code&gt;&lt;/a&gt; and if that's passed, the callback will be executed with the passed context. The following snippet is just for the demo you can find a more relevant example on &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#Using_thisArg" rel="noopener noreferrer"&gt;MDN&lt;/a&gt;. I haven't used arrow function here as that will make &lt;code&gt;this&lt;/code&gt; to be &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 javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;colorHandler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;isFavorite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;color&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;color&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cyan&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;colors&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;black&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;blue&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;red&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;cyan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;colors&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="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isFavorite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;colorHandler&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the output will be:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  So...
&lt;/h3&gt;

&lt;p&gt;Hope this was fun. That's all for our little guy. There might be a lot of other fun stuff about &lt;code&gt;forEach&lt;/code&gt;. Kindly share it in the comments to surprise us. Let's see in some time with another array method/property in &lt;strong&gt;Fun With Arrays&lt;/strong&gt; series.&lt;/p&gt;

&lt;p&gt;And a fun fact: This title was inspired from the awesome (😉) show hosted by Sheldon and Amy in &lt;strong&gt;The Big Bang Theory&lt;/strong&gt; series, named, &lt;strong&gt;Fun With Flags.&lt;/strong&gt;&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fhy6b2komgorhj87i64vh.jpg" 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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fhy6b2komgorhj87i64vh.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>documentation</category>
      <category>webdev</category>
    </item>
    <item>
      <title>EmberJS in 2019</title>
      <dc:creator>Gokul Kathirvel</dc:creator>
      <pubDate>Fri, 31 May 2019 18:00:35 +0000</pubDate>
      <link>https://dev.to/gokatz/emberjs-in-2019-3pll</link>
      <guid>https://dev.to/gokatz/emberjs-in-2019-3pll</guid>
      <description>&lt;p&gt;This blog post is a result of &lt;a href="https://blog.emberjs.com/2019/05/20/ember-2019-roadmap-call-for-posts.html"&gt;"Call for Blog Posts"&lt;/a&gt; initiative by Ember.js team for curating 2019 roadmap. &lt;/p&gt;

&lt;p&gt;Also, I hope my first try on writing an emoji-less article! :fingers-crossed: (This should not be counted as an emoji, technically)&lt;/p&gt;

&lt;p&gt;This is the first time I'm participating in the Ember roadmap blog post series. I personally like Ember and it's abstractions to enable and increase productivity.&lt;/p&gt;

&lt;p&gt;In order to write this blog, I curated a list of things WRT documentation and communication in the ecosystem that can be improved. On checking the docs and guides, &lt;strong&gt;I'm stunned that most of those points are already addressed&lt;/strong&gt; in the Guides and API docs. That's excellent to know. Thanks to all the core teams and the contributors.&lt;/p&gt;

&lt;p&gt;Below is a list of few things that I love to see in the core framework and surrounding ecosystems in the coming years.&lt;/p&gt;

&lt;h2&gt;
  
  
  1) Lightweight builds
&lt;/h2&gt;

&lt;p&gt;One of the reasons Ember is not considered among modern frameworks (that's the bitter truth) is that we aim to build a full-fledged framework with all the batteries included and ended up as a fat baby. I personally love this nature of Ember as most of the web apps ended up adding these batteries at some point of development.&lt;/p&gt;

&lt;p&gt;However, when a developer from other framework or a new JavaScript developer evaluates frameworks, the bundle size will be a predominant deciding factor. So, &lt;strong&gt;tree shaking the framework modules&lt;/strong&gt; (and application code) until that's being used will have a great impact on the above-said evaluation. I love to see these such builds being the default one in future Ember apps.&lt;/p&gt;

&lt;p&gt;There are cases where I had to leave behind Ember for this reason despite Ember outperforms most other popular frameworks like React or Vue WRT. rendering speed&lt;/p&gt;

&lt;h2&gt;
  
  
  2) Embroider
&lt;/h2&gt;

&lt;p&gt;I personally think we were hanging too much with a specialized build tool that built around broccoli for a long time. Experimenting with existing popular toolkits like Webpack with Embroider is so cool and the features that other framework users are enjoying for a long time such as &lt;strong&gt;HMR&lt;/strong&gt;, &lt;strong&gt;Code Splitting&lt;/strong&gt; at various levels (route, component, etc.,) can be brought into the ember ecosystem with Embroider. I love to see embroider being the default built tool in 2019.&lt;/p&gt;

&lt;h2&gt;
  
  
  3) Docs around Ember CLI and Broccoli internals
&lt;/h2&gt;

&lt;p&gt;Developing Addon that is not presentational is really a harder process in Ember. The actual &lt;a href="https://ember-cli.com/api/"&gt;API documentation&lt;/a&gt; for CLI is really not helpful to accomplish a task easily (TBH, that's impossible). I usually refer to other similar addons that utilize these hooks and learn from them in order to implement my logic. Since this involves pretty low-level stuff, proper documentation would be wonderful.&lt;/p&gt;

&lt;h2&gt;
  
  
  4) Error Communication
&lt;/h2&gt;

&lt;p&gt;This is inspired from the Vue ecosystem. We are not great at communicating the errors to the developers. Once I hit a few issues, it's tough to debug them and at least it requires considerable knowledge of the framework to identify and rectify them.&lt;/p&gt;

&lt;p&gt;When working with Vue, I feel the error communication is more elegant. In some cases, I just need to copy paste the suggested output from the console into my code to make it work. I can see that the error messages in Ember revamped constantly and it will be great if it's taken into account when building the roadmap for the upcoming year.&lt;/p&gt;

&lt;p&gt;For a new developer, Googling the cause of the issue might be really overwhelming if the necessary context was not given and it might lead to churn.&lt;/p&gt;

&lt;h2&gt;
  
  
  5) Developer Onboarding
&lt;/h2&gt;

&lt;p&gt;I must accept that the onboarding of a new developer becomes much easier compared to the earlier days. But there are few little bumps I've seen personally in the past years.&lt;/p&gt;

&lt;h3&gt;
  
  
  QueryParams
&lt;/h3&gt;

&lt;p&gt;This might be a little thing but it's really not intuitive. I've seen in new developers while working with query params, that it is not obvious to them why we have to make an entry in different files (&lt;a href="https://api.emberjs.com/ember/3.10/classes/Controller/properties/queryParams?anchor=queryParams"&gt;controller&lt;/a&gt; file and the corresponding &lt;a href="https://api.emberjs.com/ember/3.10/classes/Route/properties/queryParams?anchor=queryParams"&gt;route&lt;/a&gt; file) TBH, I personally cannot justify why that is being implemented in such a way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing as a separate section in the tutorials
&lt;/h3&gt;

&lt;p&gt;This might be an "Unpopular Opinion" but keeping the testing section separate in the tutorial might be a good option especially when a new developer tries out the framework for the first time. Usually, a new developer loves to see something on the screen as quickly as possible and most time I see many developers skipping this testing section and start over as after they are comfortable with the actual framework.&lt;/p&gt;

&lt;h3&gt;
  
  
  Component composition and best practices
&lt;/h3&gt;

&lt;p&gt;Basic preaching of topics like &lt;strong&gt;"why we need components?"&lt;/strong&gt; and &lt;strong&gt;"How a UI piece can be built using different component compositions"&lt;/strong&gt; and maybe few prevailing anti-patterns would be beneficial. I accept most of these topics are heavily opinionated, but, it would be great if we could document at least the most acceptable one. Maybe in a section named, &lt;strong&gt;"Advanced Component Concepts"&lt;/strong&gt; or something similar.&lt;/p&gt;

&lt;h2&gt;
  
  
  6) Ember CLI Presets or Project template
&lt;/h2&gt;

&lt;p&gt;This is a little nice to have functionality. I personally like the way Vue uses it's CLI. We can manually choose the features that we are going to use in our project, like TS or JS, Class-based component or Classic Components, Need Service workers or not from the CLI itself and the supporting packages will be installed by the CLI for us. Then we can save this as a preset and can be used in future projects. In Ember, we use &lt;code&gt;features&lt;/code&gt; json to modify these settings and it would be cool to have this integrated with the CLI service itself.&lt;/p&gt;

&lt;p&gt;A awesome addon which aims to do a similar thing is &lt;a href="https://www.npmjs.com/package/ember-cli-create"&gt;ember-cli-create&lt;/a&gt; (like &lt;code&gt;vue create&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post was originally posted on my personal blog: &lt;a href="https://gokatz.me/blog/emberjs-2019-roadmap/"&gt;https://gokatz.me/&lt;/a&gt;. You can also find articles on EmberJs, Chrome Extensions, etc., on the blog&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>ember</category>
      <category>emberjs2019</category>
    </item>
    <item>
      <title>Can we have an online gathering of Browser Extension developers</title>
      <dc:creator>Gokul Kathirvel</dc:creator>
      <pubDate>Wed, 15 May 2019 07:21:21 +0000</pubDate>
      <link>https://dev.to/gokatz/online-gathering-of-browser-extension-developers-51f4</link>
      <guid>https://dev.to/gokatz/online-gathering-of-browser-extension-developers-51f4</guid>
      <description>&lt;p&gt;Hello All Devs,&lt;/p&gt;

&lt;p&gt;I have seen a lot of &lt;a href="https://dev.to/search?q=chrome%20extension"&gt;great articles&lt;/a&gt; on Browser Extensions (Chrome, Firefox, WebExt etc.,) on dev.to. I myself love building extensions and wrote a few articles on &lt;a href="https://dev.to/gokatz/automate-your-chrome-extension-deployment-in-minutes-48gb"&gt;related topics&lt;/a&gt;. But, I guess we don't hang out much to discuss extension arch, design, and more related things. can we organize a small remote online event?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>extensions</category>
      <category>meetup</category>
    </item>
    <item>
      <title>First Time Speaker (FTS) with few tips</title>
      <dc:creator>Gokul Kathirvel</dc:creator>
      <pubDate>Sat, 11 May 2019 12:12:26 +0000</pubDate>
      <link>https://dev.to/gokatz/first-time-speaker-fts-with-few-tips-45po</link>
      <guid>https://dev.to/gokatz/first-time-speaker-fts-with-few-tips-45po</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover by &lt;a href="https://unsplash.com/@theunsteady5" rel="noopener noreferrer"&gt;Edwin Andrade&lt;/a&gt; from &lt;a href="https://unsplash.com" rel="noopener noreferrer"&gt;https://unsplash.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FTS&lt;/strong&gt;: First Time Speaker. Fake abbreviation made by me 😉&lt;/p&gt;

&lt;h2&gt;
  
  
  How it started
&lt;/h2&gt;

&lt;p&gt;I can definitely describe myself as an &lt;strong&gt;Introvert 😑&lt;/strong&gt;  It's really hard (or I can say, impossible) for me to initiate a conversation in a group of new people, even today. I wanted to do something about this, pushing myself out of my comfort zone.&lt;/p&gt;

&lt;p&gt;So, I decided to apply for the local tech meetups. While on the search, I found &lt;a href="http://awesomeconf.dev" rel="noopener noreferrer"&gt;AwesomeConf&lt;/a&gt; which focuses on the Vue framework. The theme was, &lt;strong&gt;"No one shall be a passive attendee"&lt;/strong&gt;, means everyone has to speak at least for 5 or so minutes. I really like that as the theme seems to force me to speak 😜. So, I applied for this conference. A few days later, I got a DM from the organizer that my topic was selected to present.&lt;/p&gt;

&lt;h2&gt;
  
  
  Yay! Selected 🕺 Ouch! Selected 🥴
&lt;/h2&gt;

&lt;p&gt;That was a mixed feeling. I was really happy that my proposal was selected 🤩 as well as I started to &lt;strong&gt;feel anxious about the stage, audience and literally everything&lt;/strong&gt; 🤯. I really gave a lot of thought before committing to this. Finally, I replied that I'm glad to speak at the conference.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Preparation Era
&lt;/h2&gt;

&lt;p&gt;From that moment, I pour a lot (like a loooottt...) of time in preparing the content and slides. Initially, the content was okayish and I moved on to the preparation part. I'm not a native English speaker and my language fluency is not that much strong especially when it comes to public speaking. So, I started to prepare slide notes. I &lt;strong&gt;literally wrote every single line that I planned to talk&lt;/strong&gt; (Beleive me, I even wrote down the greetings and Thank you note).&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fzrh6ldkjl934xx9wyldx.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fzrh6ldkjl934xx9wyldx.png"&gt;&lt;/a&gt;&lt;/p&gt;
Snap from my original slide deck



&lt;p&gt;It was about 20 slides and I finish writing extensive notes for all, fairly a week before the conference. Next comes the actual speaking practice. This was the toughest part 😬. First I started to read out the notes loud (locking myself inside my room) to practice the flow. One of my friends, &lt;a href="https://dev.to/sivakumar_kailasam"&gt;Sivakumar&lt;/a&gt; advised me to record the practice talk using QuickTime player or any such tool and re-watch it for improvements. It actually helped me a lot. I recorded about 4 trails and each one helps me to tune my presenting flow. TBH, when looked into the recording, I was terrified the way I read out the points. It was like reciting a poem to my teacher repeating a lot of words again and again and used a lot of "Ahhmm" word between phrases. If I did not do this practice, I can't imagine how my actual talk would be 😆&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/3orifgrO0BU09tqeJ2/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/3orifgrO0BU09tqeJ2/giphy.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have done a mock presentation with my friend, Sivakumar, a couple of days before the actual talk. He pointed out some really helpful changes wrt the setup and to the actual flow. I incorporated the most. At that point, my slides were in good shape.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Travel story
&lt;/h2&gt;

&lt;p&gt;Before the conference day, I have to &lt;strong&gt;travel from Chennai to Bangalore&lt;/strong&gt;, the venue of the conference. This was another challenge of its own. I don't travel much. Traveling to another city (State, to be precise) for this conference was really like out of my comfort zone and despite that, honestly, I enjoyed the journey. I stayed in a hotel, which I pre-booked earlier, for the night before the conf day. As this was the first try to speak in a meetup/conf in my whole life, I could not sleep that night. Rehearsed 2 times, organized my editor. (Yes, I was decided to do a live coding 😜), prepared my tees and jeans, repeatedly visiting the conference website (only to see my name in the speaker list 😃). It was a great feeling to see my name 😇&lt;/p&gt;

&lt;p&gt;Finally gone bed at almost 3:00 AM with an alarm set at 6.30 AM. Managed to wake up at 7:00 AM. Did another rehearse, freshened up, had breakfast and ready to check out at 8:30 AM. Reached the venue at 9:00 AM. &lt;/p&gt;

&lt;h2&gt;
  
  
  Finally at the hall
&lt;/h2&gt;

&lt;p&gt;As soon as I entered the conf hall, I was able to realize that my heartbeat rate was elevated. Managed to chose a seat at the center of the hall. As per the schedule, I was the second speaker. So, I decided to give another skim of my slides. &lt;/p&gt;

&lt;p&gt;But, unfortunately (or maybe, fortunately) the first speaker was running late that morning and one of the organizers asked me if I'm okay to start first. I accepted without a second thought and I don't know how I did that till date 🙃&lt;/p&gt;

&lt;p&gt;So, &lt;strong&gt;the first speaker of the conference&lt;/strong&gt;! Went up to the stage and the rest was like magic. Even though I cannot claim the talk to be perfect, I managed to finish all the slides as well as the coding session right on time (20 minutes) with a decent flow.&lt;/p&gt;

&lt;p&gt;The entire 20 minutes was a great experience. That &lt;strong&gt;gives me confidence&lt;/strong&gt; in applying for future meetups and conferences. It proved to me that I can face a group of people and project an idea that I know. This was the much-needed tool in my toolkit.&lt;/p&gt;

&lt;p&gt;I got the perk of being the first speaker of the day. I watched all the 15 talks (yes, 15 talks in a day) without any elevated heart rates 😛. As I mentioned, talking to new people was really tough for me. But, the co-speakers were really welcoming and they themselves initiated the conversation and I really like this about meetups and conferences. Got some really good friends at the end of the day.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, How was the conference? Well...
&lt;/h2&gt;

&lt;p&gt;Overall, the entire experience was great and that was really an &lt;strong&gt;"AwesomeConf" of 2019&lt;/strong&gt; for me. I have to thank the organizers, &lt;a href="https://dev.to/znck"&gt;Rahul&lt;/a&gt; and &lt;a href="https://dev.to/swapagarwal"&gt;Swapnil&lt;/a&gt; as well as the awesome sponsor, &lt;a href="https://meesho.com/" rel="noopener noreferrer"&gt;Meesho&lt;/a&gt;, for the wonderful venue and again awesome lunch 😋&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; If anyone wants to speak and you are not doing that because you think you are an introvert and not comfortable with a new group of people, I urge every one of you to attend/speak at the local meetup and conferences. You will never regret your choice and you'll definitely thank me.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tips from an FTS:
&lt;/h2&gt;

&lt;p&gt;As I mentioned, these are some tips I can give from my experience being a Frist time speaker as well as from my friends who helped me preparing the talk:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prepare the slides&lt;/strong&gt; as soon as possible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Practise your talk&lt;/strong&gt; enough. If possible, &lt;strong&gt;record them and re-watch&lt;/strong&gt;. That will definitely help you in a lot of ways.&lt;/li&gt;
&lt;li&gt;Try to do mock presentations with your friends and collect feedback (again, Record)&lt;/li&gt;
&lt;li&gt;If you are planning to do live coding session, &lt;strong&gt;set up the IDEs and servers&lt;/strong&gt; (if any) beforehand. You cannot make your attendees wait till the server is up or your IDE indexes all your files.&lt;/li&gt;
&lt;li&gt;If you are using a web browser, which you will most likely be, try to &lt;strong&gt;keep your browser clean&lt;/strong&gt; without a lot of extensions or fancy themes, new tab settings. Those things might distract attendees.&lt;/li&gt;
&lt;li&gt;Prepare and &lt;strong&gt;use snippets to do coding faster&lt;/strong&gt;. You need not write every single statement in front of the attendees.&lt;/li&gt;
&lt;li&gt;If possible, &lt;strong&gt;prepare GIFs or video of your coding session&lt;/strong&gt;. If anything goes wrong on live coding, we have a Plan B. &lt;/li&gt;
&lt;li&gt;Have the &lt;strong&gt;presenter note in few mediums&lt;/strong&gt;: Mobile, hard copy, desktop, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Have breakfast&lt;/strong&gt; on the conference day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prepare your stay and travel&lt;/strong&gt; (if any) before the conference date. This will keep your focus on the presentation and avoid unnecessary last-minute surprises. Services like Uber, OYO are really helpful.&lt;/li&gt;
&lt;li&gt;Take a &lt;strong&gt;lot of pics&lt;/strong&gt; on the conferences 😉&lt;/li&gt;
&lt;li&gt;Above all, try to &lt;strong&gt;interact with the attendees and speakers&lt;/strong&gt;. At my view, it's one of the core parts of meetups and conferences.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading through my experience. I hope the tips will be helpful. I'm so grateful that a few of my friends are more excited about this than me. Once again, &lt;strong&gt;thanks to everyone who helped me&lt;/strong&gt; in this little but effective journey.&lt;/p&gt;

&lt;p&gt;The actual title of my talk was &lt;strong&gt;&lt;a href="https://slides.com/gokatz/ember-and-vue" rel="noopener noreferrer"&gt;"Ember and Vue: How they share values?"&lt;/a&gt;&lt;/strong&gt; and planning for another blog with the actual talk content. So, stay tuned. You can find all the cool pictures taken at the conference &lt;a href="https://twitter.com/hashtag/AnAwesomeConf?f=image" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find me on Twitter as &lt;a href="https://twitter.com/_gokatz" rel="noopener noreferrer"&gt;_gokatz&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>conferences</category>
      <category>speaking</category>
      <category>vue</category>
    </item>
    <item>
      <title>Setup Tailwind@next in Vue CLI 3 project</title>
      <dc:creator>Gokul Kathirvel</dc:creator>
      <pubDate>Tue, 07 May 2019 06:05:05 +0000</pubDate>
      <link>https://dev.to/gokatz/setup-tailwind-next-in-vue-cli-3-project-2ba7</link>
      <guid>https://dev.to/gokatz/setup-tailwind-next-in-vue-cli-3-project-2ba7</guid>
      <description>&lt;p&gt;Setting up Tailwind is really an easier process consist of few simple steps. But, developers who are new to Webpack or common CSS configuration like PostCSS (like me) might feel it difficult to join all the parts. This post will help to set up and run tailwind with basic configuration in a Vue CLI 3 project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a new Project
&lt;/h2&gt;

&lt;p&gt;Create a new Vue project using Vue CLI 3 using any of your presets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vue create my-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Install Tailwind (@next)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Using npm&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;tailwindcss@next &lt;span class="nt"&gt;--save-dev&lt;/span&gt;

&lt;span class="c"&gt;# Using Yarn&lt;/span&gt;
yarn add tailwindcss@next &lt;span class="nt"&gt;--dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Load all the Tailwind defaults
&lt;/h2&gt;

&lt;p&gt;Load tailwind defaults in a &lt;code&gt;.css&lt;/code&gt; file. Create a new &lt;code&gt;css&lt;/code&gt; file (say, &lt;code&gt;src/assets/css/tailwind.css&lt;/code&gt;) and load the defaults&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* tailwind.css */&lt;/span&gt;

&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;preflight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;utilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Import this &lt;code&gt;css&lt;/code&gt; file inside &lt;code&gt;main.js&lt;/code&gt; entry file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// main.js&lt;/span&gt;

&lt;span class="c1"&gt;// other imports&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/assets/css/tailwind.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configure PostCSS
&lt;/h2&gt;

&lt;p&gt;Configur PostCSS to use tailwind styles&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;// postcss.config.js&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tailwindcss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;autoprefixer&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now restart the vue server and start working with Tailwind 🎉 &lt;br&gt;
Watch this series for more Tailwind and Vue related tips 😉&lt;/p&gt;

</description>
      <category>vue</category>
      <category>tailwindcss</category>
      <category>css</category>
    </item>
    <item>
      <title>Automate the UI Testing of your chrome extension</title>
      <dc:creator>Gokul Kathirvel</dc:creator>
      <pubDate>Mon, 22 Apr 2019 16:04:02 +0000</pubDate>
      <link>https://dev.to/gokatz/automate-the-ui-testing-of-your-chrome-extension-52e1</link>
      <guid>https://dev.to/gokatz/automate-the-ui-testing-of-your-chrome-extension-52e1</guid>
      <description>&lt;p&gt;Building a chrome extension is definitely a fun process! Chrome extensions open a whole new set of doors to the web developers and users. However, testing those awesome extensions is not as straight forward as testing any conventional web application in some aspects. In this post, Let's walk together with the path of adding our first test case that ensures the best for our extensions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why automate on the first place
&lt;/h2&gt;

&lt;p&gt;The manual testing process is one of the boring stuff in Software Engineering 😆 With the various aspects such as &lt;strong&gt;new install&lt;/strong&gt;, &lt;strong&gt;extension update&lt;/strong&gt;, &lt;strong&gt;permission update&lt;/strong&gt;, &lt;strong&gt;extension downgrade/delete&lt;/strong&gt; of the Chrome extension, the process got a lot trickier and bored. It's really easier to miss testing few aspects on every release. Thus, automating these boring stuff can ensure the proper working of our extension during every single release.&lt;/p&gt;

&lt;h2&gt;
  
  
  How testing can be done
&lt;/h2&gt;

&lt;p&gt;We will be testing a chrome extension using &lt;strong&gt;Puppeteer&lt;/strong&gt; and structure our tests with the &lt;strong&gt;mocha&lt;/strong&gt; test runner. Also, we'll see how to automate this testing process in your CI/CD process using &lt;strong&gt;CircleCI&lt;/strong&gt;. You can use any of your favorite test runner and CI/CD tool.&lt;/p&gt;

&lt;p&gt;Let's install our dependencies first,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add puppeteer mocha &lt;span class="nt"&gt;-D&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i puppeteer mocha &lt;span class="nt"&gt;--dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We can test our chrome extensions with the help of Puppeteer by mimicking the steps we would follow in our manual testing process.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open Chrome Browser&lt;/li&gt;
&lt;li&gt;Load the unpacked version of the extension (via &lt;code&gt;chrome://extensions&lt;/code&gt; page - dev mode)&lt;/li&gt;
&lt;li&gt;Open our extension popup/index page&lt;/li&gt;
&lt;li&gt;Test the targeted features&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's automate those steps one by one. For better understanding, Kindly test the script we are building at each step by running them (&lt;code&gt;node test.js&lt;/code&gt;) then and there.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Open Chrome Programmatically
&lt;/h2&gt;

&lt;p&gt;As a first step, we need to control Chrome programmatically. That exactly where &lt;em&gt;Puppeteer&lt;/em&gt; helps us. As per the docs, Puppeteer is a &lt;strong&gt;Node library which provides a high-level API to control headless (and full non-headless) Chrome&lt;/strong&gt;. In our case, we need to boot Chrome in &lt;strong&gt;full form&lt;/strong&gt; as extensions can load only in full form.&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;// test.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;puppeteer&lt;/span&gt;&lt;span class="dl"&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;browser&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;puppeteer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;headless&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// extension are allowed only in head-full mode&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;On running the script (&lt;code&gt;node test.js&lt;/code&gt;), The chromium build will be boot up with an empty page. Kill the node process to close the Chromium browser.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 2: Load Extensions
&lt;/h2&gt;

&lt;p&gt;Next up, need to load our extension into chrome. Extensions can be load into the browser instance using &lt;code&gt;--load-extension&lt;/code&gt; flag given by Puppeteer. Additionally, we need to disable all other extensions to prevent any unnecessary noise using &lt;code&gt;--disable-extensions-except&lt;/code&gt; flag.&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;// test.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;extensionPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;your&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;extension&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;// For instance, 'dist'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;browser&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;puppeteer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;headless&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// extension are allowed only in the head-full mode&lt;/span&gt;
    &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s2"&gt;`--disable-extensions-except=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;extensionPath&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="s2"&gt;`--load-extension=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;extensionPath&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;On running this script, Chrome instance will be booted along with your extension. You can find your extension logo on the toolbar menu.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 3: Go to the extension popup page
&lt;/h2&gt;

&lt;p&gt;Extension popup/index page will open when we click on the extension icon in the toolbar menu. The same page can be opened directly using the &lt;code&gt;chrome-extension&lt;/code&gt; URL for the easier testing process. A normal extension page URL will be like &lt;code&gt;chrome-extension://qwertyasdfgzxcvbniuqwiugiqwdv/index.html&lt;/code&gt;. This URL can be dissected into,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extension Protocol (&lt;code&gt;chrome-extension&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Extension ID (&lt;code&gt;qwertyasdfgzxcvbniuqwiugiqwdv&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Popup/Index page path (&lt;code&gt;index.html&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We need to construct this kind of URL for our extension in order to visit the page. Here the unknown part is the &lt;strong&gt;Extension ID.&lt;/strong&gt; Thus, we need to know the arbitrary ID of our the extension generated by Chrome.&lt;/p&gt;
&lt;h3&gt;
  
  
  Know your extension ID: The Proper way
&lt;/h3&gt;

&lt;p&gt;Chrome will assign a unique extension ID to every extension when loaded. This will be random every time we boot the extension on a new Chrome instance.  However, a stable extension ID specific for our extension can be set by following the steps mentioned in this &lt;a href="https://stackoverflow.com/questions/23873623/obtaining-chrome-extension-id-for-development/23877974#23877974" rel="noopener noreferrer"&gt;SO answer&lt;/a&gt;. This will be a bit long process but fool-proof. We can safely rely on the stable ID to test our extensions as the ID will not change when booted in various Chrome instance using Puppeteer.&lt;/p&gt;
&lt;h3&gt;
  
  
  Know your extension ID: The Background Script way
&lt;/h3&gt;

&lt;p&gt;However, if our extension got background scripts, then the process would be a bit straight forward. We can detect the Extension ID programmatically.&lt;/p&gt;

&lt;p&gt;When using background scripts, Chrome will create a target for the background script as soon as the extension gets loaded (&lt;em&gt;Step 2&lt;/em&gt;). All the page targets managed by Chrome can be accessed by the &lt;code&gt;targets&lt;/code&gt; method of the booted browser instance. using these targets, we can pull out our specific extension target with the help of &lt;code&gt;title&lt;/code&gt; property (which will be our extension title given in the &lt;code&gt;manifest.json&lt;/code&gt;). This target will contain the random extension ID assigned by Chrome during the current boot up.&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;// test.js&lt;/span&gt;

&lt;span class="c1"&gt;// This wait time is for background script to boot.&lt;/span&gt;
&lt;span class="c1"&gt;// This is completely an arbitrary one.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dummyPage&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;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newPage&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;dummyPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// arbitrary wait time.&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;extensionName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;your&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;extension&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;// For instance, 'GreetMe'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;targets&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;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;targets&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;extensionTarget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;_targetInfo&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;return&lt;/span&gt; &lt;span class="nx"&gt;_targetInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;extensionName&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;_targetInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;background_page&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;Once you fetch your extension target, we can extract the ID from the target URL. A sample background target url will be like, &lt;code&gt;chrome-extension://qwertyasdfgzxcvbniuqwiugiqwdv/background.html&lt;/code&gt;. So, the extraction will be like:&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;extensionUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;extensionTarget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_targetInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&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="p"&gt;[,,&lt;/span&gt; &lt;span class="nx"&gt;extensionID&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;extensionUrl&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We successfully got our extension ID (by either way) 💪&lt;/p&gt;
&lt;h3&gt;
  
  
  En Route to the Extension page 🚌
&lt;/h3&gt;

&lt;p&gt;Now, let's go to our extension page. For this, we need to create a new browser page and load the appropriate extension popup URL.&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;// test.js&lt;/span&gt;

&lt;span class="c1"&gt;// This is the page mentioned in `default_popup` key of `manifest.json`&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;extensionPopupHtml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;extensionPage&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;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newPage&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;extensionPage&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="s2"&gt;`chrome-extension://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;extensionID&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;extensionPopupHtml&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;At this point, running the test script will boot up a new Chrome instance and open a new Page with your extension popup HTML page content as a usual web page.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 4: Test the targeted features
&lt;/h2&gt;

&lt;p&gt;We have successfully booted up our extension page. It's time for a 🖐&lt;/p&gt;

&lt;p&gt;Now, let's pour our web app testing knowledge here. As every web application, end-to-end testing can be done using DOM querying and asserting for the proper value. The same can be applied here. DOM of our extension page can be queried using the &lt;a href="https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pageselector" rel="noopener noreferrer"&gt;&lt;code&gt;$&lt;/code&gt; (&lt;code&gt;querySelector&lt;/code&gt;)&lt;/a&gt;  and &lt;a href="https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pageselector" rel="noopener noreferrer"&gt;&lt;code&gt;$$&lt;/code&gt; (&lt;code&gt;querySelectorAll&lt;/code&gt;)&lt;/a&gt; APIs provided by Puppeteer. You can use your preferred assertion library. In this example, I'm using the node's native &lt;a href="https://nodejs.org/api/assert.html" rel="noopener noreferrer"&gt;&lt;code&gt;assert&lt;/code&gt;&lt;/a&gt; package.&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;// test.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;assert&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;inputElement&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;extensionPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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;[data-test-input]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inputElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Input is not rendered&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;Events can be triggered on the extension page using various event APIs provided by the Puppeteer.&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;extensionPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[data-test-input]&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;Gokul Kathirvel&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;extensionPage&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[data-test-greet-button]&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;greetMessage&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;extensionPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#greetMsg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;textContent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;greetMessage&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, Gokul Kathirvel!&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;Greeting message is not shown&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;NOTE:&lt;/strong&gt; Puppeteer got a lot of useful &lt;a href="https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md" rel="noopener noreferrer"&gt;APIs&lt;/a&gt; to control and extract useful information from Chrome.&lt;/p&gt;
&lt;h3&gt;
  
  
  Use test runners
&lt;/h3&gt;

&lt;p&gt;In order to patch tests in a meaningful manner and to get good visual feedback and, we can use a test runner. In this example, I'm going to demonstrate how to use &lt;a href="https://mochajs.org/" rel="noopener noreferrer"&gt;&lt;code&gt;mocha&lt;/code&gt;&lt;/a&gt; to structure our 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="c1"&gt;// test.js&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;Home Page&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="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Greet Message&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="kd"&gt;function&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;inputElement&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;extensionPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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;[data-test-input]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inputElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Input is not rendered&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;extensionPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[data-test-input]&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;Gokul Kathirvel&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;extensionPage&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[data-test-greet-button]&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;greetMessage&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;extensionPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#greetMsg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;textContent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;greetMessage&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, Gokul Kathirvel!&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;Greeting message is not shown&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Joining all the pieces
&lt;/h2&gt;

&lt;p&gt;Let's join all pieces to create a completely automated test suite for your extension.&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;// test.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;puppeteer&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;assert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;assert&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;extensionPath&lt;/span&gt; &lt;span class="o"&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;extensionPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&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;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&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;Extension UI Testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// default is 2 seconds and that may not be enough to boot browsers and pages.&lt;/span&gt;
  &lt;span class="nf"&gt;before&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&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;boot&lt;/span&gt;&lt;span class="p"&gt;();&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;Home Page&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="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Greet Message&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="kd"&gt;function&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;inputElement&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;extensionPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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;[data-test-input]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inputElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Input is not rendered&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;extensionPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[data-test-input]&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;Gokul Kathirvel&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;extensionPage&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[data-test-greet-button]&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;greetMessage&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;extensionPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#greetMsg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;textContent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;greetMessage&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, Gokul Kathirvel!&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;Greeting message is not shown&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="nf"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&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;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;boot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;browser&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;puppeteer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;headless&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// extension are allowed only in head-full mode&lt;/span&gt;
    &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="s2"&gt;`--disable-extensions-except=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;extensionPath&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="s2"&gt;`--load-extension=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;extensionPath&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dummyPage&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;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newPage&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;dummyPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// arbitrary wait time.&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;targets&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;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;targets&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;extensionTarget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;_targetInfo&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;return&lt;/span&gt; &lt;span class="nx"&gt;_targetInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GreetMe&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;extensionUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;extensionTarget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_targetInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&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="p"&gt;[,,&lt;/span&gt; &lt;span class="nx"&gt;extensionID&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;extensionUrl&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;extensionPopupHtml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

  &lt;span class="nx"&gt;extensionPage&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;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newPage&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;extensionPage&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="s2"&gt;`chrome-extension://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;extensionID&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;extensionPopupHtml&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;we can run this script by invoking the &lt;code&gt;mocha&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mocha test.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;let's create an npm script in &lt;code&gt;package.json&lt;/code&gt; to map the &lt;code&gt;mocha&lt;/code&gt; command,&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"scripts": {
  "test": "mocha test.js"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It would invoke the test and output the test case status in the terminal.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;yarn &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;mocha test.js


  Extension UI Testing
    Home Page
      ✓ Greet Message &lt;span class="o"&gt;(&lt;/span&gt;142ms&lt;span class="o"&gt;)&lt;/span&gt;


  1 passing &lt;span class="o"&gt;(&lt;/span&gt;5s&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Congrats, You made far to the end 🤝&lt;/p&gt;

&lt;p&gt;We have done creating our first test suites that test our extension page. It's time to wire this up with a CI overflow. I'm using &lt;strong&gt;CircleCI&lt;/strong&gt; for this demo. We can use any such services like &lt;strong&gt;TravisCI&lt;/strong&gt;, &lt;strong&gt;AppVeyor&lt;/strong&gt;, etc.,&lt;/p&gt;
&lt;h3&gt;
  
  
  Wiring up with CI
&lt;/h3&gt;

&lt;p&gt;create a config file for &lt;strong&gt;CircleCI&lt;/strong&gt;, &lt;code&gt;.circleci/config.yml&lt;/code&gt; and load up a few boilerplate steps. We will be using an image called &lt;code&gt;circleci/node:8.12.0-browsers&lt;/code&gt; as this image has chrome pre-installed and we need not install any further dependencies. If you are using any other services, find an appropriate image with browsers pre-built.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;docker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;circleci/node:8.12.0-browsers&lt;/span&gt;

    &lt;span class="na"&gt;working_directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/repo&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;checkout&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;restore_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;v1-dependencies-{{ checksum "package.json" }}&lt;/span&gt;

          &lt;span class="c1"&gt;# fall back to using the latest cache if no exact match is found&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;v1-dependencies-&lt;/span&gt;

      &lt;span class="c1"&gt;# Install your dependencies&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yarn install&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;save_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node_modules&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1-dependencies-{{ checksum "package.json" }}&lt;/span&gt;

      &lt;span class="c1"&gt;# build the extension if required&lt;/span&gt;
      &lt;span class="c1"&gt;# Run our test suite &lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yarn test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;OoOHoO... Congrats again. We just automated our test process successfully 🔥🔥 Try to automate your existing and future extension's testing process and be calm on your future releases. The sample extension along with their (working) tests has been hosted in &lt;a href="https://github.com/gokatz/greet-me-extension" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. If you need any help, you can refer to the source code.&lt;/p&gt;

&lt;p&gt;Hope you find this piece of writing useful. If so, I wrote about automating the chrome extension deployment in your CI/CD process in this &lt;a href="https://dev.to/gokatz/automate-your-chrome-extension-deployment-in-minutes-48gb/"&gt;blog post&lt;/a&gt;. Check out if you are manually deploying your extension. This may be the time to automate that too 😉&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/gokatz" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F6843%2F15158776.png" alt="gokatz"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/gokatz/automate-your-chrome-extension-deployment-in-minutes-48gb" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Automate your chrome extension deployment in minutes!&lt;/h2&gt;
      &lt;h3&gt;Gokul Kathirvel ・ Mar 27 '18&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#chrome&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#extensions&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



&lt;p&gt;That's all for today. Let's meet at another time with some other exciting stuff. Bye for Now. If you got any feedback or suggestion, please post in the comment. I would love to work on that.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>chromeextension</category>
      <category>automation</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Can I edit my old dev.to article to add a canonical URL to my recently setup personal blog?</title>
      <dc:creator>Gokul Kathirvel</dc:creator>
      <pubDate>Tue, 26 Feb 2019 16:51:13 +0000</pubDate>
      <link>https://dev.to/gokatz/can-i-edit-my-old-devto-article-to-add-a-canonical-url-to-my-recently-setup-personal-blog-18bd</link>
      <guid>https://dev.to/gokatz/can-i-edit-my-old-devto-article-to-add-a-canonical-url-to-my-recently-setup-personal-blog-18bd</guid>
      <description>&lt;p&gt;I recently set up my personal blogging site, &lt;a href="https://blog.gokatz.me/"&gt;https://blog.gokatz.me/&lt;/a&gt; and I wonder if I can add a canonical url to my blog from dev.to or I should do the other way by adding canonical URL to dev.to from my blog.&lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>Testing "install" and "update" flows in chrome extensions</title>
      <dc:creator>Gokul Kathirvel</dc:creator>
      <pubDate>Sun, 20 Jan 2019 19:30:14 +0000</pubDate>
      <link>https://dev.to/gokatz/testing-install-and-update-flows-in-chrome-extensions-2e40</link>
      <guid>https://dev.to/gokatz/testing-install-and-update-flows-in-chrome-extensions-2e40</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted in &lt;a href="https://blog.gokatz.me/test-install-update-flow-chrome-extensions"&gt;my personal blog&lt;/a&gt; : &lt;a href="https://blog.gokatz.me"&gt;https://blog.gokatz.me&lt;/a&gt;&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;This is a very tiny post pointing out to an existing chrome app development guide about testing chrome extension with respect to install and update flows. These testing may become tricky because during the development stage we use &lt;a href="https://developer.chrome.com/extensions/getstarted#manifest"&gt;&lt;strong&gt;Unpacked extensions&lt;/strong&gt;&lt;/a&gt;. With this method, we may not get to test the actual install and update flows as the related event will not be fired. &lt;/p&gt;

&lt;p&gt;For instance, it's hard to test the &lt;em&gt;permission&lt;/em&gt; flow when using the unpacked extension. We might include new permission into our manifest and need to test before pushing into the web store. &lt;/p&gt;

&lt;p&gt;There is a way to test such scenarios. We can pack the extension locally (into a &lt;code&gt;.crx&lt;/code&gt; file) and install our actual extension from a local file (using &lt;code&gt;.crx&lt;/code&gt; format of the extension). So that, the chrome will treat it as a normal install. Thus, we can test all the install as well as update workflows. &lt;/p&gt;

&lt;p&gt;This &lt;a href="https://developer.chrome.com/extensions/permission_warnings#view_warnings"&gt;section of the chrome extension development guide&lt;/a&gt; walk through the process of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating a &lt;code&gt;.crx&lt;/code&gt; file (extension source) and &lt;code&gt;.pem&lt;/code&gt; file (private key) for your extension &lt;/li&gt;
&lt;li&gt;Installing the &lt;code&gt;.crx&lt;/code&gt; file into Chrome&lt;/li&gt;
&lt;li&gt;Simulating the update process using the &lt;code&gt;.pem&lt;/code&gt; file. If the extension is loaded without a &lt;code&gt;.pem&lt;/code&gt; file, it will be acted as a new install and if we load with an existing &lt;code&gt;.pem&lt;/code&gt; file, the loaded &lt;code&gt;.crx&lt;/code&gt; file will be treated as an update to an existing  extension (if exists)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This section will be focused on the permission part we saw as an example. Hope this helps in deploying your extension with confidence. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bonus Note:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Always have a staging build for your extension such as a separate webstore extension &lt;a href="https://developer.chrome.com/webstore/publish#publishing-to-test-accounts"&gt;visible only to testers&lt;/a&gt;. Publish new builds to the test extension before making it live. I bet it will save you from a ton of awkwardness. It helped me a lot 😉&lt;/p&gt;

</description>
      <category>chromeextension</category>
      <category>javascript</category>
      <category>flashpost</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
