<?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: Harrison Reid</title>
    <description>The latest articles on DEV Community by Harrison Reid (@harrison_codes).</description>
    <link>https://dev.to/harrison_codes</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%2F114904%2F711f20ef-e118-42df-8a59-a05c02179919.jpg</url>
      <title>DEV Community: Harrison Reid</title>
      <link>https://dev.to/harrison_codes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/harrison_codes"/>
    <language>en</language>
    <item>
      <title>👨‍💻 4 Simple Strategies to Auto Promote Your Gatsby Blog</title>
      <dc:creator>Harrison Reid</dc:creator>
      <pubDate>Thu, 02 Jul 2020 22:12:03 +0000</pubDate>
      <link>https://dev.to/harrison_codes/4-simple-strategies-to-auto-promote-your-gatsby-blog-8ke</link>
      <guid>https://dev.to/harrison_codes/4-simple-strategies-to-auto-promote-your-gatsby-blog-8ke</guid>
      <description>&lt;p&gt;&lt;em&gt;I've recently launched a product I've been working on for while: Ippy.io - a better resume builder. It's live on Product Hunt now, so &lt;a href="https://www.producthunt.com/posts/ippy-io"&gt;check it out here&lt;/a&gt; if you're interested 😀&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What you’ll learn:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;How to set up an RSS feed for your Gatsby blog&lt;/li&gt;
&lt;li&gt;How to leverage your RSS feed to automate promotion of your posts&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Consistently creating content is hard enough. So when I’ve finally put the finishing touches on a post, the last thing I feel like is spending time marketing and promoting it.&lt;/p&gt;

&lt;p&gt;I’d much rather have robots do the hard work for me.&lt;/p&gt;

&lt;p&gt;Thankfully, if you’re using Gatsby it’s really not all that hard to set up automations to promote each of your new posts while barely lifting a finger.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The Secret Sauce (RSS!)
&lt;/h2&gt;

&lt;p&gt;RSS? Didn’t that die out a decade back? Not quite!&lt;/p&gt;

&lt;p&gt;Setting up an RSS feed for your blog is the simplest way to enable other third party services to check for new content - which is super handy if you want to leverage such services to run some sort of automation.&lt;/p&gt;

&lt;p&gt;If you’re building a Gatsby site, setting up a fully functional RSS feed couldn’t be easier. In fact, assuming you’re okay with all the default settings and are using markdown, it takes literally a single line of code.&lt;/p&gt;

&lt;p&gt;We’re going to use the offical gatsby-plugin-feed plugin for this, so you’ll want to add it to your project with:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install --save gatsby-plugin-feed&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next you’ll want to add the plugin to your &lt;code&gt;gatsby-config.js&lt;/code&gt; file, which should look something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
  siteMetadata: {
    siteUrl: `https://www.your-site-url.com`,
  },
  plugins: [
    `gatsby-plugin-feed`,
    // ...Other plugins
  ],
  // ...
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The next time you run a production build of your site, you should be able to find your RSS feed available at &lt;code&gt;your-site.com/rss.xml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you run into any problems, or need to customise things further, the plugin is well covered in the official &lt;a href="https://www.gatsbyjs.org/docs/adding-an-rss-feed/"&gt;Gatsby docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Auto Post to Social Media
&lt;/h2&gt;

&lt;p&gt;Now that you’ve got the RSS feed set up, the world is your oyster!&lt;/p&gt;

&lt;p&gt;The simplest integration is to utilise a tool like &lt;a href="https://www.zapier.com"&gt;Zapier&lt;/a&gt; to automatically send updates to your social accounts when you publish a new post.&lt;/p&gt;

&lt;p&gt;Zapier actually has a pretty generous free tier. You get 100 free Zaps per month.&lt;/p&gt;

&lt;p&gt;So, for example, you could set it up to push your newly published article to your Twitter, Facebook and LinkedIn, and if you publish an article every day (good on you!) you’ll still end up with a few Zaps left over at the end of the month.&lt;/p&gt;

&lt;p&gt;I won’t bother with the details of configuring this because honestly Zapier makes it pretty easy.&lt;/p&gt;

&lt;p&gt;You’ll basically just need to select RSS feed as the trigger for the Zap, enter your URL, and then follow their walkthrough process to hook it up to whichever social account you want.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Cross Post Content to Dev.to
&lt;/h2&gt;

&lt;p&gt;Having trouble finding an audience for your content? Cross posting can be a good solution to get some initial readers, and hopefully drive some traffic back to your own site.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/"&gt;Dev.to&lt;/a&gt; is a great option for cross posting; your content gets broadcast to a ready made technical audience who are always friendly, and eager to provide valuable feedback.&lt;/p&gt;

&lt;p&gt;Again, RSS makes this a cinch to set up - just head to your dev.to &lt;code&gt;Settings &amp;gt; Publish from RSS&lt;/code&gt;, and enter the URL of your RSS feed. Hey presto - all your new posts will pop up as drafts in your dashboard, so you can check them, make any adjustments for formatting (often not required), and publish to dev.to.&lt;/p&gt;

&lt;p&gt;Even better, dev.to embeds a link back to your site, and will automatically include your site url as the &lt;code&gt;canonical_url&lt;/code&gt;, which means you shouldn’t see any ‘duplucate content’ SEO penalties from Google.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Generate an Email Newsletter Summary
&lt;/h2&gt;

&lt;p&gt;If you’re interested in allowing users to sign up for a “Newsletter”, then RSS again makes it very very easy to automatically collate your new posts into an email to send out to your subscribers.&lt;/p&gt;

&lt;p&gt;I’m using &lt;a href="https://mailchimp.com/"&gt;MailChimp&lt;/a&gt; for this, however I’ve seen similar functionality offered by other email marketing SAAS providers.&lt;/p&gt;

&lt;p&gt;You just need to find one that works best for you.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>beginners</category>
      <category>webdev</category>
      <category>gatsby</category>
    </item>
    <item>
      <title>How To Add Custom Fields to Your Gatsby RSS Feed</title>
      <dc:creator>Harrison Reid</dc:creator>
      <pubDate>Tue, 30 Jun 2020 22:12:03 +0000</pubDate>
      <link>https://dev.to/harrison_codes/how-to-add-custom-fields-to-your-gatsby-rss-feed-3pp6</link>
      <guid>https://dev.to/harrison_codes/how-to-add-custom-fields-to-your-gatsby-rss-feed-3pp6</guid>
      <description>&lt;p&gt;&lt;em&gt;I've recently launched a product I've been working on for while: Ippy.io - a better resume builder. It's live on Product Hunt now, so &lt;a href="https://www.producthunt.com/posts/ippy-io"&gt;check it out here&lt;/a&gt; if you're interested 😀&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What you’ll learn:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;How to declare custom namespaces on your Gatsby RSS feed&lt;/li&gt;
&lt;li&gt;How to use the namespaces to add custom elements&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What you’ll build:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;An RSS feed with custom data!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ve recently been working on adding up an RSS feed for Days of Dev using &lt;a href="https://www.gatsbyjs.org/packages/gatsby-plugin-feed/"&gt;gatsby-plugin-feed&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While setting this up, I found myself facing a small roadblock; I wanted to add additional custom data to the RSS feed, and couldn’t figure out how to get it working. Specifically, I wanted to add the full text of tweets that I’d auto generate from various frontmatter fields.&lt;/p&gt;

&lt;p&gt;This would allow me to easily post to my social accounts through &lt;a href="https://www.zapier.com"&gt;Zapier&lt;/a&gt; without having to mess around with any complex logic to compose the tweets in Zapier itself (and importantly, let me avoid having to pay for a premium account!).&lt;/p&gt;

&lt;p&gt;It wasn’t immediately clear to me from the Gatsby docs how to get this working, so I thought I’d post this up here in case anyone faces the same problem in the futture!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It’s worth noting it is actually documented, but it’s included &lt;a href="https://www.gatsbyjs.org/docs/adding-an-rss-feed/#syntax-for-itunes-rss-blocks"&gt;under a header explaining how to add iTunes RSS blocks&lt;/a&gt;, which I didn’t pick up on initially.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Key: Namespaces
&lt;/h2&gt;

&lt;p&gt;If you, like me, know next to nothing about RSS, you might’ve assumed that you can just throw any XML into an RSS feed. Well, actually, you pretty much can! But there is a slight catch…&lt;/p&gt;

&lt;p&gt;To add custom elements (with custom data), you need to &lt;em&gt;namespace&lt;/em&gt; them.&lt;/p&gt;

&lt;p&gt;Fortunately, this is reasonably straightforward (particularly because we’re using gatsby-plugin-feed). Basically, it means that in the output XML, you need to declare the namespace, then prefix all of your custom xml tags with the declared namespace.&lt;/p&gt;

&lt;p&gt;For example, in the RSS feed for Days of Dev (available at &lt;a href="https://www.daysof.dev/rss.xml"&gt;daysof.dev/rss.xml&lt;/a&gt;), you’ll see the namespace declaration in the opening &lt;code&gt;&amp;lt;rss&amp;gt;&lt;/code&gt; tag - &lt;code&gt;xmlns:daysofdev="https://www.daysof.dev"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then, when I’ve added custom data, the tag name is always prefixed with the namespace followed by a colon. For example, the tag containing the tweet for a given post is included as: &lt;code&gt;&amp;lt;daysofdev:tweet&amp;gt;Some text...&amp;lt;/daysofdev:tweet&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up gatsby-plugin-feed
&lt;/h2&gt;

&lt;p&gt;Using gatsby-plugin-feed to set up namespaces, and include custom data, is relatively straightforward.&lt;/p&gt;

&lt;p&gt;To start with, follow the instructions in the gatsby docs to &lt;a href="https://www.gatsbyjs.org/docs/adding-an-rss-feed/#how-to-use-gatsby-plugin-feed"&gt;customise the RSS feed plugin&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This should leave you with a gatsby-config.js with a plugin config for gatsby-plugin-feed that looks something like the following. Note that I’ve excluded a number of the option fields here for brevity, so directly copy-pasting the whole snippet will almost certainly cause you problems.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;plugins&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;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`gatsby-plugin-feed`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;feeds&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;serialize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
              &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;allMarkdownRemark&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;allMarkdownRemark&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;edges&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;edge&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                  &lt;span class="p"&gt;{},&lt;/span&gt;
                  &lt;span class="nx"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frontmatter&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;custom_elements&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;content:encoded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&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="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;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;To include a custom element, we need to make two changes:&lt;/p&gt;

&lt;p&gt;Firstly, we need to tell gatsby-plugin-feed about the namespace we wish to declare. This is achieved by adding the &lt;code&gt;setup&lt;/code&gt; option, which extends the options with a &lt;code&gt;custom_namespaces&lt;/code&gt; field. In this example, we’ve added &lt;strong&gt;yournamespace&lt;/strong&gt;. I don’t think the URL value of the is particularly important, as long as it’s unique to your namespace.&lt;/p&gt;

