import {createStyleLayer} from './create_style_layer'; import {FillStyleLayer} from './style_layer/fill_style_layer'; import {extend} from '../util/util'; import {Color, LayerSpecification} from '@maplibre/maplibre-gl-style-spec'; import {EvaluationParameters} from './evaluation_parameters'; import {TransitionParameters} from './properties'; import {BackgroundStyleLayer} from './style_layer/background_style_layer'; import {SymbolStyleLayer} from './style_layer/symbol_style_layer'; describe('StyleLayer', () => { test('instantiates the correct subclass', () => { const layer = createStyleLayer({type: 'fill'} as LayerSpecification); expect(layer instanceof FillStyleLayer).toBeTruthy(); }); }); describe('StyleLayer#setPaintProperty', () => { test('sets new property value', () => { const layer = createStyleLayer({ 'id': 'background', 'type': 'background' }); layer.setPaintProperty('background-color', 'blue'); expect(layer.getPaintProperty('background-color')).toBe('blue'); }); test('updates property value', () => { const layer = createStyleLayer({ 'id': 'background', 'type': 'background', 'paint': { 'background-color': 'red' } }); layer.setPaintProperty('background-color', 'blue'); expect(layer.getPaintProperty('background-color')).toBe('blue'); }); test('unsets value', () => { const layer = createStyleLayer({ 'id': 'background', 'type': 'background', 'paint': { 'background-color': 'red', 'background-opacity': 1 } }) as BackgroundStyleLayer; layer.setPaintProperty('background-color', null); layer.updateTransitions({} as TransitionParameters); layer.recalculate({zoom: 0, zoomHistory: {}} as EvaluationParameters, undefined); expect(layer.paint.get('background-color')).toEqual(new Color(0, 0, 0, 1)); expect(layer.getPaintProperty('background-color')).toBeUndefined(); expect(layer.paint.get('background-opacity')).toBe(1); expect(layer.getPaintProperty('background-opacity')).toBe(1); }); test('preserves existing transition', () => { const layer = createStyleLayer({ 'id': 'background', 'type': 'background', 'paint': { 'background-color': 'red', 'background-color-transition': { duration: 600 } } as any }); layer.setPaintProperty('background-color', 'blue'); expect(layer.getPaintProperty('background-color-transition')).toEqual({duration: 600}); }); test('sets transition', () => { const layer = createStyleLayer({ 'id': 'background', 'type': 'background', 'paint': { 'background-color': 'red' } }); layer.setPaintProperty('background-color-transition', {duration: 400}); expect(layer.getPaintProperty('background-color-transition')).toEqual({duration: 400}); }); test('emits on an invalid property value', () => new Promise(done => { const layer = createStyleLayer({ 'id': 'background', 'type': 'background' }); layer.on('error', () => { expect(layer.getPaintProperty('background-opacity')).toBeUndefined(); done(); }); layer.setPaintProperty('background-opacity', 5); })); test('emits on an invalid transition property value', () => new Promise(done => { const layer = createStyleLayer({ 'id': 'background', 'type': 'background' }); layer.on('error', () => { done(); }); layer.setPaintProperty('background-opacity-transition', { duration: -10 }); })); test('can unset fill-outline-color #2886', () => { const layer = createStyleLayer({ id: 'building', type: 'fill', source: 'streets', paint: { 'fill-color': '#00f' } }) as FillStyleLayer; layer.setPaintProperty('fill-outline-color', '#f00'); layer.updateTransitions({} as TransitionParameters); layer.recalculate({zoom: 0, zoomHistory: {}} as EvaluationParameters, undefined); expect(layer.paint.get('fill-outline-color').value).toEqual({kind: 'constant', value: new Color(1, 0, 0, 1)}); layer.setPaintProperty('fill-outline-color', undefined); layer.updateTransitions({} as TransitionParameters); layer.recalculate({zoom: 0, zoomHistory: {}} as EvaluationParameters, undefined); expect(layer.paint.get('fill-outline-color').value).toEqual({kind: 'constant', value: new Color(0, 0, 1, 1)}); }); test('can transition fill-outline-color from undefined to a value #3657', () => { const layer = createStyleLayer({ id: 'building', type: 'fill', source: 'streets', paint: { 'fill-color': '#00f' } }) as FillStyleLayer; // setup: set and then unset fill-outline-color so that, when we then try // to re-set it, StyleTransition#calculate() attempts interpolation layer.setPaintProperty('fill-outline-color', '#f00'); layer.updateTransitions({} as TransitionParameters); layer.recalculate({zoom: 0, zoomHistory: {}} as EvaluationParameters, undefined); layer.setPaintProperty('fill-outline-color', undefined); layer.updateTransitions({} as TransitionParameters); layer.recalculate({zoom: 0, zoomHistory: {}} as EvaluationParameters, undefined); // re-set fill-outline-color and get its value, triggering the attempt // to interpolate between undefined and #f00 layer.setPaintProperty('fill-outline-color', '#f00'); layer.updateTransitions({} as TransitionParameters); layer.recalculate({zoom: 0, zoomHistory: {}} as EvaluationParameters, undefined); layer.paint.get('fill-outline-color'); }); test('sets null property value', () => { const layer = createStyleLayer({ 'id': 'background', 'type': 'background' }); layer.setPaintProperty('background-color-transition', null); expect(layer.getPaintProperty('background-color-transition')).toBeUndefined(); }); }); describe('StyleLayer#setLayoutProperty', () => { test('sets new property value', () => { const layer = createStyleLayer({ 'id': 'symbol', 'type': 'symbol' } as LayerSpecification); layer.setLayoutProperty('text-transform', 'lowercase'); expect(layer.getLayoutProperty('text-transform')).toBe('lowercase'); }); test('emits on an invalid property value', () => new Promise(done => { const layer = createStyleLayer({ 'id': 'symbol', 'type': 'symbol' } as LayerSpecification); layer.on('error', () => { done(); }); layer.setLayoutProperty('text-transform', 'invalidValue'); })); test('updates property value', () => { const layer = createStyleLayer({ 'id': 'symbol', 'type': 'symbol', 'layout': { 'text-transform': 'uppercase' } } as LayerSpecification); layer.setLayoutProperty('text-transform', 'lowercase'); expect(layer.getLayoutProperty('text-transform')).toBe('lowercase'); }); test('unsets property value', () => { const layer = createStyleLayer({ 'id': 'symbol', 'type': 'symbol', 'layout': { 'text-transform': 'uppercase' } } as LayerSpecification) as SymbolStyleLayer; layer.setLayoutProperty('text-transform', null); layer.recalculate({zoom: 0, zoomHistory: {}} as EvaluationParameters, undefined); expect(layer.layout.get('text-transform').value).toEqual({kind: 'constant', value: 'none'}); expect(layer.getLayoutProperty('text-transform')).toBeUndefined(); }); }); describe('StyleLayer#serialize', () => { function createSymbolLayer(layer?) { return extend({ id: 'symbol', type: 'symbol', paint: { 'text-color': 'blue' }, layout: { 'text-transform': 'uppercase' } }, layer); } test('serializes layers', () => { expect(createStyleLayer(createSymbolLayer()).serialize()).toEqual(createSymbolLayer()); }); test('serializes functions', () => { const layerPaint = { 'text-color': { base: 2, stops: [[0, 'red'], [1, 'blue']] } }; expect(createStyleLayer(createSymbolLayer({paint: layerPaint})).serialize().paint).toEqual(layerPaint); }); test('serializes added paint properties', () => { const layer = createStyleLayer(createSymbolLayer()); layer.setPaintProperty('text-halo-color', 'orange'); expect(layer.serialize().paint['text-halo-color']).toBe('orange'); expect(layer.serialize().paint['text-color']).toBe('blue'); }); test('serializes added layout properties', () => { const layer = createStyleLayer(createSymbolLayer()); layer.setLayoutProperty('text-size', 20); expect(layer.serialize().layout['text-transform']).toBe('uppercase'); expect(layer.serialize().layout['text-size']).toBe(20); }); test('serializes "visibility" of "visible"', () => { const layer = createStyleLayer(createSymbolLayer()); layer.setLayoutProperty('visibility', 'visible'); expect(layer.serialize().layout['visibility']).toBe('visible'); }); test('serializes "visibility" of "none"', () => { const layer = createStyleLayer(createSymbolLayer()); layer.setLayoutProperty('visibility', 'none'); expect(layer.serialize().layout['visibility']).toBe('none'); }); test('serializes "visibility" of undefined', () => { const layer = createStyleLayer(createSymbolLayer()); layer.setLayoutProperty('visibility', undefined); expect(layer.serialize().layout['visibility']).toBeUndefined(); }); }); describe('StyleLayer#serialize', () => { function createSymbolLayer(layer?) { return extend({ id: 'symbol', type: 'symbol', paint: { 'text-color': 'blue' }, layout: { 'text-transform': 'uppercase' } }, layer); } test('serializes layers', () => { expect(createStyleLayer(createSymbolLayer()).serialize()).toEqual(createSymbolLayer()); }); test('serializes functions', () => { const layerPaint = { 'text-color': { base: 2, stops: [[0, 'red'], [1, 'blue']] } }; expect(createStyleLayer(createSymbolLayer({paint: layerPaint})).serialize().paint).toEqual(layerPaint); }); test('serializes added paint properties', () => { const layer = createStyleLayer(createSymbolLayer()); layer.setPaintProperty('text-halo-color', 'orange'); expect(layer.serialize().paint['text-halo-color']).toBe('orange'); expect(layer.serialize().paint['text-color']).toBe('blue'); }); test('serializes added layout properties', () => { const layer = createStyleLayer(createSymbolLayer()); layer.setLayoutProperty('text-size', 20); expect(layer.serialize().layout['text-transform']).toBe('uppercase'); expect(layer.serialize().layout['text-size']).toBe(20); }); test('layer.paint is never undefined', () => { const layer = createStyleLayer({type: 'fill'} as LayerSpecification); // paint is never undefined expect(layer.paint).toBeTruthy(); }); });