<?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>Forem: Lucas Bernalte</title>
    <description>The latest articles on Forem by Lucas Bernalte (@lucasbernalte).</description>
    <link>https://forem.com/lucasbernalte</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%2F48403%2F40c3b3e3-cd98-4937-beee-1f4e0a35e34b.jpg</url>
      <title>Forem: Lucas Bernalte</title>
      <link>https://forem.com/lucasbernalte</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/lucasbernalte"/>
    <language>en</language>
    <item>
      <title>Cómo generar thumbnails automáticamente para tu blog con NextJS y Microlink Cards</title>
      <dc:creator>Lucas Bernalte</dc:creator>
      <pubDate>Wed, 06 Oct 2021 06:44:57 +0000</pubDate>
      <link>https://forem.com/lucasbernalte/como-generar-thumbnails-automaticamente-para-tu-blog-con-nextjs-y-microlink-cards-4n67</link>
      <guid>https://forem.com/lucasbernalte/como-generar-thumbnails-automaticamente-para-tu-blog-con-nextjs-y-microlink-cards-4n67</guid>
      <description>&lt;p&gt;Voy a contarte cómo puedes generar thumbnails automáticamente sin tener que diseñar tú mismo una imagen para cada artículo.&lt;br&gt;
Utilizaremos el servicio que nos da Microlink Cards, y esto te servirá si ya tienes un blog con NextJS o con cualquier otro framework.&lt;br&gt;
En este artículo además veremos concretamente su uso con NextJS para generar un thumbnail el que está generado para este artículo:&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%2Flucasbernalte.com%2Fstatic%2Fimages%2Fcomo-generar%2Fthumbnail.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%2Flucasbernalte.com%2Fstatic%2Fimages%2Fcomo-generar%2Fthumbnail.png" alt="Thumbnail generado automáticamente"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Entra en &lt;a href="https://cards.microlink.io/editor" rel="noopener noreferrer"&gt;https://cards.microlink.io/editor&lt;/a&gt;, elige un preset y cambia los parámetros que necesites.&lt;/li&gt;
&lt;li&gt;Asegúrate de tener un &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; configurable en la página de tu artículo.&lt;/li&gt;
&lt;li&gt;Copia la URL desde el editor de Microlink y úsala en tu componente con la meta etiqueta &lt;code&gt;og:image&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Usando el &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; para poner tags correctas para nuestros artículos con NextJS
&lt;/h2&gt;

&lt;p&gt;Si tienes un blog (y sobre todo, presta atención si el blog lo estás desarrollando tú mismo), por cada artículo que escribes deberías tener etiquetas &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt; dentro del &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; de tu HTML.&lt;br&gt;
Esto es necesario para el SEO de tus artículos. Si quieres que te lean, tendrán que poder buscarte en google, y cuanto mejor sea tu SEO mejor posicionado estarás. Esto no es nada nuevo.&lt;br&gt;
Si utilizas NextJS, ellos mismos tienen un componente que puedes utilizar para agregar cabeceras en cada página, de esta forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Head&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/head&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;IndexPage&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;=&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="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"My new title"&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello world!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;IndexPage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;y &lt;a href="https://nextjs.org/docs/api-reference/next/head" rel="noopener noreferrer"&gt;puedes ver más sobre esto en su documentación&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;En mi caso, estoy utilizando otro componente, NextSEO, que hace un poco la vida más fácil si estás haciendo tu blog con NextJS.&lt;br&gt;
Puedes ver en &lt;a href="https://github.com/lucbpz/lucasbernalte.com" rel="noopener noreferrer"&gt;el repositorio de este mismo blog&lt;/a&gt; el uso que hago del mismo. &lt;a href="https://github.com/garmeeh/next-seo" rel="noopener noreferrer"&gt;En el GitHub de NextSEO&lt;/a&gt; verás que tienen bastante documentación con muchos ejemplos dependiendo del tipo de contenido. Genial!&lt;/p&gt;

&lt;p&gt;Para que veáis un ejemplo sacado de este blog, el componente ya trae las diferentes props que debemos poner, en lugar de preocuparnos por cómo se llaman las meta etiquetas que debemos poner.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;NextSeo&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; – Lucas Bernalte's blog`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;summary&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;canonical&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;openGraph&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;article&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;article&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;publishedTime&lt;/span&gt;&lt;span class="p"&gt;,&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;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;featuredImage&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fijaros en este componente. Tenemos dentro de &lt;code&gt;openGraph&lt;/code&gt; una propiedad &lt;code&gt;images&lt;/code&gt; que será donde pongamos las imágenes relacionadas (o solo una, que será el thumbnail).&lt;br&gt;
Si usáramos el componente &lt;code&gt;&amp;lt;Head&amp;gt;&lt;/code&gt; que nos da NextJS (el primer ejemplo) tendríamos que poner nuestra propia etiqueta para la imagen relacionada, que sería algo así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;=&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="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://link-to-image.png"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tan solo declarando la propiedad &lt;code&gt;og:image&lt;/code&gt; tendremos un thumbnail para cuando queramos compartir nuestro artículo en redes sociales.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testeando que esto funciona &lt;em&gt;en local&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Una vez que tenemos una página publicada, tenemos herramientas para validar el &lt;strong&gt;Open Graph&lt;/strong&gt; de nuestra página, tanto para Facebook como para Twitter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developers.facebook.com/tools/debug/" rel="noopener noreferrer"&gt;Facebook Sharing Debugger&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cards-dev.twitter.com/validator" rel="noopener noreferrer"&gt;Twitter Card Validator&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;¿Cómo validamos nuestro open graph desde nuestro entorno local?&lt;/p&gt;

&lt;p&gt;Para ello usaremos una extensión de Google Chrome llamada &lt;a href="https://chrome.google.com/webstore/detail/localhost-open-graph-chec/gcbnmkhkglonipggglncobhklaegphgn" rel="noopener noreferrer"&gt;Localhost Open Graph Checker&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Es una herramienta muy simple que al instalarla, nos saldrá el icono en las extensiones de nuestro Chrome. Cuando queramos hacer una validación del open graph, solo tenemos que hacer 2 cosas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Abrir nuestra página en local.&lt;/li&gt;
&lt;li&gt;Pulsar sobre el icono de la extensión.&lt;/li&gt;
&lt;/ol&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%2Flucasbernalte.com%2Fstatic%2Fimages%2Fcomo-generar%2Flocalhost-extension.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%2Flucasbernalte.com%2Fstatic%2Fimages%2Fcomo-generar%2Flocalhost-extension.jpg" alt="Localhost"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;La extensión cogerá nuestro HTML, y copiará el &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; en una página que subirá temporalmente a una URL. Nos abrirá una página nueva en nuestro navegador donde nos saldrá el enlace para poder copiarlo, así como enlaces a los validadores mencionados anteriormente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Microlink Cards como generador de thumbnails
&lt;/h2&gt;

