<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ashley Davis</title>
    <description>The latest articles on DEV Community by Ashley Davis (@ashleydavis).</description>
    <link>https://dev.to/ashleydavis</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%2F1279362%2F25866402-61aa-4f57-954e-b29850280264.jpg</url>
      <title>DEV Community: Ashley Davis</title>
      <link>https://dev.to/ashleydavis</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ashleydavis"/>
    <language>en</language>
    <item>
      <title>Streamlined Contract Testing in Node.js: A Simple and Achievable Approach</title>
      <dc:creator>Ashley Davis</dc:creator>
      <pubDate>Wed, 27 Nov 2024 16:01:50 +0000</pubDate>
      <link>https://dev.to/appsignal/streamlined-contract-testing-in-nodejs-a-simple-and-achievable-approach-56eg</link>
      <guid>https://dev.to/appsignal/streamlined-contract-testing-in-nodejs-a-simple-and-achievable-approach-56eg</guid>
      <description>&lt;p&gt;Do you want the benefits of contract testing with much less effort? Are you convinced of the benefits of contract testing but think it’s just too difficult to roll out across your organization?&lt;/p&gt;

&lt;p&gt;You might worry that implementing Pact in your organization requires challenging changes to culture and process.&lt;/p&gt;

&lt;p&gt;In this article, I’ll show you a drastically simplified approach to contract testing that a single developer can bring online. You'll get many of the benefits of contract testing for much less work. You'll build a platform that will help convince your team of how much contract testing can help prevent problems going out to production.&lt;/p&gt;

&lt;p&gt;If you've ever tried to read the Pact documentation, you might think contract testing is a complicated team-based affair that requires new infrastructure. Let me show you that it doesn’t have to be this way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pre-requisites
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/ashleydavis/simplified-contract-testing" rel="noopener noreferrer"&gt;The example code for this article is available on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can clone the code repository using Git or download the zip file and unpack it.&lt;/p&gt;

&lt;p&gt;You’ll need Node.js installed to run the example code. The code repository contains three working examples that we’ll go through in turn. Follow along and try out each example for yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing a REST API with a Simplified Contract
&lt;/h2&gt;

&lt;p&gt;For our first example of simplified contract testing, let’s run some tests against an existing REST API. We’ll use the &lt;a href="https://jsonplaceholder.typicode.com/" rel="noopener noreferrer"&gt;JSON Placeholder REST API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;JSON Placeholder is a fake REST API that includes endpoints for creating, updating, reading, and deleting “blog posts”. In Figure 1, you can see the JSON response for getting all blog posts. &lt;a href="https://jsonplaceholder.typicode.com/posts" rel="noopener noreferrer"&gt;Load this URL in your web browser&lt;/a&gt; to see it for yourself:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffkr5hkdsz85dqlebjgn3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffkr5hkdsz85dqlebjgn3.png" alt="Figure 1: The JSON response from JSON Placeholder getting all blog posts viewed in Chrome." width="800" height="538"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 1: The JSON response from JSON Placeholder getting all blog posts, viewed in Chrome.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We'll use the Jest testing framework to run our contract tests. The Axios code library will make HTTP requests to the JSON Placeholder REST API, then we’ll check that the responses conform to a contract defined in a JSON schema. The setup for our first example is illustrated in Figure 2:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdh3zkco3rk7eu833nqyy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdh3zkco3rk7eu833nqyy.png" alt="Figure 2: Using Jest to make HTTP requests and checking the responses against a JSON schema." width="800" height="700"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 2: Using Jest to make HTTP requests and checking the responses against a JSON schema.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To try out the contract tests, you’ll need a local copy of the code repository and Node.js installed. Change into &lt;a href="https://github.com/ashleydavis/simplified-contract-testing/tree/main/rest-api" rel="noopener noreferrer"&gt;the &lt;code&gt;rest-api&lt;/code&gt; subdirectory&lt;/a&gt; for the first example project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;simplified-contract-testing/rest-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then install project dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now run the tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After a few moments, you should see the output from a handful of successful tests.&lt;/p&gt;

&lt;p&gt;Now let’s see how the code works. Listing 1 shows a pared-down version of the YAML test spec that makes a HTTP request to the &lt;code&gt;/post&lt;/code&gt; endpoint and checks the response against the &lt;code&gt;GetPostsResponse&lt;/code&gt; schema. &lt;a href="https://github.com/ashleydavis/simplified-contract-testing/blob/main/rest-api/test/test-spec.yaml" rel="noopener noreferrer"&gt;The code repo has an expanded version&lt;/a&gt; that contains tests for multiple HTTP endpoints.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;definitions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Schema for a blog post:&lt;/span&gt;
    &lt;span class="na"&gt;Post&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Represents a blog post.&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
      &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;userId&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;title&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;body&lt;/span&gt;
      &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;number&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;number&lt;/span&gt;
        &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
    &lt;span class="c1"&gt;# Schema for the REST API response:&lt;/span&gt;
    &lt;span class="na"&gt;GetPostsResponse&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GET /post response&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;array&lt;/span&gt;
      &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Reference to the Post schema.&lt;/span&gt;
        &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#/schema/definitions/Post"&lt;/span&gt;