&lt;p&gt;Secondly, we include the custom element under the &lt;code&gt;custom_elements&lt;/code&gt; field in the output of the &lt;code&gt;serialize&lt;/code&gt; function. You can see this added in the example as:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{ "yournamespace:yourcustomfield": edge.node.fields.someField }&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note that the custom element name must use the namespace, followed by a colon.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;plugins&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;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`gatsby-plugin-feed`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;custom_namespaces&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;yournamespace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://www.yournamespace.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="na"&gt;feeds&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;serialize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
              &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;allMarkdownRemark&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;allMarkdownRemark&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;edges&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;edge&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                  &lt;span class="p"&gt;{},&lt;/span&gt;
                  &lt;span class="nx"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frontmatter&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;custom_elements&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;content:encoded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;yournamespace:yourcustomfield&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;someField&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;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;This should be all you need to add arbitrary custom data to your RSS feed generated by gatsby-plugin-feed. When you next deploy your app, you should have the custom data available to make use of wherever your RSS feed is being consumed.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>javascript</category>
    </item>
    <item>
      <title>🤦‍♂️ Cartoonify Yourself!</title>
      <dc:creator>Harrison Reid</dc:creator>
      <pubDate>Sat, 23 May 2020 00:03:13 +0000</pubDate>
      <link>https://dev.to/harrison_codes/cartoonify-yourself-10l8</link>
      <guid>https://dev.to/harrison_codes/cartoonify-yourself-10l8</guid>
      <description>&lt;p&gt;Last week I wrote up a post about how I'd trained a neural network to "cartoonify" pictures of peoples faces.&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/harrison_codes" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--naT4BgVu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--UghzFeO9--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/114904/711f20ef-e118-42df-8a59-a05c02179919.jpg" alt="harrison_codes image"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/harrison_codes/i-trained-a-neural-network-to-turn-you-into-an-archer-cartoon-2hbd" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;🤷‍♂️ How I trained a neural network to turn you into an Archer cartoon  &lt;/h2&gt;
      &lt;h3&gt;Harrison Reid ・ May 14 ・ 4 min read&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#python&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#showdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#machinelearning&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;I also made it available as a twitter bot (so you could tweet at me and have your profile pic cartoonified). I think about 30 or 40 people ended up using it to cartoonify their profile pics, which was a lot of fun 😀&lt;/p&gt;

&lt;p&gt;Anyhow, I'm planning to retire the twitter bot soon (because 💸) - but I've now converted the code to run entirely in the browser using tensorflow.js, and made it available online. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://harrison.codes/cartoonify"&gt;Check it out here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note: Currently doesn't seem to work reliably (or possibly at all) on mobile browsers - working on fixing this. Also, the cartoonifying effect tends to only work on relatively close up pictures of faces (presumably as thats what it was trained on). So feel free to play around with other kinds of images, but the results probably won't be great.*&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>🤷‍♂️ How I trained a neural network to turn you into an Archer cartoon  </title>
      <dc:creator>Harrison Reid</dc:creator>
      <pubDate>Thu, 14 May 2020 14:23:41 +0000</pubDate>
      <link>https://dev.to/harrison_codes/i-trained-a-neural-network-to-turn-you-into-an-archer-cartoon-2hbd</link>
      <guid>https://dev.to/harrison_codes/i-trained-a-neural-network-to-turn-you-into-an-archer-cartoon-2hbd</guid>
      <description>&lt;p&gt;A few weeks back I decided I wanted a cartoon version of my profile picture. &lt;/p&gt;

&lt;p&gt;Sadly, as I'm not much of an artist, drawing it myself was out of the question. So I set about on what seemed the only other logical course of action...&lt;/p&gt;

&lt;p&gt;I trained a neural network to do it for me! &lt;/p&gt;




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

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



&lt;/p&gt;




&lt;p&gt;Let's get this out of the way - if you'd like a cartoon version of &lt;em&gt;your&lt;/em&gt; profile picture, here's how:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tweet at me (&lt;a href="https://twitter.com/harrison_g_reid" rel="noopener noreferrer"&gt;@harrison_g_reid&lt;/a&gt;) and include "cartoonify me" somewhere in the text of the tweet.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Within a few minutes, my (hopefully?) dependable twitter bot will reply with a cartoon-ified version of your profile picture.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;NOTE: Since this was posted, the twitter bot has been disabled because 💸, but I've put it online so you can try it out &lt;a href="https://keen-yonath-ed0e96.netlify.app/cartoonify/" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I should warn you, the results are...mixed. But it's funnier when it does a terrible job anyway, so 🤷‍♂️. Here's a GIF demo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6d4kso9w07dwxprjqwa8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6d4kso9w07dwxprjqwa8.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Read on if you want to learn how I built it...&lt;/p&gt;




&lt;h2&gt;
  
  
  Finding a Model (CartoonGAN):
&lt;/h2&gt;

&lt;p&gt;The first thing I did after deciding that this would be a fun project was google around to see if there were any existing libraries I could use. &lt;/p&gt;

&lt;p&gt;As usual, the open source world did not disappoint! I soon came across a tensorflow implementation of the &lt;a href="http://openaccess.thecvf.com/content_cvpr_2018/papers/Chen_CartoonGAN_Generative_Adversarial_CVPR_2018_paper.pdf" rel="noopener noreferrer"&gt;CartoonGAN&lt;/a&gt; generative adversarial neural network.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/mnicnc404" rel="noopener noreferrer"&gt;
        mnicnc404
      &lt;/a&gt; / &lt;a href="https://github.com/mnicnc404/CartoonGan-tensorflow" rel="noopener noreferrer"&gt;
        CartoonGan-tensorflow
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Generate your own cartoon-style images with CartoonGAN (CVPR 2018), powered by TensorFlow 2.0 Alpha.
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The Github repo has some really cool examples of converting images and gifs into anime style cartoons - I recommend checking it out. &lt;/p&gt;

&lt;p&gt;But this wasn't quite the style I was after. I wanted something a little more comic-book style - heavy black lines &amp;amp; flat colors. I wanted it to look like Archer!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F79r5n6ltx6e6rm5m6r0v.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F79r5n6ltx6e6rm5m6r0v.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fortunately, the repo contains some pretty detailed instructions on how to train the network on your own training data. &lt;/p&gt;

&lt;p&gt;So, I set about gathering &lt;strong&gt;a lot&lt;/strong&gt; of images.&lt;/p&gt;




&lt;h2&gt;
  
  
  Gathering Data:
&lt;/h2&gt;

&lt;p&gt;To train CartoonGAN, I would need two sets of images:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A large set of &lt;em&gt;real life&lt;/em&gt; images of human faces.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An equally large set of cartoon faces (from Archer)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It was &lt;strong&gt;relatively&lt;/strong&gt; easy to find a good dataset of human faces. I found the &lt;a href="http://www.robots.ox.ac.uk/~vgg/data/vgg_face2/" rel="noopener noreferrer"&gt;VGGFace2&lt;/a&gt; face dataset, which is an &lt;strong&gt;enormous&lt;/strong&gt; dataset, and far exceeded my needs.&lt;/p&gt;

&lt;p&gt;Of course, there's no dataset of faces from Archer available, so I'd need to create my own. &lt;/p&gt;

&lt;p&gt;Since I was aiming for a dataset of about 3500 images, there was no way I could realistically do this manually.&lt;/p&gt;

