Home > other >  How can I test a React Service that fetchs from a backend
How can I test a React Service that fetchs from a backend

Time:03-15

I'm checking the test coverage and I'm not currently passing the fetch line (line 3). How can I test the fetch function?

Service:

export const taskManagerRemoteService = {
  getTasks: (): Promise<any> => {
    return fetch(`${process.env.REACT_APP_BACKEND_URL}${process.env.REACT_APP_TASKS_URI}`, {
      method: "GET",
      headers:{
        'Content-Type': 'application/json'
      }
    })
  }
}

Test:

import "@testing-library/react"
import { taskManagerRemoteService } from "./task-manager.remote.service";

describe("TaskManagerRemoteService", () => {
  afterAll(() => {
    jest.clearAllMocks()
  })

  it('should get tasks when getTasks method is called', async () => {
    const spy = jest.spyOn(taskManagerRemoteService, 'getTasks').mockImplementation(() => Promise.resolve([{}]))
    const tasks = await taskManagerRemoteService.getTasks();

    expect(spy).toHaveBeenCalled()
    expect(tasks).toStrictEqual([{}])
  
    spy.mockReset();
    spy.mockRestore();
  })
})

Thank you very much in advance

CodePudding user response:

You are testing the taskManagerRemoteService.getTasks method, so you should not mock it. You should mock the fetch function and its resolved/rejected value.

There are two ways to mock an API request:

  1. msw - Mock by intercepting requests on the network level. This way you have to install additional packages and set them up. It does not need to mock and uses the original fetch method, which is closer to the real runtime environment.

  2. global.fetch = jest.fn() - Just mock the fetch function, don't need to install any package. But the potentially at risk is incorrect mocks change the fetch's behavior, the test passes, actual code fails.

Below is code using the second way:

task-manager.remote.service.ts:

export const taskManagerRemoteService = {
  getTasks: (): Promise<any> => {
    return fetch(`${process.env.REACT_APP_BACKEND_URL}${process.env.REACT_APP_TASKS_URI}`, {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
      },
    });
  },
};

task-manager.remote.service.test.ts:

import '@testing-library/react';
import { taskManagerRemoteService } from './task-manager.remote.service';

describe('TaskManagerRemoteService', () => {
  let oFetch: typeof global.fetch;
  beforeAll(() => {
    oFetch = global.fetch;
  });
  afterAll(() => {
    global.fetch = oFetch;
  });
  it('should get tasks when getTasks method is called', async () => {
    global.fetch = jest.fn().mockResolvedValue([{}]);
    const tasks = await taskManagerRemoteService.getTasks();

    expect(global.fetch).toHaveBeenCalled();
    expect(tasks).toStrictEqual([{}]);
  });
});

Test result:

 PASS  stackoverflow/71400354/task-manager.remote.service.test.ts
  TaskManagerRemoteService
    ✓ should get tasks when getTasks method is called (5 ms)

--------------------------------|---------|----------|---------|---------|-------------------
File                            | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
--------------------------------|---------|----------|---------|---------|-------------------
All files                       |     100 |      100 |     100 |     100 |                   
 task-manager.remote.service.ts |     100 |      100 |     100 |     100 |                   
--------------------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.83 s, estimated 2 s
  • Related