@@ -62,6 +62,40 @@ describe('initBubbleChart', () => {
6262 expect ( config . options . scales . x . title . text ) . toBe ( 'Effort to refactor' ) ;
6363 expect ( config . options . scales . y . title . text ) . toBe ( 'Relative churn (impact)' ) ;
6464 } ) ;
65+
66+ it ( 'renders legend labels in a gray readable in light and dark mode' , ( ) => {
67+ const created = [ ] ;
68+ window . Chart = function ( ctx , config ) { created . push ( config ) ; } ;
69+ const canvas = document . getElementById ( 'chart_GOD' ) ;
70+ initBubbleChart ( canvas , 'God Classes' , { bubbles : [ ] } ) ;
71+ const items = created [ 0 ] . options . plugins . legend . labels . generateLabels ( ) ;
72+ expect ( items . length ) . toBeGreaterThan ( 0 ) ;
73+
74+ // One gray for both palettes: the chart canvas is transparent, so legend
75+ // text sits on --bg-color (#ffffff light / #10161d dark). No single gray
76+ // can pass 4.5:1 on both, so the guard pins the balanced midpoint.
77+ // Chart.js draws each legend item's text from item.fontColor — with a
78+ // custom generateLabels, options.plugins.legend.labels.color is ignored.
79+ const legendColor = items [ 0 ] . fontColor ;
80+ items . forEach ( item => expect ( item . fontColor ) . toBe ( legendColor ) ) ;
81+ const channels = / ^ # ( [ 0 - 9 a - f ] { 2 } ) ( [ 0 - 9 a - f ] { 2 } ) ( [ 0 - 9 a - f ] { 2 } ) $ / i. exec ( legendColor || '' ) ;
82+ expect ( channels ) . not . toBeNull ( ) ;
83+ const [ r , g , b ] = [ 1 , 2 , 3 ] . map ( i => parseInt ( channels [ i ] , 16 ) ) ;
84+ expect ( r ) . toBe ( g ) ;
85+ expect ( g ) . toBe ( b ) ; // neutral gray, no palette bias
86+
87+ const luminance = ( rs , gs , bs ) => {
88+ const lin = c => {
89+ const s = c / 255 ;
90+ return s <= 0.03928 ? s / 12.92 : Math . pow ( ( s + 0.055 ) / 1.055 , 2.4 ) ;
91+ } ;
92+ return 0.2126 * lin ( rs ) + 0.7152 * lin ( gs ) + 0.0722 * lin ( bs ) ;
93+ } ;
94+ const gray = luminance ( r , g , b ) ;
95+ const contrast = lum => ( Math . max ( lum , gray ) + 0.05 ) / ( Math . min ( lum , gray ) + 0.05 ) ;
96+ expect ( contrast ( luminance ( 0xff , 0xff , 0xff ) ) ) . toBeGreaterThanOrEqual ( 4 ) ;
97+ expect ( contrast ( luminance ( 0x10 , 0x16 , 0x1d ) ) ) . toBeGreaterThanOrEqual ( 4 ) ;
98+ } ) ;
6599} ) ;
66100
67101describe ( 'initDisharmonyCharts' , ( ) => {
0 commit comments