&lt;p&gt;It took a little creativity, but I managed to &lt;em&gt;mostly&lt;/em&gt; automate this. It basically ended up as a four stage process.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Using &lt;a href="https://ffmpeg.org/" rel="noopener noreferrer"&gt;ffmpeg&lt;/a&gt;, extract a frame for every 4 seconds of video, for every episode of the first season of Archer. (If you're interested, the ffmpeg command to do this for a single video is: &lt;code&gt;ffmpeg -i video.mov -r 0.25 video-images/%04d.png&lt;/code&gt;.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Detect the location of all the faces in every frame using &lt;a href="https://www.thregr.org/~wavexx/software/facedetect/#download" rel="noopener noreferrer"&gt;facedetect&lt;/a&gt;. Yes, this works surprisingly well on cartoon faces!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Crop images for each located face using &lt;a href="https://github.com/oliver-moran/jimp" rel="noopener noreferrer"&gt;Jimp&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Manually check the extracted images, and remove all weird things that had incorrectly been identified as faces.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The end result was a set of ~3700 images. Just about every face from the first season of archer:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Faldh62mpszx017dlemnk.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Faldh62mpszx017dlemnk.jpeg" alt="A series of cartoon faces extracted from the show Archer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we're talking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Training the Model:
&lt;/h2&gt;

&lt;p&gt;This was the easy part - it basically involved cloning the the CartoonGAN repo mentioned above, copying the images to the correct directory and running the python script as per the instructions in the repo. &lt;/p&gt;

&lt;p&gt;It was a real workout for my computer though - it took &lt;em&gt;several days&lt;/em&gt; running the training in the background to make it through 30 epochs of training.&lt;/p&gt;

&lt;p&gt;Here's a gif of the training progress over the first few epochs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffrr4prcckmmc7i7dxdfs.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffrr4prcckmmc7i7dxdfs.gif" alt="A gif with 8 faces showing progress in training of the neural network"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Running it on Node:
&lt;/h2&gt;

&lt;p&gt;If you're a JavaScript developer and you haven't tried &lt;a href="https://www.tensorflow.org/js" rel="noopener noreferrer"&gt;TensorFlow.js&lt;/a&gt; yet, get amongst it. You don't really need to know all that much about Machine Learning to make use of existing models, and build some cool stuff.&lt;/p&gt;

&lt;p&gt;In any case, the Node API's for TensorFlow.js let you directly load the format of model output by the CartoonGAN training process (SavedModel format).&lt;/p&gt;

&lt;p&gt;Viola! A cartoon generating neural network running on Node.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;&lt;em&gt;If you're interested in how I've deployed the model as a twitter bot, stay tuned! I'll provide a walkthrough in a future post.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: The code for this isn't yet available on my Github, but will be made available soon.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>python</category>
      <category>showdev</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>✨ How To Start and Finish a Side Project ✨</title>
      <dc:creator>Harrison Reid</dc:creator>
      <pubDate>Sun, 26 Apr 2020 17:07:50 +0000</pubDate>
      <link>https://dev.to/harrison_codes/how-to-start-and-finish-a-side-project-23e8</link>
      <guid>https://dev.to/harrison_codes/how-to-start-and-finish-a-side-project-23e8</guid>
      <description>&lt;p&gt;I've been working on my side project &lt;a href="https://www.ippy.io"&gt;ippy.io&lt;/a&gt; a fair bit recently, and have made good progress on it. I'm happy with the functionality, and it's now available online for people to use.&lt;/p&gt;

&lt;p&gt;For me, this is a success - but I've worked on &lt;em&gt;a lot&lt;/em&gt; of other side projects over the last few years - and none of the rest have ever reached this point. They've always either just fizzled out, or I've become distracted by some new idea and moved on.&lt;/p&gt;

&lt;p&gt;I've been thinking about why I've had so much trouble sticking with side projects in the past, and the changes in attitude that I think have helped me overcome this. &lt;/p&gt;

&lt;p&gt;I posted about this on twitter yesterday, in the form of a (long) tweet thread. I've unrolled it below for ease of consumption. Enjoy!&lt;/p&gt;





&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--fA1RNIq8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1251303860099899393/edqdbjGJ_normal.jpg" alt="Harrison Reid profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Harrison Reid
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @harrison_g_reid
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mL-RlVCA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-95c212266bf9a35c02dd777b6d438dfbc5a6a4c1e82708c3ab617b069928387a.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      ✨How to start and finish a side project (a twitter thread)✨&lt;br&gt;&lt;br&gt;I’ve spent a lot of time over the last few years working on a whole bunch of different side projects. Precisely one (1) has reached a point that I’m happy with. My github is a graveyard where side projects go to die.
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      03:36 AM - 26 Apr 2020
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1254253056150999042" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-reply-action.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1254253056150999042" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-retweet-action.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      0
      &lt;a href="https://twitter.com/intent/like?tweet_id=1254253056150999042" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-like-action.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
      0
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;





&lt;h1&gt;
  
  
  How To Start and Finish a Side Project
&lt;/h1&gt;

&lt;p&gt;I’ve spent a lot of time over the last few years working on a whole bunch of different side projects. Precisely one (1) has reached a point that I’m happy with. My GitHub is a graveyard where side projects go to die. &lt;/p&gt;

&lt;p&gt;I suspect I’m not alone here - a lot of people seem to find finishing their side projects really hard.&lt;/p&gt;

&lt;p&gt;So, how do you make it easier?&lt;/p&gt;

&lt;p&gt;I’ve been thinking about this, particularly in the context of trying to build a project that makes money. These are those thoughts 🤔... &lt;/p&gt;

&lt;h2&gt;
  
  
  👉 Quit fetishizing ideas, embrace unoriginality!
&lt;/h2&gt;

&lt;p&gt;It’s easy to get stuck before you start. You can spend months in a purgatory of ideation - dreaming up the next big thing, and the next! But if all you have are ideas, then you don't really have anything. &lt;/p&gt;

&lt;p&gt;What’s more, a project doesn’t need the potential to be the "Uber of X", or the "AirBnB of Y" to be worthy of your time. You don't need to put a dent in the universe. It’s a perfectly valid to take something that already exists in the world and try to make it better. &lt;/p&gt;

&lt;p&gt;Focus less on disruption, and more on distillation. Work to find the best in existing solutions, and cut away the bad. Less revolution, more refinement.&lt;/p&gt;

&lt;p&gt;With that in mind, here’s a 3 step process to find your next side project! &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Google around for products that exist in a space that you find interesting.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Find a successful product where you think - "Yeah, I could build this".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Build it! &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Don’t steal the design, don’t steal the code, don’t steal the copy. But by all means begin by replicating functionality. Then, improve it. Build a more intuitive UI. Serve a different niche. Make it faster. Make it cheaper. &lt;/p&gt;

&lt;p&gt;Being original is overrated. Google wasn't the first search engine. McDonalds wasn't the first hamburger joint. Facebook wasn't the first social network.&lt;/p&gt;

&lt;p&gt;In reality, the original is almost never the best. So don't put so much focus on being original - focus on being the best! &lt;/p&gt;

&lt;h2&gt;
  
  
  👉 Take it slow.
&lt;/h2&gt;

&lt;p&gt;If you believe in the 80/20 rule, then you can expect 80% of progress on a project to come from 20% of the time spent on it. I don’t know how accurate that is, but I can say for sure that productivity comes in waves. &lt;/p&gt;

&lt;p&gt;So don’t stress the days that you feel like you’re getting nowhere. It’s okay to step away from the computer for a while. Take the day off. Take the week! If you're not feeling it, you're not feeling it. All you're likely to gain by pushing on is a bad mood. &lt;/p&gt;

&lt;p&gt;Overwork is a sure fire way to kill off your excitement and motivation. When it does, it’s only a matter of time before some new, shiny idea pops into your head. You chase the excitement of the fresh idea. The old project is soon forgotten, and the cycle continues. &lt;/p&gt;

&lt;p&gt;Just aim for consistent progress over time, and don’t sacrifice your sanity for the sake of a side project. &lt;/p&gt;

&lt;h2&gt;
  
  
  👉 Redefine what “finishing” means.
&lt;/h2&gt;

&lt;p&gt;If your end goal is to create a business that generates income over the long term, then you should probably stop thinking in terms of “finishing”. In this context, being finished probably means your product failed. &lt;/p&gt;

&lt;p&gt;Take a long view. Accept up front that you’ll be working on this project for many months. It makes it easier to step back for a while when you need a break, and to resist the pesky new ideas that pop up to distract you. &lt;/p&gt;

&lt;p&gt;I’m not saying you can’t move on from a project if it’s just not working out. But you want to be able to look back on it with at least a little pride, knowing that you actually gave it a good shot. This requires a long term approach.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you liked this post, &lt;a href="https://twitter.com/harrison_g_reid"&gt;follow me on twitter!&lt;/a&gt;. I'll be posting about my experiences building ippy.io, and my ongoing attempts to find it some users 😉&lt;/em&gt;&lt;/p&gt;

</description>
      <category>startup</category>
      <category>productivity</category>
      <category>motivation</category>
      <category>javascript</category>
    </item>
    <item>
      <title>2 Examples To Help You Understand JS Closures Once And For All 🙃</title>
      <dc:creator>Harrison Reid</dc:creator>
      <pubDate>Fri, 07 Feb 2020 12:33:11 +0000</pubDate>
      <link>https://dev.to/harrison_codes/2-examples-to-help-you-understand-js-closures-once-and-for-all-3d5</link>
      <guid>https://dev.to/harrison_codes/2-examples-to-help-you-understand-js-closures-once-and-for-all-3d5</guid>
      <description>&lt;p&gt;&lt;em&gt;If you find this post useful, you can follow me on &lt;a href="https://twitter.com/_twosmalltrees"&gt;twitter&lt;/a&gt;, sign up to my &lt;a href="https://www.twosmalltrees.com/mailing-list"&gt;mailing list&lt;/a&gt; or check out the other posts on my &lt;a href="https://www.twosmalltrees.com"&gt;blog&lt;/a&gt;. I've also got a couple of active side projects that you might like to check out:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://www.ippy.io"&gt;ippy.io&lt;/a&gt; - An app for creating beautiful resumes&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://many.tools"&gt;many.tools&lt;/a&gt; - A collection of useful utilities for designers and devs&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Closures are one of the classic “gotchas” in JavaScript. There are countless articles  across the internet describing closures as something you absolutely need to understand to consider yourself a competent developer, or must know before your next job interview, etc etc.&lt;/p&gt;

&lt;p&gt;Don’t get me wrong, understanding closures &lt;strong&gt;is&lt;/strong&gt; very important. The thing is, I think there’s a reasonable chance you already understand them, but just don’t understand that you understand them 😉. But if you don’t, hopefully you will soon. &lt;/p&gt;

&lt;p&gt;It’s just a hunch, but my guess is that a fair bit of the confusion around closures is simply due to terminology. That is, it can take some time to connect unfamiliar words like &lt;strong&gt;”closure”&lt;/strong&gt; and &lt;strong&gt;“lexical scope”&lt;/strong&gt; with behaviour you’ve observed and perhaps already understand in your code.&lt;/p&gt;

&lt;p&gt;Let’s take a look at a relatively straightforward example to test your current understanding.&lt;/p&gt;



&lt;h2&gt;
  
  
  1. Counter
&lt;/h2&gt;

&lt;p&gt;Take a look at the code below, and try to figure out the answers to the two commented questions (without running the code).&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;createCounter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getNext&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;count&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;getNext&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="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// ==&amp;gt; 1. What will this output?&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getNextNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createCounter&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;firstNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getNextNumber&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;secondNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getNextNumber&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;thirdNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getNextNumber&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;fourthNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getNextNumber&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="nx"&gt;firstNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;secondNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;thirdNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;fourthNumber&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// ==&amp;gt; 2. What will this output?&lt;/span&gt;

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



&lt;p&gt;If you answered:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ReferenceError (or if you knew this would be some kind of error)&lt;/li&gt;
&lt;li&gt;1, 2, 3, 4&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Congratulations! You understand closures!&lt;/p&gt;

&lt;p&gt;There are two things you need to grasp from the code above:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;count&lt;/code&gt; variable &lt;strong&gt;is not&lt;/strong&gt; accessible anywhere outside of the &lt;code&gt;createCounter()&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;count&lt;/code&gt; variable &lt;strong&gt;is&lt;/strong&gt; accessible to any functions that are declared &lt;strong&gt;within&lt;/strong&gt; the &lt;code&gt;createCounter()&lt;/code&gt; function (where it was initially declared).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is all that a closure is. Using a function (in our case &lt;code&gt;createCounter()&lt;/code&gt; ) to &lt;strong&gt;close over&lt;/strong&gt; a variable. &lt;/p&gt;

&lt;p&gt;There is no way for the &lt;code&gt;count&lt;/code&gt; variable to be accessed or set from anywhere else in our code, &lt;strong&gt;except&lt;/strong&gt; via the function that we define and return from &lt;code&gt;createCounter()&lt;/code&gt;, the &lt;code&gt;getNext()&lt;/code&gt; function. &lt;/p&gt;

&lt;p&gt;As you can see, &lt;code&gt;getNext()&lt;/code&gt; (since it was declared inside &lt;code&gt;createCounter()&lt;/code&gt;) maintains access to the &lt;code&gt;count&lt;/code&gt; variable, and is able to increment and return it.&lt;/p&gt;

&lt;p&gt;Let’s take a look at a slightly more complex example.&lt;/p&gt;



&lt;h2&gt;
  
  
  2. Election Day
&lt;/h2&gt;

&lt;p&gt;Imagine we’ve been tasked with running an election. It’s a somewhat odd election, as voters will be casting their ballots from our JavaScript console.&lt;/p&gt;

&lt;p&gt;We want a way to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Keep track of the votes&lt;/li&gt;
&lt;li&gt;Allow people to cast votes&lt;/li&gt;
&lt;li&gt;Retrieve the final results (in a secure, password protected way)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We could do something like this (but shouldn’t):&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;var&lt;/span&gt; &lt;span class="nx"&gt;candidateOneVoteCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;candidateTwoVoteCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;voteForCandidateOne&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;candidateOneVoteCount&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;voteForCandidateTwo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;candidateTwoVoteCount&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getResults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inputPassword&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inputPassword&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Wrong password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;candidateOne&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;candidateOneVoteCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;candidateTwo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;candidateTwoVoteCount&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;Since the variables storing the candidates votes are defined in the global scope, anyone casting their vote could sneakily rig our election simply by running &lt;code&gt;candidateTwoVoteCount = 1000000&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We need to keep our vote counts private. We only want it to be possible to change or retrieve these variables via the interface that we’ve defined.  That is, via:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;voteForCandidateOne()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;voteForCandidateTwo()&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;&lt;code&gt;getResults()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How can we achieve this? With a &lt;strong&gt;closure&lt;/strong&gt;.  Let’s refactor the code above to use a closure.&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;createElection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;candidateOneVoteCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;candidateTwoVoteCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;voteForCandidateOne&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;candidateOneVoteCount&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;voteForCandidateTwo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;candidateTwoVoteCount&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getResults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inputPassword&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inputPassword&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Wrong password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;candidateOne&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;candidateOneVoteCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;candidateTwo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;candidateTwoVoteCount&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="p"&gt;{&lt;/span&gt; 
    &lt;span class="nx"&gt;voteForCandidateOne&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="nx"&gt;voteForCandidateTwo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="nx"&gt;getResults&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;voteForCandidateOne&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="nx"&gt;voteForCandidateTwo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="nx"&gt;getResults&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createElection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;candidateOneVoteCount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// ReferenceError&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="nx"&gt;candidateTwoVoteCount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// ReferenceError&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="nx"&gt;getResults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;incorrectPassword&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;// Error: Wrong password&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="nx"&gt;getResults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;// =&amp;gt; { candidateOne: 0, candidateTwo: 0 }&lt;/span&gt;

&lt;span class="nx"&gt;voteForCandidateOne&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;voteForCandidateOne&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;voteForCandidateTwo&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="nx"&gt;getResults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;// =&amp;gt; { candidateOne: 2, candidateTwo: 1 }&lt;/span&gt;

&lt;span class="c1"&gt;// Please never run a real election using code like this.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Our interface functions &lt;code&gt;voteForCandidateOne()&lt;/code&gt;, &lt;code&gt;voteForCandidateTwo()&lt;/code&gt; , &lt;code&gt;getResults()&lt;/code&gt; are now declared within, and returned from &lt;code&gt;createElection()&lt;/code&gt;. As they are declared in the same scope, they maintain access to the variables storing the vote count (&lt;code&gt;candidateOneVoteCount&lt;/code&gt; &amp;amp; &lt;code&gt;candidateTwoVoteCount&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;It’s also worth noting that the functions also maintain access to the &lt;code&gt;password&lt;/code&gt; argument that is provided when &lt;code&gt;createElection()&lt;/code&gt; is called. This is later compared to the password provided in &lt;code&gt;getResults()&lt;/code&gt; to validate access.&lt;/p&gt;




&lt;p&gt;Let me know if anything here is unclear, and I'll do my best to explain it further! 🍻&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>codenewbie</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>3 Simple Snippets to Help You Understand Array .reduce()! 🥳  </title>
      <dc:creator>Harrison Reid</dc:creator>
      <pubDate>Tue, 04 Feb 2020 14:05:21 +0000</pubDate>
      <link>https://dev.to/harrison_codes/3-simple-snippets-to-help-you-understand-array-reduce-1628</link>
      <guid>https://dev.to/harrison_codes/3-simple-snippets-to-help-you-understand-array-reduce-1628</guid>
      <description>&lt;p&gt;&lt;em&gt;If you find this post useful, you can follow me on &lt;a href="https://twitter.com/_twosmalltrees"&gt;twitter&lt;/a&gt;, sign up to my &lt;a href="https://www.twosmalltrees.com/mailing-list"&gt;mailing list&lt;/a&gt; or check out the other posts on my &lt;a href="https://www.twosmalltrees.com"&gt;blog&lt;/a&gt;. I've also got a couple of active side projects that you might like to check out:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://www.ippy.io"&gt;ippy.io&lt;/a&gt; - An app for creating beautiful resumes&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://many.tools"&gt;many.tools&lt;/a&gt; - A collection of useful utilities for designers and devs&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Are you having trouble getting your head around the JS Array &lt;code&gt;.reduce()&lt;/code&gt; method? &lt;/p&gt;

&lt;p&gt;If so, don't worry - you're not alone. For whatever reason, the reduce method seems to take a while to click for many developers. I've been in this boat myself. Fortunately, once you break things down, it's not too complex. &lt;/p&gt;

&lt;p&gt;My aims for this article are to: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Offer what I think is a useful mental model for thinking about &lt;code&gt;.reduce()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Provide a series of usage examples to strengthen your understanding&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's get started.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Mental Model
&lt;/h2&gt;

&lt;p&gt;Reduce is often introduced as a way of &lt;em&gt;reducing&lt;/em&gt; an array to a single value. While this is indeed what it does, I've never found this to be particularly helpful in understanding how it works, or what I might be able to do with it.&lt;/p&gt;

&lt;p&gt;For me, the simplest way to think about &lt;code&gt;.reduce()&lt;/code&gt; is as a fancy case of &lt;code&gt;.forEach()&lt;/code&gt;. The essentials are similar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We provide a callback function &lt;/li&gt;
&lt;li&gt;We iterate over the array, and execute the callback function once per array item.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important differences are that with &lt;code&gt;.reduce()&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each invocation of the callback is aware of the return value of the previous invocation (or on the first call, the initial value we've provided). &lt;/li&gt;
&lt;li&gt;Once there are no more items in the array, the return value of the last callback invocation is returned as the final result of the &lt;code&gt;.reduce()&lt;/code&gt; call.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In fact, we can implement a reduce function ourselves using a slim wrapper around &lt;code&gt;.forEach()&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;const&lt;/span&gt; &lt;span class="nx"&gt;reduce&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;initialValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Originally stores the initialValue then updated&lt;/span&gt;
  &lt;span class="c1"&gt;// on each iteration with the return value of the callback.&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;previousReturnValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;initialValue&lt;/span&gt;

  &lt;span class="c1"&gt;// Iterate over the array items, updating the currentReturn value at each step.&lt;/span&gt;
  &lt;span class="nx"&gt;array&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;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;previousReturnValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;previousReturnValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="c1"&gt;// Return the final value once all array items have been iterated over&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;previousReturnValue&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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






&lt;p&gt;Let's now look at some examples of using &lt;code&gt;.reduce()&lt;/code&gt;, and step through the execution path.&lt;/p&gt;
&lt;h2&gt;
  
  
  1. Adding an array of numbers
&lt;/h2&gt;

&lt;p&gt;In this common example, we're adding an array of numbers to arrive at a final sum:&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;initialValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;numbersToAdd&lt;/span&gt; &lt;span class="o"&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;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&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;addFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;runningTotal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;numberToAdd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;runningTotal&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;numberToAdd&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;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;numbersToAdd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;addFunction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;initialValue&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="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// =&amp;gt; 10&lt;/span&gt;

&lt;span class="c1"&gt;// =======================================================&lt;/span&gt;

&lt;span class="c1"&gt;// How was this calculated? Lets step through it:&lt;/span&gt;

&lt;span class="c1"&gt;// The addFunction callback is invoked for each array item:&lt;/span&gt;

&lt;span class="c1"&gt;// -- FIRST CALLBACK INVOCATION -- &lt;/span&gt;
&lt;span class="c1"&gt;// Array Item =&amp;gt; 1&lt;/span&gt;
&lt;span class="c1"&gt;// Previous return value =&amp;gt; first invocation (so the initialValue is used)&lt;/span&gt;
&lt;span class="c1"&gt;// Callback invocation =&amp;gt; numbersToAdd(0, 1)&lt;/span&gt;
&lt;span class="c1"&gt;// Callback return value =&amp;gt; 1&lt;/span&gt;

&lt;span class="c1"&gt;// -- SECOND CALLBACK INVOCATION --&lt;/span&gt;
&lt;span class="c1"&gt;// Array Item =&amp;gt; 2&lt;/span&gt;
&lt;span class="c1"&gt;// Previous return value =&amp;gt; 1&lt;/span&gt;
&lt;span class="c1"&gt;// Callback invocation =&amp;gt; numbersToAdd(1, 2)&lt;/span&gt;
&lt;span class="c1"&gt;// Callback return value =&amp;gt; 3&lt;/span&gt;

&lt;span class="c1"&gt;// -- THIRD CALLBACK INVOCATION --&lt;/span&gt;
&lt;span class="c1"&gt;// Array Item =&amp;gt; 3&lt;/span&gt;
&lt;span class="c1"&gt;// Previous return value =&amp;gt; 3&lt;/span&gt;
&lt;span class="c1"&gt;// Callback invocation =&amp;gt; numbersToAdd(3, 3)&lt;/span&gt;
&lt;span class="c1"&gt;// Callback return value =&amp;gt; 6&lt;/span&gt;

&lt;span class="c1"&gt;// -- FOURTH (AND LAST) CALLBACK INVOCATION --&lt;/span&gt;
&lt;span class="c1"&gt;// Array Item =&amp;gt; 4&lt;/span&gt;
&lt;span class="c1"&gt;// Previous return value =&amp;gt; 6&lt;/span&gt;
&lt;span class="c1"&gt;// Callback invocation =&amp;gt; numbersToAdd(6, 4)&lt;/span&gt;
&lt;span class="c1"&gt;// Callback return value =&amp;gt; 10&lt;/span&gt;

&lt;span class="c1"&gt;// Final Result: 10&lt;/span&gt;

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





&lt;h2&gt;
  
  
  2. Finding the largest of an array of numbers
&lt;/h2&gt;

&lt;p&gt;Here we'll use reduce to find the maximum value in an array. &lt;/p&gt;

&lt;p&gt;This is a slightly special case, in that we haven't provided &lt;code&gt;.reduce()&lt;/code&gt; with an initial value argument. Because of this, &lt;code&gt;.reduce()&lt;/code&gt; skips the callback for the first array item, and instead uses it as the initial value for the callback invocation on the second array item.&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;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;40&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="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;101&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;findLarger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentMax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;numberToCheck&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;numberToCheck&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;currentMax&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;numberToCheck&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;currentMax&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;largest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;findLarger&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="nx"&gt;largest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// =&amp;gt; 101&lt;/span&gt;

&lt;span class="c1"&gt;// =======================================================&lt;/span&gt;

&lt;span class="c1"&gt;// How was this calculated? Lets step through it:&lt;/span&gt;

&lt;span class="c1"&gt;// The findLarger callback is invoked for each array item:&lt;/span&gt;

&lt;span class="c1"&gt;// -- FIRST CALLBACK INVOCATION -- &lt;/span&gt;
&lt;span class="c1"&gt;// Array Item =&amp;gt; 10&lt;/span&gt;
&lt;span class="c1"&gt;// Previous return value =&amp;gt; first invocation, and no initialValue provided&lt;/span&gt;
&lt;span class="c1"&gt;// Callback invocation =&amp;gt; Not Invoked&lt;/span&gt;
&lt;span class="c1"&gt;// Callback return value =&amp;gt; N/A&lt;/span&gt;

&lt;span class="c1"&gt;// -- SECOND CALLBACK INVOCATION --&lt;/span&gt;
&lt;span class="c1"&gt;// Array Item =&amp;gt; 40&lt;/span&gt;
&lt;span class="c1"&gt;// Previous return value =&amp;gt; nothing, however first array item will be used as the initialValue&lt;/span&gt;
&lt;span class="c1"&gt;// Callback invocation =&amp;gt; findLarger(10, 40)&lt;/span&gt;
&lt;span class="c1"&gt;// Callback return value =&amp;gt; 40&lt;/span&gt;

&lt;span class="c1"&gt;// -- THIRD CALLBACK INVOCATION --&lt;/span&gt;
&lt;span class="c1"&gt;// Array Item =&amp;gt; 4&lt;/span&gt;
&lt;span class="c1"&gt;// Previous return value =&amp;gt; 40&lt;/span&gt;
&lt;span class="c1"&gt;// Callback invocation =&amp;gt; findLarger(40, 4)&lt;/span&gt;
&lt;span class="c1"&gt;// Callback return value =&amp;gt; 40&lt;/span&gt;

&lt;span class="c1"&gt;// -- FOURTH CALLBACK INVOCATION --&lt;/span&gt;
&lt;span class="c1"&gt;// Array Item =&amp;gt; 50&lt;/span&gt;
&lt;span class="c1"&gt;// Previous return value =&amp;gt; 40&lt;/span&gt;
&lt;span class="c1"&gt;// Callback invocation =&amp;gt; findLarger(40, 50)&lt;/span&gt;
&lt;span class="c1"&gt;// Callback return value =&amp;gt; 50&lt;/span&gt;

&lt;span class="c1"&gt;// -- FIFTH (AND LAST) CALLBACK INVOCATION --&lt;/span&gt;
&lt;span class="c1"&gt;// Array Item =&amp;gt; 101&lt;/span&gt;
&lt;span class="c1"&gt;// Previous return value =&amp;gt; 50&lt;/span&gt;
&lt;span class="c1"&gt;// Callback invocation =&amp;gt; findLarger(50, 101)&lt;/span&gt;
&lt;span class="c1"&gt;// Callback return value =&amp;gt; 101&lt;/span&gt;

&lt;span class="c1"&gt;// Final Result: 101&lt;/span&gt;

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





&lt;h2&gt;
  
  
  3. Categorising an array into even/odd numbers.
&lt;/h2&gt;

&lt;p&gt;Of course, you're not restricted to returning numbers from the callback in &lt;code&gt;.reduce()&lt;/code&gt;. You can return anything you want. In this case, we return an object that is categorising the array values into even/odd buckets.&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;initialValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;even&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="na"&gt;odd&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;const&lt;/span&gt; &lt;span class="nx"&gt;numbersToCategorise&lt;/span&gt; &lt;span class="o"&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;3&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="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&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;categorisingReducer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;numberToCategorise&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isEven&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;numberToCategorise&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;0&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;isEven&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;even&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numberToCategorise&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;odd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numberToCategorise&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;categories&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;categories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;numbersToCategorise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;categorisingReducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;initialValue&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="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;//  =&amp;gt; { even: [4, 8, 10], odd: [1, 3] }&lt;/span&gt;

&lt;span class="c1"&gt;// =======================================================&lt;/span&gt;

&lt;span class="c1"&gt;// How was this calculated? Again, lets step through it:&lt;/span&gt;

&lt;span class="c1"&gt;// The categorisingReducer callback is invoked for each array item:&lt;/span&gt;

&lt;span class="c1"&gt;// -- FIRST CALLBACK INVOCATION -- &lt;/span&gt;
&lt;span class="c1"&gt;// Array Item =&amp;gt; 1&lt;/span&gt;
&lt;span class="c1"&gt;// Previous return value =&amp;gt; first invocation (so the initialValue is used)&lt;/span&gt;
&lt;span class="c1"&gt;// Callback invocation =&amp;gt; categorisingReducer({ even: [], odd: [] }, 1)&lt;/span&gt;
&lt;span class="c1"&gt;// Callback return value =&amp;gt; { even: [], odd: [1] }&lt;/span&gt;

&lt;span class="c1"&gt;// -- SECOND CALLBACK INVOCATION --&lt;/span&gt;
&lt;span class="c1"&gt;// Array Item =&amp;gt; 3&lt;/span&gt;
&lt;span class="c1"&gt;// Previous return value =&amp;gt; { even: [], odd: [1] }&lt;/span&gt;
&lt;span class="c1"&gt;// Callback invocation =&amp;gt; categorisingReducer({ even: [], odd: [1] }, 3)&lt;/span&gt;
&lt;span class="c1"&gt;// Callback return value =&amp;gt; { even: [], odd: [1, 3] }&lt;/span&gt;

&lt;span class="c1"&gt;// -- THIRD CALLBACK INVOCATION --&lt;/span&gt;
&lt;span class="c1"&gt;// Array Item =&amp;gt; 4&lt;/span&gt;
&lt;span class="c1"&gt;// Previous return value =&amp;gt; { even: [], odd: [1, 3] }&lt;/span&gt;
&lt;span class="c1"&gt;// Callback invocation =&amp;gt; categorisingReducer({ even: [], odd: [1, 3] }, 4)&lt;/span&gt;
&lt;span class="c1"&gt;// Callback return value =&amp;gt; { even: [4], odd: [1, 3] }&lt;/span&gt;

&lt;span class="c1"&gt;// -- FOURTH CALLBACK INVOCATION --&lt;/span&gt;
&lt;span class="c1"&gt;// Array Item =&amp;gt; 8&lt;/span&gt;
&lt;span class="c1"&gt;// Previous return value =&amp;gt; { even: [4], odd: [1, 3] }&lt;/span&gt;
&lt;span class="c1"&gt;// Callback invocation =&amp;gt; categorisingReducer({ even: [4], odd: [1, 3] }, 8)&lt;/span&gt;
&lt;span class="c1"&gt;// Callback return value =&amp;gt; { even: [4, 8], odd: [1, 3] }&lt;/span&gt;

&lt;span class="c1"&gt;// -- FIFTH (AND LAST) CALLBACK INVOCATION --&lt;/span&gt;
&lt;span class="c1"&gt;// Array Item =&amp;gt; 10&lt;/span&gt;
&lt;span class="c1"&gt;// Previous return value =&amp;gt; { even: [4, 8], odd: [1, 3] }&lt;/span&gt;
&lt;span class="c1"&gt;// Callback invocation =&amp;gt; categorisingReducer({ even: [4, 8], odd: [1, 3] }, 10)&lt;/span&gt;
&lt;span class="c1"&gt;// Callback return value =&amp;gt; { even: [4, 8, 10], odd: [1, 3] }&lt;/span&gt;

&lt;span class="c1"&gt;// Final Result: { even: [4, 8, 10], odd: [1, 3] }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;p&gt;Let me know in the comments if this was useful, or if anything about the &lt;code&gt;.reduce()&lt;/code&gt; method is still unclear to you!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>👉 What the ecma is ES6 anyway?</title>
      <dc:creator>Harrison Reid</dc:creator>
      <pubDate>Mon, 03 Feb 2020 18:17:07 +0000</pubDate>
      <link>https://dev.to/harrison_codes/what-the-ecma-is-es6-anyway-lc1</link>
      <guid>https://dev.to/harrison_codes/what-the-ecma-is-es6-anyway-lc1</guid>
      <description>&lt;p&gt;&lt;em&gt;If you find this post useful, you can sign up to my &lt;a href="https://www.twosmalltrees.com/mailing-list"&gt;mailing list&lt;/a&gt;, check out the other posts on my &lt;a href="https://www.twosmalltrees.com"&gt;blog&lt;/a&gt;, or follow me on &lt;a href="https://twitter.com/_twosmalltrees"&gt;twitter&lt;/a&gt;. I've also got a couple of active side projects that you might like to check out:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://www.ippy.io"&gt;ippy.io&lt;/a&gt; - An app for creating beautiful resumes&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://many.tools"&gt;many.tools&lt;/a&gt; - A collection of useful utilities for designers and devs&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you're new to JavaScript development, you've likely seen the terms ES6 and ES2015 mentioned, and perhaps wondered what the **** the writer was talking about. &lt;/p&gt;

&lt;p&gt;You might've even suspected a typo - after all, you're learning JS not ES. &lt;/p&gt;

&lt;p&gt;Regrettably, it's not a typo - you've just entered the somewhat confusing world of  JavaScript version naming. Welcome.&lt;/p&gt;



&lt;h2&gt;
  
  
  So… What is ES?
&lt;/h2&gt;

&lt;p&gt;ES is shorthand for ECMAScript. &lt;/p&gt;

&lt;p&gt;I know, I know, you thought you were learning JavaScript! Well, you are, but turns out you're kind of sort of &lt;em&gt;also&lt;/em&gt; learning ECMAScript. Two for the price of one! &lt;/p&gt;

&lt;p&gt;ECMAScript is the specification that defines the functionality that the JavaScript language is expected to implement. Technically, JavaScript is an implementation of the ECMAScript standard. &lt;/p&gt;

&lt;p&gt;It's actually quite interesting if you want to read more about it.&lt;/p&gt;

&lt;p&gt;If not, for the most part you can get away with mentally substituting ES =&amp;gt; JS, and ECMAScript =&amp;gt; JavaScript.&lt;/p&gt;



&lt;h2&gt;
  
  
  And What About The Numbers?
&lt;/h2&gt;

&lt;p&gt;The numbers are versions. &lt;/p&gt;

&lt;p&gt;Like all programming languages, JavaScript has developed over time. New features have been added, making our lives as programmers easier, and allowing us to more effectively author complex applications (without our code devolving into carbonara). &lt;/p&gt;

&lt;p&gt;As these new versions are released they are named. ES6, ES2015, ES7, ES2017 - these are all versions of the ECMAScript standard. &lt;/p&gt;

&lt;p&gt;When you see references to an ES version, the author will often be writing about particular features of JavaScript that are have become available in said version.&lt;/p&gt;




&lt;p&gt;Unfortunately, particularly for a few years, there were multiple names flying around for the &lt;em&gt;same&lt;/em&gt; versions. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ES6 is ES2015&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ES7 is ES2016&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whats happened here is that while originally ECMAScript versions were incrementally numbered and named, with the release of ES2015 there was a transition to naming based on the year of release.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ES6 (ECMAScript version 6) was released in June of 2015, so &lt;strong&gt;ES6 =&amp;gt; ES2015&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;ES7 (ECMAScript version 7) was released in June of 2016, so &lt;strong&gt;ES7 =&amp;gt; ES2016&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Kind of makes sense right?&lt;/p&gt;

&lt;p&gt;Unfortunately we in the JavaScript community often still use ES6/ES2015 and to a lesser degree ES7/ES2016 interchangeably, so you kind of just need to remember that these are equivalent. &lt;/p&gt;

&lt;p&gt;ES2015 and ES2016 are also versions in which some fairly substantial changes were introduced to the language spec, so you're more likely to run into discussion of these versions than others.&lt;/p&gt;



&lt;h2&gt;
  
  
  The Future
&lt;/h2&gt;

&lt;p&gt;Thankfully, in the years since the release of ES2016, the community appears to have somewhat settled into the year based naming scheme. &lt;/p&gt;

&lt;p&gt;While you'll still see references to ES8, ES9 and ES10, referring to them as ES2017, ES2018 and ES2019 seems to have become the more common practice. &lt;/p&gt;

&lt;p&gt;So cheers, to a slightly less confusing future 🍻&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>codenewbie</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Beginners, What Would You Most Like to Build in a JavaScript Tutorial?</title>
      <dc:creator>Harrison Reid</dc:creator>
      <pubDate>Fri, 31 Jan 2020 15:45:10 +0000</pubDate>
      <link>https://dev.to/harrison_codes/beginners-what-would-you-most-like-to-build-in-a-javascript-tutorial-3ami</link>
      <guid>https://dev.to/harrison_codes/beginners-what-would-you-most-like-to-build-in-a-javascript-tutorial-3ami</guid>
      <description>&lt;p&gt;In many beginner JS tutorials, the end goal is to build an app of some sort, and they are frequently of a similar type: todo lists, stopwatch timers, pared down clones of common social media apps, etc. &lt;/p&gt;

&lt;p&gt;There's obviously good reason for this - when you don't have to expend too much mental energy understanding &lt;em&gt;what&lt;/em&gt; you're building, it's easier to understand &lt;em&gt;how&lt;/em&gt;. They are also limited in scope, which makes them more manageable.&lt;/p&gt;

&lt;p&gt;However when I was working through many of this type of tutorial a few years back, I've got to admit that I sometimes found myself getting a little bored...&lt;/p&gt;




&lt;p&gt;So I'm interested to hear from the beginners out there - ignoring any issues of difficulty or complexity - what kind of app would &lt;strong&gt;you&lt;/strong&gt; want to build in a project style tutorial?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>beginners</category>
      <category>codenewbie</category>
      <category>javascript</category>
    </item>
    <item>
      <title>3 Weird Things You (Probably) Didn't Know You Can Do With The JavaScript Spread Operator 🥳</title>
      <dc:creator>Harrison Reid</dc:creator>
      <pubDate>Thu, 30 Jan 2020 12:59:49 +0000</pubDate>
      <link>https://dev.to/harrison_codes/3-weird-things-you-probably-didn-t-know-you-can-do-with-the-javascript-spread-operator-2fln</link>
      <guid>https://dev.to/harrison_codes/3-weird-things-you-probably-didn-t-know-you-can-do-with-the-javascript-spread-operator-2fln</guid>
      <description>&lt;p&gt;&lt;em&gt;If you find this post useful, you can sign up to my &lt;a href="https://www.twosmalltrees.com/mailing-list"&gt;mailing list&lt;/a&gt;, check out the other posts on my &lt;a href="https://www.twosmalltrees.com"&gt;blog&lt;/a&gt;, or follow me on &lt;a href="https://twitter.com/_twosmalltrees"&gt;twitter&lt;/a&gt;. I've also got a couple of active side projects that you might like to check out:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://www.ippy.io"&gt;ippy.io&lt;/a&gt; - An app for creating beautiful resumes&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://many.tools"&gt;many.tools&lt;/a&gt; - A collection of useful utilities for designers and devs&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;The spread operator has been enthusiastically adopted by the JavaScript community since its inclusion in the language with ES6, with good reason! It vastly simplifies many common object and array manipulations patterns. &lt;/p&gt;

&lt;p&gt;While the common uses are widely appreciated and utilised, it also facilitates some slightly more obscure patterns.&lt;/p&gt;

&lt;p&gt;Such as…&lt;/p&gt;
&lt;h2&gt;
  
  
  👉 1) Conditionally Adding Properties to an Object
&lt;/h2&gt;

&lt;p&gt;It may not be &lt;em&gt;particularly&lt;/em&gt; common, but imagine that (for whatever reason) you want to conditionally add properties to an object. Specifically, you want to add the properties if they hold a truthy value, but exclude them if they are null, undefined, or contain a falsey value. How might you approach this?&lt;/p&gt;

&lt;p&gt;A reasonable approach might be something like the following:&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;firstName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Harrison&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lastName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;123 Street Rd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;phoneNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userInfo&lt;/span&gt; &lt;span class="o"&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;firstName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;userInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firstName&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;lastName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;userInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lastName&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;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;userInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;address&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;phoneNumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;userInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;phoneNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;phoneNumber&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="nx"&gt;userInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// {&lt;/span&gt;
&lt;span class="c1"&gt;//   firstName: 'Harrison',&lt;/span&gt;
&lt;span class="c1"&gt;//   address: '123 Street Rd'&lt;/span&gt;
&lt;span class="c1"&gt;// }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;There's nothing wrong with this approach - however using the spread operator, we can move the conditional logic inside the object literal. &lt;/p&gt;

&lt;p&gt;The result is somewhat more concise, and &lt;em&gt;in my opinion&lt;/em&gt; once you've seen it a few times is actually more readable.&lt;/p&gt;

&lt;p&gt;Take a look:&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;firstName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Harrison&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lastName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;123 Street Rd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;phoneNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;firstName&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;lastName&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;phoneNumber&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;phoneNumber&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="nx"&gt;userInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// {&lt;/span&gt;
&lt;span class="c1"&gt;//   firstName: 'Harrison',&lt;/span&gt;
&lt;span class="c1"&gt;//   address: '123 Street Rd'&lt;/span&gt;
&lt;span class="c1"&gt;// }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you haven't seen this pattern before, it might take a second to grok what's going on. I'll try to explain:&lt;/p&gt;

&lt;p&gt;Lets consider the first line inside the object literal, a case in which the property should be added to the object:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;...firstName &amp;amp;&amp;amp; { firstName }&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Since &lt;code&gt;firstName&lt;/code&gt; was previously assigned the truthy value &lt;code&gt;'Harrison'&lt;/code&gt;,&lt;br&gt;
the expression &lt;code&gt;firstName &amp;amp;&amp;amp; { firstName }&lt;/code&gt; will return &lt;code&gt;{ firstName: 'Harrison' }&lt;/code&gt;. Both the left and right hand side of the &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; evaluate as truthy, and as such the right hand side is returned.&lt;/p&gt;

&lt;p&gt;This returned object is then spread into the &lt;code&gt;userInfo&lt;/code&gt; object, resulting in the firstName property being successfully set.&lt;/p&gt;

&lt;p&gt;Next, lets consider the alternate case, in which we attempt to assign a falsey value. Lets take the second line of the object literal:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;...lastName &amp;amp;&amp;amp; { lastName }&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In this case, &lt;code&gt;lastName&lt;/code&gt; is null. This means that the expression &lt;code&gt;lastName &amp;amp;&amp;amp; { lastName }&lt;/code&gt; short-circuits to returning the left hand side of the &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;, which in this case is &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We then attempt to spread &lt;code&gt;null&lt;/code&gt; into the &lt;code&gt;userInfo&lt;/code&gt; object. You might think this should result in an error, but it actually doesn't. &lt;/p&gt;

&lt;p&gt;In fact, as far as I'm aware spreading any falsey value into an object is perfectly valid syntax, but will result in no change to the object. Try it out:&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;let&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="kc"&gt;null&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="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// {}&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="kc"&gt;undefined&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="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// {}&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="kc"&gt;false&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="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// {}&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// {}&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="mi"&gt;0&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="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// {}&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...{}&lt;/span&gt; &lt;span class="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="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// {}&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...[]&lt;/span&gt; &lt;span class="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="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// {}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The end result of all this is that any truthy values will be added to the object, while any falsey values are left out! &lt;/p&gt;

&lt;p&gt;To make the code more explicit we can use the same pattern, but refactor the truthy check into its own function:&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;hasIfTruthy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;propertyName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;property&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;propertyName&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;property&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;firstName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Harrison&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lastName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;123 Street Rd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;phoneNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;hasIfTruthy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firstName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;hasIfTruthy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lastName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;hasIfTruthy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;address&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;hasIfTruthy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;phoneNumber&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;phoneNumber&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="nx"&gt;userInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// {&lt;/span&gt;
&lt;span class="c1"&gt;//   firstName: 'Harrison',&lt;/span&gt;
&lt;span class="c1"&gt;//   address: '123 Street Rd'&lt;/span&gt;
&lt;span class="c1"&gt;// }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Using this pattern, you can even completely alter the condition that dictates whether a property is included or excluded - it doesn't necessarily need to be based on just truthy-ness/falsy-ness.&lt;/p&gt;



&lt;h2&gt;
  
  
  👉 2) Spreading an Array into an Object
&lt;/h2&gt;

&lt;p&gt;So… I'm yet to think of a particularly compelling reason that you would actually do this (shout out in the comments if you have one), but you can totally spread an Array into an Object. &lt;/p&gt;

&lt;p&gt;The result is that each array element is inserted into the object, with the key set to its respective array index.&lt;/p&gt;

&lt;p&gt;Check it out:&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;fruitsArray&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;apple&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;orange&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;banano&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;fruitsObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;fruitsArray&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="nx"&gt;fruitsObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// {&lt;/span&gt;
&lt;span class="c1"&gt;//   0: 'apple',&lt;/span&gt;
&lt;span class="c1"&gt;//   1: 'orange',&lt;/span&gt;
&lt;span class="c1"&gt;//   2: 'banano'&lt;/span&gt;
&lt;span class="c1"&gt;// }&lt;/span&gt;

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





&lt;h2&gt;
  
  
  👉 3) Spreading a String Into an Array (or an Object)
