<?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: Nuno Cruz</title>
    <description>The latest articles on DEV Community by Nuno Cruz (@nunoancruz).</description>
    <link>https://dev.to/nunoancruz</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%2F312893%2F6a4364c5-3296-472f-8753-e41d00e0a852.jpg</url>
      <title>DEV Community: Nuno Cruz</title>
      <link>https://dev.to/nunoancruz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nunoancruz"/>
    <language>en</language>
    <item>
      <title>Using Cypress to Test Genome Graph Built with Canvas, D3.js and React</title>
      <dc:creator>Nuno Cruz</dc:creator>
      <pubDate>Thu, 25 Jun 2020 19:40:04 +0000</pubDate>
      <link>https://dev.to/nunoancruz/using-cypress-to-test-genome-graph-built-with-canvas-d3-js-and-react-486j</link>
      <guid>https://dev.to/nunoancruz/using-cypress-to-test-genome-graph-built-with-canvas-d3-js-and-react-486j</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted at &lt;a href="https://www.nunocruz.pt/using-cypress-to-test-genome-graph-built-with-canvas-d-3-js-and-react"&gt;nunocruz.pt&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Genome, like any other Feedzai product, is subject to an exhaustive battery of end-to-end (E2E) tests to ensure it works according to its design specifications. Since Genome is a highly visual tool, testing requires a very particular approach. We build the graph area using an HTML canvas element, which prevents us from using conventional E2E techniques. In this blog post, we'll explain how we approached and solved the problem of testing an application whose main interactions occur on a canvas element.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing a whiteboard
&lt;/h3&gt;

&lt;p&gt;Testing a traditional web application (by "traditional" I mean a User Interface (UI) where each piece of information is displayed using HTML elements) is more or less straightforward with the current E2E frameworks like Selenium or Cypress. Overall, the workflow consists of performing a set of actions on the page, such as clicking on buttons or typing text on input elements and asserting the page gets into the desired state (e.g., asserting that some elements are present on the page).&lt;/p&gt;

&lt;p&gt;This works well for almost every HTML element except the canvas element. If you are not familiar with canvas, it is an HTML element that can be used to draw graphics via scripting. We can imagine it as a whiteboard where you can freely draw anything.&lt;/p&gt;

&lt;p&gt;Compared with other HTML elements where we can nest several elements inside each other (DOM tree) to produce content, what we see on a canvas element is not represented in any nested element, which means that it doesn't produce a queryable DOM tree. From a testing perspective, how can we assert that our application gets into the desired state if we cannot query the content of a canvas element? For example, how can we test that after deleting a node from a graph, we get n - 1 nodes?&lt;/p&gt;

&lt;h3&gt;
  
  
  Exposing an API
&lt;/h3&gt;

&lt;p&gt;Before explaining how we implemented the E2E tests for Genome, it is important to give a little bit of context on how Genome, and particularly its graph, is built.&lt;/p&gt;

&lt;p&gt;Genome's graph is built using a combination of React and D3.js. A React component named GenomeGraph embeds the canvas element. Overall, this component is responsible for setting up and handling user events that target the graph. It also communicates with D3.js to compute the nodes and edges positions.&lt;/p&gt;

&lt;p&gt;D3.js is a well-known library that is used to help build visualization tools. With Genome, by default, we use the D3.js force-directed graph layout. This layout simulates physical forces on nodes until they balance (their final position). Visually speaking, the more simulations, the more the nodes tend to separate from each other, while fewer simulations might make them stay closer to each other. Figure 1 illustrates a scenario where the number of simulations is greater than the one in Figure 2.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IcfISdpB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://nunocruz.pt/static/0a2ab3fce25a25e23b00df4679777ea1/7d769/graph-300-iterations.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IcfISdpB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://nunocruz.pt/static/0a2ab3fce25a25e23b00df4679777ea1/7d769/graph-300-iterations.png" alt="Figure 1" title="Figure 1" width="880" height="567"&gt;&lt;/a&gt;&lt;em&gt;Figure 1. D3.js force simulation with around 300 iterations. As explained, in this case, the nodes are slightly apart from each other when compared with the graph in Figure 2.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZcwRzWAz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://nunocruz.pt/static/508c9eeb7cbe4e9c9879d02d33c70153/7d769/graph-13-iterations.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZcwRzWAz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://nunocruz.pt/static/508c9eeb7cbe4e9c9879d02d33c70153/7d769/graph-13-iterations.png" alt="Figure 2" title="Figure 2" width="880" height="567"&gt;&lt;/a&gt;&lt;em&gt;Figure 2. D3.js force simulation with around 13 iterations.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Cypress over Selenium
&lt;/h3&gt;

&lt;p&gt;We decided to use Cypress to implement our E2E tests. Why Cypress and not Selenium? Cypress is more developer-centric, in the sense that any Frontend developer can easily implement E2E tests using JavaScript. Another advantage is that where Selenium WebDriver runs remotely outside the browser, Cypress is the exact opposite; it runs inside the browser. The ability to run code inside the browser simplifies things. For example, you can simply drop a debugger into your application or spec code - something that makes it super easy to use the developer tools while you're developing. Besides the technical aspect, when we made our decision, Cypress was getting a lot of traction in the Frontend community. Taking all of this into account, we decided to give Cypress a try (no regrets so far).&lt;/p&gt;

&lt;p&gt;Now that we have more context on the tools used to implement and test the Genome graph, it's time to detail how we were able to test a graph drawn in a canvas element.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to test a graph drawn in a canvas element
&lt;/h3&gt;

