Skip to content

Commit

Permalink
test: getFeatureId method #29
Browse files Browse the repository at this point in the history
  • Loading branch information
wazolab committed Nov 19, 2024
1 parent c020218 commit 6d6c24b
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 26 deletions.
40 changes: 14 additions & 26 deletions src/teritorio-cluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
pinMarkerRenderDefault,
unfoldedClusterRenderSmart
} from './utils/helpers'
import { getFeatureId } from './utils/get-feature-id'
import bbox from '@turf/bbox'
import { featureCollection } from '@turf/helpers'

Expand Down Expand Up @@ -127,7 +128,7 @@ export class TeritorioCluster extends EventTarget {
}

setSelectedFeature = (feature: MapGeoJSONFeature) => {
const id = this.#getFeatureId(feature)
const id = getFeatureId(feature)
const match = this.#findFeature(id)

if (!match) {
Expand Down Expand Up @@ -182,7 +183,7 @@ export class TeritorioCluster extends EventTarget {
#featureClickHandler = (e: Event, feature: MapGeoJSONFeature) => {
e.stopPropagation()

if (!(e.currentTarget instanceof HTMLElement) || this.selectedFeatureId === this.#getFeatureId(feature))
if (!(e.currentTarget instanceof HTMLElement) || this.selectedFeatureId === getFeatureId(feature))
return

this.setSelectedFeature(feature)
Expand All @@ -202,7 +203,7 @@ export class TeritorioCluster extends EventTarget {
const iterator = this.clusterLeaves.entries()

for (const [key, value] of iterator) {
const match = value.find(feature => this.#getFeatureId(feature) === id)
const match = value.find(feature => getFeatureId(feature) === id)

if (match) {
return { clusterId: key, feature: match }
Expand All @@ -222,38 +223,25 @@ export class TeritorioCluster extends EventTarget {
return { clusterXCenter: (left + right) / 2, clusterYCenter: (top + bottom) / 2 }
}

#getFeatureId = (feature: MapGeoJSONFeature): string => {
if (feature.properties.cluster)
return feature.id!.toString()

// Vido support: shouldn't be part of this plugin
let metadata: { [key: string]: any } | undefined = feature.properties.metadata

if (typeof metadata === 'string')
metadata = JSON.parse(metadata)

return (metadata?.id.toString() || feature.properties.id.toString()) as string
}

#isFeatureInCluster = (clusterId: string, featureId: string): boolean => {
try {
const cluster = this.clusterLeaves.get(clusterId)
if (!cluster || !Array.isArray(cluster)) {
console.error(`Cluster with ID ${clusterId} not found or is not an array.`)
return false
}

const featureIndex = cluster.findIndex(feature => {
try {
return this.#getFeatureId(feature) === featureId
} catch(error) {
return getFeatureId(feature) === featureId
} catch (error) {
console.error(`Error getting feature ID for feature:`, feature, error)
return false
}
})

return featureIndex > -1
} catch(error) {
} catch (error) {
console.error(`Error checking if feature ${featureId} is in cluster ${clusterId}:`, error)
return false
}
Expand Down Expand Up @@ -292,7 +280,7 @@ export class TeritorioCluster extends EventTarget {

#renderMarker = (feature: MapGeoJSONFeature) => {
const element = document.createElement('div')
element.id = this.#getFeatureId(feature)
element.id = getFeatureId(feature)

!this.markerRender
? markerRenderDefault(element, this.markerSize)
Expand Down Expand Up @@ -352,7 +340,7 @@ export class TeritorioCluster extends EventTarget {
this.featuresMap.clear()

for (const feature of features) {
const id = this.#getFeatureId(feature)
const id = getFeatureId(feature)

// Transform to Map in order to have unique features
this.featuresMap.set(id, feature)
Expand All @@ -367,7 +355,7 @@ export class TeritorioCluster extends EventTarget {

this.featuresMap.forEach(feature => {
const coords = feature.geometry.type === 'Point' ? new LngLat(feature.geometry.coordinates[0], feature.geometry.coordinates[1]) : undefined
const id = this.#getFeatureId(feature)
const id = getFeatureId(feature)

if (!coords) {
console.error(`Feature ${id} is not Geometry.Point, thus not supported yet.`)
Expand Down Expand Up @@ -419,9 +407,9 @@ export class TeritorioCluster extends EventTarget {

// If initialFeature is part of this new cluster
// We position the Pin marker on it
if (this.initialFeature && this.#isFeatureInCluster(id, this.#getFeatureId(this.initialFeature))) {
if (this.initialFeature && this.#isFeatureInCluster(id, getFeatureId(this.initialFeature))) {
this.selectedClusterId = id
this.selectedFeatureId = this.#getFeatureId(this.initialFeature)
this.selectedFeatureId = getFeatureId(this.initialFeature)
this.#renderPinMarkerInCluster(element, coords)
this.initialFeature = undefined
}
Expand All @@ -441,7 +429,7 @@ export class TeritorioCluster extends EventTarget {

// If initialFeature is this new marker
// We position the Pin marker on it
if (this.initialFeature && (this.#getFeatureId(this.initialFeature) === id)) {
if (this.initialFeature && (getFeatureId(this.initialFeature) === id)) {
this.selectedFeatureId = id
this.#renderPinMarker(coords)
this.initialFeature = undefined
Expand Down
33 changes: 33 additions & 0 deletions src/utils/get-feature-id.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
export const getFeatureId = (feature: GeoJSON.Feature): string => {
try {
if (!feature.properties) {
throw new Error('Feature properties are null or undefined')
}

if (feature.properties.cluster) {
if (!feature.id) {
throw new Error('Feature is a cluster but is missing property id')
}
return feature.id.toString()
}

// Vido support: shouldn't be part of this plugin
if (!feature.properties.metadata || typeof feature.properties.metadata !== 'string') {
if (!feature.properties.id) {
throw new Error('Feature property id is missing')
}
return feature.properties.id.toString()
}

const metadata = JSON.parse(feature.properties.metadata)
if (!metadata.id) {
throw new Error('Feature properties metadata id is missing')
}

return metadata.id.toString()
} catch (error) {
console.error("Error in getFeatureId: ", error);

return feature.id?.toString() || 'unknown'
}
}
89 changes: 89 additions & 0 deletions tests/get-feature-id.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { describe, it, expect, vi } from 'vitest';
import { getFeatureId } from '../src/utils/get-feature-id'

describe('getFeatureId function', () => {
it('should return the feature id for clusters', () => {
const feature: GeoJSON.Feature = {
type: 'Feature',
properties: { cluster: true },
id: 123,
geometry: { type: 'Point', coordinates: [0, 0] },
};

const result = getFeatureId(feature);
expect(result).toBe('123');
});

it('should return the feature id if no metadata and but property id exists', () => {
const feature: GeoJSON.Feature = {
type: 'Feature',
properties: { id: 456 },
geometry: { type: 'Point', coordinates: [1, 1] },
};

const result = getFeatureId(feature);
expect(result).toBe('456');
});

it('should return the metadata id if metadata exists', () => {
const feature: GeoJSON.Feature = {
type: 'Feature',
properties: { metadata: '{"id": "789"}' },
geometry: { type: 'Point', coordinates: [2, 2] },
};

const result = getFeatureId(feature);
expect(result).toBe('789');
});

it('should return "unknown" when no id or metadata is available', () => {
const feature: GeoJSON.Feature = {
type: 'Feature',
properties: {},
geometry: { type: 'Point', coordinates: [3, 3] },
};

const result = getFeatureId(feature);
expect(result).toBe('unknown');
});

it('should handle malformed metadata and return "unknown"', () => {
const feature: GeoJSON.Feature = {
type: 'Feature',
properties: { metadata: 'invalid-json' },
geometry: { type: 'Point', coordinates: [4, 4] },
};

const result = getFeatureId(feature);
expect(result).toBe('unknown');
});

it('should log an error when an exception occurs', () => {
const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => { });

const feature: GeoJSON.Feature = {
type: 'Feature',
properties: {},
geometry: { type: 'Point', coordinates: [3, 3] },
};

getFeatureId(feature);

expect(consoleErrorSpy).toHaveBeenCalled()
expect(consoleErrorSpy.mock.calls[0][0]).toContain('Error in getFeatureId:');

consoleErrorSpy.mockRestore();
});

it('should return feature id if metadata is malformed but feature has id', () => {
const feature: GeoJSON.Feature = {
type: 'Feature',
properties: { metadata: 'invalid-json' },
id: 101,
geometry: { type: 'Point', coordinates: [5, 5] },
};

const result = getFeatureId(feature);
expect(result).toBe('101');
});
});

0 comments on commit 6d6c24b

Please sign in to comment.