<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Jo Hanna Pearce</title>
    <description>The latest articles on Forem by Jo Hanna Pearce (@jdpearce).</description>
    <link>https://forem.com/jdpearce</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%2F367122%2Fc8c9be41-0227-4bc8-b4fb-67f63deeccc4.jpeg</url>
      <title>Forem: Jo Hanna Pearce</title>
      <link>https://forem.com/jdpearce</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jdpearce"/>
    <language>en</language>
    <item>
      <title>How to Test Five Common NgRx Effect Patterns</title>
      <dc:creator>Jo Hanna Pearce</dc:creator>
      <pubDate>Fri, 08 May 2020 13:08:37 +0000</pubDate>
      <link>https://forem.com/jdpearce/how-to-test-five-common-ngrx-effect-patterns-26cb</link>
      <guid>https://forem.com/jdpearce/how-to-test-five-common-ngrx-effect-patterns-26cb</guid>
      <description>&lt;ul&gt;
&lt;li&gt;0. Test Harness Setup
&lt;/li&gt;
&lt;li&gt;1. Non-Dispatching Tap Effect
&lt;/li&gt;
&lt;li&gt;2. Dispatching SwitchMap Effect
&lt;/li&gt;
&lt;li&gt;3. Multi-Dispatch Effect
&lt;/li&gt;
&lt;li&gt;4. Store Dependent Effect
&lt;/li&gt;
&lt;li&gt;5. Timed Dispatch Effect
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ⚠️ Requirements
&lt;/h2&gt;

&lt;p&gt;I'm going to assume that you know something about &lt;a href="https://angular.io/" rel="noopener noreferrer"&gt;Angular&lt;/a&gt; development with &lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt; and at least a little about the &lt;a href="https://ngrx.io/" rel="noopener noreferrer"&gt;NgRx&lt;/a&gt; library and the &lt;a href="https://redux.js.org" rel="noopener noreferrer"&gt;Redux&lt;/a&gt; pattern. You might gain some insight from reading through these patterns if you're at the beginning of your journey with these technologies but I don't intend this to be introductory. &lt;/p&gt;

&lt;p&gt;I don't necessarily expect this article to be read from start to end. Consider it reference material, which is why I've linked the patterns at the start.&lt;/p&gt;

&lt;h2&gt;
  
  
  🤯 Introduction
&lt;/h2&gt;

&lt;p&gt;I've been using &lt;a href="https://ngrx.io/" rel="noopener noreferrer"&gt;NgRx&lt;/a&gt; with &lt;a href="https://angular.io" rel="noopener noreferrer"&gt;Angular&lt;/a&gt; for a few years now and yet &lt;em&gt;still&lt;/em&gt; every time I come to testing effects, my mind will often go blank. It's not that tests for effects are particularly arcane, I think it comes down to &lt;a href="https://en.wikipedia.org/wiki/Cognitive_load" rel="noopener noreferrer"&gt;cognitive load&lt;/a&gt; and the Redux-style pattern itself. We know that there's a limited amount of things we can process at any one time, and there is already so much going on in my head trying to manage &lt;a href="https://ngrx.io/guide/store/actions" rel="noopener noreferrer"&gt;actions&lt;/a&gt;, &lt;a href="https://ngrx.io/guide/store/reducers" rel="noopener noreferrer"&gt;reducers&lt;/a&gt; and &lt;a href="https://ngrx.io/guide/store/selectors" rel="noopener noreferrer"&gt;selectors&lt;/a&gt;, not to mention the complexities of understanding &lt;a href="https://rxjs-dev.firebaseapp.com/" rel="noopener noreferrer"&gt;RxJS&lt;/a&gt; pipes that trying to cram testing into my head on top of that just causes my brain to stall. &lt;/p&gt;

&lt;p&gt;One way I try to solve this problem is by having working template examples to hand.&lt;/p&gt;




&lt;h2&gt;
  
  
  📋 Copy/Paste Driven Development
&lt;/h2&gt;

&lt;p&gt;A lot of people deride this kind of technique as programming without thinking, but you know what? I'm ok with that. I don't want to have to think about what I'm writing &lt;em&gt;all&lt;/em&gt; the time. Sometimes, I know the overall shape of what I need to build. I know which pieces I need to put together, but faffing around with the intricacies of &lt;em&gt;how&lt;/em&gt; I do that can be a distraction.  &lt;/p&gt;

&lt;p&gt;Think back to learning about the &lt;a href="https://en.wikipedia.org/wiki/%3F:" rel="noopener noreferrer"&gt;ternary operator&lt;/a&gt; for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How long was it before that started to feel natural? (If it even does?) When I started programming, that felt like a little bit of extra complexity that I didn't need. I'd often have to look up how it was used elsewhere in the code to confirm that I was using it correctly!&lt;/p&gt;

&lt;p&gt;Having reference code to hand that you &lt;em&gt;know&lt;/em&gt; functions correctly is extremely useful, and not just for the novice programmer. You can copy that code and &lt;em&gt;then&lt;/em&gt; start modifying it. You know that you're starting from correct behaviour and you don't have to question everything about how you're writing the code, just the pieces you're changing.  &lt;/p&gt;

&lt;p&gt;This isn't a strategy that's going to work for everything, but I find that when using NgRx (and reactive programming in general) it can be extremely useful as you find yourself writing very similar code over and over again.  &lt;/p&gt;




&lt;p&gt;If you want to refer to some working code while checking out these patterns, I created a workspace here: &lt;a href="https://github.com/jdpearce/ngrx-effects-patterns" rel="noopener noreferrer"&gt;https://github.com/jdpearce/ngrx-effects-patterns&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  0. Test Harness Setup
&lt;/h2&gt;

