Half-Stack Developer

Fetch Mock in Deno

📅 Published: 2025-01-02

Deno provides built-in mocking APIs in its standard library.

The documentation of mock APIs is very well written in tutorial style. Here I just offer a TL;DR.

Given an example function uses fetch:

const getData = async (url: string): Promise<string> => {
  const resp = await fetch(url);
  if (!resp.ok) {
    return 'Response not OK!';
  }
  let re;
  try {
    re = await resp.json();
    re = JSON.stringify(re);
  } catch (err) {
    console.error((err as Error).message);
    re = 'JSON parsing error!';
  }
  return re;
};

And we want to test if it correctly returns error message if response of fetch is not a 200er.

So we must replace Deno's built-in fetch method with our own function which returns a response we wanted:

const respNotOk = () => {
  const resp = new Response('', {
    status: 400 // make a non-OK response
  });
  return Promise.resolve(resp);
};

using fetchStub = stub(globalThis, 'fetch', respNotOk); // "fetch" is under the "globalThis" namespace

That's all. Whenever fetch() is called, our dummy 400-Response will be returned instead. We can then assert the return value or parameters being called with. Full example code:

import {assertEquals} from '@std/assert';
import {assertSpyCallAsync, stub} from '@std/testing/mock';

const getData = async (url: string): Promise<string> => {
  const resp = await fetch(url);
  if (!resp.ok) {
    return 'Response not OK!';
  }
  let re;
  try {
    re = await resp.json();
    re = JSON.stringify(re);
  } catch (err) {
    console.error((err as Error).message);
    re = 'JSON parsing error!';
  }
  return re;
};

const respNotOk = () => {
  const resp = new Response('', {
    status: 400
  });
  return Promise.resolve(resp);
};

Deno.test('Fetch can be mocked', async () => {
  using fetchStub = stub(globalThis, 'fetch', respNotOk);

  const retVal = await getData('http://localhost/400');

  assertEquals(retVal, 'Response not OK!');

  await assertSpyCallAsync(fetchStub, 0, {
    args: ['http://localhost/400']
  });
});

🔚