Categories
Web development

Unit testing axios with adapters, using Typescript and Jest

In this post you’ll see how you can write unit tests for an axios component using adapters.

Writing unit tests of your code using jest and axios with adapters can be quite challenging. Using typescript, you might get this error TypeError: Cannot read properties of undefined(reading 'get').

In this example, I’m using axios-cache-adapter like this:

You can mock your axios component this way (axios.ts):

import axios from 'axios'
import { IAxiosCacheAdapterOptions, setupCache } from 'axios-cache-adapter'

// extending Axios type to fix TS issues
interface IExtendedAxiosCacheAdapterOptions extends IAxiosCacheAdapterOptions {
    store: { removeItem: (key: string) => void; }
    uuid: string
}

// Create `axios-cache-adapter` instance, TTL 10 minutes
const cache = setupCache({
    maxAge: 10 * 60 * 1000,
    // Invalidate only when a specific option is passed through config
    invalidate: async (config: IExtendedAxiosCacheAdapterOptions, request) => {

        if (request.clearCacheEntry) {
            await config.store.removeItem(config.uuid)
        }
    }
});

// Create `axios` instance passing the newly created `cache.adapter`
export const cachedAxios = axios.create({
    adapter: cache.adapter,
});

I usually group all my api calls in a file api.ts and export the functions:

import { AxiosResponse } from 'axios'
import { cachedAxios } from './axios'

const getDemoData = (baseUrl: string): Promise<IDemoData> => {
    return cachedAxios.get(`${baseUrl}${API_URL}/demo-endpoint`)
        .then((response: AxiosResponse<IDemoData>) => response.data)
        .catch((error) => { throw error.message; });
}

export default { getDemoData }

Finally, the axios.spec.ts test file for the api call:

import axios from 'axios'
import api from '../src/api'

// Mock jest and set the type
jest.mock('axios');
const mockedAxios = axios as jest.Mocked<typeof axios>;

jest.mock('../src/axios.ts', () => ({ cachedAxios: axios }));

describe('demo test api', () => {
    afterAll(() => {
        jest.restoreAllMocks()
    });

    it('should send a request to the API', async () => {
        mockedAxios.get.mockResolvedValue({ data: { result: 'success' } });

        const result = await api.getDemoData('demo argument');
        expect(mockedAxios.get).toHaveBeenCalledWith(`${API_URL}/demo-endpoint`);

        expect(result).toMatchObject({
            result: 'success'
        });
    });
});

Leave a Reply

Your email address will not be published. Required fields are marked *