<?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:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[testing - Rado's Blog]]></title><description><![CDATA[testing - Rado's Blog]]></description><link>https://blog.rstankov.com/</link><image><url>http://blog.rstankov.com/favicon.png</url><title>testing - Rado&apos;s Blog</title><link>https://blog.rstankov.com/</link></image><generator>Ghost 1.8</generator><lastBuildDate>Wed, 10 Jun 2026 00:31:15 GMT</lastBuildDate><atom:link href="https://blog.rstankov.com/tag/testing/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Four Tips for End-to-End Testing]]></title><description><![CDATA[The writing of unit and E2E tests is different. Because the unit tests verify one thing and E2E tests verify multiple things (some implicitly).]]></description><link>https://blog.rstankov.com/four-tips-for-end-to-end-testing/</link><guid isPermaLink="false">5fe8731f23fb95000421ceac</guid><category><![CDATA[testing]]></category><dc:creator><![CDATA[Radoslav Stankov]]></dc:creator><pubDate>Tue, 29 Dec 2020 07:21:26 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1546900703-cf06143d1239?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MXwxMjc2N3wwfDF8c2VhcmNofDR8fENvZGV8ZW58MHx8fA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1080" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://images.unsplash.com/photo-1546900703-cf06143d1239?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MXwxMjc2N3wwfDF8c2VhcmNofDR8fENvZGV8ZW58MHx8fA&ixlib=rb-1.2.1&q=80&w=1080" alt="Four Tips for End-to-End Testing"><p>I'm a big fan of <a href="https://www.browserstack.com/guide/end-to-end-testing">end-to-end</a> (E2E) tests. They give me confidence that my system works as a whole..</p>
<p>E2E tests have two goals:</p>
<ol>
<li>Make sure a particular feature works well with all of its connected pieces.</li>
<li>Group features together, so one can understand what is going on in the system.</li>
</ol>
<p>Even though we often use the same tools for writing unit and E2E tests, writing them is different. Unit tests only verify one thing and E2E tests verify multiple things (some implicitly).</p>
<p>A lot of developers find it hard to write and to debug E2E tests.</p>
<p>Here are a couple of tips to help you with writing and maintaining E2E tests.</p>
<h3 id="1usedatatesttomatchelements">1) Use <code>data-test</code> to match elements</h3>
<p>Use <code>data-test</code> attributes instead of <code>CSS</code> selectors to find elements on pages.</p>
<pre><code class="language-js">// instead of this
element.find('.description button.expand-button').simulate('click');
// write this
element.find('[data-test=&quot;test&quot;]').simulate('click');
</code></pre>
<p>Tests often break because the developer didn't know a particular property was used for testing. Having an explicit <code>data-test</code> communicates &quot;this is needed for testing&quot;.</p>
<p>I have <a href="https://blog.rstankov.com/using-rel-in-testing/">written</a> about this in more detail before.</p>
<h3 id="2verifyaftereveryaction">2) Verify after every action</h3>
<p>In unit tests, you should follow the <a href="https://thoughtbot.com/blog/four-phase-test">Four-Phase Test</a>:</p>
<pre><code>setup
action
verify
teardown
</code></pre>
<p>Here is an E2E example of that:</p>
<pre><code>setup - create an unpublished blog post

action - visit post edit page
action - select new &quot;published_at&quot; date from date picker
action - submit the form
action - go to index page

verify - post's &quot;published_at&quot; is changed
verify - the post is shown on page
</code></pre>
<p>However, in E2E, if we only verify in the end, we might miss an error that happens somewhere in the middle. For example, a validation error might occur. A better approach is to do the following:</p>
<pre><code>setup - create an unpublished blog post

action - visit post edit page
verify - the post is shown on the edit page

action - select new &quot;published_at&quot; date from date picker
verify - the correct date selected from the date picker

action - submit the form
verify - no errors and success message is shown
verify - post's &quot;published_at&quot; is changed

