From 8267f0063db7f324601e901aa4d674ab30e8e8ce Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 10:35:24 +0300 Subject: [PATCH 01/33] feat(common/utils): added RequireKeys utility type --- src/common/utils.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/common/utils.ts b/src/common/utils.ts index 20abf606..75bc1508 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -153,6 +153,8 @@ export type RemoveUnderscore = { [K in keyof T as K extends `_${infer Rest}` ? Rest : K]: T[K]; }; +export type RequireKeys = Required> & Omit; + export const validateWGS84Coordinate = (coordinate: { lon: number; lat: number }): boolean => { // eslint-disable-next-line @typescript-eslint/no-magic-numbers const [min, max] = [0, 180]; From 196fe3cdd9ec63d4c728d56ef32f1340f071f945 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 10:36:22 +0300 Subject: [PATCH 02/33] fix(tile/queries): changed param type to only require tile and subTile --- src/control/tile/DAL/queries.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/control/tile/DAL/queries.ts b/src/control/tile/DAL/queries.ts index 35dadf7a..6e065202 100644 --- a/src/control/tile/DAL/queries.ts +++ b/src/control/tile/DAL/queries.ts @@ -2,7 +2,7 @@ import { estypes } from '@elastic/elasticsearch'; import { BBox } from 'geojson'; import { CommonRequestParameters } from '../../../common/interfaces'; import { ELASTIC_KEYWORDS } from '../../constants'; -import { ConvertSnakeToCamelCase, geoContextQuery, parseGeo } from '../../../common/utils'; +import { ConvertSnakeToCamelCase, geoContextQuery, parseGeo, RequireKeys } from '../../../common/utils'; export interface TileQueryParams extends ConvertSnakeToCamelCase { tile?: string; @@ -46,7 +46,7 @@ export const queryForSubTiles = ({ geoContextMode, subTile, disableFuzziness, -}: Omit, 'mgrs'>): estypes.SearchRequest => ({ +}: RequireKeys, 'tile' | 'subTile'>): estypes.SearchRequest => ({ query: { bool: { must: [ From cfaf42925f8ade3a23c23ce13c4e503efdf26dce Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 10:36:53 +0300 Subject: [PATCH 03/33] fix(contro/utils): changed max_score type to only be a number --- src/control/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/utils.ts b/src/control/utils.ts index 2ae4f620..a8e84bd4 100644 --- a/src/control/utils.ts +++ b/src/control/utils.ts @@ -63,7 +63,7 @@ export const formatResponse = ( query: convertCamelToSnakeCase(requestParams as Record), response: { results_count: elasticResponse.hits.hits.length, - max_score: elasticResponse.hits.max_score ?? 0, + max_score: elasticResponse.hits.max_score as number, match_latency_ms: elasticResponse.took, }, }, From ba02809f16a180dab36dc9fd6cf4dbf5dd92f42b Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 10:37:57 +0300 Subject: [PATCH 04/33] feat: moved all mock objects under one folder at the top of tests directory --- tests/mockObjects/items.ts | 99 ++++++++ tests/mockObjects/locations.ts | 403 +++++++++++++++++++++++++++++++++ tests/mockObjects/routes.ts | 76 +++++++ tests/mockObjects/tiles.ts | 86 +++++++ 4 files changed, 664 insertions(+) create mode 100644 tests/mockObjects/items.ts create mode 100644 tests/mockObjects/locations.ts create mode 100644 tests/mockObjects/routes.ts create mode 100644 tests/mockObjects/tiles.ts diff --git a/tests/mockObjects/items.ts b/tests/mockObjects/items.ts new file mode 100644 index 00000000..2037d950 --- /dev/null +++ b/tests/mockObjects/items.ts @@ -0,0 +1,99 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +/* eslint-disable @typescript-eslint/no-magic-numbers */ +import { Item } from '../../src/control/item/models/item'; + +export const ITEM_1234: Item = { + type: 'Feature', + geometry: { + coordinates: [ + [ + [12.432792582620323, 41.9327692706986], + [12.432648028923637, 41.93209008126263], + [12.43295235249525, 41.93189198298137], + [12.435105441764364, 41.93235609798671], + [12.435516278586334, 41.93274663116725], + [12.43637599267521, 41.93308056343986], + [12.436026020567567, 41.93386161853829], + [12.432792582620323, 41.9327692706986], + ], + ], + type: 'Polygon', + }, + properties: { + LAYER_NAME: 'CONTROL.ITEMS', + OBJECT_COMMAND_NAME: '1234', + TILE_NAME: 'RIT', + SUB_TILE_ID: '37', + ENTITY_HEB: 'hotel', + TYPE: 'ITEM', + }, +}; + +export const ITEM_1235: Item = { + type: 'Feature', + geometry: { + coordinates: [ + [ + [12.454224879037952, 41.93533128513971], + [12.4536294370983, 41.93493944442386], + [12.453354617740985, 41.934479454425286], + [12.453308814515196, 41.93386612926582], + [12.453789748389482, 41.933065390320394], + [12.454660009686364, 41.93255427509931], + [12.455667680662373, 41.93265649847106], + [12.456217319376208, 41.933355020461335], + [12.456217319376208, 41.934309086916585], + [12.45569058227531, 41.935092773686364], + [12.454957730656645, 41.93534832163783], + [12.454224879037952, 41.93533128513971], + ], + ], + type: 'Polygon', + }, + properties: { + LAYER_NAME: 'CONTROL.ITEMS', + OBJECT_COMMAND_NAME: '1235', + TILE_NAME: 'RIT', + SUB_TILE_ID: '37', + ENTITY_HEB: 'oplympic stadium', + TYPE: 'ITEM', + }, +}; + +export const ITEM_1236: Item = { + type: 'Feature', + geometry: { + coordinates: [ + [ + [12.508591887289015, 41.908719199148294], + [12.5109416268715, 41.90414674778023], + [12.515619548794433, 41.905558627360875], + [12.514541686600694, 41.906697734719614], + [12.514929038978266, 41.9065233923005], + [12.515546733877699, 41.90711121610428], + [12.51436197480865, 41.90815873484965], + [12.513612640013008, 41.90876915151631], + [12.512974692823434, 41.90872393566693], + [12.512863305218872, 41.90807583830912], + [12.513561316395936, 41.90754911551221], + [12.513962675013943, 41.907221129768516], + [12.51419876831929, 41.906986853205694], + [12.513954805237745, 41.906893142339726], + [12.512516460769376, 41.90804005137895], + [12.511855399516293, 41.90857302052004], + [12.51176096219396, 41.908660872149284], + [12.508762577222939, 41.908924426310676], + [12.508591887289015, 41.908719199148294], + ], + ], + type: 'Polygon', + }, + properties: { + LAYER_NAME: 'CONTROL.ITEMS', + OBJECT_COMMAND_NAME: '1236', + TILE_NAME: 'RIT', + SUB_TILE_ID: '38', + ENTITY_HEB: 'hospital', + TYPE: 'ITEM', + }, +}; diff --git a/tests/mockObjects/locations.ts b/tests/mockObjects/locations.ts new file mode 100644 index 00000000..2bdadd1d --- /dev/null +++ b/tests/mockObjects/locations.ts @@ -0,0 +1,403 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +/* eslint-disable @typescript-eslint/no-magic-numbers */ +import { Feature } from 'geojson'; +import { GenericGeocodingResponse } from '../../src/common/interfaces'; +import { HierarchySearchHit } from '../../src/location/models/elasticsearchHits'; + +export type MockLocationQueryFeature = GenericGeocodingResponse['features'][number]; + +export const NY_JFK_AIRPORT: MockLocationQueryFeature = { + type: 'Feature', + geometry: { + type: 'Polygon', + coordinates: [ + [ + [-73.81278266814672, 40.66039916690434], + [-73.8177430790069, 40.66160065836647], + [-73.82178645734075, 40.66043068890016], + [-73.82341214553732, 40.658185554886586], + [-73.82407909454082, 40.65496001884071], + [-73.8229536180974, 40.650532558586235], + [-73.82211993184252, 40.647939195437345], + [-73.81290769732489, 40.643985699842915], + [-73.79214887014153, 40.63414837731818], + [-73.78339516446982, 40.62987771430167], + [-73.7898562329419, 40.62275933562921], + [-73.78443726476769, 40.620069953803636], + [-73.7791433570518, 40.627188619100366], + [-73.77639219241223, 40.62706207167477], + [-73.77159849644941, 40.62336045339214], + [-73.77209870820208, 40.619975033140975], + [-73.77047302000595, 40.61908910045176], + [-73.76547094984971, 40.628422477310664], + [-73.75338249916041, 40.63291467256053], + [-73.74733827381596, 40.63601474373485], + [-73.7467963777506, 40.64208793530722], + [-73.752548854642, 40.64749646458006], + [-73.76213624656812, 40.65309424493557], + [-73.78181122379466, 40.66270746643491], + [-73.79106514121902, 40.66438330508498], + [-73.7957754685564, 40.665205399216404], + [-73.79856831750864, 40.66283394629252], + [-73.80390390953731, 40.66175885985783], + [-73.8073637074931, 40.66039916690434], + [-73.8109068740743, 40.66074699797244], + [-73.81278266814672, 40.66039916690434], + ], + ], + }, + properties: { + matches: [{ source: 'OSM', layer: 'osm_airports', source_id: ['03ed6d97-fc81-4340-b68a-11993554eef1'] }], + names: { + en: ['JFK Airport'], + fr: ['Aeropuerto JFK'], + default: ['JFK'], + display: 'JFK Airport', + }, + placetype: 'transportation', + sub_placetype: 'airport', + regions: [ + { + region: 'USA', + sub_region_names: ['New York'], + }, + ], + }, +}; + +export const NY_POLICE_AIRPORT: MockLocationQueryFeature = { + type: 'Feature', + geometry: { + coordinates: [ + [ + [-73.50019138870562, 40.76503398530525], + [-73.49991804403106, 40.75762191351754], + [-73.50172211928987, 40.75368779651572], + [-73.502924836068, 40.74958778448408], + [-73.50095675396722, 40.746067370663354], + [-73.49587254187276, 40.74117989901089], + [-73.48810955136324, 40.74010295019133], + [-73.4862508071566, 40.74097279482331], + [-73.48450140084462, 40.74209114977816], + [-73.48335335295225, 40.743250905424986], + [-73.49368578398266, 40.7500847690697], + [-73.49363111503533, 40.75112014169309], + [-73.49166303293454, 40.75087165373341], + [-73.49128035030373, 40.75435040065955], + [-73.48406404926651, 40.75385344795657], + [-73.4860321313673, 40.75840870869581], + [-73.50019138870562, 40.76503398530525], + ], + ], + type: 'Polygon', + }, + properties: { + matches: [{ source: 'OSM', layer: 'osm_airports', source_id: ['009c6b65-3dcb-4c4f-9f02-d766ebb5d808'] }], + names: { + en: ['Nassau County Police Airport'], + fr: ['Aeropuerto de la Policía del Condado de Nassau'], + default: ['Nassau County Police Airport'], + display: 'Nassau County Police Airport', + }, + placetype: 'transportation', + sub_placetype: 'airport', + regions: [ + { + region: 'USA', + sub_region_names: ['New York'], + }, + ], + }, +}; + +export const LA_AIRPORT: MockLocationQueryFeature = { + type: 'Feature', + geometry: { + coordinates: [ + [ + [-118.42713070992883, 33.9512236894319], + [-118.43440343023548, 33.94992163234602], + [-118.43571147345608, 33.94670980636225], + [-118.43560682999878, 33.943107208682775], + [-118.43325235220159, 33.938723119106925], + [-118.42875268352236, 33.9310829780122], + [-118.41394563426408, 33.931820976094315], + [-118.39756893251248, 33.932255089782316], + [-118.38516868278077, 33.935250412835686], + [-118.37904703905322, 33.936509285268926], + [-118.37899471732432, 33.943367642688045], + [-118.3788377519829, 33.94501703885841], + [-118.39181354073204, 33.94527746687625], + [-118.39510980964849, 33.945451085112225], + [-118.3980398264626, 33.94558129855595], + [-118.39746428744567, 33.949748023597365], + [-118.39720267894361, 33.953003135913036], + [-118.40813791735772, 33.95252573110099], + [-118.42713070992883, 33.9512236894319], + ], + ], + type: 'Polygon', + }, + properties: { + matches: [{ source: 'OSM', layer: 'osm_airports', source_id: ['a4f373ab-b824-41e2-b160-e7729c73bea6'] }], + names: { + en: ['Los Angeles International Airport'], + fr: ['Aeropuerto Internacional de Los Ángeles'], + default: ['Los Angeles International Airport'], + display: 'Los Angeles International Airport', + }, + placetype: 'transportation', + sub_placetype: 'airport', + regions: [ + { + region: 'USA', + sub_region_names: ['Los Angeles'], + }, + ], + }, +}; + +export const OSM_LA_PORT: MockLocationQueryFeature = { + type: 'Feature', + geometry: { + type: 'Polygon', + coordinates: [ + [ + [-118.2505781304088, 33.7502674389752], + [-118.25604403409116, 33.76075151051916], + [-118.27057180697577, 33.748593059782564], + [-118.27503083555426, 33.741097783576635], + [-118.2747911028351, 33.734798055529765], + [-118.27215404292296, 33.73136889520775], + [-118.26807858669537, 33.720881194108856], + [-118.26424286318695, 33.721997816398385], + [-118.26640045650717, 33.72901625632974], + [-118.2431463824787, 33.735794882347946], + [-118.24492040460113, 33.739303607948656], + [-118.25072193640723, 33.73794798097781], + [-118.25220827926702, 33.74193505797223], + [-118.24937943317966, 33.74508471776615], + [-118.24798898340768, 33.74783559181691], + [-118.24909175391655, 33.74803492708783], + [-118.25096166912684, 33.74600168558719], + [-118.25326310323155, 33.745363795966625], + [-118.25278363779321, 33.74687877606813], + [-118.2505781304088, 33.7502674389752], + ], + ], + }, + properties: { + matches: [{ source: 'OSM', layer: 'osm_ports', source_id: ['0f36d985-cfbd-4aed-b0cb-ee56600c77f4'] }], + names: { + en: ['Port of Los Angeles'], + fr: ['Puerto de Los Ángeles'], + default: ['Port of Los Angeles'], + display: 'Port of Los Angeles', + }, + placetype: 'transportation', + sub_placetype: 'port', + regions: [ + { + region: 'USA', + sub_region_names: ['Los Angeles'], + }, + ], + }, +}; +export const GOOGLE_LA_PORT: MockLocationQueryFeature = { + type: 'Feature', + geometry: { + type: 'Polygon', + coordinates: [ + [ + [-118.2505781304088, 33.7502674389752], + [-118.25604403409116, 33.76075151051916], + [-118.27057180697577, 33.748593059782564], + [-118.27503083555426, 33.741097783576635], + [-118.2747911028351, 33.734798055529765], + [-118.27215404292296, 33.73136889520775], + [-118.26807858669537, 33.720881194108856], + [-118.26424286318695, 33.721997816398385], + [-118.26640045650717, 33.72901625632974], + [-118.2431463824787, 33.735794882347946], + [-118.24492040460113, 33.739303607948656], + [-118.25072193640723, 33.73794798097781], + [-118.25220827926702, 33.74193505797223], + [-118.24937943317966, 33.74508471776615], + [-118.24798898340768, 33.74783559181691], + [-118.24909175391655, 33.74803492708783], + [-118.25096166912684, 33.74600168558719], + [-118.25326310323155, 33.745363795966625], + [-118.25278363779321, 33.74687877606813], + [-118.2505781304088, 33.7502674389752], + ], + ], + }, + properties: { + matches: [{ source: 'GOOGLE', layer: 'google_ports', source_id: ['1bb11f54-939e-457b-bf68-a3920ccf629c'] }], + names: { + en: ['Port of Los Angeles'], + fr: ['Puerto de Los Ángeles'], + default: ['Port of Los Angeles'], + display: 'Port of Los Angeles', + }, + placetype: 'transportation', + sub_placetype: 'port', + regions: [ + { + region: 'USA', + sub_region_names: ['Los Angeles'], + }, + ], + }, +}; + +export const LA_WHITE_POINT_SCHOOL: MockLocationQueryFeature = { + type: 'Feature', + geometry: { + coordinates: [ + [ + [-118.30812263653988, 33.71684417247593], + [-118.30861990876181, 33.71674433152869], + [-118.30879709771484, 33.71635922964194], + [-118.30619642115158, 33.71550819588987], + [-118.30586490633668, 33.715921827872904], + [-118.30587062210924, 33.716183318328746], + [-118.30812263653988, 33.71684417247593], + ], + ], + type: 'Polygon', + }, + properties: { + matches: [ + { + source: 'OSM', + layer: 'osm_schools', + source_id: ['1a5b981b-bb0e-44dd-b9e2-424b92f2de49'], + }, + ], + names: { + en: ['White Point Elementary School'], + fr: ['Escuela Primaria White Point'], + default: ['White Point Elementary School'], + display: 'White Point Elementary School', + }, + placetype: 'education', + sub_placetype: 'school', + regions: [ + { + region: 'USA', + sub_region_names: ['Los Angeles'], + }, + ], + }, +}; + +export const PARIS_WI_SCHOOL: MockLocationQueryFeature = { + type: 'Feature', + geometry: { + coordinates: [ + [ + [2.346441270696971, 48.88088750665477], + [2.3462780852304945, 48.88018258877358], + [2.347503576087604, 48.87999951892243], + [2.347737155284733, 48.88070864783427], + [2.346441270696971, 48.88088750665477], + ], + ], + type: 'Polygon', + }, + properties: { + matches: [ + { + source: 'OSM', + layer: 'osm_schools', + source_id: ['dc02a3f9-156a-4f61-85bd-fd040cd322a3'], + }, + ], + names: { + en: ['Wi School Paris 9'], + fr: ['Ecole Wi Paris 9'], + default: ['Wi School Paris 9'], + display: 'Wi School Paris 9', + }, + placetype: 'education', + sub_placetype: 'school', + regions: [ + { + region: 'FRANCE', + sub_region_names: ['Paris'], + }, + ], + }, +}; + +export const NY_HIERRARCHY: HierarchySearchHit = { + geo_json: { + coordinates: [ + [ + [-73.74286189030825, 40.566325396473786], + [-73.47084009765854, 40.56212896709357], + [-73.550927745189, 41.11163279131463], + [-73.74424271181776, 41.225972287315074], + [-73.99969469100891, 41.26438691280978], + [-74.24962338416366, 41.05959508414017], + [-74.13087273437748, 40.7506852054762], + [-74.00659879855483, 40.530651727069795], + [-73.74286189030825, 40.566325396473786], + ], + ], + type: 'Polygon', + }, + hierarchy: 'city', + placetype: 'city', + region: 'USA', + text: 'New York', + weight: 1.1, +}; + +export const LA_HIERRARCHY: HierarchySearchHit = { + geo_json: { + coordinates: [ + [ + [-118.54430957638033, 34.07939240620722], + [-118.5350828996408, 33.695192367610986], + [-118.04596133238863, 33.47690745532634], + [-117.66265886139905, 33.379872950239346], + [-117.57145361502153, 33.63336904289318], + [-117.67279277766329, 34.23871934668085], + [-118.2605599209839, 34.28059749364003], + [-118.54430957638033, 34.07939240620722], + ], + ], + type: 'Polygon', + }, + hierarchy: 'city', + placetype: 'city', + region: 'USA', + text: 'Los Angeles', + weight: 1.1, +}; + +export const PARIS_HIERRARCHY: HierarchySearchHit = { + geo_json: { + coordinates: [ + [ + [2.226678539753607, 49.06838747927134], + [1.9344166918067742, 48.906487548202136], + [2.014124468519668, 48.56855190252173], + [2.6536844864307625, 48.53463335095324], + [2.902296837606201, 48.82159183126478], + [2.6460932696008683, 49.0124047223114], + [2.384196288972504, 49.05097737411208], + [2.226678539753607, 49.06838747927134], + ], + ], + type: 'Polygon', + }, + hierarchy: 'city', + placetype: 'city', + region: 'FRANCE', + text: 'Paris', + weight: 1.1, +}; diff --git a/tests/mockObjects/routes.ts b/tests/mockObjects/routes.ts new file mode 100644 index 00000000..d0252209 --- /dev/null +++ b/tests/mockObjects/routes.ts @@ -0,0 +1,76 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +/* eslint-disable @typescript-eslint/no-magic-numbers */ + +import { Route } from '../../src/control/route/models/route'; + +export const ROUTE_VIA_CAMILLUCCIA_A: Route = { + type: 'Feature', + geometry: { + coordinates: [ + [12.443243654365062, 41.93890891937724], + [12.442636325462843, 41.93804302794496], + [12.442828646282095, 41.93725242115204], + [12.443405608739027, 41.93556576056804], + [12.44388471483822, 41.93370245333628], + [12.445132826188399, 41.93084467089824], + [12.445812354584433, 41.93031849813403], + [12.445819951137906, 41.930296776658196], + ], + type: 'LineString', + }, + properties: { + OBJECT_COMMAND_NAME: 'via camillucciaA', + ENTITY_HEB: 'route', + TYPE: 'ROUTE', + LAYER_NAME: 'CONTROL.ROUTES', + }, +}; +export const ROUTE_VIA_CAMILLUCCIA_B: Route = { + type: 'Feature', + geometry: { + coordinates: [ + [12.445818466287847, 41.93029376141277], + [12.446047161911423, 41.930040913942264], + [12.446171038707206, 41.9297762500957], + [12.446167862379838, 41.92945014491775], + [12.446075748864388, 41.9286136066203], + ], + type: 'LineString', + }, + properties: { + OBJECT_COMMAND_NAME: 'via camillucciaB', + ENTITY_HEB: 'route', + TYPE: 'ROUTE', + LAYER_NAME: 'CONTROL.ROUTES', + }, +}; + +export const CONTROL_POINT_OLIMPIADE_111: Route = { + type: 'Feature', + geometry: { + coordinates: [12.475638293442415, 41.932360642739155], + type: 'Point', + }, + properties: { + OBJECT_COMMAND_NAME: '111', + ENTITY_HEB: 'control point', + TIED_TO: 'olimpiade', + TYPE: 'ITEM' as never, + LAYER_NAME: 'CONTROL_GIL_GDB.CTR_CONTROL_POINT_CROSS_N', + }, +}; + +export const CONTROL_POINT_OLIMPIADE_112: Route = { + type: 'Feature', + geometry: { + coordinates: [12.474175672012962, 41.932217551210556], + type: 'Point', + }, + properties: { + OBJECT_COMMAND_NAME: '112', + ENTITY_HEB: 'control point', + TIED_TO: 'olimpiade', + TYPE: 'ITEM' as never, + LAYER_NAME: 'CONTROL_GIL_GDB.CTR_CONTROL_POINT_CROSS_N', + }, +}; diff --git a/tests/mockObjects/tiles.ts b/tests/mockObjects/tiles.ts new file mode 100644 index 00000000..923df454 --- /dev/null +++ b/tests/mockObjects/tiles.ts @@ -0,0 +1,86 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +/* eslint-disable @typescript-eslint/no-magic-numbers */ + +import { Tile } from '../../src/control/tile/models/tile'; + +export const RIT_TILE: Tile = { + type: 'Feature', + geometry: { + coordinates: [ + [ + [12.539507865186607, 41.851751203650096], + [12.536787075186538, 41.94185043165008], + [12.42879133518656, 41.93952837265009], + [12.431625055186686, 41.84943698365008], + [12.539507865186607, 41.851751203650096], + ], + ], + type: 'Polygon', + }, + properties: { + TILE_NAME: 'RIT', + TYPE: 'TILE', + }, +}; + +export const RIC_TILE: Tile = { + type: 'Feature', + properties: { + TILE_NAME: 'RIC', + TYPE: 'TILE', + }, + geometry: { + coordinates: [ + [ + [12.64750356570994, 41.854073129598774], + [12.64478277570987, 41.94417235759876], + [12.536787035709892, 41.941850298598766], + [12.539620755710018, 41.85175890959876], + [12.64750356570994, 41.854073129598774], + ], + ], + type: 'Polygon', + }, +}; + +export const SUB_TILE_66: Tile = { + type: 'Feature', + properties: { + SUB_TILE_ID: '66', + TILE_NAME: 'RIT', + TYPE: 'SUB_TILE', + }, + geometry: { + coordinates: [ + [ + [12.44999804325252, 41.930226156898485], + [12.45011422425253, 41.939247112898514], + [12.439626097252557, 41.93934663789851], + [12.439510908252515, 41.93032564689851], + [12.44999804325252, 41.930226156898485], + ], + ], + type: 'Polygon', + }, +}; + +export const SUB_TILE_65: Tile = { + type: 'Feature', + properties: { + SUB_TILE_ID: '65', + TILE_NAME: 'RIT', + TYPE: 'SUB_TILE', + }, + geometry: { + coordinates: [ + [ + [12.439530324602458, 41.93031190061167], + [12.439646505602468, 41.9393328566117], + [12.429158378602494, 41.939432381611695], + [12.429043189602453, 41.930411390611695], + [12.439530324602458, 41.93031190061167], + ], + ], + type: 'Polygon', + }, +}; From 78981de209c3bd0fe3fc7cfabf3ec7a9f6cde035 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 10:38:20 +0300 Subject: [PATCH 05/33] fix: removed mockOjbects and update import to the new directory --- tests/integration/control/item/item.spec.ts | 2 +- tests/integration/control/item/mockObjects.ts | 99 ----- .../integration/control/route/mockObjects.ts | 75 ---- tests/integration/control/route/route.spec.ts | 7 +- tests/integration/control/tile/mockObjects.ts | 85 ---- tests/integration/control/tile/tile.spec.ts | 2 +- tests/integration/location/location.spec.ts | 4 +- tests/integration/location/mockObjects.ts | 403 ------------------ tests/integration/location/utils.ts | 2 +- 9 files changed, 11 insertions(+), 668 deletions(-) delete mode 100644 tests/integration/control/item/mockObjects.ts delete mode 100644 tests/integration/control/route/mockObjects.ts delete mode 100644 tests/integration/control/tile/mockObjects.ts delete mode 100644 tests/integration/location/mockObjects.ts diff --git a/tests/integration/control/item/item.spec.ts b/tests/integration/control/item/item.spec.ts index 0fad0366..7e362261 100644 --- a/tests/integration/control/item/item.spec.ts +++ b/tests/integration/control/item/item.spec.ts @@ -13,8 +13,8 @@ import { CommonRequestParameters, GenericGeocodingResponse, GeoContext, GeoConte import { cronLoadTileLatLonDataSymbol } from '../../../../src/latLon/DAL/latLonDAL'; import { S3_REPOSITORY_SYMBOL } from '../../../../src/common/s3/s3Repository'; import { expectedResponse } from '../utils'; +import { ITEM_1234, ITEM_1235, ITEM_1236 } from '../../../mockObjects/items'; import { ItemRequestSender } from './helpers/requestSender'; -import { ITEM_1234, ITEM_1235, ITEM_1236 } from './mockObjects'; describe('/search/control/items', function () { let requestSender: ItemRequestSender; diff --git a/tests/integration/control/item/mockObjects.ts b/tests/integration/control/item/mockObjects.ts deleted file mode 100644 index 96a62178..00000000 --- a/tests/integration/control/item/mockObjects.ts +++ /dev/null @@ -1,99 +0,0 @@ -/* eslint-disable @typescript-eslint/naming-convention */ -/* eslint-disable @typescript-eslint/no-magic-numbers */ -import { Item } from '../../../../src/control/item/models/item'; - -export const ITEM_1234: Item = { - type: 'Feature', - geometry: { - coordinates: [ - [ - [12.432792582620323, 41.9327692706986], - [12.432648028923637, 41.93209008126263], - [12.43295235249525, 41.93189198298137], - [12.435105441764364, 41.93235609798671], - [12.435516278586334, 41.93274663116725], - [12.43637599267521, 41.93308056343986], - [12.436026020567567, 41.93386161853829], - [12.432792582620323, 41.9327692706986], - ], - ], - type: 'Polygon', - }, - properties: { - LAYER_NAME: 'CONTROL.ITEMS', - OBJECT_COMMAND_NAME: '1234', - TILE_NAME: 'RIT', - SUB_TILE_ID: '37', - ENTITY_HEB: 'hotel', - TYPE: 'ITEM', - }, -}; - -export const ITEM_1235: Item = { - type: 'Feature', - geometry: { - coordinates: [ - [ - [12.454224879037952, 41.93533128513971], - [12.4536294370983, 41.93493944442386], - [12.453354617740985, 41.934479454425286], - [12.453308814515196, 41.93386612926582], - [12.453789748389482, 41.933065390320394], - [12.454660009686364, 41.93255427509931], - [12.455667680662373, 41.93265649847106], - [12.456217319376208, 41.933355020461335], - [12.456217319376208, 41.934309086916585], - [12.45569058227531, 41.935092773686364], - [12.454957730656645, 41.93534832163783], - [12.454224879037952, 41.93533128513971], - ], - ], - type: 'Polygon', - }, - properties: { - LAYER_NAME: 'CONTROL.ITEMS', - OBJECT_COMMAND_NAME: '1235', - TILE_NAME: 'RIT', - SUB_TILE_ID: '37', - ENTITY_HEB: 'oplympic stadium', - TYPE: 'ITEM', - }, -}; - -export const ITEM_1236: Item = { - type: 'Feature', - geometry: { - coordinates: [ - [ - [12.508591887289015, 41.908719199148294], - [12.5109416268715, 41.90414674778023], - [12.515619548794433, 41.905558627360875], - [12.514541686600694, 41.906697734719614], - [12.514929038978266, 41.9065233923005], - [12.515546733877699, 41.90711121610428], - [12.51436197480865, 41.90815873484965], - [12.513612640013008, 41.90876915151631], - [12.512974692823434, 41.90872393566693], - [12.512863305218872, 41.90807583830912], - [12.513561316395936, 41.90754911551221], - [12.513962675013943, 41.907221129768516], - [12.51419876831929, 41.906986853205694], - [12.513954805237745, 41.906893142339726], - [12.512516460769376, 41.90804005137895], - [12.511855399516293, 41.90857302052004], - [12.51176096219396, 41.908660872149284], - [12.508762577222939, 41.908924426310676], - [12.508591887289015, 41.908719199148294], - ], - ], - type: 'Polygon', - }, - properties: { - LAYER_NAME: 'CONTROL.ITEMS', - OBJECT_COMMAND_NAME: '1236', - TILE_NAME: 'RIT', - SUB_TILE_ID: '38', - ENTITY_HEB: 'hospital', - TYPE: 'ITEM', - }, -}; diff --git a/tests/integration/control/route/mockObjects.ts b/tests/integration/control/route/mockObjects.ts deleted file mode 100644 index eb60440b..00000000 --- a/tests/integration/control/route/mockObjects.ts +++ /dev/null @@ -1,75 +0,0 @@ -/* eslint-disable @typescript-eslint/naming-convention */ -/* eslint-disable @typescript-eslint/no-magic-numbers */ -import { Route } from '../../../../src/control/route/models/route'; - -export const ROUTE_VIA_CAMILLUCCIA_A: Route = { - type: 'Feature', - geometry: { - coordinates: [ - [12.443243654365062, 41.93890891937724], - [12.442636325462843, 41.93804302794496], - [12.442828646282095, 41.93725242115204], - [12.443405608739027, 41.93556576056804], - [12.44388471483822, 41.93370245333628], - [12.445132826188399, 41.93084467089824], - [12.445812354584433, 41.93031849813403], - [12.445819951137906, 41.930296776658196], - ], - type: 'LineString', - }, - properties: { - OBJECT_COMMAND_NAME: 'via camillucciaA', - ENTITY_HEB: 'route', - TYPE: 'ROUTE', - LAYER_NAME: 'CONTROL.ROUTES', - }, -}; -export const ROUTE_VIA_CAMILLUCCIA_B: Route = { - type: 'Feature', - geometry: { - coordinates: [ - [12.445818466287847, 41.93029376141277], - [12.446047161911423, 41.930040913942264], - [12.446171038707206, 41.9297762500957], - [12.446167862379838, 41.92945014491775], - [12.446075748864388, 41.9286136066203], - ], - type: 'LineString', - }, - properties: { - OBJECT_COMMAND_NAME: 'via camillucciaB', - ENTITY_HEB: 'route', - TYPE: 'ROUTE', - LAYER_NAME: 'CONTROL.ROUTES', - }, -}; - -export const CONTROL_POINT_OLIMPIADE_111: Route = { - type: 'Feature', - geometry: { - coordinates: [12.475638293442415, 41.932360642739155], - type: 'Point', - }, - properties: { - OBJECT_COMMAND_NAME: '111', - ENTITY_HEB: 'control point', - TIED_TO: 'olimpiade', - TYPE: 'ITEM' as never, - LAYER_NAME: 'CONTROL_GIL_GDB.CTR_CONTROL_POINT_CROSS_N', - }, -}; - -export const CONTROL_POINT_OLIMPIADE_112: Route = { - type: 'Feature', - geometry: { - coordinates: [12.474175672012962, 41.932217551210556], - type: 'Point', - }, - properties: { - OBJECT_COMMAND_NAME: '112', - ENTITY_HEB: 'control point', - TIED_TO: 'olimpiade', - TYPE: 'ITEM' as never, - LAYER_NAME: 'CONTROL_GIL_GDB.CTR_CONTROL_POINT_CROSS_N', - }, -}; diff --git a/tests/integration/control/route/route.spec.ts b/tests/integration/control/route/route.spec.ts index 5b117c7a..222d16cd 100644 --- a/tests/integration/control/route/route.spec.ts +++ b/tests/integration/control/route/route.spec.ts @@ -13,8 +13,13 @@ import { CommonRequestParameters, GenericGeocodingResponse, GeoContext, GeoConte import { S3_REPOSITORY_SYMBOL } from '../../../../src/common/s3/s3Repository'; import { cronLoadTileLatLonDataSymbol } from '../../../../src/latLon/DAL/latLonDAL'; import { expectedResponse } from '../utils'; +import { + ROUTE_VIA_CAMILLUCCIA_A, + ROUTE_VIA_CAMILLUCCIA_B, + CONTROL_POINT_OLIMPIADE_111, + CONTROL_POINT_OLIMPIADE_112, +} from '../../../mockObjects/routes'; import { RouteRequestSender } from './helpers/requestSender'; -import { ROUTE_VIA_CAMILLUCCIA_A, ROUTE_VIA_CAMILLUCCIA_B, CONTROL_POINT_OLIMPIADE_111, CONTROL_POINT_OLIMPIADE_112 } from './mockObjects'; describe('/search/control/route', function () { let requestSender: RouteRequestSender; diff --git a/tests/integration/control/tile/mockObjects.ts b/tests/integration/control/tile/mockObjects.ts deleted file mode 100644 index 2292a2cd..00000000 --- a/tests/integration/control/tile/mockObjects.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* eslint-disable @typescript-eslint/naming-convention */ -/* eslint-disable @typescript-eslint/no-magic-numbers */ -import { Tile } from '../../../../src/control/tile/models/tile'; - -export const RIT_TILE: Tile = { - type: 'Feature', - geometry: { - coordinates: [ - [ - [12.539507865186607, 41.851751203650096], - [12.536787075186538, 41.94185043165008], - [12.42879133518656, 41.93952837265009], - [12.431625055186686, 41.84943698365008], - [12.539507865186607, 41.851751203650096], - ], - ], - type: 'Polygon', - }, - properties: { - TILE_NAME: 'RIT', - TYPE: 'TILE', - }, -}; - -export const RIC_TILE: Tile = { - type: 'Feature', - properties: { - TILE_NAME: 'RIC', - TYPE: 'TILE', - }, - geometry: { - coordinates: [ - [ - [12.64750356570994, 41.854073129598774], - [12.64478277570987, 41.94417235759876], - [12.536787035709892, 41.941850298598766], - [12.539620755710018, 41.85175890959876], - [12.64750356570994, 41.854073129598774], - ], - ], - type: 'Polygon', - }, -}; - -export const SUB_TILE_66: Tile = { - type: 'Feature', - properties: { - SUB_TILE_ID: '66', - TILE_NAME: 'RIT', - TYPE: 'SUB_TILE', - }, - geometry: { - coordinates: [ - [ - [12.44999804325252, 41.930226156898485], - [12.45011422425253, 41.939247112898514], - [12.439626097252557, 41.93934663789851], - [12.439510908252515, 41.93032564689851], - [12.44999804325252, 41.930226156898485], - ], - ], - type: 'Polygon', - }, -}; - -export const SUB_TILE_65: Tile = { - type: 'Feature', - properties: { - SUB_TILE_ID: '65', - TILE_NAME: 'RIT', - TYPE: 'SUB_TILE', - }, - geometry: { - coordinates: [ - [ - [12.439530324602458, 41.93031190061167], - [12.439646505602468, 41.9393328566117], - [12.429158378602494, 41.939432381611695], - [12.429043189602453, 41.930411390611695], - [12.439530324602458, 41.93031190061167], - ], - ], - type: 'Polygon', - }, -}; diff --git a/tests/integration/control/tile/tile.spec.ts b/tests/integration/control/tile/tile.spec.ts index c44d6967..9ba39459 100644 --- a/tests/integration/control/tile/tile.spec.ts +++ b/tests/integration/control/tile/tile.spec.ts @@ -14,8 +14,8 @@ import { CommonRequestParameters, GenericGeocodingResponse, GeoContext, GeoConte import { S3_REPOSITORY_SYMBOL } from '../../../../src/common/s3/s3Repository'; import { cronLoadTileLatLonDataSymbol } from '../../../../src/latLon/DAL/latLonDAL'; import { expectedResponse } from '../utils'; +import { RIC_TILE, RIT_TILE, SUB_TILE_65, SUB_TILE_66 } from '../../../mockObjects/tiles'; import { TileRequestSender } from './helpers/requestSender'; -import { RIC_TILE, RIT_TILE, SUB_TILE_65, SUB_TILE_66 } from './mockObjects'; describe('/search/control/tiles', function () { let requestSender: TileRequestSender; diff --git a/tests/integration/location/location.spec.ts b/tests/integration/location/location.spec.ts index f9c81011..68314c99 100644 --- a/tests/integration/location/location.spec.ts +++ b/tests/integration/location/location.spec.ts @@ -14,7 +14,6 @@ import { S3_REPOSITORY_SYMBOL } from '../../../src/common/s3/s3Repository'; import { cronLoadTileLatLonDataSymbol } from '../../../src/latLon/DAL/latLonDAL'; import { GetGeotextSearchParams } from '../../../src/location/interfaces'; import { GenericGeocodingResponse, GeoContext, GeoContextMode, IApplication } from '../../../src/common/interfaces'; -import { LocationRequestSender } from './helpers/requestSender'; import { OSM_LA_PORT, GOOGLE_LA_PORT, @@ -25,7 +24,8 @@ import { LA_HIERRARCHY, MockLocationQueryFeature, PARIS_WI_SCHOOL, -} from './mockObjects'; +} from '../../mockObjects/locations'; +import { LocationRequestSender } from './helpers/requestSender'; import { expectedResponse, hierarchiesWithAnyWieght } from './utils'; describe('/search/location', function () { diff --git a/tests/integration/location/mockObjects.ts b/tests/integration/location/mockObjects.ts deleted file mode 100644 index 8fede417..00000000 --- a/tests/integration/location/mockObjects.ts +++ /dev/null @@ -1,403 +0,0 @@ -/* eslint-disable @typescript-eslint/naming-convention */ -/* eslint-disable @typescript-eslint/no-magic-numbers */ -import { Feature } from 'geojson'; -import { GenericGeocodingResponse } from '../../../src/common/interfaces'; -import { HierarchySearchHit } from '../../../src/location/models/elasticsearchHits'; - -export type MockLocationQueryFeature = GenericGeocodingResponse['features'][number]; - -export const NY_JFK_AIRPORT: MockLocationQueryFeature = { - type: 'Feature', - geometry: { - type: 'Polygon', - coordinates: [ - [ - [-73.81278266814672, 40.66039916690434], - [-73.8177430790069, 40.66160065836647], - [-73.82178645734075, 40.66043068890016], - [-73.82341214553732, 40.658185554886586], - [-73.82407909454082, 40.65496001884071], - [-73.8229536180974, 40.650532558586235], - [-73.82211993184252, 40.647939195437345], - [-73.81290769732489, 40.643985699842915], - [-73.79214887014153, 40.63414837731818], - [-73.78339516446982, 40.62987771430167], - [-73.7898562329419, 40.62275933562921], - [-73.78443726476769, 40.620069953803636], - [-73.7791433570518, 40.627188619100366], - [-73.77639219241223, 40.62706207167477], - [-73.77159849644941, 40.62336045339214], - [-73.77209870820208, 40.619975033140975], - [-73.77047302000595, 40.61908910045176], - [-73.76547094984971, 40.628422477310664], - [-73.75338249916041, 40.63291467256053], - [-73.74733827381596, 40.63601474373485], - [-73.7467963777506, 40.64208793530722], - [-73.752548854642, 40.64749646458006], - [-73.76213624656812, 40.65309424493557], - [-73.78181122379466, 40.66270746643491], - [-73.79106514121902, 40.66438330508498], - [-73.7957754685564, 40.665205399216404], - [-73.79856831750864, 40.66283394629252], - [-73.80390390953731, 40.66175885985783], - [-73.8073637074931, 40.66039916690434], - [-73.8109068740743, 40.66074699797244], - [-73.81278266814672, 40.66039916690434], - ], - ], - }, - properties: { - matches: [{ source: 'OSM', layer: 'osm_airports', source_id: ['03ed6d97-fc81-4340-b68a-11993554eef1'] }], - names: { - en: ['JFK Airport'], - fr: ['Aeropuerto JFK'], - default: ['JFK'], - display: 'JFK Airport', - }, - placetype: 'transportation', - sub_placetype: 'airport', - regions: [ - { - region: 'USA', - sub_region_names: ['New York'], - }, - ], - }, -}; - -export const NY_POLICE_AIRPORT: MockLocationQueryFeature = { - type: 'Feature', - geometry: { - coordinates: [ - [ - [-73.50019138870562, 40.76503398530525], - [-73.49991804403106, 40.75762191351754], - [-73.50172211928987, 40.75368779651572], - [-73.502924836068, 40.74958778448408], - [-73.50095675396722, 40.746067370663354], - [-73.49587254187276, 40.74117989901089], - [-73.48810955136324, 40.74010295019133], - [-73.4862508071566, 40.74097279482331], - [-73.48450140084462, 40.74209114977816], - [-73.48335335295225, 40.743250905424986], - [-73.49368578398266, 40.7500847690697], - [-73.49363111503533, 40.75112014169309], - [-73.49166303293454, 40.75087165373341], - [-73.49128035030373, 40.75435040065955], - [-73.48406404926651, 40.75385344795657], - [-73.4860321313673, 40.75840870869581], - [-73.50019138870562, 40.76503398530525], - ], - ], - type: 'Polygon', - }, - properties: { - matches: [{ source: 'OSM', layer: 'osm_airports', source_id: ['009c6b65-3dcb-4c4f-9f02-d766ebb5d808'] }], - names: { - en: ['Nassau County Police Airport'], - fr: ['Aeropuerto de la Policía del Condado de Nassau'], - default: ['Nassau County Police Airport'], - display: 'Nassau County Police Airport', - }, - placetype: 'transportation', - sub_placetype: 'airport', - regions: [ - { - region: 'USA', - sub_region_names: ['New York'], - }, - ], - }, -}; - -export const LA_AIRPORT: MockLocationQueryFeature = { - type: 'Feature', - geometry: { - coordinates: [ - [ - [-118.42713070992883, 33.9512236894319], - [-118.43440343023548, 33.94992163234602], - [-118.43571147345608, 33.94670980636225], - [-118.43560682999878, 33.943107208682775], - [-118.43325235220159, 33.938723119106925], - [-118.42875268352236, 33.9310829780122], - [-118.41394563426408, 33.931820976094315], - [-118.39756893251248, 33.932255089782316], - [-118.38516868278077, 33.935250412835686], - [-118.37904703905322, 33.936509285268926], - [-118.37899471732432, 33.943367642688045], - [-118.3788377519829, 33.94501703885841], - [-118.39181354073204, 33.94527746687625], - [-118.39510980964849, 33.945451085112225], - [-118.3980398264626, 33.94558129855595], - [-118.39746428744567, 33.949748023597365], - [-118.39720267894361, 33.953003135913036], - [-118.40813791735772, 33.95252573110099], - [-118.42713070992883, 33.9512236894319], - ], - ], - type: 'Polygon', - }, - properties: { - matches: [{ source: 'OSM', layer: 'osm_airports', source_id: ['a4f373ab-b824-41e2-b160-e7729c73bea6'] }], - names: { - en: ['Los Angeles International Airport'], - fr: ['Aeropuerto Internacional de Los Ángeles'], - default: ['Los Angeles International Airport'], - display: 'Los Angeles International Airport', - }, - placetype: 'transportation', - sub_placetype: 'airport', - regions: [ - { - region: 'USA', - sub_region_names: ['Los Angeles'], - }, - ], - }, -}; - -export const OSM_LA_PORT: MockLocationQueryFeature = { - type: 'Feature', - geometry: { - type: 'Polygon', - coordinates: [ - [ - [-118.2505781304088, 33.7502674389752], - [-118.25604403409116, 33.76075151051916], - [-118.27057180697577, 33.748593059782564], - [-118.27503083555426, 33.741097783576635], - [-118.2747911028351, 33.734798055529765], - [-118.27215404292296, 33.73136889520775], - [-118.26807858669537, 33.720881194108856], - [-118.26424286318695, 33.721997816398385], - [-118.26640045650717, 33.72901625632974], - [-118.2431463824787, 33.735794882347946], - [-118.24492040460113, 33.739303607948656], - [-118.25072193640723, 33.73794798097781], - [-118.25220827926702, 33.74193505797223], - [-118.24937943317966, 33.74508471776615], - [-118.24798898340768, 33.74783559181691], - [-118.24909175391655, 33.74803492708783], - [-118.25096166912684, 33.74600168558719], - [-118.25326310323155, 33.745363795966625], - [-118.25278363779321, 33.74687877606813], - [-118.2505781304088, 33.7502674389752], - ], - ], - }, - properties: { - matches: [{ source: 'OSM', layer: 'osm_ports', source_id: ['0f36d985-cfbd-4aed-b0cb-ee56600c77f4'] }], - names: { - en: ['Port of Los Angeles'], - fr: ['Puerto de Los Ángeles'], - default: ['Port of Los Angeles'], - display: 'Port of Los Angeles', - }, - placetype: 'transportation', - sub_placetype: 'port', - regions: [ - { - region: 'USA', - sub_region_names: ['Los Angeles'], - }, - ], - }, -}; -export const GOOGLE_LA_PORT: MockLocationQueryFeature = { - type: 'Feature', - geometry: { - type: 'Polygon', - coordinates: [ - [ - [-118.2505781304088, 33.7502674389752], - [-118.25604403409116, 33.76075151051916], - [-118.27057180697577, 33.748593059782564], - [-118.27503083555426, 33.741097783576635], - [-118.2747911028351, 33.734798055529765], - [-118.27215404292296, 33.73136889520775], - [-118.26807858669537, 33.720881194108856], - [-118.26424286318695, 33.721997816398385], - [-118.26640045650717, 33.72901625632974], - [-118.2431463824787, 33.735794882347946], - [-118.24492040460113, 33.739303607948656], - [-118.25072193640723, 33.73794798097781], - [-118.25220827926702, 33.74193505797223], - [-118.24937943317966, 33.74508471776615], - [-118.24798898340768, 33.74783559181691], - [-118.24909175391655, 33.74803492708783], - [-118.25096166912684, 33.74600168558719], - [-118.25326310323155, 33.745363795966625], - [-118.25278363779321, 33.74687877606813], - [-118.2505781304088, 33.7502674389752], - ], - ], - }, - properties: { - matches: [{ source: 'GOOGLE', layer: 'google_ports', source_id: ['1bb11f54-939e-457b-bf68-a3920ccf629c'] }], - names: { - en: ['Port of Los Angeles'], - fr: ['Puerto de Los Ángeles'], - default: ['Port of Los Angeles'], - display: 'Port of Los Angeles', - }, - placetype: 'transportation', - sub_placetype: 'port', - regions: [ - { - region: 'USA', - sub_region_names: ['Los Angeles'], - }, - ], - }, -}; - -export const LA_WHITE_POINT_SCHOOL: MockLocationQueryFeature = { - type: 'Feature', - geometry: { - coordinates: [ - [ - [-118.30812263653988, 33.71684417247593], - [-118.30861990876181, 33.71674433152869], - [-118.30879709771484, 33.71635922964194], - [-118.30619642115158, 33.71550819588987], - [-118.30586490633668, 33.715921827872904], - [-118.30587062210924, 33.716183318328746], - [-118.30812263653988, 33.71684417247593], - ], - ], - type: 'Polygon', - }, - properties: { - matches: [ - { - source: 'OSM', - layer: 'osm_schools', - source_id: ['1a5b981b-bb0e-44dd-b9e2-424b92f2de49'], - }, - ], - names: { - en: ['White Point Elementary School'], - fr: ['Escuela Primaria White Point'], - default: ['White Point Elementary School'], - display: 'White Point Elementary School', - }, - placetype: 'education', - sub_placetype: 'school', - regions: [ - { - region: 'USA', - sub_region_names: ['Los Angeles'], - }, - ], - }, -}; - -export const PARIS_WI_SCHOOL: MockLocationQueryFeature = { - type: 'Feature', - geometry: { - coordinates: [ - [ - [2.346441270696971, 48.88088750665477], - [2.3462780852304945, 48.88018258877358], - [2.347503576087604, 48.87999951892243], - [2.347737155284733, 48.88070864783427], - [2.346441270696971, 48.88088750665477], - ], - ], - type: 'Polygon', - }, - properties: { - matches: [ - { - source: 'OSM', - layer: 'osm_schools', - source_id: ['dc02a3f9-156a-4f61-85bd-fd040cd322a3'], - }, - ], - names: { - en: ['Wi School Paris 9'], - fr: ['Ecole Wi Paris 9'], - default: ['Wi School Paris 9'], - display: 'Wi School Paris 9', - }, - placetype: 'education', - sub_placetype: 'school', - regions: [ - { - region: 'FRANCE', - sub_region_names: ['Paris'], - }, - ], - }, -}; - -export const NY_HIERRARCHY: HierarchySearchHit = { - geo_json: { - coordinates: [ - [ - [-73.74286189030825, 40.566325396473786], - [-73.47084009765854, 40.56212896709357], - [-73.550927745189, 41.11163279131463], - [-73.74424271181776, 41.225972287315074], - [-73.99969469100891, 41.26438691280978], - [-74.24962338416366, 41.05959508414017], - [-74.13087273437748, 40.7506852054762], - [-74.00659879855483, 40.530651727069795], - [-73.74286189030825, 40.566325396473786], - ], - ], - type: 'Polygon', - }, - hierarchy: 'city', - placetype: 'city', - region: 'USA', - text: 'New York', - weight: 1.1, -}; - -export const LA_HIERRARCHY: HierarchySearchHit = { - geo_json: { - coordinates: [ - [ - [-118.54430957638033, 34.07939240620722], - [-118.5350828996408, 33.695192367610986], - [-118.04596133238863, 33.47690745532634], - [-117.66265886139905, 33.379872950239346], - [-117.57145361502153, 33.63336904289318], - [-117.67279277766329, 34.23871934668085], - [-118.2605599209839, 34.28059749364003], - [-118.54430957638033, 34.07939240620722], - ], - ], - type: 'Polygon', - }, - hierarchy: 'city', - placetype: 'city', - region: 'USA', - text: 'Los Angeles', - weight: 1.1, -}; - -export const PARIS_HIERRARCHY: HierarchySearchHit = { - geo_json: { - coordinates: [ - [ - [2.226678539753607, 49.06838747927134], - [1.9344166918067742, 48.906487548202136], - [2.014124468519668, 48.56855190252173], - [2.6536844864307625, 48.53463335095324], - [2.902296837606201, 48.82159183126478], - [2.6460932696008683, 49.0124047223114], - [2.384196288972504, 49.05097737411208], - [2.226678539753607, 49.06838747927134], - ], - ], - type: 'Polygon', - }, - hierarchy: 'city', - placetype: 'city', - region: 'FRANCE', - text: 'Paris', - weight: 1.1, -}; diff --git a/tests/integration/location/utils.ts b/tests/integration/location/utils.ts index 9e9a6da0..5c0c009b 100644 --- a/tests/integration/location/utils.ts +++ b/tests/integration/location/utils.ts @@ -2,7 +2,7 @@ import { Feature } from 'geojson'; import { GetGeotextSearchParams } from '../../../src/location/interfaces'; import { GenericGeocodingResponse } from '../../../src/common/interfaces'; -import { MockLocationQueryFeature } from './mockObjects'; +import { MockLocationQueryFeature } from '../../mockObjects/locations'; const expectedObjectWithScore = (obj: MockLocationQueryFeature, expect: jest.Expect): GenericGeocodingResponse['features'][number] => ({ From e5c2fe886ea987cfcd9f80208c35eba80b085744 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 10:38:58 +0300 Subject: [PATCH 06/33] feat(unit/control/tile): created unit tests --- tests/unit/control/tile/tile.spec.ts | 167 +++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 tests/unit/control/tile/tile.spec.ts diff --git a/tests/unit/control/tile/tile.spec.ts b/tests/unit/control/tile/tile.spec.ts new file mode 100644 index 00000000..b658c36a --- /dev/null +++ b/tests/unit/control/tile/tile.spec.ts @@ -0,0 +1,167 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { ELASTIC_KEYWORDS } from '../../../../src/control/constants'; +import { queryForSubTiles, queryForTiles, queryForTilesByBbox } from '../../../../src/control/tile/DAL/queries'; + +describe('tiles', () => { + describe('#queryForTiles', () => { + it('query for tile with disableFuzziness false', () => { + const query = queryForTiles({ + tile: 'RIC', + disableFuzziness: false, + }); + expect(query).toStrictEqual({ + query: { + bool: { + must: [ + { term: { [ELASTIC_KEYWORDS.type]: 'TILE' } }, + { match: { [ELASTIC_KEYWORDS.tileName]: { fuzziness: 1, prefix_length: 1, query: 'RIC' } } }, + ], + }, + }, + }); + }); + + it('query for tile with disableFuzziness true', () => { + const query = queryForTiles({ + tile: 'RIC', + disableFuzziness: true, + }); + expect(query).toStrictEqual({ + query: { + bool: { + must: [ + { term: { [ELASTIC_KEYWORDS.type]: 'TILE' } }, + { match: { [ELASTIC_KEYWORDS.tileName]: { fuzziness: undefined, prefix_length: 1, query: 'RIC' } } }, + ], + }, + }, + }); + }); + }); + + describe('#queryForSubTiles', () => { + it('query for sub tile with disableFuzziness false', () => { + const query = queryForSubTiles({ + tile: 'RIC', + subTile: '66', + disableFuzziness: false, + limit: 5, + }); + expect(query).toStrictEqual({ + query: { + bool: { + must: [ + { term: { [ELASTIC_KEYWORDS.type]: 'SUB_TILE' } }, + { term: { [ELASTIC_KEYWORDS.tileName]: 'RIC' } }, + { + match: { + [ELASTIC_KEYWORDS.subTileId]: { query: '66', fuzziness: 1, prefix_length: 1 }, + }, + }, + ], + }, + }, + }); + }); + + it('query for sub tile with disableFuzziness true', () => { + const query = queryForSubTiles({ + tile: 'RIC', + subTile: '66', + disableFuzziness: true, + limit: 5, + }); + expect(query).toStrictEqual({ + query: { + bool: { + must: [ + { term: { [ELASTIC_KEYWORDS.type]: 'SUB_TILE' } }, + { term: { [ELASTIC_KEYWORDS.tileName]: 'RIC' } }, + { + match: { + [ELASTIC_KEYWORDS.subTileId]: { query: '66', fuzziness: undefined, prefix_length: 1 }, + }, + }, + ], + }, + }, + }); + }); + }); + + describe('#queryForTilesByBbox', () => { + it('query for sub tile with disableFuzziness false', () => { + const query = queryForTilesByBbox({ + bbox: [12.93694771534361, 52.51211561266182, 13.080296161196031, 52.60444267653175], + disableFuzziness: false, + limit: 5, + }); + expect(query).toStrictEqual({ + query: { + bool: { + must: [{ term: { [ELASTIC_KEYWORDS.type]: 'TILE' } }], + filter: [ + { + geo_shape: { + geometry: { + shape: { + type: 'Polygon', + coordinates: [ + [ + [12.93694771534361, 52.51211561266182], + [12.93694771534361, 52.60444267653175], + [13.080296161196031, 52.60444267653175], + [13.080296161196031, 52.51211561266182], + [12.93694771534361, 52.51211561266182], + ], + ], + }, + relation: 'intersects', + }, + }, + }, + ], + should: undefined, + }, + }, + }); + }); + + it('query for sub tile with disableFuzziness true', () => { + const query = queryForTilesByBbox({ + bbox: [12.93694771534361, 52.51211561266182, 13.080296161196031, 52.60444267653175], + disableFuzziness: true, + limit: 5, + }); + expect(query).toStrictEqual({ + query: { + bool: { + must: [{ term: { [ELASTIC_KEYWORDS.type]: 'TILE' } }], + filter: [ + { + geo_shape: { + geometry: { + shape: { + type: 'Polygon', + coordinates: [ + [ + [12.93694771534361, 52.51211561266182], + [12.93694771534361, 52.60444267653175], + [13.080296161196031, 52.60444267653175], + [13.080296161196031, 52.51211561266182], + [12.93694771534361, 52.51211561266182], + ], + ], + }, + relation: 'intersects', + }, + }, + }, + ], + should: undefined, + }, + }, + }); + }); + }); +}); From fc25fbcc7ea53be1c7574efb99f1c8df600fada8 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 10:39:16 +0300 Subject: [PATCH 07/33] feat(tests/unit/control/utils): created unit tests --- tests/unit/control/utils.spec.ts | 162 +++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 tests/unit/control/utils.spec.ts diff --git a/tests/unit/control/utils.spec.ts b/tests/unit/control/utils.spec.ts new file mode 100644 index 00000000..36302478 --- /dev/null +++ b/tests/unit/control/utils.spec.ts @@ -0,0 +1,162 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import config from 'config'; +import { estypes } from '@elastic/elasticsearch'; +import { IApplication } from '../../../src/common/interfaces'; +import { ItemQueryParams } from '../../../src/control/item/DAL/queries'; +import { Item } from '../../../src/control/item/models/item'; +import { RouteQueryParams } from '../../../src/control/route/DAL/queries'; +import { Route } from '../../../src/control/route/models/route'; +import { TileQueryParams } from '../../../src/control/tile/DAL/queries'; +import { Tile } from '../../../src/control/tile/models/tile'; +import { additionalControlSearchProperties, convertCamelToSnakeCase, formatResponse } from '../../../src/control/utils'; +import { ITEM_1234 } from '../../mockObjects/items'; +import { CONTROL_POINT_OLIMPIADE_111, ROUTE_VIA_CAMILLUCCIA_A } from '../../mockObjects/routes'; +import { RIC_TILE, SUB_TILE_66 } from '../../mockObjects/tiles'; +import { elasticConfigPath } from '../../../src/common/constants'; +import { ElasticDbClientsConfig } from '../../../src/common/elastic/interfaces'; +import { CONTROL_FIELDS } from '../../../src/control/constants'; + +describe('#convertCamelToSnakeCase', () => { + it('should convert camel case to snake case', () => { + const camelCase = { + camelCaseKey: 'value', + anotherCamelCaseKey: 'anotherValue', + }; + + const snakeCase = { + camel_case_key: 'value', + another_camel_case_key: 'anotherValue', + }; + + expect(convertCamelToSnakeCase(camelCase)).toEqual(snakeCase); + }); +}); + +type ControlTypesQueryParams = TileQueryParams | ItemQueryParams | RouteQueryParams; +describe('#formatResponse', () => { + test.each<{ + feature: Tile | Item | Route; + partialQuery: Partial; + expectedNames: { + default: string[]; + display: string; + }; + }>([ + { + feature: RIC_TILE, + partialQuery: { tile: 'RIC' }, + expectedNames: { + default: ['RIC'], + display: 'Tile RIC', + }, + }, + { + feature: SUB_TILE_66, + partialQuery: { tile: 'RIC', subTile: '66' }, + expectedNames: { + default: ['66'], + display: 'Tile RIT Sub Tile 66', + }, + }, + { + feature: ROUTE_VIA_CAMILLUCCIA_A, + partialQuery: { commandName: 'via camillucciaA' }, + expectedNames: { + default: ['via camillucciaA'], + display: 'Route via camillucciaA', + }, + }, + { + feature: CONTROL_POINT_OLIMPIADE_111, + partialQuery: { commandName: 'olimpiade', controlPoint: '111' }, + expectedNames: { + default: ['111'], + display: 'Route olimpiade Control Point 111', + }, + }, + { + feature: ITEM_1234, + partialQuery: { commandName: '1234' }, + expectedNames: { + default: ['1234'], + display: 'Item 1234', + }, + }, + ])('should format elastic response to geocoding response', ({ partialQuery, feature, expectedNames }) => { + const displayNamePrefixes: IApplication['controlObjectDisplayNamePrefixes'] = { + TILE: 'Tile', + SUB_TILE: 'Sub Tile', + ROUTE: 'Route', + ITEM: 'Item', + CONTROL_POINT: 'Control Point', + }; + + const query: ControlTypesQueryParams = { disableFuzziness: true, limit: 5, ...partialQuery }; + + const generated = formatResponse( + { + took: 3, + timed_out: false, + _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, + hits: { + total: { value: 1, relation: 'eq' }, + max_score: 3.5145261, + hits: [ + { + _index: 'control_gil_v5', + _id: expect.any(String) as string, + _score: expect.any(Number) as number, + _source: feature, + }, + ], + }, + }, + query, + displayNamePrefixes + ); + + expect(generated).toEqual({ + type: 'FeatureCollection', + geocoding: { + version: process.env.npm_package_version as string, + query: convertCamelToSnakeCase(query as unknown as Record), + response: { + results_count: 1, + max_score: expect.any(Number) as number, + match_latency_ms: expect.any(Number) as number, + }, + }, + features: [ + { + type: 'Feature', + properties: { + ...feature.properties, + matches: [ + { + layer: feature.properties.LAYER_NAME, + source: 'control_gil_v5', + source_id: [], + }, + ], + names: expectedNames, + score: expect.any(Number) as number, + }, + geometry: feature.geometry, + }, + ], + }); + }); +}); + +describe('#additionalControlSearchProperties', () => { + it('should return additional control search properties', () => { + const size = 5; + const searchProperties = additionalControlSearchProperties(config, size); + + expect(searchProperties).toEqual>({ + size, + index: config.get(elasticConfigPath).control.properties.index as string, + _source: CONTROL_FIELDS, + }); + }); +}); From 57cc151f3a33dc9bb57116ae74bd5a5dfd9f717d Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 12:14:26 +0300 Subject: [PATCH 08/33] fix: changed unit test to only unit test tileManager. --- tests/unit/control/tile/tile.spec.ts | 302 ++++++++++++++------------- 1 file changed, 159 insertions(+), 143 deletions(-) diff --git a/tests/unit/control/tile/tile.spec.ts b/tests/unit/control/tile/tile.spec.ts index b658c36a..5a2b1e54 100644 --- a/tests/unit/control/tile/tile.spec.ts +++ b/tests/unit/control/tile/tile.spec.ts @@ -1,167 +1,183 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { ELASTIC_KEYWORDS } from '../../../../src/control/constants'; -import { queryForSubTiles, queryForTiles, queryForTilesByBbox } from '../../../../src/control/tile/DAL/queries'; +import jsLogger from '@map-colonies/js-logger'; +import { estypes } from '@elastic/elasticsearch'; +import { TileQueryParams } from '../../../../src/control/tile/DAL/queries'; +import { TileRepository } from '../../../../src/control/tile/DAL/tileRepository'; +import { TileManager } from '../../../../src/control/tile/models/tileManager'; +import { GenericGeocodingResponse, IApplication } from '../../../../src/common/interfaces'; +import { Tile } from '../../../../src/control/tile/models/tile'; +import { RIC_TILE, SUB_TILE_66 } from '../../../mockObjects/tiles'; +import { convertCamelToSnakeCase } from '../../../../src/control/utils'; +import { BadRequestError } from '../../../../src/common/errors'; -describe('tiles', () => { - describe('#queryForTiles', () => { - it('query for tile with disableFuzziness false', () => { - const query = queryForTiles({ - tile: 'RIC', - disableFuzziness: false, - }); - expect(query).toStrictEqual({ - query: { - bool: { - must: [ - { term: { [ELASTIC_KEYWORDS.type]: 'TILE' } }, - { match: { [ELASTIC_KEYWORDS.tileName]: { fuzziness: 1, prefix_length: 1, query: 'RIC' } } }, - ], - }, - }, - }); - }); +let tileManager: TileManager; - it('query for tile with disableFuzziness true', () => { - const query = queryForTiles({ - tile: 'RIC', - disableFuzziness: true, - }); - expect(query).toStrictEqual({ - query: { - bool: { - must: [ - { term: { [ELASTIC_KEYWORDS.type]: 'TILE' } }, - { match: { [ELASTIC_KEYWORDS.tileName]: { fuzziness: undefined, prefix_length: 1, query: 'RIC' } } }, - ], - }, - }, - }); - }); +describe('#TileManager', () => { + const getTiles = jest.fn(); + const getSubTiles = jest.fn(); + const getTilesByBbox = jest.fn(); + const controlObjectDisplayNamePrefixes = { TILE: 'Tile', SUB_TILE: 'Sub Tile', ROUTE: 'Route', ITEM: 'Item', CONTROL_POINT: 'Control Point' }; + beforeEach(() => { + jest.resetAllMocks(); + + const repository = { + getTiles, + getSubTiles, + getTilesByBbox, + } as unknown as TileRepository; + + tileManager = new TileManager( + jsLogger({ enabled: false }), + {} as never, + { + controlObjectDisplayNamePrefixes, + } as unknown as IApplication, + repository + ); }); - describe('#queryForSubTiles', () => { - it('query for sub tile with disableFuzziness false', () => { - const query = queryForSubTiles({ - tile: 'RIC', - subTile: '66', + test.each<{ + feature: Tile; + queryParams: TileQueryParams; + expectedNames: { + default: string[]; + display: string; + }; + mockFunction: jest.Mock; + }>([ + { + feature: RIC_TILE, + queryParams: { + tile: RIC_TILE.properties.TILE_NAME, + limit: 5, disableFuzziness: false, + }, + expectedNames: { + default: [RIC_TILE.properties.TILE_NAME as string], + display: `${controlObjectDisplayNamePrefixes.TILE} ${RIC_TILE.properties.TILE_NAME as string}`, + }, + mockFunction: getTiles, + }, + { + feature: SUB_TILE_66, + queryParams: { + tile: SUB_TILE_66.properties.TILE_NAME, + subTile: SUB_TILE_66.properties.SUB_TILE_ID, limit: 5, - }); - expect(query).toStrictEqual({ - query: { - bool: { - must: [ - { term: { [ELASTIC_KEYWORDS.type]: 'SUB_TILE' } }, - { term: { [ELASTIC_KEYWORDS.tileName]: 'RIC' } }, - { - match: { - [ELASTIC_KEYWORDS.subTileId]: { query: '66', fuzziness: 1, prefix_length: 1 }, - }, - }, - ], + disableFuzziness: false, + }, + expectedNames: { + default: [SUB_TILE_66.properties.SUB_TILE_ID as string], + display: `${controlObjectDisplayNamePrefixes.TILE} ${SUB_TILE_66.properties.TILE_NAME as string} ${ + controlObjectDisplayNamePrefixes.SUB_TILE + } ${SUB_TILE_66.properties.SUB_TILE_ID as string}`, + }, + mockFunction: getSubTiles, + }, + { + feature: RIC_TILE, + queryParams: { + mgrs: '33TTG958462', + limit: 5, + disableFuzziness: false, + }, + expectedNames: { + default: [RIC_TILE.properties.TILE_NAME as string], + display: `${controlObjectDisplayNamePrefixes.TILE} ${RIC_TILE.properties.TILE_NAME as string}`, + }, + mockFunction: getTilesByBbox, + }, + ])('should response with the right Geocoding GeoJSON', async ({ feature, queryParams, expectedNames, mockFunction }) => { + const hit: estypes.SearchResponse = { + took: 3, + timed_out: false, + _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, + hits: { + total: { value: 1, relation: 'eq' }, + max_score: 3.5145261, + hits: [ + { + _index: 'control_gil_v5', + _id: expect.any(String) as string, + _score: expect.any(Number) as number, + _source: feature, }, - }, - }); - }); + ], + }, + }; - it('query for sub tile with disableFuzziness true', () => { - const query = queryForSubTiles({ - tile: 'RIC', - subTile: '66', - disableFuzziness: true, - limit: 5, - }); - expect(query).toStrictEqual({ - query: { - bool: { - must: [ - { term: { [ELASTIC_KEYWORDS.type]: 'SUB_TILE' } }, - { term: { [ELASTIC_KEYWORDS.tileName]: 'RIC' } }, + mockFunction.mockResolvedValue(hit); + + const generated = await tileManager.getTiles(queryParams); + + expect(generated).toEqual>({ + type: 'FeatureCollection', + geocoding: { + version: process.env.npm_package_version as string, + query: convertCamelToSnakeCase(queryParams as unknown as Record), + response: { + results_count: 1, + max_score: expect.any(Number) as number, + match_latency_ms: expect.any(Number) as number, + }, + }, + features: [ + { + type: 'Feature', + properties: { + ...feature.properties, + matches: [ { - match: { - [ELASTIC_KEYWORDS.subTileId]: { query: '66', fuzziness: undefined, prefix_length: 1 }, - }, + layer: feature.properties.LAYER_NAME as string, + source: hit.hits.hits[0]._index, + source_id: [], }, ], + names: expectedNames, + score: expect.any(Number) as number, }, + geometry: feature.geometry, }, - }); + ], }); }); - describe('#queryForTilesByBbox', () => { - it('query for sub tile with disableFuzziness false', () => { - const query = queryForTilesByBbox({ - bbox: [12.93694771534361, 52.51211561266182, 13.080296161196031, 52.60444267653175], - disableFuzziness: false, + it('should throw BadRequestError if both tile and mgrs are provided', async () => { + const queryParams = { + tile: RIC_TILE.properties.TILE_NAME, + mgrs: '33TTG958462', + limit: 5, + disableFuzziness: false, + }; + + await expect(tileManager.getTiles(queryParams)).rejects.toThrow( + new BadRequestError("/control/tiles: only one of 'tile' or 'mgrs' query parameter must be defined") + ); + }); + + describe('Bad Path', () => { + // All requests with status code of 400 + it('should throw BadRequestError if both tile and mgrs are provided', async () => { + const queryParams = { + tile: RIC_TILE.properties.TILE_NAME, + mgrs: '33TTG958462', limit: 5, - }); - expect(query).toStrictEqual({ - query: { - bool: { - must: [{ term: { [ELASTIC_KEYWORDS.type]: 'TILE' } }], - filter: [ - { - geo_shape: { - geometry: { - shape: { - type: 'Polygon', - coordinates: [ - [ - [12.93694771534361, 52.51211561266182], - [12.93694771534361, 52.60444267653175], - [13.080296161196031, 52.60444267653175], - [13.080296161196031, 52.51211561266182], - [12.93694771534361, 52.51211561266182], - ], - ], - }, - relation: 'intersects', - }, - }, - }, - ], - should: undefined, - }, - }, - }); + disableFuzziness: false, + }; + + await expect(tileManager.getTiles(queryParams)).rejects.toThrow( + new BadRequestError("/control/tiles: only one of 'tile' or 'mgrs' query parameter must be defined") + ); }); - it('query for sub tile with disableFuzziness true', () => { - const query = queryForTilesByBbox({ - bbox: [12.93694771534361, 52.51211561266182, 13.080296161196031, 52.60444267653175], - disableFuzziness: true, + it('should throw BadRequestError if invalid MGRS tile is provided', async () => { + const queryParams = { + mgrs: 'ABC{}', limit: 5, - }); - expect(query).toStrictEqual({ - query: { - bool: { - must: [{ term: { [ELASTIC_KEYWORDS.type]: 'TILE' } }], - filter: [ - { - geo_shape: { - geometry: { - shape: { - type: 'Polygon', - coordinates: [ - [ - [12.93694771534361, 52.51211561266182], - [12.93694771534361, 52.60444267653175], - [13.080296161196031, 52.60444267653175], - [13.080296161196031, 52.51211561266182], - [12.93694771534361, 52.51211561266182], - ], - ], - }, - relation: 'intersects', - }, - }, - }, - ], - should: undefined, - }, - }, - }); + disableFuzziness: false, + }; + + await expect(tileManager.getTiles(queryParams)).rejects.toThrow(new BadRequestError(`Invalid MGRS: ${queryParams.mgrs}`)); }); }); }); From abc974e04556ab8aed280d53dc0ea11304c4fa27 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 12:14:41 +0300 Subject: [PATCH 09/33] fix: ignore DAL folders --- tests/configurations/unit/jest.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/configurations/unit/jest.config.js b/tests/configurations/unit/jest.config.js index bfd03fc4..2cea4e27 100644 --- a/tests/configurations/unit/jest.config.js +++ b/tests/configurations/unit/jest.config.js @@ -12,6 +12,7 @@ module.exports = { '!/vendor/**', '!*/common/**', '!**/controllers/**', + '!**/DAL/**', '!**/routes/**', '!**/redis/**', '!/src/*', From 779bd00e184fd02a637dc4c541099f860ead0773 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 12:15:11 +0300 Subject: [PATCH 10/33] fix: fixed mgrs routers directory name --- src/containerConfig.ts | 2 +- src/mgrs/{routers => routes}/mgrsRouter.ts | 0 src/serverBuilder.ts | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/mgrs/{routers => routes}/mgrsRouter.ts (100%) diff --git a/src/containerConfig.ts b/src/containerConfig.ts index 09f5e00b..842252cd 100644 --- a/src/containerConfig.ts +++ b/src/containerConfig.ts @@ -27,7 +27,7 @@ import { RedisClient, redisClientFactory } from './common/redis'; import { s3ClientFactory } from './common/s3'; import { S3_REPOSITORY_SYMBOL, s3RepositoryFactory } from './common/s3/s3Repository'; import { healthCheckFactory } from './common/utils'; -import { MGRS_ROUTER_SYMBOL, mgrsRouterFactory } from './mgrs/routers/mgrsRouter'; +import { MGRS_ROUTER_SYMBOL, mgrsRouterFactory } from './mgrs/routes/mgrsRouter'; export interface RegisterOptions { override?: InjectionObject[]; diff --git a/src/mgrs/routers/mgrsRouter.ts b/src/mgrs/routes/mgrsRouter.ts similarity index 100% rename from src/mgrs/routers/mgrsRouter.ts rename to src/mgrs/routes/mgrsRouter.ts diff --git a/src/serverBuilder.ts b/src/serverBuilder.ts index 6a533d37..3bf7bb5d 100644 --- a/src/serverBuilder.ts +++ b/src/serverBuilder.ts @@ -17,7 +17,7 @@ import { LAT_LON_ROUTER_SYMBOL } from './latLon/routes/latLonRouter'; import { GEOTEXT_SEARCH_ROUTER_SYMBOL } from './location/routes/locationRouter'; import { cronLoadTileLatLonDataSymbol } from './latLon/DAL/latLonDAL'; import { FeedbackApiMiddlewareManager } from './common/middlewares/feedbackApi.middleware'; -import { MGRS_ROUTER_SYMBOL } from './mgrs/routers/mgrsRouter'; +import { MGRS_ROUTER_SYMBOL } from './mgrs/routes/mgrsRouter'; @injectable() export class ServerBuilder { From c0bc840c9fc1d89dd37e11b544593431160ad4dc Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 12:17:56 +0300 Subject: [PATCH 11/33] fix: added back elasticResponse.hits.max_score ?? 0 --- src/control/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/utils.ts b/src/control/utils.ts index a8e84bd4..2ae4f620 100644 --- a/src/control/utils.ts +++ b/src/control/utils.ts @@ -63,7 +63,7 @@ export const formatResponse = ( query: convertCamelToSnakeCase(requestParams as Record), response: { results_count: elasticResponse.hits.hits.length, - max_score: elasticResponse.hits.max_score as number, + max_score: elasticResponse.hits.max_score ?? 0, match_latency_ms: elasticResponse.took, }, }, From 6722ef5fb81c1671ce73881b5b7ffaf77063dbe7 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 12:19:15 +0300 Subject: [PATCH 12/33] fix: removed unused try-catch condition --- src/control/tile/models/tileManager.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/control/tile/models/tileManager.ts b/src/control/tile/models/tileManager.ts index 0825d120..26ed9734 100644 --- a/src/control/tile/models/tileManager.ts +++ b/src/control/tile/models/tileManager.ts @@ -35,11 +35,6 @@ export class TileManager { let bbox: BBox = [0, 0, 0, 0]; try { bbox = mgrs.inverse(tileQueryParams.mgrs); - bbox.forEach((coord) => { - if (isNaN(coord)) { - throw new Error('Invalid MGRS'); - } - }); } catch (error) { throw new BadRequestError(`Invalid MGRS: ${tileQueryParams.mgrs}`); } From 6ae3c3b21c5fef705a185b80d448bfcca11b07a3 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 12:19:44 +0300 Subject: [PATCH 13/33] fix: removed unused properties --- tests/unit/control/tile/tile.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/control/tile/tile.spec.ts b/tests/unit/control/tile/tile.spec.ts index 5a2b1e54..84db9e90 100644 --- a/tests/unit/control/tile/tile.spec.ts +++ b/tests/unit/control/tile/tile.spec.ts @@ -16,7 +16,7 @@ describe('#TileManager', () => { const getTiles = jest.fn(); const getSubTiles = jest.fn(); const getTilesByBbox = jest.fn(); - const controlObjectDisplayNamePrefixes = { TILE: 'Tile', SUB_TILE: 'Sub Tile', ROUTE: 'Route', ITEM: 'Item', CONTROL_POINT: 'Control Point' }; + const controlObjectDisplayNamePrefixes = { TILE: 'Tile', SUB_TILE: 'Sub Tile' }; beforeEach(() => { jest.resetAllMocks(); From 57dae55047f3a628082b288261d8e805a39ea312 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 12:31:52 +0300 Subject: [PATCH 14/33] delete: removed duplicated test --- tests/unit/control/tile/tile.spec.ts | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/tests/unit/control/tile/tile.spec.ts b/tests/unit/control/tile/tile.spec.ts index 84db9e90..672add37 100644 --- a/tests/unit/control/tile/tile.spec.ts +++ b/tests/unit/control/tile/tile.spec.ts @@ -142,19 +142,6 @@ describe('#TileManager', () => { }); }); - it('should throw BadRequestError if both tile and mgrs are provided', async () => { - const queryParams = { - tile: RIC_TILE.properties.TILE_NAME, - mgrs: '33TTG958462', - limit: 5, - disableFuzziness: false, - }; - - await expect(tileManager.getTiles(queryParams)).rejects.toThrow( - new BadRequestError("/control/tiles: only one of 'tile' or 'mgrs' query parameter must be defined") - ); - }); - describe('Bad Path', () => { // All requests with status code of 400 it('should throw BadRequestError if both tile and mgrs are provided', async () => { From 020819b329e000591aa3c93782181e45462a9b01 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 12:32:09 +0300 Subject: [PATCH 15/33] feat(tests/control/route): added unit test --- tests/unit/control/route/route.spec.ts | 132 +++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 tests/unit/control/route/route.spec.ts diff --git a/tests/unit/control/route/route.spec.ts b/tests/unit/control/route/route.spec.ts new file mode 100644 index 00000000..baa3d517 --- /dev/null +++ b/tests/unit/control/route/route.spec.ts @@ -0,0 +1,132 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import jsLogger from '@map-colonies/js-logger'; +import { estypes } from '@elastic/elasticsearch'; +import { RouteQueryParams } from '../../../../src/control/route/DAL/queries'; +import { RouteRepository } from '../../../../src/control/route/DAL/routeRepository'; +import { RouteManager } from '../../../../src/control/route/models/routeManager'; +import { GenericGeocodingResponse, IApplication } from '../../../../src/common/interfaces'; +import { Route } from '../../../../src/control/route/models/route'; +import { convertCamelToSnakeCase } from '../../../../src/control/utils'; +import { CONTROL_POINT_OLIMPIADE_111, ROUTE_VIA_CAMILLUCCIA_A } from '../../../mockObjects/routes'; + +let tileManager: RouteManager; + +describe('#RouteManager', () => { + const getRoutes = jest.fn(); + const getControlPointInRoute = jest.fn(); + const controlObjectDisplayNamePrefixes = { ROUTE: 'Route', CONTROL_POINT: 'Control Point' }; + beforeEach(() => { + jest.resetAllMocks(); + + const repository = { + getRoutes, + getControlPointInRoute, + } as unknown as RouteRepository; + + tileManager = new RouteManager( + jsLogger({ enabled: false }), + {} as never, + { + controlObjectDisplayNamePrefixes, + } as unknown as IApplication, + repository + ); + }); + + test.each<{ + feature: Route; + queryParams: RouteQueryParams; + expectedNames: { + default: string[]; + display: string; + }; + mockFunction: jest.Mock; + }>([ + { + feature: ROUTE_VIA_CAMILLUCCIA_A, + queryParams: { + commandName: ROUTE_VIA_CAMILLUCCIA_A.properties.OBJECT_COMMAND_NAME, + limit: 5, + disableFuzziness: false, + }, + expectedNames: { + default: [ROUTE_VIA_CAMILLUCCIA_A.properties.OBJECT_COMMAND_NAME], + display: `${controlObjectDisplayNamePrefixes.ROUTE} ${ROUTE_VIA_CAMILLUCCIA_A.properties.OBJECT_COMMAND_NAME}`, + }, + mockFunction: getRoutes, + }, + { + feature: CONTROL_POINT_OLIMPIADE_111, + queryParams: { + commandName: CONTROL_POINT_OLIMPIADE_111.properties.TIED_TO as string, + controlPoint: CONTROL_POINT_OLIMPIADE_111.properties.OBJECT_COMMAND_NAME, + limit: 5, + disableFuzziness: false, + }, + expectedNames: { + default: [CONTROL_POINT_OLIMPIADE_111.properties.OBJECT_COMMAND_NAME], + display: `${controlObjectDisplayNamePrefixes.ROUTE} ${CONTROL_POINT_OLIMPIADE_111.properties.TIED_TO as string} ${ + controlObjectDisplayNamePrefixes.CONTROL_POINT + } ${CONTROL_POINT_OLIMPIADE_111.properties.OBJECT_COMMAND_NAME}`, + }, + mockFunction: getControlPointInRoute, + }, + ])('should response with the right Geocoding GeoJSON', async ({ feature, queryParams, expectedNames, mockFunction }) => { + const hit: estypes.SearchResponse = { + took: 3, + timed_out: false, + _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, + hits: { + total: { value: 1, relation: 'eq' }, + max_score: 3.5145261, + hits: [ + { + _index: 'control_gil_v5', + _id: expect.any(String) as string, + _score: expect.any(Number) as number, + _source: feature, + }, + ], + }, + }; + + mockFunction.mockResolvedValue(hit); + + const generated = await tileManager.getRoutes(queryParams); + + expect(generated).toEqual>({ + type: 'FeatureCollection', + geocoding: { + version: process.env.npm_package_version as string, + query: convertCamelToSnakeCase(queryParams as unknown as Record), + response: { + results_count: 1, + max_score: expect.any(Number) as number, + match_latency_ms: expect.any(Number) as number, + }, + }, + features: [ + { + type: 'Feature', + properties: { + ...feature.properties, + matches: [ + { + layer: feature.properties.LAYER_NAME, + source: hit.hits.hits[0]._index, + source_id: [], + }, + ], + names: expectedNames, + score: expect.any(Number) as number, + }, + geometry: feature.geometry, + }, + ], + }); + }); + + // describe('Bad Path', () => { + // // All requests with status code of 400 + // }); +}); From 24074251dddac37ce0c6bde932f85f1598d9738b Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 12:32:26 +0300 Subject: [PATCH 16/33] fix: added missing property --- src/control/route/models/route.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/control/route/models/route.ts b/src/control/route/models/route.ts index 607fcd12..91c585f1 100644 --- a/src/control/route/models/route.ts +++ b/src/control/route/models/route.ts @@ -5,6 +5,7 @@ export interface Route extends Feature { properties: GeoJsonProperties & { TYPE: 'ROUTE'; OBJECT_COMMAND_NAME: string; + TIED_TO?: string; ENTITY_HEB: string; LAYER_NAME: string; }; From ea0f4149d692a994fad1b8b7ee0e71a40937c461 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 12:33:04 +0300 Subject: [PATCH 17/33] delete: removed comment --- tests/unit/control/route/route.spec.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/unit/control/route/route.spec.ts b/tests/unit/control/route/route.spec.ts index baa3d517..fe26ede1 100644 --- a/tests/unit/control/route/route.spec.ts +++ b/tests/unit/control/route/route.spec.ts @@ -125,8 +125,4 @@ describe('#RouteManager', () => { ], }); }); - - // describe('Bad Path', () => { - // // All requests with status code of 400 - // }); }); From 436c5684a9d1245d0d39b4d5f52a407618f310b6 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 12:34:11 +0300 Subject: [PATCH 18/33] fix: fixed typo --- tests/unit/control/route/route.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unit/control/route/route.spec.ts b/tests/unit/control/route/route.spec.ts index fe26ede1..14505a9d 100644 --- a/tests/unit/control/route/route.spec.ts +++ b/tests/unit/control/route/route.spec.ts @@ -9,7 +9,7 @@ import { Route } from '../../../../src/control/route/models/route'; import { convertCamelToSnakeCase } from '../../../../src/control/utils'; import { CONTROL_POINT_OLIMPIADE_111, ROUTE_VIA_CAMILLUCCIA_A } from '../../../mockObjects/routes'; -let tileManager: RouteManager; +let routeManager: RouteManager; describe('#RouteManager', () => { const getRoutes = jest.fn(); @@ -23,7 +23,7 @@ describe('#RouteManager', () => { getControlPointInRoute, } as unknown as RouteRepository; - tileManager = new RouteManager( + routeManager = new RouteManager( jsLogger({ enabled: false }), {} as never, { @@ -92,7 +92,7 @@ describe('#RouteManager', () => { mockFunction.mockResolvedValue(hit); - const generated = await tileManager.getRoutes(queryParams); + const generated = await routeManager.getRoutes(queryParams); expect(generated).toEqual>({ type: 'FeatureCollection', From 67dbfe3eec6fca15f4b8778d9658eebf69e36ce0 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 12:44:38 +0300 Subject: [PATCH 19/33] fix: fixed logger.error message to msg. changed logger.warn to logger.error --- src/common/middlewares/feedbackApi.middleware.ts | 2 +- src/common/redis/index.ts | 2 +- src/common/s3/s3Repository.ts | 2 +- src/common/utils.ts | 2 +- src/containerConfig.ts | 8 ++++---- src/control/item/controllers/itemController.ts | 2 +- src/control/route/controllers/routeController.ts | 2 +- src/control/tile/controllers/tileController.ts | 2 +- src/latLon/DAL/latLonDAL.ts | 8 ++++---- src/latLon/controllers/latLonController.ts | 2 +- src/latLon/models/latLonManager.ts | 6 +++--- src/location/DAL/locationRepository.ts | 2 +- src/location/controllers/locationController.ts | 2 +- src/mgrs/controllers/mgrsController.ts | 2 +- src/mgrs/models/mgrsManager.ts | 2 +- 15 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/common/middlewares/feedbackApi.middleware.ts b/src/common/middlewares/feedbackApi.middleware.ts index 828430e7..4ed9e2cd 100644 --- a/src/common/middlewares/feedbackApi.middleware.ts +++ b/src/common/middlewares/feedbackApi.middleware.ts @@ -42,7 +42,7 @@ export class FeedbackApiMiddlewareManager { .then(() => { logger.info({ msg: `response ${reqId?.toString() ?? ''} saved to redis` }); }) - .catch((error: Error) => logger.error({ message: 'Error setting key:', error })); + .catch((error: Error) => logger.error({ msg: 'Error setting key:', error })); return originalJson.call(this, body); }; diff --git a/src/common/redis/index.ts b/src/common/redis/index.ts index dba9d379..5047dd68 100644 --- a/src/common/redis/index.ts +++ b/src/common/redis/index.ts @@ -38,6 +38,6 @@ export const redisClientFactory: FactoryFunction = (con .on('ready', (...args) => logger.debug({ msg: 'redis client is ready', ...args })); return redisClient; } catch (error) { - logger.error({ message: 'Connection to Redis was unsuccessful', error }); + logger.error({ msg: 'Connection to Redis was unsuccessful', error }); } }; diff --git a/src/common/s3/s3Repository.ts b/src/common/s3/s3Repository.ts index 6502badb..0fc3b717 100644 --- a/src/common/s3/s3Repository.ts +++ b/src/common/s3/s3Repository.ts @@ -49,7 +49,7 @@ const createS3Repository = (s3Client: S3Client, config: IConfig, logger: Logger) return filePath; } catch (error) { - logger.error({ message: `Error while downloading ${key}'s data from S3.`, error }); + logger.error({ msg: `Error while downloading ${key}'s data from S3.`, error }); throw error; } }, diff --git a/src/common/utils.ts b/src/common/utils.ts index 75bc1508..bf6aee99 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -218,7 +218,7 @@ export const healthCheckFactory: FactoryFunction = (container: DependencyC return; }) .catch((error: Error) => { - logger.error({ message: `Healthcheck failed for ${key}.`, error }); + logger.error({ msg: `Healthcheck failed for ${key}.`, error }); }); } diff --git a/src/containerConfig.ts b/src/containerConfig.ts index 842252cd..8c3109e9 100644 --- a/src/containerConfig.ts +++ b/src/containerConfig.ts @@ -79,7 +79,7 @@ export const registerExternalValues = async (options?: RegisterOptions): Promise const response = await Promise.all([elasticClients.control.ping(), elasticClients.geotext.ping()]); response.forEach((res) => { if (!res) { - logger.error({ message: 'Failed to connect to Elasticsearch', res }); + logger.error({ msg: 'Failed to connect to Elasticsearch', res }); } }); cleanupRegistry.register({ @@ -90,7 +90,7 @@ export const registerExternalValues = async (options?: RegisterOptions): Promise id: SERVICES.ELASTIC_CLIENTS, }); } catch (error) { - logger.error({ message: 'Failed to connect to Elasticsearch', error }); + logger.error({ msg: 'Failed to connect to Elasticsearch', error }); } }, }, @@ -103,7 +103,7 @@ export const registerExternalValues = async (options?: RegisterOptions): Promise await s3Client.send(new ListBucketsCommand({})); logger.info('Connected to S3'); } catch (error) { - logger.error({ message: 'Failed to connect to S3', error }); + logger.error({ msg: 'Failed to connect to S3', error }); } cleanupRegistry.register({ func: async () => { @@ -160,7 +160,7 @@ export const registerExternalValues = async (options?: RegisterOptions): Promise cleanupRegistry.register({ func: redis.disconnect.bind(redis), id: SERVICES.REDIS }); await redis.connect(); } catch (error) { - logger.error({ message: 'Connection to redis failed', error }); + logger.error({ msg: 'Connection to redis failed', error }); } }, }, diff --git a/src/control/item/controllers/itemController.ts b/src/control/item/controllers/itemController.ts index 298b95bb..38e52d63 100644 --- a/src/control/item/controllers/itemController.ts +++ b/src/control/item/controllers/itemController.ts @@ -41,7 +41,7 @@ export class ItemController { }); return res.status(httpStatus.OK).json(response); } catch (error: unknown) { - this.logger.warn('itemController.getItems Error:', error); + this.logger.error({ msg: 'itemController.getItems error', error }); next(error); } }; diff --git a/src/control/route/controllers/routeController.ts b/src/control/route/controllers/routeController.ts index 36be0db7..45adca5d 100644 --- a/src/control/route/controllers/routeController.ts +++ b/src/control/route/controllers/routeController.ts @@ -40,7 +40,7 @@ export class RouteController { }); return res.status(httpStatus.OK).json(response); } catch (error: unknown) { - this.logger.warn('routeController.getRoutes Error:', error); + this.logger.error({ msg: 'routeController.getRoutes error', error }); next(error); } }; diff --git a/src/control/tile/controllers/tileController.ts b/src/control/tile/controllers/tileController.ts index db3df58e..d4f12873 100644 --- a/src/control/tile/controllers/tileController.ts +++ b/src/control/tile/controllers/tileController.ts @@ -50,7 +50,7 @@ export class TileController { }); return res.status(httpStatus.OK).json(response); } catch (error: unknown) { - this.logger.warn('tileController.getTiles Error:', error); + this.logger.error({ msg: 'tileController.getTiles', error }); next(error); } }; diff --git a/src/latLon/DAL/latLonDAL.ts b/src/latLon/DAL/latLonDAL.ts index 6505134c..5b17fc08 100644 --- a/src/latLon/DAL/latLonDAL.ts +++ b/src/latLon/DAL/latLonDAL.ts @@ -37,7 +37,7 @@ export class LatLonDAL { this.dataLoadError = false; this.init().catch((error: Error) => { - this.logger.error({ message: 'Failed to initialize lat-lon data', error }); + this.logger.error({ msg: 'Failed to initialize lat-lon data', error }); this.dataLoadError = true; }); } @@ -74,7 +74,7 @@ export class LatLonDAL { this.logger.debug('latLonData initialized'); } catch (error) { - this.logger.error({ message: `Failed to initialize latLon data.`, error }); + this.logger.error({ msg: `Failed to initialize latLon data.`, error }); this.dataLoadError = true; } finally { this.onGoingUpdate = false; @@ -111,7 +111,7 @@ export class LatLonDAL { try { await fs.promises.unlink(latLonDataPath); } catch (error) { - this.logger.error({ message: `Failed to delete latLonData file ${latLonDataPath}.`, error }); + this.logger.error({ msg: `Failed to delete latLonData file ${latLonDataPath}.`, error }); } this.logger.info('loadLatLonData: update completed'); } @@ -147,7 +147,7 @@ export const cronLoadTileLatLonDataFactory: FactoryFunction if (!latLonDAL.getOnGoingUpdate()) { logger.info('cronLoadTileLatLonData: starting update'); latLonDAL.init().catch((error: Error) => { - logger.error({ message: 'cronLoadTileLatLonData: update failed', error }); + logger.error({ msg: 'cronLoadTileLatLonData: update failed', error }); }); } else { logger.info('cronLoadTileLatLonData: update is already in progress'); diff --git a/src/latLon/controllers/latLonController.ts b/src/latLon/controllers/latLonController.ts index 555efe04..97bb8825 100644 --- a/src/latLon/controllers/latLonController.ts +++ b/src/latLon/controllers/latLonController.ts @@ -39,7 +39,7 @@ export class LatLonController { return res.status(httpStatus.OK).json(response); } catch (error: unknown) { - this.logger.warn('latLonController.getCoordinates Error:', error); + this.logger.error({ msG: 'latLonController.getCoordinates error', error }); next(error); } }; diff --git a/src/latLon/models/latLonManager.ts b/src/latLon/models/latLonManager.ts index b1706cb0..8b1cd06e 100644 --- a/src/latLon/models/latLonManager.ts +++ b/src/latLon/models/latLonManager.ts @@ -26,14 +26,14 @@ export class LatLonManager { public async latLonToTile({ lat, lon, targetGrid }: WGS84Coordinate & { targetGrid: string }): Promise { if (!validateWGS84Coordinate({ lat, lon })) { - this.logger.warn("LatLonManager.latLonToTile: Invalid lat lon, check 'lat' and 'lon' keys exists and their values are legal"); + this.logger.error({ msg: "LatLonManager.latLonToTile: Invalid lat lon, check 'lat' and 'lon' keys exists and their values are legal" }); throw new BadRequestError("Invalid lat lon, check 'lat' and 'lon' keys exists and their values are legal"); } const utm = convertWgs84ToUTM({ longitude: lon, latitude: lat }); if (typeof utm === 'string') { - this.logger.warn('LatLonManager.latLonToTile: utm is string'); + this.logger.error({ msg: 'LatLonManager.latLonToTile: utm is string' }); throw new BadRequestError('utm is string'); } @@ -46,7 +46,7 @@ export class LatLonManager { const tileCoordinateData = await this.latLonDAL.latLonToTile({ x: coordinatesUTM.x, y: coordinatesUTM.y, zone: coordinatesUTM.zone }); if (!tileCoordinateData) { - this.logger.warn('LatLonManager.latLonToTile: The coordinate is outside the grid extent'); + this.logger.error({ msg: 'LatLonManager.latLonToTile: The coordinate is outside the grid extent' }); throw new BadRequestError('The coordinate is outside the grid extent'); } diff --git a/src/location/DAL/locationRepository.ts b/src/location/DAL/locationRepository.ts index bf201ad3..7fdf8f81 100644 --- a/src/location/DAL/locationRepository.ts +++ b/src/location/DAL/locationRepository.ts @@ -25,7 +25,7 @@ const createGeotextRepository = (client: ElasticClient, logger: Logger) => { if (!tokens || !tokens.length || !prediction || !prediction.length) { const message = 'No tokens or prediction'; - logger.error({ message }); + logger.error({ msg: message }); throw new BadRequestError(message); } diff --git a/src/location/controllers/locationController.ts b/src/location/controllers/locationController.ts index 85908055..41739e72 100644 --- a/src/location/controllers/locationController.ts +++ b/src/location/controllers/locationController.ts @@ -47,7 +47,7 @@ export class GeotextSearchController { const response = await this.manager.search({ query, region, source, disableFuzziness, geoContext, geoContextMode, limit }); return res.status(httpStatus.OK).json(response); } catch (error: unknown) { - this.logger.error({ message: 'Error in getGeotextSearch', error }); + this.logger.error({ msg: 'Error in getGeotextSearch', error }); next(error); } }; diff --git a/src/mgrs/controllers/mgrsController.ts b/src/mgrs/controllers/mgrsController.ts index c0b459e9..4ce70797 100644 --- a/src/mgrs/controllers/mgrsController.ts +++ b/src/mgrs/controllers/mgrsController.ts @@ -42,7 +42,7 @@ export class MgrsController { const response = this.manager.getTile({ tile }); return res.status(httpStatus.OK).json(response); } catch (error: unknown) { - this.logger.error({ message: 'MgrsController.getTile', error }); + this.logger.error({ msg: 'MgrsController.getTile', error }); next(error); } }; diff --git a/src/mgrs/models/mgrsManager.ts b/src/mgrs/models/mgrsManager.ts index 5c967805..c4b0db49 100644 --- a/src/mgrs/models/mgrsManager.ts +++ b/src/mgrs/models/mgrsManager.ts @@ -26,7 +26,7 @@ export class MgrsManager { if ((error as Error).message.includes('MGRSPoint bad conversion')) { throw new BadRequestError('Invalid MGRS tile'); } - this.logger.error({ message: 'Failed to convert MGRS tile to bbox.', error }); + this.logger.error({ msg: 'Failed to convert MGRS tile to bbox.', error }); throw error; } From b78e5c041c73ffd2c119764badbb976c88b0e765 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 12:45:36 +0300 Subject: [PATCH 20/33] feat(control/unit/item): created unit tests --- tests/unit/control/item/item.spec.ts | 110 +++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 tests/unit/control/item/item.spec.ts diff --git a/tests/unit/control/item/item.spec.ts b/tests/unit/control/item/item.spec.ts new file mode 100644 index 00000000..0fa1576e --- /dev/null +++ b/tests/unit/control/item/item.spec.ts @@ -0,0 +1,110 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import jsLogger from '@map-colonies/js-logger'; +import { estypes } from '@elastic/elasticsearch'; +import { ItemQueryParams } from '../../../../src/control/item/DAL/queries'; +import { ItemRepository } from '../../../../src/control/item/DAL/itemRepository'; +import { ItemManager } from '../../../../src/control/item/models/itemManager'; +import { GenericGeocodingResponse, IApplication } from '../../../../src/common/interfaces'; +import { Item } from '../../../../src/control/item/models/item'; +import { convertCamelToSnakeCase } from '../../../../src/control/utils'; +import { ITEM_1234 } from '../../../mockObjects/items'; + +let itemManager: ItemManager; + +describe('#ItemManager', () => { + const getItems = jest.fn(); + const controlObjectDisplayNamePrefixes = { ITEM: 'Item' }; + beforeEach(() => { + jest.resetAllMocks(); + + const repository = { + getItems, + } as unknown as ItemRepository; + + itemManager = new ItemManager( + jsLogger({ enabled: false }), + {} as never, + { + controlObjectDisplayNamePrefixes, + } as unknown as IApplication, + repository + ); + }); + + test.each<{ + feature: Item; + queryParams: ItemQueryParams; + expectedNames: { + default: string[]; + display: string; + }; + mockFunction: jest.Mock; + }>([ + { + feature: ITEM_1234, + queryParams: { + commandName: ITEM_1234.properties.OBJECT_COMMAND_NAME, + limit: 5, + disableFuzziness: false, + }, + expectedNames: { + default: [ITEM_1234.properties.OBJECT_COMMAND_NAME], + display: `${controlObjectDisplayNamePrefixes.ITEM} ${ITEM_1234.properties.OBJECT_COMMAND_NAME}`, + }, + mockFunction: getItems, + }, + ])('should response with the right Geocoding GeoJSON', async ({ feature, queryParams, expectedNames, mockFunction }) => { + const hit: estypes.SearchResponse = { + took: 3, + timed_out: false, + _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, + hits: { + total: { value: 1, relation: 'eq' }, + max_score: 3.5145261, + hits: [ + { + _index: 'control_gil_v5', + _id: expect.any(String) as string, + _score: expect.any(Number) as number, + _source: feature, + }, + ], + }, + }; + + mockFunction.mockResolvedValue(hit); + + const generated = await itemManager.getItems(queryParams); + + expect(generated).toEqual>({ + type: 'FeatureCollection', + geocoding: { + version: process.env.npm_package_version as string, + query: convertCamelToSnakeCase(queryParams as unknown as Record), + response: { + results_count: 1, + max_score: expect.any(Number) as number, + match_latency_ms: expect.any(Number) as number, + }, + }, + features: [ + { + type: 'Feature', + properties: { + ...feature.properties, + matches: [ + { + layer: feature.properties.LAYER_NAME, + source: hit.hits.hits[0]._index, + source_id: [], + }, + ], + names: expectedNames, + score: expect.any(Number) as number, + }, + geometry: feature.geometry, + }, + ], + }); + }); +}); From 6906960313ebeba640c5d9fb6e0e6ed674bfbca1 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 13:14:45 +0300 Subject: [PATCH 21/33] fix: changed error to explicitly throw BadRequestError --- src/mgrs/models/mgrsManager.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/mgrs/models/mgrsManager.ts b/src/mgrs/models/mgrsManager.ts index c4b0db49..d9489585 100644 --- a/src/mgrs/models/mgrsManager.ts +++ b/src/mgrs/models/mgrsManager.ts @@ -1,11 +1,11 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { IConfig } from 'config'; import { Logger } from '@map-colonies/js-logger'; -import { BBox, Feature, Geometry } from 'geojson'; +import { BBox, Geometry } from 'geojson'; import { inject, injectable } from 'tsyringe'; import * as mgrs from 'mgrs'; import { SERVICES } from '../../common/constants'; -import { GenericGeocodingResponse, IApplication } from '../../common/interfaces'; +import { GenericGeocodingFeatureResponse, IApplication } from '../../common/interfaces'; import { GetTileQueryParams } from '../controllers/mgrsController'; import { BadRequestError } from '../../common/errors'; import { parseGeo } from '../../common/utils'; @@ -18,16 +18,13 @@ export class MgrsManager { @inject(SERVICES.APPLICATION) private readonly application: IApplication ) {} - public getTile({ tile }: GetTileQueryParams): Feature & Pick, 'geocoding'> { + public getTile({ tile }: GetTileQueryParams): GenericGeocodingFeatureResponse { let bbox: BBox | undefined; try { bbox = mgrs.inverse(tile); } catch (error) { - if ((error as Error).message.includes('MGRSPoint bad conversion')) { - throw new BadRequestError('Invalid MGRS tile'); - } this.logger.error({ msg: 'Failed to convert MGRS tile to bbox.', error }); - throw error; + throw new BadRequestError(`Invalid MGRS tile. ${(error as Error).message}`); } const geometry = parseGeo({ bbox }) as Geometry; From 05fdf9bd7b779f1ead6a9d9c62f3c001d476fe80 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 13:14:57 +0300 Subject: [PATCH 22/33] fix: fixed expected error --- tests/integration/mgrs/mgrs.spec.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/integration/mgrs/mgrs.spec.ts b/tests/integration/mgrs/mgrs.spec.ts index 0b885b36..77977cc5 100644 --- a/tests/integration/mgrs/mgrs.spec.ts +++ b/tests/integration/mgrs/mgrs.spec.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ +import 'jest-openapi'; import { DependencyContainer } from 'tsyringe'; import { Application } from 'express'; import { CleanupRegistry } from '@map-colonies/cleanup-registry'; @@ -84,7 +85,7 @@ describe('/search/MGRS', function () { const response = await requestSender.getTile({ tile: 'ABC{}' }); expect(response.body).toMatchObject({ - message: 'Invalid MGRS tile', + message: 'Invalid MGRS tile. MGRSPoint bad conversion from ABC{}', }); expect(response.status).toBe(httpStatusCodes.BAD_REQUEST); }); @@ -97,16 +98,13 @@ describe('/search/MGRS', function () { message: "request/query must have required property 'tile'", }); }); - }); - describe('Sad Path', function () { - // All requests with status code 4XX-5XX it('should return 500 status code when MGRSPoint zone letter A not handled', async function () { const response = await requestSender.getTile({ tile: '{ABC}' }); - expect(response.status).toBe(httpStatusCodes.INTERNAL_SERVER_ERROR); + expect(response.status).toBe(httpStatusCodes.BAD_REQUEST); expect(response.body).toMatchObject({ - message: 'MGRSPoint zone letter A not handled: {ABC}', + message: 'Invalid MGRS tile. MGRSPoint zone letter A not handled: {ABC}', }); }); }); From 5527193d09134e7e3a00eedd26e089026d6401a2 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 13:15:16 +0300 Subject: [PATCH 23/33] feat(tests/unit/mgrs): unit tests created --- tests/unit/mgrs/mges.spec.ts | 73 ++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 tests/unit/mgrs/mges.spec.ts diff --git a/tests/unit/mgrs/mges.spec.ts b/tests/unit/mgrs/mges.spec.ts new file mode 100644 index 00000000..508915b6 --- /dev/null +++ b/tests/unit/mgrs/mges.spec.ts @@ -0,0 +1,73 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import jsLogger from '@map-colonies/js-logger'; +import { MgrsManager } from '../../../src/mgrs/models/mgrsManager'; +import { GetTileQueryParams } from '../../../src/mgrs/controllers/mgrsController'; +import { GenericGeocodingFeatureResponse } from '../../../src/common/interfaces'; +import { BadRequestError } from '../../../src/common/errors'; + +let mgrsManager: MgrsManager; +describe('#MgrsManager', () => { + beforeEach(() => { + mgrsManager = new MgrsManager(jsLogger({ enabled: false }), {} as never, {} as never); + }); + + describe('happy path', () => { + it('should return mgrs tile in its GeoJSON Representation', () => { + const queryParams: GetTileQueryParams = { + tile: '18SUJ2339007393', + }; + + const response = mgrsManager.getTile(queryParams); + + expect(response).toEqual({ + type: 'Feature', + geocoding: { + version: process.env.npm_package_version as string, + query: { + tile: queryParams.tile, + }, + response: { + max_score: 1, + results_count: 1, + match_latency_ms: expect.any(Number) as number, + }, + }, + bbox: [-77.03654883669269, 38.89767541638445, -77.03653756947197, 38.897684623284015], + geometry: { + type: 'Polygon', + coordinates: [ + [ + [-77.03654883669269, 38.89767541638445], + [-77.03654883669269, 38.897684623284015], + [-77.03653756947197, 38.897684623284015], + [-77.03653756947197, 38.89767541638445], + [-77.03654883669269, 38.89767541638445], + ], + ], + }, + properties: { + score: 1, + }, + }); + }); + }); + describe('sad path', () => { + it('should throw a BadRequestError for invalid MGRS tile', () => { + const queryParams: GetTileQueryParams = { + tile: 'ABC{}', + }; + + expect(() => mgrsManager.getTile(queryParams)).toThrow(new BadRequestError('Invalid MGRS tile. MGRSPoint bad conversion from ABC{}')); + }); + }); + + describe('bad path', () => { + it('should throw an error for invalid MGRS tile', () => { + const queryParams: GetTileQueryParams = { + tile: '{ABC}', + }; + + expect(() => mgrsManager.getTile(queryParams)).toThrow(new BadRequestError('Invalid MGRS tile. MGRSPoint zone letter A not handled: {ABC}')); + }); + }); +}); From e415ab4b8cc441ede57a2cd1379de46bd93f5373 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 14:58:45 +0300 Subject: [PATCH 24/33] fix: fixed GenericGeocodingFeatureResponse to inherit the Feture type from GenericGeocodingResponse --- src/common/interfaces.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/common/interfaces.ts b/src/common/interfaces.ts index 2683ca6f..02cf445e 100644 --- a/src/common/interfaces.ts +++ b/src/common/interfaces.ts @@ -109,4 +109,5 @@ export interface GenericGeocodingResponse extends Fe })[]; } -export type GenericGeocodingFeatureResponse = Feature & Pick, 'geocoding'>; +export type GenericGeocodingFeatureResponse = GenericGeocodingResponse['features'][number] & + Pick, 'geocoding'>; From 3aec89685eb3f1d2f2f6ed1e7bc202700a21b6d2 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 14:58:59 +0300 Subject: [PATCH 25/33] fix: fixed returned value accoriding to the type --- src/latLon/models/latLonManager.ts | 31 +++++++++++++++++++++++++----- src/mgrs/models/mgrsManager.ts | 11 +++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/latLon/models/latLonManager.ts b/src/latLon/models/latLonManager.ts index 8b1cd06e..645b2545 100644 --- a/src/latLon/models/latLonManager.ts +++ b/src/latLon/models/latLonManager.ts @@ -89,7 +89,18 @@ export class LatLonManager { coordinates: [lon, lat], }, properties: { - name: tileCoordinateData.tile_name, + matches: [ + { + layer: 'convertionTable', + source: 'mapcolonies', + // eslint-disable-next-line @typescript-eslint/naming-convention + source_id: [], + }, + ], + names: { + default: [tileCoordinateData.tile_name], + display: tileCoordinateData.tile_name, + }, tileName: tileCoordinateData.tile_name, subTileNumber: new Array(SUB_TILE_LENGTH).fill('').map(function (value, i) { return xNumber[i] + yNumber[i]; @@ -103,9 +114,7 @@ export class LatLonManager { lon, accuracy = MGRS_ACCURACY, targetGrid, - }: { - lat: number; - lon: number; + }: WGS84Coordinate & { accuracy?: number; targetGrid: string; }): GenericGeocodingFeatureResponse { @@ -139,9 +148,21 @@ export class LatLonManager { coordinates: [lon, lat], }, properties: { - name: mgrsStr, + matches: [ + { + layer: 'MGRS', + source: 'npm/MGRS', + // eslint-disable-next-line @typescript-eslint/naming-convention + source_id: [], + }, + ], + names: { + default: [mgrsStr], + display: mgrsStr, + }, accuracy: accuracyString[accuracy], mgrs: mgrsStr, + score: 1, }, }; } diff --git a/src/mgrs/models/mgrsManager.ts b/src/mgrs/models/mgrsManager.ts index d9489585..7ef030e6 100644 --- a/src/mgrs/models/mgrsManager.ts +++ b/src/mgrs/models/mgrsManager.ts @@ -45,6 +45,17 @@ export class MgrsManager { bbox, geometry, properties: { + matches: [ + { + layer: 'MGRS', + source: 'npm/mgrs', + source_id: [], + }, + ], + names: { + default: [tile], + display: tile, + }, score: 1, }, }; From ba62404fc049b1229a76e88deb918d097509fc8e Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 14:59:24 +0300 Subject: [PATCH 26/33] fix(tests/unit/mgrs): fixed test --- tests/unit/mgrs/mges.spec.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/unit/mgrs/mges.spec.ts b/tests/unit/mgrs/mges.spec.ts index 508915b6..8c5d3c81 100644 --- a/tests/unit/mgrs/mges.spec.ts +++ b/tests/unit/mgrs/mges.spec.ts @@ -46,6 +46,17 @@ describe('#MgrsManager', () => { ], }, properties: { + matches: [ + { + layer: 'MGRS', + source: 'npm/mgrs', + source_id: [], + }, + ], + names: { + default: ['18SUJ2339007393'], + display: '18SUJ2339007393', + }, score: 1, }, }); From 19b362bbe3720ddb58db3807b801c53e96928240 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 14:59:40 +0300 Subject: [PATCH 27/33] feat(tests/unit/latLon): created unit tests --- tests/unit/latLon/latLon.spec.ts | 171 +++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 tests/unit/latLon/latLon.spec.ts diff --git a/tests/unit/latLon/latLon.spec.ts b/tests/unit/latLon/latLon.spec.ts new file mode 100644 index 00000000..8bfb31bc --- /dev/null +++ b/tests/unit/latLon/latLon.spec.ts @@ -0,0 +1,171 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import jsLogger from '@map-colonies/js-logger'; +import { LatLonManager } from '../../../src/latLon/models/latLonManager'; +import { LatLonDAL } from '../../../src/latLon/DAL/latLonDAL'; +import { GenericGeocodingFeatureResponse, WGS84Coordinate } from '../../../src/common/interfaces'; +import { convertCamelToSnakeCase } from '../../../src/control/utils'; +import { BadRequestError } from '../../../src/common/errors'; +import * as CommonUtils from '../../../src/common/utils'; + +type QueryParams = WGS84Coordinate & { targetGrid: 'control' | 'MGRS' }; + +let latLonManager: LatLonManager; +describe('#LatLonManager', () => { + const latLonToTile = jest.fn(); + beforeEach(() => { + jest.resetAllMocks(); + const repositry = { latLonToTile } as unknown as LatLonDAL; + latLonManager = new LatLonManager(jsLogger({ enabled: false }), repositry, {} as never); + }); + + describe('happy path', () => { + it('should return control tile', async () => { + latLonToTile.mockResolvedValueOnce({ + tile_name: 'BRN', + zone: '33', + min_x: '360000', + min_y: '5820000', + ext_min_x: 360000, + ext_min_y: 5820000, + ext_max_x: 370000, + ext_max_y: 5830000, + }); + const queryParams: QueryParams = { + lat: 52.57326537485767, + lon: 12.948781146422107, + targetGrid: 'control', + }; + + const response = await latLonManager.latLonToTile(queryParams); + const minLongitude = 12.93694771534361, + minLatitude = 52.51211561266182, + maxLongitude = 13.080296161196031, + maxLatitude = 52.60444267653175; + + expect(response).toEqual({ + type: 'Feature', + geocoding: { + version: process.env.npm_package_version as string, + query: convertCamelToSnakeCase(queryParams as unknown as Record), + response: { + max_score: 1, + results_count: 1, + match_latency_ms: expect.any(Number) as number, + }, + }, + bbox: [minLongitude, minLatitude, maxLongitude, maxLatitude], + geometry: { + type: 'Polygon', + coordinates: [ + [ + [minLongitude, minLatitude], + [minLongitude, maxLatitude], + [maxLongitude, maxLatitude], + [maxLongitude, minLatitude], + [minLongitude, minLatitude], + ], + ], + }, + properties: { + matches: [ + { + layer: 'convertionTable', + source: 'mapcolonies', + source_id: [], + }, + ], + names: { + default: ['BRN'], + display: 'BRN', + }, + tileName: 'BRN', + subTileNumber: ['06', '97', '97'], + }, + }); + }); + + it('should return MGRS tile', () => { + const queryParams: QueryParams = { + lat: 52.57326537485767, + lon: 12.948781146422107, + targetGrid: 'MGRS', + }; + + const response = latLonManager.latLonToMGRS(queryParams); + + expect(response).toEqual({ + type: 'Feature', + geocoding: { + version: process.env.npm_package_version as string, + query: convertCamelToSnakeCase(queryParams as unknown as Record), + response: { + max_score: 1, + results_count: 1, + match_latency_ms: expect.any(Number) as number, + }, + }, + bbox: [12.948777289238832, 52.57325754975297, 12.948791616108007, 52.57326678960368], + geometry: { + type: 'Point', + coordinates: [12.948781146422107, 52.57326537485767], + }, + properties: { + matches: [ + { + layer: 'MGRS', + source: 'npm/MGRS', + source_id: [], + }, + ], + names: { + default: ['33UUU6099626777'], + display: '33UUU6099626777', + }, + accuracy: '1m', + mgrs: '33UUU6099626777', + score: 1, + }, + }); + }); + }); + + describe('sad path', () => { + it('should throw BadRequestError when invalid coordiantes are being provided', async () => { + const queryParams: QueryParams = { + lat: 100, + lon: 200, + targetGrid: 'control', + }; + + await expect(latLonManager.latLonToTile(queryParams)).rejects.toThrow( + new BadRequestError("Invalid lat lon, check 'lat' and 'lon' keys exists and their values are legal") + ); + }); + + it('should throw BadRequestError when the coordinate is outside the grid extent', async () => { + latLonToTile.mockResolvedValueOnce(null); + const queryParams: QueryParams = { + lat: 52.57326537485767, + lon: 12.948781146422107, + targetGrid: 'control', + }; + + await expect(latLonManager.latLonToTile(queryParams)).rejects.toThrow(new BadRequestError('The coordinate is outside the grid extent')); + }); + + it('should throw BadRequestError when convertWgs84ToUTM resolves as a string', async () => { + const spy = jest.spyOn(CommonUtils, 'convertWgs84ToUTM'); + spy.mockReturnValueOnce('abc'); + + const queryParams: QueryParams = { + lat: 52.57326537485767, + lon: 12.948781146422107, + targetGrid: 'control', + }; + + await expect(latLonManager.latLonToTile(queryParams)).rejects.toThrow(new BadRequestError('utm is string')); + + spy.mockClear(); + }); + }); +}); From 03fe36ce813e646206cfa0dfd92587bbc9d02bf5 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 15:05:30 +0300 Subject: [PATCH 28/33] fix: fixed tests to new type response --- tests/integration/latLon/latLon.spec.ts | 30 +++++++++++++++++++++---- tests/integration/mgrs/mgrs.spec.ts | 11 +++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/tests/integration/latLon/latLon.spec.ts b/tests/integration/latLon/latLon.spec.ts index fe50dd93..add94956 100644 --- a/tests/integration/latLon/latLon.spec.ts +++ b/tests/integration/latLon/latLon.spec.ts @@ -9,6 +9,7 @@ import httpStatusCodes from 'http-status-codes'; import { getApp } from '../../../src/app'; import { SERVICES } from '../../../src/common/constants'; import { LatLonDAL } from '../../../src/latLon/DAL/latLonDAL'; +import { GenericGeocodingFeatureResponse } from '../../../src/common/interfaces'; import { LatLonRequestSender } from './helpers/requestSender'; describe('/lookup', function () { @@ -45,7 +46,7 @@ describe('/lookup', function () { expect(response.status).toBe(httpStatusCodes.OK); expect(response).toSatisfyApiSpec(); - expect(response.body).toEqual({ + expect(response.body).toEqual({ type: 'Feature', geocoding: { version: expect.any(String) as string, @@ -74,7 +75,17 @@ describe('/lookup', function () { ], }, properties: { - name: 'BRN', + matches: [ + { + layer: 'convertionTable', + source: 'mapcolonies', + source_id: [], + }, + ], + names: { + default: ['BRN'], + display: 'BRN', + }, tileName: 'BRN', subTileNumber: ['06', '97', '97'], }, @@ -90,7 +101,7 @@ describe('/lookup', function () { expect(response.status).toBe(httpStatusCodes.OK); expect(response).toSatisfyApiSpec(); - expect(response.body).toEqual({ + expect(response.body).toEqual({ type: 'Feature', geocoding: { version: expect.any(String) as string, @@ -111,9 +122,20 @@ describe('/lookup', function () { coordinates: [12.948781146422107, 52.57326537485767], }, properties: { - name: '33UUU6099626777', + matches: [ + { + layer: 'MGRS', + source: 'npm/MGRS', + source_id: [], + }, + ], + names: { + default: ['33UUU6099626777'], + display: '33UUU6099626777', + }, accuracy: '1m', mgrs: '33UUU6099626777', + score: 1, }, }); }); diff --git a/tests/integration/mgrs/mgrs.spec.ts b/tests/integration/mgrs/mgrs.spec.ts index 77977cc5..3e581475 100644 --- a/tests/integration/mgrs/mgrs.spec.ts +++ b/tests/integration/mgrs/mgrs.spec.ts @@ -74,6 +74,17 @@ describe('/search/MGRS', function () { ], }, properties: { + matches: [ + { + layer: 'MGRS', + source: 'npm/mgrs', + source_id: [], + }, + ], + names: { + default: ['18SUJ2339007393'], + display: '18SUJ2339007393', + }, score: 1, }, }); From a06011cfbc5a865681f3e89513b95be31ea887c7 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 15:08:18 +0300 Subject: [PATCH 29/33] delete: removed duplicated tests --- tests/unit/control/utils.spec.ts | 128 +------------------------------ 1 file changed, 1 insertion(+), 127 deletions(-) diff --git a/tests/unit/control/utils.spec.ts b/tests/unit/control/utils.spec.ts index 36302478..494a61fc 100644 --- a/tests/unit/control/utils.spec.ts +++ b/tests/unit/control/utils.spec.ts @@ -1,17 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import config from 'config'; import { estypes } from '@elastic/elasticsearch'; -import { IApplication } from '../../../src/common/interfaces'; -import { ItemQueryParams } from '../../../src/control/item/DAL/queries'; -import { Item } from '../../../src/control/item/models/item'; -import { RouteQueryParams } from '../../../src/control/route/DAL/queries'; -import { Route } from '../../../src/control/route/models/route'; -import { TileQueryParams } from '../../../src/control/tile/DAL/queries'; -import { Tile } from '../../../src/control/tile/models/tile'; -import { additionalControlSearchProperties, convertCamelToSnakeCase, formatResponse } from '../../../src/control/utils'; -import { ITEM_1234 } from '../../mockObjects/items'; -import { CONTROL_POINT_OLIMPIADE_111, ROUTE_VIA_CAMILLUCCIA_A } from '../../mockObjects/routes'; -import { RIC_TILE, SUB_TILE_66 } from '../../mockObjects/tiles'; +import { additionalControlSearchProperties, convertCamelToSnakeCase } from '../../../src/control/utils'; import { elasticConfigPath } from '../../../src/common/constants'; import { ElasticDbClientsConfig } from '../../../src/common/elastic/interfaces'; import { CONTROL_FIELDS } from '../../../src/control/constants'; @@ -32,122 +22,6 @@ describe('#convertCamelToSnakeCase', () => { }); }); -type ControlTypesQueryParams = TileQueryParams | ItemQueryParams | RouteQueryParams; -describe('#formatResponse', () => { - test.each<{ - feature: Tile | Item | Route; - partialQuery: Partial; - expectedNames: { - default: string[]; - display: string; - }; - }>([ - { - feature: RIC_TILE, - partialQuery: { tile: 'RIC' }, - expectedNames: { - default: ['RIC'], - display: 'Tile RIC', - }, - }, - { - feature: SUB_TILE_66, - partialQuery: { tile: 'RIC', subTile: '66' }, - expectedNames: { - default: ['66'], - display: 'Tile RIT Sub Tile 66', - }, - }, - { - feature: ROUTE_VIA_CAMILLUCCIA_A, - partialQuery: { commandName: 'via camillucciaA' }, - expectedNames: { - default: ['via camillucciaA'], - display: 'Route via camillucciaA', - }, - }, - { - feature: CONTROL_POINT_OLIMPIADE_111, - partialQuery: { commandName: 'olimpiade', controlPoint: '111' }, - expectedNames: { - default: ['111'], - display: 'Route olimpiade Control Point 111', - }, - }, - { - feature: ITEM_1234, - partialQuery: { commandName: '1234' }, - expectedNames: { - default: ['1234'], - display: 'Item 1234', - }, - }, - ])('should format elastic response to geocoding response', ({ partialQuery, feature, expectedNames }) => { - const displayNamePrefixes: IApplication['controlObjectDisplayNamePrefixes'] = { - TILE: 'Tile', - SUB_TILE: 'Sub Tile', - ROUTE: 'Route', - ITEM: 'Item', - CONTROL_POINT: 'Control Point', - }; - - const query: ControlTypesQueryParams = { disableFuzziness: true, limit: 5, ...partialQuery }; - - const generated = formatResponse( - { - took: 3, - timed_out: false, - _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, - hits: { - total: { value: 1, relation: 'eq' }, - max_score: 3.5145261, - hits: [ - { - _index: 'control_gil_v5', - _id: expect.any(String) as string, - _score: expect.any(Number) as number, - _source: feature, - }, - ], - }, - }, - query, - displayNamePrefixes - ); - - expect(generated).toEqual({ - type: 'FeatureCollection', - geocoding: { - version: process.env.npm_package_version as string, - query: convertCamelToSnakeCase(query as unknown as Record), - response: { - results_count: 1, - max_score: expect.any(Number) as number, - match_latency_ms: expect.any(Number) as number, - }, - }, - features: [ - { - type: 'Feature', - properties: { - ...feature.properties, - matches: [ - { - layer: feature.properties.LAYER_NAME, - source: 'control_gil_v5', - source_id: [], - }, - ], - names: expectedNames, - score: expect.any(Number) as number, - }, - geometry: feature.geometry, - }, - ], - }); - }); -}); - describe('#additionalControlSearchProperties', () => { it('should return additional control search properties', () => { const size = 5; From 22bdc7c810bca64cbdfe708e4962430bcf1c6315 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 16:20:13 +0300 Subject: [PATCH 30/33] feat(tests/unit/location): created unit tests --- tests/unit/control/location/location.spec.ts | 154 +++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 tests/unit/control/location/location.spec.ts diff --git a/tests/unit/control/location/location.spec.ts b/tests/unit/control/location/location.spec.ts new file mode 100644 index 00000000..2c8d5dba --- /dev/null +++ b/tests/unit/control/location/location.spec.ts @@ -0,0 +1,154 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import config from 'config'; +import jsLogger from '@map-colonies/js-logger'; +import { Feature } from 'geojson'; +import { estypes } from '@elastic/elasticsearch'; +import { GeotextRepository } from '../../../../src/location/DAL/locationRepository'; +import { GeotextSearchManager } from '../../../../src/location/models/locationManager'; +import { GenericGeocodingResponse, IApplication } from '../../../../src/common/interfaces'; +import { ConvertSnakeToCamelCase } from '../../../../src/common/utils'; +import { GetGeotextSearchParams } from '../../../../src/location/interfaces'; +import { NY_JFK_AIRPORT } from '../../../mockObjects/locations'; +import { convertCamelToSnakeCase } from '../../../../src/control/utils'; +import { expectedResponse } from '../../../integration/location/utils'; + +let geotextSearchManager: GeotextSearchManager; +describe('#GeotextSearchManager', () => { + const extractName = jest.fn(); + const generatePlacetype = jest.fn(); + const extractHierarchy = jest.fn(); + const geotextSearch = jest.fn(); + beforeEach(() => { + jest.resetAllMocks(); + + const repositry = { + extractName, + generatePlacetype, + extractHierarchy, + geotextSearch, + } as unknown as GeotextRepository; + + geotextSearchManager = new GeotextSearchManager(jsLogger({ enabled: false }), config.get('application'), config, repositry); + }); + it('should return location response', async () => { + const extractNameResolve = { name: '', latency: 7 }; + const generatePlacetypeResolve = { + placeTypes: ['transportation'], + subPlaceTypes: ['airport'], + matchLatencyMs: 6, + }; + const extractHierarchyResolve = { + hierarchies: [], + matchLatencyMs: 1, + }; + + extractName.mockResolvedValueOnce(extractNameResolve); + generatePlacetype.mockResolvedValueOnce(generatePlacetypeResolve); + extractHierarchy.mockResolvedValueOnce(extractHierarchyResolve); + geotextSearch.mockResolvedValueOnce({ + took: 2, + timed_out: false, + _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, + hits: { + total: { value: 3, relation: 'eq' }, + max_score: 1.2880917, + hits: [ + { + _index: expect.any(String) as string, + _id: expect.any(String) as string, + _score: 1.2880917, + _source: { + source: NY_JFK_AIRPORT.properties.matches[0].source, + layer_name: NY_JFK_AIRPORT.properties.matches[0].layer, + source_id: NY_JFK_AIRPORT.properties.matches[0].source_id, + placetype: NY_JFK_AIRPORT.properties.placetype as string, + sub_placetype: NY_JFK_AIRPORT.properties.sub_placetype as string, + geo_json: NY_JFK_AIRPORT.geometry, + region: [(NY_JFK_AIRPORT.properties.regions as { region: string }[])[0].region], + sub_region: (NY_JFK_AIRPORT.properties.regions as { sub_region_names: string[] }[])[0].sub_region_names, + name: NY_JFK_AIRPORT.properties.names.default[0], + text: [NY_JFK_AIRPORT.properties.names.display], + translated_text: NY_JFK_AIRPORT.properties.names.fr, + }, + }, + ], + }, + }); + + const query: ConvertSnakeToCamelCase = { + query: 'airport', + disableFuzziness: false, + limit: 1, + }; + + const response = await geotextSearchManager.search(query); + + expect(response).toEqual>( + expectedResponse( + { + ...(convertCamelToSnakeCase(query as unknown as Record) as unknown as GetGeotextSearchParams), + geo_context: undefined, + geo_context_mode: undefined, + region: undefined, + source: undefined, + }, + { + place_types: ['transportation'], + sub_place_types: ['airport'], + hierarchies: undefined, + name: '', + }, + [ + { + ...NY_JFK_AIRPORT, + properties: { + ...NY_JFK_AIRPORT.properties, + names: { + ...NY_JFK_AIRPORT.properties.names, + display: expect.stringContaining('JFK') as string, + }, + }, + }, + ], + expect + ) + ); + }); + + it('should return sources', () => { + const response = geotextSearchManager.sources(); + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + expect(response).toEqual(Object.keys(config.get('application').sources!)); + }); + it('should return regions', () => { + const response = geotextSearchManager.regions(); + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + expect(response).toEqual(Object.keys(config.get('application').regions!)); + }); + + it('should return empty sources array', () => { + geotextSearchManager = new GeotextSearchManager( + jsLogger({ enabled: false }), + {} as unknown as IApplication, + config, + {} as unknown as GeotextRepository + ); + + const response = geotextSearchManager.sources(); + expect(response).toEqual(Object.keys({})); + }); + + it('should return empty regions array', () => { + geotextSearchManager = new GeotextSearchManager( + jsLogger({ enabled: false }), + {} as unknown as IApplication, + config, + {} as unknown as GeotextRepository + ); + + const response = geotextSearchManager.regions(); + expect(response).toEqual(Object.keys({})); + }); +}); From e8c91c16c4c2e13c39286ba7e55e97f501bd5536 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Mon, 21 Oct 2024 16:29:54 +0300 Subject: [PATCH 31/33] chore: moved cleanQuery function location --- src/location/DAL/locationRepository.ts | 7 +++++-- src/location/utils.ts | 9 ++------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/location/DAL/locationRepository.ts b/src/location/DAL/locationRepository.ts index 7fdf8f81..d436be44 100644 --- a/src/location/DAL/locationRepository.ts +++ b/src/location/DAL/locationRepository.ts @@ -2,7 +2,7 @@ import { Logger } from '@map-colonies/js-logger'; import { estypes } from '@elastic/elasticsearch'; import { FactoryFunction } from 'tsyringe'; import { ElasticClient } from '../../common/elastic'; -import { cleanQuery, fetchNLPService } from '../utils'; +import { fetchNLPService } from '../utils'; import { TextSearchParams, TokenResponse } from '../interfaces'; import { PlaceTypeSearchHit, HierarchySearchHit, TextSearchHit } from '../models/elasticsearchHits'; import { BadRequestError } from '../../common/errors'; @@ -12,7 +12,10 @@ import { queryElastic } from '../../common/elastic/utils'; import { SERVICES } from '../../common/constants'; import { hierarchyQuery, placetypeQuery, geotextQuery } from './queries'; -/* eslint-enable @typescript-eslint/naming-convention */ +const FIND_QUOTES = /["']/g; + +const FIND_SPECIAL = /[`!@#$%^&*()_\-+=|\\/,.<>:[\]{}\n\t\r\s;؛]+/g; +const cleanQuery = (query: string): string[] => query.replace(FIND_QUOTES, '').split(FIND_SPECIAL); // eslint-disable-next-line @typescript-eslint/explicit-function-return-type const createGeotextRepository = (client: ElasticClient, logger: Logger) => { diff --git a/src/location/utils.ts b/src/location/utils.ts index 7f9e0a71..03b69e80 100644 --- a/src/location/utils.ts +++ b/src/location/utils.ts @@ -9,14 +9,11 @@ import { TextSearchParams } from './interfaces'; import { TextSearchHit } from './models/elasticsearchHits'; import { generateDisplayName } from './parsing'; -const FIND_QUOTES = /["']/g; - -const FIND_SPECIAL = /[`!@#$%^&*()_\-+=|\\/,.<>:[\]{}\n\t\r\s;؛]+/g; - const axiosInstance = axios.create({ httpsAgent: new https.Agent({ rejectUnauthorized: false }), }); +/* istanbul ignore next */ export const fetchNLPService = async (endpoint: string, requestData: object): Promise<{ data: T[]; latency: number }> => { let res: Response | null = null, data: T[] | undefined | null = null; @@ -38,8 +35,6 @@ export const fetchNLPService = async (endpoint: string, requestData: object): return { data, latency }; }; -export const cleanQuery = (query: string): string[] => query.replace(FIND_QUOTES, '').split(FIND_SPECIAL); - /* eslint-disable @typescript-eslint/naming-convention */ export const convertResult = ( params: TextSearchParams, @@ -61,7 +56,7 @@ export const convertResult = ( placeType: number; hierarchies: number; }; - } = { nameKeys: [], mainLanguageRegex: '', externalResourcesLatency: { query: 0, nlpAnalyser: 0, placeType: 0, hierarchies: 0 } } + } ): GenericGeocodingResponse => ({ type: 'FeatureCollection', geocoding: { From 4d361cfb60ce5145aeae68a0d64d32cd8e3127ef Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Wed, 23 Oct 2024 13:32:12 +0300 Subject: [PATCH 32/33] chore: added test case variety --- devScripts/geotextElasticsearchData.json | 4 ++-- tests/mockObjects/locations.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/devScripts/geotextElasticsearchData.json b/devScripts/geotextElasticsearchData.json index 0581ea2c..21652cbd 100644 --- a/devScripts/geotextElasticsearchData.json +++ b/devScripts/geotextElasticsearchData.json @@ -58,8 +58,8 @@ "geometry_hash": "f14be42df6ec5cf2290d764a89e3009b", "region": ["USA"], "sub_region": ["New York"], - "name": "JFK", - "text": ["JFK Airport"], + "name": "JFK International Airport", + "text": ["JFK International Airport", "John F Kennedy International Airport"], "translated_text": ["Aeropuerto JFK"], "text_language": "en" } diff --git a/tests/mockObjects/locations.ts b/tests/mockObjects/locations.ts index 2bdadd1d..ec1f0f35 100644 --- a/tests/mockObjects/locations.ts +++ b/tests/mockObjects/locations.ts @@ -49,10 +49,10 @@ export const NY_JFK_AIRPORT: MockLocationQueryFeature = { properties: { matches: [{ source: 'OSM', layer: 'osm_airports', source_id: ['03ed6d97-fc81-4340-b68a-11993554eef1'] }], names: { - en: ['JFK Airport'], + en: ['JFK International Airport', 'John F Kennedy International Airport'], fr: ['Aeropuerto JFK'], - default: ['JFK'], - display: 'JFK Airport', + default: ['JFK International Airport'], + display: 'John F Kennedy International Airport', }, placetype: 'transportation', sub_placetype: 'airport', From 62b839294e14dbb6d9a62147a4ecbf12c4184c59 Mon Sep 17 00:00:00 2001 From: Niv Greenstein Date: Wed, 23 Oct 2024 13:32:41 +0300 Subject: [PATCH 33/33] fix: changed to also include highlight test-case --- tests/unit/control/location/location.spec.ts | 157 ++++++++++--------- 1 file changed, 81 insertions(+), 76 deletions(-) diff --git a/tests/unit/control/location/location.spec.ts b/tests/unit/control/location/location.spec.ts index 2c8d5dba..320d496c 100644 --- a/tests/unit/control/location/location.spec.ts +++ b/tests/unit/control/location/location.spec.ts @@ -30,90 +30,95 @@ describe('#GeotextSearchManager', () => { geotextSearchManager = new GeotextSearchManager(jsLogger({ enabled: false }), config.get('application'), config, repositry); }); - it('should return location response', async () => { - const extractNameResolve = { name: '', latency: 7 }; - const generatePlacetypeResolve = { - placeTypes: ['transportation'], - subPlaceTypes: ['airport'], - matchLatencyMs: 6, - }; - const extractHierarchyResolve = { - hierarchies: [], - matchLatencyMs: 1, - }; - extractName.mockResolvedValueOnce(extractNameResolve); - generatePlacetype.mockResolvedValueOnce(generatePlacetypeResolve); - extractHierarchy.mockResolvedValueOnce(extractHierarchyResolve); - geotextSearch.mockResolvedValueOnce({ - took: 2, - timed_out: false, - _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, - hits: { - total: { value: 3, relation: 'eq' }, - max_score: 1.2880917, - hits: [ - { - _index: expect.any(String) as string, - _id: expect.any(String) as string, - _score: 1.2880917, - _source: { - source: NY_JFK_AIRPORT.properties.matches[0].source, - layer_name: NY_JFK_AIRPORT.properties.matches[0].layer, - source_id: NY_JFK_AIRPORT.properties.matches[0].source_id, - placetype: NY_JFK_AIRPORT.properties.placetype as string, - sub_placetype: NY_JFK_AIRPORT.properties.sub_placetype as string, - geo_json: NY_JFK_AIRPORT.geometry, - region: [(NY_JFK_AIRPORT.properties.regions as { region: string }[])[0].region], - sub_region: (NY_JFK_AIRPORT.properties.regions as { sub_region_names: string[] }[])[0].sub_region_names, - name: NY_JFK_AIRPORT.properties.names.default[0], - text: [NY_JFK_AIRPORT.properties.names.display], - translated_text: NY_JFK_AIRPORT.properties.names.fr, + test.each([['JFK International Airport', 'John F Kennedy International Airport'], undefined])( + 'should return location response and highlight %s', + async (highlight) => { + const extractNameResolve = { name: '', latency: 7 }; + const generatePlacetypeResolve = { + placeTypes: ['transportation'], + subPlaceTypes: ['airport'], + matchLatencyMs: 6, + }; + const extractHierarchyResolve = { + hierarchies: [], + matchLatencyMs: 1, + }; + + extractName.mockResolvedValueOnce(extractNameResolve); + generatePlacetype.mockResolvedValueOnce(generatePlacetypeResolve); + extractHierarchy.mockResolvedValueOnce(extractHierarchyResolve); + geotextSearch.mockResolvedValueOnce({ + took: 2, + timed_out: false, + _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, + hits: { + total: { value: 3, relation: 'eq' }, + max_score: 1.2880917, + hits: [ + { + _index: expect.any(String) as string, + _id: expect.any(String) as string, + _score: 1.2880917, + _source: { + source: NY_JFK_AIRPORT.properties.matches[0].source, + layer_name: NY_JFK_AIRPORT.properties.matches[0].layer, + source_id: NY_JFK_AIRPORT.properties.matches[0].source_id, + placetype: NY_JFK_AIRPORT.properties.placetype as string, + sub_placetype: NY_JFK_AIRPORT.properties.sub_placetype as string, + geo_json: NY_JFK_AIRPORT.geometry, + region: [(NY_JFK_AIRPORT.properties.regions as { region: string }[])[0].region], + sub_region: (NY_JFK_AIRPORT.properties.regions as { sub_region_names: string[] }[])[0].sub_region_names, + name: NY_JFK_AIRPORT.properties.names.default[0], + text: NY_JFK_AIRPORT.properties.names.en, + translated_text: NY_JFK_AIRPORT.properties.names.fr, + }, + highlight: highlight ? { text: highlight } : undefined, }, - }, - ], - }, - }); + ], + }, + }); - const query: ConvertSnakeToCamelCase = { - query: 'airport', - disableFuzziness: false, - limit: 1, - }; + const query: ConvertSnakeToCamelCase = { + query: 'airport', + disableFuzziness: false, + limit: 1, + }; - const response = await geotextSearchManager.search(query); + const response = await geotextSearchManager.search(query); - expect(response).toEqual>( - expectedResponse( - { - ...(convertCamelToSnakeCase(query as unknown as Record) as unknown as GetGeotextSearchParams), - geo_context: undefined, - geo_context_mode: undefined, - region: undefined, - source: undefined, - }, - { - place_types: ['transportation'], - sub_place_types: ['airport'], - hierarchies: undefined, - name: '', - }, - [ + expect(response).toEqual>( + expectedResponse( { - ...NY_JFK_AIRPORT, - properties: { - ...NY_JFK_AIRPORT.properties, - names: { - ...NY_JFK_AIRPORT.properties.names, - display: expect.stringContaining('JFK') as string, + ...(convertCamelToSnakeCase(query as unknown as Record) as unknown as GetGeotextSearchParams), + geo_context: undefined, + geo_context_mode: undefined, + region: undefined, + source: undefined, + }, + { + place_types: ['transportation'], + sub_place_types: ['airport'], + hierarchies: undefined, + name: '', + }, + [ + { + ...NY_JFK_AIRPORT, + properties: { + ...NY_JFK_AIRPORT.properties, + names: { + ...NY_JFK_AIRPORT.properties.names, + display: expect.stringContaining('JFK') as string, + }, }, }, - }, - ], - expect - ) - ); - }); + ], + expect + ) + ); + } + ); it('should return sources', () => { const response = geotextSearchManager.sources();