<?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: Maxence Poutord</title>
    <description>The latest articles on DEV Community by Maxence Poutord (@maxpou).</description>
    <link>https://dev.to/maxpou</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%2F30845%2Fc293f1bd-64f3-4923-9437-94cd58cb2e71.jpeg</url>
      <title>DEV Community: Maxence Poutord</title>
      <link>https://dev.to/maxpou</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/maxpou"/>
    <language>en</language>
    <item>
      <title>Apps, Tools, and Gear I Use (2021 edition)</title>
      <dc:creator>Maxence Poutord</dc:creator>
      <pubDate>Thu, 11 Nov 2021 12:46:48 +0000</pubDate>
      <link>https://dev.to/maxpou/apps-tools-and-gear-i-use-2021-edition-4b46</link>
      <guid>https://dev.to/maxpou/apps-tools-and-gear-i-use-2021-edition-4b46</guid>
      <description>&lt;p&gt;This page is somewhat inspired by &lt;a href="https://wesbos.com/uses/"&gt;Wes Bos' Uses&lt;/a&gt; page. Keep in mind that&lt;br&gt;
I'm mostly doing Frontend development and I'm also a nomadic worker. In other words, I'm 100% remote and I travel. A lot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hardware
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dHERaRaf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/smgocz27pezbjmszvk50.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dHERaRaf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/smgocz27pezbjmszvk50.jpeg" alt="laptop picture" width="880" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MacBook Pro M1 (13-inch)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No extra screen.&lt;/strong&gt; I've found myself more focus with only one screen&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.therooststand.com/"&gt;Roost Laptop Stand&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://twitter.com/_maxpou/status/1436270414544654348"&gt;Keychron K3 Mechanical keyboard&lt;/a&gt; and a
Magic keyboard 2 (when I travel)&lt;/li&gt;
&lt;li&gt;Magic Trackpad 2 and a
&lt;a href="https://www.logitechg.com/en-us/products/gaming-mice/g403-hero-gaming-mouse.910-005630.html"&gt;G403 HERO Mouse&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Notepad where
&lt;a href="https://about.gitlab.com/2018/05/17/eliminating-distractions-and-getting-things-done/#2-write-down-your-mits"&gt;I write my daily MIT&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;OnePlus Nord (and an old Huawei as a backup)&lt;/li&gt;
&lt;li&gt;Sony MDR 1000X. A noise-cancelling headphone with 2 modes: wired or wireless (bluetooth). I also
have some Airpods.&lt;/li&gt;
&lt;li&gt;Travel&amp;amp;daily bag is a
&lt;a href="https://www.minaal.com/products/minaal-carry-on-bag/?variant=12494163140"&gt;Minaal Carry-on 2.0&lt;/a&gt;
(with packing cubes). I love it!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I travel too much to have a proper desk! ;)&lt;/p&gt;

&lt;h2&gt;
  
  
  IDE
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;VS Code is my favorite text editor so far.&lt;/li&gt;
&lt;li&gt;The theme I use is Material Theme which I customized.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/maxpou/dotfiles/blob/master/vscode/install_plugin.sh"&gt;Full list of plugins that I Can't Live Without&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6bJhycG3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ite4kfmxh9kb70ohs40i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6bJhycG3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ite4kfmxh9kb70ohs40i.png" alt="my ide" width="880" height="662"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All of my config files (VS Code settings, bash aliases, git config...) are accessible on [my dotfiles GitHub repository (&lt;a href="https://github.com/maxpou/dotfiles"&gt;https://github.com/maxpou/dotfiles&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Browser
&lt;/h2&gt;

&lt;p&gt;My main browser is &lt;a href="https://brave.com/"&gt;Brave&lt;/a&gt;. I also use the following extensions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm"&gt;uBlock Origin&lt;/a&gt;
and &lt;a href="https://privacybadger.org/"&gt;Privacy Badger&lt;/a&gt; to preserve my privacy on the internets&lt;/li&gt;
&lt;li&gt;&lt;a href="https://chrome.google.com/webstore/detail/grammarly-for-chrome/kbfnbcaeplbcioakkpcpgfkobkghlhen"&gt;Grammarly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi"&gt;React&lt;/a&gt;
and
&lt;a href="https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd"&gt;Vue.js&lt;/a&gt;
devtool extensions&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://accessibilityinsights.io"&gt;Accessibility Insights&lt;/a&gt; and &lt;a href="https://www.deque.com/axe/"&gt;axe&lt;/a&gt;
for Accessibility audits&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://chrome.google.com/webstore/detail/lastpass-free-password-ma/hdokiejnpimakedhajhdlcegeplioahd"&gt;LastPass&lt;/a&gt;
for password management&lt;/li&gt;
&lt;li&gt;&lt;a href="https://chrome.google.com/webstore/detail/save-to-pocket/niloccemoadcdkdjlinkgdfekeahmflj"&gt;Pocket (Save to Pocket)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Terminal &amp;amp; Command Line Apps
&lt;/h2&gt;

&lt;p&gt;I mostly use my terminal in VSCode. Otherwise, I use iTerm. My terminal theme is&lt;br&gt;
&lt;a href="https://github.com/romkatv/powerlevel10k"&gt;powerlevel10k&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OruqyRS8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p61vdh9vrnv7eajnjdyg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OruqyRS8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p61vdh9vrnv7eajnjdyg.png" alt="terminal screenshot" width="880" height="560"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the list of plugins/apps I use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/robbyrussell/oh-my-zsh/wiki/Installing-ZSH"&gt;Zsh&lt;/a&gt; with
&lt;a href="https://github.com/robbyrussell/oh-my-zsh"&gt;Oh My Zsh&lt;/a&gt;. Oh My Zsh is a framework for managing zsh
configuration.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/GoogleChrome/lighthouse"&gt;Lighthouse (CLI)&lt;/a&gt; - Auditing, performance metrics,
and best practices for Progressive Web Apps.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/github/hub"&gt;Hub&lt;/a&gt; - a wrapper for Git command &lt;em&gt;(Git+Hub=GitHub)&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/aksakalli/gtop"&gt;gtop&lt;/a&gt; - an alternative to activity monitor.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://formulae.brew.sh/formula/tree"&gt;Tree&lt;/a&gt; - to generate a tree (like the Tree Windows
command).&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/sharkdp/bat"&gt;Bat&lt;/a&gt; - the &lt;code&gt;cat&lt;/code&gt; command on steroids.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/tj/n"&gt;n&lt;/a&gt; - a super handy tool for node version management.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also use Vim from time to time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1JLPqy79--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5ke24n9xcp0cgoxt8ejw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1JLPqy79--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5ke24n9xcp0cgoxt8ejw.png" alt="vim screenshot" width="880" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Desktop Apps
&lt;/h2&gt;

&lt;p&gt;I have a very minimalistic approach when it comes to my dock. If I don't use an app -at least- once&lt;br&gt;
a day, I remove it from the dock.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Vh5pkQZG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rjlt5vmkwccycgpznx3t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Vh5pkQZG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rjlt5vmkwccycgpznx3t.png" alt="dock screenshot" width="880" height="190"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also use these applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://giphy.com/apps/giphycapture"&gt;Giphy Capture&lt;/a&gt; is my go-to screen recording app when I need
to share something with my colleagues. I found it simple to use.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.codeweavers.com/crossover"&gt;CrossOver&lt;/a&gt; - to run Windows App on Mac (it's a paid
product).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: I now use Slack in my browser (so Grammarly can proofread my messages)&lt;/p&gt;

&lt;h2&gt;
  
  
  Blogging
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.maxpou.fr"&gt;My website (maxpou.fr)&lt;/a&gt; is made with Gatsby.js. I use these services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://app.grammarly.com/"&gt;Grammarly&lt;/a&gt; - Helps me to remove typos / proofread my posts&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://docs.new/"&gt;Google Docs&lt;/a&gt; - Helps me to remove typos / proofread my posts&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.hemingwayapp.com"&gt;Hemingway&lt;/a&gt; - "Hemingway App makes your writing bold and clear"&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://squoosh.app"&gt;Squoosh&lt;/a&gt; - Image compression&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.remove.bg"&gt;Remove.bg&lt;/a&gt; - Remove background on png&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.apple.com/keynote/"&gt;Keynote (Apple)&lt;/a&gt; - To draw schemas&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://plausible.io/maxpou.fr"&gt;Plausible&lt;/a&gt; - For ethical analytics&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/maxpou/maxpou.fr"&gt;GitHub&lt;/a&gt; - Where I host my code and run CI/CD pipelines&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Gaming
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I play mostly Age Of Empire 2 DE on my MacBook (thanks CrossOver)&lt;/li&gt;
&lt;li&gt;For other games, I rely on Cloud Gaming platforms such as
&lt;a href="https://www.nvidia.com/en-us/geforce-now/"&gt;GeForce Now&lt;/a&gt;, Stadia and
&lt;a href="https://www.xbox.com/en-US/play"&gt;XCloud&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.xbox.com/en-IE/accessories/controllers/elite-wireless-controller-series-2"&gt;Xbox Elite Controller Series 2&lt;/a&gt;
is my controller. A bit pricey, but very comfortable.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>productivity</category>
      <category>developertools</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Lessons Learned by Maintaining a Large Vue.js Codebase</title>
      <dc:creator>Maxence Poutord</dc:creator>
      <pubDate>Thu, 15 Apr 2021 00:00:00 +0000</pubDate>
      <link>https://dev.to/maxpou/lessons-learned-by-maintaining-a-large-vue-js-codebase-1mc3</link>
      <guid>https://dev.to/maxpou/lessons-learned-by-maintaining-a-large-vue-js-codebase-1mc3</guid>
      <description>&lt;p&gt;I've been maintaining a massive Vue.js codebase for the last 3 years. Here are 9 lessons I've&lt;br&gt;
learned along the way. Not really mistakes I've made but most likely things I'd do differently&lt;br&gt;
today.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TL;DR:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No standards, no consistency&lt;/li&gt;
&lt;li&gt;Close the door on bikeshedding&lt;/li&gt;
&lt;li&gt;Respect your elders&lt;/li&gt;
&lt;li&gt;"F*** the future. Program for today."&lt;/li&gt;
&lt;li&gt;Dependencies: we should have been stricter&lt;/li&gt;
&lt;li&gt;Don't use TODOs&lt;/li&gt;
&lt;li&gt;Keep your audits&lt;/li&gt;
&lt;li&gt;Mimic your users&lt;/li&gt;
&lt;li&gt;Don't create your core components from scratch!&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  No standards, no consistency
&lt;/h2&gt;

&lt;p&gt;I don't think it's possible to have &lt;strong&gt;consistency&lt;/strong&gt; without any communication. If your app is&lt;br&gt;
organised in 3 different feature teams you don't want to have 3 different ways of doing one thing.&lt;br&gt;
Agree on standards then communicate. Communication is the key.&lt;/p&gt;

&lt;p&gt;Don't be afraid to repeat yourself: &lt;em&gt;"pedagogy is the art of repeating yourself"&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Close the door on bikeshedding
&lt;/h2&gt;

&lt;p&gt;It starts by linting your code. No one likes comments like "you forgot a semicolon" on pull&lt;br&gt;
requests. Find a set of rules and follow it. Blindly. If you start to discuss it, you open a door&lt;br&gt;
for bikeshedding.&lt;/p&gt;

&lt;p&gt;I also recommend you to write a "Pull request: do and don't" so everybody knows what is and what's&lt;br&gt;
not expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Respect your elders
&lt;/h2&gt;

&lt;p&gt;Working with legacy can be frustrating. But it's not a reason to finger-point your elders. Try to&lt;br&gt;
find the root cause (i.e. code was written by Backend, there was no communication at that time...).&lt;br&gt;
Migrating towards greener pastures is a slow process. If there's no plan to get rid of the debt,&lt;br&gt;
it's time to make one.&lt;/p&gt;

&lt;h2&gt;
  
  
  "F*** the future. Program for today."
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://twitter.com/dhh/status/623598101127897088?lang=en"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QBxH73DS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4gwep6fjtctok0djp4gw.jpg" alt="DHH Tweet with the original quote" width="880" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We've made a lot of big technical decisions based on FUTURE. Guess what? Years after this future&lt;br&gt;
never happened. I don't have a crystal ball so I can't tell what the future will look like. If it's&lt;br&gt;
the same for you, don't make big decisions based on dreams and hopes.&lt;/p&gt;

