diff --git a/web/client/components/data/featuregrid/formatters/__tests__/index-test.jsx b/web/client/components/data/featuregrid/formatters/__tests__/index-test.jsx
index 5e0a27287e..8dd17b2033 100644
--- a/web/client/components/data/featuregrid/formatters/__tests__/index-test.jsx
+++ b/web/client/components/data/featuregrid/formatters/__tests__/index-test.jsx
@@ -6,72 +6,120 @@
* LICENSE file in the root directory of this source tree.
*/
import React from "react";
-import ReactDOM from "react-dom";
+import ReactDOM, {unmountComponentAtNode} from "react-dom";
import expect from "expect";
+import { act } from "react-dom/test-utils";
-import NumberFormat from "../../../../I18N/Number";
-import { getFormatter, registerFormatter, unregisterFormatter } from "../index";
+import {
+ getFormatter,
+ registerFormatter,
+ unregisterFormatter
+} from "../index";
+let container = null;
describe("Tests for the formatter functions", () => {
+ beforeEach(() => {
+ // setup a DOM element as a render target
+ container = document.createElement("div");
+ document.body.appendChild(container);
+ });
+
+ afterEach(() => {
+ // cleanup on exiting
+ unmountComponentAtNode(container);
+ container.remove();
+ container = null;
+ });
it("test getFormatter for booleans", () => {
const formatter = getFormatter({ localType: "boolean" });
- expect(typeof formatter).toBe("function");
- expect(formatter()).toBe(null);
- expect(formatter({ value: true }).type).toBe("span");
- expect(formatter({ value: true }).props.children).toBe("true");
- expect(formatter({ value: false }).props.children).toBe("false");
- expect(formatter({ value: null })).toBe(null);
- expect(formatter({ value: undefined })).toBe(null);
+ act(() => {
+ ReactDOM.render(formatter({ value: true }), container);
+ });
+ expect(container.textContent).toBe("true");
+
+ act(() => {
+ ReactDOM.render(formatter({ value: false }), container);
+ });
+ expect(container.textContent).toBe("false");
});
it("test getFormatter for strings", () => {
const value = "Test https://google.com with google link";
- const formatter = getFormatter({ localType: "string" });
- expect(typeof formatter).toBe("function");
- expect(formatter()).toBe(null);
- expect(formatter({ value: "Test no links" })[0]).toBe("Test no links");
- expect(formatter({ value })[0]).toBe("Test ");
- expect(formatter({ value })[1].props.href).toBe("https://google.com");
- expect(formatter({ value })[2]).toBe(" with google link");
- expect(formatter({ value: null })).toBe(null);
- expect(formatter({ value: undefined })).toBe(null);
+ const Formatter = getFormatter({ localType: "string" });
+ act(() => {
+ ReactDOM.render(, container);
+ });
+ expect(container.textContent).toBe(value);
});
it("test getFormatter for number", () => {
- const formatter = getFormatter({ localType: "number" });
- expect(typeof formatter).toBe("function");
- expect(formatter()).toBe(null);
- expect(formatter({ value: 44.3333434353535 }).type).toBe(NumberFormat);
- expect(formatter({ value: 44.3333434353535 }).props.value).toBe(
- 44.3333434353535
- );
- expect(formatter({ value: null })).toBe(null);
- expect(formatter({ value: undefined })).toBe(null);
- expect(formatter({ value: 0 }).props.value).toBe(0);
+ const Formatter = getFormatter({ localType: "number" });
+ act(() => {
+ ReactDOM.render(, container);
+ });
+ expect(container.textContent).toBe("");
+ act(() => {
+ ReactDOM.render(, container);
+ });
+ expect(container.textContent).toBe("44.3333434353535");
+ act(() => {
+ ReactDOM.render(, container);
+ });
+ expect(container.textContent).toBe("");
+ act(() => {
+ ReactDOM.render(, container);
+ });
+ expect(container.textContent).toBe("");
+ act(() => {
+ ReactDOM.render(, container);
+ });
+ expect(container.textContent).toBe("0");
});
it("test getFormatter for int", () => {
- const formatter = getFormatter({ localType: "int" });
- expect(typeof formatter).toBe("function");
- expect(formatter()).toBe(null);
- expect(formatter({ value: 2455567 }).type).toBe(NumberFormat);
- expect(formatter({ value: 2455567 }).props.value).toBe(2455567);
- expect(formatter({ value: null })).toBe(null);
- expect(formatter({ value: undefined })).toBe(null);
- expect(formatter({ value: 0 }).props.value).toBe(0);
+ const Formatter = getFormatter({ localType: "int" });
+ act(() => {
+ ReactDOM.render(, container);
+ });
+ expect(container.textContent).toBe("");
+ act(() => {
+ ReactDOM.render(, container);
+ });
+ expect(container.textContent).toBe("2455567");
+ act(() => {
+ ReactDOM.render(, container);
+ });
+ expect(container.textContent).toBe("");
+ act(() => {
+ ReactDOM.render(, container);
+ });
+ expect(container.textContent).toBe("");
+ act(() => {
+ ReactDOM.render(, container);
+ });
+ expect(container.textContent).toBe("0");
});
+
it("test getFormatter for geometry", () => {
- const formatter = getFormatter({ localType: "Geometry" });
- expect(typeof formatter).toBe("function");
- expect(formatter()).toBe(null);
- expect(
- formatter({
- value: {
- properties: {},
- geometry: { type: "Point", coordinates: [1, 2] }
- }
- })
- ).toBe(null);
- expect(formatter({ value: null })).toBe(null);
- expect(formatter({ value: undefined })).toBe(null);
+ const Formatter = getFormatter({ localType: "Geometry" });
+ act(() => {
+ ReactDOM.render(, container);
+ });
+ expect(container.textContent).toBe("");
+ act(() => {
+ ReactDOM.render(, container);
+ });
+ expect(container.textContent).toBe("");
+ act(() => {
+ ReactDOM.render(, container);
+ });
+ expect(container.textContent).toBe("");
+ act(() => {
+ ReactDOM.render(, container);
+ });
+ expect(container.textContent).toBe("");
});
+
describe("test featureGridFormatter", () => {
beforeEach((done) => {
document.body.innerHTML = '
';
@@ -132,51 +180,55 @@ describe("Tests for the formatter functions", () => {
"date-time": "YYYY DD",
time: "HH:mm"
};
- const dateFormatter = getFormatter({ localType: "date" }, undefined, {
- dateFormats
- });
- const dateTimeFormatter = getFormatter(
- { localType: "date-time" },
- undefined,
- { dateFormats }
- );
- const timeFormatter = getFormatter({ localType: "time" }, undefined, {
- dateFormats
- });
- expect(typeof dateFormatter).toBe("function");
- expect(dateFormatter()).toBe(null);
- expect(dateFormatter({ value: "2015-02-01T12:45:00Z" })).toBe("2015");
- expect(typeof dateTimeFormatter).toBe("function");
- expect(dateTimeFormatter()).toBe(null);
- expect(dateTimeFormatter({ value: "2015-02-01Z" })).toBe("2015 01");
- expect(typeof timeFormatter).toBe("function");
- expect(timeFormatter()).toBe(null);
- expect(timeFormatter({ value: "12:45:00Z" })).toBe("12:45");
- expect(timeFormatter({ value: "1970-01-01T02:30:00Z" })).toBe("02:30"); // still able to format time even when found a full date (sometimes GeoServer returns full date instead of time only)
+ const DateFormatter = getFormatter({ localType: "date" }, undefined, { dateFormats });
+ const DateTimeFormatter = getFormatter({ localType: "date-time" }, undefined, { dateFormats });
+ const TimeFormatter = getFormatter({ localType: "time" }, undefined, { dateFormats });
+
+ act(() => {
+ ReactDOM.render(, container);
+ });
+ expect(container.textContent).toBe("2015");
+
+ act(() => {
+ ReactDOM.render(, container);
+ });
+ expect(container.textContent).toBe("2015 01");
+
+ act(() => {
+ ReactDOM.render(, container);
+ });
+ expect(container.textContent).toBe("12:45");
+
+ act(() => {
+ ReactDOM.render(, container);
+ });
+ expect(container.textContent).toBe("02:30");
});
it("test getFormatter for invalid date-time YYYY-MM-DD[Z]", () => {
const dateFormats = {
"date-time": "YYYY-MM-DD[Z]"
};
- const dateTimeWithZFormatter = getFormatter(
- { localType: "date-time" },
- undefined,
- { dateFormats }
- );
- expect(typeof dateTimeWithZFormatter).toBe("function");
- expect(dateTimeWithZFormatter({ value: "2015-02-01Z" })).toBe(
- "2015-02-01Z"
- );
- expect(dateTimeWithZFormatter({ value: "2015-02-01" })).toBe(
- "2015-02-01Z"
- );
- expect(dateTimeWithZFormatter({ value: "2015/02/01" })).toBe(
- "2015-02-01Z"
- );
- expect(dateTimeWithZFormatter({ value: "2015/02/01 03:20:10" })).toBe(
- "2015-02-01Z"
- );
- expect(dateTimeWithZFormatter({ value: "2015-02-01T12:45:00Z"})).toBe('2015-02-01Z');
+ const DateTimeWithZFormatter = getFormatter({ localType: "date-time" }, undefined, { dateFormats });
+
+ act(() => {
+ ReactDOM.render(, container);
+ });
+ expect(container.textContent).toBe("2015-02-01Z");
+
+ act(() => {
+ ReactDOM.render(, container);
+ });
+ expect(container.textContent).toBe("2015-02-01Z");
+
+ act(() => {
+ ReactDOM.render(, container);
+ });
+ expect(container.textContent).toBe("2015-02-01Z");
+
+ act(() => {
+ ReactDOM.render(, container);
+ });
+ expect(container.textContent).toBe("2015-02-01Z");
});
});
diff --git a/web/client/components/data/featuregrid/formatters/index.js b/web/client/components/data/featuregrid/formatters/index.js
index 5f2e4104e4..a08d393e1e 100644
--- a/web/client/components/data/featuregrid/formatters/index.js
+++ b/web/client/components/data/featuregrid/formatters/index.js
@@ -12,26 +12,33 @@ import reactStringReplace from "react-string-replace";
import moment from "moment";
import NumberFormat from '../../../I18N/Number';
+import { handleLongTextEnhancer } from '../../../misc/enhancers/handleLongTextEnhancer';
+
import { dateFormats as defaultDateFormats } from "../../../../utils/FeatureGridUtils";
-const BooleanFormatter = ({value} = {}) => !isNil(value) ? {value.toString()} : null;
+export const BooleanFormatter = ({value} = {}) => !isNil(value) ? {value.toString()} : null;
export const StringFormatter = ({value} = {}) => !isNil(value) ? reactStringReplace(value, /(https?:\/\/\S+)/g, (match, i) => (
{match}
)) : null;
-const NumberFormatter = ({value} = {}) => !isNil(value) ? : null;
+export const NumberFormatter = ({value} = {}) => !isNil(value) ? : null;
const DEFAULT_DATE_PART = "1970-01-01";
-const DATE_INPUT_FORAMAT = "YYYY-MM-DD[Z]";
-const dateTimeFormatter = ({value, format, type}) => {
+const DATE_INPUT_FORMAT = "YYYY-MM-DD[Z]";
+export const DateTimeFormatter = ({value, format, type}) => {
return !isNil(value)
? moment.utc(value).isValid() // geoserver sometimes returns UTC for time.
? moment.utc(value).format(format)
: type === 'time'
? moment(`${DEFAULT_DATE_PART}T${value}`).utc().format(format) // time format append default date part
: type === "date" && value?.toLowerCase()?.endsWith("z") // in case: date format and value ends with z
- ? moment(value, DATE_INPUT_FORAMAT).format(format)
+ ? moment(value, DATE_INPUT_FORMAT).format(format)
: moment(value).format(format)
: null;
};
+// add long text handling to formatters of string, date and number
+const EnhancedStringFormatter = handleLongTextEnhancer(StringFormatter);
+const EnhancedNumberFormatter = handleLongTextEnhancer(NumberFormatter);
+const enhancedDateTimeFormatter = handleLongTextEnhancer(DateTimeFormatter);
+
export const register = {};
/**
@@ -83,16 +90,16 @@ export const getFormatter = (desc, {featureGridFormatter} = {}, {dateFormats} =
return BooleanFormatter;
case 'int':
case 'number':
- return NumberFormatter;
+ return EnhancedNumberFormatter;
case 'string':
- return StringFormatter;
+ return EnhancedStringFormatter;
case 'Geometry':
return () => null;
case 'time':
case 'date':
case 'date-time':
const format = get(dateFormats, desc.localType) ?? defaultDateFormats[desc.localType];
- return ({value} = {}) => dateTimeFormatter({value, format, type: desc.localType});
+ return ({value} = {}) => enhancedDateTimeFormatter({value, format, type: desc.localType});
default:
return null;
}
diff --git a/web/client/utils/FeatureGridUtils.js b/web/client/utils/FeatureGridUtils.js
index 190f62cb91..16f9e3851f 100644
--- a/web/client/utils/FeatureGridUtils.js
+++ b/web/client/utils/FeatureGridUtils.js
@@ -18,7 +18,6 @@ import {
} from './ogc/WFS/base';
import { applyDefaultToLocalizedString } from '../components/I18N/LocalizedString';
-import { handleLongTextEnhancer } from '../components/misc/enhancers/handleLongTextEnhancer';
const getGeometryName = (describe) => get(findGeometryProperty(describe), "name");
const getPropertyName = (name, describe) => name === "geometry" ? getGeometryName(describe) : name;
@@ -148,7 +147,7 @@ export const featureTypeToGridColumns = (
editable,
filterable,
editor: getEditor(desc, field),
- formatter: handleLongTextEnhancer(getFormatter(desc, field)),
+ formatter: getFormatter(desc, field),
filterRenderer: getFilterRenderer(desc, field)
};
});
diff --git a/web/client/utils/__tests__/FeatureGridUtils-test.js b/web/client/utils/__tests__/FeatureGridUtils-test.js
index aafbbac3ea..677017bf1e 100644
--- a/web/client/utils/__tests__/FeatureGridUtils-test.js
+++ b/web/client/utils/__tests__/FeatureGridUtils-test.js
@@ -363,8 +363,6 @@ describe('FeatureGridUtils', () => {
document.getElementById("container")
);
expect(document.getElementById("container").innerHTML).toExist();
- expect(document.getElementsByTagName('span').length).toEqual(2);
- expect(document.getElementsByTagName('span')[1].innerHTML).toExist();
});
});