&lt;p&gt;The workspace I created uses &lt;a href="https://jestjs.io/" rel="noopener noreferrer"&gt;Jest&lt;/a&gt; but you could just as easily use &lt;a href="https://jasmine.github.io/" rel="noopener noreferrer"&gt;Jasmine&lt;/a&gt; for testing. Much of the code would be similar except for the spies. I also use &lt;a href="https://www.npmjs.com/package/jasmine-marbles" rel="noopener noreferrer"&gt;jasmine-marbles&lt;/a&gt; for Observable testing in most cases, but I won't use any particularly complicated syntax, I use it in the most basic way possible where I can get away with it.&lt;/p&gt;

&lt;p&gt;Most effects spec files will be initially set up as follows (imports are omitted for brevity) :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ThingEffects&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;let&lt;/span&gt; &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&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;// These are the effects under test&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;effects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ThingEffects&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;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EffectsMetadata&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ThingEffects&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;// Additional providers - very basic effects tests may not even need these&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ThingService&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;store&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MockStore&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;fromThings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ThingsPartialState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="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;initialState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// You can provide entirely different initial state here&lt;/span&gt;
      &lt;span class="c1"&gt;// it is assumed that this one is imported from the reducer file&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;fromThings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;THINGS_FEATURE_KEY&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;fromThings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="nx"&gt;TestBed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configureTestingModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;ThingEffects&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;ThingService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nf"&gt;provideMockActions&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nf"&gt;provideMockStore&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;initialAppState&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;effects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;TestBed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ThingEffects&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getEffectsMetadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;effects&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;TestBed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ThingService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;TestBed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;MockStore&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;fromThings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ThingsPartialState&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should look like a standard Angular test harness but without any component under test. &lt;a href="https://ngrx.io/api/effects/testing/provideMockActions" rel="noopener noreferrer"&gt;provideMockActions&lt;/a&gt; and &lt;a href="https://ngrx.io/api/store/testing/provideMockStore" rel="noopener noreferrer"&gt;provideMockStore&lt;/a&gt; are crucial for helping us test effects. It was truly the dark times before these existed.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Non-Dispatching Tap Effect
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;performThingAction$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createEffect&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;actions$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;ofType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ThingActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;performThingAction&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;thingService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;performAction&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;dispatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an effect that only does one thing. It calls a service when receiving a particular action. We use &lt;a href="https://rxjs-dev.firebaseapp.com/api/operators/tap" rel="noopener noreferrer"&gt;tap&lt;/a&gt; here because we don't want to modify the stream in any way. We &lt;em&gt;could&lt;/em&gt; change the stream however we like because NgRx isn't going to pay attention to the output, but it's good practice to leave the stream alone unless we have some reason to change it.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.1 Testing for non-dispatch
&lt;/h3&gt;

&lt;p&gt;All effects have &lt;a href="https://ngrx.io/guide/effects/lifecycle#effect-metadata" rel="noopener noreferrer"&gt;metadata&lt;/a&gt; attached and one of the pieces of metadata is whether or not we expect that effect to dispatch another action.&lt;/p&gt;

&lt;p&gt;We can test this by looking at the metadata directly :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should not dispatch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;performThingAction$&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;objectContaining&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1.2 Testing the service call is made
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should call the service&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="c1"&gt;// set up the initial action that triggers the effect&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ThingActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;performThingAction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// spy on the service call&lt;/span&gt;
  &lt;span class="c1"&gt;// this makes sure we're not testing the service, just the effect&lt;/span&gt;
  &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spyOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;performAction&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// set up our action list&lt;/span&gt;
  &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// check that the output of the effect is what we expect it to be&lt;/span&gt;
  &lt;span class="c1"&gt;// (by doing this we will trigger the service call)&lt;/span&gt;
  &lt;span class="c1"&gt;// Note that because we don't transform the stream in any way,&lt;/span&gt;
  &lt;span class="c1"&gt;// the output of the effect is the same as the input.&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;effects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;performThingAction$&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeObservable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;

  &lt;span class="c1"&gt;// check that the service was called&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;performAction&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveBeenCalled&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;blockquote&gt;
&lt;p&gt;⚠️ NB - If we want to cover all the bases we might write another test to check that this effect only fires when &lt;code&gt;ThingActions.performThingAction()&lt;/code&gt; is emitted. I don't tend to do this, as it's just testing whether NgRx &lt;code&gt;ofType&lt;/code&gt; works and whether you've remembered to add it. However, if this is the kind of thing you find you or your team are missing often, feel free to add that test and bring the lack of it up in code reviews. &lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2. Dispatching SwitchMap Effect
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;getThings$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;actions$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;ofType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ThingActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getThings&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;switchMap&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;thingService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getThings&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;things&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;ThingActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getThingsSuccess&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;things&lt;/span&gt; &lt;span class="p"&gt;})),&lt;/span&gt;
        &lt;span class="nf"&gt;catchError&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ThingActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getThingsFailure&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="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you've used NgRx before this may look extremely familiar. An action comes in which triggers something like an API call. This call will either succeed or fail and we dispatch a success or failure action as a result. In large NgRx codebases you might have this kind of effect all over the place.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ NB - Depending on what dispatches the initial &lt;code&gt;getThings&lt;/code&gt; action, you &lt;em&gt;may&lt;/em&gt; want to use &lt;a href="https://rxjs-dev.firebaseapp.com/api/operators/concatMap" rel="noopener noreferrer"&gt;concatMap&lt;/a&gt; instead here. This is something that would probably be more important for a call which updated the backend rather than simply fetched data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2.1 Successful service call
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should get the items and emit when the service call is successful&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="c1"&gt;// set up the initial action that triggers the effect&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ThingActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getThings&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// set up our dummy list of things to return&lt;/span&gt;
  &lt;span class="c1"&gt;// (we could create real things here if necessary)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;things&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="c1"&gt;// spy on the service call and return our dummy list&lt;/span&gt;
  &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spyOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;getThings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;mockReturnValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;things&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="c1"&gt;// set up our action list&lt;/span&gt;
  &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// check that the observable output of the effect is what we expect it to be&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;effects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getThings$&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeObservable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;cold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ThingActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getThingsSuccess&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;things&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;blockquote&gt;