&lt;span class="c1"&gt;# List of tests specs.&lt;/span&gt;
&lt;span class="na"&gt;specs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Tests the REST API that gets the list of blog posts.&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Gets all blog posts&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Gets all blog posts from the REST API.&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;get&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/posts&lt;/span&gt;
    &lt;span class="na"&gt;expected&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/json; charset=utf-8&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Reference to the schema for the REST API response.&lt;/span&gt;
        &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#/schema/definitions/GetPostsResponse"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Listing 1: A Test Spec That Makes an HTTP Request to the &lt;code&gt;/posts&lt;/code&gt; Endpoint
&lt;/h3&gt;

&lt;p&gt;How do we convert the test spec to a series of automated tests? For that, we'll use Jest’s &lt;code&gt;test.each&lt;/code&gt; function. We can use a very cool technique to generate automated tests from our data.&lt;/p&gt;

&lt;p&gt;In this case, we generate tests from our test spec loaded from the YAML file. You can see in Listing 2 that the code required to achieve this is minimal and not complicated. Listing 2 is slightly abbreviated, but not by much if you compare it to &lt;a href="https://github.com/ashleydavis/simplified-contract-testing/blob/main/rest-api/test/contract.test.js" rel="noopener noreferrer"&gt;the complete code file&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;yaml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;yaml&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;resolveRefs&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./lib/resolver&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;matchers&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;jest-json-schema&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;matchers&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// The REST API we are testing:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;baseURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://jsonplaceholder.typicode.com`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Contract tests&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="c1"&gt;// Loads the test spec:&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;testSpec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;resolveRefs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;yaml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/test-spec.yaml`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;utf-8&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="c1"&gt;// Generates a test for each contract test in the spec:&lt;/span&gt;
  &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;testSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;specs&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="s2"&gt;`$title`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Makes the HTTP request:&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&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="nx"&gt;spec&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;baseURL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;validateStatus&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="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// All status codes are ok.&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Matches headers:&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;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;headerName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expectedValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;
      &lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actualValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;headerName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&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;actualValue&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expectedValue&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="c1"&gt;// Matches response body against the expected schema:&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;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&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="nf"&gt;toMatchSchema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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;h3&gt;
  
  
  Listing 2: Generating a Series of Jest Tests from Our Data
&lt;/h3&gt;

&lt;p&gt;We have already seen how simple it can be to make data-driven contract tests against an existing REST API. Now let’s run our contract tests against a more realistic REST API backed by a database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mocking Your Database for Fast Contract Tests
&lt;/h2&gt;

&lt;p&gt;To try out this second example for yourself, change into the &lt;a href="https://github.com/ashleydavis/simplified-contract-testing/tree/main/mocked-mongodb" rel="noopener noreferrer"&gt;&lt;code&gt;mocked-mongodb&lt;/code&gt; subdirectory&lt;/a&gt;, install dependencies, and then run the tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;simplified-contract-testing/mocked-mongodb
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem with testing against real infrastructure (like a real database) is that it makes our automated tests run very slowly. We can speed this up massively by &lt;em&gt;mocking&lt;/em&gt; our database. By that, I mean replacing the real database with a fake version we can load up with pre-canned data fixtures to run our automated tests against. So while the real version of the service is configured to use a real database, the version we load for automated testing is configured to use the fake database instead. If you are interested, you can &lt;a href="https://github.com/ashleydavis/simplified-contract-testing/blob/main/mocked-mongodb/index.js" rel="noopener noreferrer"&gt;see the full code for the REST API in the code repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can see how this looks in Figure 3. Now we are running a REST API locally, and we have it talking to a mock database where we can control the data fixtures on a test-by-test basis:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwqdczkkvo852e8w46cmc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwqdczkkvo852e8w46cmc.png" alt="Figure 3: Mocking the database and controlling data fixtures on a test-by-test basis." width="800" height="642"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 3: Mocking the database and controlling data fixtures on a test-by-test basis.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It turns out to be incredibly easy to mock whole modules when using Jest. Any file we place in the &lt;a href="https://jestjs.io/docs/manual-mocks#mocking-user-modules" rel="noopener noreferrer"&gt;&lt;code&gt;__mocks__&lt;/code&gt; subdirectory&lt;/a&gt; can replace a real code module while automated tests run. So we place the file &lt;code&gt;mongodb.js&lt;/code&gt; in the &lt;code&gt;__mocks__&lt;/code&gt; subdirectory, and Jest automatically replaces &lt;code&gt;require(“mongodb”)&lt;/code&gt; with our mock version of the code. You can see &lt;a href="https://github.com/ashleydavis/simplified-contract-testing/blob/main/mocked-mongodb/__mocks__/mongodb.js" rel="noopener noreferrer"&gt;our mock version of MongoDB&lt;/a&gt; in Listing 3. Note how it exports the function &lt;code&gt;__setData__&lt;/code&gt;, which we can call from our tests to control the data fixture loaded for each test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;// A mock version of the MongoDB library.&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt; &lt;span class="c1"&gt;// Data fixtures are plugged in here.&lt;/span&gt;

