<?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: Janeth Betancourt</title>
    <description>The latest articles on DEV Community by Janeth Betancourt (@janbe30).</description>
    <link>https://dev.to/janbe30</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%2F275186%2F66e0d152-c28f-4edd-bd7f-3bca2cbd01b0.jpeg</url>
      <title>DEV Community: Janeth Betancourt</title>
      <link>https://dev.to/janbe30</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/janbe30"/>
    <language>en</language>
    <item>
      <title>Integration testing of Redux-components with MSW</title>
      <dc:creator>Janeth Betancourt</dc:creator>
      <pubDate>Fri, 14 Jun 2024 18:26:46 +0000</pubDate>
      <link>https://dev.to/janbe30/integration-testing-of-redux-components-with-msw-4emb</link>
      <guid>https://dev.to/janbe30/integration-testing-of-redux-components-with-msw-4emb</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I recently started working on integration tests for a React application with Redux-connected components, specifically Redux-Toolkit. I quickly learned a common tool to use is the &lt;a href="https://mswjs.io/"&gt;Mock Service Worker (MSW) library&lt;/a&gt; to mock network requests; this library allows you to intercept outgoing network requests and mock their responses making it super easy to test the implementation details of your components.&lt;/p&gt;

&lt;p&gt;Setting up MSW in my application is quick and easy - after installing the library, you set up the server and integrate with your testing environment (Jest, Vitest,..), and you create the handlers to mock your requests and corresponding responses. Sounds easy enough, right?&lt;/p&gt;

&lt;p&gt;Well, not so much so if you're using Axios! 🙃&lt;/p&gt;

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

&lt;p&gt;After setting up MSW and creating the handlers I started running into issues. The requests were being intercepted by MSW but my tests kept failing because the Redux state was not being updated. I knew my Redux store and component were working as expected and the requests were being dispatched just fine, yet my tests kept failing. Was something else misconfigured somewhere?! I could &lt;em&gt;not&lt;/em&gt; find any problems &lt;em&gt;anywhere&lt;/em&gt; in my codebase. I spent hours debugging and asking around hopelessly until I noticed something interesting... the response data from the successful requests was empty, yet the error response was &lt;code&gt;undefined&lt;/code&gt;. So the data was being lost somewhere between MSW and the Axios request in my Redux slice. Hmmmm.&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue discovered
&lt;/h2&gt;

&lt;p&gt;This discovery lead me to wonder if these two libraries were even compatible and sure enough, the &lt;a href="https://github.com/mswjs/msw/issues/2026"&gt;first Google result&lt;/a&gt; shed some light on the issue. MSW and Axios &lt;em&gt;are&lt;/em&gt; compatible, however, there are some discrepancies in the way the libraries handle network requests causing the response body to be dropped or unrecognized in the Axios request. &lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;A good solution that worked for me was to get Axios to be mocked to use native &lt;code&gt;fetch&lt;/code&gt; while testing, as mentioned by someone in the Github thread above. There are several ways to do this and this is a quick simple solution that allows you to keep the benefits of axios in your actual application.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;jest.setup.js or jest.polyfills.js (depending on your setup)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import axios from 'axios';

// Globals needed for MSW
const { TextEncoder, TextDecoder, ReadableStream } = require('node:util');

Reflect.set(global, 'TextEncoder', TextEncoder);
Reflect.set(global, 'TextDecoder', TextDecoder);
Reflect.set(global, 'ReadableStream', ReadableStream);

const { Request, Response, Headers, FormData } = require('undici');

Reflect.set(global, 'Request', Request);
Reflect.set(global, 'Response', Response);
Reflect.set(global, 'Headers', Headers);
Reflect.set(global, 'FormData', FormData);

// Create a custom adapter that uses fetch
axios.defaults.adapter = async (config) =&amp;gt; {
  const { url, method, data, headers } = config;

  // Convert axios config to fetch config
  const response = await fetch(url, {
    method,
    body: data ? JSON.stringify(data) : undefined,
    headers: {
      'Content-Type': 'application/json',
      ...headers,
    },
  });

  const responseData = await response.json();

  return {
    data: responseData,
    status: response.status,
    statusText: response.statusText,
    headers: response.headers,
    config,
  };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Example Redux slice&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import axios from 'axios';

export const getMyData = createAsyncThunk(
  'example/getMyData',
  async (location) =&amp;gt; {
    const response = await axios.get(`https://google.com/get/mydata`, {
      headers: {
        'x-api-key': 'YOUR_API_KEY',
      },
    });
    return response.data;
  },
);

/* Initial state */
/* Slice fn */
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Example MSW Handlers&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { http, HttpResponse } from 'msw';

  http.get(`${baseURL}/get/mydata`, ({ request }) =&amp;gt; {
    console.log('Captured a "GET /get/mydata"', request.method, request.url);
    return HttpResponse.json('123ABCDE', { status: 200 });
  }),
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Start and stop MSW in SetupTests.js&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { server } from './mocks/server';

// Establish API mocking before all tests.
beforeAll(() =&amp;gt; {
  server.listen();
});

// Reset any request handlers that we may add during the tests,
// so they don't affect other tests.
afterEach(() =&amp;gt; server.resetHandlers());

// Clean up after the tests are finished.
afterAll(() =&amp;gt; {
  server.close();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hope this helps somebody else in their testing endeavors!&lt;/p&gt;

</description>
      <category>react</category>
      <category>testing</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
