<?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: SitePoint</title>
    <description>The latest articles on DEV Community by SitePoint (@sitepointdotcom).</description>
    <link>https://dev.to/sitepointdotcom</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%2F169764%2F79ca25ee-9740-41eb-8018-e709c68a6393.jpg</url>
      <title>DEV Community: SitePoint</title>
      <link>https://dev.to/sitepointdotcom</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sitepointdotcom"/>
    <language>en</language>
    <item>
      <title>Build a Chrome Extension to Streamline Your Workflow</title>
      <dc:creator>SitePoint</dc:creator>
      <pubDate>Thu, 14 May 2020 07:56:06 +0000</pubDate>
      <link>https://dev.to/sitepoint/build-a-chrome-extension-to-streamline-your-workflow-f1j</link>
      <guid>https://dev.to/sitepoint/build-a-chrome-extension-to-streamline-your-workflow-f1j</guid>
      <description>&lt;p&gt;&lt;em&gt;By &lt;a href="https://www.sitepoint.com/author/jhibbard" rel="noopener noreferrer"&gt;James Hibbard&lt;/a&gt;. This article was originally published &lt;a href="https://www.sitepoint.com/build-a-chrome-extension/" rel="noopener noreferrer"&gt;on SitePoint&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When I began as a JavaScript editor at SitePoint, our submission process was something of a mess — articles coming from every direction in a variety of formats. So we decided to standardize things and settled on submission via GitHub in Markdown.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This was a step forward, but we still needed to convert the Markdown into HTML for our WordPress back end. The powers that be at SitePoint HQ at the time had vetoed the installation of any WordPress plugins, which made us consider if we could accomplish this task with a browser extension. Luckily we could!&lt;/p&gt;

&lt;p&gt;In the following post, I'm going to demonstrate how you can build your own Chrome extension to add additional functionality to WordPress. I'll also introduce you to &lt;a href="https://github.com/jameshibbard/SP-Tools" rel="noopener noreferrer"&gt;SP-Tools&lt;/a&gt;, the extension we use at SitePoint to make life as an editor that little bit easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Anatomy of a Chrome Extension
&lt;/h2&gt;

&lt;p&gt;Despite what you might think, building a Chrome extension isn't difficult. Let's start by looking at the various components.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Parts of the following section are borrowed from another tutorial I wrote about &lt;a href="https://www.sitepoint.com/build-vue-chrome-extension/" rel="noopener noreferrer"&gt;building a Chrome extension using Vue.js&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The core piece of any Chrome extension is a &lt;a href="https://developer.chrome.com/extensions/manifest" rel="noopener noreferrer"&gt;manifest file&lt;/a&gt;. This is in a JSON format and provides important information about an extension, such as its version, resources, or the permissions it requires.&lt;/p&gt;

&lt;p&gt;A manifest file won't do much on its own, so we can use a &lt;a href="https://developer.chrome.com/extensions/content_scripts" rel="noopener noreferrer"&gt;content script&lt;/a&gt; to add some functionality. Content scripts are files that "run in the context of web pages". That is to say, you specify the URL in your manifest file, then when your browser visits a page whose address matches the URL you specified, the content script is injected into the page and run.&lt;/p&gt;

&lt;p&gt;To demonstrate these concepts, let’s start by writing a Chrome extension to do something on the SitePoint main site.&lt;/p&gt;

&lt;p&gt;Make a new folder called &lt;code&gt;my-extension&lt;/code&gt; and two files, &lt;code&gt;manifest.json&lt;/code&gt; and &lt;code&gt;main.js&lt;/code&gt;:&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="nb"&gt;mkdir &lt;/span&gt;my-extension
&lt;span class="nb"&gt;cd &lt;/span&gt;my-extension
&lt;span class="nb"&gt;touch &lt;/span&gt;manifest.json main.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open up &lt;code&gt;manifest.json&lt;/code&gt; and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;My Extension&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;version&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.0.1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;manifest_version&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content_scripts&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;matches&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;*://*.sitepoint.com/*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;js&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;main.js&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;version&lt;/code&gt; and &lt;code&gt;manifest_version&lt;/code&gt; are all required fields. The &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;version&lt;/code&gt; fields can be whatever you want; the &lt;a href="https://developer.chrome.com/extensions/manifestVersion" rel="noopener noreferrer"&gt;manifest version&lt;/a&gt; should be set to 2 (as of Chrome 18).&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;content_scripts&lt;/code&gt; key allows us to register a content script (&lt;code&gt;main.js&lt;/code&gt;), which will be run whenever we visit SitePoint. Notice how we can use &lt;a href="https://developer.chrome.com/extensions/match_patterns" rel="noopener noreferrer"&gt;match patterns&lt;/a&gt; to specify parts of the URL, such as the protocol.&lt;/p&gt;

&lt;p&gt;Now let’s add the following code to &lt;code&gt;main.js&lt;/code&gt; to make the browser say hello whenever we visit SitePoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;alert&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 there!&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;Finally, let’s install the extension. Open Chrome and enter &lt;code&gt;chrome://extensions/&lt;/code&gt; in the address bar. You should see a page displaying the extensions you’ve installed.&lt;/p&gt;

&lt;p&gt;As we want to install our extension from a file (and not the Chrome Web Store) we need to activate &lt;em&gt;Developer mode&lt;/em&gt; using the toggle in the top right-hand corner of the page. This should add an extra menu bar with the option &lt;em&gt;Load unpacked&lt;/em&gt;. Click this button and select the &lt;code&gt;my-extension&lt;/code&gt; folder you created previously. Click &lt;em&gt;Open&lt;/em&gt; and the extension will be installed.&lt;/p&gt;

&lt;p&gt;Now when you visit SitePoint, this will happen:&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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2020%2F03%2F158348751501-chrome-ext.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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2020%2F03%2F158348751501-chrome-ext.png" alt="Basic Extension"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations! You just made a Chrome extension.&lt;/p&gt;

&lt;h3&gt;
  
  
  Background Scripts and Message Passing
&lt;/h3&gt;

&lt;p&gt;So, that dialogue box is pretty annoying right? To finish off this section, let's add a context menu entry to fire it off manually, instead of having it appear on every page load.&lt;/p&gt;

&lt;p&gt;This introduces us to another important component of Chrome extensions — &lt;a href="https://developer.chrome.com/extensions/background_pages" rel="noopener noreferrer"&gt;background scripts&lt;/a&gt;. These scripts can react to browser events (such as a user clicking a context menu entry) and they have full access to Chrome's APIs. However, they &lt;em&gt;don’t&lt;/em&gt; have access to the current page, and rely on message passing to communicate with content scripts.&lt;/p&gt;

&lt;p&gt;Update the manifest like so:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;My Extension&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;version&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.0.1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;manifest_version&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;permissions&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;contextMenus&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content_scripts&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;matches&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;*://*.sitepoint.com/*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;js&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;main.js&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;background&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scripts&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;background.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;persistent&lt;/span&gt;&lt;span class="dl"&gt;"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that we’re requesting the &lt;code&gt;contextMenus&lt;/code&gt; permission, as we want to add something to the context menu, and that we’ve registered a non-persistent background script. Making the background script non persistent allows it to be unloaded when it’s not needed.&lt;/p&gt;

&lt;p&gt;Next, create a &lt;code&gt;background.js&lt;/code&gt; file and add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onInstalled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addListener&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;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contextMenus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&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&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Say hi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;contexts&lt;/span&gt;&lt;span class="p"&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;page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;documentUrlPatterns&lt;/span&gt;&lt;span class="p"&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;*://*.sitepoint.com/*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contextMenus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onClicked&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tab&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;menuItemId&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;greet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tabs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;text&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&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We register the context menu entry when the extension is installed, then add an event listener to send a message to our content script whenever the entry is clicked.&lt;/p&gt;

&lt;p&gt;Change &lt;code&gt;main.js&lt;/code&gt; like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sendResponse&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;greet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;sendResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;I greeted the user&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;Here, we listen for a message from our background script. If it has a text of "greet", we then fire off the alert and send back a message informing the background script that we did what was requested.&lt;/p&gt;

