mock service worker, sad path test failure

fluffy-lionz

Recently just using Mock Service Worker to test my HTTP requests, i'm looking to test my failure path.

My first test passes (happy), but the error i'm receiving for my failure is "Unexpected end of JSON input"

It does behave in the way that I would like, but from a testing point of view i'm a little confused.

How can I get my failure path to pass the test?

My test file

import "whatwg-fetch";
import { rest } from "msw";
import { setupServer } from "msw/node";

import { collect } from "./collect";

const server = setupServer(
  rest.get(
    "http://api.openweathermap.org/data/2.5/weather",
    (req, res, ctx) => {
      return res(
        ctx.status(200),
        ctx.json({ base: "stations", clouds: { all: 6 }, cod: 200 })
      );
    }
  )
);

beforeAll(() => server.listen());
afterAll(() => server.close());
afterEach(() => server.resetHandlers());

it("collects data", async () => {
  const res = await collect();
  expect(res).toEqual({ base: "stations", clouds: { all: 6 }, cod: 200 });
});

it("handles failure", async () => {
  server.use(
    rest.get(
      "http://api.openweathermap.org/data/2.5/weather",
      (req, res, ctx) => {
        return res(ctx.status(401));
      }
    )
  );
  await expect(collect()).rejects.toThrow("401");
});

My fetch async function

require('dotenv').config()

export const collect = async () => {
    const key = process.env.REACT_APP_API_KE
    // try{
      const res = await fetch(`http://api.openweathermap.org/data/2.5/weather?q=london&appid=${key}`)
      if(res.status !== 200){
        const error = await res.json()
        throw { message: error.message, status: error.cod }
      }
        const data = await res.json()
        return data 
}
Som Shekhar Mukherjee

Fixing the mock server

The problem is that the collect function is expecting a JSON response even in case of an error, but your mock server doesn't return that. So, when you do res.json() in your collect function you get an error.

Update your response resolver to return a json response.

return res(ctx.json({message: "error"}), ctx.status(401));

Fixing the test

toThrow is not the correct matcher here, because async functions always return promise and in your case the collect function returns a promise that gets rejected with the thrown data.
So, you can use the toEqual matcher instead.

Also you need to update the way the error is tested. You can opt any of the following options:

Using rejects matcher:

it("handles failure", () => {
  server.use(
    rest.get(
      "http://api.openweathermap.org/data/2.5/weather",
      (req, res, ctx) => {
        return res(ctx.json({message: "error"}), ctx.status(401));
      }
    )
  );
  return expect(collect()).rejects.toEqual({ message: "error", status: 401 });
});

Using async/await syntax:

it("handles failure", async () => {
  server.use(
    rest.get(
      "http://api.openweathermap.org/data/2.5/weather",
      (req, res, ctx) => {
        return res(ctx.status(401));
      }
    )
  );
  try {
    await collect();
  } catch (err) {
    expect(err).toEqual({ message: "error", status: 401 });
  }
});

Using .catch

But in this approach you need to explicitly check that your catch assertion has been called, otherwise a fulfilled promise will not fail your test.

it("handles failure", async () => {
  server.use(
    rest.get(
      "http://api.openweathermap.org/data/2.5/weather",
      (req, res, ctx) => {
        return res(ctx.status(401));
      }
    )
  );
  expect.assertions(1);
  return collect().catch((err) =>
    expect(err).toEqual({ message: "error", status: 401 })
  );
});

Fixing the collect function

In your collect function the status should be res.status and not data.code.

And you can also clean the following code a bit by moving the res.json() call out of the conditional.

require("dotenv").config();

export const collect = async () => {
  const key = process.env.REACT_APP_API_KEY;
  const res = await fetch(
    `http://api.openweathermap.org/data/2.5/weather?q=london&appid=${key}`
  );
  const data = await res.json();
  if (res.status !== 200) {
    throw { message: data.message, status: res.status };
  }
  return data;
};

And also you shouldn't be storing secrets in react environment variables, that would be exposed. Docs enter image description here

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

XUnit Create Operation Service Mock Failure

How to mock model in service test?

Test is not running service mock promise (.then)

spring controller test by mock service

Mock a method in Service for unit test

jekyll + service worker failure : service worker does not successfully serve the manifest's start_url

Unit test for exception assertion fails despite expected and actual value matching a sad path

Test for an active service worker from within the client

Mock/Test Calls to Path.open

perl test mock make_path

How to mock Angular $q service in Jasmine test?

How to mock service and test POST controller method

How to test a change on observable in service mock?

How to test function in AngularJS service with mock data

How to mock AngularFire 2 service in unit test?

mock resttemplate to test a service as restFul client

returnValue not changing on spyOn mock service jasmine test

Symfony 4 Mock service in functional test

Test Angular2 service with mock backend

Mock service in symfony4 command test

How mock methods of repository in Service for Unit test

How to mock out call to service in an integration test?

Unit test mock service with observables => Subscribe is not a function

Grails 4.0 Mock service method in controller test

How to test response of service using mock?

Spring boot controller test - mock repository but test actual service

Is there any way to cache all files of defined folder/path in service worker?

Service Worker "fetch" event for requesting the root path never fires

Why Service Worker installed path was "/_/chrome" in google.com?

TOP Ranking

  1. 1

    Failed to listen on localhost:8000 (reason: Cannot assign requested address)

  2. 2

    Loopback Error: connect ECONNREFUSED 127.0.0.1:3306 (MAMP)

  3. 3

    How to import an asset in swift using Bundle.main.path() in a react-native native module

  4. 4

    pump.io port in URL

  5. 5

    Compiler error CS0246 (type or namespace not found) on using Ninject in ASP.NET vNext

  6. 6

    BigQuery - concatenate ignoring NULL

  7. 7

    ngClass error (Can't bind ngClass since it isn't a known property of div) in Angular 11.0.3

  8. 8

    ggplotly no applicable method for 'plotly_build' applied to an object of class "NULL" if statements

  9. 9

    Spring Boot JPA PostgreSQL Web App - Internal Authentication Error

  10. 10

    How to remove the extra space from right in a webview?

  11. 11

    java.lang.NullPointerException: Cannot read the array length because "<local3>" is null

  12. 12

    Jquery different data trapped from direct mousedown event and simulation via $(this).trigger('mousedown');

  13. 13

    flutter: dropdown item programmatically unselect problem

  14. 14

    How to use merge windows unallocated space into Ubuntu using GParted?

  15. 15

    Change dd-mm-yyyy date format of dataframe date column to yyyy-mm-dd

  16. 16

    Nuget add packages gives access denied errors

  17. 17

    Svchost high CPU from Microsoft.BingWeather app errors

  18. 18

    Can't pre-populate phone number and message body in SMS link on iPhones when SMS app is not running in the background

  19. 19

    12.04.3--- Dconf Editor won't show com>canonical>unity option

  20. 20

    Any way to remove trailing whitespace *FOR EDITED* lines in Eclipse [for Java]?

  21. 21

    maven-jaxb2-plugin cannot generate classes due to two declarations cause a collision in ObjectFactory class

HotTag

Archive