<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Julio Olivera</title>
    <description>The latest articles on DEV Community by Julio Olivera (@julioolvr).</description>
    <link>https://dev.to/julioolvr</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%2F33299%2Fc9fe2bba-95ec-4760-a7d0-3ffb36a07309.JPG</url>
      <title>DEV Community: Julio Olivera</title>
      <link>https://dev.to/julioolvr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/julioolvr"/>
    <language>en</language>
    <item>
      <title>Clean Code and Code Reviews</title>
      <dc:creator>Julio Olivera</dc:creator>
      <pubDate>Tue, 28 Jan 2020 02:40:14 +0000</pubDate>
      <link>https://dev.to/julioolvr/clean-code-and-code-reviews-35oc</link>
      <guid>https://dev.to/julioolvr/clean-code-and-code-reviews-35oc</guid>
      <description>&lt;p&gt;&lt;a href="https://twitter.com/dan_abramov"&gt;Dan Abramov&lt;/a&gt; recently published a blog post called &lt;a href="https://overreacted.io/goodbye-clean-code/"&gt;"Goodbye, Clean Code"&lt;/a&gt;, which looks back into an old work story and reflects on two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The pursuit of "clean" code just for the sake of it (and how it can actually backfire).&lt;/li&gt;
&lt;li&gt;The team dynamics around that episode.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd like to focus on the second part because it's something I've been thinking about a lot.&lt;/p&gt;

&lt;p&gt;To keep it brief (do read Dan's post, it's a short one and really drives the point home), the story is about a specific implementation by a coworker where Dan identifies duplication as something undesirable. He makes some changes, and then:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I checked in my refactoring to master and went to bed, proud of how I untangled my colleague’s messy code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lately, I've been thinking about code reviews and their purpose. I want to identify ways we can be better at them and, in order to do that, we need to understand &lt;em&gt;why&lt;/em&gt; do we have a code review process in the first place. I like this story because it highlights a couple of places where code reviews might be particularly useful.&lt;/p&gt;

&lt;p&gt;Quoting from the article again, something I wholeheartedly agree with:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A healthy engineering team is constantly building trust. Rewriting your teammate’s code without a discussion is a huge blow to your ability to effectively collaborate on a codebase together.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even if the code review process might be skipped in some exceptional cases, it most likely won't be for pure refactoring work. This means that, &lt;strong&gt;just by following the process, a situation where one rewrites a teammate's code without any discussion won't happen.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Another aspect that's often mentioned as an advantage of going through a code review process is that of learning. Sometimes that learning implies learning something new - some new API, or a new approach or even design pattern that can help tackle a problem. In this case, the post reflects about how reducing duplication doesn't necessarily lead to objectively &lt;em&gt;better&lt;/em&gt; code, and how it's instead a series of trade-offs. While it's possible that this wouldn't have come up during the review, if it did, it would've been a kind of learning where we question our own assumptions. Instead of only learning something new, we shed new light on something that we thought was clear. &lt;strong&gt;What initially might have been a routine comment, after being challenged becomes an opportunity to reevaluate and learn.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>codereview</category>
    </item>
    <item>
      <title>Your work is more than a diff</title>
      <dc:creator>Julio Olivera</dc:creator>
      <pubDate>Mon, 29 Apr 2019 04:11:18 +0000</pubDate>
      <link>https://dev.to/julioolvr/your-work-is-more-than-a-diff-8p2</link>
      <guid>https://dev.to/julioolvr/your-work-is-more-than-a-diff-8p2</guid>
      <description>&lt;p&gt;When working on a feature we don't think in terms of the files that need changing, line by line. We think at a higher level, more conceptually. On a typical MVC web application, a route is related to a specific controller's action, which in turn is related to some model performing the business logic. We think of all of these moving parts as a single "thing", just different parts in the same assembly line.&lt;/p&gt;

&lt;p&gt;Yet when we send a pull request and someone has to review our code, what they see is a series of changes. File after file. &lt;strong&gt;There's a whole layer of meaning that existed on our minds only, and now the reviewer has to reverse engineer it from the output of &lt;code&gt;git diff&lt;/code&gt;&lt;/strong&gt;. Instead of being able to see the data flow of an API call, our reviewer will see a bunch of controller files' modifications. Then maybe the models, and they have to go back and forth to understand what's going on. Then maybe at the end they'll see the new routes.&lt;/p&gt;