&lt;p&gt;Program for today!&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependencies: we should have been stricter
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kHpWHZ6Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3x5b4zgskuxcysh6lc4v.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kHpWHZ6Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3x5b4zgskuxcysh6lc4v.gif" alt="a very long list" width="480" height="272"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Me opening the package.json&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Every time I open the package.json file, I keep thinking the same thing: &lt;em&gt;"we should have been&lt;br&gt;
stricter"&lt;/em&gt;. We have a list of 95 dependencies and 90 dev-dependencies.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;I think the &lt;strong&gt;fear of being a gate blocker&lt;/strong&gt; played a big part. A second factor was probably letting&lt;br&gt;
the pull request merge without approval from a frontend developer. Having many dependencies increase&lt;br&gt;
the risk of having a malicious package. Also, if we want to change the Vue.js version, we have to&lt;br&gt;
ensure that each library support it.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;// TODO: refactor&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VRio3c_7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dl8ovru3exfgciqb9u98.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VRio3c_7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dl8ovru3exfgciqb9u98.jpg" alt="a 3y old todo!" width="780" height="108"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TODOs are the graveyard of important but not urgent tasks.&lt;/strong&gt; The "I will fix it later" strategy&lt;br&gt;
doesn't work. If you're not very proud of the code you wrote, it's fine. It happens to the best of&lt;br&gt;
us ;) But please don't pollute the code with a TODO.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep your audits
&lt;/h2&gt;

&lt;p&gt;We have made a lot of progress in terms of performances, accessibility, and code quality. In 3&lt;br&gt;
years, I've made tons of audits with tools like Google Lighthouse or Axe. But I never kept a single&lt;br&gt;
one. It's such a pity because if today someone asks me what the progress we've made over the last 6&lt;br&gt;
months, I can't give any numbers.&lt;/p&gt;

&lt;p&gt;By the way, it can also provide some metrics for your CV ;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Mimic your users
&lt;/h2&gt;

&lt;p&gt;If you work on your app locally, with a 1500€ laptop and a fiber-optic internet connection, you will&lt;br&gt;
never experience a performance issue.&lt;/p&gt;

&lt;p&gt;I can say the same thing if you're using a large screen. 2.5y ago, I went fully remote and I dropped&lt;br&gt;
my fancy 26" curved screen. I realized that a few pages or our app were not readable on a 13".&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't create your core components from scratch!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Br4qBRzU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/trzbwwbi1dy9jfbzi5se.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Br4qBRzU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/trzbwwbi1dy9jfbzi5se.jpg" alt="Creating your custom component library is a waste of time. Change my mind" width="880" height="656"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We started building our component system ~2.5y ago. A lot of components we created ended up being&lt;br&gt;
surprisingly complex. When we couldn't refactor them, we created a new one (and deprecated the&lt;br&gt;
other).&lt;br&gt;&lt;br&gt;
Today, we have ~30 deprecated components and some of them are used a hundred times.&lt;/p&gt;

&lt;p&gt;Looking backwards, we wasted so much time creating the components (from scratch), testing, making&lt;br&gt;
them accessible (a11y) and writing the documentation. If we started with an existing one, we could&lt;br&gt;
have spent more time focusing on the business or the architectural part.&lt;/p&gt;

&lt;p&gt;No one cares if the button component you're using doesn't have "the perfect border-radius"!&lt;/p&gt;




&lt;p&gt;Thank you for taking the time to read this post. I hope you found it useful! If you liked it, please give it a ❤️ or a 🦄! Also, feel free to comment or ask questions in the section below or on &lt;a href="https://twitter.com/_maxpou"&gt;Twitter @_maxpou&lt;/a&gt; :)&lt;/p&gt;




&lt;p&gt;Originally published on &lt;a href="https://www.maxpou.fr/lesson-learned-maintaining-large-vue-js-codebase"&gt;maxpou.fr&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>vue</category>
      <category>career</category>
    </item>
    <item>
      <title>Bash tips for developers</title>
      <dc:creator>Maxence Poutord</dc:creator>
      <pubDate>Wed, 17 Mar 2021 00:00:00 +0000</pubDate>
      <link>https://dev.to/maxpou/bash-tips-for-developers-1lob</link>
      <guid>https://dev.to/maxpou/bash-tips-for-developers-1lob</guid>
      <description>&lt;p&gt;Like many developers, I use the terminal on a daily basis.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hMtJ2Mij--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vsbbhay4upl27i2z1fjt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hMtJ2Mij--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vsbbhay4upl27i2z1fjt.png" alt="How my terminal looks like" width="880" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I actually use 2 different terminals: the one embedded in VScode and iTerm2 (I'm on macOS). Although this post contains the word bash, I don't use it directly. I use zsh with &lt;a href="https://ohmyz.sh"&gt;ohmyzsh&lt;/a&gt;. If you never heard about it before, it supercharges bash and adds more interactivity. It also gives me interesting feedbacks like the branch and working directory I am currently in.&lt;/p&gt;

&lt;p&gt;By the way, if you like the theme I'm using, feel free to steal &lt;a href="https://github.com/maxpou/dotfiles"&gt;my dotfiles&lt;/a&gt;. Also, I won't be covering the Git part as I already did in &lt;a href="https://www.maxpou.fr/git-cheat-sheet"&gt;this blog post&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cheatsheet
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How many ".js" files does this folder contains?
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.js"&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;