&lt;p&gt;After some analysis, we decided to use an API to expose the Genome application for consumption by our Cypress application. This allowed us to manipulate the graph and assert its state. Due to the characteristics of the &lt;em&gt;GenomeGraph&lt;/em&gt; component, it was a "natural" choice for us to use it to help build the API.&lt;/p&gt;

&lt;p&gt;A High-Order Component (HOC) is an advanced technique in React for reusing component logic. We used this technique because it generates an enhanced component from a given component. In particular, we produced an enhanced component from the &lt;em&gt;GenomeGraph&lt;/em&gt; component with the ability to create an API and expose it in the browser's global object. Even though it's not reusable, this approach seemed the cleanest and most elegant way to expose a component's API.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Since we didn't want this API exposed in the production environments, we defined a variable to enable it only in testing environments.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;From the set of operations that the API exposes, the most useful one is the &lt;em&gt;waitUntilGraphSimulationEnd&lt;/em&gt; operation. It allows us to wait for the D3.js simulation to finish in order to start interacting with the graph. Without it, it would be very difficult to interact with the graph and would probably lead to flaky tests because the graph was still "moving" from its initial to its final state.&lt;/p&gt;

&lt;p&gt;The snippet below describes the implementation of the function that waits for the simulation to end.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Implementing custom commands
&lt;/h3&gt;

&lt;p&gt;From the perspective of the Cypress application, we created several custom commands to abstract the communication with the Genome graph. The snippet below describes the implementation of the getGraphNodeInformationById and the waitUntilGraphSimulationEnd custom commands.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;While implementing our tests, we use the custom commands as if they were part of the Cypress library. The example below is a test that asserts that when clicking on a specific node, that node gets selected. You can notice the usage of the previously mentioned &lt;em&gt;waitUntilGraphSimulationEnd&lt;/em&gt; and &lt;em&gt;getGraphNodeInformationById&lt;/em&gt; custom commands.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Final thoughts
&lt;/h3&gt;

&lt;p&gt;Adopting an approach based on "direct communication" between the Cypress application and the Genome application allowed us to include our main component (Genome graph) in the set of E2E tests. However, we are aware of the drawbacks of this approach.&lt;/p&gt;

&lt;p&gt;One of the goals of E2E testing is to interact with the application like a user would: click on the screen, input text and expect to see changes on the screen. By using an API-based approach, we somehow break this goal. In practice, we fake the interaction with the graph by calling code directly from the Genome application.&lt;/p&gt;

&lt;p&gt;Another limitation are the drag and drop operations. Currently, we cannot test the scenario of dragging nodes to some part of the screen because we noticed that it introduces flakiness in our tests. While we are working on a solution to overcome this limitation, a set of manual tests were added to cover the drag and drop operations.&lt;/p&gt;

&lt;p&gt;Visual testing, an alternative to functional testing, is an approach that should be explored in the near future. This technique takes image snapshots of the application and compares them with previously approved baseline images. It is a technique that fits well on features that mainly encode information through visualization. For example, in Genome, we have a new feature named Lenses which aims to apply different colors to nodes and edges to encode certain information, e.g., entities that participated in, at least one fraudulent transaction are displayed in red, while entities participating only in genuine transactions are displayed as green. Comparing image snapshots with baseline images would be an interesting way to assert that the lenses are correctly applied to the nodes and edges.&lt;/p&gt;

&lt;p&gt;Our solution to test an application that is built mainly using canvas is far from perfect, and our goal is to continually iterate in order to solve the current limitations.&lt;/p&gt;

&lt;p&gt;Note: The credit for this solution goes to &lt;a href="https://www.linkedin.com/in/lifernandes/"&gt;Liliana Fernandes&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/victorfern/"&gt;Victor Fernandes&lt;/a&gt;. I'm only the messenger :D&lt;/p&gt;

</description>
      <category>react</category>
      <category>cypress</category>
      <category>canvas</category>
      <category>d3js</category>
    </item>
    <item>
      <title>💡How to update your npm dependencies easily 🏎</title>
      <dc:creator>Nuno Cruz</dc:creator>
      <pubDate>Wed, 01 Apr 2020 15:00:49 +0000</pubDate>
      <link>https://dev.to/nunoancruz/how-to-update-your-npm-dependencies-5dn1</link>
      <guid>https://dev.to/nunoancruz/how-to-update-your-npm-dependencies-5dn1</guid>
      <description>&lt;p&gt;In large projects with many dependencies it is sometimes hard to track which dependencies are outdated or not. Whenever you need to update them, the &lt;strong&gt;npm-check&lt;/strong&gt; tool can help you with that.&lt;/p&gt;

&lt;p&gt;This tool has an interactive mode that can be run with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx npm-check -u
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tool interactive mode looks like this:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VSHJnNCl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ny9b36stuf8dq69wkcrl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VSHJnNCl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ny9b36stuf8dq69wkcrl.png" alt="Tool interactive mode" width="880" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then you just need to use the up/down arrow keys to navigate between the packages and use the space bar to select those that you want to update. In the end, just press enter to update and install the previously selected packages.&lt;/p&gt;

&lt;p&gt;Besides listing outdated libraries, it also adds a link to the package documentation, which is very useful to quickly access the release notes to check the migration guides.&lt;/p&gt;

&lt;p&gt;Please check the tool &lt;a href="https://www.npmjs.com/package/npm-check"&gt;documentation&lt;/a&gt; for extra options.&lt;/p&gt;

</description>
      <category>npm</category>
      <category>javascript</category>
      <category>tip</category>
    </item>
  </channel>
</rss>