&lt;/h2&gt;

&lt;p&gt;This one is actually pretty nifty, and is probably more widely known than the others. You can spread a string into an array! &lt;/p&gt;

&lt;p&gt;The result is an array containing the individual characters from the string.&lt;/p&gt;

&lt;p&gt;In my opinion this allows for a more pleasant syntax than the common &lt;code&gt;'string'.split('')&lt;/code&gt; style.&lt;/p&gt;

&lt;p&gt;Here it is:&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;characters&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="s2"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;characters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// ['a', 'p', 'p', 'l', 'e']&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And if you're feeling really wild, you can even spread a string into an object 🙀&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;characters&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="s2"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;characters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// {&lt;/span&gt;
&lt;span class="c1"&gt;//   0: 'a',&lt;/span&gt;
&lt;span class="c1"&gt;//   1: 'p',&lt;/span&gt;
&lt;span class="c1"&gt;//   2: 'p',&lt;/span&gt;
&lt;span class="c1"&gt;//   3: 'l',&lt;/span&gt;
&lt;span class="c1"&gt;//   4: 'e'&lt;/span&gt;
&lt;span class="c1"&gt;// }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Stay safe out there kids.&lt;/p&gt;




&lt;p&gt;Know any other weird or wonderful uses for the JS spread operator? Let me know in the comments 😊&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>3 Deep Dive Tutorials to Make You a Better JavaScript Developer Today! 😎</title>
      <dc:creator>Harrison Reid</dc:creator>
      <pubDate>Sun, 26 Jan 2020 17:17:36 +0000</pubDate>
      <link>https://dev.to/harrison_codes/3-deep-dive-tutorials-to-make-you-a-better-javascript-developer-today-55j</link>
      <guid>https://dev.to/harrison_codes/3-deep-dive-tutorials-to-make-you-a-better-javascript-developer-today-55j</guid>
      <description>&lt;p&gt;In the modern JavaScript world, it's possible to be a remarkably productive developer while working with a relatively basic understand of the tooling and lower level structures supporting your work. &lt;/p&gt;