&lt;p&gt;Elegimos usar Microlink Cards para generar las thumbnails &lt;a href="https://twitter.com/zenorocha/status/1442864007799402498" rel="noopener noreferrer"&gt;tras leer este thread de Zeno Rocha&lt;/a&gt;.&lt;br&gt;
Microlink Cards tiene su propio editor, donde puedes elegir un preset y personalizarlo con tus propios parámetros.&lt;/p&gt;

&lt;p&gt;Puedes jugar directamente con los componentes en el editor, pero lo más fácil es directamente cambiar las &lt;code&gt;query variables&lt;/code&gt; que aparecen debajo del editor.&lt;br&gt;
El preset ya viene con unos parámetros configurables que se añaden como query params a la URL para poder generar el thumbnail con el preset elegido y con nuestra propia personalización.&lt;/p&gt;

&lt;p&gt;Veremos que cuando abrimos el editor la URL tiene un formato parecido al siguiente:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cards.microlink.io/editor?preset=dracula" rel="noopener noreferrer"&gt;https://cards.microlink.io/editor?preset=dracula&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Y al cambiar la variable &lt;code&gt;title&lt;/code&gt; a "Nuestro título" dentro de las query variables, la URL de nuestro navegador cambia a:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cards.microlink.io/editor?preset=dracula&amp;amp;title=Nuestro+t%C3%ADtulo" rel="noopener noreferrer"&gt;https://cards.microlink.io/editor?preset=dracula&amp;amp;title=Nuestro+t%C3%ADtulo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si hacemos click en el botón &lt;em&gt;Embed&lt;/em&gt; nos saldrá un popup, donde podremos elegir lo que mejor nos convenga para nuestro blog.&lt;/p&gt;

&lt;p&gt;Si usamos el componente propio de NextJS, podemos elegir la opción &lt;em&gt;SEO tags&lt;/em&gt; que nos dará algo como esto:&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="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;"image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://i.microlink.io/https%3A%2F%2Fcards.microlink.io%2F%3Fpreset%3Ddracula%26title%3DNuestro%2Bt%25C3%25ADtulo"&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;itemprop=&lt;/span&gt;&lt;span class="s"&gt;"image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://i.microlink.io/https%3A%2F%2Fcards.microlink.io%2F%3Fpreset%3Ddracula%26title%3DNuestro%2Bt%25C3%25ADtulo"&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://i.microlink.io/https%3A%2F%2Fcards.microlink.io%2F%3Fpreset%3Ddracula%26title%3DNuestro%2Bt%25C3%25ADtulo"&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://i.microlink.io/https%3A%2F%2Fcards.microlink.io%2F%3Fpreset%3Ddracula%26title%3DNuestro%2Bt%25C3%25ADtulo"&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;Si accedemos a cualquiera de los enlaces que vemos en el &lt;code&gt;content&lt;/code&gt; vemos que se abre una URL donde se acaba mostrando nuestro thumbnail! 🎉🎉🎉&lt;/p&gt;

&lt;p&gt;Si usamos el componente &lt;code&gt;NextSEO&lt;/code&gt;, tendremos que poner ese enlace dentro del apartado de la imagen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;featuredImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`https://i.microlink.io/https%3A%2F%2Fcards.microlink.io%2F%3Fpreset%3Ddracula%26title%3DNuestro%2Bt%25C3%25ADtulo`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;title&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="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;NextSeo&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; – Lucas Bernalte's blog`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;summary&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;canonical&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;openGraph&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;article&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;article&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;publishedTime&lt;/span&gt;&lt;span class="p"&gt;,&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;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;featuredImage&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    // el resto de la página
  &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aunque en realidad queremos que sea dinámico, así que podemos extraer las query variables a un objeto y convertir la URL de la siguiente forma:&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;microLinkCardParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// nuestro título, que lo obtenemos en nuestra página del blog&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;searchParams&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;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;microLinkCardParams&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;featuredImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`https://i.microlink.io/https%3A%2F%2Fcards.microlink.io%2F%3Fpreset%3Ddracula%26&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&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="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// mismo return del ejemplo anterior&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Puedes echar un ojo a &lt;a href="https://github.com/lucbpz/lucasbernalte.com/blob/main/components/BlogSeo.js" rel="noopener noreferrer"&gt;cómo está solucionado en este mismo blog&lt;/a&gt; y el código es prácticamente el mismo.&lt;/p&gt;

&lt;h2&gt;
  
  
  NOTA: qué hacer si Twitter no muestra el thumbnail.
&lt;/h2&gt;

&lt;p&gt;Una vez terminado todo el proceso y haber testeado en local, me ha pasado que el validador de Twitter no estaba pillando el thumbnail correctamente. Sin embargo, todos los parámetros estaban correctos, la URL era correcta y el validador de Facebook lo pillaba correctamente.&lt;br&gt;
Debe de ser algún bug raro. Para comprobar &lt;a href="https://twitter.com/zenorocha/status/1442864007799402498" rel="noopener noreferrer"&gt;cómo lo habían implementado en el hilo que mencionaba anteriormente&lt;/a&gt;, me fui directamente a la web de &lt;a href="https://draculatheme.com/visual-studio-code" rel="noopener noreferrer"&gt;https://draculatheme.com/visual-studio-code&lt;/a&gt; y miré la diferencia en las imágenes.&lt;/p&gt;

&lt;p&gt;El componente NextSEO sólo agrega un item &lt;code&gt;og:image&lt;/code&gt; mientras en esta web están todas las etiquetas que genera automáticamente Microlink Cards. Según la documentación de Twitter, con tener una sola &lt;code&gt;og:image&lt;/code&gt; basta para que detecte el thumbnail, pero en mi caso no estaba funcionando.&lt;/p&gt;

&lt;p&gt;La única diferencia notable en el &lt;code&gt;content&lt;/code&gt; es que la URL a la que estaba apuntando no era la misma. En lugar de apuntar a &lt;code&gt;i.microlink.io&lt;/code&gt;, está apuntando a &lt;code&gt;microlink.vercel.app&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Haciendo este cambio se soluciona el problema! 🎉🎉🎉&lt;/p&gt;

&lt;p&gt;Ya tendríamos thumbnails dinámicos para cada uno de nuestros artículos.&lt;/p&gt;




&lt;p&gt;Si te ha gustado este artículo, puedes ayudarme &lt;a href="https://twitter.com/intent/like?tweet_id=1445645498392752129" rel="noopener noreferrer"&gt;compartiéndolo en Twitter y mencionándome&lt;/a&gt;, o escríbeme un DM sin dudarlo!&lt;/p&gt;