&lt;span class="c"&gt;# You can also exclude a folder (i.e. node_modules)&lt;/span&gt;
find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.js"&lt;/span&gt; &lt;span class="nt"&gt;-not&lt;/span&gt; &lt;span class="nt"&gt;-path&lt;/span&gt; &lt;span class="s2"&gt;" **/node_modules/**"&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  How many lines of code in this folder?
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'*.vue'&lt;/span&gt; | xargs &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;

&lt;span class="c"&gt;# You can also exclude a folder (i.e. node_modules)&lt;/span&gt;
find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'*.vue'&lt;/span&gt; &lt;span class="nt"&gt;-not&lt;/span&gt; &lt;span class="nt"&gt;-path&lt;/span&gt; &lt;span class="s2"&gt;" **/node_modules/**"&lt;/span&gt; | xargs &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Find all occurrences
&lt;/h3&gt;

&lt;p&gt;Example: list where "console.log" is used in the codebase.&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;grep&lt;/span&gt; &lt;span class="nt"&gt;-Ril&lt;/span&gt; &lt;span class="s2"&gt;"console.log"&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# You can also exclude folders (i.e. .cache and node_modules)&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-Ril&lt;/span&gt; &lt;span class="s2"&gt;"console.log"&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--exclude-dir&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;&lt;span class="se"&gt;\*&lt;/span&gt;cache,node_modules&lt;span class="se"&gt;\*&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  How big is my folder?
&lt;/h3&gt;

&lt;p&gt;Example: list where "console.log" is used in the codebase.&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;du&lt;/span&gt; &lt;span class="nt"&gt;-sh&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# same but excluding git folder&lt;/span&gt;
&lt;span class="nb"&gt;du&lt;/span&gt; &lt;span class="nt"&gt;-sh&lt;/span&gt; &lt;span class="nt"&gt;-I&lt;/span&gt; .git &lt;span class="nb"&gt;.&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  What about Vim?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AO3cyoN7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gt3b8xqdiv29drx1lepu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AO3cyoN7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gt3b8xqdiv29drx1lepu.png" alt="SpaceVim a game changer for vim" width="880" height="720"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I mostly use Vim for Git commits. It can also be handy when your IDE struggle to open 10 0000 lines long files. To &lt;em&gt;pimp my vim™&lt;/em&gt;, I installed something called &lt;a href="https://spacevim.org"&gt;SpaceVim&lt;/a&gt;. It adds fancy things like a file explorer and the syntax color.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aliases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  RAM consumption
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;ram&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'ps aux | awk '&lt;/span&gt;&lt;span class="s2"&gt;"'"&lt;/span&gt;&lt;span class="s1"&gt;'{print $6/1024 " MB\t\t" $11}'&lt;/span&gt;&lt;span class="s2"&gt;"'"&lt;/span&gt;&lt;span class="s1"&gt;' | sort -rn | head -25'&lt;/span&gt;

&lt;span class="c"&gt;# Usage&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;ram
507.039 MB /usr/local/bin/node
461.391 MB /Applications/Brave
358.879 MB /Applications/Visual
...

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  🏴‍☠️ Change your mac address
&lt;/h3&gt;

&lt;p&gt;This one is not really tech-related. I mostly use this one in airports/coffee shops to renew mac address (and get illimited access).&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="k"&gt;function &lt;/span&gt;airport&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;mac&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;openssl rand &lt;span class="nt"&gt;-hex&lt;/span&gt; 6 | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/\(..\)/\1:/g; s/.$//'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;sudo &lt;/span&gt;ifconfig en0 ether &lt;span class="nv"&gt;$mac&lt;/span&gt;
  &lt;span class="nb"&gt;sudo &lt;/span&gt;ifconfig en0 down
  &lt;span class="nb"&gt;sudo &lt;/span&gt;ifconfig en0 up
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Your new physical address is &lt;/span&gt;&lt;span class="nv"&gt;$mac&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  🙃 The Russian Roulette
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;alias &lt;/span&gt;russian-roulette&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'
  [$(( $RANDOM % 6 )) == 0] &amp;amp;&amp;amp; rm -rf / || echo "You live"'&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;If you like to live on the edge... but please, be smart! And don't run commands you don't know the effects of!&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus #1: Tree
&lt;/h2&gt;

&lt;p&gt;I use &lt;a href="https://formulae.brew.sh/formula/tree"&gt;tree&lt;/a&gt; to display directories as trees. It very cool to write documentation.&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="nv"&gt;$ &lt;/span&gt;tree content/pages

├── components
│ ├── button.js
│ └── checkbox.jpg
├── pages
│ ├── about.js
│ └── dashboard.js
├── index.js
└── README.md

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bonus #2: Gtop
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/aksakalli/gtop"&gt;Gtop&lt;/a&gt; is a system monitoring dashboard. Typing Gtop on my keyboard is usually quicker than opening the activity monitor (for some unknown reasons I always struggle to find it).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Tn3aZZkn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q9fe6zr6gxwj453kisrl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Tn3aZZkn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q9fe6zr6gxwj453kisrl.png" alt="how gtop looks like" width="880" height="614"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;And you, what's your favourite bash tip?&lt;/p&gt;




&lt;p&gt;Thank you for taking the time to read this post. I hope you found it useful! If you liked it, please give it a ❤️ or a 🦄! Also, feel free to comment or ask questions in the section below or on &lt;a href="https://twitter.com/_maxpou"&gt;Twitter @_maxpou&lt;/a&gt; :)&lt;/p&gt;




&lt;p&gt;Originally published on &lt;a href="https://www.maxpou.fr/bash-for-dev"&gt;maxpou.fr&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>bash</category>
      <category>productivity</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Monorepo: is it worth jumping the bandwagon?</title>
      <dc:creator>Maxence Poutord</dc:creator>
      <pubDate>Fri, 11 Dec 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/maxpou/monorepo-is-it-worth-jumping-the-bandwagon-5dh1</link>
      <guid>https://dev.to/maxpou/monorepo-is-it-worth-jumping-the-bandwagon-5dh1</guid>
      <description>&lt;p&gt;The trend today is to split things and make them thinner. We witnessed the emergence of microservices, micro-frontends...&lt;/p&gt;

&lt;p&gt;Against this trend, some companies and projects had decided to put multiple applications/libraries under the same git repository. We call this architectural concept a monorepo (or mono repository).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zqpluHod--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9fgdg8mve1zns8ic0q3e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zqpluHod--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9fgdg8mve1zns8ic0q3e.png" alt="mono vs. multiple repository" width="880" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've been using and maintaining a monorepo for 2 years now. Here are my thoughts about it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Context: the monorepo I'm working on contains ~40 npm packages, mostly standalone vue.js apps. All those small apps are parts of a big application. We decided to split our big app into small ones because the main one had become hard to maintain. Also, we are ~15 developers working on this monorepo (not full-time).&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Pros
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🤝 Teamwork
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Favour contribution&lt;/strong&gt; :&lt;br&gt;&lt;br&gt;
When you already have the code, contributing is easier. You don't need to search for the repo, clone it and install it beforehand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better overview of the whole system&lt;/strong&gt; :&lt;br&gt;&lt;br&gt;
You already have all the source code. So you don't need to find the repo url, clone it. A plain old ctrl + F is enough.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Favour large refactoring&lt;/strong&gt; :&lt;br&gt;&lt;br&gt;
Let's say you want to change something in one package used everywhere else. You can update all the packages in one commit!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remove unused code with confidence&lt;/strong&gt; :&lt;br&gt;&lt;br&gt;
How many times you wanted to remove code but you didn't because you didn't know if code was used somewhere else? With monorepo, you don't need to go through all repo to see if this code is used or not. It's very handy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Single source of truth&lt;/strong&gt; :&lt;br&gt;&lt;br&gt;
The project I'm working on used to have a very weird name for the main branch. When we changed this name to another one, some repositories were updated, some were not (oversight). With a monorepo, you only have to find this information once.&lt;/p&gt;
&lt;h3&gt;
  
  
  👨‍👩‍👧 Dependencies
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Less space on your hard drive&lt;/strong&gt; :&lt;br&gt;&lt;br&gt;
If you're familiar with the JavaScript ecosystem, you're probably aware that the &lt;code&gt;node_module&lt;/code&gt; folder can be &lt;a href="https://www.reddit.com/r/ProgrammerHumor/comments/6s0wov/heaviest_objects_in_the_universe/"&gt;insanely heavy&lt;/a&gt;. When we had ~30 apps/packages, it used to take 12Gb on our hard drive. Yes, 12Gb! We had dependencies like Vue.js installed 30 times. Fortunately, some tools (like yarn) symlink redundant dependencies when workspaces are enabled. Thanks to this functionality, &lt;a href="https://twitter.com/_maxpou/status/1263426573379739651"&gt;we went from 12Gb to 1.7Gb&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--01iymDj7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vjrva41pyaep1sfflyp0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--01iymDj7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vjrva41pyaep1sfflyp0.png" alt="dependency-management" width="880" height="568"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: I know npm 7.0 now supports workspaces. However, it's still in the early stage. Important commands &lt;a href="https://github.com/npm/rfcs/pull/117/files"&gt;are not supported yet&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cross-package hot-reload&lt;/strong&gt; :&lt;br&gt;&lt;br&gt;
Some tools automatically symlink local dependencies together. Which means, if package-a is used in package-b, you can work on package-a and see the live result in package-b.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adding a new package is simple&lt;/strong&gt; :&lt;br&gt;&lt;br&gt;
For us, all our packages are under a &lt;code&gt;packages&lt;/code&gt; folder. Adding a new package is very straightforward: no need to parameter the continuous integration/package manager credentials, set the repository permissions... everything is already there.&lt;/p&gt;
&lt;h2&gt;
  
  
  Cons
&lt;/h2&gt;
&lt;h3&gt;
  
  
  🛠 Git &amp;amp; code hosting platforms (GitLab/GitHub...)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Authorization&lt;/strong&gt; :&lt;br&gt;&lt;br&gt;
When you set read/write permissions on GitLab/GitHub/etc., it's usually for the whole repo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;💡 Tip:&lt;/strong&gt; You can also create a &lt;a href="https://docs.gitlab.com/ee/user/project/code_owners.html"&gt;CODEOWNERS file&lt;/a&gt; to define specific ownership rule.&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="c"&gt;# .gitlab/CODEOWNERS&lt;/span&gt;
packages/app-1 @user1
packages/app-2 @user2

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

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;With the example above, if user2 opens a merge request to change app-1, user1 will have to approve it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Git log may become unreadable&lt;/strong&gt; :&lt;br&gt;&lt;br&gt;
If merge requests are merged "as is", with no squashing option (with 10-15 commits), the &lt;code&gt;git log&lt;/code&gt; will quickly become unreadable, and so unusable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;💡 Tip:&lt;/strong&gt; You can use &lt;a href="https://www.maxpou.fr/git-conventional-commits"&gt;conventional commit&lt;/a&gt; and put in parenthesis the name of the package. So if you want to retrieve one old commit, it becomes straightforward.&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="c"&gt;# will list all feature added in package-B&lt;/span&gt;
git log &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="nt"&gt;--grep&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"feat(package-B):"&lt;/span&gt;

&lt;span class="c"&gt;# or:&lt;/span&gt;
git log &lt;span class="nt"&gt;--all&lt;/span&gt; path/to/package-b

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Git log may become unusable&lt;/strong&gt; :&lt;br&gt;&lt;br&gt;
If you have a lot of commits/living branches/tags, it means you will have a lot of git objects stored. git will probably have trouble getting the history of a specific file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Forget your long-lived branches&lt;/strong&gt; :&lt;br&gt;&lt;br&gt;
If the main branch is the only source of truth, you can't have a &lt;code&gt;next&lt;/code&gt; branch. If you want to have some features only available for a specific environment, then I recommend you to use feature flags.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repository may become oversized&lt;/strong&gt; :&lt;br&gt;&lt;br&gt;
The &lt;code&gt;.git&lt;/code&gt; folder on your monorepo root might reach a few Gb.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;💡 Tip:&lt;/strong&gt; Here are 2 different options if you want to save some space&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="c"&gt;# truncate the history&lt;/span&gt;
git clone &lt;span class="nt"&gt;--depth&lt;/span&gt; 1 &amp;lt;repo-url&amp;gt; 

&lt;span class="c"&gt;# 1. clone an empty repo with no history &lt;/span&gt;
&lt;span class="c"&gt;# 2. pull the desired package&lt;/span&gt;
git clone &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--depth&lt;/span&gt; 1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--no-checkout&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--filter&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;blob:none &lt;span class="se"&gt;\&lt;/span&gt;
  &amp;lt;repo-url&amp;gt;
git checkout main &lt;span class="nt"&gt;--&lt;/span&gt; packages/package-a

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

&lt;/div&gt;



&lt;p&gt;_Note: learn more about &lt;a href="%5Bhttps://docs.gitlab.com/ee/topics/git/partial%5D(https://docs.gitlab.com/ee/topics/git/partial)_clone.html"&gt;partial cloning&lt;/a&gt;._&lt;/p&gt;

&lt;h3&gt;
  
  
  🤖 Continuous Integration (CI)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;When it's broken, everybody is!&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If the &lt;code&gt;main&lt;/code&gt; branch is marked red by your continuous integration, everybody is impacted. You cannot put this problem under the carpet. It needs to be addressed directly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Continuous Integration dilemma&lt;/strong&gt; :&lt;br&gt;&lt;br&gt;
If codebases are mutualized, you have more code. And more code means more work for continuous integration (CI) for jobs like testing, linting, building...&lt;/p&gt;

&lt;p&gt;When dealing with CI, time and reliability are the heart of the matter. On the one hand, you want it to be as fast as possible but, on the other hand, you want it to be reliable. I mean, when my CI gives me a green light, I'm more confident to merge my work.&lt;/p&gt;

&lt;p&gt;It can be tempting to reduce the number of packages analysed to gain some time. But, continuous integration will lose interest because it will not be able to spot a "cross-repository" regression.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Entire codebase&lt;/th&gt;
&lt;th&gt;Selected package&lt;/th&gt;
&lt;th&gt;Affected packages&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Build/lint/test Speed&lt;/td&gt;
&lt;td&gt;🐌 Slow&lt;/td&gt;
&lt;td&gt;🚀 Fast&lt;/td&gt;
&lt;td&gt;🚗 Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spot cross-packages regression?&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Easy to set up?&lt;/td&gt;
&lt;td&gt;😀 Yes&lt;/td&gt;
&lt;td&gt;😀 Yes&lt;/td&gt;
&lt;td&gt;😟 No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The 3rd option is, in my opinion, the most viable. But, you will have to do it manually. A 4th option could use filters. "important" labelled packages use the 1st strategy and the rest use the 2nd strategy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;💡 Tips:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If your CI pipeline is good enough and you have parallel tasks, don't forget to enable the fail-fast option.&lt;/li&gt;
&lt;li&gt;I recommend you to add a specific label to short-circuit the CI. Like if you change a typo in the README, you don't need to run unnecessary commands. (i.e. If the pull request have a "NO_CI" label, the build will not be triggered)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🤝 Teamwork
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Hidden changes&lt;/strong&gt; :&lt;br&gt;&lt;br&gt;
Some repos are sometimes more "sensitive" than others. It's easy to add a small piece of code with a big impact. It can be problematic if it's done by mistake.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Amount of code can be intimidating&lt;/strong&gt; :&lt;br&gt;&lt;br&gt;
The first time I "git pulled" the source code of Gatsby.js, I pulled the full history of ~90 packages. At first glance, I felt overwhelmed. Because it took me ages to clone the full repository (with all the history). And also, because the amount of code was massive!&lt;/p&gt;

&lt;p&gt;If you work with 10% of a codebase, you probably don't care about the 90% remaining.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Overall, I think a monorepo can be a good thing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--up0RSXv3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jwusrrexpzwk2199doyc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--up0RSXv3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jwusrrexpzwk2199doyc.png" alt="monorepo are become relevant when packages are connected and written in the same language" width="880" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In our case, it makes our life easier. All our packages are a part of the same big application and are written in the same language. Because they're a part of the same application, they &lt;em&gt;"communicate between each other"&lt;/em&gt;. Also, we're a human-sized team working on it.&lt;/p&gt;




&lt;p&gt;And as always, feel free to reach out to me on &lt;a href="https://twitter.com/_maxpou"&gt;Twitter (@_maxpou)&lt;/a&gt; or in the comment below! 😊&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.maxpou.fr/monorepo-pros-and-cons"&gt;maxpou.fr&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

</description>
      <category>git</category>
      <category>monorepo</category>
    </item>
    <item>
      <title>Tips for your GitHub Portfolio</title>
      <dc:creator>Maxence Poutord</dc:creator>
      <pubDate>Fri, 16 Oct 2020 07:53:23 +0000</pubDate>
      <link>https://dev.to/maxpou/tips-for-your-github-portfolio-1ffk</link>
      <guid>https://dev.to/maxpou/tips-for-your-github-portfolio-1ffk</guid>
      <description>&lt;p&gt;A few week ago 2 people asked me the same question on Twitter: &lt;em&gt;"how do I make a better portfolio?"&lt;/em&gt;&lt;br&gt;
Since, it's not the first time I have this question, I decided to &lt;em&gt;answer in public™️&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Before I start, just want to highlight something. Having a GitHub profile is not and should never be mandatory. It's "a nice to have".&lt;/p&gt;

&lt;h2&gt;
  
  
  Quality over quantity
&lt;/h2&gt;

&lt;p&gt;It's common to see GitHub profiles like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5h8t2k6guvik7o2c4f18.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5h8t2k6guvik7o2c4f18.png" alt="pinned GitHub repositories with no description"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;(repositories names were anonymised)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The person picked 6 repositories and pinned them. All the repo have 3 commits, no readme. This developper seems to experiment a lot of things but, nothing really stands out. If a recruiter asks you "what problem did you encounter and how did you solve it", the answer will be limited.&lt;/p&gt;

&lt;p&gt;Don't get me wrong, there's nothing bad about experimenting new things! I also have a lot of hello world projects on my GitHub profile. However, those are not pinned on my profile. I only pin what I think it's relevant. I know recruiters don't have time to go through all my projects. That's why &lt;a href="https://github.com/maxpou" rel="noopener noreferrer"&gt;I have 5&lt;/a&gt; when I'm writing those lines.&lt;/p&gt;

&lt;p&gt;Instead of having 6 small projects, pick one. And polish it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn in public
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;"I don't put it on GitHub unless it's perfect"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This quote comes from a senior dev I used to work with. I think it's a pity to think like that. In general, &lt;strong&gt;people who are afraid of making mistakes end up doing nothing&lt;/strong&gt;. If you look at popular repositories on GitHub, most of them are far from perfect. And it's fine!&lt;/p&gt;

&lt;p&gt;And also, if one day someone checks your project's git log and finds out that you forgot a bracket/semicolon, I don't think he will blame you for that. And if he does, it's good for you. Nobody wants to work with toxic people.&lt;/p&gt;

&lt;h2&gt;
  
  
  There's alway something to do!
&lt;/h2&gt;

&lt;p&gt;I did a mentoring session once with a girl who wanted to retrain in IT. She showed me the small game she developed. But, she wanted to find a new project because she thought this project was "done".&lt;/p&gt;

&lt;p&gt;A project is never done. There's always something to do... Remember the 1st advice: "Quality over quantity"!&lt;/p&gt;

&lt;p&gt;Here are a few things you can do...&lt;/p&gt;

&lt;h3&gt;
  
  
  Add a README.md
&lt;/h3&gt;

&lt;p&gt;The readme is the entry point of your project. The first thing people will see!&lt;br&gt;
I think every code repository should have one. If you don't want people to get interest in your project you can add one and write "nothing to see here".&lt;/p&gt;

&lt;p&gt;Your readme should answer those questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is this project about? &lt;em&gt;(1-2 sentences should be enough).&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;How to install it?&lt;/li&gt;
&lt;li&gt;How to use it?&lt;/li&gt;
&lt;li&gt;What does it look like? you can add a screenshot or a gif animation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; You can take some inspiration in the &lt;a href="https://github.com/matiassingers/awesome-readme" rel="noopener noreferrer"&gt;Awesome README repository&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do marketing
&lt;/h3&gt;

&lt;p&gt;If you're building an app, advertise about it! I've an ex-colleague who's building a minimalist text editor. Every now and then, he publishes links on social media (Twitter, LinkedIn...) about his product and the new features he added. He also added his product on ProductHunt/Reddit. These platforms are great to gather feedback!&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; There is also smaller communities in WhatsApp, Telegram or Discord (i.e. &lt;a href="https://discord.gg/partycorgi" rel="noopener noreferrer"&gt;Party Corgi&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Add more features
&lt;/h3&gt;

&lt;p&gt;On a green field project, finding more features should not be the hardest thing to find. If you did a bit of marketing on it or if you asked for feedback to your friends/family, you should have a list of ideas to add.&lt;/p&gt;

&lt;p&gt;At some point, you might face the situation where you have to rethink the way you wrote your app. It's a good point for you because it means you overcome the "Hello world" stage. Interesting problems usually arrive when your app is growing.&lt;/p&gt;

&lt;h3&gt;
  
  
  And also...
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Manage your todo list with tickets/issues. If you have a few tickets, you can group them into different categories: "bug", "enhancement"... If people spot a bug or have a feature request, they will probably open an "issue" on your repository! Also, one small tip: fix all bugs before starting any new feature!&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/maxpou/10-tips-for-writing-better-tests-95j"&gt;Write tests&lt;/a&gt;! Lot of dev recruiters like to see tests when they review code. The project you're working on can be a good opportunity to write some!&lt;/li&gt;
&lt;li&gt;Add &lt;strong&gt;continuous integration (CI)&lt;/strong&gt;. Every time you add code a robot will check if tests are passing and if you don't have dead code/oversights/... You can use tools like TravisCI, GitHub Actions...&lt;/li&gt;
&lt;li&gt;Automate the deployment. Many tools allow you to deploy your app on the web once you &lt;code&gt;git push&lt;/code&gt; to the &lt;code&gt;master&lt;/code&gt; branch. You can check Netlify, GitHub/GitLab Pages, Vercel...&lt;/li&gt;
&lt;li&gt;Make your app &lt;a href="https://developers.google.com/web/fundamentals/accessibility" rel="noopener noreferrer"&gt;accessible (a11y)&lt;/a&gt;, so people with disabilities can use your app.&lt;/li&gt;
&lt;li&gt;Make it mobile friendly (responsive web design) and if you feel comfortable, why not creating a Progressive Web App (PWA)?&lt;/li&gt;
&lt;li&gt;Monetize it? If you think you're solving a problem that other people have and if you, you should think about monetization. This project might pay you your coffee... or more!&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Now it's your turn. Show me your kick-ass GitHub Profile!&lt;/p&gt;




&lt;p&gt;Feel free to reach out to me on &lt;a href="https://twitter.com/_maxpou" rel="noopener noreferrer"&gt;Twitter (@_maxpou)&lt;/a&gt; or in the comment below! 😎&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.maxpou.fr/tips-for-your-github-portfolio" rel="noopener noreferrer"&gt;maxpou.fr&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

</description>
      <category>codenewbie</category>
      <category>beginners</category>
      <category>github</category>
    </item>
    <item>
      <title>Vue.js Performance Improvement with Memoization</title>
      <dc:creator>Maxence Poutord</dc:creator>
      <pubDate>Tue, 01 Sep 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/maxpou/vue-js-performance-improvement-with-memoization-3i9e</link>
      <guid>https://dev.to/maxpou/vue-js-performance-improvement-with-memoization-3i9e</guid>
      <description>&lt;p&gt;A few weeks ago, memoization helped me to fix a performance issue in my Vue.js application. The result looks like a &lt;em&gt;"Vue.js computed property with parameters"&lt;/em&gt;, although it's not possible!&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;The problem appeared in this big timeline component.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AjuReymy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nvej9689648x7yt5d1fg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AjuReymy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nvej9689648x7yt5d1fg.png" alt="the timeline component" width="880" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To make it short:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 line = 1 week of events for one person;&lt;/li&gt;
&lt;li&gt;events may overlap (Bob has one on Monday morning).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To position an event on the grid (left, width, top, height/lineHeight), I have to call a function to compute if this event overlaps with another one. &lt;strong&gt;This function was called many times and sometimes with the same parameters.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This component used to work nicely &lt;em&gt;on my local environment™️.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But, with more events/day (≃ more squares) and more users (≃ more rows), it was a different story. The component was taking ~4 to ~6 seconds to show up. I added a &lt;code&gt;console.count()&lt;/code&gt; and I realized that my function was called +700 times! 🙈&lt;/p&gt;

&lt;p&gt;My first call was to use &lt;code&gt;computed()&lt;/code&gt;, &lt;strong&gt;a cached property (based on their reactive dependencies)&lt;/strong&gt;.Unfortunately, they're not working with parameters. In other words, you cannot do that:&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;data&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="na"&gt;events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="cm"&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;computed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ❌ NOT WORKING!&lt;/span&gt;
    &lt;span class="nx"&gt;eventPosition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&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;I had to find something else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memoization to the rescue!
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;(If you're already aware of what memoization is, you can directly jump to the next part)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Memoization is a functional programming concept. The idea is to use the function's internal cache to store parameters. The first time a function is called, we compute the value then we store in a cache the output. If this function is called a 2nd time with the same parameter, it will return the value from the cache&lt;/p&gt;

&lt;p&gt;The fibonacci function is a good example of how memoization works because this implementation uses recursion. In this example, a function can be called multiple times with the same argument.&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;// without memoization&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&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="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&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;And with memoization, the same function will be written 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;// with memoization&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 1&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&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="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cache&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="c1"&gt;// 2&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;fibonacci&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;n&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="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&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="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// 3&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;n&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;I splitted this function in 3 steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;the first time the function is executed, we define an empty cache;&lt;/li&gt;
&lt;li&gt;if the value we're trying to compute is not in the cache, we compute it and add it to the cache;&lt;/li&gt;
&lt;li&gt;we return the cached value.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you add a &lt;code&gt;console.count(n)&lt;/code&gt; in the second &lt;code&gt;if()&lt;/code&gt;, you will see that with memoization, &lt;code&gt;fibonacci(12)&lt;/code&gt; will compute the value of &lt;code&gt;fibonacci(4)&lt;/code&gt; only one time instead of 34!&lt;/p&gt;

&lt;h3&gt;
  
  
  🧐 How's that possible?
&lt;/h3&gt;

&lt;p&gt;Memoization is possible because, in JavaScript, functions are prototypes of Object.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myCoolFunction&lt;/span&gt; &lt;span class="o"&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="kc"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;myCoolFunction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;__proto__&lt;/span&gt; &lt;span class="c1"&gt;// "function"&lt;/span&gt;
&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;myCoolFunction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;__proto__&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;__proto__&lt;/span&gt; &lt;span class="c1"&gt;// "object"&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;As you can see, with memoization, we &lt;strong&gt;trade the code's readability for performance&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memoization in Vue.js
&lt;/h2&gt;

&lt;p&gt;Now we have seen how memoization works, let's see how to apply this technique in a Vue.js component.For that, we have to put the function into a Vue's &lt;code&gt;methods&lt;/code&gt;. Then, it's pretty much the same as what we saw before.&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;// MyComponent.vue&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;data&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="na"&gt;events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="cm"&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;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;positionEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&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="k"&gt;typeof&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;positionEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;positionEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cache&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="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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;positionEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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;somethingToCache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;heavyFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// 🔼 add your function here&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;positionEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;somethingToCache&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;return&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;positionEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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;&lt;strong&gt;💡 Tips&lt;/strong&gt; :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;don't forget to add &lt;code&gt;this&lt;/code&gt; before your method's name.&lt;/li&gt;
&lt;li&gt;feel free to adapt the cache key with your needs!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Is it worth the trouble?
&lt;/h2&gt;

&lt;p&gt;In this very particular case: &lt;strong&gt;yes&lt;/strong&gt;. My component is using a time-consuming function multiple times with the same parameters.&lt;/p&gt;

&lt;p&gt;The component rendering went from ~4s to ~0.3s. It's 10 times quicker!!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dAaBZRQU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/86ejk411ucr8ex4745yb.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dAaBZRQU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/86ejk411ucr8ex4745yb.jpeg" alt="performance gains with memoization" width="880" height="613"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, &lt;strong&gt;I don't see memoization as a &lt;a href="https://en.wikipedia.org/wiki/Law_of_the_instrument"&gt;golden hammer&lt;/a&gt;&lt;/strong&gt;. To be honest, it's the first time I use memoization in years of web development.&lt;/p&gt;




&lt;p&gt;And that's it for today!&lt;/p&gt;

&lt;p&gt;Thanks for reading this article 🤘. I hope you found it useful! If you liked it, please give it a ❤️ or a 🦄! &lt;/p&gt;

&lt;p&gt;You can also &lt;a href="https://twitter.com/_maxpou"&gt;follow me on Twitter (@_maxpou)&lt;/a&gt; 💙&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.maxpou.fr/vuejs-performance-improvement-with-memoization"&gt;maxpou.fr&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>vue</category>
    </item>
    <item>
      <title>Vue.js Testing Made it Easy (with Testing Library)</title>
      <dc:creator>Maxence Poutord</dc:creator>
      <pubDate>Thu, 02 Jul 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/maxpou/vue-js-testing-made-it-easy-with-testing-library-1dg9</link>
      <guid>https://dev.to/maxpou/vue-js-testing-made-it-easy-with-testing-library-1dg9</guid>
      <description>&lt;p&gt;Today, I want to talk about testing in the Vue.js ecosystem. Between my previous job and my current one, I've been searching for too long a way to test Vue.js applications. I always ended up with something too verbose or overcomplicated.&lt;/p&gt;

&lt;p&gt;1.5 year ago, my colleague John introduced me to a very cool library: &lt;a href="https://github.com/testing-library/vue-testing-library" rel="noopener noreferrer"&gt;Vue Testing Library&lt;/a&gt;. In a nutshell, it provides a solution to test Vue.js applications... but from a user point of view. Their motto? This one:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The more your tests resemble the way your software is used, the more confidence they can give you.&lt;/p&gt;

&lt;p&gt;－ &lt;a href="https://kentcdodds.com" rel="noopener noreferrer"&gt;Kent C. Dodds&lt;/a&gt;, author of Testing Library&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We were already using the official library: vue-test-utils. It provides good results for unit testing components. But, we were not completely convinced by the integration tests. In addition, I don't think unit testing components bring much value. We decided to give a try.&lt;/p&gt;

&lt;p&gt;After a year of using it, a colleague he threw this question on the Frontend chat:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fhttps%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkxl6hflqh1gstdylgfs1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fhttps%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkxl6hflqh1gstdylgfs1.png" alt="Poll: should we use testing library only"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;(actually the only 👎 is due to a misunderstanding)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Why do we all like it? Because it provides an &lt;strong&gt;easy&lt;/strong&gt; and &lt;strong&gt;straightforward&lt;/strong&gt; way to test our Vue.js Application.&lt;/p&gt;

&lt;p&gt;Ok, enough talking. Let's jump to the code :)&lt;/p&gt;
&lt;h2&gt;
  
  
  Let's get it started!
&lt;/h2&gt;

&lt;p&gt;For this article, I'll take a small app I created.&lt;/p&gt;

&lt;p&gt;👉 A demo is available here: &lt;a href="https://vue-testing-library.netlify.app/#/" rel="noopener noreferrer"&gt;vue-testing-library.netlify.app&lt;/a&gt;&lt;br&gt;&lt;br&gt;
👉 Code is here: &lt;a href="https://github.com/maxpou/vue-testing-library-sample" rel="noopener noreferrer"&gt;github.com/maxpou/vue-testing-library-sample&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnb3adaq7mngizuvlsfkt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnb3adaq7mngizuvlsfkt.png" alt="app screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The application features are quite basic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fetch products from the Star Wars API and print it to the screen;&lt;/li&gt;
&lt;li&gt;filter products by name when user type something in the textbox;&lt;/li&gt;
&lt;li&gt;add product in the basket;&lt;/li&gt;
&lt;li&gt;
&lt;del&gt;buy products.&lt;/del&gt; Sorry. I'm Max, not Elon Musk. I can't sell starships 😁&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This application is heavily based on vue-cli (including jest+vue-test-utils). Actually, Vue Testing Library &lt;strong&gt;acts as a wrapper for vue-test-utils&lt;/strong&gt;. You can add the library like this:&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;--save-dev&lt;/span&gt; @testing-library/vue @testing-library/jest-dom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/testing-library/jest-dom" rel="noopener noreferrer"&gt;Jest-dom&lt;/a&gt; is not mandatory. But I recommend you to install it as it provides some very handy matchers for Jest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our first test
&lt;/h2&gt;

&lt;p&gt;The first thing I want to test is the presence of starships on the screen!&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;// tests/unit/catalog.spec.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&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 show products name, detail and price&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;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Executor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Kuat Drive Yards, Fondor Shipyards&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByText&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,143,350,000.00&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now run &lt;code&gt;npm test&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;💥 Boom! It's done!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;render(App)&lt;/code&gt;: this is where we instantiate the component.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;screen.getByText('Executor')&lt;/code&gt;: we search for the &lt;em&gt;"Executor"&lt;/em&gt; occurrence in the mounted component. If this value is not found, an error will be thrown. This value must be unique!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Also, you probably realised that you don't need to do any specific configuration!&lt;/p&gt;

&lt;p&gt;Note: the API calls are &lt;a href="https://dev.to/jest-mock-axios-calls"&gt;mocked with Jest&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interacting with the page (click, keypress...)
&lt;/h2&gt;

&lt;p&gt;Now I want to test a user interaction. The spaceship filtering is a good candidate.&lt;br&gt;
Let's test the following scenario: if the user types &lt;em&gt;"wing"&lt;/em&gt;, we should only see &lt;em&gt;"X-wing"&lt;/em&gt; and &lt;em&gt;"Y-wing"&lt;/em&gt;.&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="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 filter products when user type on the textbox&lt;/span&gt;&lt;span class="dl"&gt;'&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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fireEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;change&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByLabelText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Filter results&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;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wing&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="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;queryByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Death Star&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBeInTheDocument&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;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;X-wing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBeInTheDocument&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;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Y-wing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBeInTheDocument&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;
  
  
  fireEvent()
&lt;/h3&gt;

&lt;p&gt;To write text in an input text, we use &lt;code&gt;fireEvent.change(selector, options)&lt;/code&gt;. If we wanted to "click" on something, we would use instead &lt;code&gt;fireEvent.click()&lt;/code&gt;. Keep in mind, &lt;code&gt;fireEvent&lt;/code&gt; returns a promise, don't forget the await statement before.&lt;/p&gt;

&lt;h3&gt;
  
  
  queryByText() vs. getByText()
&lt;/h3&gt;

&lt;p&gt;When you want to test a missing text, &lt;code&gt;queryByText&lt;/code&gt; is the prefered way.&lt;br&gt;
Remember, &lt;code&gt;getByText&lt;/code&gt; throws an error when the text is not present! &lt;/p&gt;

&lt;p&gt;I mentioned before, I use Jest-dom. To extend Jest's &lt;code&gt;expect()&lt;/code&gt; function, you need to register it on the config files (&lt;a href="https://github.com/maxpou/vue-testing-library-sample/blob/master/jest.config.js#L6-L8" rel="noopener noreferrer"&gt;like this&lt;/a&gt;).&lt;/p&gt;
&lt;h2&gt;
  
  
  Testing the router (with vue-router)
&lt;/h2&gt;

&lt;p&gt;Usually, Vue.js components are not aware of the router. We have to provide the routes to the render function.&lt;/p&gt;

&lt;p&gt;We could define the routes on every test... but I don't like to write the same code multiple times. Instead, I recommend you to overload Testing Library's &lt;code&gt;render()&lt;/code&gt; function with our defined routes.&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;// tests/render.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../src/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ui&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="nf"&gt;r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;routes&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 I want to test something with a page transition, my test will look like the previous tests.&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../render&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&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;basket should be empty&lt;/span&gt;&lt;span class="dl"&gt;'&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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fireEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Basket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Your basket is empty!&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You probably noticed the &lt;code&gt;findByText()&lt;/code&gt;. I could not use &lt;code&gt;getByText()&lt;/code&gt; because new page rendering is asynchronous.&lt;br&gt;
&lt;code&gt;findByXXX&lt;/code&gt; is good when you want to find something that is not accessible straight away.&lt;/p&gt;
&lt;h2&gt;
  
  
  Testing the store (with Vuex)
&lt;/h2&gt;

&lt;p&gt;This part is a little bit trickier than the router part.&lt;/p&gt;

&lt;p&gt;To work properly, a Vuex store needs to be registered somewhere.&lt;/p&gt;

&lt;p&gt;The painless way I found to test components with a store, was to split it into 2 separate functions. Your tests will use &lt;code&gt;getDefaultStore()&lt;/code&gt; and your app will use the Vuex instance (2nd export).&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;// src/store/index.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getDefaultStore&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="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;getters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Vuex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getDefaultStore&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, you can override Testing Library's &lt;code&gt;render()&lt;/code&gt; function with your custom stuff.&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;// tests/render.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ui&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;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getDefaultStore&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="c1"&gt;// reset/override default store here&lt;/span&gt;
  &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;basket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&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="nx"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;catalog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;starships&lt;/span&gt; &lt;span class="o"&gt;=&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="nx"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;catalog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;catalog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fullyLoaded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;,&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might wonder why I'm cleaning the store with multiple &lt;code&gt;store.modules.xxxx&lt;/code&gt;? Well, I want my test to &lt;a href="https://dev.to/10-tips-write-better-tests#2---isolate-your-tests"&gt;be fully isolated&lt;/a&gt;. It's not an easy job since Vuex is based on mutations. Without these lines, you may have problems where test #3 depends on test #2.&lt;/p&gt;

&lt;p&gt;Once it's done, you don't need to do anything specific. Vuex test should look like any other test,&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="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 add items to basket&lt;/span&gt;&lt;span class="dl"&gt;'&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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fireEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByLabelText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Add Millennium Falcon&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fireEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByLabelText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Add Imperial shuttle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fireEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByLabelText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Add Imperial shuttle&lt;/span&gt;&lt;span class="dl"&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;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;navigation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toHaveTextContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Basket (3)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fireEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Basket (3)&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See! It doesn't look like I'm testing a store 🙂&lt;/p&gt;

&lt;h2&gt;
  
  
  One render function to rule them all!
&lt;/h2&gt;

&lt;p&gt;Let's sum up. We created a custom wrapper for the vue-router and another one for Vuex. I could post a render function 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;// test/render.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ui&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;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getDefaultStore&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="c1"&gt;// store overrides...&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;routes&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...but, it's a little bit too &lt;em&gt;"hello world"&lt;/em&gt; for me. I guess you also use some cool Vue.js related libraries (VueI18n, VeeValidate...)? &lt;br&gt;
Here's good news for you. This is the wrapper I use for ~90% of my tests:&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&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;storeOverrides&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="o"&gt;=&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="nf"&gt;r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;store&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="nf"&gt;getDefaultStore&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;storeOverrides&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;vue&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="nx"&gt;router&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;vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;VueI18n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;VeeValidate&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;i18n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;VueI18n&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;en&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="na"&gt;silentTranslationWarn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;i18n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;router&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;The &lt;code&gt;storeOverrides&lt;/code&gt; parameter allows you to override a part of the store for a specific test (i.e. testing functionality with a different user).&lt;/p&gt;

&lt;h2&gt;
  
  
  The quest for the perfect query
&lt;/h2&gt;

&lt;p&gt;In the beginning, finding the perfect query to use can be hazardous. In this blog post, we already saw a few.&lt;br&gt;
If you're lost, don't worry. &lt;strong&gt;&lt;code&gt;getByText()&lt;/code&gt; and &lt;code&gt;queryByText()&lt;/code&gt; cover the most common usages&lt;/strong&gt;. Once you're comfortable with them, feel free to check these resources.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://testing-library.com/docs/guide-which-query" rel="noopener noreferrer"&gt;testing-library.com/docs/guide-which-query&lt;/a&gt;: the official documentation;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testing-playground.com/" rel="noopener noreferrer"&gt;testing-playground.com&lt;/a&gt;: you can copy/paste your HTML and they will tell you which query is the most appropriate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, when you hesitate, &lt;strong&gt;think about your users&lt;/strong&gt;. How do they interact with your app? &lt;br&gt;
For a login feature, do you want them to: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fill their credentials in a textbox with a &lt;code&gt;class="form form-password"&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;fill their credentials in a textbox labeled "password"?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You see? 😉&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/10-tips-write-better-tests#6---test-your-app-in-the-same-way-as-a-user-will-use-it"&gt;Think users&lt;/a&gt;. If you pick the 2nd, you will kill two birds with one stone. You will test the login feature &lt;strong&gt;plus your component accessibility&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; &lt;a href="https://github.com/testing-library/eslint-plugin-testing-library" rel="noopener noreferrer"&gt;eslint-plugin-testing-library&lt;/a&gt; is a great addition! It can spot some misused queries.&lt;/p&gt;
&lt;h2&gt;
  
  
  Debugging
&lt;/h2&gt;

&lt;p&gt;Vue Testing Library doesn't let you access to component's internals. It's voluntary.&lt;br&gt;
The idea behind this decision is to prevent developers from &lt;a href="https://dev.to/10-tips-write-better-tests#8---avoid-implementation-detail"&gt;testing implementation detail&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here's what you can do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;add some &lt;code&gt;console.log()&lt;/code&gt; in the lifecycle component (&lt;code&gt;mounted&lt;/code&gt;, &lt;code&gt;updated&lt;/code&gt;...);&lt;/li&gt;
&lt;li&gt;use the &lt;code&gt;debug()&lt;/code&gt; function provided by the library.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&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 test something but it&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s1"&gt;s not working&lt;/span&gt;&lt;span class="dl"&gt;'&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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;// screen.getByText('broken assertion')&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then, when you &lt;code&gt;npm test&lt;/code&gt;, component DOM will be printed in the console (with a nice syntax color).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🙋🏽‍♀️ Help, &lt;code&gt;debug()&lt;/code&gt; give me a truncated output!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can override the debug max size like this.&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="nv"&gt;DEBUG_PRINT_LIMIT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100000 npm &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;And that's it for today!&lt;/p&gt;

&lt;p&gt;Thank you for reading. Feel free to comment or ask questions in the section below or on &lt;a href="https://twitter.com/_maxpou" rel="noopener noreferrer"&gt;Twitter (@_maxpou)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy testing 🙂&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.maxpou.fr/vue-js-testing-library" rel="noopener noreferrer"&gt;maxpou.fr&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>javascript</category>
      <category>vue</category>
    </item>
    <item>
      <title>Code Coverage: The Great Illusion</title>
      <dc:creator>Maxence Poutord</dc:creator>
      <pubDate>Thu, 07 May 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/maxpou/code-coverage-the-great-illusion-3an0</link>
      <guid>https://dev.to/maxpou/code-coverage-the-great-illusion-3an0</guid>
      <description>&lt;p&gt;The company I'm working for recently set a code coverage rule requirement.  Although I believe tests improve the software quality and help developers to write code with confidence, I'm strongly against this coverage rules. I believe this metric should never be used as a target. But first, let's understand how code coverage works under the hood.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article is intended for web application testing. Not for a library (open source or not).&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How Code Coverage is generated
&lt;/h2&gt;

&lt;p&gt;Let's take the following code:&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&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;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// do something with 'a'.&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// do something else.&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;will be rewriten as:&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cov_2mofekog2n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;f&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;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;cov_2mofekog2n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s&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;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="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// do something with 'a'.&lt;/span&gt;
    &lt;span class="nx"&gt;cov_2mofekog2n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;b&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;span class="mi"&gt;0&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="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// do something else.&lt;/span&gt;
    &lt;span class="nx"&gt;cov_2mofekog2n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;b&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;span class="mi"&gt;1&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="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 global counter object &lt;code&gt;cov_2mofekog2n&lt;/code&gt; is created for this file. This object's have key that stand for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;f&lt;/code&gt;: function;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;s&lt;/code&gt;: statement. Note: the else belongs to the if statement. That's why we have only one statement here.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;b&lt;/code&gt;: branch. Note that branch 0 have 2 counter (because if and else are 2 different branches)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As &lt;a href="https://blog.npmjs.org/post/178487845610/rethinking-javascript-test-coverage" rel="noopener noreferrer"&gt;Benjamin Coe mentioned&lt;/a&gt;, this way of measuring the coverage changed had now. Code coverage is now computed on Node V8's side. But, the idea of a global counter remains the same.&lt;/p&gt;

&lt;p&gt;Now we have seen how this metric is computed, let's see why we shouldn't use it as a target.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reason #1: Covered code !== tested code
&lt;/h2&gt;

&lt;p&gt;We can take the previous code example and add the following test.&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;// foo.test.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./foo.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&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;Foo.js&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;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 do something&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;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;foo&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if you run &lt;code&gt;npm run test -- --coverage&lt;/code&gt;, you will get... 100% code coverage. In other words: &lt;strong&gt;You don't need any assertion to cover code&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;The example itself might sound ridiculous because dev usually don't write empty functions or tests like that. Ok. &lt;/p&gt;

&lt;p&gt;Let's take a more realistic example.&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;// shop.spec.js&lt;/span&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;Shop&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;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 render the component&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;wrapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Shop&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="nx"&gt;products&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;wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;toMatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/Our products/&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;With a test like this, it's super easy to get high coverage. However, this test doesn't test anything related on how the product itself is rendered.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code coverage doesn't give any indication of what is actually tested.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Reason #2: Dev focus on coverage instead of confidence
&lt;/h2&gt;

&lt;p&gt;If I continue with the shop example. We still have one test that tests almost nothing (but covers a lot!).&lt;br&gt;
When I get the code coverage report, it says that one scenario is not tested: when one product is available.&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="nf"&gt;getPageTitle&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Our product&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Our products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;According to you, what is the next step now?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a test to cover this untested function? (with a low impact)&lt;/li&gt;
&lt;li&gt;or reinforce tests on parts that are already covered but not tested? (with a high impact)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are in a company with a xx% code coverage requirement, you will be more inclined to "cover" code to bump the score.&lt;/p&gt;

&lt;p&gt;We were supposed to &lt;strong&gt;write tests for confidence&lt;/strong&gt;. Confidence to ship code that works as expected. And we ends up writing tests for metrics. A nonsense!&lt;/p&gt;

&lt;p&gt;Also, if you have a xx% code coverage policy, it means you're expecting the same level of test across the whole application. &lt;strong&gt;Do you think that a hidden settings page and a main feature deserves the same attention?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Reason #3: High code coverage !== high quality of tests
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;"When a measure becomes a target, it ceases to be a good measure"&lt;br&gt;&lt;br&gt;
－ Goodhart's law&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In one of my previous experiences, I was granted as a tech lead. I thought it could be a good idea to set a 100% code coverage policy. I thought it was something good to enforce the code quality. I was pretty proud to have a 100%cc and keep it over the time. And one day I got disillusioned when I went through the code base.&lt;/p&gt;

&lt;p&gt;Some dev didn't write code for confidence but to make the CI build green. As we saw before, if you understand how code coverage works, it's super easy to trump this metric.&lt;/p&gt;

&lt;p&gt;Here are a few example of low quality tests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a dev couldn't test an &lt;code&gt;if&lt;/code&gt; statement. So he updated the code to trump the coverage and get the 100%.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;myFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;something&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unitTest&lt;/span&gt; &lt;span class="o"&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="c1"&gt;// code&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;weirdAndHardToTestCondition&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;unitTest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// code&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;whatever&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;ul&gt;
&lt;li&gt;
&lt;a href="https://dev.to/10-tips-write-better-tests#8---avoid-implementation-detail"&gt;implementation detail&lt;/a&gt; a.k.a. tests that result with false positives and false negatives. You have a lot of them when you search for react/vue components on GitHub;&lt;/li&gt;
&lt;li&gt;reducing code legibility when code cannot be tested. Less lines of code === less uncovered percentage. You can also write more verbose code on the covered part to gain even more percent.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="c1"&gt;// given generatePdf() is hard to test...&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&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;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&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;lastname&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.pdf`&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;formatData&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;data&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;PDF&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generatePdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// now become&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PDF&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generatePdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&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;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&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;lastname&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.pdf`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;formatData&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;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;and the cherry on top: a developper extended the testing framework to test private methods. That spicy one was in PHP (with the reflection method).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Not all code need to be tested
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzghyjoq7q5ix1lci6fop.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzghyjoq7q5ix1lci6fop.png" alt="code coverage evolution vs effort"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before giving my &lt;a href="https://dev.to/speaking/#talks"&gt;talk about Frontend Testing&lt;/a&gt;, I asked developers why they don't test. Without any surprises, most of them told me: &lt;em&gt;"we don't have time to test"&lt;/em&gt;. When I asked my maker friends, I heard the same song.&lt;/p&gt;

&lt;p&gt;Writing tests cost time. Therefore money.&lt;/p&gt;

&lt;p&gt;Sometimes the amount of time invested on writing tests does not pay off. Because of the time consuming aspect or because devs are flooded by too many tests.&lt;/p&gt;

&lt;p&gt;That's more or less what Kent C. Dodds explains in his famous post &lt;a href="https://kentcdodds.com/blog/write-tests" rel="noopener noreferrer"&gt;Write tests. Not too many. Mostly integration.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up: should we throw out the baby with the bathwater?
&lt;/h2&gt;

&lt;p&gt;Of course not :)&lt;/p&gt;

&lt;p&gt;Sometimes, &lt;em&gt;but not always&lt;/em&gt;, Code Coverage can help to highlight untested parts of an application. But it's just a metric. So please, use it as a metric, as a tool to help you to take the right decision. Not the opposite!&lt;/p&gt;




&lt;p&gt;Thanks for reading this article 🤘. I hope you found it useful! If you liked it, please give it a ❤️ or a 🦄! Feel free to comment or ask questions in the section below or on &lt;a href="https://twitter.com/_maxpou" rel="noopener noreferrer"&gt;Twitter (@_maxpou)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.maxpou.fr/https://www.maxpou.fr/code-coverage" rel="noopener noreferrer"&gt;maxpou.fr&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>javascript</category>
    </item>
    <item>
      <title>10 Tips for Working From Home</title>
      <dc:creator>Maxence Poutord</dc:creator>
      <pubDate>Sun, 15 Mar 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/maxpou/10-tips-for-working-from-home-1nmd</link>
      <guid>https://dev.to/maxpou/10-tips-for-working-from-home-1nmd</guid>
      <description>&lt;p&gt;Because of the Coronavirus, a lot of people are going to experiment with the “home office”. Working From Home can be great but it can also be terrible if you don’t follow the right habits from the start.&lt;/p&gt;

&lt;p&gt;I’m working 100% remotely since October 2018. Here are my tips to avoid the most common pitfalls and make it a success :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Workspace
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. 🛌 NEVER work from your bed.
&lt;/h3&gt;

&lt;p&gt;I know how comfy and warm a bed can be. This is not a reason to work from it. If you start to establish a mental association between your sleep and your work, the quality of your sleep will decrease. Also, you’ll start to think more and more about work when you are in your bed.&lt;/p&gt;

&lt;p&gt;For the reasons mentioned above, also avoid working from your bedroom. Instead, you can use a spare room. If you don’t have one, you can create an "office corner" in the kitchen.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. 🪑 Find the best workspace
&lt;/h3&gt;

&lt;p&gt;Working from the couch or a long/armchair can be ok for a meeting or a 1,5h working session. It’s not viable for more. Otherwise, you will end up with &lt;a href="https://en.wikipedia.org/wiki/Repetitive_strain_injury"&gt;RSI&lt;/a&gt;/back pain/etc. The strict minimum to have a decent working session is a table, a chair and some natural light. I also found myself better with a laptop stand + external keyboard&amp;amp;trackpad. Also, don’t neglect the decoration. Add plants!&lt;/p&gt;

&lt;p&gt;If you want some inspiration, &lt;a href="https://www.maxpou.fr/uses"&gt;here's my setup&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; if the virus spread were not a thing, I’d recommend you to find some cafe to work from. Having a group of people to work with once a week is also super cool.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. 📲 Reduce distractions
&lt;/h3&gt;

&lt;p&gt;When no one is watching you, it might be tempting to waste your time on your phone, social media...&lt;/p&gt;

&lt;p&gt;Here are some counterspells:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;put your phone in silent mode (or Do Not Disturb mode);&lt;/li&gt;
&lt;li&gt;install a blocker and disallow social media from 9 am to 5 pm;&lt;/li&gt;
&lt;li&gt;schedule deep work sessions and turn off slack. When I was in Asia (7-8H ahead of my coworkers), I used to do 90% of my day job in the morning. If you wonder how, the answer is simple: nobody was connected. This tool can be good for communication but it’s a productivity annihilator.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; your boss might expect you to keep the same level of productivity while working remotely. To be brief: it’s impossible. You’re going to introduce a wholesale change in the way you and your teamwork, your productivity will be impacted. Plus some people also have to manage kids, anxiety...&lt;/p&gt;

&lt;h2&gt;
  
  
  Work
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4. ✋ Know when to stop
&lt;/h3&gt;

&lt;p&gt;Sometimes we have close to zero output of our workday. As a software engineer, I often work all day on a bug and solution results in a one-line fix. You feel a bit guilty but it's ok to do so. Because in an office, &lt;em&gt;people see you working&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It does not have to be different when you're working remotely&lt;/strong&gt;. You don't have to work more just because you think you should have done more. Have some rest, you will do better tomorrow! 💪&lt;/p&gt;

&lt;p&gt;When you work in an office, you see people leaving the office in the evening and you don't really see them when you're remote. If you can unplug, you can set an alarm.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. 🗣 Overcommunicate and be transparent on your activities
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Between what I think, what I want to say, what I believe I say, what I say, what you want to hear, what you believe to hear, what you hear, what you want to understand, what you think you understand, what you understand...They are ten possibilities that we might have some problem communicating. But let's try anyway...&lt;br&gt;&lt;br&gt;
— Bernard Werber&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you work remotely, the chances of having a tunnel effect are increased. When I'm working on big features, I always share screenshot/video capture (super easy with &lt;a href="https://giphy.com/apps/giphycapture"&gt;Giphy Capture&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;People can blame you if you don't communicate. But if you overcommunicate, no one will.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. 📽 Turn on your webcam during meetings
&lt;/h3&gt;

&lt;p&gt;Enabling the camera removes a lot of stupid problems like: "is he serious or is he joking?". Also, it makes the conversation more human. What I mean is it can also reduce the feeling of isolation that is present in many remote workers. You may have people by your side, but not everyone have. Maybe your face is the only face your colleague will see today. Think about it.&lt;/p&gt;

&lt;p&gt;Just make sure you don't have a bottle of beer next to you. If you're live on the TV, &lt;a href="https://www.youtube.com/watch?v=Mh4f9AYRCZY&amp;amp;feature=emb_title"&gt;put the kid away&lt;/a&gt; ;)&lt;/p&gt;

&lt;h3&gt;
  
  
  7. ☑️ Have a checklist of things to do
&lt;/h3&gt;

&lt;p&gt;Balancing time is hard. You can write down your MITs (Most Important Things). It's a mix between a daily log and a todo list.&lt;/p&gt;

&lt;p&gt;MIT helped me a lot to organise my workday and also tell my manager what I've done over the last week. I've to admit that I haven't used it for a long time.&lt;/p&gt;

&lt;p&gt;If you find it hard to manage your priorities, you can use the Eisenhower Matrix. It's my go-to tool when it comes to priorities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Life
&lt;/h2&gt;

&lt;h3&gt;
  
  
  8. 🍛 Get a proper lunch break
&lt;/h3&gt;

&lt;p&gt;What I mean here is: &lt;strong&gt;don't eat in front of your work&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Even if you're home, don't hesitate to physically move during your break. Like changing rooms, going on the sofa... the idea is to create distance between you and your work. So you know you're on a break. Not 50% working / 50% resting.&lt;/p&gt;

&lt;p&gt;Also, don't hesitate to take a five-minute break to step away from your laptop. You will come back happier and more productive.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. 🍃 Take care of yourself
&lt;/h3&gt;

&lt;p&gt;This one might sound stupid but some people slowly forget some basics things in life like having a shower, eating healthy, doing exercise...&lt;/p&gt;

&lt;p&gt;We're not (yet) in a post-apocalyptic world. Life can't be resumed to sleep-work-eat-work-netflix-sleep. Repeat.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. ⏰ Establish a routine
&lt;/h3&gt;

&lt;p&gt;Home office removes time to commute. You don’t owe this time to your boss. No, it’s yours! Take leverage of this gain for yourself. Establishing a routine is a good way to slowly start and end your day. There are thousands of things to do! Cooking, reading, walking the dog, yoga, meditation...&lt;/p&gt;

&lt;p&gt;Here's mine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;07:15am wake up (after 8h sleep)&lt;/li&gt;
&lt;li&gt;07:35am catch-up on Twitter + Mail/Telegram/WhatsApp groups&lt;/li&gt;
&lt;li&gt;07:45am do some push-up + get ready&lt;/li&gt;
&lt;li&gt;08:00am prepare breakfast (avo toast/fruit salads 👨‍🍳) + drink my coffee + watch video/read a blog post&lt;/li&gt;
&lt;li&gt;08:30am start working&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;When I need more sleep, I start later. I never start working without having some time for me first.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Create your routing with your needs. It doesn't have to be outstanding. Make it simple and be consistent.&lt;/p&gt;




&lt;p&gt;And you, what's your best advice for working from home?&lt;/p&gt;




&lt;p&gt;Thanks for reading this article 🤘. I hope you found it useful! If you liked it, please give it a ❤️ or a 🦄! Feel free to comment or ask questions in the section below or on &lt;a href="https://twitter.com/_maxpou"&gt;Twitter (@_maxpou)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.maxpou.fr/10-tips-for-working-from-home"&gt;maxpou.fr&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>remote</category>
    </item>
    <item>
      <title>10 Tips For Writing Better Tests</title>
      <dc:creator>Maxence Poutord</dc:creator>
      <pubDate>Tue, 04 Feb 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/maxpou/10-tips-for-writing-better-tests-95j</link>
      <guid>https://dev.to/maxpou/10-tips-for-writing-better-tests-95j</guid>
      <description>&lt;h2&gt;
  
  
  #1 - Think documentation
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Your company wiki can be outdated. Tests can't.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Everybody wants good and well-written documentation. Unfortunately, it's hard to keep it up to date.I believe tests can replace, somehow, a part of the documentation. Tests provide a good description of how your application should behave.&lt;/p&gt;

&lt;p&gt;Let me show you an example I could write:&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;// Shop.spec.js&lt;/span&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 show list of product&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="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&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 hide non-available products&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="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&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 display a discount label when available&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="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&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 paginate when &amp;gt; 10 products&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="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just by reading the name of the name of the file and the 4 descriptions, I already know what is this functionality and some business rules.&lt;/p&gt;

&lt;p&gt;Also, if the &lt;em&gt;"should hide non-available products"&lt;/em&gt; test breaks, I know exactly where to start my investigations.&lt;/p&gt;

&lt;h2&gt;
  
  
  #2 - Isolate your tests
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fukrqvhzg34dgknl1yfpv.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fukrqvhzg34dgknl1yfpv.gif" alt="side effects"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To better organise your test file, you can group related assertions under the same test (= the same &lt;code&gt;it()&lt;/code&gt;/&lt;code&gt;test()&lt;/code&gt;). Try to keep your reasonably small. Smaller tests are &lt;strong&gt;easier to understand and easier to maintain&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Sometimes, we need to test a full process. Like a payment flow where you have a few different steps &lt;em&gt;(i.e. payment info &amp;gt; user address &amp;gt; confirmation)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If you hesitate between creating one big test vs one test per step, where "step 2" depends on "step 1", go for the first option. It's OK to have some longer tests.&lt;/p&gt;

&lt;p&gt;Sharing a state between tests is a bad idea. They're hard to debug and soon or later, you will face weird issues caused by side effects. &lt;strong&gt;Always keep your tests isolated&lt;/strong&gt;. Tests should not depend on each other.&lt;/p&gt;

&lt;h2&gt;
  
  
  #3 - Keep it flat
&lt;/h2&gt;

&lt;p&gt;I tend not to write any condition (if/else/...) in my tests. If your test has an if condition, maybe you are testing 2 different things. Which means, your test may have too many responsibilities.&lt;/p&gt;

&lt;p&gt;Remember the S of SOLID (S = Single-responsibility Principle). If it makes the coffee, toast your bread and fetch the forecast... there might be something wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  #4 - Only mock what you can't control
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Every time we mock, we diverge from the real world scenario.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For this reason, you should avoid them as much as possible. But, sometimes we have no other option but to use it. Here are the only exceptions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;for external API calls (HTTP GET/POST/...);&lt;/li&gt;
&lt;li&gt;for browsers API (local/session storage, navigator...);&lt;/li&gt;
&lt;li&gt;... and time-based stuff (&lt;a href="//./jest-mock-date"&gt;date&lt;/a&gt;, random methods...).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Talking about time, if you're testing a timer, don't block the pipeline for the x seconds required by the timer. Mock the clock!&lt;/p&gt;

&lt;h2&gt;
  
  
  #5 - Avoid assertion in loops (forEach/...)
&lt;/h2&gt;

&lt;p&gt;A common error is to test a list in a loop.&lt;/p&gt;

&lt;p&gt;Example: I want to test a page that loads 30 items.&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fakeDataProducts&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../fixtures&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&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 shows list of product&lt;/span&gt;&lt;span class="dl"&gt;'&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;wrapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ProductList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;fakeDataProducts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&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;wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBeInTheDocument&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;What's wrong here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Too many assertions&lt;/strong&gt; : multiple assertions can potentially slow down the execution of the test suite.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-valuable tests&lt;/strong&gt; : asserting the presence of one item can be a good idea. But, testing the presence of each item doesn't seem to add much value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Exception&lt;/strong&gt; : When each element of the array represents a different use case.&lt;/p&gt;

&lt;h2&gt;
  
  
  #6 - Test your app in the same way as a user will use it
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The more your tests resemble the way your software is used, the more confidence they can give you.&lt;br&gt;&lt;br&gt;
— Kent C. Dodds&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let say you want to login on your favourite social network. You fill your username and your password. And after that: do you search in the DOM for the button with &lt;code&gt;id="login-form-btn"&lt;/code&gt;? or do you click on the button called "Log In"? Why do you test differently?&lt;/p&gt;

&lt;p&gt;If the keyword "Log In" is already present on the page, you can query your item with accessibility attribute &lt;em&gt;(i.e. &lt;code&gt;aria-label&lt;/code&gt;, ...)&lt;/em&gt;. In this way, you will enforce your component accessibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  #7 - Favour integration tests
&lt;/h2&gt;

&lt;p&gt;You probably read Martin Fowler's blog talking about the &lt;a href="https://martinfowler.com/bliki/TestPyramid.html" rel="noopener noreferrer"&gt;Testing Pyramid&lt;/a&gt;. In a nutshell, this blog said: write a lot of unit tests (fast and cheap), some integration tests and a few end-to-end tests (slow and expensive).&lt;/p&gt;

&lt;p&gt;But, this post was written in 2012. 8 years ago! I believe we play a different game today with different rules too.&lt;/p&gt;

&lt;p&gt;Unit testing a Redux/Vuex store gives me zero confidence. I've done it in the past. Many times... but, the number of bugs haven't changed. Why? Because bugs and regressions are generally not in small pieces of code.We found them at a higher level.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjzl2i3hg33egivownpif.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjzl2i3hg33egivownpif.gif" alt="integration tests"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;(Unit vs. Integration tests)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Integration tests are more expensive than unit tests. But, it's worth the trouble.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  #8 - Avoid implementation detail
&lt;/h2&gt;

&lt;p&gt;Let's say you want to test a "like button". You might be tempted to do something 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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wrapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LikeButton&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;wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Like&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;simulate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&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;wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;state&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;liked&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;What's wrong here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;False positives:&lt;/strong&gt; (aka &lt;em&gt;false alarm&lt;/em&gt;) It looks like an error but it's not.
Let say, you want to refactor the component. By refactoring, I mean changing the implementation, not in the behaviour or the contract (props, events...). Otherwise, it's not a refactor.
If you rename &lt;code&gt;liked&lt;/code&gt; to &lt;code&gt;isLiked&lt;/code&gt;, the test will fail. And it should not. We write tests to fail when something goes wrong. Nobody cares about a variable name! But, it's a different story when it comes to behaviour. Only test what matters!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;False negatives:&lt;/strong&gt; (test pass but it shouldn't)
Instead of verifying the output, we check the internals. We can't be sure the output still works as expected.This scenario can happen because we did not test the app in the same way as your final user will. In other words, our users and other devs who are going to use this component don't really care about the magic inside the component.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To avoid implementation detail, &lt;strong&gt;treat your component as a black box:&lt;/strong&gt; only test the inputs and the outputs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwmoxqiqahtu21rjk0536.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwmoxqiqahtu21rjk0536.png" alt="component black box"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The same test, without implementation detail could be:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spy&lt;/span&gt; &lt;span class="o"&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;fn&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;wrapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LikeButton&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;spy&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;)
&lt;/span&gt;&lt;span class="nx"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Like&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;simulate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&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;wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aria-label&lt;/span&gt;&lt;span class="dl"&gt;'&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;liked&lt;/span&gt;&lt;span class="dl"&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;spy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;calls&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;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #9 - Always green
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F902x3913keg7dcxsmpqb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F902x3913keg7dcxsmpqb.jpg" alt="Bender kill all human"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I remember when I joined a company a few years ago. On Day One, I couldn't start the application. After investigations, it turns out someone had forgotten a &lt;code&gt;;&lt;/code&gt; in a SQL file and pushed it to master. The application was broken because of a god damn semicolon. With basic tooling, those kinds of problems should never happen.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you ask a dev to run the run manually the test before opening a pull request, it's not gonna work. Humans are fallible. Plus, this is a dumb job. Better delegate this job to a robot, they are cheap and never lie. Automated jobs will ensure your tests are always green.&lt;/p&gt;

&lt;p&gt;Because I don't even trust myself, all of my side projects have CI enabled by default. The only way for me to merge my own code is &lt;a href="https://github.com/maxpou/gatsby-starter-morning-dew/pulls?q=is%3Apr+is%3Aclosed" rel="noopener noreferrer"&gt;to open a pull request and get a green build&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  #10 - Write tests for confidence, not for metrics
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;"When a measure becomes a target, it ceases to be a good measure"&lt;br&gt;&lt;br&gt;
－ Goodhart's law&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I see a lot of people writing &lt;em&gt;Coverage-Driven Test™️&lt;/em&gt;. Because their manager asked to, or because they want to show off with a "100% code coverage" on the GitHub repository.&lt;/p&gt;

&lt;p&gt;In my opinion, this is a really bad idea. And for a few reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code covered does not necessarily mean code tested;&lt;/li&gt;
&lt;li&gt;High code coverage gives the &lt;strong&gt;illusion of quality&lt;/strong&gt;. But, you can have a high percentage with irrelevant tests that does nothing except bumping the score (cf. implementation detail);&lt;/li&gt;
&lt;li&gt;Dev doesn't write tests for being confident but to satisfy a metric.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This last point is very important. By taking the problem on the wrong side, we forgot why we write tests.We should all write tests for &lt;strong&gt;confidence&lt;/strong&gt;. Confidence for shipping code that works as described and also confidence that the behaviour will remain unchanged 6 months later when you or a colleague will work on this part of the application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not all code needs tests.&lt;/strong&gt; Expecting the same amount of test in your App hidden settings and in the payment page is absolute nonsense. Writing tests is an investment. If tests don't provide any visible ROI (Return On Investment), skip them. Except, if you're working on a library (open source or not).&lt;/p&gt;




&lt;p&gt;And you, what's your golden rule for testing?&lt;/p&gt;




&lt;p&gt;Thanks for reading this article 🤘. I hope you found it useful! If you liked it, please give it a ❤️ or a 🦄! Feel free to comment or ask questions in the section below or on &lt;a href="https://twitter.com/_maxpou" rel="noopener noreferrer"&gt;Twitter (@_maxpou)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.maxpou.fr/10-tips-write-better-tests" rel="noopener noreferrer"&gt;maxpou.fr&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>beginners</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to generate social share images with Gatsby</title>
      <dc:creator>Maxence Poutord</dc:creator>
      <pubDate>Thu, 23 Jan 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/maxpou/how-to-generate-social-share-images-with-gatsby-2bk9</link>
      <guid>https://dev.to/maxpou/how-to-generate-social-share-images-with-gatsby-2bk9</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;TL;DR: Generating share images can be done in 3 steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;create a preview page;
&lt;/li&gt;
&lt;li&gt;screenshot it (with pupetter);
&lt;/li&gt;
&lt;li&gt;add the image in the page's metatags.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qeHlF_hK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/9l9rlwdat52lj6ze166s.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qeHlF_hK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/9l9rlwdat52lj6ze166s.jpg" alt="3 steps" width="880" height="246"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;When you spend hours writing a blog post, you want it to stand out, not to be lost in a feed. That's why having a social share image attached to your blog post is crucial. People are drawn to visual content. Our brains respond very quick to images in comparison to plain text.&lt;/p&gt;

&lt;p&gt;The idea behind this post is to show you how to generate preview images like this for your Gatsby.js website.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HTYMzYUY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/4ahhdb75d2huutrp1f1v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HTYMzYUY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/4ahhdb75d2huutrp1f1v.png" alt="Preview" width="880" height="656"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Social share images are used by social media (Twitter/Facebook/LinkedIn...) and also some conversational applications (Slack/Telegram/WhatsApp/...).&lt;/p&gt;

&lt;p&gt;Before we start, keep in mind that Gatsby is static website generator. We can't generate image &lt;em&gt;"on the fly"&lt;/em&gt; as we do with other languages (i.e. PHP...).&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: create the preview page
&lt;/h2&gt;

&lt;p&gt;The preview page is meant to be screenshotted and only screenshotted!&lt;/p&gt;

&lt;p&gt;Your blog post page should be generated with something like &lt;code&gt;createPage()&lt;/code&gt;. So, we are going to duplicate this statement to create the preview page.&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;// gatsby-node.js&lt;/span&gt;
&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;posts&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;// create the blog post page&lt;/span&gt;
  &lt;span class="nx"&gt;createPage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frontmatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/templates/blog-post.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frontmatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="c1"&gt;// create the blogpost page preview&lt;/span&gt;
  &lt;span class="nx"&gt;createPage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frontmatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/image_tw`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/templates/blog-post-share-image.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frontmatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&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;💡 &lt;strong&gt;How to disable this page in production?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I guess you don't want to see this page is production right?If you wrap the &lt;code&gt;createPage&lt;/code&gt; in the following "if condition". So, the page will be only accessible with &lt;code&gt;gatsby develop&lt;/code&gt; command.&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gatsby_executing_command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;develop&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="nx"&gt;createPage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="c1"&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;Then, we need to create the &lt;code&gt;blog-post-share-image.js&lt;/code&gt;. In the GraphQL query, fetch fields you want to use (post title, time to read...). And render everything in a rectangle (i.e. 440 x 220 pixels).&lt;/p&gt;

&lt;p&gt;If you want, &lt;a href="https://github.com/maxpou/gatsby-starter-morning-dew/blob/master/src/templates/blog-post-share-image.js"&gt;here's the template I use for maxpou.fr&lt;/a&gt;. Now, use your HTML/CSS skill to make the nicest preview 💪.&lt;/p&gt;

&lt;p&gt;After that, the preview should be accessible at &lt;code&gt;http://localhost:8000/your-article-slug/image_share&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2l_Wn4Ld--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ftp08n7q4a0m43swhxg9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2l_Wn4Ld--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ftp08n7q4a0m43swhxg9.png" alt="building the page" width="880" height="525"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: screenshot the preview
&lt;/h2&gt;

&lt;p&gt;To take a screenshot, I use pupetter. Here's a part of the script I am using to take a screenshot:&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;// scripts/generatePostPreviewImages.js&lt;/span&gt;
&lt;span class="c1"&gt;// full script available here:&lt;/span&gt;
&lt;span class="c1"&gt;// https://github.com/maxpou/gatsby-starter-morning-dew/blob/master/scripts/generatePostPreviewImages.js&lt;/span&gt;

&lt;span class="c1"&gt;// #!/usr/bin/env node&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;puppeteer&lt;/span&gt;&lt;span class="dl"&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;takeScreenshot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;destination&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;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;launch&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;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;screenshot&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;clip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;x&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;span class="na"&gt;y&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;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;440&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;220&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;close&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;main&lt;/span&gt; &lt;span class="o"&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;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getArticleFiles&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;for&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;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&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;destinationFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-share.png`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// (existsSync check if the file already exist)&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;existsSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;destinationFile&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;takeScreenshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/image_share`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;destinationFile&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Created &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;destinationFile&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;...and in the package.json, make the script available as a command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*/&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"generatePostPreviewImages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./scripts/generatePostPreviewImages.js"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;p&gt;We are now ready to create the picture! To generate the preview image, open 2 terminals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Terminal 1: &lt;code&gt;npm run gatsby develop&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Terminal 2: &lt;code&gt;npm run generatePostPreviewImages&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You should have generated some preview images (1 per blog post). The script above put the image directly in the blog post folder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: integrate the picture in the DOM
&lt;/h2&gt;