&lt;p&gt;This is not a bad thing! It's a sign that the JavaScript world has developed an ecosystem of robust tooling and frameworks with maintainers who place a high value on user friendly documentation. &lt;/p&gt;

&lt;p&gt;Having said that, when it comes time to solving obscure bugs 🐛, and Stack Overflow isn't giving you any love, having the knowledge (and patience) to drill down a few layers can be very helpful. Nothing beats getting into the weeds! 🌿 &lt;/p&gt;

&lt;p&gt;On that note, here are three of my favourite "deep-dive" style tutorials. Give these a whirl, and you'll learn a bunch, and likely gain much respect for the devs out there that maintain the tools we use every day!&lt;/p&gt;

&lt;h2&gt;
  
  
  1) &lt;a href="https://pomb.us/build-your-own-react/"&gt;Build Your Own React - Rodrigo Pombo&lt;/a&gt;  ⚛️
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GevTQsUA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/dwlbxdtuyg6gutgooakq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GevTQsUA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/dwlbxdtuyg6gutgooakq.png" alt="Screenshot of https://pomb.us/build-your-own-react/"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Do you work with React? Do you actually know how React works? Like, under the hood? If not, get stuck into this tutorial and you will soon.&lt;/p&gt;

&lt;h2&gt;
  
  
  2) &lt;a href="https://eloquentjavascript.net/12_language.html"&gt;Eloquent Javascript Chapter 12: Build a Programming Language in JS - Marijn Haverbeke&lt;/a&gt; 👷
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4kL6cMFe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/392z1r2uk05mx73dsvr0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4kL6cMFe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/392z1r2uk05mx73dsvr0.png" alt="Screenshot of https://eloquentjavascript.net/12_language.html"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's all in the title! You'll quite literally build your own programming language. And once you're done with this chapter, go back and read the rest of the book - you won't be disappointed.&lt;/p&gt;