</description>
      <category>react</category>
      <category>nextjs</category>
      <category>beginners</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Por qué usar Testing Library en lugar de Enzyme</title>
      <dc:creator>Lucas Bernalte</dc:creator>
      <pubDate>Tue, 16 Feb 2021 10:12:19 +0000</pubDate>
      <link>https://forem.com/lucasbernalte/por-que-usar-testing-library-en-lugar-de-enzyme-2c2</link>
      <guid>https://forem.com/lucasbernalte/por-que-usar-testing-library-en-lugar-de-enzyme-2c2</guid>
      <description>&lt;p&gt;Original: &lt;a href="https://lucasbernalte.com/blog/por-que-usar-testing-library-en-lugar-de-enzyme" rel="noopener noreferrer"&gt;https://lucasbernalte.com/blog/por-que-usar-testing-library-en-lugar-de-enzyme&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;La librería de testing creada por Kent C. Dodds y mantenida por su comunidad, Testing Library (no podían haber elegido un mejor nombre) ha tenido un tremendo éxito en la comunidad de desarrollo y aun empezando solo con React, ya existen Testing Libraries para Svelte, Vue, Angular, Cypress, etc. Antes de que existiera, los desarrolladores de React utilizaban Enzyme, creada por AirBnB, como su librería de testing.&lt;/p&gt;

&lt;p&gt;En este artículo voy a explicarte qué hacen ambas librerías y por qué elegir Testing Library sobre Enzyme como tu librería de testing en tu stack de desarrollo.&lt;/p&gt;

&lt;h1&gt;
  
  
  Enzyme
&lt;/h1&gt;