&lt;p&gt;The social image is now generated. Before you add it in the HTML's body, don't forget to link the image with the blog post.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# ./my-blog-post.md
--------
&lt;/span&gt;title: "How to generate social share images with Gatsby"
slug: generate-social-image-share-with-gatsby
cover: ./cover.png
&lt;span class="gh"&gt;# links preview image&lt;/span&gt;
&lt;span class="gh"&gt;imageShare: ./git-under-the-hood-share.png
--------
&lt;/span&gt;
Your blog post content

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

&lt;/div&gt;



&lt;p&gt;When you render your blog post, you can add the image generated in an SEO component.&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="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;BlogPostTemplate&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;render&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;post&lt;/span&gt; &lt;span class="o"&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Layout&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SEO&lt;/span&gt;
          &lt;span class="nx"&gt;imageShare&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frontmatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;imageShare&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publicURL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="cm"&gt;/* other: title, description, url... */&lt;/span&gt;
        &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Wrapper&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Article&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Wrapper&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Layout&lt;/span&gt;&lt;span class="err"&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;The SEO component purpose is to manage all the meta-information located in the page's &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;.If you don't have this component, you can get some inspiration from the &lt;a href="https://github.com/gatsbyjs/gatsby-starter-blog/blob/master/src/components/seo.js"&gt;Gatsby-starter-blog&lt;/a&gt;. Also, feel free to copy/paste &lt;a href="https://github.com/maxpou/gatsby-starter-morning-dew/blob/master/src/components/SEO.js#L33-L45"&gt;the code I wrote for my website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At the end, you should have something similar in your HTML's body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Open Graph meta tags --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:url"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://www.maxpou.fr/super-cool-blog"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:type"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"article"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"My super-cool blog post | maxpou.fr"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"This is my very cool blog post description!"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://www.maxpou.fr/path/to/image/generated.png"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Twitter Card Tags --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:card"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"summary_large_image"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:creator"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"_maxpou"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"My super-cool blog post | gatsby-starter-morning-dew"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"This is my very cool blog post description!"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://www.maxpou.fr/path/to/image/generated.png"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;and... tadaa it should works 🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If you want to check your metatags, you can use &lt;a href="https://cards-dev.twitter.com/validator"&gt;Twitter cards Validator&lt;/a&gt;. To test the Open Graph tags, I usually send a message to myself on Slack.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PpAq1AcT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0ryeqihrhc632yj3na2q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PpAq1AcT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0ryeqihrhc632yj3na2q.png" alt="Twitter Card Validator" width="880" height="506"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;That's it for today! I hope this post will help you to generate your social images share. I copied all examples from my Gatsby starter/theme: &lt;a href="https://github.com/maxpou/gatsby-starter-morning-dew"&gt;gatsby-starter-morning-dew&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Thank you for taking the time to read this post. I hope you found it useful! If you liked it, please give it a ❤️ or a 🦄! Feel free to comment or ask questions in the section below or on &lt;a href="https://twitter.com/_maxpou"&gt;Twitter (@_maxpou)&lt;/a&gt; :)&lt;/p&gt;