&lt;p&gt;The exact details are highly dependent on the project and on our design pattern of choice but whatever the case, &lt;strong&gt;looking at a series of modified files, line by line, doesn't convey the same ideas and thought-process that was going through our heads while coding&lt;/strong&gt;. The underlying structure and design is not immediately obvious by looking at the changes alone. And while the code is the final form of those ideas, &lt;strong&gt;it's the design, the solution that we came up with at a conceptual level, what makes the real output of our work&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Based on that observation, I think as contributors it's important to find ways to transmit that thought process to our reviewers. And while I doubt there's a perfect way to achieve that, there are various techniques we can use to make our work easier to understand.&lt;/p&gt;

&lt;p&gt;The first one, which is arguably both the best and the hardest to achieve, is to &lt;strong&gt;keep the scope of pull requests as small as possible&lt;/strong&gt;. Smaller pull requests, without lots of moving parts, are easier to understand by looking at the code alone. If they have a clearly scoped goal, each modified line can be clearly traced back to that goal. Smaller changes can be more thoroughly reviewed. When the reviewer can understand the whole scope of the changes at once it makes it harder for bugs to slip in.&lt;/p&gt;

&lt;p&gt;That being said, sometimes this isn't achievable. It could be that a big feature is full of moving parts and it's hard to scope them to a single change that makes sense to merge on its own. Or it could be that we send a pull request for a refactor which necessarily makes changes across the whole codebase.&lt;/p&gt;

&lt;p&gt;For that purpose, I think writing a good description is crucial for the reviewer's understanding of our pull request. The modifications are just a list of all the moving parts that we needed to achieve our goal, &lt;strong&gt;the description tells the story of our work&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So, what makes a good description? This is highly subjective, but I think a good description should strive for a balance between clarity and brevity. A good description is &lt;strong&gt;the shortest description that can get the point across to our reviewer&lt;/strong&gt;. And that means that it not only depends on the changes themselves, &lt;em&gt;it also depends on the reviewer!&lt;/em&gt; A traditional feature in an MVC app might require little clarification if it's going to be reviewed by senior developers. A link to the corresponding user story in your issue tracker for background, maybe some clarification if you decided to add a new dependency, but little more is probably needed. If, instead, the pull request is going to be reviewed by someone less experienced, or someone from another team who might have less background on the codebase, then a more detailed explanation can be useful to guide them through the changes.&lt;/p&gt;

&lt;p&gt;Even though this is subjective I've found that pointing reviewers to the &lt;em&gt;interface&lt;/em&gt; of the changes, so to speak, can be incredibly useful. Were you working on UI changes? &lt;strong&gt;A screenshot or a GIF are worth a thousand words&lt;/strong&gt;. Is it an API endpoint? &lt;strong&gt;Point your reviewers to the tests that use that new endpoint&lt;/strong&gt;. Fixing a bug? Again, &lt;strong&gt;the tests that trigger the now fixed bug are a good place to make your reviewers go to&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Think about it this way: &lt;strong&gt;imagine you were sitting right next to your reviewer, explaining your changes&lt;/strong&gt;. If at some point you would jump to the app and show something visually, that's the moment to add a screenshot. If you were to show how an endpoint works, that's the moment to point to a test. Give your reviewers something to get started with so that they don't have to navigate the changes blindly.&lt;/p&gt;

&lt;p&gt;All in all, &lt;strong&gt;a reviewer has to understand what our goal is, how are we modeling the solution, and how did we implement it&lt;/strong&gt;. Looking at the changes alone can explain the last part. In many cases, pointing to a ticket on an issue tracker can be enough to explain the goal. And it's left for the pull request description to tie those together by explaining the thought process that led to our particular implementation.&lt;/p&gt;

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

