DEV Community: Arpple The latest articles on DEV Community by Arpple (@arpple). https://dev.to/arpple 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%2F194769%2F533cfafd-8b30-439c-8b3a-40fdd2667631.jpg DEV Community: Arpple https://dev.to/arpple en Debug Lesson: the problem from Chrome, CookieStore and var Arpple Mon, 17 Apr 2023 04:41:27 +0000 https://dev.to/arpple/debug-lesson-the-problem-from-chrome-cookiestorage-and-var-5fah https://dev.to/arpple/debug-lesson-the-problem-from-chrome-cookiestorage-and-var-5fah <p>I want to write this post as a lesson from my debug session in step-by-step on how I think and solve the problem I got. I hope it will be useful for someone or myself in the future.</p> <p>This start when I found some bug at work and after hours of debugging, Not sure if I should call it lucky or unluckily that this bug only happen in my dev environment but as this is from my work's project, I will only use images/code from much more simple example code instead.</p> <h2> What happened? </h2> <p>So I worked with some web project that using 3rd party library. It's just some analytic tool but in this case, I can't blame the tool itself directly on why it cause the problem.</p> <p>Whatever, there's some part of the library that have this kind of code<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight javascript"><code><span class="kd">var</span> <span class="nx">cookieStore</span> <span class="o">=</span> <span class="p">{</span> <span class="na">remove</span><span class="p">:</span> <span class="p">(</span><span class="nx">key</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span> <span class="c1">// delete cookie with key</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">delete</span><span class="dl">'</span><span class="p">,</span> <span class="nx">key</span><span class="p">)</span> <span class="p">}</span> <span class="p">}</span> <span class="kd">var</span> <span class="nx">otherStore</span> <span class="o">=</span> <span class="p">{</span> <span class="na">remove</span><span class="p">:</span> <span class="p">(</span><span class="nx">key</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span> <span class="c1">// delete data in storage with key</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">delete</span><span class="dl">'</span><span class="p">,</span> <span class="nx">key</span><span class="p">)</span> <span class="p">}</span> <span class="p">}</span> <span class="kd">function</span> <span class="nx">getStore</span><span class="p">()</span> <span class="p">{</span> <span class="c1">// check if using cookie ...</span> <span class="k">return</span> <span class="nx">cookieStore</span> <span class="p">}</span> <span class="kd">function</span> <span class="nx">removeStore</span><span class="p">(</span><span class="nx">key</span><span class="p">)</span> <span class="p">{</span> <span class="nx">getStore</span><span class="p">().</span><span class="nx">remove</span><span class="p">(</span><span class="nx">key</span><span class="p">)</span> <span class="p">}</span> <span class="nx">removeStore</span><span class="p">(</span><span class="dl">'</span><span class="s1">some-key</span><span class="dl">'</span><span class="p">)</span> </code></pre> </div> <p>if you try to run this (you can try paste this in console) in Firefox, it will result in <code>delete some-key</code>. But in Chrome, it will result in <code>Uncaught TypeError: getStore(...).remove is not a function</code></p> <h2> Debugging </h2> <p>At first I haven't tried it on Firefox so I don't know it Chrome specific issue.</p> <p>The first thing I suspect is that <code>getStore()</code> somehow result in something without <code>remove()</code> function (undefined/null/other object) so I try to inspect on the result of it and see that the <code>cookieStore</code> returned from the function is some <code>CookieStore{}</code> object instead of object with remove() function <code>{ remove: ... }</code></p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RKkUvbWC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4hz2li38xs25q3n11l94.png" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RKkUvbWC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4hz2li38xs25q3n11l94.png" alt="checking getStore() result" width="667" height="482"></a></p> <p>Next I check if the line for assignment of the <code>var cookieStore = ...</code> is executed or not (as in actual code is much complicate). Turn out value of <code>cookieStore</code> before and right after the assignment line are both <code>CookieStore{}</code> </p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_D64ELh3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xs5z34opvgfs8ptytnxd.png" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_D64ELh3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xs5z34opvgfs8ptytnxd.png" alt="checking assignment" width="679" height="467"></a></p> <p>Even though it doesn't seem to be re-assign problem, I still check if there is other script that assign the value to this <code>cookieStore</code> variable before actual calling to <code>getStore()</code><br> Using global search, I only find one place which is my assignment</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0LbeDzXa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tb6liid7vk7tch0vg5lh.png" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0LbeDzXa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tb6liid7vk7tch0vg5lh.png" alt="global search" width="548" height="207"></a></p> <p>Next, I tried to check where this <code>CookieStore{}</code> come from. It doesn't seem to have any reference on it anywhere.<br> Turn out, if you open any page even blank page in Chrome and type to see variable <code>cookieStore</code>. You can get the result as <code>CookieStore{}</code> already.</p> <p>Now I'm pretty sure this is cause from a browser and not from any script. I tried to test my script on other browser. </p> <p>On Firefox, I see that my script is working fine. Also checking <code>cookieStore</code> variable in blank page result in <code>undefined</code></p> <p>I can now conclude that on Chrome, declaring <code>var cookieStore</code> will be override by Chrome default <code>CookieStore{}</code> and cause this problem.</p> <h2> Conclusion </h2> <p>this is exactly what happen when you use <code>var</code>. The variable can be shadow from global scope and cause the assignment not working. But this time it is declared by Chrome internally so it become harder to find. </p> <p>And the reason this only happen on dev environment because in production, the code is minified so variable name is changed to some minified character and not getting shadowed by Chrome.</p> <p>To fix this problem. If you can change from <code>var cookieStore =</code> to <code>const</code> or <code>let</code> it will working just fine. But in my case this is code from 3rd party so I need to check with it. Luckily it is fixed in newer version so all I need to do is update it.</p> webdev javascript debug writing test and BDD Arpple Thu, 10 Jun 2021 21:29:50 +0000 https://dev.to/arpple/writing-test-and-bdd-54p https://dev.to/arpple/writing-test-and-bdd-54p <p><em>this post will focus on no side effect environment module testing, and the code is not in any programming language :P</em></p> <h2> intro </h2> <p>let's first take a look at simple how-to write a test that I sees people usually do now<br> suppose we have module (or class) Cart<br> we will follow the OO concept of encapsulating state as private and have a public method<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>module Cart private items public fn isEmpty() public fn addItem(item) public fn checkOut() </code></pre> </div> <p>just to be simple we will use item as string "A", "B" and the checkout will just print format list of purchased items<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>&gt; cart.addItem("A") &gt; cart.checkout() Order: A &gt; cart.addItem("B") &gt; cart.checkout() Order: A, B </code></pre> </div> <p>now let's start writing a test on each function, start with the very easy first test on <code>isEmpty()</code><br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>module CartTest describe "isEmpty()" test "it return true when no item" cart = new Cart() assert cart.isEmpty() == true </code></pre> </div> <p>this is so simple. let's see the next method <code>addItem()</code><br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>describe "addItem()" test "it return ..." </code></pre> </div> <h2> more complicate </h2> <p>we already stuck at the name of test. this method just add the item to cart without returning any result<br> you can make a method return boolean to represent the success/fail result but it still not what we expect a method to do, to actually put item in the cart<br> instead of checking the result, we want to check the state of the cart for it's items but the <code>items</code> property is private<br> the quick easy way would be<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight diff"><code><span class="p">module Cart </span><span class="gd">- private items </span><span class="gi">+ public items </span></code></pre> </div> <p>or<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight diff"><code><span class="p">module Cart </span><span class="gi">+ public fn getItems() </span></code></pre> </div> <p>we change the items to be exposed to public scope. now we can test<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>describe "addItem()" test "it add item to cart's items list" cart = new Cart() assert cart.items == [] cart.addItem("A") assert cart.items == ["A"] </code></pre> </div> <p>but this break a concept of encapsulation and make a test become a white box testing. we would prefer black box approach because we don't want the detail and logic of module to grow outside of itself and become hard to understand</p> <p> ! <p>making this an ORM model and asserting the database row doesn't mean it solve this problem </p> </p> <p><strong>let's just keep it like this and see the next test</strong><br> the <code>isEmpty()</code> test we wrote is not covered all the cases it can be. also we want to test <code>addItem()</code> with multiple item.<br> we need to setup test with already added item. someone may come up with this solution<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>describe "isEmpty()" test "it return true when no item" ... test "it return false when cart have items" cart = new Cart() cart.items = ["A"] assert cart.isEmpty() == false describe "addItem()" test "it add item to cart" ... test "it can add more item to cart" cart = new Cart() cart.items = ["A"] cart.addItem("B") assert cart.items == ["A", "B"] </code></pre> </div> <p>by setting items directly (or create public fn setItems to set it). you can isolate a test to just it's testing method.<br> also if some method require more pre-setup state, setting up state directly often be the quick way to do.</p> <p>the problem is, this is not the actual usage of your module. by directly setting state, it can happen to be a "shouldn't exists state" which mean you are testing the thing that not actually exists in real code</p> <p> stupid example <br> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> module Cart public isActive public isDelete public fn activate() this.isActive = true this.isDelete = false public fn delete() this.isActive = false this.isDelete = true </code></pre> </div> <p>by using public method, both flags won't result in same true/false state. but with manual setup, you may create<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>cart = new Cart() cart.isActive = true cart.isDelete = true </code></pre> </div> <br> </p> <p>also as mentioned before, the state shouldn't be exposed out of module. so this kind of setup is not a way we want to do.</p> <p> ! <br> making this an ORM model and pre insert into database row doesn't mean it solve this problem<br> </p> <h2> taking a step back </h2> <p><em>if you just want code and howto, skip this part :P</em></p> <p>for now we have 2 problems</p> <ul> <li>we want to test the fn that modify state but don't want to expose the state</li> <li>we want to setup pre-state but also don't want to expose the state</li> </ul> <p>this may feel like a paradox that cannot be solved. But let's take a step back and look at the bigger picture of module with methods and state.</p> <p>imagine if we build a boiler machine. <br> we may not want to wire the power into the heater part to test that this machine can boil the water without testing the turn on button.<br> for this context, we want to test the complete machine not a component</p> <p>the same with module, many times that it is designed that each method cannot live by itself, but work together as a state diagram<br> <a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Gvr_H_GR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://training-course-material.com/images/9/90/StateMachineDiagram.png" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Gvr_H_GR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://training-course-material.com/images/9/90/StateMachineDiagram.png" alt="img"></a><br> look at this example state machine diagram<br> not all transition is drawn out from the initial state so it shouldn't work without previous transition and you shouldn't jump to any state without transition</p> <p>apply this with code module, not all method will work without setup by some other method and you can't set the state directly.</p> <p>for this I want you to forget about testing individual method and instead focus on testing the <strong>Behavior of entire module</strong> or BDD</p> <p><em>yes BDD is not just forcing test name with awkward Given When Then and don't need to be on the top level end-to-end or feature test</em></p> <h2> Let's do BDD </h2> <p>from the example above we may see that testing single method is not work well with encapsulated black box logic because the whole module isn't mean to be used by just that single method alone.<br> let's look at the problem we found again<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>describe "addItem()" test "it add item to cart's items list" cart = new Cart() assert cart.items == [] cart.addItem("A") assert cart.items == ["A"] </code></pre> </div> <p>because we can't verify the result of <code>addItem()</code> alone but we can look in another way, the <code>addItem()</code> is actually the passage to the <code>checkout()</code>. So we will test both of them together<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight diff"><code><span class="p">describe "checkout()" </span> test "it print order with single item" cart = new Cart() cart.addItem("A") assert cart.checkout == "Order: A" </code></pre> </div> <p>we don't care to describe what <code>addItem()</code> do behind the scene. we only know that we need it before <code>checkout()</code>. so there is nothing like <code>list</code> or something internal in the test at all</p> <p>the next problem was about setup pre-state, again we can just use the addItem together<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight diff"><code><span class="p">describe "isEmpty()" </span> test "it return false when cart have items" cart = new Cart() cart.addItem("A") assert cart.isEmpty() == false describe "checkout()" test "it print order with single item" ... test "it print order with multiple item" cart = new Cart() cart.addItem("A") cart.addItem("B") assert cart.checkout == "Order: A, B" </code></pre> </div> <p>and because we don't focus a test to just single method, let's remove a <code>describe</code> with the method name from tests and rename some tests<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight diff"><code><span class="p">module CartTest </span><span class="gd">- describe "isEmpty()" </span> test "new cart is empty" test "cart with single item is not empty" test "cart with multiple items is not empty" - describe "checkout()" test "new cart cannot checkout" test "print order from cart with single item" test "print order from cart with multiple items" </code></pre> </div> <p>we can see some pattern here. there are 3 tests per (removed) describe scope with the new cart, single item and multiple items in both of them. let's try group them together<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>describe "new cart" cart = new Cart() test "should be empty" test "cannot checkout" describe "cart with single item" cart = new Cart() cart.addItem("A") test "should not be empty" test "should print order with single item" describe "cart with multiple items" cart = new Cart() cart.addItem("A") cart.addItem("B") test "should not be empty" test "should print order with multiple items" </code></pre> </div> <p>by grouping these together, not only we get the shorter name. we can also share the setup code in each describe block because it is tested on the same state</p> <p>and if you try hard enough, you can phrase it to the given-when-then pattern.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>given new cart when check empty then it return true when checkout then it return error </code></pre> </div> <p><code>given</code> map directly to the setup state<br> <code>when</code> is the method or action we execute<br> <code>then</code> map expected result</p> <p>I think this test pattern is a lot more easier to map to these GWT format than the previous per-method pattern because we test the module by actual <code>Behavior</code> thus BDD</p> <h2> Summary </h2> <ul> <li>testing per method is hard because some method is not self-completed</li> <li>instead we want to test behavior of entire module using only public method (Black Box)</li> <li>we group test by pre setup state so we can share setup code</li> <li>the test is more reflect to real world use-case </li> </ul> <p> ! <br> this example may not be ideal. because in real case, we may not want <code>items</code> to be private because UI will need to show list of it<br> and checkout should actually be outside of cart (another service/module) because the dependency should be <code>Order -&gt; Cart</code> to avoid cart being God Object<br> </p> <h2> Extra </h2> <p>I recommend to have multiple <code>it</code> or <code>then</code> per test if need. In this way it is easier to describe the behavior of your module<br> for example</p> <blockquote> <p>when cancel an order, mark status as 'canceled', update timestamp and fire event order canceled</p> </blockquote> <p>even grouping by state and describe logic in the test name, it can make test name and body too long<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>describe "created order" it "cancel order mark status as 'canceled', update timestamp and fire event" // and because its very long, we most likely do it "can cancel successfully" </code></pre> </div> <p>better example: test by behavior, descriptive name, separate each assertion<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>describe "created order" describe "when cancel" test "it mark status as 'canceled" test "it update timestamp" test "it fire event" </code></pre> </div> <p>separate each topic in it's own <code>test/it/then</code> is easier to add new requirement or adjust existing one and test report will looks very clean and can better describe behavior of the code</p> testing bdd