&lt;span class="c1"&gt;// --snip--&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MongoCollection&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collectionName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;collectionName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;collectionName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;_id&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;collectionData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;collectionName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;collectionData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;el&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;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__value&lt;/span&gt;&lt;span class="p"&gt;);&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="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// A mock version of Mongodb's find function.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Returns the data fixture:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;collectionName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;insertOne&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;insertedId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;newly-inserted&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;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MongoDatabase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collectionName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MongoCollection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collectionName&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MongoClient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MongoDatabase&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="c1"&gt;// Allows automated tests to set data fixtures.&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;__setData__&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;_data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;MongoClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;__setData__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Listing 3: The Mock Version of MongoDB
&lt;/h3&gt;

&lt;p&gt;Now that we have a mock database and the ability to load data fixtures, we must give our test spec the ability to control which data fixture is loaded for each test. You can see a snippet of the &lt;a href="https://github.com/ashleydavis/simplified-contract-testing/blob/main/mocked-mongodb/test/test-spec.yaml" rel="noopener noreferrer"&gt;updated test spec&lt;/a&gt; in Listing 3. Note the new &lt;code&gt;fixture&lt;/code&gt; field that, in this case, specifies that this test should load the data fixture named &lt;code&gt;many-posts&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Gets all blog posts&lt;/span&gt;
    &lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Gets all blog posts from the REST API.&lt;/span&gt;
    &lt;span class="s"&gt;# Specifies the data fixture to load before running the test&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;fixture&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;many-posts&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;get&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/posts&lt;/span&gt;
    &lt;span class="na"&gt;expected&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt;
        &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/json; charset=utf-8&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#/schema/definitions/GetPostsResponse"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Listing 4: A Test That Loads the Data Fixture &lt;code&gt;many-posts&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;What we are missing now is the code that loads the data fixture for each test, which you can see in Listing 5 — or &lt;a href="https://github.com/ashleydavis/simplified-contract-testing/blob/main/mocked-mongodb/test/contract.test.js" rel="noopener noreferrer"&gt;check out the full version in the code repo&lt;/a&gt;. We are now running a local REST API so you can see how we start the web server before each test. Also note the call to &lt;code&gt;loadFixture&lt;/code&gt; at the start of each test, which loads the data&lt;br&gt;
fixture requested by the test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// --snip--&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Contract tests&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="c1"&gt;// Loads the test spec:&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;testSpec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;resolveRefs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;yaml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/test-spec.yaml`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;utf-8&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="c1"&gt;// --snip--&lt;/span&gt;

  &lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Starts the web server on a random port before each test:&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;startServer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;afterEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;closeServer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;testSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;specs&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="s2"&gt;`$title`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spec&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;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Loads a named database fixture into the mock MongoDB for each test:&lt;/span&gt;
      &lt;span class="nf"&gt;loadFixture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;clearFixture&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Makes the HTTP request:&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&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="nx"&gt;spec&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;baseURL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;validateStatus&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="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Matches status:&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;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Matches headers:&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;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;headerName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expectedValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;
      &lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actualValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;headerName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&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;actualValue&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expectedValue&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="c1"&gt;// Matches response body against the expected schema:&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;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&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="nf"&gt;toMatchSchema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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;h3&gt;
  
  
  Listing 5: Starting the Web Server and Loading Data Fixtures Before Each Test
&lt;/h3&gt;

&lt;p&gt;Running contract tests against a REST API is pretty useful, but we must often also work with services that communicate via asynchronous message queues. For &lt;a href="https://github.com/ashleydavis/simplified-contract-testing/tree/main/mocked-rabbit" rel="noopener noreferrer"&gt;this third and final example&lt;/a&gt;, we will extend our REST API so that it can send and receive messages through a RabbitMQ instance. Try out the tests for yourself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;simplified-contract-testing/mocked-rabbit
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Mocking Your Message Queue for Fast, Asynchronous Contract Tests
&lt;/h2&gt;

&lt;p&gt;Please note that we are mocking RabbitMQ in this example, but in principle, this technique can work for any asynchronous messaging system (such as Kafka or SQS).&lt;/p&gt;