&lt;p&gt;⚠️ NB - It doesn't actually matter whether we use &lt;code&gt;hot&lt;/code&gt; or &lt;code&gt;cold&lt;/code&gt; here. If more than one thing was going to subscribe to the effect it might actually make a difference, but that doesn't happen here. The difference between &lt;code&gt;hot&lt;/code&gt; and &lt;code&gt;cold&lt;/code&gt; observables can be extremely confusing and it may make no sense that within these tests it seems irrelevant, but sorting out that particular &lt;a href="https://en.wikipedia.org/wiki/Gordian_Knot" rel="noopener noreferrer"&gt;Gordian knot&lt;/a&gt; is beyond the scope of this article. Just know that this code, for the moment at least, does the job. (I don't want to encourage cargo cult development though, so when you have bandwidth to dig into the difference, there's &lt;a href="https://medium.com/@benlesh/hot-vs-cold-observables-f8094ed53339" rel="noopener noreferrer"&gt;a good article by Ben Lesh&lt;/a&gt; that goes into detail)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2.2 Unsuccessful service call
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should emit an error action when the service call is unsuccessful&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="c1"&gt;// set up the initial action that triggers the effect&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ThingActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getThings&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;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;There was an error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// spy on the service call and return an error this time&lt;/span&gt;
  &lt;span class="nf"&gt;spyOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;getThings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;and&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;returnValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;throwError&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="c1"&gt;// set up our action list&lt;/span&gt;
  &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// check that the output of the effect is what we expect it to be&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;effects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getThings$&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeObservable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;cold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ThingActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getThingsFailure&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="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 is pretty similar to the previous test except we've sneaked in usage of the &lt;a href="https://rxjs-dev.firebaseapp.com/api/index/function/throwError" rel="noopener noreferrer"&gt;throwError function&lt;/a&gt;. You can follow the link for more detail but all it does is create an observable that immediately emits an error notification, which is exactly what we want to mock as a return value from our &lt;code&gt;getThings&lt;/code&gt; method.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Multi-Dispatch Effect
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;initialiseThing$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;actions$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;ofType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ThingActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initialisingAction&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;switchMap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;_action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;thingService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getThings&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
    &lt;span class="nf"&gt;switchMap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;things&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="na"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
      &lt;span class="k"&gt;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;things&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ThingActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getThingsSuccess&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;things&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ThingActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialiseComplete&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;actions&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;Sometimes you need to dispatch more than one action. Again the choice of &lt;code&gt;switchMap&lt;/code&gt; or &lt;code&gt;concatMap&lt;/code&gt; (or even &lt;code&gt;mergeMap&lt;/code&gt;) is very much context dependent, the important thing here is that one action goes in and one or more come out.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ NB - This also illustrates a slightly magical feature of &lt;code&gt;switchMap&lt;/code&gt; where if you return any array-like object from the projection, it will automagically treat it like an observable of the objects in the array. In this case it's like switching to an &lt;code&gt;Observable&amp;lt;Action&amp;gt;&lt;/code&gt;. If you find this confusing (and I wouldn't blame you here) you can replace &lt;code&gt;return actions;&lt;/code&gt; with &lt;code&gt;return from(actions);&lt;/code&gt; instead (cf. &lt;a href="https://rxjs-dev.firebaseapp.com/api/index/function/from" rel="noopener noreferrer"&gt;from&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3.1 Testing for multiple action output
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should emit initialiseComplete &amp;amp; getThingsSuccess if thing is found.&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;things&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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thing 1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spyOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;getThings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;mockReturnValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;things&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ThingActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialisingAction&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;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;cold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;(bc)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ThingActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getThingsSuccess&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;things&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="na"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ThingActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialiseComplete&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;effects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initialiseThing$&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeObservable&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;This shows the usage of a &lt;a href="https://rxjs-dev.firebaseapp.com/guide/testing/internal-marble-tests" rel="noopener noreferrer"&gt;sync grouping&lt;/a&gt;. That is, groups of notifications which are all emitted together. In this case, our &lt;code&gt;getThingsSuccess&lt;/code&gt; and &lt;code&gt;initialiseComplete&lt;/code&gt;. I've used this kind of pattern before to end an initialisation sequence of actions without making the last action do double-duty. Being able to fork your actions like this can be extremely useful if you have main sequences of actions with optional side quests being triggered (that's how I think of them).&lt;/p&gt;