&lt;p&gt;Enzyme es una librería de utilidades de Testing para React, que hace fácil la lectura del output de nuestros componentes, teniendo una API intuitiva y flexible.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo renderiza Enzyme un componente?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Shallow rendering: para limitar el test de un componente a su propia unidad, es decir, un nivel de profundidad, sin incluir nada de lo que está por debajo.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&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="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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Title&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Subcomponent&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"info"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&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="c1"&gt;// output de shallow(&amp;lt;MyComponent /&amp;gt;) no renderiza Subcomponent&lt;/span&gt;
&lt;span class="cm"&gt;/*
&amp;lt;div&amp;gt;
    &amp;lt;h1&amp;gt;Title&amp;lt;/h1&amp;gt;
    &amp;lt;Subcomponent type="info" /&amp;gt;
&amp;lt;/div&amp;gt;
*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Full DOM Rendering: Es la única opción de Enzyme que monta el componente, así que tiene que hacerlo en al menos, algo parecido a un browser, como el JSDOM.&lt;/li&gt;
&lt;li&gt;Static Rendering API: Genera HTML a partir del árbol de React de tu componente, para poder analizar la estructura HTML resultante.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ¿Qué podemos comprobar y testear con Enzyme?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Podemos interactuar con los elementos de dentro de nuestro componente como sus props y métodos, incluso hacer que se actualice, de forma imperativa:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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;(&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SomeComponent&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;);&lt;/span&gt;
&lt;span class="nf"&gt;act&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;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;handler&lt;/span&gt;&lt;span class="dl"&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;update&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;Podemos también setear sus props con &lt;code&gt;setProps&lt;/code&gt; o sus estado, con &lt;code&gt;setState&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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;(&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Foo&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"foo"&lt;/span&gt; &lt;span class="p"&gt;/&amp;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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;have&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lengthOf&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="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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;have&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lengthOf&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="nx"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bar&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;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;.foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;have&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lengthOf&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;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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;have&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lengthOf&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Simular algunos eventos.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&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;a&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Desmontar el componente.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unmount&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Testing Library
&lt;/h1&gt;

&lt;p&gt;Testing Library es un set de utilidades de testing simple y completo que promueve las buenas prácticas del testing. Es una ayuda para testear User Interfaces de forma centrada en el usuario.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo renderiza React Testing Library un componente?
&lt;/h2&gt;

&lt;p&gt;Hablamos concretamente de React Testing Library, y no de Testing Library a secas, para hacer la comparación con Enzyme, ya que en otro framework, el renderizado sería diferente. React Testing Library usa el mismo método que usamos para renderizar un componente en nuestra aplicación, &lt;code&gt;ReactDOM.render&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Esto hace que cuando se renderiza un componente en el test, pasa por los mismos ciclos de vida que pasa cuando se renderiza "en la vida real" ya que se hacen de la misma forma.&lt;/p&gt;

&lt;p&gt;React Testing Library te provee de una función &lt;code&gt;render&lt;/code&gt; que hará este renderizado por ti y te devolvera un tipo de dato que contiene queries para hacerle a este componente.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/testing-library/react-testing-library/blob/master/src/pure.js#L63" rel="noopener noreferrer"&gt;Aquí puedes ver dónde se realiza el &lt;code&gt;render&lt;/code&gt; dentro del código de RTL&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué podemos comprobar y testear con Testing Library?
&lt;/h2&gt;

&lt;p&gt;Testing Library tiene como premisa evitar testear implementaciones, así que lo que podemos hacer es interactuar con el DOM o en React, con el JSDOM. Esto implica que podemos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Comprobar que existe un elemento con queries directamente
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.component-class&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;ul&gt;
&lt;li&gt;Lanzar eventos, al igual que se lanzan eventos desde el DOM cuando el usuario interactúa con el componente.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&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;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;button&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;ul&gt;
&lt;li&gt;Comprobar que existe un elemento con las queries recomendadas, para seguir las buenas prácticas, y que las encontramos como respuesta del método render o dentro de un objeto screen, que contiene todo lo que renderizamos en el test. Esto podemos hacerlo de forma síncrona, o asíncrona. El método asíncrono, en realidad internamente, lo intentaría ejecutar varias veces, teniendo un timeout configurable a nivel global o por ejecución.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="p"&gt;/&amp;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;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// síncrono. Lanza error si no existe.&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;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// síncrono. Devuelve null si no existe.&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;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// asíncrono.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Comprobar que un elemento ha dejado de existir en el DOM:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;waitForElementToBeRemoved&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;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;the mummy&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;Para saber qué query utilizar en cada momento, su documentación nos dice cuáles son las más recomendadas: &lt;a href="https://testing-library.com/docs/queries/about#priority" rel="noopener noreferrer"&gt;https://testing-library.com/docs/queries/about#priority&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Si necesitamos debuggear un test porque no sabemos qué se está renderizando y tenemos un árbol demasiado grande, no podremos ver bien el resultado en la terminal y se acabará cortando el árbol. Para ello, han desarrollado una herramienta visual, &lt;a href="https://testing-playground.com/" rel="noopener noreferrer"&gt;Testing Playground&lt;/a&gt; donde podemos visualizar nuestro componente (aunque no tenga los estilos demasiado bien) y ver el árbol completo. Para ello, dentro de nuestro test ponemos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logTestingPlaygroundURL&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;y ya nos saldrá por consola un link que nos llevará a dicha herramienta con nuestro HTML.&lt;/p&gt;

&lt;h1&gt;
  
  
  Por qué la comunidad está migrando a Testing Library
&lt;/h1&gt;

&lt;p&gt;Si comparamos la opción de Testing Library con el "mount" de Enzyme, serían las más similares. ¿Por qué entonces la comunidad está eligiendo una frente a la otra?&lt;/p&gt;

&lt;p&gt;Pues bien, antes de contestar a esta pregunta, es necesario hacerse otra pregunta.&lt;/p&gt;

&lt;p&gt;¿Cuántos usuarios tiene nuestro componente?&lt;/p&gt;

&lt;p&gt;En la mayoría de los casos, un componente tendrá dos usuarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Por un lado, el usuario final, que ve nuestra aplicación e interactúa con él.&lt;/li&gt;
&lt;li&gt;El desarrollador que mantiene el código y puede modificarlo, o reutilizarlo en otro sitio.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cuando agregamos opciones como &lt;code&gt;shallow&lt;/code&gt; rendering, o mocks para testear nuestro componente de forma aislada, estamos creando un tercer usuario de nuestro componente: el test. Esto implica que este test necesitará mantenimiento, estará de alguna medida enlazado con la implementación, y cuando ésta cambie, tendremos que cambiar nuestro test. Nuestro código se vuelve mucho más mantenible cuando sólo tenemos dos usuarios.&lt;/p&gt;

&lt;p&gt;Testing Library directamente no da una opción &lt;code&gt;shallow&lt;/code&gt; precisamente porque &lt;a href="https://www.giffgaff.io/tech/react-test-driven-development/" rel="noopener noreferrer"&gt;su premisa es hacer tests de una forma "Behavior Driven"&lt;/a&gt;.  Esta forma de testear, aunque parece ser "opinionated", es en realidad la forma más efectiva de testear User Interfaces, &lt;a href="https://kentcdodds.com/blog/testing-implementation-details/" rel="noopener noreferrer"&gt;evitando testear implementaciones&lt;/a&gt;. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"We try to only expose methods and utilities that encourage you to write tests that closely resemble how your React components are used."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tanto es así, que pasó a ser la primera librería de testing recomendada en la documentación oficial de React. &lt;/p&gt;

&lt;p&gt;AirBnB, el propio creador de Enzyme, vio el potencial y comenzó su adopción, manteniendo de momento ambas librerías (tenían más de 17000 tests en Enzyme, imposible migrarlo en un commit...). Y &lt;a href="https://www.infoq.com/news/2020/03/airbnb-drops-ownership-enzyme/" rel="noopener noreferrer"&gt;en marzo de 2020 AirBnB anunció que iban a hacer el transfer del ownership de la librería,&lt;/a&gt; aunque pensaban seguir contribuyendo.&lt;/p&gt;

&lt;p&gt;Algunas de los repositorios Open Source más grandes en Github como Storybook o Gatsby ya usan React Testing Library, y algunas como Material UI están desde abril en proceso de migración.&lt;/p&gt;

&lt;p&gt;React va a día de hoy por la v17, y Enzyme, al basarse en la propia implementación de React para poder renderizar, necesita de un "adapter" para funcionar, y todavía no han sacado ninguno oficial para la v17, teniendo que &lt;a href="https://www.npmjs.com/package/@wojtekmaj/enzyme-adapter-react-17" rel="noopener noreferrer"&gt;instalarse un adapter no-oficial&lt;/a&gt; para que pueda funcionar con la última versión.&lt;/p&gt;

&lt;h1&gt;
  
  
  Mi recomendación
&lt;/h1&gt;

&lt;p&gt;Cada librería tiene su contexto, y hay que entender el contexto y la premisa con la que fueron creadas. La adopción de testear comportamientos por parte de la comunidad es muy grande y es la forma de aportar más valor con tus tests. Yo recomiendo elegir Testing Library para evitar caer en la tentación y testear cosas que no deberías, como props que se pasan de un sitio a otro (estarías testeando la propia implementación de React). Además proporciona una API muy buena e intuitiva para comprobar nuestra UI incluso de forma asíncrona, y la comunidad está haciendo un gran trabajo, extrayendo el core de la librería y sacando a utilidades toda su API para que pueda ser utilizada con cualquier framework. Y también están desarrollando &lt;code&gt;user-event&lt;/code&gt; una librería que simula los eventos reales que realizaría un usuario como "click", "doble-click", "escribir", etc. &lt;/p&gt;




&lt;p&gt;Si te ha gustado este artículo, puedes ayudarme dándole visibilidad. &lt;a href="https://twitter.com/lucasbernalte" rel="noopener noreferrer"&gt;Sígueme en Twitter&lt;/a&gt; para estar al tanto del contenido que voy creando.&lt;/p&gt;

&lt;p&gt;🙋‍♂️ Happy Testing!&lt;/p&gt;

</description>
      <category>react</category>
      <category>testing</category>
      <category>frontend</category>
      <category>spanish</category>
    </item>
    <item>
      <title>4 pasos para crear una buena API de componente reusable</title>
      <dc:creator>Lucas Bernalte</dc:creator>
      <pubDate>Tue, 22 Dec 2020 16:43:00 +0000</pubDate>
      <link>https://forem.com/lucasbernalte/4-pasos-para-crear-una-buena-api-de-componente-reusable-3hi8</link>
      <guid>https://forem.com/lucasbernalte/4-pasos-para-crear-una-buena-api-de-componente-reusable-3hi8</guid>
      <description>&lt;p&gt;Original: &lt;a href="https://lucasbernalte.com/blog/4-cosas-a-tener-en-cuenta-al-crear-componentes-reutilizables" rel="noopener noreferrer"&gt;https://lucasbernalte.com/blog/4-cosas-a-tener-en-cuenta-al-crear-componentes-reutilizables&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Creando componentes reusables siempre empiezo dudando de qué API debería tener - en un componente hablamos de entradas y salidas, props que entran y eventos que salen - o en el caso de React, métodos que ejecutan.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Evita estados imposibles&lt;/li&gt;
&lt;li&gt;Deja espacio para la personalización.&lt;/li&gt;
&lt;li&gt;Piensa en la Developer Experience (DX).&lt;/li&gt;
&lt;li&gt;Evita abstracciones innecesarias&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En este caso, el "Too long, didn't read" nos sirve de índice, ya que vamos a desarrollar cada punto por separado.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Evita estados imposibles
&lt;/h2&gt;

&lt;p&gt;Este apartado está fuertemente inspirado en la charla &lt;a href="https://www.youtube.com/watch?v=IcgmSRJHu_8" rel="noopener noreferrer"&gt;"Making Impossible States Impossible" de Richard Feldman.&lt;/a&gt; Básicamente consiste en declarar un modelo de datos que no permite que estados no compatibles colisionen. Si utilizas un lenguaje tipado, te beneficiarás mucho más de esto, pero también podemos hacer esto con JavaScript. &lt;/p&gt;

&lt;p&gt;En &lt;a href="https://kentcdodds.com/blog/make-impossible-states-impossible" rel="noopener noreferrer"&gt;este otro artículo&lt;/a&gt;, Kent C. Dodds lo pone de manifiesto en un ejemplo tal y como lo buscamos, un estado que hemos creado en un componente de React, y que da lugar a posibles estados que no deberían coexistir. &lt;/p&gt;

&lt;p&gt;Si tenemos una notificación que puede ser de tipo "info", "warning" y "error", el componente puede ser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Notification&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;info&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="k"&gt;return&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;así, podríamos usar el componente de diferentes formas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Notification&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"error!"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Notification&lt;/span&gt; &lt;span class="na"&gt;info&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"info!"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sin embargo, estamos dejando al usuario de nuestro componente la posibilidad de utilizarlo mal, colisionando ciertas props sin saber qué va a pasar. ¿Qué pasará cuando el usuario lo utilice así?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Notification&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt; &lt;span class="na"&gt;info&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"mensaje"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto que acabamos de ver es algo a evitar cuando estamos creando un componente reutilizable, y más si lo van a utilizar personas de fuera de nuestro equipo, donde debemos dejar un componente completamente testeado y documentado. Tenemos la opción de crear un test para indicar cuál es el comportamiento correcto en este caso:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&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;when error and info are set&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...&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;O mejor, evitar ese estado, haciendo que "error", "info" y "warning" sean valores de un &lt;code&gt;type&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Notification&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"warning"&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"warning message!"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como dice Richard Fieldman en la charla que mencionábamos&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Testear está bien, pero lo imposible está mejor&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  2. Deja espacio para la personalización
&lt;/h2&gt;

&lt;p&gt;Personalizar los componentes que usamos de alguna librería es algo muy común, ya sea simplemente personalizar los estilos de un componente, o personalizar alguna parte de la interfaz, sustituyendo por ejemplo un texto por un componente propio. &lt;/p&gt;

&lt;p&gt;Este punto es muy abierto y puede sonar poco definido, ya que dependerá del framework que estemos utilizando, bien podemos usar &lt;code&gt;&amp;lt;slot&amp;gt;&lt;/code&gt; si estamos usando WebComponents, o en el caso de React, hacer uso del &lt;code&gt;children&lt;/code&gt; o directamente dejar una prop abierta para el componente a renderizar...&lt;/p&gt;

&lt;p&gt;Lo que debemos saber de este punto es que puede que el usuario de nuestro componente lo utilice tal cual, o por su caso de uso necesite un punto extra de flexibilidad.&lt;/p&gt;

&lt;p&gt;Un ejemplo muy básico sería un componente que renderiza un listado de items. El componente puede renderizar el item como si fuera cualquier cosa, así que podríamos pasar un listado de items que en realidad sería un listado de JSX que renderizará, incluso cada uno puede tener sus &lt;code&gt;onClick&lt;/code&gt; correspondientes, haciendo que un componente del estilo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RenderList&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Message&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;HiddenMessages&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;RenderList&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;acepte en su variable data tanto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messages&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;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;_&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Hello, this is message &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="s2"&gt; here. Cool, huh?`&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messages&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;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;_&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;button &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Evita abstracciones innecesarias
&lt;/h2&gt;

&lt;p&gt;Somos desarrolladores. Buscamos siempre cómo aportar lo máximo con abstracciones para permitir todos los casos de uso posibles. A veces esto nos puede llevar a pensar cosas del estilo: bueno, si hago X, esta feature es gratis, así que por qué no).&lt;/p&gt;

&lt;p&gt;Sin embargo esta abstracción que en teoría hacemos para ahorrar tiempo al usuario y darle lo máximo, a veces puede ser innecesaria e incluso perjudicial, haciendo que sea demasiado compleja para un usuario que está iniciándose con nuestro componente, y en lugar de ayudarle, si no consigue lo que ha venido a hacer, incluso desista y no lo use.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://sandimetz.com/blog/2016/1/20/the-wrong-abstraction" rel="noopener noreferrer"&gt;Duplication is far cheaper than the wrong abstraction&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Siguiendo el patrón que se comenta en esa charla, y tomando como el ejemplo del componente anterior que renderiza una lista, podemos seguir el siguiente proceso mental que nos lleva el desarrollo del mismo:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Desarrollamos componente que permite renderizar una lista de items.&lt;/li&gt;
&lt;li&gt;Creamos la abstracción para que se pueda pasar contenido JSX.&lt;/li&gt;
&lt;li&gt;Hay un nuevo requerimiento, cada item irá con un icono, y la mayoría de las veces será el mismo.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Creamos una abstracción para poder pasar un icono que se repetirá con cada item. Ahora nuestro componente se usaría:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RenderList&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"fa-file"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Message&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;HiddenMessages&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;RenderList&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Esta abstracción nos hace pensar en el tiempo que ahorramos con esa nueva prop.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ahora pensamos qué pasa si queremos diferentes iconos y refactorizamos para poder pasar &lt;code&gt;icons&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RenderList&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;icons&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fa-file&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="s2"&gt;fa-file&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="s2"&gt;fa-danger&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Message&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;HiddenMessages&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;RenderList&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Esto nos ha llevado a una abstracción que parece no ser la mejor a la hora de resolver el problema inicial, ya que el requisito de&lt;br&gt;
renderizar también un icono se podía hacer desde el principio, pasándole al componente una lista de JSX personalizada.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lo que fue una abstracción universal, ahora se comporta diferente para diferentes casos de uso. - Sandi Metz&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Piensa en la Developer eXperience
&lt;/h2&gt;

&lt;p&gt;Crea los componentes para el usuario más importante del mundo - tu "yo del futuro".&lt;/p&gt;

&lt;p&gt;Porque todo lo visto anteriormente no tiene por qué ser para un usuario desconocido - puede ser para tu equipo y/o para ti. Y además de pensar en la API, ten en cuenta que una parte del mantenimiento del software es la documentación y el testing, y con el tiempo nos olvidaremos de cosas si no las dejamos por escrito. Redacta una documentación que no dé lugar a dudas y tests que puedan ser usados como documentación, ya que por la sintaxis podemos hacer que se escriban de forma que describan su comportamiento (además es como se debería testear).&lt;/p&gt;

&lt;p&gt;La idea es tardar lo mínimo en entender cómo funciona el componente.&lt;/p&gt;

&lt;p&gt;Porque la documentación y los tests pueden hacer que "triunfe" nuestro componente, o pueden "romperlo". Cuando un desarrollador está usando tu componente por primera vez, lo primero que hará será leer la documentación. Si tu guía inicial no está clara, puede que pierdas a este usuario. &lt;/p&gt;

&lt;p&gt;Tendemos a enfocarnos mucho en los detalles de implementación y perdemos la visión de los desarrolladores que entran por primera vez y necesitan tener una visión clara de lo que van a usar.&lt;/p&gt;

&lt;p&gt;En definitiva, también es nuestro trabajo asegurar que se han tenido en cuenta las necesidades del desarrollador.&lt;/p&gt;

&lt;p&gt;Piensa en las veces que como desarrollador, cuando buscas un componente has seguido este proceso:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Necesitas X&lt;/li&gt;
&lt;li&gt;Buscas y encuentras una librería que en teoría parece que hace X.&lt;/li&gt;
&lt;li&gt;No consigues el resultado que buscas, y desistes, desinstalando la librería y buscando otra o fabricándola tú mismo.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Conclusiones
&lt;/h2&gt;

&lt;p&gt;Espero que este artículo te ayude a la hora de crear tu siguiente componente dentro de un catálogo o a la hora de crear un componente de forma aislada o incluso para crear un catálogo de componentes completo. Estos criterios son los que tengo como fundamento, aunque hay casos especiales y tampoco hay que tener un plan para seguirlo 100% a la perfección, pero con estos 4 puntos seguro que ves tu componente de otra manera 😊. Buena suerte!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newComponent&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeBetterThan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oldComponent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>beginners</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Decidir qué testear en Frontend</title>
      <dc:creator>Lucas Bernalte</dc:creator>
      <pubDate>Mon, 23 Nov 2020 09:02:07 +0000</pubDate>
      <link>https://forem.com/lucasbernalte/decidir-que-testear-en-frontend-2j9b</link>
      <guid>https://forem.com/lucasbernalte/decidir-que-testear-en-frontend-2j9b</guid>
      <description>&lt;p&gt;Original: &lt;a href="https://lucasbernalte.com/blog/decidir-que-testear-en-front" rel="noopener noreferrer"&gt;https://lucasbernalte.com/blog/decidir-que-testear-en-front&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Mi visión del testing en Frontend
&lt;/h2&gt;

&lt;p&gt;Desde hace un tiempo me he interesado un poco por encima de la media (tras unos cálculos exhaustivos) en el testing, y especialmente en la parte donde he estado trabajando más, en el Front. En mis últimos proyectos he trabajado con React y con Polymer. Si buscas cómo hacer tests con unos y con otros seguramente te salgan cosas muy variadas.&lt;/p&gt;

&lt;p&gt;La realidad es que cualquier framework en Front puede testearse igual.&lt;/p&gt;

&lt;p&gt;La realidad es que cualquier framework en Front debería poder testearse igual (o casi).&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;El conocimiento que se suele encontrar de testing se basa mucho en que aprendas las herramientas, pero no qué testear.&lt;/li&gt;
&lt;li&gt;Muchas veces se tiene un concepto erróneo del testing en front, lo que hace que se pongan esfuerzos en cosas no tan eficaces (&lt;a href="https://twitter.com/lucasbernalte/status/1328609820761583617" rel="noopener noreferrer"&gt;no olvidar cuál el propósito de hacer tests&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Todos los frameworks en Front deberían testearse igual.&lt;/li&gt;
&lt;li&gt;Mira a tu componente a los ojos e identifica visualmente qué deberías testear.&lt;/li&gt;
&lt;li&gt;Pon los esfuerzos donde haya más ratio de cosas testeadas por tiempo invertido, es lo que más valor aportará.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Identifica qué testear
&lt;/h2&gt;

&lt;p&gt;Las primeras búsquedas en google sobre testear componentes de React con Jest te redirigen a algunos enlaces donde te explican el setup de Jest con React y hacer un test. Si especificamos un poco más y buscamos algo del tipo  "what to test" o "qué testear en front" o "cómo saber qué testear en front" tampoco encontramos mucho al respecto.&lt;/p&gt;

&lt;p&gt;Cuando un desarrollador front cambia de framework o de proyecto, el testing no es algo que tendría que reaprender. Si la herramienta usada para testear es diferente, la sintaxis es diferente o hay algo extra que hay que hacer, no pasaría nada, sin embargo ese concepto de saber qué testear en componentes de front no cambia.&lt;/p&gt;

&lt;p&gt;Porque lo ideal es testear el frontend tal y como ves los componentes, con tus propios ojos. En definitiva, tal y como lo vería un usuario de tu aplicación.&lt;/p&gt;




&lt;p&gt;Elige un componente. Crea el típico test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&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;MyComponent&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 correctly&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;Si te lo estás preguntando, los repos más top en Github y de los desarrolladores más top es muy probable que contengan tests con este típico &lt;em&gt;should render correctly&lt;/em&gt; :).&lt;/p&gt;

&lt;p&gt;Pregúntate qué sería necesario definir para que &lt;code&gt;MyComponent&lt;/code&gt; se renderizara correctamente. Para ello, la manera más sencilla sería irnos al browser, encontrarlo dentro de nuestra vista, o dentro de nuestro catálogo e identificar qué nos ha llevado a decir que estaba viéndose correctamente (puede ser que contenga un texto, un icono, un botón, etc).  No tendríamos forma de identificar que tiene una propiedad &lt;code&gt;myProperty&lt;/code&gt; con valor &lt;code&gt;1&lt;/code&gt; , así que no deberíamos poner nuestro foco en testear eso (a lo mejor esto cambiaría si tuviéramos tiempo infinito para testear, pero normalmente no es la realidad).&lt;/p&gt;

&lt;p&gt;Testea qué debería verse (no te centres demasiado en el cómo debería verse si no es muy importante, &lt;a href="https://applitools.com/blog/visual-testing-a-guide-for-front-end-developers/" rel="noopener noreferrer"&gt;no estamos hablando de visual testing&lt;/a&gt;), testea qué debería de pasar cuando el usuario realiza una acción (un click, escribir en un input..) y qué debería de pasar después de esa acción.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pon los esfuerzos en el test que aporte más valor
&lt;/h2&gt;

&lt;p&gt;Es complicado decir un punto donde poner los esfuerzos a la hora de hacer tests de componentes en front - pero no es complicado decir donde NO debemos poner los esfuerzos.&lt;/p&gt;

&lt;p&gt;Hace unos meses di con &lt;a href="https://kentcdodds.com/blog/write-tests" rel="noopener noreferrer"&gt;un artículo que expresa al 100% mi visión sobre el testing&lt;/a&gt; de &lt;a href="https://twitter.com/kentcdodds" rel="noopener noreferrer"&gt;Kent C. Dodds&lt;/a&gt; que hace un análisis de una frase del CEO de Vercel, nada más y nada menos. Lo más interesante del artículo es como pone a prueba la clásica pirámide de testing para comentar que esa pirámide no es la ideal si no dejamos de lado el propósito de hacer tests en el front: &lt;strong&gt;si hay algo mal en el código, debería estar fallando algún test.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Si ponemos los esfuerzos en hacer tests unitarios de todo, aislando cada pequeña parte que tengamos fuera del contexto, tendríamos que hacer muchos tests para comprobar una pequeña funcionalidad. Sin embargo, con un solo test de integración cubrimos mucho más que con varios tests unitarios, lo que nos proporciona un buen mecanismo para empezar a meterle tests a un componente, e incluso para entender cómo funciona un componente que no tiene tests. Se introduce un concepto nuevo, el de "Test de Integración" pero no hay que confundirlos con los tests de integración de Backend. Estos tests en el front se parecen mucho más a los tests unitarios que a otra cosa - simplemente la unidad pasa a ser un componente contenedor de otros componentes.&lt;/p&gt;

&lt;p&gt;Un ejemplo de qué puede pasar si sólo tenemos tiempo para hacer un test y hemos hecho un test unitario:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/erinfranmc/status/1148986961207730176?s=20" rel="noopener noreferrer"&gt;https://twitter.com/erinfranmc/status/1148986961207730176&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Un Test de integración en Front se parece mucho a un Test unitario. Solamente cambia la unidad, que pasa a ser un componente contenedor de otros componentes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://kentcdodds.com/blog/unit-vs-integration-vs-e2e-tests" rel="noopener noreferrer"&gt;https://kentcdodds.com/blog/unit-vs-integration-vs-e2e-tests&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Buenos ejemplos de cosas que testear:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Comprobar que se ve bien el componente (decide qué significa “bien”).&lt;/li&gt;
&lt;li&gt;Hacer click en un botón y comprobar que se abre una modal.&lt;/li&gt;
&lt;li&gt;Cerrar la modal y esperar a que se vea el componente con otro estado.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;pueden hacerse dentro del mismo test, y podríamos decir que este test "pasa a ser de integración", pero lo ejecutaremos dentro de una suite de tests con nuestro runner de tests unitarios, al ladito de los tests unitarios.&lt;/p&gt;

&lt;p&gt;No te preocupes por las opiniones que puedan surgir sobre el testing. Suele haber más opiniones que análisis sobre este tema. Una vez que pones a prueba estos conceptos, empiezas a ver el verdadero valor de los tests. Si recuerdas siempre el propósito que comentamos anteriormente, y empiezas a probar como un usuario interactuaría con tu componente, estarás optimizando el tiempo a la vez que agregando mucha más robustez a tu aplicación. Después de hacer esto, cuando empieces a desarrollar una feature nueva sobre el mismo componente, y veas que algo no funciona, y era por el test, verás que además el test que hiciste en su momento te está ayudando a ti. En ese momento sabrás que el "&lt;a href="https://pbs.twimg.com/media/DVUoM94VQAAzuws.jpg" rel="noopener noreferrer"&gt;Testing Trophy&lt;/a&gt;" es tuyo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/kentcdodds/status/960723172591992832" rel="noopener noreferrer"&gt;https://twitter.com/kentcdodds/status/960723172591992832&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Si te ha gustado este artículo, compártelo. Quieres hablar más sobre este tema? Empecemos una conversación en &lt;a href="https://twitter.com/lucasbernalte" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;. Sería interesante compartir buenos y malos ejemplos, y me gustaría saber qué opináis sobre esto, y si soléis hacer tests, cómo los hacéis y si tenéis alguna duda.&lt;/p&gt;

&lt;p&gt;Para estar al tanto de otras cosas en las que voy trabajando y artículos que voy seleccionando, como algunos que comparto en este post, puedes suscribirte a mi newsletter desde mi &lt;a href="https://lucasbernalte.com" rel="noopener noreferrer"&gt;website&lt;/a&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;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newSuscribers&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="nx"&gt;oldSuscribers&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>testing</category>
      <category>test</category>
      <category>frontend</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Introduciendo React Query</title>
      <dc:creator>Lucas Bernalte</dc:creator>
      <pubDate>Mon, 26 Oct 2020 11:53:11 +0000</pubDate>
      <link>https://forem.com/lucasbernalte/introduciendo-react-query-3lki</link>
      <guid>https://forem.com/lucasbernalte/introduciendo-react-query-3lki</guid>
      <description>&lt;p&gt;Original: &lt;a href="https://lucasbernalte.com/blog/introduciendo-react-query" rel="noopener noreferrer"&gt;https://lucasbernalte.com/blog/introduciendo-react-query&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Buenas a todos!&lt;/p&gt;

&lt;p&gt;Os quiero hablar de un descubrimiento de hace unos meses pero que hasta ahora no había podido poner en práctica, y que para mí ha sido un antes y un después a la hora de manejar estado en una aplicación en React: React-Query.&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%2Flucasbernalte.com%2Fstatic%2Fimages%2Freact-query%2Flogo.svg" 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%2Flucasbernalte.com%2Fstatic%2Fimages%2Freact-query%2Flogo.svg" alt="logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Gracias a &lt;a href="https://www.youtube.com/watch?v=seU46c6Jz7E" rel="noopener noreferrer"&gt;una charla de su autor, Tanner Linsley, en el React Summit&lt;/a&gt;, me decidí tras un tiempo a echarle un ojo, porque me pareció super interesante, y quería compartir con vosotros un poco mis impresiones y los problemas que me ha solucionado.&lt;/p&gt;

&lt;h2&gt;
  
  
  TLDR;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;React Query reduce la complejidad de manejar estados asíncronos.&lt;/li&gt;
&lt;li&gt;Podrías pensar que es capaz de “conectar” dichos estados y las queries entre sí.&lt;/li&gt;
&lt;li&gt;Distingue entre queries y mutaciones (acciones que cambian datos en BBDD y hacen las queries obsoletas).&lt;/li&gt;
&lt;li&gt;Se acabó el gestionar los casos de loadings y error.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Una intro sobre React Query
&lt;/h1&gt;

&lt;p&gt;Siempre me ha parecido que lo que veía sobre gestionar estado en el front no terminaban de resolver los problemas de la asincronía, y requerían de muchos trozos de código iguales, que aunque se podían refactorizar, siempre acababas centrándote en controlar estos estados, y no en lo que de verdad tiene importancia.&lt;/p&gt;

&lt;p&gt;Pero qué es React Query?&lt;/p&gt;

&lt;p&gt;Pues no es más que una libraría para manejar estado de Backend. React Query puede manejar las peticiones a una API por ti, y puede gestionar cuándo debes actualizar los datos, incluso de forma automática. &lt;/p&gt;

&lt;h3&gt;
  
  
  Queries y mutaciones
&lt;/h3&gt;

&lt;p&gt;La forma en la que React Query es capaz de identificar cada petición es mediante una &lt;code&gt;key&lt;/code&gt; que le indicaremos. Además, distingue entre queries y mutaciones. Las &lt;a href="https://react-query.tanstack.com/docs/guides/queries" rel="noopener noreferrer"&gt;queries&lt;/a&gt; las podrá hacer de forma automática, y podrá manejar su estado “fresh” (sus datos están actualizados) o “stale” (sus datos están obsoletos). React Query te proporciona unos hooks para manejarlas, &lt;code&gt;useQuery&lt;/code&gt; y algunos más, dependiendo del tipo de query que queramos hacer (podemos hacer paginadas, infinitas...).&lt;/p&gt;

&lt;p&gt;Sin embargo, las &lt;a href="https://react-query.tanstack.com/docs/guides/mutations" rel="noopener noreferrer"&gt;mutaciones&lt;/a&gt;, son aquellas queries que modifican datos en BBDD (por ejemplo un POST, PUT o DELETE en un típico CRUD). Si tenemos una lista de libros que obtenemos con un GET, la edición, adición o borrado de un libro serían &lt;strong&gt;mutaciones&lt;/strong&gt; sobre la lista de libros. Estas mutaciones, no tienen ninguna key al no tener que mantener en caché ningún dato, puesto que son acciones que se realizarían puntualmente. Entonces, el hook &lt;code&gt;useMutation&lt;/code&gt; en lugar de recibir la key, recibe directamente la función que realiza la mutación, y una configuración adicional.&lt;/p&gt;

&lt;p&gt;Un caso de uso que contiene queries y mutaciones sería el siguiente:&lt;/p&gt;

&lt;p&gt;Tenemos una tabla con proyectos en la DB y un CRUD básico en el Backend. Si tenemos en Front un listado y por ejemplo una creación, podríamos tener estas dos queries:&lt;/p&gt;

&lt;p&gt;Por un lado la query que se trae los proyectos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&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;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GetProjects&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getProjects&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El funcionamiento dentro de un componente de React es muy sencillo. React Query por defecto, va a realizar una petición en un componente al montarse cuando esté utilizando un hook como &lt;code&gt;useQuery&lt;/code&gt;. Utilizando la query anterior, vemos que nos da un estado de &lt;code&gt;isLoading&lt;/code&gt; y al resolverse, nos dará o bien un &lt;code&gt;data&lt;/code&gt; o un &lt;code&gt;error&lt;/code&gt;. El componente volverá a renderizar cuando cambie uno de estos parámetros y tendremos ese manejo ya controlado de forma automática!&lt;/p&gt;

&lt;p&gt;Y por otro lado el método para crear proyectos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;createProject&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMutation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createProject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;onSuccess&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="nx"&gt;queryCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invalidateQueries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GetProjects&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="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos vincular el primer parámetro del array que nos devuelve con la acción a realizar (probablemente con algún onClick) y fijaos lo que está pasando. Estamos utilizando una &lt;code&gt;mutation&lt;/code&gt;, pasándole la función que va a “mutar” los datos que no controlamos, y luego le pasamos qué hacer en el caso en el que la petición haya ido correctamente en el &lt;code&gt;onSuccess&lt;/code&gt;. Y lo que le estamos diciendo en ese onSuccess es que ejecute una función que va a invalidar la query con el nombre &lt;code&gt;’GetProjects’&lt;/code&gt;. Automáticamente si detecta que hay una query invalidada, vuelve a pedir los datos, con lo que se vuelve a repetir el flujo de antes y no haría falta gestionar ese estado de “refresh” tampoco.&lt;/p&gt;

&lt;h1&gt;
  
  
  Un caso un poco más específico
&lt;/h1&gt;

&lt;p&gt;Pues bien, después de conocer por encima qué serían las queries y qué serían las mutaciones, en mi primera implementación de React Query, vi el caso de uso que tenía delante:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Una tabla que muestra datos (una query paginada).&lt;/li&gt;
&lt;li&gt;Acciones de la tabla a nivel de fila y de toda la tabla (mutaciones sobre los datos).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Qué requisitos debe cumplir nuestra implementación?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Debe manejar un estado complejo de la tabla&lt;/li&gt;
&lt;li&gt;Debe manejar cancelaciones.&lt;/li&gt;
&lt;li&gt;Debe manejar un dato que se obtiene en la primera request, para enviar en peticiones sucesivas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;El componente de tabla que usamos es un componente propio, que nos hace tener que manejar un estado en el componente que lo usa, para guardar ciertos datos (filtrado, paginación, pageSize).&lt;/p&gt;

&lt;p&gt;Además para estas peticiones de tabla, necesitamos un parámetro extra que Backend nos devuelve en la primera petición, y que enviaremos en las peticiones sucesivas. Si este parámetro cambiara, tendremos que enviarlo en la siguiente petición y así (temas de caché). &lt;/p&gt;

&lt;p&gt;El primer approach fue utilizar una query paginada, añadiendo a la &lt;code&gt;key&lt;/code&gt; la paginación, el pageSize y los filtros. Como puedes crear tus propios hooks con React Query, en principio cada query tendrá su propio hook.&lt;/p&gt;

&lt;p&gt;Ahora tenemos que añadir el tema de la cancelación y el manejar un dato, así que decidí crear mi hook para manejar todo eso de forma especial para cada petición que tenga que ver con una tabla:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;myParam&lt;/span&gt;&lt;span class="p"&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;useGetMyTableDataQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tableState&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 a new AbortController instance for this request&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;controller&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;AbortController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// Get the abortController's signal&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signal&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;usePaginatedQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Queries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;QueryName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tableState&lt;/span&gt;&lt;span class="p"&gt;.&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;tableState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tableState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filters&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;promise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchMyTableData&lt;/span&gt;&lt;span class="p"&gt;({...&lt;/span&gt;&lt;span class="nx"&gt;tableState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;param&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;myParam&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="c1"&gt;// Cancel the request if React Query calls the `promise.cancel` method&lt;/span&gt;
      &lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cancel&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="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abort&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;promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolvedData&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;myParam&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;resolvedData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;myParam&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;resolvedData&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;De momento para controlar el tema del parámetro que tenemos que guardar para siguientes peticiones, lo haremos a través de una &lt;code&gt;closure&lt;/code&gt; (&lt;a href="https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36" rel="noopener noreferrer"&gt;pregunta de examen&lt;/a&gt;), guardando el resultado en &lt;code&gt;myParam&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Las acciones que modifican filas o la tabla completa, no tienen más complejidad que la mostrada en el ejemplo con &lt;code&gt;useMutation&lt;/code&gt; anterior. Simplemente invalidan la query, o en algunos casos, varias queries (no importa si invalida algunas que no están en pantalla, puesto que no las va a pedir).&lt;/p&gt;




&lt;h3&gt;
  
  
  Contenido extra
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;¿Se te ocurre alguna otra forma de resolver el pr&lt;a href="https://es.reactjs.org/docs/hooks-reference.html#useref" rel="noopener noreferrer"&gt;o&lt;/a&gt;blema resuelto con la &lt;code&gt;closure&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;&lt;a href="https://slides.com/lucasbernalte/react-query-intro" rel="noopener noreferrer"&gt;Slides de introducción a React Query&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Si te ha gustado este post, ¡tengo para ti otra buena noticia! Estoy preparando un curso de React Query que subiré a una plataforma de e-learning y me gustaría saber tu opinión. El curso será en inglés, pero si te interesa tenerlo en español, házmelo saber vía &lt;a href="//mailto:hola@lucasbernalte.com?subject=Curso%20React%20Query&amp;amp;body=Hola!%20Me%20gustar%C3%ADa%20tener%20acceso%20al%20contenido%20del%20curso%20de%20React%20Query%20en%20Espa%C3%B1ol.%20Gracias!"&gt;email&lt;/a&gt;, o directamente por &lt;a href="http://www.twitter.com/lucasbernalte" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;. Si quieres además contenido que voy encontrándome por mi camino, no olvides suscribirte a mi &lt;a href="http://lucasbernalte.com" rel="noopener noreferrer"&gt;newsletter&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Un saludo!&lt;/p&gt;

</description>
      <category>react</category>
      <category>reactquery</category>
      <category>architecture</category>
      <category>spanish</category>
    </item>
  </channel>
</rss>