&lt;p&gt;Let's mock the module &lt;code&gt;amqplib&lt;/code&gt; (essentially RabbitMQ), so that we can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Directly invoke asynchronous message handlers.&lt;/li&gt;
&lt;li&gt;Retrieve asynchronous published messages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can see how this looks in Figure 4. Our Jest tests are now acting through our mock version of RabbitMQ to interact with our REST API:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg25postzjj50isfqhxm5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg25postzjj50isfqhxm5.png" alt="Figure 4: Using a mock version of RabbitMQ to interact with our REST API during automated testing." width="800" height="642"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 4: Using a mock version of RabbitMQ to interact with our REST API during automated testing.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Our mock version of AMQPlib, which we use to replace RabbitMQ, is similar to our mock version of MongoDB. We add the file &lt;code&gt;amqplib.js&lt;/code&gt; to the &lt;code&gt;__mocks__&lt;/code&gt; subdirectory and Jest automatically replaces &lt;code&gt;require(“amqplib”)&lt;/code&gt; with the mock version you see in Listing 6. Published messages are saved in the &lt;code&gt;__published__&lt;/code&gt; object, and the mock AMQPlib also tracks message handlers in the &lt;code&gt;__consume__&lt;/code&gt; object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;crypto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Allows the contract tests to check messages that were published to the message queue:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;__published__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="c1"&gt;// Allows the contract tests to invoke message handlers:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;__consume__&lt;/span&gt; &lt;span class="o"&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;__queue_bindings__&lt;/span&gt; &lt;span class="o"&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;mockChannel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;assertExchange&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;assertQueue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randomBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hex&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;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;bindQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queueName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;exchangeName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;__queue_bindings__&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;exchangeName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;queueName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="c1"&gt;// Publishes a message to a mock queue.&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;exchange&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;routingKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;__published__&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;exchange&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&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="c1"&gt;// Binds an event handler to a message queue.&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;consume&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;__consume__&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="nf"&gt;ack&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mockConnection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;createChannel&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="nx"&gt;mockChannel&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;connect&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="nx"&gt;mockConnection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;__published__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;__consume__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;__queue_bindings__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Listing 6: The Mock Version of AMQPlib Used to Replace RabbitMQ
&lt;/h3&gt;

&lt;p&gt;With RabbitMQ mocked, our Jest tests can now invoke asynchronous message handlers directly in our code and then check any asynchronous responses that are subsequently published. Now that we can trigger HTTP requests or asynchronous messages from our tests, we need to update our test spec to specify the required type for each test. You can see an example in Listing 7. Note how the &lt;code&gt;type&lt;/code&gt; field specifies &lt;code&gt;rabbit&lt;/code&gt;, and the &lt;code&gt;exchange&lt;/code&gt; field selects the RabbitMQ “exchange” we are using to trigger the asynchronous message handler we are trying to test.&lt;/p&gt;

&lt;p&gt;At this point, we are not just checking “immediate responses” from HTTP requests, we now must also be able to check for asynchronous messages and compare them against the expected JSON schema. Note the &lt;code&gt;asyncResponse&lt;/code&gt; section of Listing 7 and how it defines the schema for a message that is expected to be published on the &lt;code&gt;payment-processed&lt;/code&gt; exchange.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Processes a payment on new user&lt;/span&gt;
    &lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Processes a payment on adding a new user.&lt;/span&gt;
    &lt;span class="s"&gt;fixture&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;many-posts&lt;/span&gt;
    &lt;span class="s"&gt;# The "trigger" that invokes the code to be tested&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rabbit&lt;/span&gt;
    &lt;span class="na"&gt;exchange&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;new-user&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;John Doe&lt;/span&gt;
    &lt;span class="na"&gt;expected&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Expectations for the asynchronous response:&lt;/span&gt;
        &lt;span class="na"&gt;asyncResponse&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rabbit&lt;/span&gt;
            &lt;span class="na"&gt;exchange&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payment-processed&lt;/span&gt;
            &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#/schema/definitions/UserPaymentProcessedMessage"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Listing 7: A Test Triggers an Async Message Handler
&lt;/h3&gt;

&lt;p&gt;We have extended our contract testing system to be even more flexible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We can trigger HTTP requests or asynchronous message handlers.&lt;/li&gt;
&lt;li&gt;We can match HTTP responses and asynchronous responses against a schema.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means we can test the following combinations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trigger an HTTP request and check that its immediate response matches expectations.&lt;/li&gt;
&lt;li&gt;Trigger an HTTP request and check that it results in publishing an asynchronous message that matches expectations.&lt;/li&gt;
&lt;li&gt;Trigger an async message handler and check that it results in publishing an asynchronous message that matches expectations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find examples of all these combinations in the &lt;a href="https://github.com/ashleydavis/simplified-contract-testing/blob/main/mocked-rabbit/test/test-spec.yaml" rel="noopener noreferrer"&gt;expanded test spec in the code repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The code that generates our contract testing suite is getting more complex, as you can see in Listing 8. Still, it’s not bad considering the number of tests and the different testing combinations that we can achieve with this relatively small piece of code. &lt;a href="https://github.com/ashleydavis/simplified-contract-testing/blob/main/mocked-rabbit/test/contract.test.js" rel="noopener noreferrer"&gt;See the full code that generates the contract tests in the code repo&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="c1"&gt;// --snip--&lt;/span&gt;

