<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Matheus Marques on Medium]]></title>
        <description><![CDATA[Stories by Matheus Marques on Medium]]></description>
        <link>https://medium.com/@matiosfm?source=rss-808de76c1a3f------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/2*VcpimLOluqJZPmNfQm2LUw.jpeg</url>
            <title>Stories by Matheus Marques on Medium</title>
            <link>https://medium.com/@matiosfm?source=rss-808de76c1a3f------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 07:07:57 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@matiosfm/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[React UI Testing com StoryShots e Enzyme]]></title>
            <link>https://medium.com/@matiosfm/react-ui-testing-com-storyshots-e-enzyme-7e97fa124076?source=rss-808de76c1a3f------2</link>
            <guid isPermaLink="false">https://medium.com/p/7e97fa124076</guid>
            <category><![CDATA[storybook]]></category>
            <category><![CDATA[enzyme]]></category>
            <category><![CDATA[shot-story]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[jest]]></category>
            <dc:creator><![CDATA[Matheus Marques]]></dc:creator>
            <pubDate>Sat, 02 Jun 2018 11:15:15 GMT</pubDate>
            <atom:updated>2018-06-02T11:15:15.210Z</atom:updated>
            <content:encoded><![CDATA[<p>Quando estamos falando de pequenas aplicações é muito provável que os testes são ignorados. Em aplicações JavaScript, aqueles arquivos .test.js criados a partir do boilerplate são excluídos e vida segue assim.</p><h4>A negliglência é tomada pela insegurança</h4><p>Muitos componentes são criados e é normal que exista muitas interações de lógica e de estilo entre eles. Nossa aplicação vai ganhando corpo e a negligência pela criação de testes acaba dando uma sensação de insegurança quando é preciso modificar algo que já foi feito há muito tempo. Ainda pode ser pior se o que precisa ser modificado sem foi feito por você. Aí é que é preciso mais tempo para entender aquilo e o que precisa mudar para consertar algum bug ou trazer alguma melhoria.</p><p>Eu passei por isso e a única solução foi refatorar uma grande quantidade de código para que atendesse às novas especificações. Com os testes desde o início, era bem provável que não precisasse fazer todo esse retrabalho e focar apenas nas modificações necessárias e garantir que as rotinas de testes não venha com erros.</p><p>Então, resolvi compartilhar um pouco dessa minha trajetória com testes no React e, mais especificamente, testes de interface (UI Testing).</p><h3>UI Testing</h3><p>O próprio nome já entrega. UI Testing são testes voltados para interface. Normalmente, dois testes são realizadas todos os dias sem que se perceba. São os <em>Structural Testing</em> e <em>Interaction Testing</em>. Quando se observa o posicionamento dos elementos criados dentro de uma página web é feito um <em>Structural Testing</em>, mesmo que seja manual. Quando se observa o comportamento (cliques de botões, por exemplo) de um componente no React é feito um <em>Interaction Testing</em><strong><em>.</em></strong></p><p>Quando é preciso lidar com muitas telas e muitas interações, a forma manual e habitual para fazer esses testes torna-se cansativo e ineficaz. Então, <em>Enzyme</em> e <em>StoryShoots</em> foram criados para nos ajudar.</p><h4>Enzyme</h4><p><em>Enzyme</em> é um utilitário de testes de JavaScript feito para o React para facilitar a vida dos programadores na hora de declarar, manipular e estudar a saída de seus componentes. Por de trás do panos, <em>Enzyme</em> faz uso do jQuery para atingir os elementos de seus componentes e realizar ações de cliques ou verificar tamanho, cor, etc.</p><h4>StoryShots</h4><p><em>StoryShots</em> é um addon feito para o <a href="https://storybook.js.org/">Storybook</a> para integrar os Snapshots do <a href="https://facebook.github.io/jest/">Jest</a>, esse que é outro utilitário de testes de JavaScript para escrever testes unitários. StoryShots irá capturar o estado atual da estrutura da interface da aplicação naquele momento. É como se fosse tirada uma foto. Se qualquer mudança que tenha impacto na estrutura aconteça, o teste não é aceito e duas coisas devem ser consideradas:</p><ul><li>Realmente foi preciso mudar a estrutura então é necessário atualizar a StoryShot.</li><li>Um mudança inesperada aconteceu e é preciso retornar ao código e corrigir os problemas para que o teste da StoryShot seja aceito.</li></ul><h3>Começando com o bom e velho setup</h3><p>Para facilitar, a aplicação será criada a partir do <a href="https://github.com/facebook/create-react-app"><em>Create React App</em></a> para agilizar as configurações iniciais de repositório. Para isso, vamos instalar globalmente esse pacote</p><pre>yarn global add create-react-app<br>create-react-app ui-easy-test<br>cd ui-easy-test</pre><h3>Instalando o Storybook</h3><p>Assim como o CRA, é preciso instalar o CLI do storybook para ter uma configuração inicial sem grandes esforços. Dentro da pasta ui-easy-test execute os comandos para ter o <em>Storybook</em> nesse projeto.</p><pre>yarn global add @storybook/cli<br>getstorybook<br>yarn run storybook</pre><p>Agora, se irmos até http://localhost:9009 vemos a interface padrão do Storybook com dois exemplos de <em>stories</em>. Foram criados duas pastas por padrão .storybook e src/stories que irão guardar as configurações do storybook e a adição de addons e as <em>stories</em> propriamente ditas, respectivamente.</p><h3>Criando nosso componente</h3><p>Para os estudos adiante vamos criar nosso primeiro componente no projeto dentro da pasta src/components chamado Toggler .</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kfaKZF316WUSu2ku3kOqaQ.png" /><figcaption>Botão Toggler</figcaption></figure><p>Um toggler simples que modifica seu estado de ativo para inativo e vice-versa e muda sua label de acordo com seu estado.</p><h3>Criando nossa primeira <em>story</em></h3><p>Agora que temos esse componente, é preciso criar uma <em>story</em>. Por padrão, todas as <em>stories</em> que estiverem dentro do arquivo index.jsdentro da pasta src/stories serão automaticamente adicionador ao <em>Storybook</em>. Portanto, vamos criar nossa primeira <em>story</em>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/822/1*cQVKuuFinL2irLp234V-5A.png" /><figcaption><em>Story d</em>o componente Toggler</figcaption></figure><p>Um conjunto de stories pode ser criado a partir de storiesOf . Seu primeiro parâmetro é o nome desse conjunto e cada <em>story </em>é individualmente chamada em cada add() subsequente. Seu primeiro parâmetro é o nome da <em>story </em>e seu segundo parâmetro é uma função que deve retornar um elemento DOM, no nosso caso, o componente Toggler , para que esse seja renderizado no <em>Storybook</em>.</p><p>Até aí tudo bem. Temos nosso conjunto de <em>stories </em>e nosso componente, mas está faltando instalar o <em>Enzyme</em> e o <em>StoryShot.</em></p><h3>Instalando e configurando o Enzyme</h3><pre>yarn add enzyme --dev<br>yarn add enzyme-adapter-react-16 --dev<br>yarn add react-test-renderer --dev</pre><p>Hoje, estamos na versão 16.4 do React e para que o <em>Enzyme</em> funcione corretamente é preciso instalar o adapter do React 16. Além disso, o pacote react-test-renderer é instalado para garantir que os componentes possam ser renderizados isoladamente sem depender de um DOM, garantindo nossos testes sem se preocupar em renderizar algo além dos nossos componentes, seja ele um botão, um input ou um formulário.</p><p>Ótimo, agora que todos os pacotes foram instalados é preciso acrescentar algumas configurações extras para que nada dê errado. É preciso criar inicialmente o arquivosrc/setupTests.js com o trecho de código abaixo para que o <em>Enzyme</em> não aponte erros de Adapter ao longo dos testes. Esse arquivo é identificado automaticamente pelo <em>Create React App </em>com<em> </em>o objetivo de facilitar a configuração inicial dos nossos testes.</p><pre>import Enzyme from &#39;enzyme&#39;;<br>import Adapter from &#39;enzyme-adapter-react-16&#39;;</pre><pre>Enzyme.configure({ adapter: new Adapter() });</pre><h3>Primeiro teste com Enzyme e Jest</h3><p>Agora podemos criar nosso primeiro teste utilizando o Enzyme e o Jest. Para que a aplicação identifique os testes com o comando yarn test é preciso criar arquivos com o padrão *.test.js . Vamos criar Toggler.test.js dentro da pasta src/components .</p><pre>import React from &#39;react&#39;;<br>import { shallow } from &#39;enzyme&#39;;<br>import { expect } from &#39;chai&#39;;<br>import Toggler from &#39;./Toggler&#39;;</pre><pre>describe(&#39;Assertions&#39;, function () {<br>  const activeLabel = &#39;Toggle me! ✅&#39;;<br>  const inactiveLabel = &#39;Toggle me! ❌&#39;;</pre><pre>  it(&#39;click once state.active should be true and label &#39; + activeLabel, () =&gt; {<br>    const wrapper = shallow(&lt;Toggler /&gt;);</pre><pre>    wrapper.find(&#39;button&#39;).simulate(&#39;click&#39;);</pre><pre>    expect(wrapper.state().active).to.equal(true);<br>    expect(wrapper.text()).to.equal(activeLabel);<br>  });</pre><pre>  it(&#39;click twice state.active should be false and label &#39; + inactiveLabel, () =&gt; {<br>    const wrapper = shallow(&lt;Toggler /&gt;);</pre><pre>    wrapper.find(&#39;button&#39;).simulate(&#39;click&#39;);<br>    wrapper.find(&#39;button&#39;).simulate(&#39;click&#39;);</pre><pre>    expect(wrapper.state().active).to.equal(false);<br>    expect(wrapper.text()).to.equal(inactiveLabel);<br>  });<br>});</pre><p>Para os testes foi utilizado a biblioteca de assertions chai para facilitar as afirmações feitas com os resultados dos testes e o shallow render do Enzyme para que childrens dos componentes não afetem o resultado dos testes. (Para entender isso melhor tem esse ótimo <a href="https://hackernoon.com/testing-react-components-with-jest-and-enzyme-41d592c174f">artigo</a> sobre Enzyme e Jest). describe e it são usados para descrever um conjunto de testes e um comportamento dele, respectivamente. Ambos têm um título como primeiro parâmetro e uma função como segundo parâmetro para a escrita dos testes. expect é o resultado que se espera do teste realizado.</p><p>Para os dois casos (Clicar duas vezes ou clicar uma vez), realizar a interação entre o clique do Togglerse espera um resultado específico do seu estado, assim como um tipo de Label. Se algum dos testes falhar, o problema irá aparecer no console (Experimente trocar algum dos resultados do expect de <em>true</em> para <em>false). </em>Se tudo ocorrer bem, teremos essa tela nos dizendo que tudo está bem e todos os testes passaram.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sdTjOrb4ETQy_8kxpezmOg.png" /><figcaption>Testes do Botão Toggler</figcaption></figure><h3>Instalando e Configurando o StoryShot</h3><p>Para configurar o <em>StoryShot </em>é mais simples. Basta a gente instalar o addon com</p><pre>yarn add @storybook/addon-storyshots --dev</pre><p>criar o arquivo de teste storyshots.test.js dentro da pastasrc/stories</p><pre>import initStoryshots from &#39;@storybook/addon-storyshots&#39;;</pre><pre>initStoryshots();</pre><p>E é isso! Agora todas as nossas <em>stories</em> serão uma StoryShot. Nossa telinha de testes fica assim agora.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8N0aTs0FsYk1o0KB8XcqpA.png" /><figcaption>Testes do Botão Toggler e seu Snapshot</figcaption></figure><p>Se modificarmos por alguma razão a Label do nosso componenteToggler de Toggle Me! ✅ ou ❌ para apenas Toggle, todos os testes irão falhar.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8CFMdQgh0dXesFQGZS4bPA.png" /><figcaption>Erros após mudar a Label do Toggler</figcaption></figure><p>Isso, porque mudamos a StoryShot (o console pergunta se queremos modificar apertando ‘u’ ou inspecionar as mudanças desse trecho) e porque os <em>asserts </em>não estão mais corretos, já que se esperava por uma das duas Labels antigas.</p><h3>Tá. Mas, porque utilizar as duas ferramentas de teste juntas?</h3><p><em>Enzyme</em> é muito bom em estudar o comportamento dos componentes, mas sozinho não consegue estudar o posicionamento e estilo deles. É preciso utilizar o Jest Snapshot juntamente com o <em>Enzyme</em> para criar o mesmo resultado que o StoryShot, porém perdemos o ambiente fenomenal que o Storybook nos proporciona.</p><p>Exploramos pouco aqui, mas ele é uma excelente ferramenta para documentar nossos componentes (existe outros <a href="https://storybook.js.org/addons/addon-gallery/">addons</a> para isso!). Criar diversas interações com as props dos componentes, event handlers e por aí vai. Além do mais, StoryShot é bem simples de instalar quando se tem o Storybook configurado, então acho que vale dar uma chance à ele.</p><p>O que eu posso concluir sobre tudo isso é que eu fico feliz de finalmente tomar gosto pela programação orientada à testes (TDD) e buscar melhorar cada vez mais meus conhecimentos. É melhor construir uma base sólida desde o início para que as loucuras ao logo do projeto sejam tranquilamente ajustadas.</p><p>Foi um artigo longo e com muita teoria, mas mesmo assim, fiz um <a href="https://github.com/marquesm91/ui-easy-test">repo</a> no Github para que eu posso continuar estudando e me aprimorar para escrever testes cada vez melhores.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7e97fa124076" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>