&lt;p&gt;Not all reviewers will necessarily be developers. In our team, we've found it incredibly useful to include project managers and designers in the review process. Given that they don't necessarily have an environment set up to run our changes locally, &lt;strong&gt;deploying each pull request to a separate environment simplifies enormously the process of reviewing changes from a functional point of view&lt;/strong&gt;. This might not make sense on every project but I highly recommend it for web applications wherever possible.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Cover picture by Irvan Smith, found at &lt;a href="https://unsplash.com/photos/5eBW5GomfhY"&gt;unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>collaboration</category>
      <category>pullrequest</category>
      <category>codereview</category>
      <category>teamwork</category>
    </item>
    <item>
      <title>Writing tests for redux-observable</title>
      <dc:creator>Julio Olivera</dc:creator>
      <pubDate>Sun, 24 Sep 2017 23:46:49 +0000</pubDate>
      <link>https://dev.to/julioolvr/writing-tests-for-redux-observable</link>
      <guid>https://dev.to/julioolvr/writing-tests-for-redux-observable</guid>
      <description>

&lt;p&gt;I attended a talk about &lt;code&gt;redux-observable&lt;/code&gt; recently and, having been playing with Rx and liking it, I decided to give it a try. I won't get into the details of how to use it, but I did spend some time figuring out a way to easily test my epics that I wanted to share.&lt;/p&gt;

&lt;p&gt;Let's say that, for authenticating users of our app, we have an epic that looks like this:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;loginEpic&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="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&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;ofType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;LOGIN_START&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;mergeMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;api&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;login&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;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&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;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loginSuccessful&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Observable&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;loginFailed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;))),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The epic takes our main stream of actions and for each &lt;code&gt;LOGIN_START&lt;/code&gt; action, generates either an action with the &lt;code&gt;loginSuccessful&lt;/code&gt; action creator, or one with the &lt;code&gt;loginFailed&lt;/code&gt; action creator.&lt;/p&gt;

&lt;p&gt;Here I see three things that deserve their own unit test:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The proper API call is being made.&lt;/li&gt;
&lt;li&gt;We generate the success action if the login succeeded.&lt;/li&gt;
&lt;li&gt;We generate the error action if the login fails.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rationale behind all of the tests is going to be the same: We'll create an observable with the LOGIN_START action and pass it to the epic, subscribe to it and assert on the actions generated. Let's take a look at the first one, to check the API call:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I'm using Jest for the assertions and mocking here, but the same could be done with any other framework&lt;/em&gt;&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'logins through the api on LOGIN_START'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&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;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'test@test.com'&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;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'123456'&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;action$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ActionsObservable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)]);&lt;/span&gt;

  &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mockImplementation&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;ActionsObservable&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;epic&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="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscribe&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;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;done&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;A couple of things to note:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;login&lt;/code&gt; function is the action creator that generates &lt;code&gt;LOGIN_START&lt;/code&gt; actions. Since we have it already, it makes sense to use it.&lt;/li&gt;
&lt;li&gt;The API is implemented to return observables, so that's why the mock implementation returns one that simply emits an empty object (we don't really care about the response in this test)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;api&lt;/code&gt; is mocked with Jest's mock facilities outside this test, like this:&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jest.mock('../lib/api', () =&amp;gt; ({ login: jest.fn() }));
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Other than that, we pass the action stream to the epic, we subscribe and then we expect that after the first action is generated then we should've called the API already with the right parameters. Let's take a look at the tests that check the generated actions:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'emits a LOGIN_SUCCESS action if the API call succeeds'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&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;action$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ActionsObservable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'test@test.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'123456'&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

  &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mockImplementation&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;ActionsObservable&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;user&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="nx"&gt;epic&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="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;LOGIN_SUCCESS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;expect&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;payload&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'emits a LOGIN_FAILED action if the API call fails'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&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;action$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ActionsObservable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'test@test.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'123456'&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="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mockImplementation&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;ActionsObservable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;throw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="nx"&gt;epic&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="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;LOGIN_FAILED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;expect&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;payload&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The gist of it is that we filter the actions generated by the epic to ensure that we got the right type, and then when we subscribe we check that the payload of those actions are the right ones.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: I'm using &lt;code&gt;filter&lt;/code&gt; instead of &lt;code&gt;ofType&lt;/code&gt; like I would use to filter by action type inside an epic. This is because I can't be sure that the observable returned by the epic is going to be an &lt;code&gt;ActionsObservable&lt;/code&gt; instead of a regular observable.&lt;/p&gt;

&lt;p&gt;And that's it! I think this is a simple way to test epics. It might not be enough for more complicated cases, but personally I found it very simple and easy to reason about.&lt;/p&gt;


</description>
      <category>react</category>
      <category>redux</category>
      <category>reduxobservable</category>
    </item>
  </channel>
</rss>