&lt;span class="c1"&gt;// The "http" trigger.&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;http&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&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="nx"&gt;spec&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;baseURL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;validateStatus&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="kc"&gt;true&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="c1"&gt;// The "rabbit" trigger.&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;rabbit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;amqplib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__queue_bindings__&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exchange&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`No queue is bound for exchange '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exchange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Uses the mock "amqplib" to invoke the message handler:&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;consumeHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;amqplib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__consume__&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;consumeHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`No consumer found for queue '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' bound to exchange '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exchange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'`&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;consumeHandler&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="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;triggers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;rabbit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;testSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;specs&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="s2"&gt;`$title`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// --snip--&lt;/span&gt;

  &lt;span class="c1"&gt;// Triggers the code to be tested.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;trigger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;triggers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&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;immediateResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Matches the immediate response against the expected schema.&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;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;immediateResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;immediateResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;immediateResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;immediateResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;immediateResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;headerName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expectedValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;immediateResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;
      &lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actualValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;immediateResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;headerName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&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;actualValue&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expectedValue&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;immediateResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;immediateResponse&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="nf"&gt;toMatchSchema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;immediateResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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="c1"&gt;// Matches the async response against the expected schema.&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;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asyncResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expectedResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asyncResponse&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;expectedResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exchange&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s2"&gt;`An exchange is required for async responses on spec '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;spec&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;'`&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actualAsyncResponsePayload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="nx"&gt;amqplib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__published__&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;expectedResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exchange&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;actualAsyncResponsePayload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s2"&gt;`Expected async response to be published on exchange '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;expectedResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exchange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'.`&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expectedResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;actualAsyncResponsePayload&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toMatchSchema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expectedResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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;h3&gt;
  
  
  Listing 8: Our Contract Testing Code Now Handles HTTP and Asynchronous Requests and Responses
&lt;/h3&gt;

&lt;p&gt;Our adventure in contract testing isn’t complete until we fully automate our tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Contract Tests to Your CI/CD Pipeline
&lt;/h2&gt;

&lt;p&gt;We can automate our tests in any CI/CD provider, as long as we can clone our code, install Node.js, and run the following commands in our project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm ci
npm &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Given that our external dependencies are mocked (MongoDB and RabbitMQ in these examples), that’s all that we need to get our simplified contract tests running in our CI/CD pipeline.&lt;/p&gt;

&lt;p&gt;Listing 9 shows a CI pipeline for GitHub Actions. &lt;a href="https://github.com/ashleydavis/simplified-contract-testing/blob/main/.github/workflows/contract-tests.yml" rel="noopener noreferrer"&gt;You can see the full, multi-project version in the code repo&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Automated contract tests&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;contract-tests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v3&lt;/span&gt; &lt;span class="c1"&gt;# Installs Node.js.&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt; &lt;span class="c1"&gt;# Installs project dependencies.&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm test&lt;/span&gt; &lt;span class="c1"&gt;# Runs the automated contract tests.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Listing 9: The GitHub Actions Workflow Runs Simplified Contract Tests for a Project
&lt;/h3&gt;

&lt;p&gt;Back in the beginning of this article, I showed how we can run contract tests against an existing REST API. In the same way, we can run our contract tests against any REST API or service that we can access.&lt;/p&gt;

&lt;p&gt;Because we control the code making the HTTP request, we can augment the code to include authentication details for the production deployment of our REST API and then run the contract tests against it. If you are contract testing against a production service via asynchronous messaging, then you'll need access (e.g., via an SSH tunnel or Kubernetes port forwarding) to your message queue.&lt;/p&gt;

&lt;p&gt;Obviously, we must be very careful if we run contract tests against a production system, especially when tests can make changes to that system. In the full version of my example, you may have noticed that one of the tests makes an HTTP POST request to create a blog post in the REST API. Tests like this are probably best run against a QA or staging deployment, but if you really do want to run them against production, you might want a test account to easily flush out after running tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bringing It Together: How I Applied Contract Testing
&lt;/h2&gt;

&lt;p&gt;In my team, we used the simplified approach to contract testing covered in this post without making the team adopt any arduous processes. We integrated it into our usual automated testing process (in this example, running &lt;code&gt;npm test&lt;/code&gt; in our CI pipeline), and we didn’t need any new infrastructure (like a contract broker) to bring all this together.&lt;/p&gt;

&lt;p&gt;Mocking, while not specifically related to contract testing, proved essential in making it convenient and fast to run these tests. Contract testing is more on the level of integration testing in terms of how much code it can cover for the least amount of effort.&lt;/p&gt;

&lt;p&gt;But because we mock certain external services (like the database and message queue), our contract tests can be much closer to unit tests in terms of performance. This makes it easy and fast to run our contract tests locally for frequent feedback while we make code changes to a REST API or microservice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;In this article, we've shown you that contract testing in Node.js can be as simple as defining a JSON schema and then using your favorite testing framework to check responses from REST APIs and asynchronous messaging.&lt;/p&gt;