&lt;p&gt;To try this out, head back to the extensions page (at &lt;code&gt;chrome://extensions/&lt;/code&gt;), then click the reload icon and reload any SitePoint page. When you right click, you should now see a context menu entry.&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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2020%2F03%2F158349074502-chrome-ext.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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2020%2F03%2F158349074502-chrome-ext.png" alt="Context menu entry for our extension"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Enhancing WordPress' Functionality with a Chrome Extension
&lt;/h2&gt;

&lt;p&gt;Now that we’ve familiarized ourselves with the basic components of a Chrome extension, let's look at how we can make some additions to WordPress' functionality.&lt;/p&gt;

&lt;p&gt;To follow along with this section, you’ll need a &lt;a href="https://wordpress.org/support/article/how-to-install-wordpress/" rel="noopener noreferrer"&gt;working installation of WordPress&lt;/a&gt;. I installed mine locally. It’s running on an Apache server at &lt;code&gt;http://localhost/wp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The code for this extension can be found on &lt;a href="https://github.com/sitepoint-editors/wp-enhance" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding a Markdown Converter
&lt;/h3&gt;

&lt;p&gt;Let's start by adding a Markdown converter to the WordPress editor. True to the experience on SitePoint, I'll be using the "classic" editor (achieved by installing the &lt;a href="https://wordpress.org/plugins/disable-gutenberg/" rel="noopener noreferrer"&gt;Disable Gutenberg plugin&lt;/a&gt;) and the &lt;em&gt;Text&lt;/em&gt; view.&lt;/p&gt;

&lt;p&gt;To begin, create the following folder structure for our new extension:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wp-enhance
├── lib
│   ├── jquery.min.js
│   └── showdown.min.js
├── manifest.json
└── scripts
    └── main.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the command line:&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="nb"&gt;mkdir &lt;/span&gt;wp-enhance
&lt;span class="nb"&gt;cd &lt;/span&gt;wp-enhance
&lt;span class="nb"&gt;mkdir &lt;/span&gt;lib scripts
&lt;span class="nb"&gt;touch &lt;/span&gt;lib/showdown.min.js lib/jquery.min.js
&lt;span class="nb"&gt;touch &lt;/span&gt;scripts/main.js
&lt;span class="nb"&gt;touch &lt;/span&gt;manifest.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we’ll be using the &lt;a href="https://github.com/showdownjs/showdown" rel="noopener noreferrer"&gt;Showdown markdown converter&lt;/a&gt; and jQuery (because I'm lazy).&lt;/p&gt;

&lt;p&gt;The first order of business is to grab the latest minified version of these libraries (&lt;a href="https://cdnjs.cloudflare.com/ajax/libs/showdown/1.9.1/showdown.min.js" rel="noopener noreferrer"&gt;Showdown&lt;/a&gt; and &lt;a href="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js" rel="noopener noreferrer"&gt;jQuery&lt;/a&gt;) and add the contents to the appropriate files.&lt;/p&gt;

&lt;p&gt;Next, add the following code to &lt;code&gt;manifest.json&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="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;manifest_version&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;WP Enhance&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;description&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A Chrome extension to enhance WordPress' functionality&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;version&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.0.1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content_scripts&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;matches&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost/wp/wp-admin/post-new.php&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;js&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lib/jquery.min.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lib/showdown.min.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scripts/main.js&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's nothing spectacular going on here. The extension is set to run when we visit &lt;code&gt;http://localhost/wp/wp-admin/post-new.php&lt;/code&gt;, and we're including the two libraries we just downloaded.&lt;/p&gt;

&lt;p&gt;Finally, in &lt;code&gt;scripts/main&lt;/code&gt; add the following:&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use strict&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;$editorToolbar&lt;/span&gt; &lt;span class="o"&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;#ed_toolbar&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;$mainTextArea&lt;/span&gt; &lt;span class="o"&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;#content&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="nf"&gt;getShowdownConverter&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;converter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;showdown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Converter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Set any options here, for example to add table support&lt;/span&gt;
  &lt;span class="nx"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setOption&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tables&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&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;converter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addMDButton&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;mdConverter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getShowdownConverter&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;$convertButton&lt;/span&gt; &lt;span class="o"&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;&amp;lt;input /&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&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;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ed_button button button-small&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Convert MD to HTML&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;md&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$mainTextArea&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;val&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;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mdConverter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeHtml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;md&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;$mainTextArea&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;val&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;$editorToolbar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$convertButton&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;addMDButton&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we’re creating a new button and appending it to the WordPress editor's toolbar. When it’s clicked, we’re calling Showdown's &lt;code&gt;makeHtml&lt;/code&gt; method, which we pass the contents of the content area. This returns us some HTML, which we then insert back into the editor.&lt;/p&gt;

&lt;p&gt;Load the extension and visit the new post page. You should see something like this:&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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2020%2F03%2F158349764203-chrome-ext.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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2020%2F03%2F158349764203-chrome-ext.png" alt="The Markdown Converter"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm sure you'll agree, that's a reasonably impressive result in just a few lines of code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding a Date Picker to the Publish Widget
&lt;/h3&gt;

&lt;p&gt;Next, we're going to enhance the publish widget with a datepicker. This will replace the series of drop-downs and input boxes that you normally see when you click the &lt;em&gt;Edit&lt;/em&gt; link next to the "Publish immediately" message in WordPress' &lt;em&gt;Publish&lt;/em&gt; widget.&lt;/p&gt;

&lt;p&gt;The first thing we’ll need to do is to download a datepicker. For this demo I'll be using &lt;a href="https://github.com/xdan/datetimepicker" rel="noopener noreferrer"&gt;this one&lt;/a&gt;. You can download the necessary files from &lt;a href="https://github.com/xdan/datetimepicker/releases/tag/2.5.20" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Unzip that file and place &lt;code&gt;build/jquery.datetimepicker.full.min.js&lt;/code&gt; into our &lt;code&gt;lib&lt;/code&gt; folder. Then create a new &lt;code&gt;css&lt;/code&gt; folder in the extension and place &lt;code&gt;build/jquery.datetimepicker.min.css&lt;/code&gt; into it.&lt;/p&gt;

&lt;p&gt;Our extension should now look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wp-enhance
├── css
│   └── jquery.datetimepicker.min.css
├── lib
│   ├── jquery.datetimepicker.full.min.js
│   ├── jquery.min.js
│   └── showdown.min.js
├── manifest.json
└── scripts
    └── main.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now include these files in the manifest:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;manifest_version&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;WP Enhance&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;description&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A Chrome extension to enhance WordPress' functionality&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;version&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.0.1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content_scripts&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;matches&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost/wp/wp-admin/post-new.php&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;js&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lib/jquery.min.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lib/showdown.min.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lib/jquery.datetimepicker.full.min.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scripts/main.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;css&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;css/jquery.datetimepicker.min.css&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we need to alter our content script (&lt;code&gt;main.js&lt;/code&gt;) to look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;$editorToolbar&lt;/span&gt; &lt;span class="o"&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;#ed_toolbar&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;$mainTextArea&lt;/span&gt; &lt;span class="o"&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;#content&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;$timeStampDiv&lt;/span&gt; &lt;span class="o"&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;#timestampdiv&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;$wpSchedulePostDropdown&lt;/span&gt; &lt;span class="o"&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;.timestamp-wrap&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;$datepicker&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;$dd&lt;/span&gt; &lt;span class="o"&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;#jj&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;$mm&lt;/span&gt; &lt;span class="o"&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;#mm&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;$yyyy&lt;/span&gt; &lt;span class="o"&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;#aa&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;$hh&lt;/span&gt; &lt;span class="o"&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;#hh&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;$mn&lt;/span&gt; &lt;span class="o"&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;#mn&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="nf"&gt;getShowdownConverter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addMDButton&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addDatePicker&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;$datepicker&lt;/span&gt; &lt;span class="o"&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;&amp;lt;input /&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bandaid-datepicker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&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;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Date and time&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;$datepicker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;datetimepicker&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;$timeStampDiv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prepend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$datepicker&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;addMDButton&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;$wpSchedulePostDropdown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hide&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nf"&gt;addDatePicker&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;$datepicker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&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="nf"&gt;updateDateFields&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// String in format yyyy/mm/dd hh:mm&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dateString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;$yyyy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;val&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dateString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nx"&gt;$mm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;val&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dateString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nx"&gt;$dd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;val&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dateString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nx"&gt;$hh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;val&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dateString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nx"&gt;$mn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;val&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dateString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&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;What we’re doing is getting a reference to the input elements that WP uses to manage the time and date of the scheduled post. We’re then hiding these elements and initializing the datepicker. Whenever a user selects a date, the hidden field is updated and the post can be scheduled.&lt;/p&gt;

&lt;p&gt;Reload the extension, then refresh the WordPress new post page. What you have now should look like this:&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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2020%2F03%2F158350271304-chrome-ext.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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2020%2F03%2F158350271304-chrome-ext.png" alt="The datepicker widget"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Again, an impressive result for not much code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing the Extension
&lt;/h2&gt;

&lt;p&gt;One of the things I noticed early on with our SP-Tools extension was that, when WordPress got updated, things would break. So, I got to thinking how I could test the extension and decided that some end-to-end tests with &lt;a href="https://nightwatchjs.org/" rel="noopener noreferrer"&gt;Nightwatch&lt;/a&gt; would make sense.&lt;/p&gt;

&lt;p&gt;In the following section, I'll demonstrate how we can test our extension in the same way.&lt;/p&gt;

&lt;p&gt;First, we'll need to generate a &lt;code&gt;package.json&lt;/code&gt; file. In the extension root, run &lt;code&gt;npm init -y&lt;/code&gt;. Next, let's install Nightwatch and the ChromeDriver as dev dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; nightwatch chromedriver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now make a &lt;code&gt;test&lt;/code&gt;directory and add a &lt;code&gt;nightwatch.config.js&lt;/code&gt; file, as well as a &lt;code&gt;wp.js&lt;/code&gt; file for our test code:&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="nb"&gt;mkdir test
touch test&lt;/span&gt;/nightwatch.config.js &lt;span class="nb"&gt;test&lt;/span&gt;/wp.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following to the config 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="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;src_folders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;output_folder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;page_objects_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;custom_commands_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;custom_assertions_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="na"&gt;webdriver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;start_process&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;9515&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;server_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node_modules/.bin/chromedriver&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;log_path&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="na"&gt;cli_args&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="na"&gt;test_settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;desiredCapabilities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;browserName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chrome&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;chromeOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;load-extension=./&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;--test-type&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="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part is &lt;code&gt;'load-extension=./',&lt;/code&gt;, which tells Nightwatch to load our extension into the test browser.&lt;/p&gt;

&lt;p&gt;And add the following to &lt;code&gt;wp.js&lt;/code&gt; (replacing my login credentials with your own):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test WordPress Mods&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;browser&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;browser&lt;/span&gt;
      &lt;span class="c1"&gt;// Login to WP Dashboard&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost/wp/wp-login.php&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#user_login&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;jim&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#user_pass&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;secret&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;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;#wp-submit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="c1"&gt;// Go to New Post Page&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost/wp/wp-admin/post-new.php&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="c1"&gt;// Test MD &amp;gt; HTML conversion&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#content&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;## level 2 heading&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;### level 3 heading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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;input[value="MD"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;valueContains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#content&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;&amp;lt;h2 id="level2heading"&amp;gt;level 2 heading&amp;lt;/h2&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;valueContains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#content&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;&amp;lt;h3 id="level3heading"&amp;gt;level 3 heading&amp;lt;/h3&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="c1"&gt;// This is here so that you can take a look at the browser&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pause&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&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 run the tests using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node_modules/.bin/nightwatch &lt;span class="nt"&gt;--config&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt;/nightwatch.config.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see an instance of the Chrome browser open and Nightwatch perform the tests we’ve specified. The result of the tests is output to the terminal.&lt;/p&gt;

&lt;p&gt;Hopefully Nightwatch's DSL is pretty self explanatory. You can read more about it in their &lt;a href="https://nightwatchjs.org/api/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;. If you fancy a challenge, try adding tests for the datepicker.&lt;/p&gt;

&lt;p&gt;Note that I've hardcoded my credentials here. If you use this for anything other than demonstration purposes, it'll be a good idea to move these to a config file that’s not committed to GitHub.&lt;/p&gt;

&lt;p&gt;And don't forget you can find the code for everything I’ve demonstrated so far on &lt;a href="https://github.com/sitepoint-editors/wp-enhance" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Notable Features of SitePoint's Chrome Extension
&lt;/h2&gt;

&lt;p&gt;As I'm sure you've realized, your mileage will vary regarding how useful you find such a browser extension. Most people will have (slightly) different needs and will be able to install WordPress plugins to solve most of the problems they encounter.&lt;/p&gt;

&lt;p&gt;Nonetheless, in this final section, I'd like to outline some of the features we have added to our &lt;a href="https://github.com/jameshibbard/SP-Tools" rel="noopener noreferrer"&gt;SP-Tools extension&lt;/a&gt; in the hope that they might inspire or even be useful for others.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  A &lt;em&gt;Capitalize and Check&lt;/em&gt; button. This converts the post title to &lt;a href="http://www.grammar-monster.com/lessons/capital_letters_title_case.htm" rel="noopener noreferrer"&gt;title case&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;  A headline analysis tool, which gives you a score out of 100 for your title and offers suggestions for improvements.&lt;/li&gt;
&lt;li&gt;  A &lt;em&gt;Capitalize Subheadings&lt;/em&gt; button, which checks the remaining headings in the article for title capitalization.&lt;/li&gt;
&lt;li&gt;  A &lt;em&gt;Copy Link&lt;/em&gt; button, which copies the post's current permalink to the clipboard.&lt;/li&gt;
&lt;li&gt;  A &lt;em&gt;Rebuild Link&lt;/em&gt; button, which rebuilds the post's permalink. This is useful, for example, when WordPress creates a permalink based on a draft heading which subsequently changes.&lt;/li&gt;
&lt;li&gt;  An extensible &lt;a href="http://www.urbandictionary.com/define.php?term=molly-guard" rel="noopener noreferrer"&gt;molly-guard&lt;/a&gt;, which performs a number of checks and disables/enables the publish button accordingly. Among other things, it checks for:

&lt;ul&gt;
&lt;li&gt;  a sensible post permalink&lt;/li&gt;
&lt;li&gt;  the presence of relative URLs in the editor pane&lt;/li&gt;
&lt;li&gt;  the presence of empty links in the editor pane&lt;/li&gt;
&lt;li&gt;  the presence of &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; tags in the editor pane&lt;/li&gt;
&lt;li&gt;  the presence of &lt;code&gt;[special]&lt;/code&gt; shortcode tags in the excerpt&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  A &lt;em&gt;Copy Tags&lt;/em&gt; button, which gives you a comma-separated list of tags copied to the clipboard.&lt;/li&gt;

&lt;li&gt;  A &lt;em&gt;rel="sponsored"&lt;/em&gt; button, which toggles the &lt;code&gt;rel&lt;/code&gt; attribute of all links in a post as being &lt;code&gt;sponsored&lt;/code&gt;.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;If you'd like to check it out, you can &lt;a href="https://github.com/jameshibbard/SP-Tools" rel="noopener noreferrer"&gt;find our extension on GitHub&lt;/a&gt;. There are a few other goodies in there, such as context menu entries, some code to turn off the infinite scroll on our main site and, of course, tests with Nightwatch.&lt;/p&gt;

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

&lt;p&gt;In this tutorial, we’ve looked at the various components that make up a Chrome extension. I’ve demonstrated how we can build and test our own Chrome extension to enhance the basic functionality of a WordPress install. I’ve also introduced you to SP-Tools, SitePoint's own Chrome extension, which we use to make various editing tasks somewhat easier.&lt;/p&gt;

&lt;p&gt;If you find our extension useful, or adapt it to do anything else, I'd love to hear from you on &lt;a href="https://twitter.com/jchibbard" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>productivity</category>
      <category>wordpress</category>
    </item>
    <item>
      <title>10 Top Chrome Extensions for Your Web Development Workflow</title>
      <dc:creator>SitePoint</dc:creator>
      <pubDate>Fri, 06 Sep 2019 02:59:36 +0000</pubDate>
      <link>https://dev.to/sitepointdotcom/10-top-chrome-extensions-for-your-web-development-workflow-2pa8</link>
      <guid>https://dev.to/sitepointdotcom/10-top-chrome-extensions-for-your-web-development-workflow-2pa8</guid>
      <description>&lt;p&gt;&lt;em&gt;By &lt;a href="https://www.sitepoint.com/author/jhibbard/" rel="noopener noreferrer"&gt;James Hibbard&lt;/a&gt;. &lt;a href="https://www.sitepoint.com/10-top-chrome-extensions-for-your-web-development-workflow/" rel="noopener noreferrer"&gt;Originally published on SitePoint&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As web developers we work in a very fast paced industry and staying on top of things can sometimes be a challenge. That's why I believe we should take full advantage of whatever tools we have at our disposal to help keep our heads above water. Today I'm going to present ten Chrome extensions that are geared to optimizing your web development workflow, hopefully making you that little bit more productive.&lt;/p&gt;

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

&lt;p&gt;As can be read on &lt;a href="https://developer.chrome.com/extensions" rel="noopener noreferrer"&gt;Chrome's developer portal&lt;/a&gt;, extensions are small software programs that can customize your browsing experience. This can be anything from a spelling and grammar checker that checks your writing as you type, to a password manager that saves your login details for your favorite sites.&lt;/p&gt;

&lt;p&gt;There are literally thousands of extensions available for Chrome, all of which can be downloaded for free from the &lt;a href="https://chrome.google.com/webstore/category/extension" rel="noopener noreferrer"&gt;Chrome Web Store&lt;/a&gt;. You can check which extensions you currently have installed by visiting the following link in your browser: &lt;a href="https://dev.tochrome://extensions/"&gt;chrome://extensions/&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;This article focuses on the Google Chrome browser due to its huge market share (currently 65% and rising). There are also many Chrome-based browsers which support extensions. These include Brave, Vivaldi and, coming soon, Microsoft Edge. However, we should remember that Chrome isn't the only show in town and that many of the extensions mentioned here have a &lt;a href="https://addons.mozilla.org/en-US/firefox/" rel="noopener noreferrer"&gt;Firefox&lt;/a&gt; and/or &lt;a href="https://addons.opera.com/en/" rel="noopener noreferrer"&gt;Opera&lt;/a&gt; equivalent.&lt;/p&gt;

&lt;p&gt;Finally, before we dive into the extensions, take a minute to remember that Chrome is proprietary software published by Google. As we all know, there are &lt;a href="https://en.wikipedia.org/wiki/Privacy_concerns_regarding_Google" rel="noopener noreferrer"&gt;privacy concerns associated with using Google products&lt;/a&gt;, so maybe head over to GitHub and check out the &lt;a href="https://github.com/Eloston/ungoogled-chromium" rel="noopener noreferrer"&gt;ungoogled-chromium project&lt;/a&gt; instead. As the name suggests, this is Google Chromium, sans integration with Google.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Web Developer
&lt;/h2&gt;

&lt;p&gt;We'll start off with the Swiss Army knife of extensions. With over 1 million users and a 4.5 star rating on the Chrome Web Store, Web Developer is something of a must have. It adds a toolbar button to Chrome which, when clicked, displays a plethora of tools that can be used on any web page. These are grouped by category (CSS, forms, images etc) and allow you to do such things as disable JavaScript, outline images with missing &lt;code&gt;alt&lt;/code&gt; attributes, resize the browser window, validate a page's HTML, view a page's meta tag information and much more.&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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2019%2F06%2F1559637493web-developer.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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2019%2F06%2F1559637493web-developer.png" alt="Web Developer Chrome extension"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can &lt;a href="https://chrome.google.com/webstore/detail/web-developer/bfbameneiokkgbdmiekhjnmfkcnldhhm" rel="noopener noreferrer"&gt;download it here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Your Framework's Developer Tools
&lt;/h2&gt;

&lt;p&gt;If you're developing an app with a JavaScript framework and you're not using that framework's developer tools, then you're probably doing it wrong. Let me explain using Vue as an example.&lt;/p&gt;

&lt;p&gt;If you have a Vue app which you need to debug, or you just want to see what's going on under the hood, then what do you do? Inspecting the page's source will show you the HTML that Vue is rendering, but there is much more to a Vue app than that. What about a component's props, data or computed properties? Or your app's state or routing? How do you inspect any of those?&lt;/p&gt;

&lt;p&gt;The good news is that the Vue.js dev tools have you covered. Simply install the extension and open it up on a page running a development build of Vue to see exactly what is happening in your app.&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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2019%2F06%2F1559638848vue-dev-tools.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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2019%2F06%2F1559638848vue-dev-tools.png" alt="Vue.js Dev Tools"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are links to download the dev tools for the big three frameworks.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd" rel="noopener noreferrer"&gt;Vue&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi" rel="noopener noreferrer"&gt;React&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi" rel="noopener noreferrer"&gt;Ember&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Daily 2.0 - Source for Busy Developer
&lt;/h2&gt;

&lt;p&gt;As we work in a fast paced industry, keeping up with news and goings on can sometimes be a challenge. Enter Daily 2.0, an extension that gathers the latest web development and tech posts from around the internet and presents them in an attractive masonry-style lay out on your new tab page.&lt;/p&gt;

&lt;p&gt;The extension is easy to use. When you install it you are asked to pick from a bunch of categories that interest you and Daily 2.0 does the rest. Hovering over the sidebar on the new tab page allows you to filter your feed based on tags and sources.&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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2019%2F06%2F1559814218daily-2.0.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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2019%2F06%2F1559814218daily-2.0.png" alt="Daily 2.0 - Source for Busy Developers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can &lt;a href="https://chrome.google.com/webstore/detail/daily-20-source-for-busy/jlmpjdjjbgclbocgajdjefcidcncaied" rel="noopener noreferrer"&gt;get it here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Toggl Button: Productivity &amp;amp; Time Tracker
&lt;/h2&gt;

&lt;p&gt;If you're a busy freelancer, if you work remotely, or if you just need to track the time you're spending on a project, then Toggl is for you.&lt;/p&gt;

&lt;p&gt;This extension requires you to create an account before you can use it. Once you're logged in it enables quick and easy real time productivity tracking with all the data stored in your Toggl account. It comes with a built-in Pomodoro timer, as well as integrations for a whole host of internet services (such as GitHub, Trello and Slack). One of my favorite features is that it will pop up a notification when you've been idle and the timer was running, allowing you to discard the time.&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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2019%2F06%2F1559815145toggl.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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2019%2F06%2F1559815145toggl.png" alt="Toggl Button: Productivity &amp;amp; Time Tracker"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Toggl can be &lt;a href="https://chrome.google.com/webstore/detail/toggl-button-productivity/oejgccbfbmkkpaidnkphaiaecficdnfn" rel="noopener noreferrer"&gt;downloaded here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Lighthouse
&lt;/h2&gt;

&lt;p&gt;Lighthouse is an open-source, automated tool for improving the performance and quality of your web pages. You can either install it via the Chrome Web Store or, as of Chrome version 60, you can run it directly from the &lt;em&gt;Audits&lt;/em&gt; tab of the browser's DevTools (press F12 and select &lt;em&gt;Audits&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Once you have opened Lighthouse, click &lt;em&gt;Generate report&lt;/em&gt; and optionally select which audit categories to include. Lighthouse will run the selected audits against the page, and generate a report on how well the page did. From there, you can use the failing audits as indicators of how to improve the page. Each audit also includes links to further reading and potential fixes.&lt;/p&gt;

&lt;p&gt;Lighthouse is produced by Google, and presumably uses the same ranking factors as their search engine. This means it can offer you some of the best advice out there on how to optimize your site.&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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2019%2F06%2F1560006297lighthouse.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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2019%2F06%2F1560006297lighthouse.png" alt="Lighthouse"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can &lt;a href="https://chrome.google.com/webstore/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk" rel="noopener noreferrer"&gt;grab it here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. OneTab
&lt;/h2&gt;

&lt;p&gt;So here's the situation. You're working on your web app when suddenly you run up against an unexpected bug. You spend a couple of hours tracking down a fix and by the time you're finished, you have a whole bunch of tabs open in your browser. Add those to the tabs from the project you were working on yesterday, as well as all those articles you haven't quite got round to reading yet, and pretty soon you find yourself in tab chaos.&lt;/p&gt;

&lt;p&gt;This is where the OneTab extension can help you regain a measure of sanity. Whenever you find yourself with too many tabs, click the OneTab icon to convert all of your tabs into a list. When you need to access the tabs again, you can either restore them individually or all at once. Used properly, this extension can give you quite the productivity boost.&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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2019%2F06%2F1560007421one-tab.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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2019%2F06%2F1560007421one-tab.png" alt="OneTab in action"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OneTab can be &lt;a href="https://chrome.google.com/webstore/detail/onetab/chphlpgkkbolifaimnlloiipkdnihall" rel="noopener noreferrer"&gt;downloaded from here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. CSS Peeper
&lt;/h2&gt;

&lt;p&gt;CSS Peeper bills itself as a CSS viewer tailored to designers, which allows you to extract CSS and build beautiful style guides. It does this by allowing you to inspect the CSS rules for any element on a page and presenting all of the style information in a simplistic, yet well-organized manner. It also lists all of a page's colors and images, which can be copied to your clipboard, or exported at the touch of a button.&lt;/p&gt;

&lt;p&gt;This extension is considerably easier to use than the browser's built-in &lt;em&gt;Inspect Element&lt;/em&gt; functionality, the only downside is that you cannot change an element's styles on the fly.&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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2019%2F06%2F1560092741css-peeper.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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2019%2F06%2F1560092741css-peeper.png" alt="CSS Peeper"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can &lt;a href="https://chrome.google.com/webstore/detail/css-peeper/mbnbehikldjhnfehhnaidhjhoofhpehk" rel="noopener noreferrer"&gt;find CSS Peeper here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. User CSS
&lt;/h2&gt;

&lt;p&gt;This extension goes hand in glove with CSS Peeper, offering a quick and easy way to add custom CSS a web page. Once installed, User CSS is easy to use — you click the extensions icon and enter your styles in the side panel that slides out.&lt;/p&gt;

&lt;p&gt;One nice feature of this extension is that your custom CSS styles are persisted. This means you can also use it to permanently hide distracting features on websites you frequent, for example, the trending widget on Twitter.&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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2019%2F06%2F1560093680user-css.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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2019%2F06%2F1560093680user-css.png" alt="User CSS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can &lt;a href="https://chrome.google.com/webstore/detail/user-css/okpjlejfhacmgjkmknjhadmkdbcldfcb" rel="noopener noreferrer"&gt;download User CSS here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Web Developer Checklist
&lt;/h2&gt;

&lt;p&gt;Going live with a new project can be stressful at the best of times — there are a whole bunch of things to remember and coordinate. For example, did you remember to validate the site's HTML? Did you check the SEO? What about accessibility checks? Did you run it through Google Page Speed? The list goes on.&lt;/p&gt;

&lt;p&gt;This is where the Web Developer Checklist extension can help. It analyses a web page for violations of best practices and allows you to discover problem areas in your website before you hand it off to your client. The extension is a companion to the excellent &lt;a href="http://webdevchecklist.com/" rel="noopener noreferrer"&gt;WebDevChecklist.com&lt;/a&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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2019%2F06%2F1560096059web-developer-checklist.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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2019%2F06%2F1560096059web-developer-checklist.png" alt="Web Developer Checklist"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Web Developer Checklist can &lt;a href="https://chrome.google.com/webstore/detail/web-developer-checklist/iahamcpedabephpcgkeikbclmaljebjp" rel="noopener noreferrer"&gt;be downloaded here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Tampermonkey
&lt;/h2&gt;

&lt;p&gt;Userscripts are little computer programs that allow you to alter the behavior of a web page. These can be used for a variety of tasks, such as tweaking a site's layout to your preferences, adding extra functionality to a page, or automating repetitive tasks.&lt;/p&gt;

&lt;p&gt;Tampermonkey is a userscript manager — an extension that allows you to manage and run userscripts, as well as create your own. And it's this last capability that has earned it a place on the list, as you can use Tampermonkey to great effect to streamline your web development workflow. For example, I was recently working on a large form which I needed to test. Instead of manually entering the values every time, I wrote a Tampermonkey script to do that for me, saving me countless keystrokes.&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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2019%2F06%2F1560097180tampermonkey.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%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2019%2F06%2F1560097180tampermonkey.png" alt="Tampermonkey"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tampermonkey can &lt;a href="https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo" rel="noopener noreferrer"&gt;be found here&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;In this post we have looked at ten of my favorite Chrome extensions to boost your web development workflow. I hope this has given you some inspiration, but please remember that this list is by no means exhaustive.&lt;/p&gt;

&lt;p&gt;If I've missed your favorite extension, or you have a gem to share with other readers, I'd be glad to hear from you in the comments below.&lt;/p&gt;

&lt;p&gt;Thanks for reading.&lt;/p&gt;

</description>
      <category>chrome</category>
      <category>productivity</category>
      <category>webdev</category>
    </item>
    <item>
      <title>📚 7 development articles from SitePoint - August</title>
      <dc:creator>SitePoint</dc:creator>
      <pubDate>Fri, 06 Sep 2019 02:53:04 +0000</pubDate>
      <link>https://dev.to/sitepointdotcom/7-development-articles-from-sitepoint-august-1g46</link>
      <guid>https://dev.to/sitepointdotcom/7-development-articles-from-sitepoint-august-1g46</guid>
      <description>&lt;p&gt;We've been working hard to provide developers with useful knowledge and unique viewpoints on SitePoint, and would love to show you some of our top articles from August.&lt;/p&gt;

&lt;h2&gt;
  
  
  5 Super CSS Grid Generators for Your Layouts
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;CSS Grid has turned out to be the most exciting evolution of CSS for quite a while. It’s a specific CSS tool for building any web layout you can think of, from the simplest to the most complex. Today, CSS Grid is widely supported by all major browsers — it’s clear that the dark days of hacking layouts using floats are gone forever.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;➤ Read &lt;a href="https://www.sitepoint.com/css-grid-generators/"&gt;5 Super CSS Grid Generators for Your Layouts&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Create Web Animations with Anime.js
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;There are many JavaScript animation libraries out there, but Anime.js is one of the best. It’s easy to use, has a small and simple API, and offers everything you could want from a modern animation engine. The library has a small file size and supports all modern browsers, including IE/Edge 11+.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;➤ Read &lt;a href="https://www.sitepoint.com/get-started-anime-js/"&gt;How to Create Web Animations with Anime.js&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Every Dev Company Needs to Know about NoOps Development
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;NoOps is a new development approach that involves relieving developers of needing to constantly work with operations members, speeding up deployment time, testing, and workflow.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;➤ Read &lt;a href="https://www.sitepoint.com/noops-development/"&gt;What Every Dev Company Needs to Know about NoOps Development&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How the Top 1% of Candidates Ace Their Job Interviews
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;You’ve done it. You’ve made it through the initial screening process. You’ve just earned an interview with one of the most prestigious and successful companies in your industry. As you’re waiting in the office with three other candidates, a fourth candidate walks in.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;➤ Read &lt;a href="https://www.sitepoint.com/ace-job-interviews/"&gt;How the Top 1% of Candidates Ace Their Job Interviews&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Use Windows Subsystem for Linux 2 and Windows Terminal
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;In this article, you’ll learn how you can use Windows Subsystem for Linux 2 to set up and run a local Linux shell interface in Windows without using a virtual machine. This not like using terminals such as Git Bash or cmder that have a subset of UNIX tools added to $PATH. This is actually like running a full Linux kernel on Windows that can execute native Linux applications. That’s pretty awesome, isn’t it?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;➤ Read &lt;a href="https://www.sitepoint.com/wsl2-windows-terminal/"&gt;How to Use Windows Subsystem for Linux 2 and Windows Terminal&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  25+ JavaScript Shorthand Coding Techniques
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;This really is a must read for any JavaScript developer. I have written this guide to shorthand JavaScript coding techniques that I have picked up over the years. To help you understand what is going on, I have included the longhand versions to give some coding perspective.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;➤ Read &lt;a href="https://www.sitepoint.com/shorthand-javascript-techniques/"&gt;25+ JavaScript Shorthand Coding Techniques&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Redesign Unsplash Using Styled Components
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Writing future-proof CSS is hard. Conflicting classnames, specificity issues, and so on, come up when you have to write and maintain thousands of lines of CSS. To get rid of the aforementioned issues, Styled Components was created.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;➤ Read &lt;a href="https://www.sitepoint.com/using-styled-components/"&gt;How to Redesign Unsplash Using Styled Components&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Premium Previews
&lt;/h2&gt;

&lt;p&gt;We've also released a number of extracts from SitePoint Premium on the blog. Check them out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.sitepoint.com/vue-development-environment/"&gt;How to Set Up a Vue Development Environment&lt;/a&gt; by James Hibbard&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sitepoint.com/getting-started-with-react-native/"&gt;Getting Started with React Native&lt;/a&gt; by Wern Ancheta&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sitepoint.com/master-modern-javascript-with-this-curated-reading-list/"&gt;Master Modern JavaScript with This Curated Reading List&lt;/a&gt; by James Hibbard&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sitepoint.com/how-to-build-a-cipher-machine-with-javascript/"&gt;How to Build a Cipher Machine with JavaScript&lt;/a&gt; by Darren Jones&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it for this month. If you're looking for more, check out &lt;a href="https://dev.to/sitepointdotcom/6-development-articles-from-sitepoint-july-5ch0"&gt;our July roundup&lt;/a&gt;. Let us know what you'd like to see more of in the comments!&lt;/p&gt;

</description>
      <category>css</category>
      <category>javascript</category>
      <category>career</category>
      <category>devops</category>
    </item>
    <item>
      <title>How to Launch a Side Project from Zero</title>
      <dc:creator>SitePoint</dc:creator>
      <pubDate>Fri, 23 Aug 2019 04:29:16 +0000</pubDate>
      <link>https://dev.to/sitepointdotcom/how-to-launch-a-side-project-from-zero-47jk</link>
      <guid>https://dev.to/sitepointdotcom/how-to-launch-a-side-project-from-zero-47jk</guid>
      <description>&lt;p&gt;&lt;em&gt;By &lt;a href="https://www.sitepoint.com/author/achen/" rel="noopener noreferrer"&gt;Amie Chen&lt;/a&gt;. &lt;a href="https://www.sitepoint.com/how-to-launch-a-side-project-from-zero/" rel="noopener noreferrer"&gt;Originally published on SitePoint&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Want to launch a side project, but not sure where to begin? Since 2017, I have launched several projects, including &lt;a href="https://tryspider.com" rel="noopener noreferrer"&gt;Spider&lt;/a&gt;, &lt;a href="https://pretzel.amie-chen.com" rel="noopener noreferrer"&gt;Pretzel&lt;/a&gt;, &lt;a href="https://stitches.hyperyolo.com" rel="noopener noreferrer"&gt;Stitches&lt;/a&gt; and &lt;a href="https://github.com/amiechen/dribbble-sketch-palette/" rel="noopener noreferrer"&gt;Dribbble color palette&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At first, it wasn't clear which steps of the launch process were more important than others. But after my third launch, I had hatched a plan and started tweaking it. In this article, I will share the lessons I learned and walk you through the process of making a product. Hopefully you can take this as a starting point or inspiration, and make something tailored for yourself.&lt;/p&gt;

&lt;p&gt;Start by checking out &lt;a href="https://www.notion.so/986cb2aad42f45c2b92e955312c9f5f9?v=d29c11fd7e804547a19143a9f7293865" rel="noopener noreferrer"&gt;this checklist&lt;/a&gt; that I've developed over a number of side projects. Feel free to run with it and adapt it for your own projects.&lt;/p&gt;

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

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



&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Keep a Problem Notebook
&lt;/h2&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%2Fwww.sitepoint.com%2Fwp-content%2Fuploads%2F2019%2F05%2F1557985979bookofgrudges.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%2Fwww.sitepoint.com%2Fwp-content%2Fuploads%2F2019%2F05%2F1557985979bookofgrudges.jpg" alt="book_of_grudges"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Many of us keep an idea notebook, but I would advocate keeping a “book of grudges”: one with problems and wrongs you find intriguing to solve. Mine is a kanban board with different labels — design, social, security, etc. With these labels, I know what problem could be easily solved with a post-it note, and what could be solved by a clever app. I stare at this board often and maintain it diligently — it tells me what my current priority is, and what the next long term goal is.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Know Yourself First
&lt;/h2&gt;

&lt;p&gt;If you’re like me, your book of grudges is extensive. To figure out what is worth spending time on, let’s start with why. Why do you want to create a product?&lt;/p&gt;

&lt;p&gt;For me, there are two reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; I like helping people and listening to their daily struggles. It gives me different perspectives on life.&lt;/li&gt;
&lt;li&gt; Nothing brings me as much joy as making things. The satisfaction of creating something of my own is far greater than any shiny new job or huge paycheque.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With the two causes combined, I noticed I’m drawn to smaller and refined issues. You can spot a trend among all the products I've made — they are utilitarian and focused.&lt;/p&gt;

&lt;p&gt;So, ask yourself why to narrow the field of selections. If new technologies and the possibilities they bring fascinate you, maybe an open-ended, AR powered camera app would excite you. Whatever you choose, starting by understanding your cause will help you feel less overwhelmed.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Ideation and Design
&lt;/h2&gt;

&lt;p&gt;Once you have a problem to tackle and you’re armed with enough knowledge regarding the problem, it’s time to ideate the solution. During ideation, the only goal is to generate as many solutions as possible without being judgmental. I write my ideas out in a Markdown file and keep the session around 30 minutes.&lt;/p&gt;

&lt;p&gt;Sometimes, I sit on this Markdown file for several days while doing more research. Once I decide on an approach, then I can start writing user stories and sketching wireframes. Because these latter two steps both require a clear path, I try to iron out all the doubts and questions beforehand.&lt;/p&gt;

&lt;p&gt;Writing user stories is like envisioning how the user would use the product in detail. Here is an example of what I did for Spider:&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%2Fwww.sitepoint.com%2Fwp-content%2Fuploads%2F2019%2F05%2F1557985994userstories.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%2Fwww.sitepoint.com%2Fwp-content%2Fuploads%2F2019%2F05%2F1557985994userstories.png" alt="spider user stories"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, every step explains “what user sees and what user does.” It creates a clear workflow that makes drawing wireframes a breeze.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Branding and High-fidelity Mockups
&lt;/h2&gt;

&lt;p&gt;Often times I spend one or two days working on the visual design and branding. Many would argue that's unnecessary for an MVP — but I think there's a value in a good first impression and cohesive branding. Plus, the designer in me really enjoys this part.&lt;/p&gt;

&lt;p&gt;To design efficiently, I recommend maintaining a small toolkit that consists of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  an extensive UI kit in Sketch or Figma&lt;/li&gt;
&lt;li&gt;  a few of your favorite fonts and pairings&lt;/li&gt;
&lt;li&gt;  a few of your favorite color palettes&lt;/li&gt;
&lt;li&gt;  a versatile SVG icon library&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, focus on nailing these design assets first:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The button style in hover and normal state&lt;/li&gt;
&lt;li&gt;  The body font vs the title&lt;/li&gt;
&lt;li&gt;  The input style&lt;/li&gt;
&lt;li&gt;  The navigation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remember, try not to spend too much time fussing over details.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Code It Up
&lt;/h2&gt;

&lt;p&gt;When it comes to development, I (would rather) believe no one spits out beautiful code on the first go. Though time consuming, an iterative approach works better for me. Usually, I start by writing a functional app (with terrible code) to prove the concept. After that, I play with the end result and think about how I can do it better. Finally, I scratch the whole thing and rewrite everything — this time with quality and maintainability in mind. The second iteration should result in better quality code.&lt;/p&gt;

&lt;p&gt;The Basecamp team rewrites their app from the ground up every four years. It’s an approach I find necessary if you want to keep a focused product and maintain a manageable code base.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Spread the Word
&lt;/h2&gt;

&lt;p&gt;All the usual marketing strategies aside, what I found to be effective is simply telling someone about a thing by showing them how it’d be useful to them. With that in mind, it’s crucial to focus on these things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  A clear elevator pitch for the product&lt;/li&gt;
&lt;li&gt;  Demo video of how the product can help people&lt;/li&gt;
&lt;li&gt;  Marketing website with a feature list and FAQ&lt;/li&gt;
&lt;li&gt;  Documentation&lt;/li&gt;
&lt;li&gt;  Consistent, high-quality promotion assets for various platforms like Product Hunt/Twitter/email&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When people are confused about your product, they move on. Be as honest and clear as you can be — it speaks to people better that way!&lt;/p&gt;

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

&lt;p&gt;We all have something inside that we'd like to share with the world: it could be an idea, a project or a talent. Don't let the imposter syndrome cripple you. More likely than not, you are ready to create something of your own. Add something to the world that only you can add to it.&lt;/p&gt;

</description>
      <category>career</category>
      <category>sideprojects</category>
      <category>startup</category>
    </item>
    <item>
      <title>4 Signs It’s a Bad Idea to Quit Your Dev Job</title>
      <dc:creator>SitePoint</dc:creator>
      <pubDate>Wed, 07 Aug 2019 05:42:16 +0000</pubDate>
      <link>https://dev.to/sitepointdotcom/4-signs-it-s-a-bad-idea-to-quit-your-dev-job-4epo</link>
      <guid>https://dev.to/sitepointdotcom/4-signs-it-s-a-bad-idea-to-quit-your-dev-job-4epo</guid>
      <description>&lt;h3&gt;
  
  
  (&amp;amp; What to Do When You Have to Stay)
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;By &lt;a href="https://www.sitepoint.com/author/alexm/"&gt;Andrew McDermott&lt;/a&gt;. Originally published on &lt;a href="https://www.sitepoint.com/4-signs-its-a-bad-idea-to-quit-your-job/"&gt;SitePoint&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Edwarden, a developer and StackExchange user, wanted advice.&lt;/p&gt;

&lt;p&gt;His boss yelled at him for requesting a promotion in the future. Or more specifically, asking for advice on the best process for receiving a promotion. Edwarden exceeded his manager’s expectations. Other managers were also very happy with his performance as well.&lt;/p&gt;

&lt;p&gt;His manager also knew what Edwarden wanted to discuss ahead of time.&lt;/p&gt;

&lt;p&gt;It didn’t matter.&lt;/p&gt;

&lt;p&gt;His manager exploded. He began yelling, shouting and stomping his feet. &lt;em&gt;“You’ve only been here… how many months?! Seven?! And now you’re asking for a promotion!”&lt;/em&gt; His manager threw a tantrum and continued to interrupt him until he agreed that he had no “additional concerns.”&lt;/p&gt;

&lt;h2&gt;
  
  
  Here’s the Advice He Received from Other Users
&lt;/h2&gt;

&lt;p&gt;You should quit your job.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  You should look for a new job, I don’t think your boss is going to promote you&lt;/li&gt;
&lt;li&gt;  How many red flags do you need to see before you look for a new job?&lt;/li&gt;
&lt;li&gt;  Do yourself a favor and get out&lt;/li&gt;
&lt;li&gt;  This shows you why the turnover rate is high and why you should try to get out as soon as possible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Is it a bad idea for him to quit his job?&lt;/p&gt;

&lt;p&gt;How do you know?&lt;/p&gt;

&lt;p&gt;It’s not something we’re taught in school. We graduate, get a job and then we’re just supposed to figure this out on our own. While some of us do, many of us don’t.&lt;/p&gt;

&lt;p&gt;That’s the question.&lt;/p&gt;

&lt;p&gt;What are the signs that indicate it’s a bad idea to quit your job? First, let’s take a look at some of the more common/obvious answers.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; You don’t have another job lined up&lt;/li&gt;
&lt;li&gt; You don’t have any savings to carry you through the transition from old to new&lt;/li&gt;
&lt;li&gt; You need the money or you aren’t sure you’ll get as much somewhere else&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We’re all familiar with the usual reasons given when people suggest that you should stay at a job you obviously would prefer to leave. And you know what? This is solid advice. What about the uncommon and obscure reasons that are &lt;em&gt;more important&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;Let’s take a look.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. You’ll Be Branded as a Job Hopper If You Leave Now
&lt;/h2&gt;

&lt;p&gt;Mark Suster is a well-known entrepreneur and successful venture capitalist. He offers businesses some essential, yet wildly unpopular advice.&lt;/p&gt;

&lt;p&gt;Never hire job hoppers.&lt;/p&gt;

&lt;p&gt;In his &lt;a href="https://bothsidesofthetable.com/never-hire-job-hoppers-never-they-make-terrible-employees-e30cd5ff7322"&gt;post&lt;/a&gt;, &lt;em&gt;Never Hire Job Hoppers. Never. They Make Terrible Employees&lt;/em&gt;, he defines a job hopper and explains why it’s so detrimental for companies to hire them. Here’s his subjective definition.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“It’s kind of like that famous saying about art, “you know it when you see it.” If you’re 30 and have had 6 jobs since college you’re 98% likely to be a job hopper. You’re probably disloyal. You don’t have staying power. You’re in it more for yourself than your company. OR… You make bad decisions about which companies you join.&lt;/p&gt;

&lt;p&gt;Are you 25 and have worked for 3 companies, each for 18 months? You’re on the borderline. If they are Google, Facebook and then a startup — you’re fine. That’s less than 1%. If you’re 42 and the longest you’ve EVER worked at a company is 3 years — TOAST. That means you’ve likely had 7 short-term jobs since college.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;He basically describes job hoppers as disloyal mercenaries. This kinda, sorta implies that he views these employees as selfish and untrustworthy. This is bad news if you’re looking to quit your job.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is it true though?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It doesn’t matter whether it’s true or not. Most employers agree with him. &lt;a href="http://blog.au.indeed.com/2018/11/21/report-76-of-employers-have-decided-not-to-interview-candidates-with-a-history-of-short-term-jobs/"&gt;Research from Indeed&lt;/a&gt; shows &lt;strong&gt;&lt;em&gt;76 percent of employers&lt;/em&gt;&lt;/strong&gt; don’t want to hire job hoppers. Most employers won’t admit that if you ask because, legalities. &lt;a href="https://www.bls.gov/news.release/pdf/nlsoy.pdf"&gt;Research&lt;/a&gt; from the Department of Labor validates the frequency of job-hopping.&lt;/p&gt;

&lt;p&gt;Here’s some pushback.&lt;/p&gt;

&lt;p&gt;A quick Google search shows there are plenty of articles suggesting that attitudes on job-hopping have changed. That it’s &lt;em&gt;the new normal&lt;/em&gt;. Many of the people reading these articles feel good. Are you one of those people who feel it’s not as much of an issue as it used to be?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Either way, it’s a complete disaster (for you).&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you’re right&lt;/em&gt;, employers have become mercenaries as well. This means employee &lt;a href="https://www.nytimes.com/topic/subject/layoffs-and-job-reductions"&gt;disloyalty&lt;/a&gt; &lt;a href="https://www.bizjournals.com/dayton/blog/morning_call/2014/06/employers-are-shrinking-benefits-study-finds.html"&gt;has increased&lt;/a&gt; employer disloyalty. It’s easier for them to mistreat their people. &lt;em&gt;If you’re wrong&lt;/em&gt;, you’re not going to get the job. &lt;em&gt;Either way,&lt;/em&gt; &lt;strong&gt;you lose.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Quit prematurely and you may hurt your career in the long term.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. You May Be Blacklisted
&lt;/h2&gt;

&lt;p&gt;It’s a hotly debated topic.&lt;/p&gt;

&lt;p&gt;Do HR blacklists exist? Some HR professionals say they don’t and are insulted by the suggestion that they do. Other professionals (and developers) say they do. Which side is right?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First, the argument &lt;em&gt;for&lt;/em&gt; &lt;a href="https://www.wsj.com/articles/SB10001424052748703389004575033583145567138"&gt;blacklists&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“At a networking event last August in Bellevue, Wash., a recruiter pointed to a software developer across the room. He’s qualified, but “very bad in his presentation skills,” he told career coach Paul Anderson and a human resources official for a big technology concern. “What’s that guy’s name?” Mr. Anderson remembers the HR official asking, and then scribbling the name in her notebook. “I want to add him to our blacklist.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;It gets worse.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“The developer then walked over to the trio to inquire whether the recruiter had found relevant openings for him. The recruiter replied he was still looking. But once the job seeker left, the recruiter “told us he would never submit him to any clients,” Mr. Anderson recalls.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Mr. Anderson claims &lt;em&gt;he blacklisted prospects&lt;/em&gt; during his tenure at Microsoft. Other &lt;a href="https://www.linkedin.com/pulse/employer-unfairly-blacklisted-employee-heres-what-j-t-o-donnell"&gt;articles&lt;/a&gt;&lt;a href="https://www.monster.com/career-advice/article/things-that-will-blacklist-you-from-job"&gt;recount&lt;/a&gt; a similar story.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next, the arguments &lt;a href="https://www.quora.com/Is-there-any-blacklist-held-online-and-used-by-recruiters-and-HR-personnel-for-employees-who-have-left-on-negative-terms/answer/Steve-Toomey-2"&gt;&lt;em&gt;against&lt;/em&gt;&lt;/a&gt; blacklists.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Candidates do have a record when they apply to a large company, but each opportunity is on its own merit and we do not use data from other jobs or a “Black List” to disqualify anyone. All recruiters have bias like any other human, and hiring managers do tend to remember bad candidates, but nothing like a Black or Hit List that I have ever witnessed in my 15 years as a recruiter.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Other HR professionals &lt;a href="https://www.quora.com/Is-there-any-blacklist-held-online-and-used-by-recruiters-and-HR-personnel-for-employees-who-have-left-on-negative-terms/answer/Marcus-Fischer"&gt;agree&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Most companies find its (sic) own ways to make sure that they “remember” why an employee left to avoid rehiring of employees who left on negative terms but there is no shared resource where companies share information about employees. The strongest “weapon” is the reference call.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;What if &lt;em&gt;both sides&lt;/em&gt; are right?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A formal blacklist or database that’s shared across several organizations would be an illegal and very risky move. An internal (and informal) “&lt;em&gt;do not hire&lt;/em&gt;” list would be more appealing. As we saw earlier, it would be easier to discuss this with recruiters and other HR professionals in a casual setting.&lt;/p&gt;

&lt;p&gt;Do you work for an organization that blacklists? Here are a few strategies you can use to detect blacklisting.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Talk to former employees&lt;/strong&gt; before you quit. You’re looking for a specific scenario. A series of circumstances where new employers were on the verge of hiring these former employees, then suddenly lose interest.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Look for rehires.&lt;/strong&gt; Does your organization have a large pool of employees who previously left the organization only to be rehired at a later date? This is a very good sign. It’s an indication that revenge isn’t a core value.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Ask former employees&lt;/strong&gt; how long it took to find a new position. If a large portion of former employees struggle to land a new position, proceed with caution. Have a large number of these employees lost positions they were on the verge of winning? Secure a new position before leaving your current job.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If there’s &lt;em&gt;any&lt;/em&gt; chance that you’ll need a reference from your current job in the future these strategies are important to-dos. They’re important even if you’re planning on a career change.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. You Don’t Have a Replacement Plan
&lt;/h2&gt;

&lt;p&gt;Isn’t this another way of saying you don’t have another job lined up?&lt;/p&gt;

&lt;p&gt;Nope.&lt;/p&gt;

&lt;p&gt;A replacement plan means you have a plan to find a new position at your ideal company. This plan achieves very specific goals and objectives and is focused on one thing. Hold and carry.&lt;/p&gt;

&lt;p&gt;What does that mean?&lt;/p&gt;

&lt;p&gt;You’re maintaining and/or improving on your current circumstances. This means you have a plan to…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Establish a mutually beneficial relationship with allies, mentors, influencers, and connectors&lt;/li&gt;
&lt;li&gt;  Identify and cultivate relationships with ideal companies&lt;/li&gt;
&lt;li&gt;  Curate a list of sources that feed you a consistent stream of information&lt;/li&gt;
&lt;li&gt;  Maintain and/or improve on your current salary and benefits package&lt;/li&gt;
&lt;li&gt;  Protect yourself from negative circumstances in the future (terrible boss, layoffs, firing, etc.)&lt;/li&gt;
&lt;li&gt;  Identify pathways to promotion, leadership and performance positions ahead of time&lt;/li&gt;
&lt;li&gt;  Minimize interruptions and downtime due to transition&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use &lt;a href="https://www.sitepoint.com/5-simple-strategies-to-double-your-salary/"&gt;these&lt;/a&gt;&lt;a href="https://www.sitepoint.com/why-the-highest-paid-developers-fight-their-coworkers/"&gt;posts&lt;/a&gt; to create a detailed plan of attack before you leave your current job or &lt;a href="https://www.sitepoint.com/3-unexpected-signals-employers-send-fire/"&gt;avoid the unexpected firing&lt;/a&gt;. If you don’t have a plan with these details and you decide to quit, you’re rolling the dice.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Leaving Means You Hurt Your Co-Workers
&lt;/h2&gt;

&lt;p&gt;This could be a co-worker, manager or friend you’re on good terms with. There are certain situations where leaving makes things worse for the co-workers you leave behind.&lt;/p&gt;

&lt;p&gt;Here’s a &lt;a href="https://www.reddit.com/r/cscareerquestions/comments/bg1qf9/what_are_your_worst_manager_stories/eli2pxs/"&gt;scenario&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are three dev teams at your company. All three teams are completely siloed from each other. For some bizarre reason, you’re the only dev who can provide all three teams with the data they need to finish a large project.&lt;/p&gt;

&lt;p&gt;But your boss is the &lt;em&gt;worst&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In fact, he’s the reason why you want to quit. He’s made work an unbearable disaster. You’re expected to put out a never-ending series of dumpster fires every day at work. Your boss is responsible for many of them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here’s why it may be a bad idea to leave.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you want to get another job you’re probably going to need a reference, or at the very least, a way to explain the gap in your resume if you decide to omit your current position. Remember the mutually beneficial relationships I mentioned in step three? Your co-workers are part of that list.&lt;/p&gt;

&lt;p&gt;Who cares?&lt;/p&gt;

&lt;p&gt;An &lt;a href="https://www.monster.com/career-advice/article/5-types-of-coworkers-you-need-in-inner-circle"&gt;article&lt;/a&gt; from Monster outlines the five types of co-workers you need in your inner circle to get ahead in your career (&lt;em&gt;e.g. a friend, HR confidant, mentor with clout, gatekeeper, and competitor&lt;/em&gt;). Leaving prematurely (or in a way that hurts your co-workers) destroys these relationships.&lt;/p&gt;

&lt;p&gt;Have to leave anyway?&lt;/p&gt;

&lt;p&gt;Do your very best to tie up loose ends before you go. Work to make things as easy as you can for your co-workers. Focus on leaving your current company on the very best of terms, even if you hate your current manager.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should you do if you have to stay at your job?
&lt;/h2&gt;

&lt;p&gt;Staying is an opportunity in disguise. If you’re desperate to leave it certainly won’t feel that way. It’ll probably feel terrible. Many people would recommend that you keep your head down, that you do your best to make it through until you find something better.&lt;/p&gt;

&lt;p&gt;There’s a good chance you have other (better) cards to play.&lt;/p&gt;

&lt;p&gt;Here’s what I mean.&lt;/p&gt;

&lt;h3&gt;
  
  
  Search for Dysfunctional Patterns and Problems
&lt;/h3&gt;

&lt;p&gt;The greater the dysfunction and problems at your current company the bigger the opportunity to add significant value. Look for work-related issues you can fix. You’re looking for opportunities that go above and beyond your normal workload. Why on earth would you go to the trouble of working &lt;em&gt;harder&lt;/em&gt; for your current company?&lt;/p&gt;

&lt;p&gt;Your accomplishment portfolio.&lt;/p&gt;

&lt;p&gt;If you’re able to score several big wins at your current organization you have the leverage you need to negotiate a large salary increase at your next position. The more value you add in your current position, the more value you’ll receive (with negotiation) in your next position.&lt;/p&gt;

&lt;p&gt;Here’s how your accomplishments factor in.&lt;/p&gt;

&lt;p&gt;Anytime you achieve anything of value, no matter how small, you open your notes and you jot it down.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Received a compliment from a manager in another department? Write it down.&lt;/li&gt;
&lt;li&gt;  Fixed three times as many bugs as the next developer in your company? &lt;em&gt;Write it down.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;  Have you created libraries and tools for other developers at your company? &lt;strong&gt;&lt;em&gt;Write it down&lt;/em&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Don’t Judge, Just Write
&lt;/h3&gt;

&lt;p&gt;Make a list of anything and everything good you’ve done for your company. Make a list of the names, dates and times. You’re looking to create a sizeable list of accomplishments. If you’re looking to turbocharge the effectiveness of your accomplishments, ask your managers or co-workers for feedback.&lt;/p&gt;

&lt;p&gt;Keep doing this.&lt;/p&gt;

&lt;p&gt;You now have a list of amazing stories you can share on your cover letter, in your resume, and in job interviews. Even better, you have specific names, dates and times which makes your stories powerful and incredibly compelling.&lt;/p&gt;

&lt;p&gt;What’s next?&lt;/p&gt;

&lt;h3&gt;
  
  
  Take Future Co-Workers to Lunch
&lt;/h3&gt;

&lt;p&gt;Remember those mutually beneficial relationships I mentioned in step three? You’re going to go through their LinkedIn contacts list. Reach out to co-workers who have &lt;a href="https://www.linkedin.com/help/linkedin/answer/110/your-network-and-degrees-of-connection?lang=en"&gt;second-degree connections&lt;/a&gt; at companies you’re interested in. If you’ve taken the time to serve them, you’re in a good position to request a favor.&lt;/p&gt;

&lt;p&gt;It doesn’t matter if these companies are hiring.&lt;/p&gt;

&lt;p&gt;Ask your co-workers to make an introduction via LinkedIn or, if you’re concerned about privacy, send these second-degree connections an &lt;a href="https://www.linkedin.com/help/linkedin/answer/1584"&gt;InMail&lt;/a&gt; to introduce yourself. Here’s a template you can customize — just substitute the bold elements.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Hi &lt;strong&gt;First Name&lt;/strong&gt;,&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I’m &lt;strong&gt;friends&lt;/strong&gt; with &lt;strong&gt;mutual contact&lt;/strong&gt;. I’d love your advice on &lt;strong&gt;…&lt;/strong&gt;. Can I take you to lunch this week?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Let me know what works best for you.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;First + Last Name&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You’ll want to identify the five types of co-workers you would need in your inner circle if you received a position &lt;em&gt;at their company&lt;/em&gt;. Then, when you’re ready, take them to lunch. Ask them about the things you need to do to earn a job at their company. While you’re chatting, look for ways you can add value.&lt;/p&gt;

&lt;p&gt;Rinse and repeat.&lt;/p&gt;

&lt;p&gt;If it’s a fit, work to build a &lt;em&gt;genuine relationship&lt;/em&gt; with each of these contacts. Invite them out after work. Include them in parties and get-togethers. Why does this work? &lt;a href="https://www.asanet.org/sites/default/files/savvy/documents/press/pdfs/ASR_December2012_Lauren_Rivera_News_Release.pdf"&gt;Research shows&lt;/a&gt; employers prefer to hire friends, people they want to hang out with. It’s a straightforward way to earn a position at the organization of your choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sometimes It’s a Bad Idea to Quit Your Job
&lt;/h2&gt;

&lt;p&gt;It’s not something we’re taught in school. When we graduate, we’re told to get a job. Then we’re just supposed to figure these details out on our own. When things go south with our jobs, many of us aren’t sure how to handle it. Sometimes the signs indicate it’s a bad idea to quit your job.&lt;/p&gt;

&lt;p&gt;When you have to stay, there are benefits.&lt;/p&gt;

&lt;p&gt;We’re all familiar with the usual reasons given when others tell us to stay at a job we want to leave. The usual advice is good advice. But we’re not told how to make the most of a bad situation.&lt;/p&gt;

&lt;p&gt;Elite, A player developers know-how.&lt;/p&gt;

&lt;p&gt;Now you do too. With the right strategy and tactics, you’ll have the strategies you need to convert a difficult situation into an incredible opportunity.&lt;/p&gt;

</description>
      <category>career</category>
      <category>productivity</category>
      <category>startup</category>
    </item>
    <item>
      <title>📚 6 development articles from SitePoint - July</title>
      <dc:creator>SitePoint</dc:creator>
      <pubDate>Mon, 29 Jul 2019 05:11:45 +0000</pubDate>
      <link>https://dev.to/sitepointdotcom/6-development-articles-from-sitepoint-july-5ch0</link>
      <guid>https://dev.to/sitepointdotcom/6-development-articles-from-sitepoint-july-5ch0</guid>
      <description>&lt;p&gt;We've been working hard to provide developers with useful knowledge and unique viewpoints on SitePoint, and would love to show you some of our top articles from June.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn to Design and Animate in 3D with Zdog
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;There’s a cool JavaScript library that names like Chris Gannon, Val Head, and CodePen are all raving about. You can also find it on Product Hunt, where it’s been doing rather well. The library is none other than Dave DeSandro‘s Zdog.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;➤ Read &lt;a href="https://www.sitepoint.com/learn-zdog/"&gt;Learn to Design and Animate in 3D with Zdog&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Plot Charts in Python with Matplotlib
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;You generate a huge amount of data on a daily basis. A critical part of data analysis is visualization. A variety of graphing tools have developed over the past few years. Given the popularity of Python as a language for data analysis, this tutorial focuses on creating graphs using a popular Python library — Matplotlib.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;➤ &lt;a href="https://www.sitepoint.com/plot-charts-python-matplotlib/"&gt;Read How to Plot Charts in Python with Matplotlib&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4 Signs It’s a Bad Idea to Quit Your Job
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Edwarden, a developer and StackExchange user, wanted advice. His boss yelled at him for requesting a promotion in the future. Or more specifically, asking for advice on the best process for receiving a promotion. Edwarden exceeded his manager’s expectations. Other managers were also very happy with his performance as well. His manager also knew what Edwarden wanted to discuss ahead of time. It didn’t matter.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;➤ Read &lt;a href="https://www.sitepoint.com/4-signs-its-a-bad-idea-to-quit-your-job/"&gt;4 Signs It’s a Bad Idea to Quit Your Job&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  10+ Top Vue.js Tools &amp;amp; Libraries
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Vue continues to grow in popularity and is rapidly being adopted by many developers, and Vue.js tools are popping up everywhere. This is not without reason: Vue’s shallow learning curve, clear functionality-driven structure, and excellent documentation make it easy for novices to pick it up, and for more experienced developers to make a switch from other frameworks like React or Angular.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;➤ Read &lt;a href="https://www.sitepoint.com/vue-js-tools-libraries/"&gt;10+ Top Vue.js Tools &amp;amp; Libraries&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  An Introduction to Cloudflare Workers
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Cloud computing in its various incarnations — SaaS, PaaS, IaaS — has had big successes. Some of us still recall the $212 million purchase of PaaS provider Heroku in 2010, which at that time was — architecturally speaking — little more than a high-level deployment layer. It had a very posh gem for smooth and easy deployment of apps and frameworks like RoR, Python or Node apps running on Amazon’s infrastructure. The concept of Serverless Computing was born.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;➤ Read &lt;a href="https://www.sitepoint.com/cloudflare-workers/"&gt;An Introduction to Cloudflare Workers&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A Beginner’s Guide to Feathers.js
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Feathers is built on top of Express, a minimalist web framework for Node.js. If you’ve completed the tutorials demonstrated in the links, you’ll realize that it’s quite tiring building RESTful APIs using just Express. With Feathers, most of the repetitive work is already done for you. You only need to focus on configuring and customizing code. Let’s dive into the code and learn how this web framework works.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;➤ Read &lt;a href="https://www.sitepoint.com/feathers-js-guide/"&gt;A Beginner’s Guide to Feathers.js&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Premium Previews
&lt;/h2&gt;

&lt;p&gt;We've also released a number of extracts from SitePoint Premium for free on the blog. Check them out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.sitepoint.com/pusher-vue-real-time-chat-app/"&gt;Build a Real-time Chat App with Pusher and Vue.js&lt;/a&gt; by Michael Wanyoike&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sitepoint.com/vue-components-intro/"&gt;A Beginner’s Guide to Working With Components in Vue&lt;/a&gt; by Kingsley Silas&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sitepoint.com/best-design-handoff-tools/"&gt;8 of the Best Design Handoff Tools&lt;/a&gt; by Daniel Schwarz&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sitepoint.com/headless-cms-vue/"&gt;How to Build a Vue Front End for a Headless CMS&lt;/a&gt; by Michael Wanyoike&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it for this month. If you're looking for more, check out &lt;a href="https://dev.to/sitepointdotcom/5-development-articles-from-sitepoint-june-2890"&gt;our June roundup&lt;/a&gt;. Let us know what you'd like to see more of in the comments!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>design</category>
      <category>vue</category>
    </item>
    <item>
      <title>📚 5 development articles from SitePoint - June</title>
      <dc:creator>SitePoint</dc:creator>
      <pubDate>Mon, 01 Jul 2019 05:25:31 +0000</pubDate>
      <link>https://dev.to/sitepointdotcom/5-development-articles-from-sitepoint-june-2890</link>
      <guid>https://dev.to/sitepointdotcom/5-development-articles-from-sitepoint-june-2890</guid>
      <description>&lt;p&gt;We've been working hard to provide developers with useful knowledge and unique viewpoints on SitePoint, and would love to show you some of our top articles from June.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Replace Redux with React Hooks and the Context API
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;"The most popular way for handling shared application state in React is using a framework such as Redux. Quite recently, the React team introduced several new features which include React Hooks and the Context API. These two features effectively eliminated a lot of challenges that developers of large React projects have been facing. One of the biggest problems was ‘prop drilling’ which was common with nested components. The solution was to use a state management library like Redux. This unfortunately came with the expense of writing boilerplate code — but now, it’s possible to replace Redux with React Hooks and the Context API.&lt;/p&gt;

&lt;p&gt;In this article, you are going to learn a new way of handling state in your React projects, without writing excessive code or installing a bunch of libraries — as is the case with Redux. React hooks allows you to use local state inside of function components, while the Context API allows you to share state with other components."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;➤ Read &lt;a href="https://www.sitepoint.com/replace-redux-react-hooks-context-api/"&gt;How to Replace Redux with React Hooks and the Context API&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  10 Top Chrome Extensions for Your Web Development Workflow
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;"As web developers we work in a very fast paced industry and staying on top of things can sometimes be a challenge. That’s why I believe we should take full advantage of whatever tools we have at our disposal to help keep our heads above water. Today I’m going to present ten Chrome extensions that are geared to optimizing your web development workflow, hopefully making you that little bit more productive."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;➤ Read &lt;a href="https://www.sitepoint.com/10-top-chrome-extensions-for-your-web-development-workflow/"&gt;10 Top Chrome Extensions for Your Web Development Workflow&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  7 Worst UX Mistakes Limiting Your Growth
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;"Growth is often the top focus for businesses that are “onto something.” They’ve found what makes customers tick, their special recipe, and now they’re ready for the world to see.&lt;/p&gt;

&lt;p&gt;However, scaling doesn’t only scale success.&lt;/p&gt;

&lt;p&gt;If there’s friction in the UX, bugs, technical limitations, or any other types of UX flaws, these flaws are magnified as a product scales, which is why the most successful businesses are the ones that take their time and try not to grow too rapidly."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;➤ Read &lt;a href="https://www.sitepoint.com/worst-ux-mistakes/"&gt;7 Worst UX Mistakes Limiting Your Growth&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Set Up a Mobile Development Environment
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;"The use of mobile devices has increased considerably in the past decade. It has been over two years since mobile browsing took over desktop. The usability of mobile devices has exploded, too. Mobile devices now come with huge processing power.&lt;/p&gt;

&lt;p&gt;We often dismiss mobile platforms as serious workhorses for developers, but today, it’s possible to take advantage of mobile portability with a level of flexibility that gets closer to the desktop every year.&lt;/p&gt;

&lt;p&gt;This post explains the process of running a Linux development environment from your mobile device using Samsung Dex."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;➤ Read &lt;a href="https://www.sitepoint.com/mobile-development-environment/"&gt;How to Set Up a Mobile Development Environment&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Get Started with Vuetify
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;"In this article, you will learn how you can quickly build an attractive and interactive frontend very quickly using Vuetify. Building a friendly application interface with a great user experience is a skill that requires practice and knowledge. While Vuetify won’t make you a skilled UX practitioner overnight, it will help provide a solid start to those who are new in this area."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;➤ Read &lt;a href="https://www.sitepoint.com/get-started-vuetify/"&gt;How to Get Started with Vuetify&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Premium Previews
&lt;/h2&gt;

&lt;p&gt;We've also released a number of extracts from SitePoint Premium for free on the blog. Check them out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.sitepoint.com/content-as-ux-building-a-more-human-web/"&gt;Content as UX: Building a More Human Web&lt;/a&gt; by Georgina Laidlaw&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sitepoint.com/user-research-methods-deep-dive/"&gt;A Deep Dive into User Research Methods&lt;/a&gt; by Mark Seabridge&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sitepoint.com/how-analytics-helped-solve-a-ux-issue/"&gt;How Analytics Helped Solve a UX Issue&lt;/a&gt; by Daniel Schwarz&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sitepoint.com/vuex-beginner-guide/"&gt;Getting Started with Vuex: a Beginner’s Guide&lt;/a&gt; by Michael Wanyoike&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sitepoint.com/vue-cli-intro/"&gt;A Beginner’s Guide to Vue CLI&lt;/a&gt; by Ahmed Bouchefra&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sitepoint.com/mind-mapping-tools-for-designers/"&gt;The 9 Best Mind Mapping Tools for Designers&lt;/a&gt; by Daniel Schwarz&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it for this month. If you're looking for more, check out &lt;a href="https://hashnode.com/post/7-development-articles-from-sitepoint-may-cjw9wz5m3000anss10c8u3t87"&gt;our May roundup&lt;/a&gt;. Let us know what you'd like to see more of in the comments!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>redux</category>
      <category>vue</category>
    </item>
    <item>
      <title>📚 7 development articles from SitePoint - May</title>
      <dc:creator>SitePoint</dc:creator>
      <pubDate>Thu, 30 May 2019 00:20:53 +0000</pubDate>
      <link>https://dev.to/sitepointdotcom/7-development-articles-from-sitepoint-may-26n0</link>
      <guid>https://dev.to/sitepointdotcom/7-development-articles-from-sitepoint-may-26n0</guid>
      <description>&lt;p&gt;We've been working hard to provide developers with useful knowledge and unique viewpoints on SitePoint, and would love to show you some of our top articles from May.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.sitepoint.com/introduction-to-nest-js-for-angular-developers/?utm_source=bookmarksites&amp;amp;utm_medium=devto"&gt;Introduction to Nest.js for Angular Developers&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;We introduce Nest.js for Angular developers. Nest is a progressive Node framework, written in TypeScript and sharing many concepts with Angular.&lt;/p&gt;

&lt;p&gt;Read &lt;a href="https://www.sitepoint.com/introduction-to-nest-js-for-angular-developers/?utm_source=bookmarksites&amp;amp;utm_medium=devto"&gt;Introduction to Nest.js for Angular Developers&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.sitepoint.com/collaborative-coding-tools-for-remote-pair-programming?utm_source=bookmarksites&amp;amp;utm_medium=devto"&gt;6 Collaborative Coding Tools for Remote Pair Programming&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Whether you work on a distributed team or just have the occasional problem-solving session with a friend, you'll find a remote pair programming tool here.&lt;/p&gt;

&lt;p&gt;Read &lt;a href="https://www.sitepoint.com/collaborative-coding-tools-for-remote-pair-programming?utm_source=bookmarksites&amp;amp;utm_medium=devto"&gt;6 Collaborative Coding Tools for Remote Pair Programming&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.sitepoint.com/explore-graphql-with-apollo-react/?utm_source=bookmarksites&amp;amp;utm_medium=devto"&gt;Explore GraphQL with Apollo &amp;amp; React: Build a Superhero Database&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;We shed some light on what GraphQL is and give you an opportunity for some hands-on experience with Apollo and React.&lt;/p&gt;

&lt;p&gt;Read &lt;a href="https://www.sitepoint.com/explore-graphql-with-apollo-react/?utm_source=bookmarksites&amp;amp;utm_medium=devto"&gt;Explore GraphQL with Apollo &amp;amp; React: Build a Superhero Database&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.sitepoint.com/best-javascript-charting-libraries/?utm_source=bookmarksites&amp;amp;utm_medium=devto"&gt;18+ JavaScript Libraries for Creating Beautiful Charts&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Learn about 18+ JavaScript libraries for creating charts and graphs — from heavy-duty libraries like D3.js to simple options for representing data quickly and beautifully.&lt;/p&gt;

&lt;p&gt;Read &lt;a href="https://www.sitepoint.com/best-javascript-charting-libraries/?utm_source=bookmarksites&amp;amp;utm_medium=devto"&gt;18+ JavaScript Libraries for Creating Beautiful Charts&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.sitepoint.com/how-to-launch-a-side-project-from-zero/?utm_source=bookmarksites&amp;amp;utm_medium=devto"&gt;How to Launch a Side Project from Zero&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Amie Chen shares the lessons she has learned from building her own products, and shows you how to launch a side project.&lt;/p&gt;

&lt;p&gt;Read &lt;a href="https://www.sitepoint.com/how-to-launch-a-side-project-from-zero/?utm_source=bookmarksites&amp;amp;utm_medium=devto"&gt;How to Launch a Side Project from Zero&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.sitepoint.com/why-the-highest-paid-developers-fight-their-coworkers/?utm_source=bookmarksites&amp;amp;utm_medium=devto"&gt;Why the Highest Paid Developers “Fight” Their Coworkers&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;At some point, if it hasn't happened already, your coworkers or your boss will ask you to do something foolish.&lt;/p&gt;

&lt;p&gt;Read &lt;a href="https://www.sitepoint.com/why-the-highest-paid-developers-fight-their-coworkers/?utm_source=bookmarksites&amp;amp;utm_medium=devto"&gt;Why the Highest Paid Developers “Fight” Their Coworkers&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.sitepoint.com/build-a-desktop-application-with-electron-and-angular/?utm_source=bookmarksites&amp;amp;utm_medium=devto"&gt;Build a Desktop Application with Electron and Angular&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;In this tutorial we’ll build a cross-platform desktop application with Electron and web technologies such as TypeScript and Angular.&lt;/p&gt;

&lt;p&gt;Read &lt;a href="https://www.sitepoint.com/build-a-desktop-application-with-electron-and-angular/?utm_source=bookmarksites&amp;amp;utm_medium=devto"&gt;Build a Desktop Application with Electron and Angular&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Premium Previews
&lt;/h2&gt;

&lt;p&gt;We've also released a number of extracts from SitePoint Premium for free on the blog. Check them out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.sitepoint.com/a-beginners-guide-to-pug/?utm_source=bookmarksites&amp;amp;utm_medium=devto"&gt;A Beginner’s Guide to Pug&lt;/a&gt; by James Hibbard&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sitepoint.com/webpack-beginner-guide/?utm_source=bookmarksites&amp;amp;utm_medium=devto"&gt;A Beginner's Guide to Webpack&lt;/a&gt; by Ivaylo Gerchev&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sitepoint.com/build-vue-chrome-extension/?utm_source=bookmarksites&amp;amp;utm_medium=devto"&gt;How to Build a Chrome Extension with Vue&lt;/a&gt; by James Hibbard&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it for this month. If you're looking for more, check out &lt;a href="https://dev.to/jfalconer/5-development-articles-from-sitepoint-april-5hhh"&gt;our April roundup&lt;/a&gt;. Let us know what you'd like to see more of in the comments!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>angular</category>
      <category>react</category>
      <category>career</category>
    </item>
    <item>
      <title>Why the Highest Paid Developers “Fight” Their Coworkers</title>
      <dc:creator>SitePoint</dc:creator>
      <pubDate>Wed, 22 May 2019 04:19:36 +0000</pubDate>
      <link>https://dev.to/sitepointdotcom/why-the-highest-paid-developers-fight-their-coworkers-549a</link>
      <guid>https://dev.to/sitepointdotcom/why-the-highest-paid-developers-fight-their-coworkers-549a</guid>
      <description>&lt;p&gt;You're going to be asked to do it.&lt;/p&gt;

&lt;p&gt;At some point, if it hasn't happened already, your coworkers or your boss will ask you to do something foolish. Something &lt;em&gt;you know&lt;/em&gt; will make things worse for you, your coworkers, maybe even the business itself.&lt;/p&gt;

&lt;p&gt;If you're like most developers, you do it anyway.&lt;/p&gt;

&lt;p&gt;That's what most will do, right? It's better to keep your head down, avoid making waves and simply do what you're told. Job security isn't a thing anymore, but that's one of the best things you can do to keep your job, for a while at least.&lt;/p&gt;

&lt;h2&gt;
  
  
  This Common Mistake Creates a Career Handicap
&lt;/h2&gt;

&lt;p&gt;This is the problem.&lt;/p&gt;

&lt;p&gt;Most employees want to keep their jobs and their clients. They don't have the leverage or control they want over their own careers. &lt;em&gt;They need their job&lt;/em&gt;. In fact, most people are terrified of losing their jobs.&lt;/p&gt;

&lt;p&gt;This has a cascading effect.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://phys.org/news/2012-02-job-loss-dissatisfaction-lack-commitment.html"&gt;Research shows&lt;/a&gt; the fear of losing your job creates job dissatisfaction and a lack of commitment at work. This, in turn, affects job performance, negatively increasing the likelihood that you will lose your job. It's a &lt;a href="https://en.wikipedia.org/wiki/Virtuous_circle_and_vicious_circle"&gt;vicious cycle&lt;/a&gt; that seems to repeat itself over and over.&lt;/p&gt;

&lt;p&gt;But there's something worse than the fear of a job loss.&lt;/p&gt;

&lt;p&gt;It's the &lt;em&gt;misplaced&lt;/em&gt; confidence or expectation of job security, the kind of confidence that crushes you when you're actually let go. Both of these issues are a problem, and both of these issues are continually ignored.&lt;/p&gt;

&lt;p&gt;Why is it a problem?&lt;/p&gt;

&lt;p&gt;Because &lt;a href="https://www.forbes.com/sites/zackfriedman/2019/01/11/live-paycheck-to-paycheck-government-shutdown/#3db1bad74f10"&gt;78 percent of employees&lt;/a&gt; live paycheque-to-paycheque. This includes workers making $100,000+ per year. This is the real reason why most employees have no leverage, no ability to say no. This is the reason most developers won't fight with their coworkers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Developers Need to Fight Their Coworkers
&lt;/h2&gt;

&lt;p&gt;What do I mean by "fight?"&lt;/p&gt;

&lt;p&gt;I'm talking about the ability to explicitly confront anyone, regardless of status, about their poor behavior. At some point, you'll be asked to do something you know is wrong. It isn't always a moral issue, sometimes it's a logistics or planning issue. Other times it a performance issue. Here are a few examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  You're asked to do something questionable&lt;/li&gt;
&lt;li&gt;  You're instructed to subtly alter or manipulate your end-users&lt;/li&gt;
&lt;li&gt;  Your boss or a coworker requests work that will break something somewhere else&lt;/li&gt;
&lt;li&gt;  Your boss or coworker requests work that comes with negative consequences in the future&lt;/li&gt;
&lt;li&gt;  You're told to ignore, reject or avoid a problem that needs immediate attention&lt;/li&gt;
&lt;li&gt;  You're asked to cover up a problem or minimize a mistake as a personal favor to someone else&lt;/li&gt;
&lt;li&gt;  You're implicitly expected to side with a boss' or coworker's bad idea&lt;/li&gt;
&lt;li&gt;  You'll be expected to push out shoddy or low quality work to meet a pressing deadline&lt;/li&gt;
&lt;li&gt;  You'll be asked to promise something everyone knows you can't (or shouldn't) deliver&lt;/li&gt;
&lt;li&gt;  You'll be pushed into situations where you're expected to choose between two very bad outcomes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Okay then, how do I expect developers to "fight?"&lt;/p&gt;

&lt;p&gt;Most of the time your conscience tells you. You know when you're supposed to speak up in some capacity, whether it's for yourself or for others. You also know how you feel when you don't.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fighting could be as simple as:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://www.sitepoint.com/why-the-highest-paid-developers-fight-their-coworkers/?utm_source=bookmarkingsites&amp;amp;utm_medium=devto"&gt;Continue reading this article by Andrew McDermott on SitePoint.&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>career</category>
    </item>
    <item>
      <title>How to Build Runnable JavaScript Specifications</title>
      <dc:creator>SitePoint</dc:creator>
      <pubDate>Tue, 21 May 2019 00:17:09 +0000</pubDate>
      <link>https://dev.to/sitepointdotcom/how-to-build-runnable-javascript-specifications-2nlk</link>
      <guid>https://dev.to/sitepointdotcom/how-to-build-runnable-javascript-specifications-2nlk</guid>
      <description>&lt;p&gt;&lt;a href="https://www.sitepoint.com/runnable-javascript-specifications/?utm_source=bookmarkingsites&amp;amp;utm_medium=devto"&gt;By James Kolce. Originally published on SitePoint.&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Programming is not only about giving the computer instructions about how to accomplish a task, it’s also about communicating ideas in a precise way with other people, or even to your future self. Such communication can have multiple goals, maybe to share information or just to allow easier modifications—it’s hard to change something if you don’t understand it or if you don’t remember what you did long time ago. Documentation is key, either as simple comments in your code or as whole documents describing the overall functionality of a program.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--M9hcK30x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://d2mxuefqeaa7sj.cloudfront.net/s_818F7181A681401E9CD6F5EECD5F95BEA237B640D6600304108D1E06F6DEDED2_1552627146225_carbon.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M9hcK30x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://d2mxuefqeaa7sj.cloudfront.net/s_818F7181A681401E9CD6F5EECD5F95BEA237B640D6600304108D1E06F6DEDED2_1552627146225_carbon.png" alt="A Simple JavaScript Specification File"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we write software we also need to make sure that the code has the intended functionality. While there are &lt;a href="https://bit.ly/2En14ZJ"&gt;formal methods to define semantics&lt;/a&gt;, the easiest and quickest (but less rigorous) way is to put that functionality into use and see if it produces the expected results.&lt;/p&gt;

&lt;p&gt;Most developers are familiar with these practices: code documentation as comments to make explicit the goal of a block of code, and a series of tests to make sure functions give the desired output.&lt;/p&gt;

&lt;p&gt;But usually documentation and testing are done in different steps. By unifying these practices, we can offer a better experience for anyone involved in the development of a project. This article explores a simple implementation of a program to run JavaScript specifications that work for both documentation and testing.&lt;/p&gt;

&lt;p&gt;We are going to build a command-line interface that finds all the specification files in a directory, extracts all the assertions found inside each specification and evaluates their result, finally showing the results of which assertions failed and which ones passed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Specification Format
&lt;/h2&gt;

&lt;p&gt;Each specification file will export a single string from a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals."&gt;template literal&lt;/a&gt;. The first line can be taken as the title of the specification. The template literal will allow us to embed JS expressions between the string and each expression will represent an assertion. To identify each assertion we can start the line with a distinctive character, in this case, we can use the combination of the bar character (&lt;code&gt;|&lt;/code&gt;) and a dash (&lt;code&gt;-&lt;/code&gt;), which resembles a &lt;a href="https://en.wikipedia.org/wiki/Turnstile_(symbol)"&gt;turnstile symbol&lt;/a&gt; that can sometimes be found as a symbolic representation for logical assertions.&lt;/p&gt;

&lt;p&gt;The following is an example with some explanations of its use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;dependency&lt;/span&gt; &lt;span class="o"&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;./dependency&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&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="s2"&gt;`
  Example of a Specification File

  This project allows to test JavaScript programs using specification files.
  Every *.spec.js file exports a single template literal that includes a general
  explanation of the file being specified. Each file represents a logical
  component of a bigger system. Each logical component is composed of several
  units of functionality that can be tested for certain properties.
  Each one of this units of functionality may have one or more
  assertions. Each assertion is denoted by a line as the following:

  |- &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; The dependency has been loaded and the first assert has
  been evaluated.

  Multiple assertions can be made for each file:

  |- &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="s2"&gt; This assertion will fail.

  |- &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; This assertion will succeed.

  The combination of | and - will form a Turnstile ligature (|-) using the appropriate
  font. Fira Code is recommended. A Turnstile symbol was used by Gottlob Frege
  at the start of sentenses being asserted as true.

  The intended usage is for specification-first software. Where the programmer
  defines the high level structure of a program in terms of a specification,
  then progressively builds the parts conforming that specification until all
  the tests are passed. A desired side-effect is having a simple way to generate
  up-to-date documentation outside the code for API consumers.
`&lt;/span&gt;

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



&lt;p&gt;Now let's proceed with the high level structure of our program.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Structure of Our Program
&lt;/h2&gt;

&lt;p&gt;The whole structure of our program can be defined in a few lines of code, and without any dependencies other than two Node.js libraries to work with the filesystem (&lt;code&gt;fs&lt;/code&gt;) and directory paths (&lt;code&gt;path&lt;/code&gt;). In this section we define just the structure of our program, function definitions will come in the next sections.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cp"&gt;#!/usr/bin/env node
&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="o"&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;fs&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;path&lt;/span&gt; &lt;span class="o"&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;path&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;specRegExp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;spec&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;js$/&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;// Get all the specification file paths&lt;/span&gt;
&lt;span class="c1"&gt;// If a specification file is provided then just test that file&lt;/span&gt;
&lt;span class="c1"&gt;// Otherwise find all the specification files in the target directory&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;specRegExp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;findSpecifications&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;specRegExp&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Get the content of each specification file&lt;/span&gt;
&lt;span class="c1"&gt;// Get the assertions of each specification file&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assertionGroups&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getAssertions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getSpecifications&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;// Log all the assertions&lt;/span&gt;
&lt;span class="nx"&gt;logAssertions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;assertionGroups&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Check for any failed assertions and return an appropriate exit code&lt;/span&gt;
&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exitCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;checkAssertions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;assertionGroups&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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



&lt;p&gt;Because this is also the entry point of our &lt;a href="https://en.wikipedia.org/wiki/Command-line_interface"&gt;CLI&lt;/a&gt; (&lt;em&gt;command-line interface&lt;/em&gt;), we need to add the first line, the &lt;a href="https://en.wikipedia.org/wiki/Shebang_(Unix)"&gt;shebang&lt;/a&gt;, that indicates that this file should be executed by the &lt;code&gt;node&lt;/code&gt; program. There is no need to add a specific library to handle the command options, since we are only interested in a single parameter. However, you may consider other options if you plan to extend this program in a considerable manner.&lt;/p&gt;

&lt;p&gt;To get the target testing file or directory, we have to &lt;em&gt;join&lt;/em&gt; the path where the command was executed (using &lt;code&gt;process.cwd()&lt;/code&gt;) with the argument provided by the user as the first argument when executing the command (using &lt;code&gt;process.argv[2]&lt;/code&gt;). You can find a reference to these values in the Node.js documentation for &lt;a href="https://nodejs.org/docs/latest/api/process.html"&gt;the process object&lt;/a&gt;. In this way we obtain the absolute path of the target directory/file.&lt;/p&gt;

&lt;p&gt;Now, the first thing that we have to do is to find all the JavaScript specification files. As seen in line 12, we can use the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator"&gt;conditional operator&lt;/a&gt; to provide more flexibility: if the user provides a specification file as the target then we just use that file path directly, otherwise, if the user provides a directory path then we have to find all the files that match our pattern as defined by the &lt;code&gt;specRegExp&lt;/code&gt; constant, we do this using a &lt;code&gt;findSpecifications&lt;/code&gt; function that we will define later. This function will return an array of paths for each specification file in the target directory.&lt;/p&gt;

&lt;p&gt;In line 18 we are defining the &lt;code&gt;assertionGroups&lt;/code&gt; constant as the result of combining two functions &lt;code&gt;getSpecifications()&lt;/code&gt; and &lt;code&gt;getAssertions()&lt;/code&gt;. First we get the content of each specification file and then we extract the assertions from them. We will define those two functions later, for now just note that we use the output of the first function as the parameter of the second one, thus simplifying the procedure and making a direct connection between those two functions. While we could have just one function, by splitting them, we can get a better overview of what is the actual process, remember that a program should be clear to understand; just making it work is not enough.&lt;/p&gt;

&lt;p&gt;The structure of the &lt;code&gt;assertionsGroup&lt;/code&gt; constant would be as follows:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;assertionGroup[specification][assertion]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next, we log all those assertions to the user as a way to report the results using a &lt;code&gt;logAssertions()&lt;/code&gt; function. Each assertion will contain the result (&lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;) and a small description, we can use that information to give a special color for each type of result.&lt;/p&gt;

&lt;p&gt;Finally, we define the &lt;a href="https://nodejs.org/docs/latest/api/process.html#process_process_exitcode"&gt;exit code&lt;/a&gt; depending on the results of the assertions. This gives the process information about how the program ended: &lt;em&gt;was the process successful or something failed?&lt;/em&gt;. An exit code of &lt;code&gt;0&lt;/code&gt; means that the process exited successfully, or &lt;code&gt;1&lt;/code&gt; if something failed, or in our case, when &lt;em&gt;at least one&lt;/em&gt; assertion failed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding All the Specification Files
&lt;/h2&gt;

&lt;p&gt;To find all the JavaScript specification files we can use a recursive function that traverses the directory indicated by the user as a parameter to the CLI. While we search, each file should be checked with the regular expression that we defined at the beginning of the program (&lt;code&gt;/\.spec\.js$/&lt;/code&gt;), which is going to match all file paths ending with &lt;code&gt;.spec.js&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;findSpecifications&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;matchPattern&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;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;matchPattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;isFile&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;Our &lt;code&gt;findSpecifications&lt;/code&gt; function takes a target directory (&lt;code&gt;dir&lt;/code&gt;) and a regular expression that identifies the specification file (&lt;code&gt;matchPattern&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting the Contents of Each Specification
&lt;/h2&gt;

&lt;p&gt;Since we are exporting template literals, getting the content and the evaluated assertions is simple, we have to import each file and when it gets imported all the assertions get evaluated automatically.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getSpecifications&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paths&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;paths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&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;Using the &lt;code&gt;map()&lt;/code&gt; function we replace the path of the array with the content of the file using the node’s &lt;code&gt;require&lt;/code&gt; function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extracting the Assertions from the Text
&lt;/h2&gt;

&lt;p&gt;At this point we have an array with the contents of each specification file and their assertions already evaluated. We use the turnstile indicator (&lt;code&gt;|-&lt;/code&gt;) to find all those assertions and extract them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getAssertions&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;specifications&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;specifications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;specification&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;specification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;assertions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;specification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt; |&lt;/span&gt;&lt;span class="se"&gt;\t)&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;(\|&lt;/span&gt;&lt;span class="sr"&gt;-&lt;/span&gt;&lt;span class="se"&gt;)(&lt;/span&gt;&lt;span class="sr"&gt;.|&lt;/span&gt;&lt;span class="se"&gt;\n)&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;?\.&lt;/span&gt;&lt;span class="sr"&gt;/gm&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;assertion&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assertionFragments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;(?:\|&lt;/span&gt;&lt;span class="sr"&gt;-&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt; &lt;/span&gt;&lt;span class="se"&gt;(\w&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt; &lt;/span&gt;&lt;span class="se"&gt;((?:&lt;/span&gt;&lt;span class="sr"&gt;.|&lt;/span&gt;&lt;span class="se"&gt;\n)&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;assertion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;assertionFragments&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;assertionFragments&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sr"&gt; /&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="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;This function will return a similar array, but replacing the content of each specification with an object following this structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  title: &amp;lt;String: Name of this particular specification&amp;gt;,
  assertions: [
    {
      value: &amp;lt;Boolean: The result of the assertion&amp;gt;,
      description: &amp;lt;String: The short description for the assertion&amp;gt;
    }
  ]
}

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



&lt;p&gt;The &lt;code&gt;title&lt;/code&gt; is set with the first line of the specification string. Then each assertion is stored as an array in the &lt;code&gt;assertions&lt;/code&gt; key. The &lt;code&gt;value&lt;/code&gt; represents the result of the assertion as a &lt;em&gt;Boolean&lt;/em&gt;. We will use this value to know if the assertion was successful or not. Also, the description will be shown to the user as a way to identify which assertions succeeded and which ones failed. We use regular expressions in each case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Logging Results
&lt;/h2&gt;

&lt;p&gt;The array that we have built along the program now has a series of JavaScript specification files containing a list of found assertions with their result and description, so there is not much to do other than reporting the results to the user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;logAssertions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;assertionGroups&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Methods to log text with colors&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ansiColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`\x1b[1m\x1b[34m&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\x1b[39m\x1b[22m`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;green&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`\x1b[32m  ✔  &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\x1b[39m`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;red&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`\x1b[31m  ✖  &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\x1b[39m`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Log the results&lt;/span&gt;
  &lt;span class="nx"&gt;assertionGroups&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;group&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;ansiColor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nx"&gt;group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assertions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;assertion&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;assertion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;ansiColor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;green&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;assertion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ansiColor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;red&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;assertion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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



&lt;p&gt;We can format our input with colors depending on the results. To show colors on the terminal we need to add &lt;a href="https://en.wikipedia.org/wiki/ANSI_escape_code"&gt;ANSI escape codes&lt;/a&gt;. To simplify their usage in the next block we have saved each color as methods of an &lt;code&gt;ansiColor&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;First we want to show the title of the specification, remember that we are using the first dimension of the array for each specification, which we have named it as a &lt;code&gt;group&lt;/code&gt; (of assertions.) Then we log all the assertions depending on their value using their respective color: green for assertions that evaluated as &lt;code&gt;true&lt;/code&gt; and red for assertions that had another value. Note the comparison, we are checking for &lt;code&gt;true&lt;/code&gt;, &lt;strong&gt;as a string&lt;/strong&gt;, since we are receiving strings from each file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checking Results
&lt;/h2&gt;

&lt;p&gt;Finally, the last step is to check if all the tests were successful or not.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;checkAssertions&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;assertionGroups&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;assertionGroups&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;group&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assertions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;assertion&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;assertion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;false&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="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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



&lt;p&gt;We check every assertion group (specification) to see if &lt;em&gt;at least one&lt;/em&gt; value is &lt;code&gt;'&lt;/code&gt;&lt;code&gt;false&lt;/code&gt;&lt;code&gt;'&lt;/code&gt; using the &lt;code&gt;some()&lt;/code&gt; method of &lt;code&gt;Array&lt;/code&gt;. We have nested two of them because we have a two dimensional array.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running Our Program
&lt;/h2&gt;

&lt;p&gt;At this point our CLI should be ready to run some JavaScript specifications and see if assertions are picked up and evaluated. In a &lt;code&gt;test&lt;/code&gt; directory you can copy the specification example from the beginning of this article, and paste the following command inside your &lt;code&gt;package.json&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scripts&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node index.js test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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



&lt;p&gt;… where &lt;code&gt;test&lt;/code&gt; is the name of the directory where you have included the sample specification file.&lt;/p&gt;

&lt;p&gt;When running the &lt;code&gt;npm test&lt;/code&gt; command, you should see the results with their respective colors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Last Words
&lt;/h2&gt;

&lt;p&gt;We have implemented a very simple but useful command-line program that can help us to make better software. There are some lessons that we can gain from this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Software can be simple and useful at the same time.&lt;/li&gt;
&lt;li&gt;  We can build our own tools if we want something different, there is no reason to conform.&lt;/li&gt;
&lt;li&gt;  Software is more than “making it work" but also about communicating ideas.&lt;/li&gt;
&lt;li&gt;  Some times we can improve something just by changing the point of view. In this case, the format of the specification files: just a simple string!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An example workflow for this program, would be to place one &lt;code&gt;.spec.js&lt;/code&gt; file per module in your projects, describing in detail the intended functionality and properties that the program should have in form of assertions. You can sketch the idea of a new project in this way, and continuously improve until all the assertions have passed.&lt;/p&gt;

&lt;p&gt;You can find the source code used in this article &lt;a href="https://github.com/KolceBackyard/spec"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
  </channel>
</rss>