&lt;h2&gt;
  
  
  3) &lt;a href="https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/plugin-handbook.md#toc-writing-your-first-babel-plugin"&gt;Babel Plugin Handbook - jamiebuilds and contributors&lt;/a&gt; 👍
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9DZTakzW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/f9vkjs1jfko0g9w1m55a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9DZTakzW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/f9vkjs1jfko0g9w1m55a.png" alt="Screenshot of https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/plugin-handbook.md#toc-writing-your-first-babel-plugin"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While not strictly a tutorial (although there is quick "Writing your first babel plugin" section), a read through the Babel Plugin Handbook (and the associated &lt;a href="https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/user-handbook.md"&gt;Babel User Handbook&lt;/a&gt; will take your understanding of this commonly used tool to a whole new level. &lt;/p&gt;

&lt;p&gt;You'll also be introduced to a bunch of other concepts (like Abstract Syntax Trees) along the way.&lt;/p&gt;




&lt;p&gt;Do you have any other recommendations for great JS deep dive tutorials? Let me know in the comments below! 😃&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you found this post useful, you can follow me on &lt;a href="https://dev.to/harrison_codes"&gt;dev.to&lt;/a&gt; or &lt;a href="https://twitter.com/_twosmalltrees"&gt;twitter&lt;/a&gt;. I've also got a couple of side projects that you might like to check out:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://www.ippy.io"&gt;ippy.io&lt;/a&gt; - An app for creating beautiful resumes&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://many.tools"&gt;many.tools&lt;/a&gt; - A collection of useful utilities for designers and devs&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>tutorial</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Build Your Own JavaScript Test Framework (in TypeScript)</title>
      <dc:creator>Harrison Reid</dc:creator>
      <pubDate>Fri, 24 Jan 2020 21:33:49 +0000</pubDate>
      <link>https://dev.to/harrison_codes/building-your-own-javascript-test-framework-in-typescript-45c</link>
      <guid>https://dev.to/harrison_codes/building-your-own-javascript-test-framework-in-typescript-45c</guid>
      <description>&lt;p&gt;&lt;em&gt;This is the first in a planned series of posts where I'll take some heavily used tools from the JavaScript ecosystem and attempt to build minimal versions from the ground up.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;If you've worked with JavaScript for a while, you might be familiar with some of the more common test frameworks. The two that spring to mind for me are &lt;strong&gt;Mocha&lt;/strong&gt; and &lt;strong&gt;Jest&lt;/strong&gt;, but there are plenty of others out there with varying levels of popularity. &lt;/p&gt;

