@@ -95,6 +95,65 @@ describe('deriveBlockVersion - tab underline', () => {
9595 const b = deriveBlockVersion ( makeTabParagraph ( { style : 'single' , color : '#000000' } ) ) ;
9696 expect ( a ) . toBe ( b ) ;
9797 } ) ;
98+
99+ // SD-3330: the painter's tab underline thickness comes from fontSize, and its offset/color
100+ // come from measured line metrics fed by fontFamily and the run color. Each must change the
101+ // block version, or a font-size/family/color edit leaves a stale tab underline cached.
102+ const makeStyledTabParagraph = (
103+ overrides : Partial < { fontSize : number ; fontFamily : string ; color : string ; bold : boolean ; italic : boolean } > ,
104+ ) : FlowBlock => ( {
105+ kind : 'paragraph' ,
106+ id : 'p1' ,
107+ attrs : { } ,
108+ runs : [
109+ {
110+ kind : 'tab' ,
111+ text : '\t' ,
112+ pmStart : 1 ,
113+ pmEnd : 2 ,
114+ underline : { style : 'single' , color : '#000000' } ,
115+ ...overrides ,
116+ } as TabRun ,
117+ ] ,
118+ } ) ;
119+
120+ it ( 'produces a different version when the tab fontSize changes' , ( ) => {
121+ const small = deriveBlockVersion ( makeStyledTabParagraph ( { fontSize : 12 } ) ) ;
122+ const large = deriveBlockVersion ( makeStyledTabParagraph ( { fontSize : 24 } ) ) ;
123+ expect ( large ) . not . toBe ( small ) ;
124+ } ) ;
125+
126+ it ( 'produces a different version when the tab fontFamily changes' , ( ) => {
127+ const arial = deriveBlockVersion ( makeStyledTabParagraph ( { fontFamily : 'Arial' } ) ) ;
128+ const times = deriveBlockVersion ( makeStyledTabParagraph ( { fontFamily : 'Times New Roman' } ) ) ;
129+ expect ( times ) . not . toBe ( arial ) ;
130+ } ) ;
131+
132+ it ( 'produces a different version when the tab run color changes' , ( ) => {
133+ const black = deriveBlockVersion ( makeStyledTabParagraph ( { color : '#000000' } ) ) ;
134+ const red = deriveBlockVersion ( makeStyledTabParagraph ( { color : '#FF0000' } ) ) ;
135+ expect ( red ) . not . toBe ( black ) ;
136+ } ) ;
137+
138+ // SD-3330 review: tab-only line metrics now come from the tab's font via getFontInfoFromRun, which
139+ // feeds bold/italic into the measured ascent/descent, so toggling them must change the version.
140+ it ( 'produces a different version when the tab bold changes' , ( ) => {
141+ const plain = deriveBlockVersion ( makeStyledTabParagraph ( { bold : false } ) ) ;
142+ const bold = deriveBlockVersion ( makeStyledTabParagraph ( { bold : true } ) ) ;
143+ expect ( bold ) . not . toBe ( plain ) ;
144+ } ) ;
145+
146+ it ( 'produces a different version when the tab italic changes' , ( ) => {
147+ const plain = deriveBlockVersion ( makeStyledTabParagraph ( { italic : false } ) ) ;
148+ const italic = deriveBlockVersion ( makeStyledTabParagraph ( { italic : true } ) ) ;
149+ expect ( italic ) . not . toBe ( plain ) ;
150+ } ) ;
151+
152+ it ( 'is stable when tab fontSize, fontFamily and color are identical' , ( ) => {
153+ const a = deriveBlockVersion ( makeStyledTabParagraph ( { fontSize : 16 , fontFamily : 'Arial' , color : '#123456' } ) ) ;
154+ const b = deriveBlockVersion ( makeStyledTabParagraph ( { fontSize : 16 , fontFamily : 'Arial' , color : '#123456' } ) ) ;
155+ expect ( a ) . toBe ( b ) ;
156+ } ) ;
98157} ) ;
99158
100159describe ( 'deriveBlockVersion - table image content' , ( ) => {
0 commit comments