@@ -6,6 +6,7 @@ const mockMultiRender = vi.fn();
66const mockGridRender = vi . fn ( ) ;
77const mockLegacyRender = vi . fn ( ) ;
88const mockProtocolRender = vi . fn ( ) ;
9+ const mockRegistryGet = vi . fn ( ( ) => null ) ;
910
1011const controlsMethods = {
1112 addLabeledInput : vi . fn ( ) ,
@@ -57,7 +58,7 @@ vi.mock('../../js/core/state', () => ({
5758
5859vi . mock ( '../../js/core/plugin_registry' , ( ) => ( {
5960 registry : {
60- get : vi . fn ( ( ) => null )
61+ get : mockRegistryGet
6162 }
6263} ) ) ;
6364
@@ -115,6 +116,8 @@ describe('PropertiesPanel', () => {
115116 mockAppState . getSelectedWidget . mockReturnValue ( null ) ;
116117 mockAppState . getSelectedWidgets . mockReturnValue ( [ ] ) ;
117118 mockAppState . settings . renderingMode = 'direct' ;
119+ mockRegistryGet . mockReset ( ) ;
120+ mockRegistryGet . mockReturnValue ( null ) ;
118121
119122 document . body . innerHTML = `
120123 <div id="propertiesPanel"></div>
@@ -159,7 +162,7 @@ describe('PropertiesPanel', () => {
159162 expect ( mockMultiRender ) . toHaveBeenCalledWith ( panel , [ 'w1' , 'w2' ] ) ;
160163 } ) ;
161164
162- it ( 're- renders into multi-select mode when selection expands but first id stays the same ' , async ( ) => {
165+ it ( 'renders single-widget panel and falls back to legacy renderer ' , async ( ) => {
163166 const widget = {
164167 id : 'w1' ,
165168 type : 'sensor_text' ,
@@ -171,39 +174,49 @@ describe('PropertiesPanel', () => {
171174 } ;
172175
173176 mockAppState . selectedWidgetId = 'w1' ;
177+ mockAppState . selectedWidgetIds = [ 'w1' ] ;
178+ mockAppState . getSelectedWidgetIds . mockReturnValue ( [ 'w1' ] ) ;
174179 mockAppState . getSelectedWidget . mockReturnValue ( widget ) ;
175180 mockAppState . getSelectedWidgets . mockReturnValue ( [ widget ] ) ;
176181
177182 const { PropertiesPanel } = await import ( '../../js/core/properties.js' ) ;
178183 const panel = new PropertiesPanel ( mockApp ) ;
179184
180- // First render in single-select mode
181- mockAppState . getSelectedWidgetIds . mockReturnValue ( [ 'w1' ] ) ;
182- mockAppState . selectedWidgetIds = [ 'w1' ] ;
183185 panel . render ( ) ;
184186
185- // Expand selection to multi-select while keeping first selected ID
186- mockAppState . getSelectedWidgetIds . mockReturnValue ( [ 'w1' , 'w2' ] ) ;
187- mockAppState . selectedWidgetIds = [ 'w1' , 'w2' ] ;
188- panel . render ( ) ;
187+ const content = document . getElementById ( 'propertiesPanel' ) ?. textContent || '' ;
188+ expect ( content ) . toContain ( 'Properties' ) ;
189+ expect ( mockGridRender ) . toHaveBeenCalled ( ) ;
190+ expect ( mockLegacyRender ) . toHaveBeenCalled ( ) ;
191+ expect ( controlsMethods . addVisibilityConditions ) . toHaveBeenCalled ( ) ;
192+ } ) ;
189193
190- expect ( mockMultiRender ) . toHaveBeenCalledWith ( panel , [ 'w1' , 'w2' ] ) ;
194+ it ( 'auto-populates title from selected entity state' , async ( ) => {
195+ const { PropertiesPanel } = await import ( '../../js/core/properties.js' ) ;
196+ const panel = new PropertiesPanel ( mockApp ) ;
197+
198+ panel . autoPopulateTitleFromEntity ( 'w1' , 'sensor.temp' ) ;
199+
200+ expect ( mockAppState . updateWidget ) . toHaveBeenCalledWith ( 'w1' , { title : 'Temperature' } ) ;
191201 } ) ;
192202
193- it ( 'renders single-widget panel and falls back to legacy renderer ' , async ( ) => {
203+ it ( 'renders common LVGL properties before schema-driven LVGL fields ' , async ( ) => {
194204 const widget = {
195- id : 'w1 ' ,
196- type : 'sensor_text ' ,
205+ id : 'w-lvgl ' ,
206+ type : 'lvgl_button ' ,
197207 x : 10 ,
198208 y : 20 ,
199209 width : 100 ,
200210 height : 40 ,
201- props : { }
211+ props : { clickable : true }
202212 } ;
203213
204- mockAppState . selectedWidgetId = 'w1' ;
205- mockAppState . selectedWidgetIds = [ 'w1' ] ;
206- mockAppState . getSelectedWidgetIds . mockReturnValue ( [ 'w1' ] ) ;
214+ mockRegistryGet . mockReturnValue ( {
215+ schema : [ { section : 'Content' , fields : [ ] } ]
216+ } ) ;
217+ mockAppState . selectedWidgetId = 'w-lvgl' ;
218+ mockAppState . selectedWidgetIds = [ 'w-lvgl' ] ;
219+ mockAppState . getSelectedWidgetIds . mockReturnValue ( [ 'w-lvgl' ] ) ;
207220 mockAppState . getSelectedWidget . mockReturnValue ( widget ) ;
208221 mockAppState . getSelectedWidgets . mockReturnValue ( [ widget ] ) ;
209222
@@ -212,20 +225,8 @@ describe('PropertiesPanel', () => {
212225
213226 panel . render ( ) ;
214227
215- const content = document . getElementById ( 'propertiesPanel' ) ?. textContent || '' ;
216- expect ( content ) . toContain ( 'Properties' ) ;
217- expect ( mockGridRender ) . toHaveBeenCalled ( ) ;
218- expect ( mockLegacyRender ) . toHaveBeenCalled ( ) ;
219- expect ( controlsMethods . addVisibilityConditions ) . toHaveBeenCalled ( ) ;
220- } ) ;
221-
222- it ( 'auto-populates title from selected entity state' , async ( ) => {
223- const { PropertiesPanel } = await import ( '../../js/core/properties.js' ) ;
224- const panel = new PropertiesPanel ( mockApp ) ;
225-
226- panel . autoPopulateTitleFromEntity ( 'w1' , 'sensor.temp' ) ;
227-
228- expect ( mockAppState . updateWidget ) . toHaveBeenCalledWith ( 'w1' , { title : 'Temperature' } ) ;
228+ expect ( controlsMethods . addCommonLVGLProperties ) . toHaveBeenCalledWith ( widget , widget . props ) ;
229+ expect ( mockSchemaRender ) . toHaveBeenCalled ( ) ;
229230 } ) ;
230231
231232 it ( 'invokes drop-shadow helper action for selected widgets' , async ( ) => {
0 commit comments