diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_text_property.test.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_text_property.test.tsx
new file mode 100644
index 000000000000..4550a27ac2d9
--- /dev/null
+++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_text_property.test.tsx
@@ -0,0 +1,109 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+jest.mock('../components/vector_style_editor', () => ({
+ VectorStyleEditor: () => {
+ return
mockVectorStyleEditor
;
+ },
+}));
+
+import React from 'react';
+
+// @ts-ignore
+import { DynamicTextProperty } from './dynamic_text_property';
+import { RawValue, VECTOR_STYLES } from '../../../../../common/constants';
+import { IField } from '../../../fields/field';
+import { Map as MbMap } from 'mapbox-gl';
+import { mockField, MockLayer, MockStyle } from './test_helpers/test_util';
+import { IVectorLayer } from '../../../layers/vector_layer';
+
+export class MockMbMap {
+ _paintPropertyCalls: unknown[];
+ _lastTextFieldValue: unknown | undefined;
+
+ constructor(lastTextFieldValue?: unknown) {
+ this._paintPropertyCalls = [];
+ this._lastTextFieldValue = lastTextFieldValue;
+ }
+ setLayoutProperty(layerId: string, propName: string, value: undefined | 'string') {
+ if (propName !== 'text-field') {
+ throw new Error('should only use to test `text-field`');
+ }
+ this._lastTextFieldValue = value;
+ this._paintPropertyCalls.push([layerId, value]);
+ }
+
+ getLayoutProperty(layername: string, propName: string): unknown | undefined {
+ if (propName !== 'text-field') {
+ throw new Error('should only use to test `text-field`');
+ }
+ return this._lastTextFieldValue;
+ }
+
+ getPaintPropertyCalls(): unknown[] {
+ return this._paintPropertyCalls;
+ }
+}
+
+const makeProperty = (mockStyle: MockStyle, field: IField | null) => {
+ return new DynamicTextProperty(
+ {},
+ VECTOR_STYLES.LABEL_TEXT,
+ field,
+ (new MockLayer(mockStyle) as unknown) as IVectorLayer,
+ () => {
+ return (value: RawValue) => value + '_format';
+ }
+ );
+};
+
+describe('syncTextFieldWithMb', () => {
+ describe('with field', () => {
+ test('Should set', async () => {
+ const dynamicTextProperty = makeProperty(new MockStyle({ min: 0, max: 100 }), mockField);
+ const mockMbMap = (new MockMbMap() as unknown) as MbMap;
+
+ dynamicTextProperty.syncTextFieldWithMb('foobar', mockMbMap);
+
+ // @ts-expect-error
+ expect(mockMbMap.getPaintPropertyCalls()).toEqual([
+ ['foobar', ['coalesce', ['get', '__kbn__dynamic__foobar__labelText'], '']],
+ ]);
+ });
+ });
+
+ describe('without field', () => {
+ test('Should clear', async () => {
+ const dynamicTextProperty = makeProperty(new MockStyle({ min: 0, max: 100 }), null);
+ const mockMbMap = (new MockMbMap([
+ 'foobar',
+ ['coalesce', ['get', '__kbn__dynamic__foobar__labelText'], ''],
+ ]) as unknown) as MbMap;
+
+ dynamicTextProperty.syncTextFieldWithMb('foobar', mockMbMap);
+
+ // @ts-expect-error
+ expect(mockMbMap.getPaintPropertyCalls()).toEqual([['foobar', undefined]]);
+ });
+
+ test('Should not clear when already cleared', async () => {
+ // This verifies a weird edge-case in mapbox-gl, where setting the `text-field` layout-property to null causes tiles to be invalidated.
+ // This triggers a refetch of the tile during panning and zooming
+ // This affects vector-tile rendering in tiled_vector_layers with custom vector_styles
+ // It does _not_ affect EMS, since that does not have a code-path where a `text-field` need to be resynced.
+ // Do not remove this logic without verifying that mapbox-gl does not re-issue tile-requests for previously requested tiles
+
+ const dynamicTextProperty = makeProperty(new MockStyle({ min: 0, max: 100 }), null);
+ const mockMbMap = (new MockMbMap(undefined) as unknown) as MbMap;
+
+ dynamicTextProperty.syncTextFieldWithMb('foobar', mockMbMap);
+
+ // @ts-expect-error
+ expect(mockMbMap.getPaintPropertyCalls()).toEqual([]);
+ });
+ });
+});
diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_text_property.ts b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_text_property.ts
index 22ea3067b174..e8612388a5ae 100644
--- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_text_property.ts
+++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_text_property.ts
@@ -20,7 +20,9 @@ export class DynamicTextProperty extends DynamicStyleProperty {
+ return new StaticTextProperty({ value }, VECTOR_STYLES.LABEL_TEXT);
+};
+
+describe('syncTextFieldWithMb', () => {
+ test('Should set with value', async () => {
+ const dynamicTextProperty = makeProperty('foo');
+ const mockMbMap = (new MockMbMap() as unknown) as MbMap;
+
+ dynamicTextProperty.syncTextFieldWithMb('foobar', mockMbMap);
+
+ // @ts-expect-error
+ expect(mockMbMap.getPaintPropertyCalls()).toEqual([['foobar', 'foo']]);
+ });
+
+ test('Should not clear when already cleared', async () => {
+ // This verifies a weird edge-case in mapbox-gl, where setting the `text-field` layout-property to null causes tiles to be invalidated.
+ // This triggers a refetch of the tile during panning and zooming
+ // This affects vector-tile rendering in tiled_vector_layers with custom vector_styles
+ // It does _not_ affect EMS, since that does not have a code-path where a `text-field` need to be resynced.
+ // Do not remove this logic without verifying that mapbox-gl does not re-issue tile-requests for previously requested tiles
+
+ const dynamicTextProperty = makeProperty('');
+ const mockMbMap = (new MockMbMap(undefined) as unknown) as MbMap;
+
+ dynamicTextProperty.syncTextFieldWithMb('foobar', mockMbMap);
+
+ // @ts-expect-error
+ expect(mockMbMap.getPaintPropertyCalls()).toEqual([]);
+ });
+});
diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/static_text_property.ts b/x-pack/plugins/maps/public/classes/styles/vector/properties/static_text_property.ts
index b0016106b8c3..fb05fa052db2 100644
--- a/x-pack/plugins/maps/public/classes/styles/vector/properties/static_text_property.ts
+++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/static_text_property.ts
@@ -18,7 +18,9 @@ export class StaticTextProperty extends StaticStyleProperty
if (this.getOptions().value.length) {
mbMap.setLayoutProperty(mbLayerId, 'text-field', this.getOptions().value);
} else {
- mbMap.setLayoutProperty(mbLayerId, 'text-field', null);
+ if (typeof mbMap.getLayoutProperty(mbLayerId, 'text-field') !== 'undefined') {
+ mbMap.setLayoutProperty(mbLayerId, 'text-field', undefined);
+ }
}
}
}