From 44c6092d3a5a61463eb77b2e1e3fb7fe20263bd3 Mon Sep 17 00:00:00 2001 From: evansiroky Date: Fri, 9 Feb 2018 13:02:21 -0800 Subject: [PATCH 1/2] fix(bulk): gracefully handle unfound bulk result --- __tests__/__snapshots__/index.js.snap | 36 +++++++- __tests__/index.js | 90 ++++++++++++------- .../mock-bulk-result-with-bad-address.json | 1 + index.js | 22 +++++ 4 files changed, 117 insertions(+), 32 deletions(-) create mode 100644 __tests__/mock-bulk-result-with-bad-address.json diff --git a/__tests__/__snapshots__/index.js.snap b/__tests__/__snapshots__/index.js.snap index b134a1e..507698c 100644 --- a/__tests__/__snapshots__/index.js.snap +++ b/__tests__/__snapshots__/index.js.snap @@ -96,8 +96,6 @@ Object { } `; -exports[`basic bulk request uri 1`] = `"/arcgis/rest/services/World/GeocodeServer/geocodeAddresses"`; - exports[`basic reverse g-a-g response 1`] = ` Object { "features": Array [ @@ -251,3 +249,37 @@ Object { `; exports[`basic search request uri 1`] = `"/arcgis/rest/services/World/GeocodeServer/findAddressCandidates?outFields=*&maxLocations=10&SingleLine=123%20main%20st&f=json"`; + +exports[`bulk g-a-g response with no address found 1`] = ` +Object { + "features": Array [ + Object { + "geometry": Object { + "coordinates": Array [ + 0, + 0, + ], + "type": "point", + }, + "properties": Object { + "confidence": 0, + "country": "", + "country_a": "", + "county": "", + "label": "Address not found", + "locality": "", + "name": "", + "neighbourhood": "", + "region": "", + "resultId": 0, + }, + "type": "feature", + }, + ], + "query": Object { + "addresses": Array [ + "aefgjil", + ], + }, +} +`; diff --git a/__tests__/index.js b/__tests__/index.js index 766e653..7d524f2 100644 --- a/__tests__/index.js +++ b/__tests__/index.js @@ -5,19 +5,59 @@ import nock from 'nock' import {autocomplete, bulk, reverse, search} from '../index' const mockBulkResult = require('./mock-bulk-result.json') +const mockBulkResultWithBadAddress = require('./mock-bulk-result-with-bad-address.json') const mockReverseResult = require('./mock-reverse-result.json') const mockSearchResult = require('./mock-search-result.json') const mockSuggestResult = require('./mock-suggest-result.json') +function prepareNock ( + type: 'autocomplete' | 'bulk' | 'search' | 'reverse', + snapshotUri = true, + response?: Object +) { + if (type === 'bulk') { + // nock for auth token + nock('https://www.arcgis.com/') + .post(/sharing\/oauth2\/token/) + .reply(200, { access_token: 'test', expires_in: 86400 }) + } + + let n = nock('https://geocode.arcgis.com/') + + switch (type) { + case 'autocomplete': + n = n.get(/arcgis\/rest\/services\/World\/GeocodeServer\/suggest/) + response = response || mockSuggestResult + break + case 'bulk': + n = n.post(/arcgis\/rest\/services\/World\/GeocodeServer\/geocodeAddresses/) + response = response || mockBulkResult + break + case 'reverse': + n = n.get(/arcgis\/rest\/services\/World\/GeocodeServer\/reverseGeocode/) + response = response || mockReverseResult + break + case 'search': + n = n.get(/arcgis\/rest\/services\/World\/GeocodeServer\/findAddressCandidates/) + response = response || mockSearchResult + break + default: + throw new Error('invalid type') + } + + n.reply(200, (uri, requestBody) => { + if (snapshotUri) { + expect(uri).toMatchSnapshot(`basic ${type} request uri`) + } + + return response + }) +} + describe('geocoder-arcgis-geojson', () => { describe('autocomplete', () => { it('should make basic autocomplete query', async () => { - nock('https://geocode.arcgis.com/') - .get(/arcgis\/rest\/services\/World\/GeocodeServer\/suggest/) - .reply(200, (uri, requestBody) => { - expect(uri).toMatchSnapshot('basic autocomplete request uri') - return mockSuggestResult - }) + prepareNock('autocomplete') const result = await autocomplete({ text: '123 main st' @@ -28,18 +68,7 @@ describe('geocoder-arcgis-geojson', () => { describe('bulk', () => { it('should make basic bulk query', async () => { - // nock for auth token - nock('https://www.arcgis.com/') - .post(/sharing\/oauth2\/token/) - .reply(200, { access_token: 'test', expires_in: 86400 }) - - // nock for bulk geocode reqeust - nock('https://geocode.arcgis.com/') - .post(/arcgis\/rest\/services\/World\/GeocodeServer\/geocodeAddresses/) - .reply(200, (uri, requestBody) => { - expect(uri).toMatchSnapshot('basic bulk request uri') - return mockBulkResult - }) + prepareNock('bulk', false) const result = await bulk({ addresses: ['123 main st'], @@ -48,16 +77,22 @@ describe('geocoder-arcgis-geojson', () => { }) expect(result).toMatchSnapshot('basic bulk g-a-g response') }) + + it('should handle bulk query resulting in no address found', async () => { + prepareNock('bulk', false, mockBulkResultWithBadAddress) + + const result = await bulk({ + addresses: ['aefgjil'], + clientId: 'test', + clientSecret: 'test' + }) + expect(result).toMatchSnapshot('bulk g-a-g response with no address found') + }) }) describe('reverse', () => { it('should make basic reverse query', async () => { - nock('https://geocode.arcgis.com/') - .get(/arcgis\/rest\/services\/World\/GeocodeServer\/reverseGeocode/) - .reply(200, (uri, requestBody) => { - expect(uri).toMatchSnapshot('basic reverse request uri') - return mockReverseResult - }) + prepareNock('reverse') const result = await reverse({ point: { @@ -71,12 +106,7 @@ describe('geocoder-arcgis-geojson', () => { describe('search', () => { it('should make basic search query', async () => { - nock('https://geocode.arcgis.com/') - .get(/arcgis\/rest\/services\/World\/GeocodeServer\/findAddressCandidates/) - .reply(200, (uri, requestBody) => { - expect(uri).toMatchSnapshot('basic search request uri') - return mockSearchResult - }) + prepareNock('search') const result = await search({ text: '123 main st' diff --git a/__tests__/mock-bulk-result-with-bad-address.json b/__tests__/mock-bulk-result-with-bad-address.json new file mode 100644 index 0000000..3e29903 --- /dev/null +++ b/__tests__/mock-bulk-result-with-bad-address.json @@ -0,0 +1 @@ +{"spatialReference":{"wkid":4326,"latestWkid":4326},"locations":[{"address":"","score":0,"attributes":{"ResultID":0,"Loc_name":"","Status":"U","Score":0,"Match_addr":"","LongLabel":"","ShortLabel":"","Addr_type":"","Type":"","PlaceName":"","Place_addr":"","Phone":"","URL":"","Rank":0,"AddBldg":"","AddNum":"","AddNumFrom":"","AddNumTo":"","AddRange":"","Side":"","StPreDir":"","StPreType":"","StName":"","StType":"","StDir":"","BldgType":"","BldgName":"","LevelType":"","LevelName":"","UnitType":"","UnitName":"","SubAddr":"","StAddr":"","Block":"","Sector":"","Nbrhd":"","District":"","City":"","MetroArea":"","Subregion":"","Region":"","RegionAbbr":"","Territory":"","Zone":"","Postal":"","PostalExt":"","Country":"","LangCode":"","Distance":0,"X":0,"Y":0,"DisplayX":0,"DisplayY":0,"Xmin":0,"Xmax":0,"Ymin":0,"Ymax":0,"ExInfo":""}}]} diff --git a/index.js b/index.js index 44a26ae..607c482 100644 --- a/index.js +++ b/index.js @@ -55,6 +55,28 @@ function getGeocoder (clientId: ?string, clientSecret: ?string, endpoint: ?strin * Translate arcgis candidate json to geojson */ function candidateToGeojson (candidate) { + if (!candidate.location) { + // no result found for this candidate + return { + geometry: { + coordinates: [0, 0], + type: 'point' + }, + properties: { + confidence: 0, + country: '', + country_a: '', + county: '', + label: 'Address not found', + locality: '', + name: '', + neighbourhood: '', + region: '', + resultId: candidate.attributes.ResultID // this only appears in bulk geocode results + }, + type: 'feature' + } + } return { geometry: { coordinates: lonlat.toCoordinates(candidate.location), From b00a611b399eadff14ebd410e8b520f48b3227bf Mon Sep 17 00:00:00 2001 From: evansiroky Date: Wed, 14 Feb 2018 11:00:28 -0800 Subject: [PATCH 2/2] refactor(test): use composable functions --- __tests__/index.js | 72 ++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 44 deletions(-) diff --git a/__tests__/index.js b/__tests__/index.js index 7d524f2..a01c371 100644 --- a/__tests__/index.js +++ b/__tests__/index.js @@ -10,54 +10,31 @@ const mockReverseResult = require('./mock-reverse-result.json') const mockSearchResult = require('./mock-search-result.json') const mockSuggestResult = require('./mock-suggest-result.json') -function prepareNock ( - type: 'autocomplete' | 'bulk' | 'search' | 'reverse', - snapshotUri = true, - response?: Object -) { - if (type === 'bulk') { - // nock for auth token - nock('https://www.arcgis.com/') - .post(/sharing\/oauth2\/token/) - .reply(200, { access_token: 'test', expires_in: 86400 }) - } - - let n = nock('https://geocode.arcgis.com/') - - switch (type) { - case 'autocomplete': - n = n.get(/arcgis\/rest\/services\/World\/GeocodeServer\/suggest/) - response = response || mockSuggestResult - break - case 'bulk': - n = n.post(/arcgis\/rest\/services\/World\/GeocodeServer\/geocodeAddresses/) - response = response || mockBulkResult - break - case 'reverse': - n = n.get(/arcgis\/rest\/services\/World\/GeocodeServer\/reverseGeocode/) - response = response || mockReverseResult - break - case 'search': - n = n.get(/arcgis\/rest\/services\/World\/GeocodeServer\/findAddressCandidates/) - response = response || mockSearchResult - break - default: - throw new Error('invalid type') - } +const ARCGIS_GEOCODE_URL = 'https://geocode.arcgis.com/' +const BULK_URL = /arcgis\/rest\/services\/World\/GeocodeServer\/geocodeAddresses/ +const REVERSE_URL = /arcgis\/rest\/services\/World\/GeocodeServer\/reverseGeocode/ +const SEARCH_URL = /arcgis\/rest\/services\/World\/GeocodeServer\/findAddressCandidates/ +const SUGGEST_URL = /arcgis\/rest\/services\/World\/GeocodeServer\/suggest/ + +function nockArcGet (url: RegExp) { + return nock(ARCGIS_GEOCODE_URL).get(url) +} - n.reply(200, (uri, requestBody) => { - if (snapshotUri) { - expect(uri).toMatchSnapshot(`basic ${type} request uri`) - } +function nockArcPost (url: RegExp) { + return nock(ARCGIS_GEOCODE_URL).post(url) +} +function snapshotUri (type: string, response: Object) { + return (uri, requestBody) => { + expect(uri).toMatchSnapshot(`basic ${type} request uri`) return response - }) + } } describe('geocoder-arcgis-geojson', () => { describe('autocomplete', () => { it('should make basic autocomplete query', async () => { - prepareNock('autocomplete') + nockArcGet(SUGGEST_URL).reply(200, snapshotUri('autocomplete', mockSuggestResult)) const result = await autocomplete({ text: '123 main st' @@ -67,8 +44,15 @@ describe('geocoder-arcgis-geojson', () => { }) describe('bulk', () => { + beforeEach(() => { + // nock for auth token + nock('https://www.arcgis.com/') + .post(/sharing\/oauth2\/token/) + .reply(200, { access_token: 'test', expires_in: 86400 }) + }) + it('should make basic bulk query', async () => { - prepareNock('bulk', false) + nockArcPost(BULK_URL).reply(200, mockBulkResult) const result = await bulk({ addresses: ['123 main st'], @@ -79,7 +63,7 @@ describe('geocoder-arcgis-geojson', () => { }) it('should handle bulk query resulting in no address found', async () => { - prepareNock('bulk', false, mockBulkResultWithBadAddress) + nockArcPost(BULK_URL).reply(200, mockBulkResultWithBadAddress) const result = await bulk({ addresses: ['aefgjil'], @@ -92,7 +76,7 @@ describe('geocoder-arcgis-geojson', () => { describe('reverse', () => { it('should make basic reverse query', async () => { - prepareNock('reverse') + nockArcGet(REVERSE_URL).reply(200, snapshotUri('reverse', mockReverseResult)) const result = await reverse({ point: { @@ -106,7 +90,7 @@ describe('geocoder-arcgis-geojson', () => { describe('search', () => { it('should make basic search query', async () => { - prepareNock('search') + nockArcGet(SEARCH_URL).reply(200, snapshotUri('search', mockSearchResult)) const result = await search({ text: '123 main st'