action - go to index page
verify - the post is shown on page
</code></pre>
<p>In this way, if the date picker fails, we will know immediately instead of having to hunt down why the unpublished post is not shown on the index page.</p>
<p>Many assertions are already made by your testing library of choice - like <code>click_link &quot;foo&quot;</code> failing if it can't find what it's looking for. But there might be gaps when you have custom components, and you could make your own checks for those.</p>
<h3 id="3writehelpersforcustomoperations">3) Write helpers for custom operations</h3>
<p>Often in E2E, you have to perform a group of related operations. It is useful to have shared helpers for those.</p>
<p>For example, if you have a fancy calendar picker.  Every time you use it, you will have to write the following:</p>
<pre><code>- click data-test=&quot;calendar-picker&quot;
- enter the correct year in a text input
- pick a correct month from month picker
- click on the correct day
- click the &quot;ok&quot; button to save
</code></pre>
<p>It makes a lot more sense to have a single helper function, so when you change &quot;ok&quot; with &quot;done&quot;, you can do it in one place.</p>
<pre><code class="language-js">Helpers.selectInCalendarPicker(date)
</code></pre>
<p>Here are some other examples for grouping operations:</p>
<pre><code class="language-js">Helpers.loginAs(user)
Helpers.enterCommentWith(text)
Helpers.submitCommentWith(text)
Helpers.closeModal()
Helpers.enterInForm(values)
</code></pre>
<p>You can hide your <code>verify</code> checks in those helpers.</p>
<p>This is essential to have a maintainable E2E test suite. Ideally, a good test should read like a story and its implementation details would be hidden.</p>
<h3 id="4waitforajax">4) Wait for Ajax</h3>
<p>Often you have an Ajax call, followed by an assertion. Those calls take time and can lead to timeouts.</p>
<p>I always have a <code>waitForAjax</code> helper in my projects:</p>
<pre><code class="language-js">await Helper.waitForAjax();
</code></pre>
<p>Here is a sample implementation with <a href="http://apollographql.com/">Apollo</a> and <a href="https://github.com/teamcapybara/capybara">Cypbara</a>:</p>
<pre><code class="language-js">import { ApolloLink, concat } from 'apollo-link';
import { environment } from '~/config';

let recordRequestsInFlight = (networkLink) =&gt; networkLink;

if (environment.isBrowser &amp;&amp; environment.isTest) {
  recordRequestsInFlight = (networkLink) =&gt; {
    const recorderLink = new ApolloLink((operation, forward) =&gt; {
      window.test.apolloRequestsInFlight += 1;
      
      return forward(operation).map((result) =&gt; {
        window.test.apolloRequestsInFlight -= 1;
        return result;
      });
    });
    return concat(recorderLink, networkLink);
  };
}

// Usage
new ApolloClient({
 link: recordRequestsInFlight(
   new HttpLink(/* ... */),
 ),
 // ...
});
</code></pre>
<pre><code class="language-ruby"># this waits until there are no upcoming XHR request
def wait_for_ajax
  Timeout.timeout(Capybara.default_max_wait_time) do
    loop while page.evaluate_script('window.test.hasInFlightRequests()')
  end
rescue Timeout::Error
  # NOTE(rstankov): Some times this fails on CI while code is working
  nil
