2 changed files with 140 additions and 1 deletions
@ -0,0 +1,111 @@ |
|||
import { describe, it, expect } from "vitest"; |
|||
import { render, screen, fireEvent } from "@testing-library/react"; |
|||
import { Table } from "@components/generic/Table/index.tsx"; |
|||
import { TimeAgo } from "@components/generic/TimeAgo.tsx"; |
|||
import { Mono } from "@components/generic/Mono.tsx"; |
|||
|
|||
|
|||
describe("Generic Table", () => { |
|||
it("Can render an empty table.", () => { |
|||
render( |
|||
<Table |
|||
headings={[]} |
|||
rows={[]} |
|||
/> |
|||
); |
|||
expect(screen.getByRole("table")).toBeInTheDocument(); |
|||
}); |
|||
|
|||
it("Can render a table with headers and no rows.", async () => { |
|||
render( |
|||
<Table |
|||
headings={[ |
|||
{ title: "", type: "blank", sortable: false }, |
|||
{ title: "Short Name", type: "normal", sortable: true }, |
|||
{ title: "Long Name", type: "normal", sortable: true }, |
|||
{ title: "Model", type: "normal", sortable: true }, |
|||
{ title: "MAC Address", type: "normal", sortable: true }, |
|||
{ title: "Last Heard", type: "normal", sortable: true }, |
|||
{ title: "SNR", type: "normal", sortable: true }, |
|||
{ title: "Encryption", type: "normal", sortable: false }, |
|||
{ title: "Connection", type: "normal", sortable: true }, |
|||
]} |
|||
rows={[]} |
|||
/> |
|||
); |
|||
await screen.findByRole('table'); |
|||
expect(screen.getAllByRole("columnheader")).toHaveLength(9); |
|||
}); |
|||
|
|||
// A simplified version of the rows in pages/Nodes.tsx for testing purposes
|
|||
const mockDevicesWithShortNameAndConnection = [ |
|||
{user: {shortName: "TST1"}, hopsAway: 1, lastHeard: Date.now() + 1000 }, |
|||
{user: {shortName: "TST2"}, hopsAway: 0, lastHeard: Date.now() + 4000 }, |
|||
{user: {shortName: "TST3"}, hopsAway: 4, lastHeard: Date.now() }, |
|||
{user: {shortName: "TST4"}, hopsAway: 3, lastHeard: Date.now() + 2000 } |
|||
]; |
|||
|
|||
const mockRows = mockDevicesWithShortNameAndConnection.map(node => [ |
|||
<h1 data-testshortname> { node.user.shortName } </h1>, |
|||
<><TimeAgo timestamp={node.lastHeard * 1000} /></>, |
|||
<Mono key="hops" data-testhops> |
|||
{node.lastHeard !== 0 |
|||
? node.hopsAway === 0 |
|||
? "Direct" |
|||
: `${node.hopsAway?.toString()} ${ |
|||
node.hopsAway > 1 ? "hops" : "hop" |
|||
} away` |
|||
: "-"} |
|||
</Mono> |
|||
]) |
|||
|
|||
it("Can sort rows appropriately.", async () => { |
|||
render( |
|||
<Table |
|||
headings={[ |
|||
{ title: "Short Name", type: "normal", sortable: true }, |
|||
{ title: "Last Heard", type: "normal", sortable: true }, |
|||
{ title: "Connection", type: "normal", sortable: true }, |
|||
]} |
|||
rows={mockRows} |
|||
/> |
|||
); |
|||
const renderedTable = await screen.findByRole('table'); |
|||
const columnHeaders = screen.getAllByRole("columnheader"); |
|||
expect(columnHeaders).toHaveLength(3); |
|||
|
|||
// Will be sorted "Last heard" "asc" by default
|
|||
expect( [...renderedTable.querySelectorAll('[data-testshortname]')] |
|||
.map(el=>el.textContent) |
|||
.map(v=>v?.trim()) |
|||
.join(',')) |
|||
.toMatch('TST2,TST4,TST1,TST3'); |
|||
|
|||
fireEvent.click(columnHeaders[0]); |
|||
|
|||
// Re-sort by Short Name asc
|
|||
expect( [...renderedTable.querySelectorAll('[data-testshortname]')] |
|||
.map(el=>el.textContent) |
|||
.map(v=>v?.trim()) |
|||
.join(',')) |
|||
.toMatch('TST1,TST2,TST3,TST4'); |
|||
|
|||
fireEvent.click(columnHeaders[0]); |
|||
|
|||
// Re-sort by Short Name desc
|
|||
expect( [...renderedTable.querySelectorAll('[data-testshortname]')] |
|||
.map(el=>el.textContent) |
|||
.map(v=>v?.trim()) |
|||
.join(',')) |
|||
.toMatch('TST4,TST3,TST2,TST1'); |
|||
|
|||
fireEvent.click(columnHeaders[2]); |
|||
|
|||
// Re-sort by Hops Away
|
|||
expect( [...renderedTable.querySelectorAll('[data-testshortname]')] |
|||
.map(el=>el.textContent) |
|||
.map(v=>v?.trim()) |
|||
.join(',')) |
|||
.toMatch('TST2,TST1,TST4,TST3'); |
|||
}); |
|||
}) |
|||
Loading…
Reference in new issue