@@ -295,6 +295,91 @@ test('registerTriggers should warn when registration errors occur', async () =>
295295 ) ;
296296} ) ;
297297
298+ test ( 'ensureDockercomposeTriggerForContainer should create a trigger with container name only when no compose path' , async ( ) => {
299+ const triggerId = await registry . ensureDockercomposeTriggerForContainer ( 'my-service' ) ;
300+ expect ( triggerId ) . toBe ( 'dockercompose.my-service' ) ;
301+ expect ( Object . keys ( registry . getState ( ) . trigger ) ) . toContain ( triggerId ) ;
302+ } ) ;
303+
304+ test ( 'ensureDockercomposeTriggerForContainer should create trigger with parent folder and container name' , async ( ) => {
305+ const triggerId = await registry . ensureDockercomposeTriggerForContainer ( 'my-service' , '/home/user/myapp/docker-compose.yml' ) ;
306+ expect ( triggerId ) . toBe ( 'dockercompose.myapp-my-service' ) ;
307+ expect ( Object . keys ( registry . getState ( ) . trigger ) ) . toContain ( triggerId ) ;
308+ } ) ;
309+
310+ test ( 'ensureDockercomposeTriggerForContainer should append a number when name conflicts' , async ( ) => {
311+ const triggerId1 = await registry . ensureDockercomposeTriggerForContainer ( 'my-service' ) ;
312+ const triggerId2 = await registry . ensureDockercomposeTriggerForContainer ( 'my-service' ) ;
313+
314+ expect ( triggerId1 ) . toBe ( 'dockercompose.my-service' ) ;
315+ expect ( triggerId2 ) . toBe ( 'dockercompose.my-service-2' ) ;
316+ } ) ;
317+
318+ test ( 'ensureDockercomposeTriggerForContainer should append a number when name conflicts with compose path' , async ( ) => {
319+ const triggerId1 = await registry . ensureDockercomposeTriggerForContainer ( 'my-service' , '/home/user/myapp/docker-compose.yml' ) ;
320+ const triggerId2 = await registry . ensureDockercomposeTriggerForContainer ( 'my-service' , '/home/user/myapp/docker-compose.yml' ) ;
321+
322+ expect ( triggerId1 ) . toBe ( 'dockercompose.myapp-my-service' ) ;
323+ expect ( triggerId2 ) . toBe ( 'dockercompose.myapp-my-service-2' ) ;
324+ } ) ;
325+
326+ test ( 'ensureDockercomposeTriggerForContainer should handle Windows paths' , async ( ) => {
327+ const triggerId = await registry . ensureDockercomposeTriggerForContainer ( 'my-service' , 'C:\\Users\\user\\myapp\\docker-compose.yml' ) ;
328+ expect ( triggerId ) . toBe ( 'dockercompose.myapp-my-service' ) ;
329+ expect ( Object . keys ( registry . getState ( ) . trigger ) ) . toContain ( triggerId ) ;
330+ } ) ;
331+
332+ test ( 'ensureDockercomposeTriggerForContainer should handle paths without parent folder' , async ( ) => {
333+ const triggerId = await registry . ensureDockercomposeTriggerForContainer ( 'my-service' , '/docker-compose.yml' ) ;
334+ // When path has no parent folder (slice(-2, -1)[0] returns undefined for single-segment paths),
335+ // falls back to container name only
336+ expect ( triggerId ) . toBe ( 'dockercompose.my-service' ) ;
337+ expect ( Object . keys ( registry . getState ( ) . trigger ) ) . toContain ( triggerId ) ;
338+ } ) ;
339+
340+ test ( 'sanitizeComponentName should handle empty string' , ( ) => {
341+ const result = registry . testable_sanitizeComponentName ( '' ) ;
342+ expect ( result ) . toBe ( 'container' ) ;
343+ } ) ;
344+
345+ test ( 'sanitizeComponentName should handle strings with only special characters' , ( ) => {
346+ const result = registry . testable_sanitizeComponentName ( '@@@###$$$' ) ;
347+ // Result should be composed only of safe characters for component names
348+ expect ( result ) . toMatch ( / ^ [ a - z 0 - 9 . _ - ] * $ / ) ;
349+ } ) ;
350+
351+ test ( 'sanitizeComponentName should lowercase and trim mixed-case names with whitespace' , ( ) => {
352+ const input = ' My-Component_Name ' ;
353+ const result = registry . testable_sanitizeComponentName ( input ) ;
354+
355+ // Should be all lowercase
356+ expect ( result ) . toBe ( result . toLowerCase ( ) ) ;
357+ // Should not have leading or trailing whitespace
358+ expect ( result . startsWith ( ' ' ) ) . toBe ( false ) ;
359+ expect ( result . endsWith ( ' ' ) ) . toBe ( false ) ;
360+ expect ( result ) . toBe ( 'my-component_name' ) ;
361+ } ) ;
362+
363+ test ( 'sanitizeComponentName should handle various special characters' , ( ) => {
364+ const input = 'Comp@#Name!$ With%Chars' ;
365+ const result = registry . testable_sanitizeComponentName ( input ) ;
366+
367+ // Should be lowercase and contain only safe characters
368+ expect ( result ) . toBe ( result . toLowerCase ( ) ) ;
369+ expect ( result ) . toMatch ( / ^ [ a - z 0 - 9 . _ - ] * $ / ) ;
370+ expect ( result ) . toBe ( 'comp--name---with-chars' ) ;
371+ } ) ;
372+
373+ test ( 'sanitizeComponentName should handle unicode and symbols robustly' , ( ) => {
374+ const input = 'Üñïçødë-µ_Service!' ;
375+ const result = registry . testable_sanitizeComponentName ( input ) ;
376+
377+ // Should be lowercase and contain only safe characters
378+ expect ( result ) . toBe ( result . toLowerCase ( ) ) ;
379+ expect ( result ) . toMatch ( / ^ [ a - z 0 - 9 . _ - ] * $ / ) ;
380+ } ) ;
381+
382+
298383test ( 'registerWatchers should register all watchers' , async ( ) => {
299384 watchers = {
300385 watcher1 : {
0 commit comments