@cdc/core 4.26.1 → 4.26.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/qa-test-developer.md +126 -0
- package/CLAUDE.local.md +67 -0
- package/LICENSE +201 -0
- package/_stories/Gallery.Charts.stories.tsx +35 -42
- package/_stories/Gallery.DataBite.stories.tsx +15 -8
- package/_stories/Gallery.Maps.stories.tsx +37 -28
- package/_stories/Gallery.WaffleChart.stories.tsx +1 -1
- package/_stories/PageART.stories.tsx +5 -4
- package/_stories/PageBRFSS.stories.tsx +21 -16
- package/_stories/PageCancerRegistries.stories.tsx +15 -15
- package/_stories/PageEasternEquineEncephalitis.stories.tsx +33 -19
- package/_stories/PageExcessiveAlcoholUse.stories.tsx +148 -143
- package/_stories/PageMaternalMortality.stories.tsx +5 -4
- package/_stories/PageOralHealth.stories.tsx +15 -10
- package/_stories/PageRespiratory.stories.tsx +4 -4
- package/_stories/PageSmokingTobacco.stories.tsx +15 -10
- package/_stories/PageStateDiabetesProfiles.stories.tsx +15 -10
- package/_stories/PageWastewater.stories.tsx +44 -30
- package/_stories/VegaImport.stories.tsx +401 -0
- package/_stories/vega-fixtures/bars-with-line.json +444 -0
- package/_stories/vega-fixtures/bars.json +58 -0
- package/_stories/vega-fixtures/combo-bar-rolling-mean.json +88 -0
- package/_stories/vega-fixtures/combo.json +68 -0
- package/_stories/vega-fixtures/grouped-horizontal-bars.json +83 -0
- package/_stories/vega-fixtures/grouped-horizontal-bars2.json +231 -0
- package/_stories/vega-fixtures/horizontal-bar.json +427 -0
- package/_stories/vega-fixtures/horizontal-bars-with-bad-colors.json +197 -0
- package/_stories/vega-fixtures/horizontal-bars2.json +58 -0
- package/_stories/vega-fixtures/lines.json +227 -0
- package/_stories/vega-fixtures/measles-bars.json +348 -0
- package/_stories/vega-fixtures/measles-map.json +11101 -0
- package/_stories/vega-fixtures/measles-stacked-bars.json +2147 -0
- package/_stories/vega-fixtures/multi-dataset.json +255 -0
- package/_stories/vega-fixtures/no-data.json +14 -0
- package/_stories/vega-fixtures/pie-chart.json +94 -0
- package/_stories/vega-fixtures/repeat-spec.json +47 -0
- package/_stories/vega-fixtures/stacked-area.json +222 -0
- package/_stories/vega-fixtures/stacked-bar-with-rect.json +3412 -0
- package/_stories/vega-fixtures/stacked-bars-with-line.json +364 -0
- package/_stories/vega-fixtures/stacked-bars.json +212 -0
- package/_stories/vega-fixtures/stacked-horizontal-bars.json +140 -0
- package/_stories/vega-fixtures/warning-combo.json +59 -0
- package/_stories/vega-fixtures/warning-scatter-and-line.json +1182 -0
- package/assets/callout-flag.svg +7 -0
- package/assets/icon-chart-area.svg +1 -0
- package/assets/icon-chart-radar.svg +23 -0
- package/assets/logo2.svg +31 -0
- package/components/AdvancedEditor/EmbedEditor.tsx +270 -38
- package/components/Alert/components/Alert.styles.css +2 -2
- package/components/ComboBox/combobox.styles.css +48 -48
- package/components/CustomColorsEditor/CustomColorsEditor.css +53 -53
- package/components/CustomColorsEditor/CustomColorsEditor.tsx +3 -10
- package/components/DataTable/DataTable.tsx +46 -18
- package/components/DataTable/DataTableStandAlone.tsx +1 -0
- package/components/DataTable/components/ChartHeader.tsx +21 -12
- package/components/DataTable/components/MapHeader.tsx +34 -28
- package/components/DataTable/components/SortIcon/sort-icon.css +5 -5
- package/components/DataTable/data-table.css +50 -52
- package/components/DataTable/helpers/applyCustomOrder.ts +17 -0
- package/components/DataTable/helpers/getChartCellValue.ts +10 -7
- package/components/DataTable/helpers/getMapDataTableColumnKeys.ts +22 -0
- package/components/DataTable/helpers/getSeriesName.ts +6 -0
- package/components/DataTable/helpers/mapCellMatrix.tsx +33 -23
- package/components/DataTable/helpers/tests/mapCellMatrix.test.ts +33 -0
- package/components/DownloadButton.tsx +14 -6
- package/components/EditorPanel/ColumnsEditor.tsx +38 -31
- package/components/EditorPanel/CustomSortOrder.tsx +94 -0
- package/components/EditorPanel/DataTableEditor.tsx +139 -23
- package/components/EditorPanel/EditorPanel.styles.css +71 -71
- package/components/EditorPanel/EditorPanel.tsx +3 -8
- package/components/EditorPanel/EditorPanelDispatch.tsx +4 -4
- package/components/EditorPanel/FootnotesEditor.tsx +2 -2
- package/components/EditorPanel/VizFilterEditor/NestedDropdownEditor.tsx +21 -12
- package/components/EditorPanel/VizFilterEditor/VizFilterEditor.tsx +16 -10
- package/components/EditorPanel/VizFilterEditor/components/FilterOrder.tsx +33 -29
- package/components/EditorPanel/components/MarkupVariablesEditor.tsx +160 -106
- package/components/EditorPanel/components/PanelMarkup.tsx +5 -1
- package/{styles/v2/components → components/EditorPanel}/editor.scss +76 -22
- package/components/EditorPanel/sections/StyleTreatmentSection.tsx +99 -0
- package/components/EditorPanel/sections/VisualSection.tsx +11 -0
- package/components/EditorWrapper/editor-wrapper.style.css +1 -1
- package/components/Filters/Filters.tsx +3 -5
- package/components/Filters/components/Tabs.tsx +19 -7
- package/{styles → components/Filters}/filters.scss +3 -3
- package/components/Footnotes/FootnotesStandAlone.tsx +4 -2
- package/components/HeaderThemeSelector/HeaderThemeSelector.css +61 -5
- package/components/Layout/components/Responsive.tsx +14 -6
- package/components/Layout/components/Sidebar/components/Sidebar.tsx +1 -1
- package/components/Layout/components/Sidebar/components/sidebar.styles.scss +14 -20
- package/components/Layout/components/Visualization/index.tsx +50 -38
- package/components/Layout/components/Visualization/visualizations.scss +232 -15
- package/components/Layout/components/VisualizationContainer.test.tsx +67 -0
- package/components/Layout/components/VisualizationContainer.tsx +37 -0
- package/components/Layout/components/VisualizationContent.test.tsx +182 -0
- package/components/Layout/components/VisualizationContent.tsx +75 -0
- package/components/Layout/index.tsx +5 -5
- package/components/Layout/styles/editor-utils.scss +3 -3
- package/components/Layout/styles/editor.scss +4 -4
- package/components/Legend/Legend.Gradient.tsx +7 -1
- package/components/Loader/loader.styles.css +2 -2
- package/components/Loading.jsx +1 -1
- package/components/MediaControls.tsx +10 -3
- package/components/MultiSelect/multiselect.styles.css +19 -19
- package/components/NestedDropdown/nesteddropdown.styles.css +15 -15
- package/components/PaletteSelector/PaletteSelector.css +15 -15
- package/components/RichTooltip/richTooltip.css +6 -6
- package/components/Table/table.styles.css +2 -2
- package/components/Waiting.tsx +1 -1
- package/components/_stories/CustomColorsEditor.stories.tsx +37 -0
- package/components/_stories/DataTable.stories.tsx +1 -0
- package/components/_stories/Filters.stories.tsx +1 -1
- package/components/_stories/styles.scss +0 -1
- package/components/elements/Button.jsx +1 -1
- package/components/elements/Card.jsx +1 -1
- package/{styles/v2/components → components/elements}/button.scss +9 -8
- package/components/inputs/InputCheckbox.jsx +1 -1
- package/components/inputs/InputSelect.tsx +1 -1
- package/components/inputs/InputText.jsx +1 -1
- package/components/inputs/InputToggle.tsx +1 -1
- package/{styles/v2/components/input → components/inputs}/_input-check-radio.scss +2 -2
- package/{styles/v2/components/input → components/inputs}/_input-group.scss +3 -3
- package/{styles/v2/components/input → components/inputs}/_input-slider.scss +2 -2
- package/{styles/v2/components/input → components/inputs}/_input.scss +5 -5
- package/{styles/v2/components/input → components/inputs}/index.scss +2 -2
- package/{styles → components}/loading.scss +1 -1
- package/components/managers/DataDesigner.tsx +1 -1
- package/{styles/v2/components → components/managers}/data-designer.scss +6 -7
- package/components/ui/Accordion.jsx +1 -1
- package/components/ui/Icon.tsx +1 -1
- package/components/ui/LoadSpin.jsx +1 -1
- package/components/ui/Modal.jsx +1 -1
- package/components/ui/Overlay.jsx +1 -1
- package/components/ui/Title/index.test.tsx +34 -0
- package/components/ui/Title/index.tsx +24 -7
- package/components/ui/Title/title.styles.css +119 -25
- package/components/ui/Tooltip.tsx +1 -1
- package/components/ui/_stories/Title.stories.tsx +1 -1
- package/{styles/v2/components → components/ui}/accordion.scss +3 -3
- package/components/ui/accordion.styles.css +11 -11
- package/{styles/v2/components → components/ui}/modal.scss +2 -2
- package/{styles/v2/components → components/ui}/overlay.scss +6 -6
- package/{styles/v2/components → components}/ui/tooltip.scss +1 -1
- package/{styles → components}/waiting.scss +9 -3
- package/data/colorPalettes.ts +18 -5
- package/data/mapColorPalettes.ts +10 -0
- package/devTemplate/dev.js +285 -0
- package/devTemplate/index.html +30 -0
- package/devTemplate/preview.html +1503 -0
- package/devTemplate/sidebar.css +151 -0
- package/dist/cove-main.css +2530 -3901
- package/dist/cove-main.css.map +1 -1
- package/generateViteConfig.js +111 -2
- package/helpers/DataTransform.ts +1 -5
- package/helpers/backfillDefaults.ts +35 -0
- package/helpers/constants.ts +12 -0
- package/helpers/cove/date.ts +64 -3
- package/helpers/cove/number.ts +29 -15
- package/helpers/cove/string.ts +29 -0
- package/helpers/coveUpdateWorker.ts +14 -8
- package/helpers/displayDataAsText.ts +1 -1
- package/helpers/embed/embedCodeGenerator.ts +80 -0
- package/helpers/embed/embedHelper.js +169 -0
- package/helpers/embed/filterUtils.ts +121 -0
- package/helpers/embed/index.ts +17 -0
- package/helpers/embed/urlValidation.ts +119 -0
- package/helpers/extractDataAndMetadata.ts +20 -0
- package/helpers/fetchRemoteData.ts +14 -8
- package/helpers/filterVizData.ts +6 -1
- package/helpers/getFileExtension.ts +0 -6
- package/helpers/labelHash.ts +9 -0
- package/helpers/markupProcessor.ts +56 -38
- package/helpers/metrics/types.ts +3 -0
- package/helpers/palettes/colorDistributions.ts +1 -1
- package/helpers/palettes/utils.ts +12 -12
- package/helpers/parseCsvWithQuotes.ts +15 -14
- package/helpers/prepareScreenshot.ts +33 -10
- package/helpers/testing.ts +44 -0
- package/helpers/tests/DataTransform.test.ts +125 -0
- package/helpers/tests/abbreviateNumber.test.ts +59 -0
- package/helpers/tests/backfillDefaults.test.ts +253 -0
- package/helpers/tests/date.test.ts +110 -0
- package/helpers/tests/extractDataAndMetadata.test.ts +93 -0
- package/helpers/tests/markupProcessor.test.ts +315 -124
- package/helpers/tests/number.test.ts +42 -0
- package/helpers/tests/prepareScreenshot.test.ts +28 -28
- package/helpers/tests/testStandaloneBuild.ts +36 -26
- package/helpers/tests/useDataVizClasses.test.ts +66 -0
- package/helpers/tests/visualizationWrapperUsage.test.ts +57 -0
- package/helpers/useDataVizClasses.ts +13 -7
- package/helpers/vegaConfig.ts +1 -1
- package/helpers/vegaConfigImport.ts +160 -0
- package/helpers/ver/4.24.4.ts +24 -0
- package/helpers/ver/4.26.1.ts +1 -1
- package/helpers/ver/4.26.2.ts +84 -0
- package/helpers/ver/4.26.3.ts +44 -0
- package/helpers/ver/4.26.4.ts +31 -0
- package/helpers/ver/tests/4.26.1.test.ts +105 -0
- package/helpers/ver/tests/4.26.2.test.ts +298 -0
- package/helpers/ver/tests/4.26.3.test.ts +168 -0
- package/helpers/ver/tests/4.26.4.test.ts +88 -0
- package/helpers/ver/tests/coveUpdateWorker.test.ts +57 -0
- package/helpers/viewports.ts +2 -0
- package/package.json +27 -32
- package/styles/_global.scss +7 -7
- package/styles/_reset.scss +2 -2
- package/styles/{v2/base → base}/_file-selector.scss +4 -4
- package/styles/{v2/base → base}/_general.scss +2 -4
- package/styles/{v2/base → base}/index.scss +1 -1
- package/styles/base.scss +107 -165
- package/styles/cove-main.scss +3 -6
- package/styles/layout/_component.scss +110 -0
- package/styles/{v2/layout → layout}/_data-table.scss +7 -7
- package/styles/layout/_wrapper-padding.scss +27 -0
- package/styles/{v2/main.scss → main.scss} +3 -1
- package/styles/{v2/themes → themes}/_color-definitions.scss +46 -41
- package/styles/{_accessibility.scss → utils/_accessibility.scss} +1 -1
- package/styles/{v2/utils → utils}/_grid.scss +8 -3
- package/styles/{_global-variables.scss → utils/_properties.scss} +133 -112
- package/styles/{v2/utils → utils}/index.scss +2 -1
- package/types/Annotation.ts +10 -11
- package/types/Axis.ts +2 -0
- package/types/ComponentStyles.ts +1 -0
- package/types/ConfigureData.ts +1 -0
- package/types/General.ts +2 -0
- package/types/MarkupInclude.ts +1 -0
- package/types/MarkupVariable.ts +2 -1
- package/types/Palette.ts +22 -0
- package/types/Table.ts +9 -0
- package/types/Visualization.ts +7 -0
- package/_stories/StoryRenderingTests.stories.tsx +0 -164
- package/helpers/embedCodeGenerator.ts +0 -109
- package/styles/_common-components.css +0 -73
- package/styles/_variables.scss +0 -63
- package/styles/v2/layout/_component.scss +0 -21
- package/styles/v2/utils/_variables.scss +0 -9
- package/{styles/v2/components/card.scss → components/elements/card.css} +2 -2
- /package/{styles/v2/components → components/ui}/icon.scss +0 -0
- /package/{styles/v2/components → components/ui}/loadspin.scss +0 -0
- /package/styles/{v2/base → base}/_heading.scss +0 -0
- /package/styles/{v2/base → base}/_reset.scss +0 -0
- /package/styles/{v2/layout → layout}/_alert.scss +0 -0
- /package/styles/{v2/layout → layout}/_progression.scss +0 -0
- /package/styles/{v2/layout → layout}/_tooltip.scss +0 -0
- /package/styles/{v2/layout → layout}/index.scss +0 -0
- /package/styles/{v2/themes → themes}/index.scss +0 -0
- /package/styles/{v2/utils → utils}/_align.scss +0 -0
- /package/styles/{v2/utils → utils}/_animations.scss +0 -0
- /package/styles/{v2/utils → utils}/_breakpoints.scss +0 -0
- /package/styles/{v2/utils → utils}/_mixins.scss +0 -0
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vega Import Stories
|
|
3
|
+
*
|
|
4
|
+
* Each story imports a Vega/Vega-Lite JSON config, converts it to a COVE config
|
|
5
|
+
* via the Vega importer pipeline, and renders the resulting chart or map.
|
|
6
|
+
*
|
|
7
|
+
* Play functions verify that each conversion renders without errors.
|
|
8
|
+
*/
|
|
9
|
+
import React from 'react'
|
|
10
|
+
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
11
|
+
import { within, expect, waitFor } from 'storybook/test'
|
|
12
|
+
|
|
13
|
+
import Chart from '@cdc/chart/src/CdcChart'
|
|
14
|
+
import CdcMap from '@cdc/map/src/CdcMap'
|
|
15
|
+
import { maybeConvertVega } from '@cdc/core/helpers/vegaConfigImport'
|
|
16
|
+
|
|
17
|
+
// --- Import Vega fixture JSON files (alphabetical by filename) ---
|
|
18
|
+
import vegaBarsWithLine from './vega-fixtures/bars-with-line.json'
|
|
19
|
+
import vegaBars from './vega-fixtures/bars.json'
|
|
20
|
+
import vegaComboBarRollingMean from './vega-fixtures/combo-bar-rolling-mean.json'
|
|
21
|
+
import vegaCombo from './vega-fixtures/combo.json'
|
|
22
|
+
import vegaGroupedHorizontalBars from './vega-fixtures/grouped-horizontal-bars.json'
|
|
23
|
+
import vegaGroupedHorizontalBars2 from './vega-fixtures/grouped-horizontal-bars2.json'
|
|
24
|
+
import vegaHorizontalBar from './vega-fixtures/horizontal-bar.json'
|
|
25
|
+
import vegaHorizontalBarsWithBadColors from './vega-fixtures/horizontal-bars-with-bad-colors.json'
|
|
26
|
+
import vegaHorizontalBars2 from './vega-fixtures/horizontal-bars2.json'
|
|
27
|
+
import vegaLines from './vega-fixtures/lines.json'
|
|
28
|
+
import vegaMeaslesBars from './vega-fixtures/measles-bars.json'
|
|
29
|
+
import vegaMeaslesMap from './vega-fixtures/measles-map.json'
|
|
30
|
+
import vegaMeaslesStackedBars from './vega-fixtures/measles-stacked-bars.json'
|
|
31
|
+
import vegaMultiDataset from './vega-fixtures/multi-dataset.json'
|
|
32
|
+
import vegaNoData from './vega-fixtures/no-data.json'
|
|
33
|
+
import vegaPieChart from './vega-fixtures/pie-chart.json'
|
|
34
|
+
import vegaRepeatSpec from './vega-fixtures/repeat-spec.json'
|
|
35
|
+
import vegaStackedArea from './vega-fixtures/stacked-area.json'
|
|
36
|
+
import vegaStackedBarWithRect from './vega-fixtures/stacked-bar-with-rect.json'
|
|
37
|
+
import vegaStackedBars from './vega-fixtures/stacked-bars.json'
|
|
38
|
+
import vegaStackedBarsWithLine from './vega-fixtures/stacked-bars-with-line.json'
|
|
39
|
+
import vegaStackedHorizontalBars from './vega-fixtures/stacked-horizontal-bars.json'
|
|
40
|
+
import vegaWarningCombo from './vega-fixtures/warning-combo.json'
|
|
41
|
+
import vegaWarningScatterAndLine from './vega-fixtures/warning-scatter-and-line.json'
|
|
42
|
+
|
|
43
|
+
// --- Convert all configs at module evaluation time (top-level await) ---
|
|
44
|
+
// Ordered alphabetically by original filename
|
|
45
|
+
const fixtures: Record<string, any> = {
|
|
46
|
+
barsWithLine: vegaBarsWithLine,
|
|
47
|
+
bars: vegaBars,
|
|
48
|
+
comboBarRollingMean: vegaComboBarRollingMean,
|
|
49
|
+
combo: vegaCombo,
|
|
50
|
+
groupedHorizontalBars: vegaGroupedHorizontalBars,
|
|
51
|
+
groupedHorizontalBars2: vegaGroupedHorizontalBars2,
|
|
52
|
+
horizontalBar: vegaHorizontalBar,
|
|
53
|
+
horizontalBarsWithBadColors: vegaHorizontalBarsWithBadColors,
|
|
54
|
+
horizontalBars2: vegaHorizontalBars2,
|
|
55
|
+
lines: vegaLines,
|
|
56
|
+
measlesBars: vegaMeaslesBars,
|
|
57
|
+
measlesMap: vegaMeaslesMap,
|
|
58
|
+
measlesStackedBars: vegaMeaslesStackedBars,
|
|
59
|
+
multiDataset: vegaMultiDataset,
|
|
60
|
+
noData: vegaNoData,
|
|
61
|
+
pieChart: vegaPieChart,
|
|
62
|
+
repeatSpec: vegaRepeatSpec,
|
|
63
|
+
stackedArea: vegaStackedArea,
|
|
64
|
+
stackedBarWithRect: vegaStackedBarWithRect,
|
|
65
|
+
stackedBars: vegaStackedBars,
|
|
66
|
+
stackedBarsWithLine: vegaStackedBarsWithLine,
|
|
67
|
+
stackedHorizontalBars: vegaStackedHorizontalBars,
|
|
68
|
+
warningCombo: vegaWarningCombo,
|
|
69
|
+
warningScatterAndLine: vegaWarningScatterAndLine
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const convertedConfigs: Record<string, any> = {}
|
|
73
|
+
const conversionErrors: Record<string, string[]> = {}
|
|
74
|
+
const conversionWarnings: Record<string, string[]> = {}
|
|
75
|
+
|
|
76
|
+
for (const [key, vegaJson] of Object.entries(fixtures)) {
|
|
77
|
+
// Capture console warnings/errors during conversion
|
|
78
|
+
const warnings: string[] = []
|
|
79
|
+
const errors: string[] = []
|
|
80
|
+
|
|
81
|
+
const originalWarn = console.warn
|
|
82
|
+
const originalError = console.error
|
|
83
|
+
|
|
84
|
+
console.warn = (...args: any[]) => {
|
|
85
|
+
const message = args.map(arg => (typeof arg === 'string' ? arg : JSON.stringify(arg))).join(' ')
|
|
86
|
+
warnings.push(message)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
console.error = (...args: any[]) => {
|
|
90
|
+
const message = args.map(arg => (typeof arg === 'string' ? arg : JSON.stringify(arg))).join(' ')
|
|
91
|
+
errors.push(message)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
convertedConfigs[key] = await maybeConvertVega({ ...vegaJson })
|
|
96
|
+
} catch (err) {
|
|
97
|
+
console.error(`Failed to convert ${key}:`, err)
|
|
98
|
+
convertedConfigs[key] = null
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
console.warn = originalWarn
|
|
102
|
+
console.error = originalError
|
|
103
|
+
|
|
104
|
+
conversionErrors[key] = [...warnings, ...errors]
|
|
105
|
+
conversionWarnings[key] = warnings
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// --- Storybook meta ---
|
|
109
|
+
const meta: Meta = {
|
|
110
|
+
title: 'Regression Tests/Vega Importer',
|
|
111
|
+
parameters: {
|
|
112
|
+
layout: 'fullscreen'
|
|
113
|
+
},
|
|
114
|
+
tags: ['!autodocs']
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export default meta
|
|
118
|
+
|
|
119
|
+
// --- Shared play function: verify the chart/map rendered ---
|
|
120
|
+
const assertRendered = async ({ canvasElement }: { canvasElement: HTMLElement }) => {
|
|
121
|
+
await waitFor(
|
|
122
|
+
() => {
|
|
123
|
+
const coveModule = canvasElement.querySelector('.cove-visualization')
|
|
124
|
+
expect(coveModule).toBeTruthy()
|
|
125
|
+
},
|
|
126
|
+
{ timeout: 15000 }
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
// Verify an SVG was rendered
|
|
130
|
+
const svgs = canvasElement.querySelectorAll('svg')
|
|
131
|
+
expect(svgs.length).toBeGreaterThan(0)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// --- Shared play function: verify map rendered ---
|
|
135
|
+
const assertMapRendered = async ({ canvasElement }: { canvasElement: HTMLElement }) => {
|
|
136
|
+
await waitFor(
|
|
137
|
+
() => {
|
|
138
|
+
const coveModule = canvasElement.querySelector('.cove-visualization')
|
|
139
|
+
expect(coveModule).toBeTruthy()
|
|
140
|
+
},
|
|
141
|
+
{ timeout: 15000 }
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
// For maps, check for either SVG or canvas elements
|
|
145
|
+
await waitFor(
|
|
146
|
+
() => {
|
|
147
|
+
const svgs = canvasElement.querySelectorAll('svg')
|
|
148
|
+
const canvases = canvasElement.querySelectorAll('canvas')
|
|
149
|
+
const hasRenderedContent = svgs.length > 0 || canvases.length > 0
|
|
150
|
+
expect(hasRenderedContent).toBe(true)
|
|
151
|
+
},
|
|
152
|
+
{ timeout: 15000 }
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// --- Shared play function: verify error configs failed properly ---
|
|
157
|
+
const assertConversionFailed =
|
|
158
|
+
(expectedErrorPattern: string | RegExp) =>
|
|
159
|
+
async ({ canvasElement }: { canvasElement: HTMLElement }) => {
|
|
160
|
+
// Wait a bit for any async operations to complete
|
|
161
|
+
await new Promise(resolve => setTimeout(resolve, 500))
|
|
162
|
+
|
|
163
|
+
// Verify error message is displayed
|
|
164
|
+
const errorElement = canvasElement.querySelector('[data-testid="error"]')
|
|
165
|
+
expect(errorElement).toBeTruthy()
|
|
166
|
+
expect(errorElement?.textContent).toContain('failed to convert')
|
|
167
|
+
|
|
168
|
+
// Verify the specific error message appears
|
|
169
|
+
const errorMessages = canvasElement.querySelector('[data-testid="error-messages"]')
|
|
170
|
+
expect(errorMessages).toBeTruthy()
|
|
171
|
+
|
|
172
|
+
const errorText = errorMessages?.textContent || ''
|
|
173
|
+
if (typeof expectedErrorPattern === 'string') {
|
|
174
|
+
expect(errorText).toContain(expectedErrorPattern)
|
|
175
|
+
} else {
|
|
176
|
+
expect(expectedErrorPattern.test(errorText)).toBe(true)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Verify no visualization rendered
|
|
180
|
+
const coveModule = canvasElement.querySelector('.cove-visualization')
|
|
181
|
+
expect(coveModule).toBeNull()
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// --- Helper to build a chart story ---
|
|
185
|
+
const chartStory = (key: string): StoryObj => ({
|
|
186
|
+
render: () => {
|
|
187
|
+
const config = convertedConfigs[key]
|
|
188
|
+
if (!config) return <div data-testid='error'>Config "{key}" failed to convert</div>
|
|
189
|
+
return <Chart config={{ ...config }} isEditor={false} />
|
|
190
|
+
},
|
|
191
|
+
play: assertRendered
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
// --- Helper to build a map story ---
|
|
195
|
+
const mapStory = (key: string): StoryObj => ({
|
|
196
|
+
render: () => {
|
|
197
|
+
const config = convertedConfigs[key]
|
|
198
|
+
if (!config) return <div data-testid='error'>Config "{key}" failed to convert</div>
|
|
199
|
+
return <CdcMap config={{ ...config }} navigationHandler={() => {}} setConfig={() => {}} />
|
|
200
|
+
},
|
|
201
|
+
play: assertMapRendered
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
// --- Helper to build an error story (expects conversion to fail) ---
|
|
205
|
+
const errorStory = (key: string, expectedErrorPattern: string | RegExp): StoryObj => ({
|
|
206
|
+
render: () => {
|
|
207
|
+
const config = convertedConfigs[key]
|
|
208
|
+
const errorMessages = conversionErrors[key] || []
|
|
209
|
+
|
|
210
|
+
if (!config) {
|
|
211
|
+
return (
|
|
212
|
+
<div style={{ padding: '20px', fontFamily: 'monospace' }}>
|
|
213
|
+
<div data-testid='error' style={{ color: '#28a745', fontWeight: 'bold', marginBottom: '10px' }}>
|
|
214
|
+
✓ Config "{key}" failed to convert (expected)
|
|
215
|
+
</div>
|
|
216
|
+
<div
|
|
217
|
+
data-testid='error-messages'
|
|
218
|
+
style={{
|
|
219
|
+
backgroundColor: '#f5f5f5',
|
|
220
|
+
padding: '15px',
|
|
221
|
+
borderRadius: '4px',
|
|
222
|
+
border: '1px solid #ddd'
|
|
223
|
+
}}
|
|
224
|
+
>
|
|
225
|
+
<strong>Error Messages:</strong>
|
|
226
|
+
<ul style={{ marginTop: '10px', paddingLeft: '20px' }}>
|
|
227
|
+
{errorMessages.map((msg, i) => (
|
|
228
|
+
<li key={i} style={{ marginBottom: '5px' }}>
|
|
229
|
+
{msg}
|
|
230
|
+
</li>
|
|
231
|
+
))}
|
|
232
|
+
</ul>
|
|
233
|
+
</div>
|
|
234
|
+
</div>
|
|
235
|
+
)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return (
|
|
239
|
+
<div data-testid='unexpected-success' style={{ padding: '20px', color: '#c41e3a', fontWeight: 'bold' }}>
|
|
240
|
+
⚠️ Config "{key}" unexpectedly succeeded - this should have failed!
|
|
241
|
+
</div>
|
|
242
|
+
)
|
|
243
|
+
},
|
|
244
|
+
play: assertConversionFailed(expectedErrorPattern)
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
// --- Helper to build a warning story (renders with warnings) ---
|
|
248
|
+
const warningStory = (
|
|
249
|
+
key: string,
|
|
250
|
+
Component: typeof Chart | typeof CdcMap,
|
|
251
|
+
expectedWarningPattern: string | RegExp
|
|
252
|
+
): StoryObj => ({
|
|
253
|
+
render: () => {
|
|
254
|
+
const config = convertedConfigs[key]
|
|
255
|
+
const warnings = conversionWarnings[key] || []
|
|
256
|
+
|
|
257
|
+
if (!config) {
|
|
258
|
+
return <div data-testid='error'>Config "{key}" failed to convert</div>
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return (
|
|
262
|
+
<div>
|
|
263
|
+
{warnings.length > 0 && (
|
|
264
|
+
<div
|
|
265
|
+
data-testid='warnings'
|
|
266
|
+
style={{
|
|
267
|
+
backgroundColor: '#fff3cd',
|
|
268
|
+
border: '1px solid #ffc107',
|
|
269
|
+
borderRadius: '4px',
|
|
270
|
+
padding: '15px',
|
|
271
|
+
margin: '20px',
|
|
272
|
+
fontFamily: 'monospace',
|
|
273
|
+
fontSize: '14px'
|
|
274
|
+
}}
|
|
275
|
+
>
|
|
276
|
+
<div style={{ color: '#856404', fontWeight: 'bold', marginBottom: '10px' }}>⚠️ Conversion Warnings:</div>
|
|
277
|
+
<ul style={{ margin: '0', paddingLeft: '20px', color: '#856404' }}>
|
|
278
|
+
{warnings.map((msg, i) => (
|
|
279
|
+
<li key={i} style={{ marginBottom: '5px' }}>
|
|
280
|
+
{msg}
|
|
281
|
+
</li>
|
|
282
|
+
))}
|
|
283
|
+
</ul>
|
|
284
|
+
</div>
|
|
285
|
+
)}
|
|
286
|
+
<Component config={{ ...config }} isEditor={false} />
|
|
287
|
+
</div>
|
|
288
|
+
)
|
|
289
|
+
},
|
|
290
|
+
play: async ({ canvasElement }: { canvasElement: HTMLElement }) => {
|
|
291
|
+
// Verify warnings were captured
|
|
292
|
+
const warningsElement = canvasElement.querySelector('[data-testid="warnings"]')
|
|
293
|
+
expect(warningsElement).toBeTruthy()
|
|
294
|
+
|
|
295
|
+
// Verify the warning contains the expected text
|
|
296
|
+
const warningText = warningsElement?.textContent || ''
|
|
297
|
+
|
|
298
|
+
if (typeof expectedWarningPattern === 'string') {
|
|
299
|
+
expect(warningText).toContain(expectedWarningPattern)
|
|
300
|
+
} else {
|
|
301
|
+
expect(expectedWarningPattern.test(warningText)).toBe(true)
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Verify the visualization still rendered
|
|
305
|
+
await assertRendered({ canvasElement })
|
|
306
|
+
}
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
// ============================================================================
|
|
310
|
+
// Stories — alphabetical by original filename
|
|
311
|
+
// ============================================================================
|
|
312
|
+
|
|
313
|
+
// bars-with-line.json
|
|
314
|
+
export const BarsWithLineTests: StoryObj = chartStory('barsWithLine')
|
|
315
|
+
|
|
316
|
+
// bars.json
|
|
317
|
+
export const BarsTests: StoryObj = chartStory('bars')
|
|
318
|
+
|
|
319
|
+
// combo-bar-rolling-mean.json
|
|
320
|
+
export const ComboBarRollingMeanTests: StoryObj = chartStory('comboBarRollingMean')
|
|
321
|
+
|
|
322
|
+
// combo.json
|
|
323
|
+
export const ComboTests: StoryObj = chartStory('combo')
|
|
324
|
+
|
|
325
|
+
// grouped-horizontal-bars.json
|
|
326
|
+
export const GroupedHorizontalBarsTests: StoryObj = chartStory('groupedHorizontalBars')
|
|
327
|
+
|
|
328
|
+
// grouped-horizontal-bars2.json
|
|
329
|
+
export const GroupedHorizontalBars2Tests: StoryObj = chartStory('groupedHorizontalBars2')
|
|
330
|
+
|
|
331
|
+
// horizontal-bar.json
|
|
332
|
+
export const HorizontalBarTests: StoryObj = chartStory('horizontalBar')
|
|
333
|
+
|
|
334
|
+
// horizontal-bars-with-bad-colors.json
|
|
335
|
+
export const HorizontalBarsWithBadColorsTests: StoryObj = chartStory('horizontalBarsWithBadColors')
|
|
336
|
+
|
|
337
|
+
// horizontal-bars2.json
|
|
338
|
+
export const HorizontalBars2Tests: StoryObj = chartStory('horizontalBars2')
|
|
339
|
+
|
|
340
|
+
// lines.json
|
|
341
|
+
export const LinesTests: StoryObj = chartStory('lines')
|
|
342
|
+
|
|
343
|
+
// measles-bars.json
|
|
344
|
+
export const MeaslesBarsTests: StoryObj = chartStory('measlesBars')
|
|
345
|
+
|
|
346
|
+
// measles-map.json
|
|
347
|
+
export const MeaslesMapTests: StoryObj = mapStory('measlesMap')
|
|
348
|
+
|
|
349
|
+
// measles-stacked-bars.json
|
|
350
|
+
export const MeaslesStackedBarsTests: StoryObj = chartStory('measlesStackedBars')
|
|
351
|
+
|
|
352
|
+
// multi-dataset.json
|
|
353
|
+
export const MultiDatasetTests: StoryObj = chartStory('multiDataset')
|
|
354
|
+
|
|
355
|
+
// stacked-area.json
|
|
356
|
+
export const StackedAreaTests: StoryObj = chartStory('stackedArea')
|
|
357
|
+
|
|
358
|
+
// stacked-bar-with-rect.json
|
|
359
|
+
export const StackedBarWithRectTests: StoryObj = chartStory('stackedBarWithRect')
|
|
360
|
+
|
|
361
|
+
// stacked-bars.json
|
|
362
|
+
export const StackedBarsTests: StoryObj = chartStory('stackedBars')
|
|
363
|
+
|
|
364
|
+
// stacked-horizontal-bars.json
|
|
365
|
+
export const StackedHorizontalBarsTests: StoryObj = chartStory('stackedHorizontalBars')
|
|
366
|
+
|
|
367
|
+
// ============================================================================
|
|
368
|
+
// Error Test Stories (Expected to Fail)
|
|
369
|
+
// ============================================================================
|
|
370
|
+
|
|
371
|
+
// no-data.json - Config references external data URL instead of embedded data
|
|
372
|
+
export const NoDataErrorTests: StoryObj = errorStory('noData', 'No data was found')
|
|
373
|
+
|
|
374
|
+
// pie-chart.json - Pie charts are not supported by COVE's Vega importer
|
|
375
|
+
export const PieChartErrorTests: StoryObj = errorStory(
|
|
376
|
+
'pieChart',
|
|
377
|
+
/could not find a COVE chart type|Supported marks are/
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
// repeat-spec.json - Vega-Lite repeat/spec operators are not supported
|
|
381
|
+
export const RepeatSpecErrorTests: StoryObj = errorStory('repeatSpec', /does not support.*repeat\/spec operator/)
|
|
382
|
+
|
|
383
|
+
// stacked-bars-with-line.json - Complex combinations may not be supported
|
|
384
|
+
export const StackedBarsWithLineErrorTests: StoryObj = errorStory(
|
|
385
|
+
'stackedBarsWithLine',
|
|
386
|
+
/one of them appears to be stacked/
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
// ============================================================================
|
|
390
|
+
// Warning Test Stories (Render with Warnings)
|
|
391
|
+
// ============================================================================
|
|
392
|
+
|
|
393
|
+
// warning-combo.json - Combo chart with multiple mark types
|
|
394
|
+
export const WarningComboTests: StoryObj = warningStory('warningCombo', Chart, 'only support these types of marks')
|
|
395
|
+
|
|
396
|
+
// warning-scatter-and-line.json - Scatter plot with line
|
|
397
|
+
export const WarningScatterAndLineTests: StoryObj = warningStory(
|
|
398
|
+
'warningScatterAndLine',
|
|
399
|
+
Chart,
|
|
400
|
+
'only support these types of marks'
|
|
401
|
+
)
|