&lt;p&gt;Originally published on &lt;a href="https://www.maxpou.fr/generate-social-image-share-with-gatsby"&gt;maxpou.fr&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>gatsby</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Git: Cheat Sheet (advanced)</title>
      <dc:creator>Maxence Poutord</dc:creator>
      <pubDate>Mon, 02 Dec 2019 10:00:02 +0000</pubDate>
      <link>https://dev.to/maxpou/git-cheat-sheet-advanced-3a17</link>
      <guid>https://dev.to/maxpou/git-cheat-sheet-advanced-3a17</guid>
      <description>&lt;p&gt;If you find git confusing, I created this little cheat sheet! Please, note that I voluntary skipped the basic commands like &lt;code&gt;git commit&lt;/code&gt;, &lt;code&gt;git pull/push&lt;/code&gt;... This cheat sheet is intended for an "advanced" usage of git.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ffgviyzh10boel5s7rwfb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ffgviyzh10boel5s7rwfb.png" alt="Git Cheat Sheet"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🧭 Navigation - Go to the previous branch
&lt;/h2&gt;



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

&lt;/div&gt;

&lt;h2&gt;
  
  
  🔍 Get the history
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Log in one line&lt;/span&gt;
git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;

&lt;span class="c"&gt;# Retrieve all commits by message&lt;/span&gt;
&lt;span class="c"&gt;# Here all commit that contain 'homepage'&lt;/span&gt;
git log &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="nt"&gt;--grep&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'homepage'&lt;/span&gt;

