Skip to content

Instantly share code, notes, and snippets.

@rafaelrozon
Last active April 26, 2023 12:29
Show Gist options
  • Save rafaelrozon/ed86efbea53094726e162dc05882cddc to your computer and use it in GitHub Desktop.
Save rafaelrozon/ed86efbea53094726e162dc05882cddc to your computer and use it in GitHub Desktop.
Mock Axios requests in Storybook
import React from 'react';
import { storiesOf } from '@storybook/react';
// 1. import axios and MockAdapter
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
// 2. create the mock
const mock = new MockAdapter(axios);
// 2.1 the api request to be intercepted has to match exactly
const API_REQUEST = 'https://swapi.co/api/planets/1';
// 3. your component
class Test extends React.Component {
constructor(props) {
super(props);
this.state = { data: {} };
}
componentDidMount() {
const that = this;
axios.get(API_REQUEST).
then(function(response) {
that.setState({ data: response.data })
});
}
render() {
return (
<div>
Response is <pre>{JSON.stringify(this.state.data, null, ' ')}</pre>
</div>
);
}
}
storiesOf('Mocking Api responses with Axios and axios-mock-adapter', module)
.add('Test', () => {
// 4. create the mock inside the story
// if this is outside it'll mess up with other axios instances/requests
mock.onGet(API_REQUEST).reply(200, { test: 'some mock data' });
return <Test />
});
@husni1992
Copy link

This comes when I tried to do the above. Any idea?

utils.js:117 Uncaught (in promise) Error: Request failed with status code 404
at createErrorResponse (utils.js:117)
at Object.settle (utils.js:97)
at handleRequest (handle_request.js:78)
at index.js:18
at new Promise ()
at MockAdapter. (index.js:17)
at dispatchRequest (dispatchRequest.js:59)

@ignaciojcano
Copy link

Found this answer while I was trying to mock axios inside of my stories, ran into an issue when I added multiple stores (that 404 error that @husni1992 mentions) it was basically an issue with the mocks colliding.

I ended working around it creating a helper component, which does the mocking.

Helper component:

import { useEffect } from 'react';
import MockAdapter from 'axios-mock-adapter';
import { api } from '../../services'; // This is an AxiosInstance

interface IProps {
  children: any;
  mock: (adapter: MockAdapter) => void;
}

const apiMock = new MockAdapter(api);

const AxiosMock = ({ children, mock }: IProps) => {
  useEffect(() => {
    mock(apiMock);
    return () => {
      apiMock.reset();
    };
  });
  return children;
};

export default AxiosMock;

Usage in stories:

export const Default = () => {
  const mock = (apiMock: MockAdapter) => {
    apiMock.onGet('/api/meetings/1').reply(200, {
      id: 1,
      title: 'A Meeting',
    });
  };
  return (
    <AxiosMock mock={mock}>
      <Meeting />
    </AxiosMock>
  );
};

I'm using Storybooks CSF

@laurentiu1981
Copy link

Initially I used example above and got same erors.
Moved const mock = new MockAdapter(axios); inside story and error is gone.

@shchypylov
Copy link

Be aware that if you use your own Axios instance you should mock that instance, not the imported one

const axios = require('axios');
const axiosInstance = axios.create({
    timeout: 30000
});
const mock = new MockAdapter(axiosInstance);

@flopiti
Copy link

flopiti commented Dec 31, 2022

Initially I used example above and got same erors. Moved const mock = new MockAdapter(axios); inside story and error is gone.

I did this in all my stories and fixed my problem.

@lukasvice
Copy link

lukasvice commented Apr 26, 2023

Many thanks to @ignaciojcano for your solution.

I would like to share my modified version that avoids the mock being always active in other stories.
With this approach you don't have to move const mock = new MockAdapter(axios); inside the stories as noted by @laurentiu1981.

import MockAdapter from 'axios-mock-adapter'
import { ReactElement, ReactNode, useEffect, useRef } from 'react'
import axios from 'axios'

type AxiosMockProps = {
  children: ReactNode
  mock: (adapter: MockAdapter) => void
}

export function AxiosForBffMock({
  children,
  mock,
}: AxiosMockProps): ReactElement {
  const mockAdapter = useRef(new MockAdapter(axios)).current
  mock(mockAdapter)

  useEffect(() => {
    return () => {
      mockAdapter.restore()
    }
  }, [mockAdapter])

  return <>{children}</>
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment