Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

import { BoolFormat } from './boolean';
import { HTML_CONTEXT_TYPE, TEXT_CONTEXT_TYPE } from '../content_types';

describe('Boolean Format', () => {
let boolean: BoolFormat;
Expand Down Expand Up @@ -64,4 +65,15 @@ describe('Boolean Format', () => {

expect(boolean.convert(s)).toBe(s);
});

test('handles a missing value', () => {
expect(boolean.convert(null, TEXT_CONTEXT_TYPE)).toBe('(null)');
expect(boolean.convert(undefined, TEXT_CONTEXT_TYPE)).toBe('(null)');
expect(boolean.convert(null, HTML_CONTEXT_TYPE)).toBe(
'<span class="ffString__emptyValue">(null)</span>'
);
expect(boolean.convert(undefined, HTML_CONTEXT_TYPE)).toBe(
'<span class="ffString__emptyValue">(null)</span>'
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import { i18n } from '@kbn/i18n';
import { KBN_FIELD_TYPES } from '@kbn/field-types';
import { FieldFormat } from '../field_format';
import type { TextContextTypeConvert } from '../types';
import type { HtmlContextTypeConvert, TextContextTypeConvert } from '../types';
import { FIELD_FORMAT_IDS } from '../types';
import { asPrettyString } from '../utils';

Expand Down Expand Up @@ -42,4 +42,13 @@ export class BoolFormat extends FieldFormat {
return asPrettyString(value, options);
}
};

htmlConvert: HtmlContextTypeConvert = (value, options) => {
const missing = this.checkForMissingValueHtml(value);
if (missing) {
return missing;
}

return this.textConvert(value, options);
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import { BytesFormat } from './bytes';
import { FORMATS_UI_SETTINGS } from '../constants/ui_settings';
import type { FieldFormatsGetConfigFn } from '../types';
import { HTML_CONTEXT_TYPE } from '../content_types';

describe('BytesFormat', () => {
const config: { [key: string]: string } = {
Expand All @@ -29,4 +30,17 @@ describe('BytesFormat', () => {

expect(formatter.convert('5150000')).toBe('5MB');
});

test('missing value', () => {
const formatter = new BytesFormat({}, getConfig);

expect(formatter.convert(null)).toBe('(null)');
expect(formatter.convert(undefined)).toBe('(null)');
expect(formatter.convert(null, HTML_CONTEXT_TYPE)).toBe(
'<span class="ffString__emptyValue">(null)</span>'
);
expect(formatter.convert(undefined, HTML_CONTEXT_TYPE)).toBe(
'<span class="ffString__emptyValue">(null)</span>'
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,27 @@
*/

import { ColorFormat } from './color';
import { HTML_CONTEXT_TYPE } from '../content_types';
import { HTML_CONTEXT_TYPE, TEXT_CONTEXT_TYPE } from '../content_types';

describe('Color Format', () => {
const checkResult = (text: string | number, color: string, backgroundColor: string) =>
`<span style=\"color:${color};background-color:${backgroundColor};display:inline-block;padding:0 8px;border-radius:3px\">${text}</span>`;

const checkMissingValues = (colorer: ColorFormat) => {
expect(colorer.convert(null, HTML_CONTEXT_TYPE)).toBe(
'<span class="ffString__emptyValue">(null)</span>'
);
expect(colorer.convert(undefined, HTML_CONTEXT_TYPE)).toBe(
'<span class="ffString__emptyValue">(null)</span>'
);
expect(colorer.convert('', HTML_CONTEXT_TYPE)).toBe(
'<span class="ffString__emptyValue">(blank)</span>'
);
expect(colorer.convert(null, TEXT_CONTEXT_TYPE)).toBe('(null)');
expect(colorer.convert(undefined, TEXT_CONTEXT_TYPE)).toBe('(null)');
expect(colorer.convert('', TEXT_CONTEXT_TYPE)).toBe('(blank)');
};

describe('field is a number', () => {
test('should add colors if the value is in range', () => {
const colorer = new ColorFormat(
Expand All @@ -34,6 +49,8 @@ describe('Color Format', () => {
expect(colorer.convert(100, HTML_CONTEXT_TYPE)).toBe(checkResult(100, 'blue', 'yellow'));
expect(colorer.convert(150, HTML_CONTEXT_TYPE)).toBe(checkResult(150, 'blue', 'yellow'));
expect(colorer.convert(151, HTML_CONTEXT_TYPE)).toBe('151');

checkMissingValues(colorer);
});

test('should not convert invalid ranges', () => {
Expand Down Expand Up @@ -73,6 +90,8 @@ describe('Color Format', () => {

expect(colorer.convert(true, HTML_CONTEXT_TYPE)).toBe(checkResult('true', 'blue', 'yellow'));
expect(colorer.convert(false, HTML_CONTEXT_TYPE)).toBe('false');

checkMissingValues(colorer);
});
});

Expand Down Expand Up @@ -103,6 +122,8 @@ describe('Color Format', () => {
expect(converter('AB', HTML_CONTEXT_TYPE)).toBe(checkResult('AB', 'white', 'red'));
expect(converter('AB <', HTML_CONTEXT_TYPE)).toBe(checkResult('AB &lt;', 'white', 'red'));
expect(converter('a', HTML_CONTEXT_TYPE)).toBe('a');

checkMissingValues(colorer);
});

test('returns original value (escaped) when regex is invalid', () => {
Expand All @@ -122,6 +143,8 @@ describe('Color Format', () => {
const converter = colorer.getConverterFor(HTML_CONTEXT_TYPE) as Function;

expect(converter('<', HTML_CONTEXT_TYPE)).toBe('&lt;');

checkMissingValues(colorer);
});

test('returns original value (escaped) on regex with syntax error', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import ReactDOM from 'react-dom/server';
import { findLast, cloneDeep, escape } from 'lodash';
import { KBN_FIELD_TYPES } from '@kbn/field-types';
import { FieldFormat } from '../field_format';
import type { HtmlContextTypeConvert } from '../types';
import type { HtmlContextTypeConvert, TextContextTypeConvert } from '../types';
import { FIELD_FORMAT_IDS } from '../types';
import { asPrettyString } from '../utils';
import { DEFAULT_CONVERTER_COLOR } from '../constants/color_default';
Expand Down Expand Up @@ -62,7 +62,21 @@ export class ColorFormat extends FieldFormat {
}
}

textConvert: TextContextTypeConvert = (val: string | number, options) => {
const missing = this.checkForMissingValueText(val);
if (missing) {
return missing;
}

return asPrettyString(val, options);
};

htmlConvert: HtmlContextTypeConvert = (val: string | number, options) => {
const missing = this.checkForMissingValueHtml(val);
if (missing) {
return missing;
}

const color = this.findColorRuleForVal(val) as typeof DEFAULT_CONVERTER_COLOR;

const displayVal = escape(asPrettyString(val, options));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import { CurrencyFormat } from './currency';
import { FORMATS_UI_SETTINGS } from '../constants/ui_settings';
import type { FieldFormatsGetConfigFn } from '../types';
import { HTML_CONTEXT_TYPE, TEXT_CONTEXT_TYPE } from '../content_types';

describe('CurrencyFormat', () => {
const config: { [key: string]: string } = {
Expand All @@ -29,4 +30,17 @@ describe('CurrencyFormat', () => {

expect(formatter.convert('12000.23')).toBe('$12000.2');
});

test('missing value', () => {
const formatter = new CurrencyFormat({ pattern: '$0.[0]' }, getConfig);

expect(formatter.convert(null, TEXT_CONTEXT_TYPE)).toBe('(null)');
expect(formatter.convert(undefined, TEXT_CONTEXT_TYPE)).toBe('(null)');
expect(formatter.convert(null, HTML_CONTEXT_TYPE)).toBe(
'<span class="ffString__emptyValue">(null)</span>'
);
expect(formatter.convert(undefined, HTML_CONTEXT_TYPE)).toBe(
'<span class="ffString__emptyValue">(null)</span>'
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import moment from 'moment-timezone';
import { DateNanosFormat, analysePatternForFract, formatWithNanos } from './date_nanos_shared';
import type { FieldFormatsGetConfigFn } from '../types';
import { HTML_CONTEXT_TYPE, TEXT_CONTEXT_TYPE } from '../content_types';

describe('Date Nanos Format', () => {
let convert: Function;
Expand Down Expand Up @@ -71,9 +72,15 @@ describe('Date Nanos Format', () => {
});
});

test('decoding an undefined or null date should return an empty string', () => {
expect(convert(null)).toBe('-');
expect(convert(undefined)).toBe('-');
test('decoding a missing value', () => {
expect(convert(null, TEXT_CONTEXT_TYPE)).toBe('(null)');
expect(convert(undefined, TEXT_CONTEXT_TYPE)).toBe('(null)');
expect(convert(null, HTML_CONTEXT_TYPE)).toBe(
'<span class="ffString__emptyValue">(null)</span>'
);
expect(convert(undefined, HTML_CONTEXT_TYPE)).toBe(
'<span class="ffString__emptyValue">(null)</span>'
);
});

test('should clear the memoization cache after changing the date', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ import { memoize, noop } from 'lodash';
import { KBN_FIELD_TYPES } from '@kbn/field-types';
import type { Moment } from 'moment';
import moment from 'moment';
import { NULL_LABEL } from '@kbn/field-formats-common';
import { FieldFormat, FIELD_FORMAT_IDS } from '..';
import type { TextContextTypeConvert } from '../types';
import type { TextContextTypeConvert, HtmlContextTypeConvert } from '../types';

interface FractPatternObject {
length: number;
Expand Down Expand Up @@ -102,7 +103,7 @@ export class DateNanosFormat extends FieldFormat {

this.memoizedConverter = memoize(function converter(value: string | number) {
if (value === null || value === undefined) {
return '-';
return NULL_LABEL;
}

const date = moment(value);
Expand All @@ -121,4 +122,13 @@ export class DateNanosFormat extends FieldFormat {

return this.memoizedConverter(val);
};

htmlConvert: HtmlContextTypeConvert = (val, options) => {
const missing = this.checkForMissingValueHtml(val);
if (missing) {
return missing;
}

return this.textConvert(val, options);
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ describe('Duration Format', () => {
input: 125,
output: '2 minutes',
},
{
input: null,
output: '(null)',
},
{
input: undefined,
output: '(null)',
},
],
});

Expand Down Expand Up @@ -552,9 +560,9 @@ describe('Duration Format', () => {
showSuffix: boolean | undefined;
useShortSuffix?: boolean;
includeSpaceWithSuffix?: boolean;
fixtures: Array<{ input: number; output: string }>;
fixtures: Array<{ input: number | null | undefined; output: string }>;
}) {
fixtures.forEach((fixture: { input: number; output: string }) => {
fixtures.forEach((fixture: { input: number | null | undefined; output: string }) => {
const input = fixture.input;
const output = fixture.output;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type { unitOfTime, Duration } from 'moment';
import moment from 'moment';
import { KBN_FIELD_TYPES } from '@kbn/field-types';
import { FieldFormat } from '../field_format';
import type { TextContextTypeConvert } from '../types';
import type { HtmlContextTypeConvert, TextContextTypeConvert } from '../types';
import { FIELD_FORMAT_IDS } from '../types';
import {
DEFAULT_DURATION_INPUT_FORMAT,
Expand Down Expand Up @@ -68,6 +68,11 @@ export class DurationFormat extends FieldFormat {
}

textConvert: TextContextTypeConvert = (val: number) => {
const missing = this.checkForMissingValueText(val);
if (missing) {
return missing;
}

const inputFormat = this.param('inputFormat');
const outputFormat = this.param('outputFormat') as keyof Duration;
const outputPrecision = this.param('outputPrecision');
Expand Down Expand Up @@ -107,6 +112,15 @@ export class DurationFormat extends FieldFormat {

return humanPrecise ? precise : prefix + precise + suffix;
};

htmlConvert: HtmlContextTypeConvert = (val, options) => {
const missing = this.checkForMissingValueHtml(val);
if (missing) {
return missing;
}

return this.textConvert(val, options);
};
}

// Array of units is to find the first unit duration value that is not 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

import { GeoPointFormat } from './geo_point';
import { HTML_CONTEXT_TYPE, TEXT_CONTEXT_TYPE } from '../content_types';

describe('GeoPoint Format', () => {
describe('output format', () => {
Expand Down Expand Up @@ -88,5 +89,22 @@ describe('GeoPoint Format', () => {
);
expect(geoPointFormat.convert('notgeopoint')).toBe('notgeopoint');
});

test('missing value', () => {
const geoPointFormat = new GeoPointFormat(
{
transform: 'lat_lon_string',
},
jest.fn()
);
expect(geoPointFormat.convert(null, TEXT_CONTEXT_TYPE)).toBe('(null)');
expect(geoPointFormat.convert(undefined, TEXT_CONTEXT_TYPE)).toBe('(null)');
expect(geoPointFormat.convert(null, HTML_CONTEXT_TYPE)).toBe(
'<span class="ffString__emptyValue">(null)</span>'
);
expect(geoPointFormat.convert(undefined, HTML_CONTEXT_TYPE)).toBe(
'<span class="ffString__emptyValue">(null)</span>'
);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import type { Point } from 'geojson';
import { i18n } from '@kbn/i18n';
import { KBN_FIELD_TYPES } from '@kbn/field-types';
import { FieldFormat } from '../field_format';
import type { TextContextTypeConvert } from '../types';
import type { TextContextTypeConvert, HtmlContextTypeConvert } from '../types';
import { FIELD_FORMAT_IDS } from '../types';
import { asPrettyString, geoUtils } from '../utils';
const { ddToMGRS, ddToDMS } = geoUtils;
Expand Down Expand Up @@ -119,8 +119,9 @@ export class GeoPointFormat extends FieldFormat {
val: Point | { lat: number; lon: number } | string,
options
) => {
if (!val) {
return '';
const missing = this.checkForMissingValueText(val);
if (missing) {
return missing;
}

const point: Point | null = isPoint(val) ? (val as Point) : toPoint(val);
Expand All @@ -146,4 +147,13 @@ DMS: ${ddToDMS(point.coordinates[1], point.coordinates[0])}`;
return asPrettyString(val, options);
}
};

htmlConvert: HtmlContextTypeConvert = (val, options) => {
const missing = this.checkForMissingValueHtml(val);
if (missing) {
return missing;
}

return this.textConvert(val, options);
};
}
Loading
Loading