UNPKG

@openmrs/esm-api

Version:

The javascript module for interacting with the OpenMRS API

281 lines (250 loc) • 8.32 kB
import { isObservable } from 'rxjs'; import { getConfig as mockGetConfig } from '@openmrs/esm-config'; import { navigate as mockNavigate } from '@openmrs/esm-navigation'; import { openmrsFetch, openmrsObservableFetch } from './openmrs-fetch'; describe('openmrsFetch', () => { beforeEach(() => { // @ts-ignore window.openmrsBase = '/openmrs'; // @ts-ignore window.getOpenmrsSpaBase = () => '/openmrs/spa/'; window.fetch = jest.fn(); Object.defineProperty(window, 'location', { writable: true, value: { assign: jest.fn() }, }); }); afterEach(() => { // @ts-ignore delete window.openmrsBase; // @ts-ignore delete window.getOpenmrsSpaBase; }); it(`throws an error if you don't pass in a url string`, () => { // @ts-expect-error expect(() => openmrsFetch()).toThrow(/first argument/); // @ts-expect-error expect(() => openmrsFetch({})).toThrow(/first argument/); }); it('throws an error if you pass in an invalid fetchInit object', () => { // @ts-expect-error expect(() => openmrsFetch('/session', 'invalid second arg')).toThrow(/second argument/); // @ts-expect-error expect(() => openmrsFetch('/session', 123)).toThrow(/second argument/); }); it('throws an Error if there is no openmrsBase', () => { // @ts-ignore delete window.openmrsBase; expect(() => openmrsFetch('/session')).toThrow(/openmrsBase/); }); it('calls window.fetch with the correct arguments for a basic GET request', () => { // @ts-ignore window.fetch.mockReturnValue(new Promise(() => {})); openmrsFetch('/ws/rest/v1/session'); expect(window.fetch).toHaveBeenCalledWith('/openmrs/ws/rest/v1/session', { headers: { Accept: 'application/json', 'Disable-WWW-Authenticate': 'true', }, }); }); it('calls window.fetch correctly for requests that have a request body', () => { // @ts-ignore window.fetch.mockReturnValue(new Promise(() => {})); const requestBody = { some: 'json' }; openmrsFetch('/ws/rest/v1/session', { method: 'POST', body: requestBody, }); expect(window.fetch).toHaveBeenCalledWith('/openmrs/ws/rest/v1/session', { headers: { Accept: 'application/json', 'Disable-WWW-Authenticate': 'true', }, body: JSON.stringify(requestBody), method: 'POST', }); }); it('allows you to specify your own Accept request header', () => { // @ts-ignore window.fetch.mockReturnValue(new Promise(() => {})); const requestBody = { some: 'json' }; openmrsFetch('/ws/rest/v1/session', { headers: { Accept: 'application/xml', }, }); expect(window.fetch).toHaveBeenCalledWith('/openmrs/ws/rest/v1/session', { headers: { Accept: 'application/xml', 'Disable-WWW-Authenticate': 'true', }, }); }); it('allows you to specify no Accept request header to be sent', () => { // @ts-ignore window.fetch.mockReturnValue(new Promise(() => {})); openmrsFetch('/ws/rest/v1/session', { headers: { // specifically null on purpose Accept: null, }, }); expect(window.fetch).toHaveBeenCalledWith('/openmrs/ws/rest/v1/session', { headers: { 'Disable-WWW-Authenticate': 'true', }, }); }); it('returns a promise that resolves with a json object when the request succeeds', () => { // @ts-ignore window.fetch.mockReturnValue( Promise.resolve({ ok: true, status: 200, clone: () => ({ text: () => Promise.resolve('{ "value": "hi" }'), }), }), ); return openmrsFetch('/ws/rest/v1/session').then((response) => { expect(response.status).toBe(200); expect(response.data).toEqual({ value: 'hi' }); }); }); it('returns a promise that resolves with null when the request succeeds with HTTP 204', () => { // @ts-ignore window.fetch.mockReturnValue( Promise.resolve({ ok: true, status: 204, json: () => Promise.reject(Error("No json for HTTP 204's!!")), }), ); return openmrsFetch('/ws/rest/v1/session').then((response) => { expect(response.status).toBe(204); expect(response.data).toEqual(null); }); }); it('gives you an amazing error when the server responds with a 500 that has json', () => { // @ts-ignore window.fetch.mockReturnValue( Promise.resolve({ ok: false, status: 500, statusText: 'Internal Server Error', clone: () => ({ text: () => Promise.resolve( JSON.stringify({ error: 'The server is dead', }), ), }), }), ); return openmrsFetch('/ws/rest/v1/session') .then((data) => { fail("Promise shouldn't resolve when server responds with 500"); }) .catch((err) => { expect(err.message).toMatch(/Server responded with 500 \(Internal Server Error\)/); expect(err.message).toMatch(/\/ws\/rest\/v1\/session/); expect(err.responseBody).toEqual({ error: 'The server is dead' }); expect(err.response.status).toBe(500); }); }); it("gives you an amazing error when the server responds with a 400 that doesn't have json", () => { // @ts-ignore window.fetch.mockReturnValue( Promise.resolve({ ok: false, status: 400, statusText: 'You goofed up', clone: () => ({ text: () => Promise.resolve('a string response body'), }), }), ); return openmrsFetch('/ws/rest/v1/session') .then((data) => { fail("Promise shouldn't resolve when server responds with 400"); }) .catch((err) => { expect(err.message).toMatch(/Server responded with 400 \(You goofed up\)/); expect(err.message).toMatch(/\/ws\/rest\/v1\/session/); expect(err.responseBody).toEqual('a string response body'); expect(err.response.status).toBe(400); }); }); it('navigates to spa login page when the server responds with a 401', () => { (mockGetConfig as any).mockResolvedValueOnce({ redirectAuthFailure: { enabled: true, url: '/openmrs/spa/login', errors: [401], resolvePromise: true, }, }); // @ts-ignore window.fetch.mockReturnValue( Promise.resolve({ ok: false, status: 401, statusText: 'You are not authorized', text: () => Promise.resolve('a string response body'), }), ); return openmrsFetch('/ws/rest/v1/session').then((data) => { //@ts-ignore expect(mockNavigate.mock.calls[0][0]).toStrictEqual({ to: '/openmrs/spa/login', }); }); }); }); describe('openmrsObservableFetch', () => { beforeEach(() => { // @ts-ignore window.openmrsBase = '/openmrs'; window.fetch = jest.fn(); }); it('calls window.fetch with the correct arguments for a basic GET request', (done) => { // @ts-ignore window.fetch.mockReturnValue( Promise.resolve({ ok: true, status: 200, clone: () => ({ text: () => Promise.resolve('{"value": "hi"}'), }), }), ); const observable = openmrsObservableFetch('/ws/rest/v1/session'); expect(isObservable(observable)).toBe(true); observable.subscribe( (response) => { expect(response.data).toEqual({ value: 'hi' }); done(); }, (err) => { done.fail(err); }, ); expect(window.fetch).toHaveBeenCalled(); // @ts-ignore expect(window.fetch.mock.calls[0][0]).toEqual('/openmrs/ws/rest/v1/session'); // @ts-ignore expect(window.fetch.mock.calls[0][1].headers.Accept).toEqual('application/json'); }); it('aborts the fetch request when subscription is unsubscribed', () => { // @ts-ignore window.fetch.mockReturnValue(new Promise(() => {})); const subscription = openmrsObservableFetch('/ws/rest/v1/session').subscribe(); // @ts-ignore const abortSignal: AbortSignal = window.fetch.mock.calls[0][1].signal; expect(abortSignal.aborted).toBe(false); subscription.unsubscribe(); expect(abortSignal.aborted).toBe(true); }); });