{
    "componentChunkName": "component---src-templates-blog-post-js",
    "path": "/making-sense-of-destructured-imports-for-testing-and-stubs/",
    "result": {"data":{"site":{"siteMetadata":{"title":"DeveloPanda","author":"Eyad Kobatte"}},"markdownRemark":{"id":"8ee3090c-a269-5095-9284-716d55ee0685","excerpt":"Edit This article has been edited with the following Previously, I wrote that we would be getting new instances of a function when we destructure an import. But…","html":"<h2>Edit</h2>\n<p>This article has been edited with the following</p>\n<p>Previously, I wrote that we would be getting new instances of a function when we destructure an import.</p>\n<p>But in reality, we create a local variable that will not be reflected with newer changes when we destructure an import.</p>\n<hr>\n<p>Testing is an immensely useful skill to have in your utility belt.</p>\n<p><img src=\"/2902a550275c1f1f6dea314dd0e83afa/batman_utility_belt.gif\" alt=\"Batman Utility Belt\"></p>\n<p>Fortunately, I had the privilege of learning to write tests recently. When I learned JavaScript, it was with ES5 and Promises and all the modern goodies of JavaScript, so all my code heavily relies on ES5+ features and barely includes any callbacks (Say no to callback hell)</p>\n<p>I faced this issue recently where we are using destructured imports in our node.js file and stubbing a few HTTP methods. All our stubs failed and our tests started making HTTP calls to actual APIs. I ran down this path of trying to google what was going wrong yet no results could be found. What I learned from here mainly applies to testing but its applications could be anywhere we want to reuse a module/package instead of creating local copies of a function</p>\n<p>We are using <a href=\"https://www.npmjs.com/package/got\">got</a> as an HTTP library in our node.js backend. <code class=\"language-text\">GOT</code> has been designed in such a way where the specific methods that are needed can be destructured and imported so we do not import the whole package. Nice!!</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token comment\">// lib/func/index.js</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> get <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'got'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// Only import get and no other methods</span>\n\n<span class=\"token comment\">// More code here</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">fakeFunc</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> result <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token string\">'API'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">return</span> result<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n\nmodule<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> fakeFunc<span class=\"token punctuation\">;</span></code></pre></div>\n<p>Not really. We started facing an issue when we write tests, and stub the methods from got</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token comment\">// lib/func/index.spec.js</span>\n\n<span class=\"token keyword\">const</span> got <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'got'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">const</span> sinon <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'sinon'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> fakeFunc <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'.'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// More code here</span>\n\n<span class=\"token function\">describe</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Test API Calls'</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">done</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> stub <span class=\"token operator\">=</span> sinon<span class=\"token punctuation\">.</span><span class=\"token function\">stub</span><span class=\"token punctuation\">(</span>got<span class=\"token punctuation\">,</span> <span class=\"token string\">'get'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token function\">fakeFunc</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">data</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// Write your tests here</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>You can see that we stub the get function from the got package. We would now expect our test to not make an HTTP call to the API specified in the code.</p>\n<p>Sadly, this is not what happens. In the <code class=\"language-text\">lib/func/index.js</code> file when we write <code class=\"language-text\">const { get } = require('got')</code>, we create a local variable with a copy of the the get module from <code class=\"language-text\">GOT</code>. This variable is not reflected when stubbed. So at this point, we have 1 get function which is a copy before we stubbed it, and a get function which is stubbed in our test file.</p>\n<p>When we destructure an import, we effectively created a local variable of the get module that is not tied to the stub that we created. This means that the test will hit the API and get actual data. (Big no-no)</p>\n<p>To fix this problem, We import <code class=\"language-text\">GOT</code> as a whole library and use the modules from the <code class=\"language-text\">GOT</code> package without destructuring. Small sacrifice for a bigger win.</p>\n<h2>How we temporarily fixed this problem</h2>\n<p>We had not yet realized that destructuring would be creating local copies of modules. So upon googling for a solution, we found a library called <a href=\"https://www.npmjs.com/package/proxyquire\">proxyquire</a> which will mock our dependencies in the functions. This would mean we can replace the non-stubbed version of the get instance in our function with a stubbed value from the test.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token comment\">// lib/func/index.spec.js</span>\n\n<span class=\"token keyword\">const</span> got <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'got'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">const</span> sinon <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'sinon'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">const</span> proxyquire <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'proxyquire'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// We do not import our function here</span>\n<span class=\"token comment\">// const fakeFunc = require('.');</span>\n\n<span class=\"token comment\">// More code here</span>\n\n<span class=\"token function\">describe</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Test API Calls'</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">done</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> stub <span class=\"token operator\">=</span> sinon<span class=\"token punctuation\">.</span><span class=\"token function\">stub</span><span class=\"token punctuation\">(</span>got<span class=\"token punctuation\">,</span> <span class=\"token string\">'get'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// Notice how we do not stub the got module here</span>\n\n  <span class=\"token comment\">// Mock the get module in the got dependency with our stub here</span>\n  <span class=\"token keyword\">const</span> functionHolder <span class=\"token operator\">=</span> <span class=\"token function\">proxyquire</span><span class=\"token punctuation\">(</span><span class=\"token string\">'.'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">got</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token literal-property property\">get</span><span class=\"token operator\">:</span> stub<span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n  functionHolder<span class=\"token punctuation\">.</span><span class=\"token function\">fakeFunc</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">data</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// Write your tests here</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>This fixed the problem for a while until we ended up using <code class=\"language-text\">PROXYQUIRE</code> everywhere, even when it is not needed. This is not the best way to go about it as we are now mocking our dependencies instead of fixing a problem</p>\n<p>In the end, we steered clear of proxyquire and stopped destructuring imports for the <code class=\"language-text\">GOT</code> package</p>\n<p><img src=\"/8cc15aae15c0316096eb281f558f4e1b/working_cat.gif\" alt=\"Working cat\"></p>","frontmatter":{"title":"Making sense of destructured imports for testing and stubs","date":"April 16, 2020"}}},"pageContext":{"slug":"/making-sense-of-destructured-imports-for-testing-and-stubs/","previous":null,"next":{"fields":{"slug":"/thinking-in-typescript/"},"frontmatter":{"title":"Thinking in TypeScript"}}}},
    "staticQueryHashes": ["3128451518","569354865"]}