&lt;p&gt;Using this simplified approach to contract testing, you can get started very quickly and gain practical results that will help convince your team that contract testing is worthwhile.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;P.S. If you liked this post, &lt;a href="https://blog.appsignal.com/javascript-sorcery" rel="noopener noreferrer"&gt;subscribe to our JavaScript Sorcery list&lt;/a&gt; for a monthly deep dive into more magical JavaScript tips and tricks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.P.S. If you need an APM for your Node.js app, go and &lt;a href="https://www.appsignal.com/nodejs" rel="noopener noreferrer"&gt;check out the AppSignal APM for Node.js&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>node</category>
    </item>
    <item>
      <title>Effective Testing in JavaScript</title>
      <dc:creator>Ashley Davis</dc:creator>
      <pubDate>Thu, 23 May 2024 12:00:00 +0000</pubDate>
      <link>https://dev.to/appsignal/effective-testing-in-javascript-29fj</link>
      <guid>https://dev.to/appsignal/effective-testing-in-javascript-29fj</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;The single most important rule of testing is to do it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Kernighan &amp;amp; Pike, The Practice of Programming, 1999&lt;/p&gt;

&lt;p&gt;Despite constantly changing technologies and the needs of customers, some wisdom seems eternal. &lt;em&gt;Programmers need to test their code.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But thorough testing takes time. When we do it well, everything works, and a massive testing effort feels like a waste. However, when we do it badly, our code is often broken, and we wish that we had done better testing.&lt;/p&gt;

&lt;p&gt;I have some good news for you. Testing doesn’t have to be arduous and we can still get good results. Part of it comes down to our attitude: come at it the right way and it will be much easier.&lt;/p&gt;

&lt;p&gt;Another part of it is the techniques we use. In this blog post, I’ll show you some testing techniques (with code examples on GitHub) that can deliver much more bang for your buck.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Test?
&lt;/h2&gt;

&lt;p&gt;We test our code to ensure that it works. I know, it seems obvious.&lt;/p&gt;

&lt;p&gt;But that’s not enough. To be more effective, we must catch bugs early. The earlier we find them, the cheaper they are to fix. When a bug goes out to production and is found by a customer, then it’s a whole lot more expensive to get it reported, reproduced, and handed off to a developer — and they probably then have to spend time loading the mental context they need to find and fix it.&lt;/p&gt;

&lt;p&gt;Testing enables refactoring. Evolution allows good design to &lt;em&gt;emerge&lt;/em&gt; naturally through repeated refactoring and simplification, but we can’t do that safely without testing.&lt;/p&gt;

&lt;p&gt;The best reason for testing is that it allows us to see things from our customer's perspective. This is one of the most important perspectives we can take, helping us see the bigger picture around our code.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Fundamental Rule of Development
&lt;/h2&gt;

&lt;p&gt;I don’t have many hard and fast rules, but this one is inviolable:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Keep your code working.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a mantra I repeat to myself while coding. Coding becomes a game where I take code through a series of iterations, going from working code to working code, then testing and making it work again. And so it goes. The sum total is a large amount of working and reliable code.&lt;/p&gt;

&lt;p&gt;I’ve been writing code for a long time. In the early years of my career, I was arrogant enough to assume that my code would come out working and was often surprised when it didn’t.&lt;/p&gt;

&lt;p&gt;In the later part of my career, I’ve turned that assumption around: now, I think that most code comes out broken. Going further, I believe that &lt;em&gt;the natural state of code is being broken&lt;/em&gt;. There are so many more ways code can be broken than for it to accidentally work.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Should We Test Our Code?
&lt;/h2&gt;

&lt;p&gt;We should test our code early and often.&lt;/p&gt;

&lt;p&gt;Testing frequently means problems don’t build up and snowball into bigger problems. It creates the fast feedback loop we need to stay on track and be agile.&lt;/p&gt;

&lt;p&gt;Testing early means we don’t delay the discovery of problems. We should aim for a small distance between coding and testing. The less we have to test, the easier it is to test, and the less chance that unnoticed bugs can creep into our code.&lt;/p&gt;

&lt;p&gt;We should make frequent commits to our code repository. I like to think of this as &lt;em&gt;putting working code in the bank&lt;/em&gt;. If, at any point, I run into a mess, I can reset my working code to the last commit — which I know is working, because I only commit working code. I can abandon my work in progress at any time without losing much effort. Aiming for small commits means I never have much work to lose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Manual Testing vs. Automated Testing
&lt;/h2&gt;

&lt;p&gt;I’ve been a developer for over 26 years, and I’ve probably spent more time doing manual testing than automated testing. So I know for sure that there’s nothing inherently wrong with manual testing and I still often do it, even when I do later follow it up with automated testing.&lt;/p&gt;

&lt;p&gt;Manual testing can get us a long way. Except that repeating the same manual tests over and over again is tedious and time-consuming, not to mention prone to mistakes and laziness (you never forget to test right?).&lt;/p&gt;

&lt;p&gt;When we write an automated test for a feature or a piece of code, we get all future testing of that feature for free. For this reason, automated testing can be worthwhile, but it will only pay for itself over the long haul.&lt;/p&gt;