&lt;span class="c"&gt;# Retrieve all commit by author&lt;/span&gt;
git log &lt;span class="nt"&gt;--author&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Maxence"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  🙈Ooops #1: I reseted an unwanted commit. How to rollback?
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Get everything you did&lt;/span&gt;
git reflog

&lt;span class="c"&gt;# then reset to the desired commit (i.e. HEAD@{4})&lt;/span&gt;
git reset HEAD@&lt;span class="o"&gt;{&lt;/span&gt;4&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;# ...or...&lt;/span&gt;
git reset &lt;span class="nt"&gt;--hard&lt;/span&gt; &amp;lt;commit-sha1&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For more detail about this command, I wrote this post.&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/maxpou" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F30845%2Fc293f1bd-64f3-4923-9437-94cd58cb2e71.jpeg" alt="maxpou"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/maxpou/what-s-happens-when-you-git-commit-59n7" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;What's happens when you `git commit`&lt;/h2&gt;
      &lt;h3&gt;Maxence Poutord ・ Oct 16 '19&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#git&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#tutorial&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#beginners&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  🤦‍♀️Ooops #2: I mixed-up with my local repo. How to clean it?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git fetch origin
git checkout master
git reset &lt;span class="nt"&gt;--hard&lt;/span&gt; origin/master
&lt;span class="c"&gt;# You're now up-to-date with master!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🕵🏻‍♂️Difference between my branch and &lt;code&gt;master&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git diff master..my-branch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ✔ Custom commits
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Edit last commit&lt;/span&gt;
git commit &lt;span class="nt"&gt;--amend&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"A better message"&lt;/span&gt;

&lt;span class="c"&gt;# Add something to the last commit without writing message again&lt;/span&gt;
git add &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit &lt;span class="nt"&gt;--amend&lt;/span&gt; &lt;span class="nt"&gt;--no-edit&lt;/span&gt;

&lt;span class="c"&gt;# empty commit - can be useful to re-trigger CI build...&lt;/span&gt;
git commit &lt;span class="nt"&gt;--allow-empty&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"chore: re-trigger build"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;If you don't know what to put in your commit messages, I wrote &lt;a href="https://www.maxpou.fr/git-conventional-commits" rel="noopener noreferrer"&gt;a post about conventional commits&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ♻️ Squash commits
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Let say I want to rebase the last 3 commits:&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;git rebase -i HEAD~3&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Leave the first "pick" and replace the rest by "&lt;code&gt;squash&lt;/code&gt;" (or "&lt;code&gt;s&lt;/code&gt;")&lt;/li&gt;
&lt;li&gt;Tidy up the commit message and save (&lt;code&gt;:wq&lt;/code&gt; in vi).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Waa9A_h4eHI"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  🎯Fixup
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Let say I want to add something in the commit &lt;code&gt;fed14a4c&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fmok5hzy5nx9gb0p4fjhr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fmok5hzy5nx9gb0p4fjhr.png" alt="git commit --fixup"&gt;&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;git add &lt;span class="nb"&gt;.&lt;/span&gt;

git commit &lt;span class="nt"&gt;--fixup&lt;/span&gt; HEAD~1
&lt;span class="c"&gt;# or replace HEAD~1 by the commit hash (fed14a4c)&lt;/span&gt;

git rebase &lt;span class="nt"&gt;-i&lt;/span&gt; HEAD~3 &lt;span class="nt"&gt;--autosquash&lt;/span&gt;
&lt;span class="c"&gt;# save&amp;amp;quit the file (:wq in VI)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🕹Execute command on each commit when rebasing
&lt;/h2&gt;

&lt;p&gt;For massives features, you might end up with a branch with a few commits inside. And then tests are failing and you want to identify the "guilty commit". You can use &lt;code&gt;rebase --exec&lt;/code&gt; to execute a command on each commit of the history.&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="c"&gt;# Will run "npm test" command on the last 3 commit ❤️&lt;/span&gt;
git rebase HEAD~3 &lt;span class="nt"&gt;--exec&lt;/span&gt; &lt;span class="s2"&gt;"npm run test"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F00dbu0n42i9mj3p1i67l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F00dbu0n42i9mj3p1i67l.png" alt="rebase --exec"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🦋Stash
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Because it's not all about &lt;code&gt;git stash&lt;/code&gt; and &lt;code&gt;git stash pop&lt;/code&gt;&lt;/em&gt; ;)&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="c"&gt;# save all tracked files&lt;/span&gt;
git stash save &lt;span class="s2"&gt;"your message"&lt;/span&gt;

&lt;span class="c"&gt;# list your stashes&lt;/span&gt;
git stash list

&lt;span class="c"&gt;# retrieve stash and delete&lt;/span&gt;
git stash apply stash@&lt;span class="o"&gt;{&lt;/span&gt;1&lt;span class="o"&gt;}&lt;/span&gt;
git stash drop stash@&lt;span class="o"&gt;{&lt;/span&gt;1&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;# ... or in 1 command&lt;/span&gt;
git stash pop stash@&lt;span class="o"&gt;{&lt;/span&gt;1&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🗑 Clean
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# remove branches that no longer exist on remote&lt;/span&gt;
git fetch &lt;span class="nt"&gt;-p&lt;/span&gt;

&lt;span class="c"&gt;# remove all branch that contains "greenkeeper"&lt;/span&gt;
git fetch &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git branch &lt;span class="nt"&gt;--remote&lt;/span&gt; | fgrep greenkeeper | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/^.\{9\}//'&lt;/span&gt; | xargs git push origin &lt;span class="nt"&gt;--delete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🐙 GitHub = &lt;code&gt;Git&lt;/code&gt; + &lt;code&gt;Hub&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;I use &lt;a href="https://github.com/github/hub" rel="noopener noreferrer"&gt;Hub&lt;/a&gt; as a wrapper for git. To enable it you've to set hub as an alias for git (&lt;code&gt;alias git='hub'&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;&lt;span class="c"&gt;# Open browser and go to the repository url (GitHub only)&lt;/span&gt;
git browse
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other commands &lt;a href="https://hub.github.com/hub.1.html" rel="noopener noreferrer"&gt;are available here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🦄 Bonus: my favourite git aliases
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;g&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'git'&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;glog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'git log --oneline --decorate --graph'&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gst&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'git status'&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'git push'&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;ga&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'git add'&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'git commit -v'&lt;/span&gt;

&lt;span class="c"&gt;# 🤘&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;yolo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'git push --force'&lt;/span&gt;

&lt;span class="c"&gt;# useful for daily stand-up&lt;/span&gt;
git-standup&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;AUTHOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;AUTHOR&lt;/span&gt;:&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;git config user.name&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

    &lt;span class="nv"&gt;since&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yesterday
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%u&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; 1 &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nv"&gt;since&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"2 days ago"&lt;/span&gt;
    &lt;span class="k"&gt;fi

    &lt;/span&gt;git log &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="nt"&gt;--since&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$since&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--oneline&lt;/span&gt; &lt;span class="nt"&gt;--author&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AUTHOR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you, what's your favourite git command?&lt;/p&gt;




&lt;p&gt;Thank you for taking the time to read this post. I hope you found it useful! If you liked it, please give it a ❤️ or a 🦄! Also, feel free to comment or ask questions in the section below or on &lt;a href="https://twitter.com/_maxpou" rel="noopener noreferrer"&gt;Twitter @_maxpou&lt;/a&gt; :)&lt;/p&gt;




&lt;p&gt;Originally published on &lt;a href="https://www.maxpou.fr/git-cheat-sheet" rel="noopener noreferrer"&gt;maxpou.fr&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>git</category>
      <category>cheatsheet</category>
    </item>
  </channel>
</rss>