&lt;p&gt;These are powerful libraries, with great tooling built around them. If your aim is to effectively test an application you're working on, I strongly advise  against building your own - just choose your favourite of the many existing options and get going. &lt;/p&gt;

&lt;p&gt;However if you're interested in how you could approach this challenge, keep reading!&lt;/p&gt;
&lt;h2&gt;
  
  
  What we'll build
&lt;/h2&gt;

&lt;p&gt;We're going to use typescript to build a test framework called Pretzel Test 🥨. It'll be basic but functional, and will provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A test API - ie: describe blocks, before/beforeEach blocks etc…&lt;/li&gt;
&lt;li&gt;An expectations API - ie: expect(value).toEqual(someExpectedValue)&lt;/li&gt;
&lt;li&gt;A test reporter to output results to the terminal&lt;/li&gt;
&lt;li&gt;CLI invocation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you don't have time to follow along, the &lt;a href="https://github.com/twosmalltrees/pretzel-test"&gt;final code&lt;/a&gt; and an &lt;a href="https://github.com/twosmalltrees/pretzel-test-example"&gt;example&lt;/a&gt; using Pretzel Test are available on github.&lt;/p&gt;

&lt;p&gt;Here's a snippet to demonstrate the API we're shooting for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pretzel-test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;addNumbers&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./util.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;addNumbers&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;before&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Before block&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// After block&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Before each block&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;afterEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// After each block&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;should correctly add two positive numbers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&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;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;addNumbers&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="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;should correctly add two negative numbers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&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;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;addNumbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you can see, Pretzel Test will use a chainable API rather than the common nested describe blocks style. This was an intentional decision; I wanted to explore alternatives to that common pattern, as I find nested describe blocks can become unwieldy and difficult to parse.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part One: Project structure
&lt;/h2&gt;

&lt;p&gt;We're going to build this in TypeScript. Let's get started. First up, create a new project in your preferred fashion. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;pretzel-test
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;pretzel-test
&lt;span class="nv"&gt;$ &lt;/span&gt;yarn init
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then we'll install a few dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;yarn add typescript colors command-line-args glob lodash
&lt;span class="nv"&gt;$ &lt;/span&gt;yarn add &lt;span class="nt"&gt;--dev&lt;/span&gt; @types/colors @types/node @types/glob
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In your project root, create the following directory structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;📁pretzel-test
|- 📝tsconfig.json
|- 📁bin
   |- 📝cli.js
|- 📁src
   |- 📝describe.ts
   |- 📝expect.ts
   |- 📝main.ts
   |- 📝reporter.ts
   |- 📝runner.ts
   |- 📝types.ts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



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

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "compilerOptions": {
    "outDir": "./dist",
    "lib": ["es2015"]
  },
  "include": ["src"]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It's not a complex tsconfig.json, however it's worth taking a look at the &lt;a href="http://www.typescriptlang.org/docs/handbook/compiler-options.html"&gt;typescript docs&lt;/a&gt; if you're unsure about what's going on there.&lt;/p&gt;

&lt;p&gt;If you're coding along in TypeScript, keep in mind that you'll need to compile the code with &lt;code&gt;tsc&lt;/code&gt; before running it from the dist folder.&lt;/p&gt;

&lt;p&gt;Then, in src/main.ts we'll import and and export the user facing API of pretzel test. The functions we import don't exist yet, but we'll build them out.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/main.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;describe&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./describe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./expect&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Part Two: src/types.ts
&lt;/h2&gt;

&lt;p&gt;In types.ts we'll define the main types that are used throughout the project. Taking a read through this should help you understand how the test framework is structured. Enter the following in your types.ts file. I'll explain it further below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/types.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;before&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;afterEach&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./describe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ChainableApi&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;currentTestGroup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TestGroup&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;it&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;case&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;before&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;before&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;after&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;afterEach&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;afterEach&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;TestGroup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;tests&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="nl"&gt;before&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;after&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;afterEach&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Test&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TestResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Options&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;rootDir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;matching&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;TestResult&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;beforeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;afterError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;beforeEachError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;afterEachError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Error&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;Let's look at the interfaces we've defined in this file:&lt;/p&gt;

&lt;h3&gt;
  
  
  ChainableApi
&lt;/h3&gt;

&lt;p&gt;This interface represents the object that will be returned by a call to &lt;code&gt;describe()&lt;/code&gt;. Further, any chained calls to &lt;code&gt;before()&lt;/code&gt; &lt;code&gt;beforeEach()&lt;/code&gt; &lt;code&gt;after()&lt;/code&gt; &lt;code&gt;afterEach()&lt;/code&gt; or &lt;code&gt;it()&lt;/code&gt; will return an object implementing this same interface, which will allow users of the API to chain an arbitrary number of calls to the initial &lt;code&gt;describe()&lt;/code&gt; function. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ChainableApi&lt;/code&gt; interface also references a &lt;code&gt;currentTestGroup&lt;/code&gt; property, which we've declared as implementing the &lt;code&gt;TestGroup&lt;/code&gt; interface.&lt;/p&gt;

&lt;h3&gt;
  
  
  TestGroup
&lt;/h3&gt;

&lt;p&gt;Conceptually, a test group represents a parsed set of tests that begin with a call to &lt;code&gt;describe()&lt;/code&gt; , and encompasses any chained methods on that call. &lt;/p&gt;

&lt;p&gt;When it comes time to run our tests, the descriptions and callbacks passed in to the describe API will be pulled out into an object implementing the &lt;code&gt;TestGroup&lt;/code&gt; interface. &lt;/p&gt;

&lt;p&gt;To accomodate this, we've defined a description property of type &lt;strong&gt;string&lt;/strong&gt;, to contain the test description passed to the initial describe() call. We've then defined four properties - &lt;code&gt;before&lt;/code&gt; , &lt;code&gt;beforeEach&lt;/code&gt; , &lt;code&gt;after&lt;/code&gt; &amp;amp; &lt;code&gt;afterEach&lt;/code&gt; - which each accept an array of functions. These properties will be used to reference the callbacks functions passed to their respective methods in the &lt;code&gt;ChainableApi&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, we define a tests property, which accepts an array of objects implementing the &lt;code&gt;Test&lt;/code&gt; interface. &lt;/p&gt;

&lt;h3&gt;
  
  
  Test
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;Test&lt;/code&gt; interface is quite similar to &lt;code&gt;TestGroup&lt;/code&gt; , but will store references for a single test as defined by a call to &lt;code&gt;it()&lt;/code&gt;. &lt;code&gt;it()&lt;/code&gt; will accept two arguments - a description, and a callback function that runs the test expectations. As such, we have another description property of type &lt;strong&gt;string&lt;/strong&gt; &amp;amp; an fn property of type &lt;strong&gt;Function&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We also have a result property, of type &lt;code&gt;TestResult&lt;/code&gt; which will be used to store the results of the individual test after it's been run.&lt;/p&gt;

&lt;h3&gt;
  
  
  TestResult
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;TestResult&lt;/code&gt; interface contains a passed property that accepts a &lt;strong&gt;boolean&lt;/strong&gt;, which will indicate if the test passed or failed.&lt;/p&gt;

&lt;p&gt;The remainder of the fields on TestResult are used to keep track of any errors thrown when running the test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part Three: src/describe.ts
&lt;/h2&gt;

&lt;p&gt;In this file we define the test API of Pretzel Test. This, combined with the expectations API are what (hypothetical) users of our framework would use to author their tests. Here's the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/describe.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ChainableApi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TestGroup&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./types&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;testRunner&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./runner&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;getInitialTestGroup&lt;/span&gt; &lt;span class="o"&gt;=&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="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;TestGroup&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="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="na"&gt;tests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="na"&gt;before&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="na"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="na"&gt;after&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="na"&gt;afterEach&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="nx"&gt;before&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ChainableApi&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTestGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;before&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&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="nx"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ChainableApi&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTestGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;after&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&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="nx"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ChainableApi&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTestGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&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="nx"&gt;afterEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ChainableApi&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTestGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;afterEach&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&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="nx"&gt;test&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="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ChainableApi&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTestGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&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="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;result&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="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;beforeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;beforeEachError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;afterError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;afterEachError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&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="k"&gt;this&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="nx"&gt;describe&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="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ChainableApi&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;currentTestGroup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TestGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getInitialTestGroup&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="nx"&gt;testRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pushTestGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentTestGroup&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="nx"&gt;currentTestGroup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;it&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="na"&gt;case&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;before&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;after&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;afterEach&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;describe&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;before&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;afterEach&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I'll run through the above function by function:&lt;/p&gt;

&lt;h3&gt;
  
  
  describe() 
&lt;/h3&gt;

&lt;p&gt;The entry point to the API is the &lt;code&gt;describe&lt;/code&gt; function, which accepts a description string as its single argument. First, the function builds a &lt;code&gt;currentTestGroup&lt;/code&gt; object (Initially the &lt;code&gt;currentTestGroup&lt;/code&gt; object will only store the description that has been passed to describe, with all other properties set to empty arrays). &lt;/p&gt;

&lt;p&gt;Next up, we call &lt;code&gt;testRunner.pushTestGroup&lt;/code&gt; and pass in the current test group object. &lt;code&gt;testRunner&lt;/code&gt; is an instance of the &lt;code&gt;TestRunner&lt;/code&gt; class, which we haven't yet defined, however its job will be to collect and run each &lt;code&gt;TestGroup&lt;/code&gt; - so we pass it a reference to the test group that has been created as a result of the &lt;code&gt;describe&lt;/code&gt; call.&lt;/p&gt;

&lt;p&gt;Finally, the &lt;code&gt;describe&lt;/code&gt; function returns an object that implements the &lt;code&gt;ChainableApi&lt;/code&gt; interface. It contains references to the chainable methods (&lt;code&gt;before&lt;/code&gt;, &lt;code&gt;beforeEach&lt;/code&gt;, &lt;code&gt;after&lt;/code&gt;, &lt;code&gt;afterEach&lt;/code&gt; &amp;amp; &lt;code&gt;it&lt;/code&gt;) along with the current test group via the &lt;code&gt;currentTestGroup&lt;/code&gt; property.&lt;/p&gt;

&lt;h3&gt;
  
  
  before(), beforeEach(), after &amp;amp; afterEach ()
&lt;/h3&gt;

&lt;p&gt;These functions all behave in the same way. First, they push the callback that's passed as an argument into their respective property on the &lt;code&gt;currentTestGroup&lt;/code&gt; object, and then return &lt;code&gt;this&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Because these methods will always be chained to a &lt;code&gt;describe()&lt;/code&gt; call, the &lt;code&gt;this&lt;/code&gt; keyword in each method will refer to the parent object that the methods were called on (in this case, the object returned from the initial describe block). &lt;/p&gt;