end
</code></pre>
<p><a href="https://gist.github.com/RStankov/5c9bb46f0a4e07a3a2e9af19e8738c51">Code in Gist</a></p>
<h2 id="conclusion">Conclusion</h2>
<p>Those tips are valid independently if you test with <a href="https://github.com/teamcapybara/capybara">Cypbara</a>, <a href="https://www.cypress.io/">Cypress</a> or <a href="https://developer.apple.com/documentation/xctest">XCTest</a> or similar. Their goal is to make your tests more reliable and easy to write, so you can spend more time developing your features instead of hunting for brittle tests.</p>
<p>If you have any questions or comments, you can ping me on <a href="https://twitter.com/rstankov">Twitter</a>.</p>
</div>]]></content:encoded></item><item><title><![CDATA[Testing Friction]]></title><description><![CDATA[One of the barriers to entry for writing tests is the "ergonomics" of our tools. ]]></description><link>https://blog.rstankov.com/testing-f/</link><guid isPermaLink="false">5f83194fd6656e00046a5c17</guid><category><![CDATA[testing]]></category><dc:creator><![CDATA[Radoslav Stankov]]></dc:creator><pubDate>Tue, 13 Oct 2020 05:46:03 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1489875347897-49f64b51c1f8?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjEyNzY3fQ" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://images.unsplash.com/photo-1489875347897-49f64b51c1f8?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjEyNzY3fQ" alt="Testing Friction"><p>One of the barriers to entry for writing tests is the &quot;ergonomics&quot; of our tools. Requiring too much ceremony or boilerplate for every test will put off even the most enthusiastic testers.</p>
<p>One of the reasons testing is common in Ruby land is tools do a lot of the setup/tear down for you. A lot of this comes from tight integration of libraries like Rails, RSpec, FactoryBot.</p>
<p>In JavaScript land, things are decoupled, and you need to do too much setup/configuration.</p>
<p>To have a sound testing story, you need to build your testing tools to integrate the different parts. Writing tests should be frictionless so that you can focus only on testing logic.</p>
<p>The second friction point in testing is speed - If it's faster to run the test, I'll do it more often. Having to wait makes you test less frequently. The best tooling investment I ever did is integrate <a href="https://github.com/vim-test/vim-test">vim-test</a> and run the current test from my editor with a simple shortcut.</p>
</div>]]></content:encoded></item><item><title><![CDATA[Testing React Components Tricks]]></title><description><![CDATA[Couple of minor tricks, which makes testing react components easer and future proved.]]></description><link>https://blog.rstankov.com/testing-react-components-tricks/</link><guid isPermaLink="false">59be8eefa0d6a8000444e82f</guid><category><![CDATA[React]]></category><category><![CDATA[testing]]></category><dc:creator><![CDATA[Radoslav Stankov]]></dc:creator><pubDate>Sat, 07 Oct 2017 18:49:12 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1504639725590-34d0984388bd?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;s=a2c64b46cd380a3cb8fe6acda35d735d" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://images.unsplash.com/photo-1504639725590-34d0984388bd?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&s=a2c64b46cd380a3cb8fe6acda35d735d" alt="Testing React Components Tricks"><p>When I'm writing test, I have a couple of goals:</p>
<ul>
<li>keep tests simple and understandable</li>
<li>only test the important characteristics</li>
<li>try to make future-proof as possible</li>
</ul>
<p>Here are some of the tricks, I use to accomplish those goals.</p>
<p>Most of the components, I write follow the <a href="https://medium.com/styled-components/component-folder-pattern-ee42df37ec68">&quot;Component Folder Pattern&quot;</a>. Where I have something like the following:</p>
<pre><code>/components/CustomComponent/index.js - component itself
/components/CustomComponent/index.test.js - test file
/components/CustomComponent/styles.css - styles for this compoennt
/components/CustomComponent/SubComponent.js - any subcompoennts
/components/CustomComponent/Fragment.graphq - GraphQL fragment
/compoennts/CustomComponent/... - other things related to this component
</code></pre>
<p>I like this pattern a lot. Especially for tests, since you can find the unit test for a specific component quite easy. One other benefit is that, <strong>when you rename the component you don't have to rename its test file</strong>.</p>
<p>My tests usually look something like this:</p>
<pre><code class="language-js">// I don't use  the actual component name, in this way 
// when you rename the component, no test change is required
import Component from './index'; 

