@@ -2856,4 +2856,128 @@ describe('Style#_updatePlacement', () => {
28562856 expect ( startNewPlacementSpy ) . not . toHaveBeenCalled ( ) ;
28572857 expect ( continuePlacementSpy ) . not . toHaveBeenCalled ( ) ;
28582858 } ) ;
2859+
2860+ test ( 'returns true when symbol layer is added after load due to symbolBucketsChanged' , async ( ) => {
2861+ const map = new StubMap ( ) ;
2862+ // @ts -expect-error - painter is not part of StubMap but required for _updatePlacement
2863+ map . painter = { scaleFactor : 1 } ;
2864+ const replacementSource = { updateTime : 0 } ;
2865+
2866+ const style = new Style ( map ) ;
2867+ style . loadJSON ( {
2868+ "version" : 8 ,
2869+ "sources" : {
2870+ "geojson" : {
2871+ "type" : "geojson" ,
2872+ "data" : { "type" : "FeatureCollection" , "features" : [ ] }
2873+ }
2874+ } ,
2875+ "layers" : [ ]
2876+ } ) ;
2877+
2878+ await waitFor ( style , 'style.load' ) ;
2879+
2880+ const tr = map . transform ;
2881+ tr . resize ( 512 , 512 ) ;
2882+
2883+ style . update ( { zoom : tr . zoom , fadeDuration : 0 } ) ;
2884+ style . _updatePlacement ( tr , false , 0 , false , replacementSource ) ;
2885+
2886+ expect ( style . pauseablePlacement . isDone ( ) ) . toBeTruthy ( ) ;
2887+
2888+ style . addLayer ( {
2889+ "id" : "symbol" ,
2890+ "type" : "symbol" ,
2891+ "source" : "geojson"
2892+ } ) ;
2893+
2894+ style . update ( { zoom : tr . zoom , fadeDuration : 0 } ) ;
2895+
2896+ // Spy on crossTileSymbolIndex.addLayer to return true (simulating new symbol buckets)
2897+ // This happens in real scenarios when tiles have symbol features
2898+ vi . spyOn ( style . crossTileSymbolIndex , 'addLayer' ) . mockReturnValue ( true ) ;
2899+
2900+ const result = style . _updatePlacement ( tr , false , 0 , false , replacementSource ) ;
2901+
2902+ expect ( result ) . toBeTruthy ( ) ;
2903+ } ) ;
2904+
2905+ test ( 'returns true when transformChanged' , async ( ) => {
2906+ const map = new StubMap ( ) ;
2907+ // @ts -expect-error - painter is not part of StubMap but required for _updatePlacement
2908+ map . painter = { scaleFactor : 1 } ;
2909+ const replacementSource = { updateTime : 0 } ;
2910+
2911+ const style = new Style ( map ) ;
2912+ style . loadJSON ( {
2913+ "version" : 8 ,
2914+ "sources" : {
2915+ "geojson" : {
2916+ "type" : "geojson" ,
2917+ "data" : { "type" : "FeatureCollection" , "features" : [ ] }
2918+ }
2919+ } ,
2920+ "layers" : [ {
2921+ "id" : "symbol" ,
2922+ "type" : "symbol" ,
2923+ "source" : "geojson"
2924+ } ]
2925+ } ) ;
2926+
2927+ await waitFor ( style , 'style.load' ) ;
2928+
2929+ const tr = map . transform ;
2930+ tr . resize ( 512 , 512 ) ;
2931+
2932+ style . update ( { zoom : tr . zoom , fadeDuration : 0 } ) ;
2933+ style . _updatePlacement ( tr , false , 0 , false , replacementSource ) ;
2934+
2935+ expect ( style . pauseablePlacement . isDone ( ) ) . toBeTruthy ( ) ;
2936+
2937+ // Change transform to trigger transformChanged
2938+ tr . zoom = 5 ;
2939+
2940+ // Use fadeDuration > 0 so that setStale() is called when placement is
2941+ // considered stale due to transform change (line 4210-4211 in style.ts)
2942+ const result = style . _updatePlacement ( tr , false , 300 , false , replacementSource ) ;
2943+
2944+ expect ( result ) . toBeTruthy ( ) ;
2945+ } ) ;
2946+
2947+ test ( 'returns true when replacementSourceChanged' , async ( ) => {
2948+ const map = new StubMap ( ) ;
2949+ // @ts -expect-error - painter is not part of StubMap but required for _updatePlacement
2950+ map . painter = { scaleFactor : 1 } ;
2951+
2952+ const style = new Style ( map ) ;
2953+ style . loadJSON ( {
2954+ "version" : 8 ,
2955+ "sources" : {
2956+ "geojson" : {
2957+ "type" : "geojson" ,
2958+ "data" : { "type" : "FeatureCollection" , "features" : [ ] }
2959+ }
2960+ } ,
2961+ "layers" : [ {
2962+ "id" : "symbol" ,
2963+ "type" : "symbol" ,
2964+ "source" : "geojson"
2965+ } ]
2966+ } ) ;
2967+
2968+ await waitFor ( style , 'style.load' ) ;
2969+
2970+ const tr = map . transform ;
2971+ tr . resize ( 512 , 512 ) ;
2972+
2973+ style . update ( { zoom : tr . zoom , fadeDuration : 0 } ) ;
2974+ style . _updatePlacement ( tr , false , 0 , false , { updateTime : 0 } ) ;
2975+
2976+ expect ( style . pauseablePlacement . isDone ( ) ) . toBeTruthy ( ) ;
2977+
2978+ // Change replacementSource updateTime to trigger replacementSourceChanged
2979+ const result = style . _updatePlacement ( tr , false , 300 , false , { updateTime : 1 } ) ;
2980+
2981+ expect ( result ) . toBeTruthy ( ) ;
2982+ } ) ;
28592983} ) ;
0 commit comments