UNPKG

fiftyone.geolocation

Version:

Perform reverse geocoding using longitude and latitude to populate postal addresses

234 lines (203 loc) 7.3 kB
/* ********************************************************************* * This Original Work is copyright of 51 Degrees Mobile Experts Limited. * Copyright 2025 51 Degrees Mobile Experts Limited, Davidson House, * Forbury Square, Reading, Berkshire, United Kingdom RG1 3EU. * * This Original Work is licensed under the European Union Public Licence * (EUPL) v.1.2 and is subject to its terms as set out below. * * If a copy of the EUPL was not distributed with this file, You can obtain * one at https://opensource.org/licenses/EUPL-1.2. * * The 'Compatible Licences' set out in the Appendix to the EUPL (as may be * amended by the European Commission) shall be deemed incompatible for * the purposes of the Work and the provisions of the compatibility * clause in Article 5 of the EUPL shall not apply. * * If using the Work as, or as part of, a network application, by * including the attribution notice(s) required under Article 5 of the EUPL * in the end user terms of the application under an appropriate heading, * such notice(s) shall fulfill the requirements of that article. * ********************************************************************* */ const path = require('path'); const GeoLocation = require(path.resolve(__dirname, '..')); const myResourceKey = process.env.RESOURCE_KEY || '!!YOUR_RESOURCE_KEY!!'; const TestLat = '51.4578261'; const TestLon = '-0.975922996290084'; const expectedProperties = { location: [ 'javascript', 'building', 'streetnumber', 'road', 'town', // For some reason, the value of the 'county' property returned // by the call to the cloud is always null on the build agent, // despite working correctly locally. // After spending the best part of a day trying to resolve this, // we've decided to exclude the county property from this test // for the moment. // 'county', 'region', 'state', 'zipcode', 'country', 'countrycode' ], location_digitalelement: [ 'javascript', 'town', 'county', 'region', 'state', 'zipcode', 'country', 'countrycode' ] }; // Skip the rest of the examples when async is not available let isAsync = true; try { eval('async () => {}'); } catch (e) { isAsync = false; } if (isAsync) { // Check that if no evidence is yet available for location // engine, accessing a valid property will return HasValue=false // and a correct error message. test('No evidence error message', done => { if (myResourceKey === '!!YOUR_RESOURCE_KEY!!') { throw new Error('No resource key is present!'); } const pipeline = new GeoLocation.GeoLocationPipelineBuilder({ resourceKey: myResourceKey }).build(); const flowData = pipeline.createFlowData(); flowData.process().then(function () { const country = flowData.location.country; expect(country.hasValue).toBe(false); // Debug: log the actual message to understand CI failure console.log('DEBUG - Actual noValueMessage:', JSON.stringify(country.noValueMessage)); expect(country.noValueMessage.indexOf('This property requires ' + 'evidence values from JavaScript running on the client. It ' + 'cannot be populated until a future request is made that ' + 'contains this additional data.') !== -1).toBe(true); done(); }); }); test('Available Properties 51Degrees', async done => { if (myResourceKey === '!!YOUR_RESOURCE_KEY!!') { throw new Error('No resource key is present!'); } const pipeline = new GeoLocation.GeoLocationPipelineBuilder({ resourceKey: myResourceKey, locationProvider: 'fiftyonedegrees' }).build(); const engine = pipeline.flowElements.location; await testAvailableProperties(done, pipeline, engine); }); test('Value Types 51Degrees', async done => { if (myResourceKey === '!!YOUR_RESOURCE_KEY!!') { throw new Error('No resource key is present!'); } const pipeline = new GeoLocation.GeoLocationPipelineBuilder({ resourceKey: myResourceKey, locationProvider: 'fiftyonedegrees' }).build(); const engine = pipeline.flowElements.location; await testValueTypes(done, pipeline, engine); }); } else { // Skip if async is not available (e.g node 6) test.skip('Workaround', () => 1); } async function testAvailableProperties (done, pipeline, engine) { const flowData = pipeline.createFlowData(); flowData.evidence.add('query.51D_Pos_latitude', TestLat); flowData.evidence.add('query.51D_Pos_longitude', TestLon); await flowData.process(); expectedProperties[engine.dataKey].forEach(key => { try { const apv = flowData[engine.dataKey][key]; if (apv === undefined) { done.fail(new Error(`Aspect property value for ${key} should not be undefined.`)); } expect(apv).not.toBeNull(); expect(apv).toBeDefined(); if (apv.hasValue === true) { if (apv.value == null || apv.value === undefined) { done.fail(new Error(`${key}.value should not be null`)); } } else { if (apv.noValueMessage == null || apv.noValueMessage === undefined) { done.fail(new Error(`${key}.noValueMessage should not be null`)); } } } catch (err) { done.fail(err); } }); done(); } async function testValueTypes (done, pipeline, engine) { const flowData = pipeline.createFlowData(); flowData.evidence.add('query.51D_Pos_latitude', TestLat); flowData.evidence.add('query.51D_Pos_longitude', TestLon); await flowData.process(); Object.keys(engine.properties).forEach(key => { if (expectedProperties[engine.dataKey].includes(key)) { const property = engine.properties[key.toLowerCase()]; const expectedType = property.type; const apv = flowData[engine.dataKey][key]; expect(apv).not.toBeNull(); expect(apv).toBeDefined(); expect(apv.hasValue, 'No value for \'' + key + '\'. (' + apv.noValueMessage + ')').toBe(true); expect(apv.value).toBe51DType(key, expectedType); } }); done(); } expect.extend({ // Method to validate a given value has the expected type. toBe51DType (received, name, fodType) { const valueType = typeof received; let valid = false; switch (fodType) { case 'Boolean': valid = valueType === 'boolean'; break; case 'String': valid = valueType === 'string'; break; case 'JavaScript': valid = valueType === 'string'; break; case 'Int32': valid = valueType === 'number'; break; case 'Double': valid = valueType === 'number'; break; case 'Array': valid = valueType === 'object' && Array.isArray(received); break; default: valid = false; break; } if (valid) { return { message: () => `${name}: expected node type '${valueType}' not to be equivalent to fodType '${fodType}' for value: '${received}'`, pass: true }; } else { return { message: () => `${name}: expected node type '${valueType}' to be equivalent to fodType '${fodType}' for value: '${received}'`, pass: false }; } } });