&lt;p&gt;As such, these methods have access to the &lt;code&gt;currentTestGroup&lt;/code&gt; object via &lt;code&gt;this.currentTestGroup&lt;/code&gt;. By returning this at the end of each function, we allow an arbitrary number of these methods can be chained, and each will still be able to access currentTestGroup in the same way.&lt;/p&gt;

&lt;h3&gt;
  
  
  it()
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;it&lt;/code&gt; method is pretty similar to the other chainable methods in behaviour, with a couple of notable differences. &lt;/p&gt;

&lt;p&gt;Firstly, it accepts a description argument along with a callback function. Second, rather than only pushing a callback function, it builds and pushes an object implementing the the full &lt;code&gt;Test&lt;/code&gt; interface to the &lt;code&gt;currentTestGroup&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part Four: src/expect.ts
&lt;/h2&gt;

&lt;p&gt;This is file is where we create our expectation API. For now, we'll keep this very simple, and only implement matchers for &lt;code&gt;.toEqual()&lt;/code&gt; and &lt;code&gt;.notToEqual()&lt;/code&gt;, however this could be extended to provide more functionality. Take a look:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/expect.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;colors&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lodash&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;getToEqual&lt;/span&gt; &lt;span class="o"&gt;=&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="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;expectedValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isEqual&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;expectedValue&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Expected &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;expectedValue&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; to equal &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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;yellow&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;const&lt;/span&gt; &lt;span class="nx"&gt;getNotToEqual&lt;/span&gt; &lt;span class="o"&gt;=&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="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;expectedValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&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;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isEqual&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;expectedValue&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Expected &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;expectedValue&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; not to equal &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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;yellow&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&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="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;getToEqual&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="na"&gt;notToEqual&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;getNotToEqual&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="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;expect()&lt;/code&gt; function accepts a value of any type, returning an object with our &lt;code&gt;toEqual()&lt;/code&gt; and &lt;code&gt;notToEqual()&lt;/code&gt; expectation functions. If the expectations fail, they throw a error (which is caught and recorded by the &lt;code&gt;testRunner&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We're cheating a little here and using &lt;a href="https://lodash.com/docs/4.17.15#isEqual"&gt;Lodash's isEqual()&lt;/a&gt; method to perform the actual equality comparison, as it provides a deep equality check that's a bit tricky to code manually.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part Five: src/runner.ts
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;TestRunner&lt;/code&gt; class has a few responsibilities:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It serves as the entry point to Pretzel Test. When we later implement the cli script to start the test run, it will do so with a call to &lt;code&gt;testRunner.run()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It initiates an instance of the &lt;code&gt;Reporter&lt;/code&gt; class (which will be responsible for logging the test results to the console.&lt;/li&gt;
&lt;li&gt;It locates and imports test files matching the glob pattern passed through as options.&lt;/li&gt;
&lt;li&gt;It collects the test groups from the imported files, then loops over them and invokes the actual test functions, recording the results.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/runner.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;glob&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;glob&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Reporter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./reporter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;TestGroup&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;Options&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./types&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;EventEmitter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;events&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;TestRunner&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;EventEmitter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;events&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;testRunStarted&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_RUN_STARTED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;testRunCompleted&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_RUN_COMPLETED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;afterBlockError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AFTER_BLOCK_ERROR&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;testGroupStarted&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_GROUP_STARTED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;testGroupCompleted&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_GROUP_COMPLETED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;singleTestCompleted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SINGLE_TEST_COMPLETED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nl"&gt;suite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TestGroup&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Reporter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Reporter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;suite&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;pushTestGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;testGroup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TestGroup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;suite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;testGroup&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;buildSuite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Options&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;testFilePaths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;matching&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rootDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;absolute&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="nx"&gt;testFilePaths&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;require&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;runBeforeEachBlocks&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;Test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;testGroup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TestGroup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;testGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;beforeEachError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;runTestFn&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;Test&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fn&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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;passed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;passed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;runAfterEachBlocks&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;Test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;testGroup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TestGroup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;testGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;afterEach&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;afterEachError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;runTests&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;testGroup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TestGroup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;testGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tests&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runBeforeEachBlocks&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;testGroup&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;await&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;runTestFn&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="k"&gt;await&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;runAfterEachBlocks&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;testGroup&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TestRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;singleTestCompleted&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="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;runBefore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;testGroup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TestGroup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;testGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;before&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;testGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tests&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;test&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;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;beforeError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;runAfter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;testGroup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TestGroup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;testGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;after&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TestRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;afterBlockError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;testGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tests&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;test&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;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;beforeError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;runTestGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;testGroup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TestGroup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TestRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;testGroupStarted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;testGroup&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&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;runBefore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;testGroup&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&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;runTests&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;testGroup&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&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;runAfter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;testGroup&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TestRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;testGroupCompleted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;testGroup&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buildSuite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TestRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;testRunStarted&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;testGroup&lt;/span&gt; &lt;span class="k"&gt;of&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;suite&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;await&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;runTestGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;testGroup&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TestRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;testRunCompleted&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;testRunner&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;TestRunner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Reporter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I won't go through this file function by function (or you'll be here all day), however there is one thing I'd like to point out. You'll see that the TestRunner class extends Nodes inbuilt &lt;a href="https://nodejs.org/api/events.html#events_class_eventemitter"&gt;EventEmitter&lt;/a&gt;. This gives us access to &lt;code&gt;emit()&lt;/code&gt; and &lt;code&gt;on()&lt;/code&gt;, which you'll see being used above, and in &lt;code&gt;reporter.ts&lt;/code&gt;. This is how the testRunner communicates with the reporter, and triggers the reporter to log output to the console.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part Five: src/reporter.ts
&lt;/h2&gt;

&lt;p&gt;As you've hopefully seen above, the &lt;code&gt;Reporter&lt;/code&gt; class is imported and initialised by the &lt;code&gt;testRunner&lt;/code&gt;, with the testRunner passing itself as an argument to the &lt;code&gt;Reporter&lt;/code&gt; constructor. The &lt;code&gt;Reporter&lt;/code&gt; constructor then initialises a set of event listeners on the &lt;code&gt;testRunner&lt;/code&gt; (using the EventEmitter &lt;code&gt;.on()&lt;/code&gt; function, which in turn trigger callbacks that &lt;code&gt;console.log&lt;/code&gt; the various testRunner events (passing test, failing test, etc).&lt;/p&gt;

&lt;p&gt;We're also using the &lt;code&gt;colors&lt;/code&gt; npm package to make the console output a little more interesting.&lt;/p&gt;

&lt;p&gt;Here's the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/reporter.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;colors&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;TestRunner&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./runner&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="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;TestGroup&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./types&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;indent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;  &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Reporter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;testRunner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TestRunner&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;testRunner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;testRunner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;testRunner&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initEventListeners&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;printSummary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;totalCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;passedCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;failedCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;testRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;suite&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;testGroup&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;totalCount&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;testGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;testGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tests&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;test&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;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;passedCount&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;else&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="s2"&gt;`\n ○ &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;testGroup&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="s2"&gt;. &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;red&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="s2"&gt;`\n&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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="nx"&gt;failedCount&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="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="s2"&gt;`\n Total tests run: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;totalCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;yellow&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="s2"&gt;` Passing tests: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;passedCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;green&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="s2"&gt;` Failing tests: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;failedCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n`&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="p"&gt;};&lt;/span&gt;

  &lt;span class="nx"&gt;handleTestGroupStarted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;testGroup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TestGroup&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="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`\n &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;testGroup&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;grey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nx"&gt;handleTestGroupCompleted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

  &lt;span class="nx"&gt;handleTestRunStarted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="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="s2"&gt; [Pretzel 🥨]: Starting test run...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;yellow&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nx"&gt;handleTestRunCompleted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="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="s2"&gt; [Pretzel 🥨]: Test run completed.&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="nx"&gt;yellow&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="s2"&gt; Summary:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;yellow&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;printSummary&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nx"&gt;handleAfterBlockError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&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="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="s2"&gt;There was an error in an after block...&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;handleSingleTestCompleted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Test&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;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;passed&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="s2"&gt;`   ○ &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; ✓`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;grey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;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;`   ○ &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;description&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; ✖`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;red&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;initEventListeners&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="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;testRunStarted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;testRunCompleted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;afterBlockError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;singleTestCompleted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;testGroupStarted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;testGroupCompleted&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;TestRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;testRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;testRunStarted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleTestRunStarted&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;testRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;testRunCompleted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleTestRunCompleted&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;testRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;afterBlockError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleAfterBlockError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;testRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;testGroupStarted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleTestGroupStarted&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;testRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;testGroupCompleted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleTestGroupCompleted&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;testRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;singleTestCompleted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleSingleTestCompleted&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Part Seven: bin/cli.js
&lt;/h2&gt;

&lt;p&gt;The final piece of the pretzel! This script, when combined with a little config in &lt;code&gt;package.json&lt;/code&gt;, will allow our test framework to be invoked from the command line by users who have installed our package. &lt;/p&gt;

&lt;p&gt;In this script, we use the &lt;code&gt;command-line-args&lt;/code&gt; npm package to collect some required configuration options from the user:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--rootDir&lt;/code&gt; sets the root tests directory&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--matching&lt;/code&gt; accepts a glob pattern to match test files (ie. &lt;code&gt;**/*.test.js&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If these options aren't provided, then we through an error.&lt;/p&gt;

&lt;p&gt;Then, we import the testRunner (importantly, this is being imported from &lt;code&gt;dist/&lt;/code&gt;, not &lt;code&gt;src/&lt;/code&gt;), and initiate the test run by calling &lt;code&gt;testRunner.run(options)&lt;/code&gt; with the provided user options.&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;commandLineArgs&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="s2"&gt;command-line-args&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;optionDefinitions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rootDir&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;r&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="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;matching&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;m&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="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;commandLineArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;optionDefinitions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rootDir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rootDir is a required argument&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;matching&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;matching is a required argument&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;testRunner&lt;/span&gt; &lt;span class="p"&gt;}&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="s2"&gt;../dist/runner.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;testRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To allow this script to be invoked from the command line, we need to register it. We also need to point the package.json to the entry point (&lt;code&gt;dist/main.js&lt;/code&gt;)Add the following to &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pretzel-test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dist/main.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"pretzel-test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./bin/cli.js"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And thats it! We're done!&lt;/p&gt;

&lt;p&gt;Almost...&lt;/p&gt;

&lt;p&gt;In order to use this package to run some tests on your machine, you'll need to &lt;code&gt;npm link&lt;/code&gt; it (since pretzel-test isn't actually available on npm). From your pretzel-test project root run &lt;code&gt;npm link&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Then from the root of the package you want to run &lt;code&gt;pretzel-test&lt;/code&gt; in, run &lt;code&gt;npm link pretzel-test&lt;/code&gt;. You should now be able to &lt;code&gt;require('pretzel-test')&lt;/code&gt; as normal from within this package.&lt;/p&gt;

&lt;p&gt;Alternatively, you can clone the &lt;a href="https://github.com/twosmalltrees/pretzel-test-example"&gt;Pretzel Test Example Repo&lt;/a&gt; that I've created, which provides an example of using the framework and how to set it up. Take a look at the readme for further instructions.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you found this post useful, you can follow me on &lt;a href="https://dev.to/harrison_codes"&gt;dev.to&lt;/a&gt; or &lt;a href="https://twitter.com/_twosmalltrees"&gt;twitter&lt;/a&gt;. I've also got a couple of side projects that you might like to check out:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://www.ippy.io"&gt;ippy.io&lt;/a&gt; - An app for creating beautiful resumes&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://many.tools"&gt;many.tools&lt;/a&gt; - A collection of useful utilities for designers and devs&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