&lt;h3&gt;
  
  
  3.2 Testing single action output
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should just emit initialiseComplete if no things are found.&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;things&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spyOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;getThings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;mockReturnValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;things&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ThingActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialisingAction&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;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;cold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ThingActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialiseComplete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;effects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initialiseThing$&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeObservable&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;This should look familiar. There's nothing new introduced here at all! Yay!&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Store Dependent Effect
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;storeReadingEffect$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createEffect&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;actions$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;ofType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ThingActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;thingsModified&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nf"&gt;withLatestFrom&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;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selectThings&lt;/span&gt;&lt;span class="p"&gt;))),&lt;/span&gt;
      &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;_action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;things&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;thingService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;persistThings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;things&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;dispatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sometimes you end up needing to pull a value from the store. Don't feel bad about that. It's actually extremely common! In this case we're using &lt;a href="https://rxjs-dev.firebaseapp.com/api/operators/withLatestFrom" rel="noopener noreferrer"&gt;withLatestFrom&lt;/a&gt; which means that every time we get a &lt;code&gt;thingsModified&lt;/code&gt; action, we grab the latest state and &lt;code&gt;selectThings&lt;/code&gt; from it. To test this, we need to provide some state and that's where &lt;code&gt;provideMockStore&lt;/code&gt; and the &lt;a href="https://ngrx.io/api/store/testing/MockStore" rel="noopener noreferrer"&gt;MockStore&lt;/a&gt; come into play.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should read things from the store and do something with them&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;things&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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thing 1&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="c1"&gt;// Note here that we have to provide a ThingsPartialState&lt;/span&gt;
  &lt;span class="c1"&gt;// not just a ThingsState.&lt;/span&gt;
  &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;fromThings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;THINGS_FEATURE_KEY&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;log&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
      &lt;span class="nx"&gt;things&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;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spyOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;persistThings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;mockReturnValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;things&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ThingActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;thingsModified&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;effects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storeReadingEffect$&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeObservable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;things&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;

  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;persistThings&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;things&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 only new thing here is that we call &lt;code&gt;store.setState&lt;/code&gt;. This is a wonderous boon to the test writing developer. In the old times we would actually dispatch actions to build up store state, but that would require those actions and associated reducers already existed and you would end up tightly coupling your tests to unrelated code. This is much simpler and neater (and it means you can write tests when the actions and reducers that might populate that slice of the store don't even exist yet).&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Timed Dispatch Effect
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;timedDispatchEffect$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;actions$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;ofType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ThingActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startThingTimer&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ThingsEffects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timerDuration&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;mapTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ThingActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;thingTimerComplete&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 is a slightly contrived example, but I have done similar things in the past. One particular case involved waiting for a few seconds so that a user could read a notification before they were redirected elsewhere.&lt;/p&gt;

&lt;p&gt;To test this we need to abandon marbles though!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should dispatch after a delay (fakeAsync)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;fakeAsync&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;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ThingActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startThingTimer&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;effects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timedDispatchEffect$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;action&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;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeUndefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nf"&gt;tick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ThingsEffects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timerDuration&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ThingActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;thingTimerComplete&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;Angular handily provides us with the &lt;a href="https://angular.io/api/core/testing/fakeAsync" rel="noopener noreferrer"&gt;fakeAsync&lt;/a&gt; function which lets us control the flow of time. &lt;a href="https://rxjs-dev.firebaseapp.com/api/operators/delay" rel="noopener noreferrer"&gt;delay&lt;/a&gt; has its concept of time based on the scheduler it uses, so in order to test this with marbles we would have to (somehow) tell it that we want to use the &lt;a href="https://rxjs-dev.firebaseapp.com/api/testing/TestScheduler" rel="noopener noreferrer"&gt;TestScheduler&lt;/a&gt; alongside hot and cold rather than the default &lt;a href="https://rxjs-dev.firebaseapp.com/guide/scheduler#scheduler-types" rel="noopener noreferrer"&gt;async Scheduler&lt;/a&gt;. This wouldn't be a trivial thing to do as often these kinds of operators are buried deep in your effect and you really don't want to have to start injecting schedulers into your effects. It's simpler just to discard marbles entirely and test it with &lt;code&gt;fakeAsync&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;fakeAsync&lt;/code&gt; we set up a normal subscription to the effect as we would in non-test code and then trigger it by ticking forward time with a function appropriately called &lt;code&gt;tick&lt;/code&gt;. When we tick far enough, the observer will be triggered, &lt;code&gt;output&lt;/code&gt; will be populated and we can check that it matches what we expect!&lt;/p&gt;




&lt;p&gt;That brings us to the end of these patterns with the important point that there is always another way to test them. You don't have to use marbles at all, in fact it could be argued that they make things more complicated for these kinds of cases not less! That decision is up to you. Don't worry too much about what you decide as long as it makes sense to you. There's never any point in sticking with something you find confusing. Do what works for you.&lt;/p&gt;

&lt;p&gt;As always, if you have any questions, corrections or comments, feel free to get in touch here or on &lt;a href="https://twitter.com/jdpearce" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ngrx</category>
      <category>typescript</category>
      <category>angular</category>
      <category>patterns</category>
    </item>
    <item>
      <title>TIL: HTMLLinkElement.href returns more than you think...</title>
      <dc:creator>Jo Hanna Pearce</dc:creator>
      <pubDate>Tue, 21 Apr 2020 16:29:59 +0000</pubDate>
      <link>https://forem.com/jdpearce/til-htmllinkelement-href-returns-more-than-you-think-1p5k</link>
      <guid>https://forem.com/jdpearce/til-htmllinkelement-href-returns-more-than-you-think-1p5k</guid>
      <description>&lt;p&gt;I recently came across a bit of code that was trying to change the &lt;a href="https://en.wikipedia.org/wiki/Favicon" rel="noopener noreferrer"&gt;favicon&lt;/a&gt; on every route change of a single page application.&lt;/p&gt;

&lt;p&gt;i.e. Every time the URL changed from &lt;code&gt;/users&lt;/code&gt; to &lt;code&gt;/users/fred&lt;/code&gt; a function would run that checked the current &lt;code&gt;favicon&lt;/code&gt; href and updated it if necessary.&lt;/p&gt;

&lt;p&gt;It did this with a tiny bit of javascript like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// where `expectedHref` is something like '/favicon-shop.ico'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;link&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;link[rel*=icon]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;expectedHref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;expectedHref&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What I noticed was that it was changing the favicon with &lt;em&gt;every&lt;/em&gt; route change. Why?&lt;/p&gt;

&lt;p&gt;It turns out that the &lt;code&gt;href&lt;/code&gt; property on an &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLinkElement" rel="noopener noreferrer"&gt;HTMLLinkElement&lt;/a&gt; always returns the full &lt;a href="https://en.wikipedia.org/wiki/Uniform_Resource_Identifier" rel="noopener noreferrer"&gt;URI&lt;/a&gt; of the linked resource rather than just the content of the &lt;code&gt;href&lt;/code&gt; attribute!&lt;/p&gt;

&lt;p&gt;We should have been using &lt;code&gt;getAttribute&lt;/code&gt; instead 🤦‍♀️&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// = 'http://example.com/favicon.ico'&lt;/span&gt;
&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;href&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// = '/favicon.ico'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>todayilearned</category>
      <category>javascript</category>
    </item>
    <item>
      <title>15 Minute Nx on a bed of Clouds</title>
      <dc:creator>Jo Hanna Pearce</dc:creator>
      <pubDate>Wed, 15 Apr 2020 17:07:31 +0000</pubDate>
      <link>https://forem.com/jdpearce/15-minute-nx-on-a-bed-of-clouds-1290</link>
      <guid>https://forem.com/jdpearce/15-minute-nx-on-a-bed-of-clouds-1290</guid>
      <description>&lt;p&gt;With all the focus these days on home cooking, I thought I'd write up a recipe of my own which you can follow without even having to go into the kitchen.  &lt;/p&gt;

&lt;p&gt;For those of you craving the taste of a real monorepo, this recipe combines &lt;a href="https://nx.dev/" rel="noopener noreferrer"&gt;Nx&lt;/a&gt; with a continuous integration service and then adds some fresh &lt;a href="https://nx.app/" rel="noopener noreferrer"&gt;Nx Cloud&lt;/a&gt; for a piquant dash of the efficiency that comes with &lt;a href="https://en.wikipedia.org/wiki/Memoization" rel="noopener noreferrer"&gt;computation memoization&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;If it's not clear what computation memoization is or how it can help you, then this could be the recipe for you!  &lt;/p&gt;

&lt;p&gt;Unlike a standard recipe the product of following this set of instructions should be &lt;em&gt;understanding&lt;/em&gt;. The quality of what you create as a result of combining all the ingredients together doesn't matter. You could love or hate the result, but what I hope you'll come away with is a little more knowledge. That's what writing this achieved for me.  &lt;/p&gt;

&lt;p&gt;I want to emphasise that I describe this as a recipe because there is no single right way to combine all these ingredients. What follows is something that worked for me. If you find any problems, errors or just have questions, feel free to tweet me &lt;a href="https://twitter.com/jdpearce" rel="noopener noreferrer"&gt;@jdpearce&lt;/a&gt;.  &lt;/p&gt;

&lt;h2&gt;
  
  
  ⚠️ Requirements
&lt;/h2&gt;

&lt;p&gt;There is only so much I can explain without making this article unwieldy, so I'll assume that anyone reading this has some understanding of JavaScript development and already has &lt;a href="https://nodejs.org" rel="noopener noreferrer"&gt;Node&lt;/a&gt; and &lt;a href="https://www.npmjs.com/" rel="noopener noreferrer"&gt;npm&lt;/a&gt; installed. You can use another package manager if you like, but I'm only going to provide instructions for the lowest common denominator.&lt;/p&gt;

&lt;p&gt;I am going to assume you have &lt;em&gt;some&lt;/em&gt; idea what a &lt;a href="https://en.wikipedia.org/wiki/Monorepo" rel="noopener noreferrer"&gt;monorepo&lt;/a&gt; actually is and why you might want to use one. Following this recipe may give you some insight into how they can be used, but I'm not going to go into detail about the pros and cons.&lt;/p&gt;

&lt;p&gt;While I list having a &lt;a href="https://github.com/" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; account as an ingredient, I'm not going to explain how to set up new repositories and I will assume a certain amount of knowledge of &lt;a href="https://git-scm.com/" rel="noopener noreferrer"&gt;git&lt;/a&gt; itself. There are better articles out there which can go into detail about this. If you run into problems I will always recommend "&lt;a href="https://ohshitgit.com/" rel="noopener noreferrer"&gt;Oh Shit, Git!?!&lt;/a&gt;" 😁  &lt;/p&gt;

&lt;h2&gt;
  
  
  🥬 Ingredients
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;1 x &lt;a href="https://nx.dev/" rel="noopener noreferrer"&gt;Nx (Extensible Dev Tools for Monorepos)&lt;/a&gt; workspace (v9.2.2 as of writing)&lt;/li&gt;
&lt;li&gt;1 x &lt;a href="https://nx.app/" rel="noopener noreferrer"&gt;Nx Cloud (Computation Memoization in the Cloud)&lt;/a&gt; account&lt;/li&gt;
&lt;li&gt;1 x &lt;a href="https://circleci.com/" rel="noopener noreferrer"&gt;CircleCI (Continuous integration)&lt;/a&gt; account&lt;/li&gt;
&lt;li&gt;1 x &lt;a href="https://github.com/" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; account&lt;/li&gt;
&lt;li&gt;Back and/or front end frameworks to taste (I'm going to use &lt;a href="https://reactjs.org/" rel="noopener noreferrer"&gt;React&lt;/a&gt; and &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;Express&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🥒 Preparation
&lt;/h2&gt;

&lt;p&gt;Before we start, I recommend that you have accounts with &lt;a href="https://circleci.com/" rel="noopener noreferrer"&gt;CircleCI&lt;/a&gt;, &lt;a href="https://nx.app/" rel="noopener noreferrer"&gt;Nx Cloud&lt;/a&gt; and &lt;a href="https://github.com/" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; ready. You don't want to ruin the flow of a good home cooking session by having to run out to the shops and generate new passwords.  &lt;/p&gt;

&lt;p&gt;Make sure your &lt;a href="https://circleci.com/" rel="noopener noreferrer"&gt;CircleCI&lt;/a&gt; account is connected to your &lt;a href="https://github.com/" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; account. You can achieve that via the &lt;a href="https://circleci.com/account" rel="noopener noreferrer"&gt;Account Integrations&lt;/a&gt; dashboard.  &lt;/p&gt;

&lt;p&gt;I'm going to assume that you also have &lt;a href="https://nx.dev/" rel="noopener noreferrer"&gt;Nx&lt;/a&gt; installed globally. You don't need to do this, you can just as easily use &lt;code&gt;npx nx&lt;/code&gt; or &lt;code&gt;yarn nx&lt;/code&gt; to call it, but it does mean I have to write less. To install with &lt;code&gt;npm&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Now that we're all prepared, let's get cooking! &lt;/p&gt;

&lt;h2&gt;
  
  
  1. Creating the Nx Workspace (Monorepo)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ⏱ 3 minutes
&lt;/h3&gt;

&lt;p&gt;Find a place on your file system where you want to create the new workspace and run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-nx-workspace@latest nx-cloud-recipe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll be asked a set of questions for the kind of workspace you want to create. I'm going to choose the &lt;code&gt;react-express&lt;/code&gt; preset which will create two applications; a React front end and an Express API. You can call the front end application whatever you like, but I'll go with &lt;code&gt;todos&lt;/code&gt; as that seems to be fairly standard &lt;del&gt;tutorial&lt;/del&gt; recipe fare, and I'll just select &lt;code&gt;CSS&lt;/code&gt; as the default stylesheet format for now.  &lt;/p&gt;

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

&lt;p&gt;Once the creation script has worked its magic, you should find a new workspace with an initialised git repository in the &lt;code&gt;nx-cloud-recipe&lt;/code&gt; folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;nx-cloud-recipe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To check that everything is set up as expected, why not run a test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nx &lt;span class="nb"&gt;test &lt;/span&gt;todos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On my machine this runs in a couple of seconds and the output looks like this:  &lt;/p&gt;

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

&lt;p&gt;Or we could run all the tests in the monorepo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nx run-many &lt;span class="nt"&gt;--target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output of that should look something like this:  &lt;/p&gt;

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

&lt;p&gt;You should find that the output for this command is generated &lt;em&gt;almost instantaneously&lt;/em&gt;. This is because Nx locally caches the output of certain computational tasks, such as in this case running tests. There only happens to be one test suite in the entire monorepo and we just ran it and therefore cached it.  &lt;/p&gt;

&lt;p&gt;If we make changes to the &lt;code&gt;todos&lt;/code&gt; application, the same command will be smart enough to recognise that something has changed and the test will be run.  &lt;/p&gt;

&lt;p&gt;You can pause here if you wish to get a feel for this particular ingredient. Try running both applications and seeing the output at &lt;a href="http://localhost:4200" rel="noopener noreferrer"&gt;http://localhost:4200&lt;/a&gt; -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nx serve api &amp;amp; nx serve todos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;NB&lt;/strong&gt; You'll need to run these in different instances of &lt;code&gt;cmd&lt;/code&gt;/&lt;code&gt;powershell&lt;/code&gt; if you're running on Windows. Alternatively, you could investigate the power of &lt;a href="https://nx.dev/react/plugins_workspace_builders/run-commands" rel="noopener noreferrer"&gt;&lt;code&gt;run-commands&lt;/code&gt;&lt;/a&gt;, but that's beyond the scope of this recipe for the moment.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  2. Push Your Monorepo to GitHub
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ⏱ 2 minutes
&lt;/h3&gt;

&lt;p&gt;Create a new, empty repository on GitHub, I've called mine the same as the local monorepo, but you don't have to (you could call it &lt;code&gt;bob&lt;/code&gt; or &lt;code&gt;alice&lt;/code&gt; if you really wanted 🤷‍♀️). After you've done that, come back to the local command line to push the generated code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote add origin https://github.com/jdpearce/nx-cloud-recipe.git
git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;NB&lt;/strong&gt; Don't try to push to my repo, I don't think you'll be allowed. Copy the link to your own repository from the screen that GitHub helpfully shows you with all the possible ways you can push code to it.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  3. Connect to CircleCI
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ⏱ 2 minutes
&lt;/h3&gt;

&lt;p&gt;Go to your &lt;a href="https://circleci.com/dashboard" rel="noopener noreferrer"&gt;CircleCI dashboard&lt;/a&gt; and select "Add Projects". This should bring you to a page something like this where you can search for the new GitHub repository that you've just created:  &lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;ℹ️ &lt;strong&gt;NB&lt;/strong&gt; If the repository doesn't appear in the list, you may have to refresh the page.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Click on the "Set up Project" button and then select the "Node" configuration template:  &lt;/p&gt;

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

&lt;p&gt;Next we have to click the appallingly badly named "Start Building" button, which does nothing of the sort:  &lt;/p&gt;

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

&lt;p&gt;We're going to let CircleCI create a new branch called &lt;code&gt;circleci-project-setup&lt;/code&gt; and commit a new file &lt;code&gt;.circle/config.yml&lt;/code&gt;  &lt;/p&gt;

&lt;p&gt;Click on the "Add Config" button and let it do it's thing.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;NB&lt;/strong&gt; I am not a big fan of &lt;a href="https://yaml.org/" rel="noopener noreferrer"&gt;YAML&lt;/a&gt;. I think it's difficult to write and more importantly difficult to &lt;em&gt;read&lt;/em&gt;. Be warned that there is unfortunately quite a bit of it coming up. &lt;a href="https://tvtropes.org/pmwiki/pmwiki.php/Main/YMMV" rel="noopener noreferrer"&gt;YMMV&lt;/a&gt;, of course...  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  4. Adding &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt; jobs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ⏱ 5 minutes
&lt;/h3&gt;

&lt;p&gt;At your local command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git fetch
git checkout circleci-project-setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're going to cheat a little here. Detailed configuration of CircleCI is far beyond the scope of this recipe so I'm going to provide you with a store-bought configuration that sets up both &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt; jobs. There are many ways to do this, so don't believe for a moment that this is the best or only way to achieve this goal. If you have the time artisanal, hand-crafted YAML is the way to go, but store-bought is fine for now.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ &lt;strong&gt;NB&lt;/strong&gt; Deployment is also beyond the scope of this recipe, but my colleague &lt;a href="https://twitter.com/volkeron" rel="noopener noreferrer"&gt;Rares Matei&lt;/a&gt; is publishing something covering deployment in the near future.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Using your editor of choice, replace the contents of the &lt;code&gt;.circleci/config.yml&lt;/code&gt; file with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.1&lt;/span&gt;

&lt;span class="na"&gt;orbs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;node&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;circleci/node@2.0.1&lt;/span&gt;

&lt;span class="c1"&gt;# Reusable Commands&lt;/span&gt;
&lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;npm_install&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Install&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Cache&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Dependencies'&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;save_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nx-cloud-recipe-{{ checksum "package-lock.json" }}&lt;/span&gt;
          &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;~/.cache&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node_modules&lt;/span&gt;

  &lt;span class="na"&gt;restore_npm_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Restore&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Cached&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Dependencies'&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;restore_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;nx-cloud-recipe-{{ checksum "package-lock.json" }}&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;nx-cloud-recipe-&lt;/span&gt; &lt;span class="c1"&gt;# used if checksum fails&lt;/span&gt;

  &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Setup&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Executor'&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;checkout&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;attach_workspace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;at&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/project&lt;/span&gt;

&lt;span class="c1"&gt;# Available Jobs&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;initialise&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;executor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node/default&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;checkout&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;restore_npm_cache&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm_install&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;persist_to_workspace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/project&lt;/span&gt;
          &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node_modules&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;dist&lt;/span&gt;

  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;executor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node/default&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;setup&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build all affected projects&lt;/span&gt;
          &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx nx affected:build --base=master --head=HEAD&lt;/span&gt;

  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;executor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node/default&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;setup&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run all affected tests&lt;/span&gt;
          &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx nx affected:test --base=master --head=HEAD&lt;/span&gt;

&lt;span class="na"&gt;workflows&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build-and-test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;initialise&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;requires&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;initialise&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;requires&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;initialise&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;😱&lt;/p&gt;

&lt;p&gt;This is a really scary amount of YAML and personally I find it difficult to read. CircleCI's documentation is pretty unhelpful for the novice too, so I'll try to briefly explain what's going here.  &lt;/p&gt;

&lt;p&gt;At the top level we have groupings of &lt;a href="https://circleci.com/docs/2.0/jobs-steps/#section=getting-started" rel="noopener noreferrer"&gt;&lt;code&gt;orbs&lt;/code&gt;, &lt;code&gt;commands&lt;/code&gt;, &lt;code&gt;jobs&lt;/code&gt; and &lt;code&gt;workflows&lt;/code&gt;&lt;/a&gt;. In the &lt;code&gt;orbs&lt;/code&gt; group we indicate that we're using the &lt;a href="https://circleci.com/orbs/registry/orb/circleci/node" rel="noopener noreferrer"&gt;&lt;code&gt;circleci/node@2.0.1&lt;/code&gt;&lt;/a&gt; orb, which is a collection of bits and pieces for working with &lt;code&gt;node&lt;/code&gt; projects. In particular it includes the default executor which is the environment used to run the jobs.  &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;commands&lt;/code&gt; group declares and defines three commands that can be used within jobs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;npm_install&lt;/code&gt; - runs a standard dependency installation and populates a local cache&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;restore_npm_cache&lt;/code&gt; - restores from that local cache&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;setup&lt;/code&gt; - checks out the code and restores a workspace&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;jobs&lt;/code&gt; group declares and defines three jobs that we can sequence within workflows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;initialise&lt;/code&gt; - check out the code, restore caches, run an npm install command and then persist all this to the workspace&lt;/li&gt;
&lt;li&gt; &lt;code&gt;build&lt;/code&gt; - builds all the affected projects&lt;/li&gt;
&lt;li&gt; &lt;code&gt;test&lt;/code&gt; - tests all the affected projects&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ &lt;strong&gt;NB&lt;/strong&gt; It's worth noting here that the build and test jobs use &lt;a href="https://nx.dev/react/cli/affected" rel="noopener noreferrer"&gt;&lt;code&gt;nx affected&lt;/code&gt;&lt;/a&gt; logic to decide which projects to build or test. Nx is smart enough to know which projects have been touched by a particular commit (or range of commits) and will run the appropriate target for those projects &lt;strong&gt;&lt;em&gt;only&lt;/em&gt;&lt;/strong&gt;. This should save you considerable amounts of time in your CI environment. In this case we're only running build and test for those projects which have changes when comparing between &lt;code&gt;HEAD&lt;/code&gt; and the current &lt;code&gt;master&lt;/code&gt; branch, so this should work well for pull requests.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lastly, the &lt;code&gt;workflows&lt;/code&gt; group defines a single workflow called &lt;code&gt;build-and-test&lt;/code&gt; which specifies that the &lt;code&gt;initialise&lt;/code&gt; job must be run before either &lt;code&gt;build&lt;/code&gt; or &lt;code&gt;test&lt;/code&gt; can be run.&lt;/p&gt;

&lt;p&gt;If you save, commit, and push this to GitHub, you should see something like this in CircleCI:&lt;/p&gt;

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

&lt;p&gt;🎉&lt;/p&gt;

&lt;p&gt;If everything looks good as above, we can get that configuration into the &lt;code&gt;master&lt;/code&gt; branch with a pull request.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ &lt;strong&gt;NB&lt;/strong&gt; You &lt;em&gt;could&lt;/em&gt; make this workflow run only when a pull request is &lt;em&gt;created&lt;/em&gt;, but that (along with many other configuration niceties) is beyond the scope of this recipe. Still, this is one of the many aspects of this recipe that you can experiment with later! 🧪&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  5. Connect to Nx Cloud
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ⏱ 3 minutes
&lt;/h3&gt;

&lt;p&gt;The first step is to go to your &lt;a href="https://nx.app/" rel="noopener noreferrer"&gt;Nx Cloud dashboard&lt;/a&gt; and create a new workspace. I've called mine the same as the repository, but again you don't have to do this if you're not really bothered about naming&lt;sup id="fnref1"&gt;1&lt;/sup&gt;.&lt;/p&gt;

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

&lt;p&gt;Once you've named the workspace, you'll be presented with this set of instructions for CI and local configuration. I've blocked out the tokens in the screenshot above so that nefarious web users don't store their caches in my workspace and use up my Nx Cloud Coupons (you should get 5 hours free when you first sign up).&lt;/p&gt;

&lt;p&gt;We're now going to add that local &lt;em&gt;read-only&lt;/em&gt; token to our &lt;code&gt;nx-cloud-recipe&lt;/code&gt; repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout master
git pull
git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; nx-cloud-configuration
npm &lt;span class="nb"&gt;install&lt;/span&gt; @nrwl/nx-cloud &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; nx g @nrwl/nx-cloud:init &lt;span class="nt"&gt;--token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;token&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(The last line here should be copied and pasted from the "Set up for local development" section shown above)&lt;/p&gt;

&lt;p&gt;Next we need to add the &lt;em&gt;read-write&lt;/em&gt; token to our CircleCI setup:&lt;/p&gt;

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

&lt;p&gt;(You can find this by selecting the "Workflows" section on the left and then clicking the little cog icon next to the &lt;code&gt;nx-cloud-recipe&lt;/code&gt; workflow)&lt;/p&gt;

&lt;p&gt;CircleCI is now ready for you to commit and push the &lt;code&gt;nx-cloud-configuration&lt;/code&gt; branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-am&lt;/span&gt; &lt;span class="s2"&gt;"feat: add nx cloud configuration"&lt;/span&gt;
git push &lt;span class="nt"&gt;--set-upstream&lt;/span&gt; origin nx-cloud-configuration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should result in a beautiful green set of workflow steps which means you're ready to create a pull request and merge that back into &lt;code&gt;master&lt;/code&gt;!&lt;/p&gt;

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

&lt;p&gt;Time now for you to sit back, pour a glass of something enjoyable and serve the completed dish...  &lt;/p&gt;




&lt;h2&gt;
  
  
  🍇 Taste the Fruits of Your Labour!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://nx.dev/" rel="noopener noreferrer"&gt;Nx&lt;/a&gt; and its &lt;a href="https://nx.dev/react/cli/affected" rel="noopener noreferrer"&gt;affected logic&lt;/a&gt; has your back when it comes to saving time in your continuous integration environment. When it comes to saving &lt;em&gt;developer&lt;/em&gt; time locally, that's where &lt;a href="https://nx.app/" rel="noopener noreferrer"&gt;Nx Cloud&lt;/a&gt; can really shine.&lt;/p&gt;

&lt;p&gt;Check out the repo into a new folder, e.g.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ..
git clone https://github.com/jdpearce/nx-cloud-recipe.git nx-cloud-recipe2
&lt;span class="nb"&gt;cd &lt;/span&gt;nx-cloud-recipe2
npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;NB&lt;/strong&gt; I'd rather you didn't clone my repository, but you can if you want. I make no guarantees about it having valid coupons on the account though, so you may not see any effect.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This repo shouldn't have any local cache since we haven't run build or test here before, however, if we try building everything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nx run-many &lt;span class="nt"&gt;--target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;build &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see almost &lt;em&gt;instant&lt;/em&gt; output:&lt;/p&gt;

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

&lt;p&gt;With the new &lt;a href="https://nx.app/" rel="noopener noreferrer"&gt;Nx Cloud&lt;/a&gt; configuration in place, and because you haven't yet made any changes to the repository, the build process you run locally would be identical to the one that was run in CI, so Nx will read from the cache that was generated when the build ran in CI, saving us the amount of time it would normally have taken to run!  &lt;/p&gt;

&lt;p&gt;If we check back on the &lt;a href="https://nx.app/" rel="noopener noreferrer"&gt;Nx Cloud&lt;/a&gt; site, you should be able to see that we've had an impact on the graph:  &lt;/p&gt;

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

&lt;p&gt;A whole MINUTE saved! 🤯  &lt;/p&gt;

&lt;p&gt;Ok, maybe that's not hugely impressive in this case, but then we did create this workspace mere minutes ago.  &lt;/p&gt;

&lt;p&gt;ℹ️ &lt;strong&gt;NB&lt;/strong&gt; One minute is the smallest unit that the chart labels will actually display, but the chart is drawn with finer precision, which is why the "minute" saved in &lt;code&gt;build&lt;/code&gt; is bigger than the "minute" saved in &lt;code&gt;test&lt;/code&gt; 🤓  &lt;/p&gt;

&lt;p&gt;Imagine how much time you would save if this were a mature workspace with numerous apps and libraries&lt;sup id="fnref2"&gt;2&lt;/sup&gt;. We've seen cases where in only weeks, teams have saved hundreds of hours of developer time. That's &lt;em&gt;your&lt;/em&gt; time, and that means more time for you to do the things you care about.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Naming is, of course, one of the two hardest problems in computer science. Those being:   ↩&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Naming things&lt;/li&gt;
&lt;li&gt;Cache invalidation&lt;/li&gt;
&lt;li&gt;Off-by-one errors&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;


&lt;li id="fn2"&gt;

&lt;p&gt;You don't actually have to imagine this. The following chart shows that over two weeks one particular team of 20-30 saved enough time to make up a whole extra developer! &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ojupqaseqtbg01vu462.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ojupqaseqtbg01vu462.png" width="800" height="501"&gt;&lt;/a&gt;   ↩&lt;/p&gt;


&lt;/li&gt;


&lt;/ol&gt;

</description>
      <category>nx</category>
      <category>javascript</category>
      <category>nxcloud</category>
      <category>monorepo</category>
    </item>
  </channel>
</rss>