// future proving, I use `Component.name`, 
// so your test always show the correct component name
// (this works for normal functions as well)
describe(Component.name, () =&gt; {
   // I use SUD (system under test) wrapper component for the tests
   // in this way each test contains only the props, specific to a test case
   const defaults = {
     // some default properties
   };
   const SUD = (props) =&gt; &lt;Component {...defaults} {...props} /&gt;;
   
   it('renders something when someProp is given', () =&gt; {
     // this test only cares about `someProp`
     const wrapper = render(&lt;SUD someProp={&quot;value&quot;} /&gt;);
     // ... rest of the test
   });
});
</code></pre>
<p>I format my <code>it</code> test description in the following format:</p>
<pre><code class="language-js">it('[action]')
it('[action] when [condition]')
it('can [action] when [condition'])
</code></pre>
<p>Here are some examples:</p>
<pre><code class="language-js">it('renders a form')
it('renders error messages when invalid data is given')
it('can submit a form when valid data is given')
</code></pre>
<p>If you want to learn more about the terminology you can check out the <a href="https://speakerdeck.com/rstankov/testing-in-javascript">slides</a> from my recent talk <a href="https://speakerdeck.com/rstankov/testing-in-javascript">&quot;Testing in Javascript&quot;</a> at <a href="http://techtalks.bg/events/javascriptjava/">Tech Talks</a>.</p>
</div>]]></content:encoded></item><item><title><![CDATA[Using "data-test" in Tests]]></title><description><![CDATA[A better approach for selecting elements during testing, than using custom class names.]]></description><link>https://blog.rstankov.com/using-rel-in-testing/</link><guid isPermaLink="false">598468bfaf8dad5ca316eb68</guid><category><![CDATA[React]]></category><category><![CDATA[testing]]></category><dc:creator><![CDATA[Radoslav Stankov]]></dc:creator><pubDate>Mon, 20 Jun 2016 18:02:43 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1484417894907-623942c8ee29?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;s=3e0921a978c0c1c17f4d56715e2096d8" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://images.unsplash.com/photo-1484417894907-623942c8ee29?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&s=3e0921a978c0c1c17f4d56715e2096d8" alt="Using "data-test" in Tests"><p>When testing HTML components, I often see people using class names as selectors. For example:</p>
<pre><code class="language-javascript">element.find('.description button.expand-button').simulate('click');
</code></pre>
<p>While this seems convenient at first, there are some drawbacks. HTML structure and css classes tend to change due to design changes. Which will cause you re-write tests quite often. Also, if you are using <a href="https://github.com/css-modules/css-modules">css-modules</a> you can't rely on class names.</p>
<p>Because of that, for quite some time now, I have started marking elements with <code>data-test</code> attribute.</p>
<p>React example <em>(using <a href="https://github.com/airbnb/enzyme/">enzyme</a> and <a href="https://github.com/producthunt/chai-enzyme">chai-enzyme</a>)</em>:</p>
<pre><code class="language-jsx">describe(Description.name, () =&gt; {
  it('cut off text based on `cutoffLength`', () =&gt; {
    const el = shallow(&lt;Description text=&quot;test&quot; cutoffLength={1} /&gt;);
    
    expect(el).to.have.text('t...');
    expect(el).not.to.have.text('test');
  });

  it('hides expand button when text is short', () =&gt; {
    const el = shallow(&lt;Description text=&quot;test&quot; cutoffLength={10} /&gt;);
    expect(el).not.to.have.descendants('[data-text=&quot;expand-button&quot;]');
  });

  it('shows expand button when text is long', () =&gt; {
    const el = shallow(&lt;Description text=&quot;test&quot; cutoffLength={1} /&gt;);
    expect(el).to.have.descendants('[data-test=&quot;expand-button&quot;]');
  });

  it('clicking expand button reveals the whole text', () =&gt; {
    const el = shallow(&lt;Description text=&quot;test&quot; cutoffLength={1} /&gt;);

    el.find('[data-test=&quot;expand-button&quot;]').simulate('click');

    expect(el).not.to.have.descendants('[data-test=&quot;expand-button&quot;]');
    expect(el).to.have.text('test');
  });
});
</code></pre>
<p>The component code:</p>
<pre><code class="language-jsx">import React from 'react';
import styles from &quot;./style.css&quot;;

export default Description extends React.Component {
  state = { expanded: false };

  render() {
    const { text, cutoffLength } = this.props;

    if (this.state.expanded || text.length &lt; cutoffLength) {
      return (
        &lt;div className={styles.description}&gt;
          {this.props.text}
        &lt;/div&gt;
      );
    }

    return (
      &lt;div className={styles.description}&gt;
        {`${ text.substr(0, cutoffLength) }...`}
        &lt;button 
          data-test=&quot;expand-button&quot; 
          className={styles.expand} 
          onClick={this.expand}&gt;show more&lt;/button&gt;
      &lt;/div&gt;
    );
  }

  expand = () =&gt; {
    this.setState({ expanded: true });
  };
}
</code></pre>
<p>I'm also using <code>data-test</code> attributes for testing with <a href="https://github.com/jnicklas/capybara">Capybara</a> in Ruby land.</p>
<pre><code class="language-ruby">describe 'Product page' do
  it 'has product description rev' do
    product = create :post, :with_long_description

    visit product_path(product)

    expect(page).not_to have_text product.description

    # This can be extracted into `find_test_attr` or `click_test_attr`
    find(:css, '[data-test=&quot;expand&quot;]').click

    expect(page).to have_text product.description

    # This can be extracted into `have_test_arr`
    expect(page).not_to have_css('[data-test=&quot;expand&quot;]')
  end
end
</code></pre>
</div>]]></content:encoded></item></channel></rss>