&lt;p&gt;Automated testing allows us to scale up our testing. A single developer has the potential to conduct vastly more tests than they could ever achieve manually. Of course, this assumes that a massive effort has already been expended to build the automated tests in the first place.&lt;/p&gt;

&lt;p&gt;Because automated testing is &lt;em&gt;automatic&lt;/em&gt;, it means we won’t be tempted to skip or forget testing. It also enables more frequent testing, which, as discussed, is crucial to getting fast feedback and &lt;em&gt;keeping our code working&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Running a suite of automated tests gives us immediate confidence in our code, which is priceless and hard to achieve with manual testing.&lt;/p&gt;

&lt;p&gt;Even after espousing the benefits of automated testing, I can assuredly say that &lt;em&gt;not all code is worth the effort&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Not All Code Has Equal Value
&lt;/h3&gt;

&lt;p&gt;The stark fact is that not all code is equally important. Some code will be used once or infrequently, some will be thrown out, and some will be drastically changed from its original form.&lt;/p&gt;

&lt;p&gt;On the other hand, some code will be very important, some will be updated and evolved constantly, some will need to be very reliable, and some will need to be very secure.&lt;/p&gt;

&lt;p&gt;At the outset of writing any piece of code, it’s extremely difficult to know if that code is worth the effort of automated tests. If you invest in automated tests (or automating anything) when the effort isn’t warranted, you will waste precious time that might be better spent elsewhere.&lt;/p&gt;

&lt;p&gt;Using test-driven development (TDD) or otherwise aiming for 100% test coverage is a huge sacrifice in productivity because it treats all code as equally valuable. There is a diminishing return on investment for your effort. The more we push our testing to the extreme, the less value it yields.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Single Best Way to Improve at Testing
&lt;/h2&gt;

&lt;p&gt;I used TDD for many years before I realized I was spending way too much effort trying to test &lt;em&gt;all the code&lt;/em&gt;, including the code that didn’t require that level of effort. Sometimes I still use TDD, but only for the most important code. I enjoy practicing TDD and it has helped build my testing discipline. I learned to create code that’s easier to test, but I don’t often do it now. It’s far too expensive for the resource-starved startups I’ve bootstrapped in recent years.&lt;/p&gt;

&lt;p&gt;But TDD gave me what was probably my single most important lesson ever in coding and testing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Think about testing before coding.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Any effort we make to visualize testing before coding results in code that is easier to test. Code that is easier to test is &lt;em&gt;easier to keep working&lt;/em&gt;. Of course, this has nothing to do with TDD and we can easily fit &lt;em&gt;thinking&lt;/em&gt; into our normal development process without TDD or even without any automated testing.&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%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-05%2Fthinking-before-coding.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%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-05%2Fthinking-before-coding.png" alt="Thinking before coding"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Effective JavaScript Testing Techniques
&lt;/h2&gt;

&lt;p&gt;Following are some techniques for good testing with less effort.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ashleydavis/javascript-testing-examples/" rel="noopener noreferrer"&gt;You can find the set of example projects here&lt;/a&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Technique&lt;/th&gt;
&lt;th&gt;Usage&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Output testing&lt;/td&gt;
&lt;td&gt;Manual or automated&lt;/td&gt;
&lt;td&gt;Comparing previous output to the latest output to see what has changed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Visual testing&lt;/td&gt;
&lt;td&gt;Manual or automated&lt;/td&gt;
&lt;td&gt;Comparing before and after screenshots to see what has changed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manual testing, followed by automated testing&lt;/td&gt;
&lt;td&gt;Automated&lt;/td&gt;
&lt;td&gt;Testing manually to confirm the code works. Followed by automated tests.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Integration testing REST APIs&lt;/td&gt;
&lt;td&gt;Automated&lt;/td&gt;
&lt;td&gt;Applying automated testing to whole services.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend testing with Playwright&lt;/td&gt;
&lt;td&gt;Automated&lt;/td&gt;
&lt;td&gt;Testing frontends using Playwright.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Output Testing
&lt;/h3&gt;

&lt;p&gt;Like &lt;em&gt;golden testing&lt;/em&gt;, output testing checks the output against the last known working version. We can easily use a &lt;em&gt;Diff tool&lt;/em&gt; (e.g., &lt;code&gt;git diff&lt;/code&gt;) to view the differences.&lt;/p&gt;

&lt;p&gt;This is great for data pipelines (we diff the data that is output), but we can also use it to test behavior by including a log of important events in the output.&lt;/p&gt;

&lt;p&gt;Output testing can be used manually (we can visually check the differences) or automatically (by having our CI pipeline fail if there are differences).&lt;/p&gt;

&lt;p&gt;Output testing is simple to start using. It supports refactoring (any refactor should cause no difference in the output).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ashleydavis/javascript-testing-examples/tree/main/output-testing" rel="noopener noreferrer"&gt;Here's some example code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-05%2Foutput-testing.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%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-05%2Foutput-testing.png" alt="Testing by comparing output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Visual Testing
&lt;/h3&gt;

