diff --git a/ui/src/features/common/analysis-modal/transforms.test.ts b/ui/src/features/common/analysis-modal/transforms.test.ts index e3750a498f..f97428bc27 100644 --- a/ui/src/features/common/analysis-modal/transforms.test.ts +++ b/ui/src/features/common/analysis-modal/transforms.test.ts @@ -24,7 +24,8 @@ import { metricStatusLabel, metricSubstatus, printableCloudWatchQuery, - printableDatadogQuery + printableDatadogQuery, + transformMeasurements } from './transforms'; import { AnalysisStatus, FunctionalStatus } from './types'; @@ -559,4 +560,43 @@ describe('analysis modal transforms', () => { tableValue: { latency: null, cpuUsage: null } }); }); + + // Regression: a provider that returns plain text (the web provider passes a + // text/plain body through unchanged) used to throw a SyntaxError out of + // JSON.parse and take the whole analysis modal down with it. + test('transformMeasurements() with a plain text measurement value', () => { + expect(transformMeasurements([], [{ value: 'PASS' }])).toEqual({ + chartable: false, + min: 0, + max: null, + measurements: [{ value: 'PASS', chartValue: null, tableValue: 'PASS' }] + }); + }); + test('transformMeasurements() with a malformed JSON measurement value', () => { + expect(transformMeasurements([], [{ value: '{"cpuUsage":' }])).toEqual({ + chartable: false, + min: 0, + max: null, + measurements: [{ value: '{"cpuUsage":', chartValue: null, tableValue: '{"cpuUsage":' }] + }); + }); + test('transformMeasurements() still parses a valid JSON measurement value', () => { + expect(transformMeasurements([], [{ value: '500' }])).toEqual({ + chartable: true, + min: 0, + max: 500, + measurements: [{ value: '500', chartValue: 500, tableValue: 500 }] + }); + }); + test('transformMeasurements() with both parseable and unparseable values', () => { + expect(transformMeasurements([], [{ value: '500' }, { value: 'PASS' }])).toEqual({ + chartable: false, + min: 0, + max: 500, + measurements: [ + { value: '500', chartValue: 500, tableValue: 500 }, + { value: 'PASS', chartValue: null, tableValue: 'PASS' } + ] + }); + }); }); diff --git a/ui/src/features/common/analysis-modal/transforms.ts b/ui/src/features/common/analysis-modal/transforms.ts index 046ef4f86e..9bec6b9f6a 100644 --- a/ui/src/features/common/analysis-modal/transforms.ts +++ b/ui/src/features/common/analysis-modal/transforms.ts @@ -783,7 +783,19 @@ const transformMeasurementValue = ( }; } - const parsedValue = JSON.parse(value); + let parsedValue; + try { + parsedValue = JSON.parse(value); + } catch { + // Providers are not obliged to return JSON. The web provider, for one, + // passes a plain text response through untouched. Such a value cannot be + // charted, but it is still worth surfacing in the table as-is. + return { + canChart: false, + chartValue: null, + tableValue: value + }; + } // single number measurement value if (isFiniteNumber(parsedValue)) {