11import { describe , it , expect } from 'vitest'
2- import { renderVolumeTable } from '../src/volume-table'
2+ import { renderServiceTable , renderVolumeTable } from '../src/volume-table'
33import type { ServiceInfo } from '../src/services'
44
55function makeService ( overrides : Partial < ServiceInfo > & { name : string } ) : ServiceInfo {
@@ -14,6 +14,70 @@ function makeService(overrides: Partial<ServiceInfo> & { name: string }): Servic
1414 }
1515}
1616
17+ describe ( 'renderServiceTable' , ( ) => {
18+ it ( 'returns empty wrapper for no services' , ( ) => {
19+ const container = renderServiceTable ( [ ] )
20+ expect ( container . querySelector ( 'table' ) ) . toBeNull ( )
21+ } )
22+
23+ it ( 'renders base columns: Service, Image, Ports, Networks' , ( ) => {
24+ const services = [
25+ makeService ( { name : 'app' , image : 'nginx:latest' , ports : [ '80:80' ] , networks : [ 'frontend' ] } ) ,
26+ ]
27+ const container = renderServiceTable ( services )
28+ const ths = container . querySelectorAll ( 'th' )
29+ expect ( ths [ 0 ] ! . textContent ) . toBe ( 'Service' )
30+ expect ( ths [ 1 ] ! . textContent ) . toBe ( 'Image' )
31+ expect ( ths [ 2 ] ! . textContent ) . toBe ( 'Ports' )
32+ expect ( ths [ 3 ] ! . textContent ) . toBe ( 'Networks' )
33+ } )
34+
35+ it ( 'renders service data in rows' , ( ) => {
36+ const services = [
37+ makeService ( { name : 'plex' , image : 'plex:latest' , ports : [ '32400:32400' ] , networks : [ 'media' ] } ) ,
38+ ]
39+ const container = renderServiceTable ( services )
40+ const tds = container . querySelectorAll ( 'tbody td' )
41+ expect ( tds [ 0 ] ! . textContent ) . toBe ( 'plex' )
42+ expect ( tds [ 1 ] ! . textContent ) . toBe ( 'plex:latest' )
43+ expect ( tds [ 2 ] ! . textContent ) . toBe ( '32400:32400' )
44+ expect ( tds [ 3 ] ! . textContent ) . toBe ( 'media' )
45+ } )
46+
47+ it ( 'shows dash for empty ports and networks' , ( ) => {
48+ const services = [ makeService ( { name : 'app' , image : 'nginx' } ) ]
49+ const container = renderServiceTable ( services )
50+ const tds = container . querySelectorAll ( 'tbody td' )
51+ expect ( tds [ 2 ] ! . textContent ) . toBe ( '\u2014' )
52+ expect ( tds [ 3 ] ! . textContent ) . toBe ( '\u2014' )
53+ } )
54+
55+ it ( 'includes extras as dynamic columns' , ( ) => {
56+ const services = [
57+ makeService ( { name : 'app' , image : 'nginx' , extras : new Map ( [ [ 'restart' , 'unless-stopped' ] ] ) } ) ,
58+ makeService ( { name : 'db' , image : 'postgres' , extras : new Map ( [ [ 'restart' , 'always' ] , [ 'hostname' , 'pg-host' ] ] ) } ) ,
59+ ]
60+ const container = renderServiceTable ( services )
61+ const ths = container . querySelectorAll ( 'th' )
62+ const headers = Array . from ( ths ) . map ( th => th . textContent )
63+ expect ( headers ) . toContain ( 'restart' )
64+ expect ( headers ) . toContain ( 'hostname' )
65+
66+ // app row: has restart, no hostname
67+ const rows = container . querySelectorAll ( 'tbody tr' )
68+ const appCells = rows [ 0 ] ! . querySelectorAll ( 'td' )
69+ const restartIdx = headers . indexOf ( 'restart' )
70+ const hostnameIdx = headers . indexOf ( 'hostname' )
71+ expect ( appCells [ restartIdx ] ! . textContent ) . toBe ( 'unless-stopped' )
72+ expect ( appCells [ hostnameIdx ] ! . textContent ) . toBe ( '\u2014' )
73+
74+ // db row: has both
75+ const dbCells = rows [ 1 ] ! . querySelectorAll ( 'td' )
76+ expect ( dbCells [ restartIdx ] ! . textContent ) . toBe ( 'always' )
77+ expect ( dbCells [ hostnameIdx ] ! . textContent ) . toBe ( 'pg-host' )
78+ } )
79+ } )
80+
1781describe ( 'renderVolumeTable' , ( ) => {
1882 it ( 'returns empty div for no services' , ( ) => {
1983 const table = renderVolumeTable ( [ ] )
0 commit comments