&lt;p&gt;Like &lt;em&gt;snapshot testing&lt;/em&gt;, visual testing compares the visual output (e.g., a screenshot) of our application against the last known working version.&lt;/p&gt;

&lt;p&gt;This is more difficult than output testing, but it works well for checking that changes in our code make no (or little) difference to its visual output.&lt;/p&gt;

&lt;p&gt;My code example uses Puppeteer to screenshot a web page and then ImageMagick to compare the screenshots. ImageMagick gives a metric indicating the amount of differences. This allows us to set a threshold and tune the system to tolerate small differences to a level that we can live with.&lt;/p&gt;

&lt;p&gt;Visual testing can be used manually (we scan the differences with our eyes) or automatically (failing our CI pipeline when ImageMagic’s &lt;em&gt;difference metric&lt;/em&gt; is above a certain threshold).&lt;/p&gt;

&lt;p&gt;With a visual testing system in place, we can quickly scale it across 100s or 1,000s of web pages. It can take some time to run a big test suite, but it’s the fastest way to search for visual problems across many web pages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ashleydavis/javascript-testing-examples/tree/main/visual-testing" rel="noopener noreferrer"&gt;Here's the example code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-05%2Fvisual-testing.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%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-05%2Fvisual-testing.png" alt="Testing by comparing visual output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Manual Testing, then Automated Testing
&lt;/h3&gt;

&lt;p&gt;We can get more effective results from traditional automated testing if we do manual testing followed up by automated testing.&lt;/p&gt;

&lt;p&gt;This means we can go through multiple rounds of evolution and refactoring supported by manual testing (or output testing, as mentioned previously) before we commit to automated testing. This can save a lot of time because it’s very time-consuming to have to keep automated tests working while we are creating and evolving new code.&lt;/p&gt;

&lt;p&gt;Creating automated tests becomes easy as well. We can use the captured output or code behavior for our automated tests. Fitting automated tests to the code (that we already know works) can be much easier than attempting to write tests from scratch.&lt;/p&gt;

&lt;p&gt;Saving automated testing until later also allows for an informed decision about whether automated testing is actually necessary in each particular case.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ashleydavis/javascript-testing-examples/tree/main/traditional-automated-testing" rel="noopener noreferrer"&gt;Check out some example code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-05%2Fmanual-before-automated-testing.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%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-05%2Fmanual-before-automated-testing.png" alt="Manual testing followed by automated testing"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Integration Testing REST APIs
&lt;/h3&gt;

&lt;p&gt;The most effective way to test REST APIs is to make HTTP requests against the entire service using a traditional automated testing framework (e.g., Jest).&lt;/p&gt;

&lt;p&gt;This is much faster to implement than unit testing and much easier to keep working over time. We get to test more code with a smaller suite of tests.&lt;/p&gt;

&lt;p&gt;We can also test other types of services in a similar way (for example, a microservice that accepts inputs from a message queue). In cases like this, we can feed input via messages instead of HTTP requests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ashleydavis/javascript-testing-examples/tree/main/rest-api-testing" rel="noopener noreferrer"&gt;See some example code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-05%2Fintegration-testing-rest-api.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%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-05%2Fintegration-testing-rest-api.png" alt="Integration testing REST APIs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Frontend Testing with Playwright
&lt;/h3&gt;

&lt;p&gt;Anyone who has tried to test UI components using traditional automated testing will tell you how painful it can be.&lt;/p&gt;

&lt;p&gt;A more effective way of testing UIs is using a frontend testing framework like &lt;a href="https://blog.appsignal.com/2023/07/12/an-introduction-to-playwright-for-nodejs.html" rel="noopener noreferrer"&gt;Playwright&lt;/a&gt;. We can do end-to-end testing of our whole system (frontend and backend), or we can completely mock the backend to focus on integration testing the frontend. This kind of testing covers the most ground for the least effort.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ashleydavis/javascript-testing-examples/tree/main/ui-testing" rel="noopener noreferrer"&gt;See some example code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-05%2Ffrontend-testing.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%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-05%2Ffrontend-testing.png" alt="Frontend testing with Playwright"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;We all have to test our code. That’s the only way to ensure it’s fit for purpose.&lt;/p&gt;

&lt;p&gt;But as we've seen in this post, we don’t have to labor on time-intensive traditional testing methods. There are more effective testing techniques out there that can save us so much time, and we can still have great tests. I encourage you to come up with testing techniques for your situation that need little effort.&lt;/p&gt;

&lt;p&gt;The important thing is that we deliver valuable and reliable code to our customers. They don’t care how we build or test it, only that we give them something that works well and delivers the value they need.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you liked this post, &lt;a href="https://blog.appsignal.com/javascript-sorcery" rel="noopener noreferrer"&gt;subscribe to our JavaScript Sorcery list&lt;/a&gt; for a monthly deep dive into more magical JavaScript tips and tricks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.P.S. If you need an APM for your Node.js app, go and &lt;a href="https://www.appsignal.com/nodejs" rel="noopener noreferrer"&gt;check out the AppSignal APM for Node.js&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

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