Skip to content

Commit 16f15d3

Browse files
ethanbienstocklhawkinsclaudeEthan Bienstock
authored
Establish React component testing patterns for geoset-map-chart (#345)
* #310 establish React component testing patterns for geoset-map-chart plugin Add comprehensive test suite covering utility functions, components, and hooks: - MultiLegend component tests with theme provider wrapper - colors.ts: computeSizeScale, toRGBA, rgbaArrayToHex, applyColorMapping, computeMetricColorScaleUnified, getFeatureColor, percentile helpers, lerp functions - colorsFallback.ts: hasValidFill, normalizeRGBA, normalizeColorToHex, rgbaArrayToCssString, rgbaObjectToArray - dataProcessing.ts: getBreakPoints, parseRawFeatures, normalizeNullCategory, getGeometryType - fitViewport.ts: isValidViewport, toNumericViewport, fitViewport, calculateAutozoomViewport - convertToGeoJson.ts: convertToGeoJSONFeature (GeoJSON, WKT, edge cases) - computeBoundsFromPoints.ts: bounds computation and expansion - hooks.ts and legendHelpers.ts: full coverage - Extract legendHelpers utility from MultiLegend for testability - Add shared test fixtures and theme-wrapped render helper 11 test suites, 218 tests, src/utils coverage raised from 14.7% to 49.2% Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * #310 expand test coverage for geoset-map-chart utility modules Add new test suites and expand existing ones: - validateLayerType: full coverage of geometry type mapping - measureDistance: Haversine formula and imperial formatting - safeStringify: circular reference handling and prettyStringify - liveViewportStore: set/get round-trip - formatNumber: legend number formatting with K/M/B suffixes - colors.ts: cssToRgbaArray, normalizeColorInput, addColor, normalizeCategoryColorMapping object branch, breakpoint edge cases - dataProcessing.ts: getBreakPointColorScaler and getBuckets Coverage raised from 43% to 57% statements for src/utils/ Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Merge conflict fix * fix: deduplicate formatLegendNumber test cases after merge conflict * #310 add Legend component tests and fix TS errors in test files Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * #310 expand GeoSetLayer tests with getLayer and getLayerStates coverage Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: address PR #339 review feedback on test quality - Extract duplicated svgIcons jest.mock blocks into shared test/mocks/svgIcons.ts - Restore deck.gl rendering-order comments in sorting tests - Remove unfailable and trivial tests (liveViewportStore, safeStringify) - Consolidate normalizeNullCategory tests with it.each - Fix brittle computeSizeScale midpoint assertion - Add edge-case tests: getDefaultColors undefined props, applyCategoryEnabledState falsy values, MULTI WKT geometries, unrecognized geoJsonLayer, invalid Legend position - Add explanatory comment for cssToRgbaArray canvas mocking Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: cast invalid position string to any for TS compatibility Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: lhawkins <lhawkins@teamraft.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Ethan Bienstock <ethan.bienstock@acf.hhs.gov>
1 parent 8b8a70b commit 16f15d3

25 files changed

Lines changed: 4508 additions & 86 deletions

superset-frontend/jest.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ module.exports = {
5656
],
5757
coverageReporters: ['lcov', 'json-summary', 'html', 'text'],
5858
transformIgnorePatterns: [
59-
'node_modules/(?!d3-(interpolate|color|time|scale)|@mapbox/tiny-sdf|remark-gfm|(?!@ngrx|(?!deck.gl)|d3-scale)|markdown-table|micromark-*.|decode-named-character-reference|character-entities|mdast-util-*.|unist-util-*.|ccount|escape-string-regexp|nanoid|@rjsf/*.|sinon|echarts|zrender|fetch-mock|pretty-ms|parse-ms|ol|@babel/runtime|@emotion|cheerio|cheerio/lib|parse5|dom-serializer|entities|htmlparser2|rehype-sanitize|hast-util-sanitize|unified|unist-.*|hast-.*|rehype-.*|remark-.*|mdast-.*|micromark-.*|parse-entities|property-information|space-separated-tokens|comma-separated-tokens|bail|devlop|zwitch|longest-streak|geostyler|geostyler-.*|react-error-boundary|react-json-tree|react-base16-styling|lodash-es)',
59+
'node_modules/(?!d3-(interpolate|color|time|scale|array)|internmap|@mapbox/tiny-sdf|remark-gfm|(?!@ngrx|(?!deck.gl)|d3-scale)|markdown-table|micromark-*.|decode-named-character-reference|character-entities|mdast-util-*.|unist-util-*.|ccount|escape-string-regexp|nanoid|@rjsf/*.|sinon|echarts|zrender|fetch-mock|pretty-ms|parse-ms|ol|@babel/runtime|@emotion|cheerio|cheerio/lib|parse5|dom-serializer|entities|htmlparser2|rehype-sanitize|hast-util-sanitize|unified|unist-.*|hast-.*|rehype-.*|remark-.*|mdast-.*|micromark-.*|parse-entities|property-information|space-separated-tokens|comma-separated-tokens|bail|devlop|zwitch|longest-streak|geostyler|geostyler-.*|react-error-boundary|react-json-tree|react-base16-styling|lodash-es)',
6060
],
6161
preset: 'ts-jest',
6262
transform: {

superset-frontend/plugins/geoset-map-chart/src/GeoSetMultiMap/Multi.tsx

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,7 @@ import { fetchMapboxApiKey, getCachedMapboxApiKey } from '../utils/mapboxApi';
5454
import { multiChartMigration } from '../utils/migrationApi';
5555
import ClickPopupBox, { ClickedFeatureInfo } from '../components/ClickPopupBox';
5656
import { setLiveViewport } from '../utils/liveViewportStore';
57-
// Apply enabled state to legend categories based on visibility map
58-
const applyCategoryEnabledState = (
59-
categories: CategoryEntry[] | undefined,
60-
visibility: Record<string, boolean>,
61-
): CategoryEntry[] | undefined =>
62-
categories?.map(cat => ({
63-
...cat,
64-
enabled: visibility[cat.label] !== false,
65-
}));
57+
import { applyCategoryEnabledState } from '../utils/legendHelpers';
6658

6759
// Utility to convert snake_case or camelCase to Title Case
6860
const toTitleCase = (str: string) =>

superset-frontend/plugins/geoset-map-chart/src/components/MultiLegend.tsx

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { Swatch } from '../utils/legendSwatch';
77
import { formatBoundLabel } from '../utils/formatNumber';
88
import GraduatedIcons from './GraduatedIcons';
99
import CategorySizeGrid, { CategorySizeGridItem } from './CategorySizeGrid';
10+
import { getDefaultColors } from '../utils/legendHelpers';
1011

1112
export type MultiLegendProps = {
1213
legendGroups: LegendGroup[];
@@ -206,27 +207,6 @@ const IndeterminateCheckbox: React.FC<{
206207
);
207208
};
208209

209-
const getDefaultColors = (
210-
layer: LegendEntry,
211-
): { fill: RGBAColor; stroke: RGBAColor } => {
212-
if (layer.simpleStyle) {
213-
return {
214-
fill: layer.simpleStyle.fillColor,
215-
stroke: layer.simpleStyle.strokeColor,
216-
};
217-
}
218-
if (layer.metric) {
219-
return { fill: layer.metric.startColor, stroke: layer.metric.startColor };
220-
}
221-
if (layer.categories && layer.categories.length > 0) {
222-
return {
223-
fill: layer.categories[0].fillColor,
224-
stroke: layer.categories[0].strokeColor,
225-
};
226-
}
227-
return { fill: [0, 122, 135, 255], stroke: [0, 122, 135, 255] };
228-
};
229-
230210
const LegendEntryContent: React.FC<{
231211
sliceId: string;
232212
legendEntry: LegendEntry;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import type { RGBAColor } from './colors';
2+
import type { LegendEntry, CategoryEntry } from '../types';
3+
4+
/** Resolve the default fill/stroke colors for a legend entry. */
5+
export const getDefaultColors = (
6+
layer: LegendEntry,
7+
): { fill: RGBAColor; stroke: RGBAColor } => {
8+
if (layer.simpleStyle) {
9+
return {
10+
fill: layer.simpleStyle.fillColor,
11+
stroke: layer.simpleStyle.strokeColor,
12+
};
13+
}
14+
if (layer.metric) {
15+
return { fill: layer.metric.startColor, stroke: layer.metric.startColor };
16+
}
17+
if (layer.categories && layer.categories.length > 0) {
18+
return {
19+
fill: layer.categories[0].fillColor,
20+
stroke: layer.categories[0].strokeColor,
21+
};
22+
}
23+
return { fill: [0, 122, 135, 255], stroke: [0, 122, 135, 255] };
24+
};
25+
26+
/** Apply enabled state to legend categories based on visibility map. */
27+
export const applyCategoryEnabledState = (
28+
categories: CategoryEntry[] | undefined,
29+
visibility: Record<string, boolean>,
30+
): CategoryEntry[] | undefined =>
31+
categories?.map(cat => ({
32+
...cat,
33+
enabled: visibility[cat.label] !== false,
34+
}));

0 commit comments

Comments
 (0)