Skip to content

Commit

Permalink
Migrate from XMLHttpRequest to fetch API
Browse files Browse the repository at this point in the history
  • Loading branch information
simon04 committed Dec 15, 2024
1 parent ce88eab commit fe751be
Show file tree
Hide file tree
Showing 11 changed files with 69 additions and 82 deletions.
10 changes: 6 additions & 4 deletions spec/arcgis.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { describe, expect, it, vi } from 'vitest';
import { testXMLHttpRequest } from './mockXMLHttpRequest';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { mockFetchRequest } from './mockFetchRequest';
import { ArcGis } from '../src/geocoders/arcgis';

describe('L.Control.Geocoder.ArcGis', () => {
it('geocodes Innsbruck', () => {
afterEach(() => vi.clearAllMocks());
it('geocodes Innsbruck', async () => {
const geocoder = new ArcGis();
const callback = vi.fn();
testXMLHttpRequest(
mockFetchRequest(
'https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/findAddressCandidates?token=&SingleLine=Innsbruck&outFields=Addr_Type&forStorage=false&maxLocations=10&f=json',
{
spatialReference: { wkid: 4326, latestWkid: 4326 },
Expand All @@ -28,6 +29,7 @@ describe('L.Control.Geocoder.ArcGis', () => {
() => geocoder.geocode('Innsbruck', callback)
);

await vi.waitUntil(() => callback.mock.calls.length);
const feature = callback.mock.calls[0][0][0];
expect(feature.name).toBe('Innsbruck, Innsbruck-Stadt, Tirol');
expect(feature.center).toStrictEqual({ lat: 47.26800000000003, lng: 11.391300000000058 });
Expand Down
10 changes: 6 additions & 4 deletions spec/google.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { describe, expect, it, vi } from 'vitest';
import { testXMLHttpRequest } from './mockXMLHttpRequest';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { mockFetchRequest } from './mockFetchRequest';
import { Google } from '../src/geocoders/google';
import { GeocodingResult } from '../src/geocoders/api';

describe('L.Control.Geocoder.Google', () => {
it('geocodes Innsbruck', () => {
afterEach(() => vi.clearAllMocks());
it('geocodes Innsbruck', async () => {
const geocoder = new Google({ apiKey: '0123xyz' });
const callback = vi.fn();
testXMLHttpRequest(
mockFetchRequest(
'https://maps.googleapis.com/maps/api/geocode/json?key=0123xyz&address=Innsbruck',
{
results: [
Expand Down Expand Up @@ -71,6 +72,7 @@ describe('L.Control.Geocoder.Google', () => {
() => geocoder.geocode('Innsbruck', callback)
);

await vi.waitUntil(() => callback.mock.calls.length);
const feature: GeocodingResult = callback.mock.calls[0][0][0];
expect(feature.name).toBe('Innsbruck, Austria');
expect(feature.center).toStrictEqual({ lat: 47.2692124, lng: 11.4041024 });
Expand Down
15 changes: 9 additions & 6 deletions spec/here.spec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { describe, expect, it, vi } from 'vitest';
import { testXMLHttpRequest } from './mockXMLHttpRequest';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { mockFetchRequest } from './mockFetchRequest';
import { HERE } from '../src/geocoders/here';
import { HEREv2 } from '../src/geocoders/here';
import { GeocodingResult } from '../src/geocoders/api';

describe('L.Control.Geocoder.HERE', () => {
it('geocodes Innsbruck', () => {
afterEach(() => vi.clearAllMocks());
it('geocodes Innsbruck', async () => {
const geocoder = new HERE({ app_id: 'xxx', app_code: 'yyy' });
const callback = vi.fn();
testXMLHttpRequest(
mockFetchRequest(
'https://geocoder.api.here.com/6.2/geocode.json?searchtext=Innsbruck&gen=9&app_id=xxx&app_code=yyy&jsonattributes=1&maxresults=5',
{
response: {
Expand Down Expand Up @@ -77,6 +78,7 @@ describe('L.Control.Geocoder.HERE', () => {
() => geocoder.geocode('Innsbruck', callback)
);

await vi.waitUntil(() => callback.mock.calls.length);
const feature: GeocodingResult = callback.mock.calls[0][0][0];
expect(feature.name).toBe('Innsbruck, Tirol, Österreich');
expect(feature.center).toStrictEqual({ lat: 47.268, lng: 11.3913 });
Expand All @@ -89,11 +91,11 @@ describe('L.Control.Geocoder.HERE', () => {
});

describe('L.Control.Geocoder.HEREv2', () => {
it('geocodes Innsbruck', () => {
it('geocodes Innsbruck', async () => {
const geocodingParams = { at: '50.62925,3.057256' };
const geocoder = new HEREv2({ apiKey: 'xxx', geocodingQueryParams: geocodingParams });
const callback = vi.fn();
testXMLHttpRequest(
mockFetchRequest(
'https://geocode.search.hereapi.com/v1/discover?q=Innsbruck&apiKey=xxx&limit=10&at=50.62925%2C3.057256',
{
items: [
Expand Down Expand Up @@ -167,6 +169,7 @@ describe('L.Control.Geocoder.HEREv2', () => {
() => geocoder.geocode('Innsbruck', callback)
);

await vi.waitUntil(() => callback.mock.calls.length);
const feature: GeocodingResult = callback.mock.calls[0][0][0];
expect(feature.name).toBe(
'Salumeria Italiana, 151 Richmond St, Boston, MA 02109, United States'
Expand Down
3 changes: 2 additions & 1 deletion spec/latlng.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import * as L from 'leaflet';
import { LatLng } from '../src/geocoders/latlng';

describe('LatLng', () => {
afterEach(() =>vi.clearAllMocks())
// test cases from https://github.com/openstreetmap/openstreetmap-website/blob/master/test/controllers/geocoder_controller_test.rb
let expected;
beforeEach(() => {
Expand Down
10 changes: 6 additions & 4 deletions spec/mapbox.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { describe, expect, it, vi } from 'vitest';
import { testXMLHttpRequest } from './mockXMLHttpRequest';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { mockFetchRequest } from './mockFetchRequest';
import { Mapbox } from '../src/geocoders/mapbox';

describe('L.Control.Geocoder.Mapbox', () => {
it('geocodes Milwaukee Ave', () => {
afterEach(() => vi.clearAllMocks());
it('geocodes Milwaukee Ave', async () => {
const geocoder = new Mapbox({ apiKey: '0123' });
const callback = vi.fn();
testXMLHttpRequest(
mockFetchRequest(
'https://api.mapbox.com/geocoding/v5/mapbox.places/Milwaukee%20Ave.json?access_token=0123',
{
type: 'FeatureCollection',
Expand Down Expand Up @@ -66,6 +67,7 @@ describe('L.Control.Geocoder.Mapbox', () => {
() => geocoder.geocode('Milwaukee Ave', callback)
);

await vi.waitUntil(() => callback.mock.calls.length);
const feature = callback.mock.calls[0][0][0];
expect(feature.name).toBe('825 Milwaukee Ave, Deerfield, Illinois 60015, United States');
expect(feature.center).toStrictEqual({ lat: 42.166602, lng: -87.921434 });
Expand Down
14 changes: 14 additions & 0 deletions spec/mockFetchRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { expect, vi } from 'vitest';

export function mockFetchRequest<T>(url: string, response: T, trigger: () => void) {
const headers = { Accept: 'application/json' };
global.fetch = vi.fn(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve(response)
})
) as any;
trigger();
expect(fetch).toBeCalledTimes(1);
expect(fetch).toBeCalledWith(url, { headers });
}
22 changes: 0 additions & 22 deletions spec/mockXMLHttpRequest.ts

This file was deleted.

18 changes: 10 additions & 8 deletions spec/nominatim.spec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { describe, expect, it, vi } from 'vitest';
import { testXMLHttpRequest } from './mockXMLHttpRequest';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { mockFetchRequest } from './mockFetchRequest';
import { Nominatim } from '../src/geocoders/nominatim';

describe('L.Control.Geocoder.Nominatim', () => {
afterEach(() => vi.clearAllMocks());
const geocoder = new Nominatim();

it('geocodes Innsbruck', () => {
it('geocodes Innsbruck', async () => {
const callback = vi.fn();

testXMLHttpRequest(
mockFetchRequest(
'https://nominatim.openstreetmap.org/search?q=innsbruck&limit=5&format=json&addressdetails=1',
[
{
Expand All @@ -23,8 +24,7 @@ describe('L.Control.Geocoder.Nominatim', () => {
class: 'boundary',
type: 'administrative',
importance: 0.763909048330467,
icon:
'https://nominatim.openstreetmap.org/images/mapicons/poi_boundary_administrative.p.20.png',
icon: 'https://nominatim.openstreetmap.org/images/mapicons/poi_boundary_administrative.p.20.png',
address: {
city_district: 'Innsbruck',
city: 'Innsbruck',
Expand All @@ -38,6 +38,7 @@ describe('L.Control.Geocoder.Nominatim', () => {
() => geocoder.geocode('innsbruck', callback)
);

await vi.waitUntil(() => callback.mock.calls.length);
const feature = callback.mock.calls[0][0][0];
expect(feature.name).toBe('Innsbruck, Tyrol, Austria');
expect(feature.html).toBe(
Expand All @@ -54,10 +55,10 @@ describe('L.Control.Geocoder.Nominatim', () => {
expect(callback.mock.calls).toMatchSnapshot();
});

it('reverse geocodes 47.3/11.3', () => {
it('reverse geocodes 47.3/11.3', async () => {
const callback = vi.fn();

testXMLHttpRequest(
mockFetchRequest(
'https://nominatim.openstreetmap.org/reverse?lat=47.3&lon=11.3&zoom=9&addressdetails=1&format=json',
{
place_id: 197718025,
Expand All @@ -78,6 +79,7 @@ describe('L.Control.Geocoder.Nominatim', () => {
() => geocoder.reverse({ lat: 47.3, lng: 11.3 }, 131000, callback)
);

await vi.waitUntil(() => callback.mock.calls.length);
const feature = callback.mock.calls[0][0][0];
expect(feature.name).toBe('Innsbruck-Land, Tyrol, Austria');
expect(feature.html).toBe('<span class="">Tyrol Austria</span>');
Expand Down
10 changes: 6 additions & 4 deletions spec/pelias.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { describe, expect, it, vi } from 'vitest';
import { testXMLHttpRequest } from './mockXMLHttpRequest';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { mockFetchRequest } from './mockFetchRequest';
import { Openrouteservice } from '../src/geocoders/pelias';

describe('L.Control.Geocoder.Openrouteservice', () => {
afterEach(() => vi.clearAllMocks());
const geocoder = new Openrouteservice({ apiKey: '0123' });

it('geocodes Innsbruck', () => {
it('geocodes Innsbruck', async () => {
const callback = vi.fn();
testXMLHttpRequest(
mockFetchRequest(
'https://api.openrouteservice.org/geocode/search?api_key=0123&text=innsbruck',
{
geocoding: {
Expand Down Expand Up @@ -49,6 +50,7 @@ describe('L.Control.Geocoder.Openrouteservice', () => {
() => geocoder.geocode('innsbruck', callback)
);

await vi.waitUntil(() => callback.mock.calls.length);
const feature = callback.mock.calls[0][0][0];
expect(feature.name).toBe('Innsbruck, Austria');
expect(feature.center).toStrictEqual({ lat: 47.272308, lng: 11.407851 });
Expand Down
10 changes: 6 additions & 4 deletions spec/photon.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { describe, expect, it, vi } from 'vitest';
import { testXMLHttpRequest } from './mockXMLHttpRequest';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { mockFetchRequest } from './mockFetchRequest';
import { Photon } from '../src/geocoders/photon';
import { GeocodingResult } from '../src/geocoders/api';

describe('L.Control.Geocoder.Photon', () => {
it('geocodes Innsbruck', () => {
afterEach(() => vi.clearAllMocks());
it('geocodes Innsbruck', async () => {
const geocoder = new Photon();
const callback = vi.fn();
testXMLHttpRequest(
mockFetchRequest(
'https://photon.komoot.io/api/?q=Innsbruck',
{
features: [
Expand Down Expand Up @@ -54,6 +55,7 @@ describe('L.Control.Geocoder.Photon', () => {
() => geocoder.geocode('Innsbruck', callback)
);

await vi.waitUntil(() => callback.mock.calls.length);
const feature: GeocodingResult = callback.mock.calls[0][0][0];
expect(feature.name).toBe('Innsbruck, Innsbruck, Tyrol, Austria');
expect(feature.center).toStrictEqual({ lat: 47.2654296, lng: 11.3927685 });
Expand Down
29 changes: 4 additions & 25 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,31 +56,10 @@ export function getJSON(
params: Record<string, unknown>,
callback: (message: any) => void
): void {
const xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = () => {
if (xmlHttp.readyState !== 4) {
return;
}
let message;
if (xmlHttp.status !== 200 && xmlHttp.status !== 304) {
message = '';
} else if (typeof xmlHttp.response === 'string') {
// IE doesn't parse JSON responses even with responseType: 'json'.
try {
message = JSON.parse(xmlHttp.response);
} catch (e) {
// Not a JSON response
message = xmlHttp.response;
}
} else {
message = xmlHttp.response;
}
callback(message);
};
xmlHttp.open('GET', url + getParamString(params), true);
xmlHttp.responseType = 'json';
xmlHttp.setRequestHeader('Accept', 'application/json');
xmlHttp.send(null);
const headers = { Accept: 'application/json' };
fetch(url + getParamString(params), { headers })
.then(response => response.json())
.then(j => callback(j));
}

/**
Expand Down

0 comments on commit fe751be

Please sign in to comment.