1
+ import { describe , it , expect } from "vitest" ;
2
+ import { render , screen , fireEvent } from "@testing-library/react" ;
3
+ import { Table } from "@components/generic/Table/index.tsx" ;
4
+ import { TimeAgo } from "@components/generic/TimeAgo.tsx" ;
5
+ import { Mono } from "@components/generic/Mono.tsx" ;
6
+
7
+
8
+ describe ( "Generic Table" , ( ) => {
9
+ it ( "Can render an empty table." , ( ) => {
10
+ render (
11
+ < Table
12
+ headings = { [ ] }
13
+ rows = { [ ] }
14
+ />
15
+ ) ;
16
+ expect ( screen . getByRole ( "table" ) ) . toBeInTheDocument ( ) ;
17
+ } ) ;
18
+
19
+ it ( "Can render a table with headers and no rows." , async ( ) => {
20
+ render (
21
+ < Table
22
+ headings = { [
23
+ { title : "" , type : "blank" , sortable : false } ,
24
+ { title : "Short Name" , type : "normal" , sortable : true } ,
25
+ { title : "Long Name" , type : "normal" , sortable : true } ,
26
+ { title : "Model" , type : "normal" , sortable : true } ,
27
+ { title : "MAC Address" , type : "normal" , sortable : true } ,
28
+ { title : "Last Heard" , type : "normal" , sortable : true } ,
29
+ { title : "SNR" , type : "normal" , sortable : true } ,
30
+ { title : "Encryption" , type : "normal" , sortable : false } ,
31
+ { title : "Connection" , type : "normal" , sortable : true } ,
32
+ ] }
33
+ rows = { [ ] }
34
+ />
35
+ ) ;
36
+ await screen . findByRole ( 'table' ) ;
37
+ expect ( screen . getAllByRole ( "columnheader" ) ) . toHaveLength ( 9 ) ;
38
+ } ) ;
39
+
40
+ // A simplified version of the rows in pages/Nodes.tsx for testing purposes
41
+ const mockDevicesWithShortNameAndConnection = [
42
+ { user : { shortName : "TST1" } , hopsAway : 1 , lastHeard : Date . now ( ) + 1000 } ,
43
+ { user : { shortName : "TST2" } , hopsAway : 0 , lastHeard : Date . now ( ) + 4000 } ,
44
+ { user : { shortName : "TST3" } , hopsAway : 4 , lastHeard : Date . now ( ) } ,
45
+ { user : { shortName : "TST4" } , hopsAway : 3 , lastHeard : Date . now ( ) + 2000 }
46
+ ] ;
47
+
48
+ const mockRows = mockDevicesWithShortNameAndConnection . map ( node => [
49
+ < h1 data-testshortname > { node . user . shortName } </ h1 > ,
50
+ < > < TimeAgo timestamp = { node . lastHeard * 1000 } /> </ > ,
51
+ < Mono key = "hops" data-testhops >
52
+ { node . lastHeard !== 0
53
+ ? node . hopsAway === 0
54
+ ? "Direct"
55
+ : `${ node . hopsAway ?. toString ( ) } ${
56
+ node . hopsAway > 1 ? "hops" : "hop"
57
+ } away`
58
+ : "-" }
59
+ </ Mono >
60
+ ] )
61
+
62
+ it ( "Can sort rows appropriately." , async ( ) => {
63
+ render (
64
+ < Table
65
+ headings = { [
66
+ { title : "Short Name" , type : "normal" , sortable : true } ,
67
+ { title : "Last Heard" , type : "normal" , sortable : true } ,
68
+ { title : "Connection" , type : "normal" , sortable : true } ,
69
+ ] }
70
+ rows = { mockRows }
71
+ />
72
+ ) ;
73
+ const renderedTable = await screen . findByRole ( 'table' ) ;
74
+ const columnHeaders = screen . getAllByRole ( "columnheader" ) ;
75
+ expect ( columnHeaders ) . toHaveLength ( 3 ) ;
76
+
77
+ // Will be sorted "Last heard" "asc" by default
78
+ expect ( [ ...renderedTable . querySelectorAll ( '[data-testshortname]' ) ]
79
+ . map ( el => el . textContent )
80
+ . map ( v => v ?. trim ( ) )
81
+ . join ( ',' ) )
82
+ . toMatch ( 'TST2,TST4,TST1,TST3' ) ;
83
+
84
+ fireEvent . click ( columnHeaders [ 0 ] ) ;
85
+
86
+ // Re-sort by Short Name asc
87
+ expect ( [ ...renderedTable . querySelectorAll ( '[data-testshortname]' ) ]
88
+ . map ( el => el . textContent )
89
+ . map ( v => v ?. trim ( ) )
90
+ . join ( ',' ) )
91
+ . toMatch ( 'TST1,TST2,TST3,TST4' ) ;
92
+
93
+ fireEvent . click ( columnHeaders [ 0 ] ) ;
94
+
95
+ // Re-sort by Short Name desc
96
+ expect ( [ ...renderedTable . querySelectorAll ( '[data-testshortname]' ) ]
97
+ . map ( el => el . textContent )
98
+ . map ( v => v ?. trim ( ) )
99
+ . join ( ',' ) )
100
+ . toMatch ( 'TST4,TST3,TST2,TST1' ) ;
101
+
102
+ fireEvent . click ( columnHeaders [ 2 ] ) ;
103
+
104
+ // Re-sort by Hops Away
105
+ expect ( [ ...renderedTable . querySelectorAll ( '[data-testshortname]' ) ]
106
+ . map ( el => el . textContent )
107
+ . map ( v => v ?. trim ( ) )
108
+ . join ( ',' ) )
109
+ . toMatch ( 'TST2,TST1,TST4,TST3' ) ;
110
+ } ) ;
111
+ } )
0 commit comments